Exemple #1
0
 def modelDefaults(self):
     model = QStandardItemModel()
     model.setHorizontalHeaderLabels([
         self.tr('enabled'),
         self.tr('map to'),
         self.tr('label'),
         self.tr('ODK type'),
         self.tr('hint'),
         self.tr('required'),
         self.tr('default'),
         self.tr('QVar_type'),
         self.tr('widget'),
         self.tr('choices'),
         self.tr('appearance'),
         self.tr('read_only'),
         self.tr('calculation')
     ])
     self.setModel(model)
     self.hideColumn(7)
     self.hideColumn(8)
     self.hideColumn(11)
     self.hideColumn(12)
     for column in range(0,12):
         if column > 3:
             width = 60
         elif column == 3:
             width = 90
         else:
             width = 140
         self.setColumnWidth(column,width)
     return model
     model.itemChanged.connect(self.cleanTreeItem)
Exemple #2
0
 def actualizePeakModelComparative():
     model = QStandardItemModel()
     #root=MSDialogController.getColouredRootItem(sample)
     sampleList = QApplication.instance().model
     groups = sampleList.peaksGrouping()
     model.setVerticalHeaderLabels([
         "/".join(map(str,
                      round([mass, rt], 4).tolist()))
         for mass, rt in sorted(groups.keys(), key=lambda x: x[0])
     ])
     model.setHorizontalHeaderLabels(
         [spl.shortName() for spl in sampleList.isamples()])
     for i, key in enumerate(sorted(groups.keys(), key=lambda x: x[0])):
         zeros = [0.] * len(sampleList)
         for peak in groups[key]:
             try:
                 idx = [spl.shortName() for spl in sampleList
                        ].index(peak.sample.shortName())
             except ValueError:
                 print "Error in %s" % MSDialogController.actualizePeakModelComparative.__name__
             zeros[idx] = peak
         for j in xrange(len(zeros)):
             item = QStandardItem()
             if not zeros[j]:
                 item.setBackground(QBrush(Qt.red))
                 item.setText("Not found")
             else:
                 MSDialogController.setRightIcon(
                     zeros[j], item)  #set the colour actually
                 item.setText(str(round(zeros[j].area, 2)))
             model.setItem(i, j, item)
     return model
class dockUrlMonitor(QTreeView):
    ''' dock widget for get all credentials logger netcreds'''
    def __init__(self, parent=None,info={}):
        super(dockUrlMonitor, self).__init__(parent)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['URL','HTTP-Headers'])
        self.setModel(self.model)
        self.setUniformRowHeights(True)
        self.setColumnWidth(0,130)

    def writeModeData(self,data):
        ''' get data output and add on QtableWidgets '''
        ParentMaster = QStandardItem('[ {0[src]} > {0[dst]} ] {1[Method]} {1[Host]}{1[Path]}'.format(
        data['urlsCap']['IP'], data['urlsCap']['Headers']))
        ParentMaster.setIcon(QIcon('icons/accept.png'))
        ParentMaster.setSizeHint(QSize(30,30))
        for item in data['urlsCap']['Headers']:
            ParentMaster.appendRow([QStandardItem('{}'.format(item)),
            QStandardItem(data['urlsCap']['Headers'][item])])
        self.model.appendRow(ParentMaster)
        self.setFirstColumnSpanned(ParentMaster.row(),
        self.rootIndex(), True)
        self.scrollToBottom()

    def clear(self):
        self.model.clear()

    def stopProcess(self):
        self.clearSelection()
Exemple #4
0
class dockUrlMonitor(QTreeView):
    ''' dock widget for get all credentials logger netcreds'''
    def __init__(self, parent=None, info={}):
        super(dockUrlMonitor, self).__init__(parent)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(['URL', 'HTTP-Headers'])
        self.setModel(self.model)
        self.setUniformRowHeights(True)
        self.setColumnWidth(0, 130)

    def writeModeData(self, data):
        ''' get data output and add on QtableWidgets '''
        ParentMaster = QStandardItem(
            '[ {0[src]} > {0[dst]} ] {1[Method]} {1[Host]}{1[Path]}'.format(
                data['urlsCap']['IP'], data['urlsCap']['Headers']))
        ParentMaster.setIcon(QIcon('icons/accept.png'))
        ParentMaster.setSizeHint(QSize(30, 30))
        for item in data['urlsCap']['Headers']:
            ParentMaster.appendRow([
                QStandardItem('{}'.format(item)),
                QStandardItem(data['urlsCap']['Headers'][item])
            ])
        self.model.appendRow(ParentMaster)
        self.setFirstColumnSpanned(ParentMaster.row(), self.rootIndex(), True)
        self.scrollToBottom()

    def clear(self):
        self.model.clear()

    def stopProcess(self):
        self.clearSelection()
    def __display_table_rslt(self, table_rows):
        '''
        controls table_comp_rslt widget
        fill the widget with table_rows list
        @param table_rows: []
        '''

        rows_count = len(table_rows)
        model = QStandardItemModel(rows_count, 3)

        model.setHorizontalHeaderLabels(TAB_LABELS)

        # fill model with data
        for row in range(rows_count):
            for col in range(3):
                item = QStandardItem()
                item.setData(str(table_rows[row][col]), Qt.DisplayRole)
                model.setItem(row, col, item)

        # self.table_comp_rslt.clearContents()
        if self.table_comp_rslt.isSortingEnabled():
            self.table_comp_rslt.setSortingEnabled(False)

        proxy = numsort.NumberSortModel()
        proxy.setSourceModel(model)
        self.table_comp_rslt.setModel(proxy)
        self.table_comp_rslt.resizeColumnsToContents()
        self.table_comp_rslt.setSortingEnabled(True)
Exemple #6
0
    def initialize_buckets_table(self):
        self.storj_engine = StorjEngine()  # init StorjEngine
        logger.info("resolving buckets")
        model = QStandardItemModel(1, 1)  # initialize model for inserting to table

        model.setHorizontalHeaderLabels(['Name', 'Storage', 'Transfer', 'ID'])

        i = 0
        try:
            for bucket in self.storj_engine.storj_client.bucket_list():
                item = QStandardItem(bucket.name)
                model.setItem(i, 0, item)  # row, column, item (QStandardItem)

                item = QStandardItem(str(bucket.storage))
                model.setItem(i, 1, item)  # row, column, item (QStandardItem)

                item = QStandardItem(str(bucket.transfer))
                model.setItem(i, 2, item)  # row, column, item (QStandardItem)

                item = QStandardItem(bucket.id)
                model.setItem(i, 3, item)  # row, column, item (QStandardItem)

                i = i + 1

        except sjexc.StorjBridgeApiError as e:
            QtGui.QMessageBox.about(
                self,
                'Unhandled bucket resolving exception',
                'Exception: %s' % e)

        self.bucket_manager_ui.total_buckets_label.setText(str(i))  # set label of user buckets number
        self.bucket_manager_ui.bucket_list_tableview.setModel(model)
        self.bucket_manager_ui.bucket_list_tableview.horizontalHeader().setResizeMode(QtGui.QHeaderView.Stretch)
Exemple #7
0
 def actualizePeakModelComparative():
     model = QStandardItemModel()
     #root=MSDialogController.getColouredRootItem(sample)
     sampleList = QApplication.instance().model
     groups = sampleList.peaksGrouping()
     model.setVerticalHeaderLabels(["/".join(map(str, round([mass, rt], 4).tolist())) for mass, rt in sorted(groups.keys(), key=lambda x:x[0])])
     model.setHorizontalHeaderLabels([spl.shortName() for spl in sampleList.isamples()])
     for i, key in enumerate(sorted(groups.keys(), key=lambda x:x[0])):
         zeros = [0.] * len(sampleList)
         for peak in groups[key]:
             try:
                 idx = [spl.shortName() for spl in sampleList].index(peak.sample.shortName())
             except ValueError:
                 print "Error in %s"%MSDialogController.actualizePeakModelComparative.__name__
             zeros[idx] = peak
         for j in xrange(len(zeros)):
             item = QStandardItem()
             if not zeros[j]:
                 item.setBackground(QBrush(Qt.red))
                 item.setText("Not found")
             else:
                 MSDialogController.setRightIcon(zeros[j], item)#set the colour actually
                 item.setText(str(round(zeros[j].area, 2)))
             model.setItem(i, j, item)
     return model
Exemple #8
0
class BreakpointsViewer(QTreeView):
    """ showing bps  """
    def __init__(self, parent):
        super(QTreeView, self).__init__(parent)
        self.setAutoScroll(True)
        self.source_files = {}
        self.focus_signal = None
        self.header().setResizeMode(QHeaderView.ResizeToContents)
        self._show_args = None
        self.bp_data = QStandardItemModel()
        self.setModel(self.bp_data)
        self.setAlternatingRowColors(True)

    def set_focus_signal(self, signal):
        """ set callback to focus source file line"""
        self.focus_signal = signal

    def clear(self):
        """ clear the widget"""
        self.bp_data.clear()
        self.bp_data.setHorizontalHeaderLabels(['ID', 'Hits', 'Ignore Count', 'Condition'])

    def update_bp_info(self, target):
        """ update breakpoint info """
        self.clear()
        root = self.bp_data.invisibleRootItem()
        for breakpoint in target.breakpoint_iter():
            if not breakpoint.IsValid() or breakpoint.IsInternal():
                continue
            bp_item = QStandardItem(str(breakpoint.id))
            bp_row =[bp_item, QStandardItem(str(breakpoint.GetHitCount())), 
                       QStandardItem(str(breakpoint.GetIgnoreCount())), QStandardItem(str(breakpoint.GetCondition()))]
            for loc in breakpoint:
                loc_row = [QStandardItem(str(loc.GetID())), QStandardItem(str(loc.GetAddress().GetLineEntry()))]
                bp_item.appendRow(loc_row)
            root.appendRow(bp_row)
        self.expandToDepth(1)

    def mousePressEvent(self, event):
        """ overrided """
        idx = self.indexAt(event.pos())
        if idx.isValid() and self.focus_signal:
            model = idx.model()
            idx = idx.sibling(idx.row(), 0)
            if idx.isValid():
                item = model.itemFromIndex(idx)
                if item and item.isSelectable():
                    if item in self.source_files:
                        file_info = self.source_files[item]
                        if self.focus_signal:
                            self.focus_signal.emit(file_info.GetFileSpec().fullpath,
                                                   file_info.GetLine())
                        self.frame_changed.emit(self.frames[item])

                    else:
                        logging.error('frame cannot find associated source file')

        QTreeView.mousePressEvent(self, event)
 def buildModel(self, choosenOne):
     identificationModel = QStandardItemModel()
     if choosenOne.formulas:
         identificationModel.setHorizontalHeaderLabels(["score", "formula", "diff mass", "names"])
         for i, f in enumerate(choosenOne.formulas.iterkeys()):
             identificationModel.setItem(i, 0, MSStandardItem(str(choosenOne.formulas[f]["score"])))
             identificationModel.setItem(i, 1, QStandardItem(str(f)))
             identificationModel.setItem(i, 2, MSStandardItem(str(choosenOne.formulas[f]["diffmass"])))
             identificationModel.setItem(i, 3, QStandardItem(choosenOne.formulas[f]["names"]))
     return identificationModel
Exemple #10
0
    def _configure_model(self):
        model = QStandardItemModel(0, 3, self)

        # Set headers
        headers = [
            self.tr('Name'),
            self.tr('Data Type'),
            self.tr('Description')
        ]
        model.setHorizontalHeaderLabels(headers)

        self.setModel(model)
    def _configure_model(self):
        model = QStandardItemModel(0, 3, self)

        # Set headers
        headers = [
            self.tr('Name'),
            self.tr('Data Type'),
            self.tr('Description')
        ]
        model.setHorizontalHeaderLabels(headers)

        self.setModel(model)
Exemple #12
0
    def populateTable(self, table):
        cols = len(self.param.cols)
        rows = len(table)
        model = QStandardItemModel(rows, cols)

        # Set headers
        model.setHorizontalHeaderLabels(self.param.cols)

        # Populate table
        for i in xrange(rows):
            for j in xrange(cols):
                item = QStandardItem(table[i][j])
                model.setItem(i, j, item)
        self.tblView.setModel(model)
Exemple #13
0
    def populateTable(self, table):
        cols = len(self.param.cols)
        rows = len(table)
        model = QStandardItemModel(rows, cols)

        # Set headers
        model.setHorizontalHeaderLabels(self.param.cols)

        # Populate table
        for i in xrange(rows):
            for j in xrange(cols):
                item = QStandardItem(table[i][j])
                model.setItem(i, j, item)
        self.tblView.setModel(model)
    def set_headers(self, qtable):
        feature_type = utils_giswater.get_item_data(
            self.dlg_lot, self.dlg_lot.cmb_visit_class, 2).lower()
        columns_name = self.controller.get_columns_list('om_visit_lot_x_' +
                                                        str(feature_type))
        columns_name.append(['validate'])
        standard_model = QStandardItemModel()
        qtable.setModel(standard_model)
        qtable.horizontalHeader().setStretchLastSection(True)

        # # Get headers
        headers = []
        for x in columns_name:
            headers.append(x[0])
        # Set headers
        standard_model.setHorizontalHeaderLabels(headers)
Exemple #15
0
    def getSampleModel(spl, flags='peak', **kw):
        from gui.MetBaseGui import MSStandardItem
        if flags not in ('peak', 'cluster', 'id'):
            return
        model = QStandardItemModel()
        if flags == 'peak':
            from utils.misc import Hot
            areas = [peak.area for peak in spl.rawPeaks.ipeaks()]
            mxInt = max(areas)
            model.setHorizontalHeaderLabels(MSSample.peakModelLabel)

            for i, peak in enumerate(spl.rawPeaks.ipeaks()):
                model.setItem(i, 0, MSStandardItem(str(peak.mass())))
                model.item(i, 0).setBackground(
                    QBrush(Hot._get_color(areas[i] / mxInt, True, alpha=0.5)))

                model.setItem(i, 1, MSStandardItem(str(peak.rt)))
                model.item(i, 1).setBackground(
                    QBrush(Hot._get_color(areas[i] / mxInt, True, alpha=0.5)))

                model.setItem(i, 2, MSStandardItem(str(peak.area)))
                model.item(i, 2).setBackground(
                    QBrush(Hot._get_color(areas[i] / mxInt, True, alpha=0.5)))

                model.setItem(i, 3, MSStandardItem(str(peak.sn)))
                model.item(i, 3).setBackground(
                    QBrush(Hot._get_color(areas[i] / mxInt, True, alpha=0.5)))

                model.setItem(i, 4, MSStandardItem(str(peak.r_coef)))
                model.item(i, 4).setBackground(
                    QBrush(Hot._get_color(areas[i] / mxInt, True, alpha=0.5)))

        elif flags == 'cluster':
            model.setHorizontalHeaderLabels(MSSample.clusterModelLabel)
            for i, peak in enumerate(spl.mappedPeaks.ipeaks()):
                model.setItem(i, 0, MSStandardItem(str(peak.mass())))
                model.setItem(i, 1, MSStandardItem(str(peak.rt)))
                model.setItem(i, 2, MSStandardItem(str(peak.area)))
                info_iso = ""
                info_frag = ""
                for iso in peak.isoCluster:
                    info_iso += '%s/%s\t' % (str(iso.mass()), str(iso.rt))
                for add in peak.fragCluster:
                    info_frag += '%s/%s\t' % (str(add.mass()), str(add.rt))
                model.setItem(i, 3, MSStandardItem(info_iso))
                model.setItem(i, 4, MSStandardItem(info_frag))
        return model
Exemple #16
0
    def getSampleModel(spl, flags='peak', **kw):
        from gui.MetBaseGui import MSStandardItem
        if flags not in ('peak', 'cluster', 'id'):
            return
        model = QStandardItemModel()
        if flags=='peak':
            from utils.misc import Hot
            areas=[peak.area for peak in spl.rawPeaks.ipeaks()]
            mxInt=max(areas)
            model.setHorizontalHeaderLabels(MSSample.peakModelLabel)

            for i, peak in enumerate(spl.rawPeaks.ipeaks()):
                model.setItem(i, 0, MSStandardItem(str(peak.mass())))
                model.item(i, 0).setBackground(QBrush(Hot._get_color(areas[i]/mxInt, True, alpha=0.5)))

                model.setItem(i, 1, MSStandardItem(str(peak.rt)))
                model.item(i, 1).setBackground(QBrush(Hot._get_color(areas[i]/mxInt, True, alpha=0.5)))

                model.setItem(i, 2, MSStandardItem(str(peak.area)))
                model.item(i, 2).setBackground(QBrush(Hot._get_color(areas[i]/mxInt, True, alpha=0.5)))

                model.setItem(i, 3, MSStandardItem(str(peak.sn)))
                model.item(i, 3).setBackground(QBrush(Hot._get_color(areas[i]/mxInt, True, alpha=0.5)))

                model.setItem(i, 4, MSStandardItem(str(peak.r_coef)))
                model.item(i, 4).setBackground(QBrush(Hot._get_color(areas[i]/mxInt, True, alpha=0.5)))

        elif flags=='cluster':
            model.setHorizontalHeaderLabels(MSSample.clusterModelLabel)
            for i, peak in enumerate(spl.mappedPeaks.ipeaks()):
                model.setItem(i, 0, MSStandardItem(str(peak.mass())))
                model.setItem(i, 1, MSStandardItem(str(peak.rt)))
                model.setItem(i, 2, MSStandardItem(str(peak.area)))
                info_iso ="";info_frag=""
                for iso in peak.isoCluster:
                    info_iso += '%s/%s\t'%(str(iso.mass()),str(iso.rt))
                for add in peak.fragCluster:
                    info_frag += '%s/%s\t'%(str(add.mass()),str(add.rt))
                model.setItem(i, 3, MSStandardItem(info_iso))
                model.setItem(i, 4, MSStandardItem(info_frag))
        return model
 def __init__(self, data, parent=None):
     """Constructor."""
     super(GDALLocationInfoForm, self).__init__(parent)
     self.setupUi(self)
     
     self.treeView.setSelectionBehavior(QAbstractItemView.SelectRows)
     
     model = QStandardItemModel()
     model.setHorizontalHeaderLabels([self.tr('object/attribute'), self.tr('value')])
     
     self.treeView.setModel(model)
     self.treeView.setUniformRowHeights(True)
     
     
     for object_name, object_attrs in data.items():
         parent = QStandardItem(object_name)
         for attr_name, attr_value in object_attrs.items():
             attr_name_item = QStandardItem(attr_name)
             attr_value_item = QStandardItem(attr_value)
             parent.appendRow([attr_name_item, attr_value_item])
         model.appendRow(parent)
Exemple #18
0
class EntryList:
    def __init__(self, filename=None):
        self.scopes = {}
        self.topLevelEntries = []
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(["Name", "File", "Line", "Type"])
        
        if filename:
            self.readFromFile(filename)
        
    def readFromFile(self, filename):
        self.scopes = {}
        self.topLevelEntries = []
        self.model.clear()
        self.model.setHorizontalHeaderLabels(["Name", "File", "Line", "Type"])
        
        e = ctags.TagEntry()
        tf = ctags.CTags(filename)
        while tf.next(e):
            self.addFromTagEntry(e)
    
    def getScope(self, scope):
        hier = scope.split("::")
        for s in range(len(hier)):
            scopename = "::".join(hier[0:s+1])
            if scopename not in self.scopes:
                self.scopes[scopename] = Struct(self)
        return self.scopes[scope]

    def addFromTagEntry(self, e):
        kind = e['kind']
        name = e['name']
        file_ = e['file']
        lineNumber = int(e['lineNumber'])
        if e['struct']:
            scope = e['struct']
        elif e['class']:
            scope = e['class']
        else:
            scope = None
        
        # Only add a class/struct if it wasn't present in the file before; this
        # can happen if there are template specializations such as myclass and
        # myclass<T>, which are both represented as myclass in the file. If the
        # entry is present, it will have a line number, so use that as a
        # heuristic ;).
        add = True
        if kind == "class":
            n = self.getScope(scope+"::"+name if scope else name)
            if n.lineNumber == None:
                n.setValues(name, file_, lineNumber, scope, Struct.CLASS)
            else:
                add = False
        elif kind == "struct":
            n = self.getScope(scope+"::"+name if scope else name)
            if n.lineNumber == None:
                n.setValues(name, file_, lineNumber, scope, Struct.STRUCT)
            else:
                add = False
        elif kind == "function":
            n = Function(self)
            n.setValues(name, file_, lineNumber, scope, e['signature'])
        elif kind == "member" and scope: # namespace members are declared as member, but don't have a scope
            n = Member(self)
            n.setValues(name, file_, lineNumber, scope, {"private": Member.PRIVATE, "protected": Member.PROTECTED, "public": Member.PUBLIC, None: None}[e['access']])
        else:
            n = Entry(self)
            n.setValues(name, file_, lineNumber, scope)
        if add:
            n.addToParent()
Exemple #19
0
class OWTestLearners(widget.OWWidget):
    name = "Test & Score"
    description = "Cross-validation accuracy estimation."
    icon = "icons/TestLearners1.svg"
    priority = 100

    inputs = [("Learner", Learner,
               "set_learner", widget.Multiple),
              ("Data", Table, "set_train_data", widget.Default),
              ("Test Data", Table, "set_test_data"),
              ("Preprocessor", Preprocess, "set_preprocessor")]

    outputs = [("Predictions", Orange.data.Table),
               ("Evaluation Results", Orange.evaluation.Results)]

    settingsHandler = settings.ClassValuesContextHandler()

    #: Resampling/testing types
    KFold, LeaveOneOut, ShuffleSplit, TestOnTrain, TestOnTest = 0, 1, 2, 3, 4

    #: Selected resampling type
    resampling = settings.Setting(0)
    #: Number of folds for K-fold cross validation
    k_folds = settings.Setting(10)
    #: Number of repeats for ShuffleSplit sampling
    n_repeat = settings.Setting(10)
    #: ShuffleSplit sampling p
    sample_p = settings.Setting(75)

    TARGET_AVERAGE = "(Average over classes)"
    class_selection = settings.ContextSetting(TARGET_AVERAGE)

    def __init__(self):
        super().__init__()

        self.data = None
        self.test_data = None
        self.preprocessor = None
        self.train_data_missing_vals = False
        self.test_data_missing_vals = False

        #: An Ordered dictionary with current inputs and their testing
        #: results.
        self.learners = OrderedDict()

        sbox = gui.widgetBox(self.controlArea, "Sampling")
        rbox = gui.radioButtons(
            sbox, self, "resampling", callback=self._param_changed
        )
        gui.appendRadioButton(rbox, "Cross validation")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox, self, "k_folds", 2, 50, label="Number of folds:",
                 callback=self.kfold_changed)
        gui.appendRadioButton(rbox, "Leave one out")
        gui.appendRadioButton(rbox, "Random sampling")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox, self, "n_repeat", 2, 50, label="Repeat train/test",
                 callback=self.shuffle_split_changed)
        gui.widgetLabel(ibox, "Relative training set size:")
        gui.hSlider(ibox, self, "sample_p", minValue=1, maxValue=99,
                    ticks=20, vertical=False, labelFormat="%d %%",
                    callback=self.shuffle_split_changed)

        gui.appendRadioButton(rbox, "Test on train data")
        gui.appendRadioButton(rbox, "Test on test data")

        rbox.layout().addSpacing(5)
        self.apply_button = gui.button(
            rbox, self, "Apply", callback=self.apply, default=True)

        self.cbox = gui.widgetBox(self.controlArea, "Target class")
        self.class_selection_combo = gui.comboBox(
            self.cbox, self, "class_selection", items=[],
            sendSelectedValue=True, valueType=str,
            callback=self._on_target_class_changed,
            contentsLength=8)

        gui.rubber(self.controlArea)

        self.view = QTreeView(
            rootIsDecorated=False,
            uniformRowHeights=True,
            wordWrap=True,
            editTriggers=QTreeView.NoEditTriggers
        )
        header = self.view.header()
        header.setResizeMode(QHeaderView.ResizeToContents)
        header.setDefaultAlignment(Qt.AlignCenter)
        header.setStretchLastSection(False)

        self.result_model = QStandardItemModel(self)
        self.result_model.setHorizontalHeaderLabels(["Method"])
        self.view.setModel(self.result_model)
        self.view.setItemDelegate(ItemDelegate())

        box = gui.widgetBox(self.mainArea, "Evaluation Results")
        box.layout().addWidget(self.view)

    def sizeHint(self):
        return QSize(780, 1)

    def set_learner(self, learner, key):
        """
        Set the input `learner` for `key`.
        """
        if key in self.learners and learner is None:
            # Removed
            del self.learners[key]
        else:
            self.learners[key] = Input(learner, None, None)
            self._invalidate([key])

    def set_train_data(self, data):
        """
        Set the input training dataset.
        """
        self.error(0)
        self.information(0)
        if data and not data.domain.class_var:
            self.error(0, "Train data input requires a class variable")
            data = None

        if isinstance(data, SqlTable):
            if data.approx_len() < AUTO_DL_LIMIT:
                data = Table(data)
            else:
                self.information(0, "Train data has been sampled")
                data_sample = data.sample_time(1, no_cache=True)
                data_sample.download_data(AUTO_DL_LIMIT, partial=True)
                data = Table(data_sample)

        self.warning(4)
        self.train_data_missing_vals = data is not None and \
                                       np.isnan(data.Y).any()
        if self.train_data_missing_vals or self.test_data_missing_vals:
            self.warning(4, self._get_missing_data_warning(
                self.train_data_missing_vals, self.test_data_missing_vals
            ))
            if data:
                data = RemoveNaNClasses(data)

        self.data = data
        self.closeContext()
        if data is not None:
            self._update_class_selection()
            self.openContext(data.domain.class_var)
        self._invalidate()

    def set_test_data(self, data):
        """
        Set the input separate testing dataset.
        """
        self.error(1)
        self.information(1)
        if data and not data.domain.class_var:
            self.error(1, "Test data input requires a class variable")
            data = None

        if isinstance(data, SqlTable):
            if data.approx_len() < AUTO_DL_LIMIT:
                data = Table(data)
            else:
                self.information(1, "Test data has been sampled")
                data_sample = data.sample_time(1, no_cache=True)
                data_sample.download_data(AUTO_DL_LIMIT, partial=True)
                data = Table(data_sample)

        self.warning(4)
        self.test_data_missing_vals = data is not None and \
                                      np.isnan(data.Y).any()
        if self.train_data_missing_vals or self.test_data_missing_vals:
            self.warning(4, self._get_missing_data_warning(
                self.train_data_missing_vals, self.test_data_missing_vals
            ))
            if data:
                data = RemoveNaNClasses(data)

        self.test_data = data
        if self.resampling == OWTestLearners.TestOnTest:
            self._invalidate()

    def _get_missing_data_warning(self, train_missing, test_missing):
        return "Instances with unknown target values were removed from{}data"\
            .format(train_missing * test_missing * " "
                    or train_missing * " train " or test_missing * " test ")

    def set_preprocessor(self, preproc):
        """
        Set the input preprocessor to apply on the training data.
        """
        self.preprocessor = preproc
        self._invalidate()

    def handleNewSignals(self):
        """Reimplemented from OWWidget.handleNewSignals."""
        self._update_class_selection()
        self.apply()

    def kfold_changed(self):
        self.resampling = OWTestLearners.KFold
        self._param_changed()

    def shuffle_split_changed(self):
        self.resampling = OWTestLearners.ShuffleSplit
        self._param_changed()

    def _param_changed(self):
        self._invalidate()

    def _update_results(self):
        """
        Run/evaluate the learners.
        """
        self.warning([1, 2])
        self.error(2)

        if self.data is None:
            return

        class_var = self.data.domain.class_var

        if self.resampling == OWTestLearners.TestOnTest:
            if self.test_data is None:
                self.warning(2, "Missing separate test data input")
                return
            elif self.test_data.domain.class_var != class_var:
                self.error(2, ("Inconsistent class variable between test " +
                               "and train data sets"))
                return

        # items in need of an update
        items = [(key, slot) for key, slot in self.learners.items()
                 if slot.results is None]
        learners = [slot.learner for _, slot in items]
        if len(items) == 0:
            return

        if self.test_data is not None and \
                self.resampling != OWTestLearners.TestOnTest:
            self.warning(1, "Test data is present but unused. "
                            "Select 'Test on test data' to use it.")

        rstate = 42
        def update_progress(finished):
            self.progressBarSet(100 * finished)
        common_args = dict(
            store_data=True,
            preprocessor=self.preprocessor,
            callback=update_progress)
        self.setStatusMessage("Running")
        self.progressBarInit()

        try:
            if self.resampling == OWTestLearners.KFold:
                warnings = []
                results = Orange.evaluation.CrossValidation(
                    self.data, learners, k=self.k_folds, random_state=rstate,
                    warnings=warnings, **common_args)
                if warnings:
                    self.warning(2, warnings[0])
            elif self.resampling == OWTestLearners.LeaveOneOut:
                results = Orange.evaluation.LeaveOneOut(
                    self.data, learners, **common_args)
            elif self.resampling == OWTestLearners.ShuffleSplit:
                train_size = self.sample_p / 100
                results = Orange.evaluation.ShuffleSplit(
                    self.data, learners, n_resamples=self.n_repeat,
                    train_size=train_size, test_size=None,
                    random_state=rstate, **common_args)
            elif self.resampling == OWTestLearners.TestOnTrain:
                results = Orange.evaluation.TestOnTrainingData(
                    self.data, learners, **common_args)
            elif self.resampling == OWTestLearners.TestOnTest:
                results = Orange.evaluation.TestOnTestData(
                    self.data, self.test_data, learners, **common_args)
            else:
                assert False
        except RuntimeError as e:
            self.error(2, str(e))
            self.setStatusMessage("")
            self.progressBarFinished()
            return

        learner_key = {slot.learner: key for key, slot in self.learners.items()}
        for learner, result in zip(learners, split_by_model(results)):
            stats = None
            if class_var.is_discrete:
                scorers = classification_stats.scores
            elif class_var.is_continuous:
                scorers = regression_stats.scores
            else:
                scorers = None
            if scorers:
                ex = result.failed[0]
                if ex:
                    stats = [Try.Fail(ex)] * len(scorers)
                    result = Try.Fail(ex)
                else:
                    stats = [Try(lambda: score(result)) for score in scorers]
                    result = Try.Success(result)
            key = learner_key[learner]
            self.learners[key] = \
                self.learners[key]._replace(results=result, stats=stats)

        self.setStatusMessage("")
        self.progressBarFinished()

    def _update_header(self):
        # Set the correct horizontal header labels on the results_model.
        headers = ["Method"]
        if self.data is not None:
            if self.data.domain.has_discrete_class:
                headers.extend(classification_stats.headers)
            else:
                headers.extend(regression_stats.headers)

        # remove possible extra columns from the model.
        for i in reversed(range(len(headers),
                                self.result_model.columnCount())):
            self.result_model.takeColumn(i)

        self.result_model.setHorizontalHeaderLabels(headers)

    def _update_stats_model(self):
        # Update the results_model with up to date scores.
        # Note: The target class specific scores (if requested) are
        # computed as needed in this method.
        model = self.view.model()
        # clear the table model, but preserving the header labels
        for r in reversed(range(model.rowCount())):
            model.takeRow(r)

        target_index = None
        if self.data is not None:
            class_var = self.data.domain.class_var
            if class_var.is_discrete and \
                    self.class_selection != self.TARGET_AVERAGE:
                target_index = class_var.values.index(self.class_selection)
        else:
            class_var = None

        errors = []
        has_missing_scores = False

        for key, slot in self.learners.items():
            name = learner_name(slot.learner)
            head = QStandardItem(name)
            head.setData(key, Qt.UserRole)
            if isinstance(slot.results, Try.Fail):
                head.setToolTip(str(slot.results.exception))
                head.setText("{} (error)".format(name))
                head.setForeground(QtGui.QBrush(Qt.red))
                errors.append("{name} failed with error:\n"
                              "{exc.__class__.__name__}: {exc!s}"
                              .format(name=name, exc=slot.results.exception))

            row = [head]

            if class_var is not None and class_var.is_discrete and \
                    target_index is not None:
                if slot.results is not None and slot.results.success:
                    ovr_results = results_one_vs_rest(
                        slot.results.value, target_index)

                    stats = [Try(lambda: score(ovr_results))
                             for score in classification_stats.scores]
                else:
                    stats = None
            else:
                stats = slot.stats

            if stats is not None:
                for stat in stats:
                    item = QStandardItem()
                    if stat.success:
                        item.setText("{:.3f}".format(stat.value[0]))
                    else:
                        item.setToolTip(str(stat.exception))
                        has_missing_scores = True
                    row.append(item)

            model.appendRow(row)

        if errors:
            self.error(3, "\n".join(errors))
        else:
            self.error(3)

        if has_missing_scores:
            self.warning(3, "Some scores could not be computed")
        else:
            self.warning(3)

    def _update_class_selection(self):
        self.class_selection_combo.setCurrentIndex(-1)
        self.class_selection_combo.clear()
        if not self.data:
            return

        if self.data.domain.has_discrete_class:
            self.cbox.setVisible(True)
            class_var = self.data.domain.class_var
            items = [self.TARGET_AVERAGE] + class_var.values
            self.class_selection_combo.addItems(items)

            class_index = 0
            if self.class_selection in class_var.values:
                class_index = class_var.values.index(self.class_selection) + 1

            self.class_selection_combo.setCurrentIndex(class_index)
            self.class_selection = items[class_index]
        else:
            self.cbox.setVisible(False)

    def _on_target_class_changed(self):
        self._update_stats_model()

    def _invalidate(self, which=None):
        # Invalidate learner results for `which` input keys
        # (if None then all learner results are invalidated)
        if which is None:
            which = self.learners.keys()

        model = self.view.model()
        statmodelkeys = [model.item(row, 0).data(Qt.UserRole)
                         for row in range(model.rowCount())]

        for key in which:
            self.learners[key] = \
                self.learners[key]._replace(results=None, stats=None)

            if key in statmodelkeys:
                row = statmodelkeys.index(key)
                for c in range(1, model.columnCount()):
                    item = model.item(row, c)
                    if item is not None:
                        item.setData(None, Qt.DisplayRole)
                        item.setData(None, Qt.ToolTipRole)

        self.apply_button.setEnabled(True)

    def apply(self):
        self.apply_button.setEnabled(False)
        self._update_header()
        # Update the view to display the model names
        self._update_stats_model()
        self._update_results()
        self._update_stats_model()
        self.commit()

    def commit(self):
        valid = [slot for slot in self.learners.values()
                 if slot.results is not None and slot.results.success]
        if valid:
            # Evaluation results
            combined = results_merge([slot.results.value for slot in valid])
            combined.learner_names = [learner_name(slot.learner)
                                      for slot in valid]

            # Predictions & Probabilities
            predictions = combined.get_augmented_data(combined.learner_names)
        else:
            combined = None
            predictions = None
        self.send("Evaluation Results", combined)
        self.send("Predictions", predictions)
class ConnectionsDialog(QtGui.QDialog, Ui_DlgConnections):

    on_connect = pyqtSignal(str, str)
    on_add = pyqtSignal(str, list)
    on_connection_change = pyqtSignal()
    on_zoom_change = pyqtSignal()

    _connections_array = "connections"
    _table_headers = OrderedDict([("ID", "id"), ("Min. Zoom", "minzoom"),
                                  ("Max. Zoom", "maxzoom"),
                                  ("Description", "description")])

    _OMT = "OpenMapTiles.com"

    _predefined_connections = {
        _OMT: "https://free.tilehosting.com/data/v3.json?key={token}"
    }
    _tokens = {_OMT: "6irhAXGgsi8TrIDL0211"}

    def __init__(self, default_browse_directory):
        QtGui.QDialog.__init__(self)
        self.setupUi(self)
        self.options = OptionsGroup(self.grpOptions, self._on_zoom_change)
        self.settings = QSettings("VtrSettings")
        self.connections = {}
        self.selected_connection = None
        self.selected_layer_id = None
        self.cbxConnections.currentIndexChanged['QString'].connect(
            self._handle_connection_change)
        self.btnCreateConnection.clicked.connect(self._create_connection)
        self.btnConnect.clicked.connect(self._handle_connect)
        self.btnEdit.clicked.connect(self._edit_connection)
        self.btnDelete.clicked.connect(self._delete_connection)
        self.btnAdd.clicked.connect(self._load_tiles_for_connection)
        self.btnSave.clicked.connect(self._export_connections)
        self.btnLoad.clicked.connect(self._import_connections)
        self.btnHelp.clicked.connect(lambda: webbrowser.open(_HELP_URL))
        self.btnBrowse.clicked.connect(self._select_file_path)
        self.btnBrowseTrexCache.clicked.connect(self._select_trex_cache_folder)
        self.open_path = None
        self.browse_path = default_browse_directory
        self.model = QStandardItemModel()
        self.model.setHorizontalHeaderLabels(self._table_headers.keys())
        self.tblLayers.setModel(self.model)
        self._load_connections()
        self._add_loaded_connections()
        self.edit_connection_dialog = EditConnectionDialog()
        _update_size(self)

    def _select_file_path(self):
        open_file_name = QFileDialog.getOpenFileName(
            None, "Select Mapbox Tiles", self.browse_path,
            "Mapbox Tiles (*.mbtiles)")
        if open_file_name and os.path.isfile(open_file_name):
            self.txtPath.setText(open_file_name)
            self._handle_path_or_folder_selection(open_file_name)

    def _select_trex_cache_folder(self):
        open_file_name = QFileDialog.getExistingDirectory(
            None, "Select t-rex Cache directory", self.browse_path)
        if open_file_name and os.path.isdir(open_file_name):
            self.txtTrexCachePath.setText(open_file_name)
            self._handle_path_or_folder_selection(open_file_name)

    def _handle_path_or_folder_selection(self, path):
        self.browse_path = path
        self.open_path = path
        name = os.path.basename(path)
        self.on_connect.emit(name, path)

    def _on_zoom_change(self):
        self.on_zoom_change.emit()

    def set_nr_of_tiles(self, nr_tiles):
        self.options.set_nr_of_tiles(nr_tiles)

    def _load_tiles_for_connection(self):
        indexes = self.tblLayers.selectionModel().selectedRows()
        selected_layers = map(lambda i: self.model.item(i.row()).text(),
                              indexes)
        name, url = self._get_current_connection()
        self.on_add.emit(url, selected_layers)

    def _export_connections(self):
        file_name = QFileDialog.getSaveFileName(
            None, "Export Vector Tile Reader Connections", "", "csv (*.csv)")
        if file_name:
            with open(file_name, 'w') as csvfile:
                fieldnames = ['name', 'url']
                writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
                writer.writeheader()
                for name in self.connections:
                    writer.writerow({
                        'name': name,
                        'url': self.connections[name]
                    })

    def _import_connections(self):
        file_name = QFileDialog.getOpenFileName(
            None, "Export Vector Tile Reader Connections", "", "csv (*.csv)")
        if file_name:
            with open(file_name, 'r') as csvfile:
                reader = csv.DictReader(csvfile)
                for row in reader:
                    self._set_connection_url(row['name'], row['url'])
            self._add_loaded_connections()

    def _load_connections(self):
        settings = self.settings
        connections = settings.beginReadArray(self._connections_array)
        for i in range(connections):
            settings.setArrayIndex(i)
            name = settings.value("name")
            url = settings.value("url")
            self._set_connection_url(name, url)
        settings.endArray()

    def _add_loaded_connections(self):
        for index, name in enumerate(self._predefined_connections.keys()):
            url = self._predefined_connections[name]
            self._set_connection_url(name, url)

        for name in sorted(self.connections):
            is_already_added = self.cbxConnections.findText(name) != -1
            if not is_already_added:
                self.cbxConnections.addItem(name)
        if len(self.connections) > 0:
            self.cbxConnections.setCurrentIndex(0)

    def _delete_connection(self):
        index = self.cbxConnections.currentIndex()
        connection = self.cbxConnections.currentText()
        msg = "Are you sure you want to remove the connection '{}' and all associated settings?".format(
            connection)
        reply = QMessageBox.question(self.activateWindow(), 'Confirm Delete',
                                     msg, QMessageBox.Yes, QMessageBox.No)
        if reply == QtGui.QMessageBox.Yes:
            self.cbxConnections.removeItem(index)
            self.connections.pop(connection)
            self._save_connections()

    def _save_connections(self):
        settings = self.settings
        settings.beginWriteArray(self._connections_array)
        for index, key in enumerate(self.connections):
            settings.setArrayIndex(index)
            settings.setValue("name", key)
            settings.setValue("url", self.connections[key])
        settings.endArray()

    def _set_connection_url(self, name, url):
        self.connections[name] = url

    def _handle_connect(self):
        conn = self._get_current_connection()
        name = conn[0]
        url = conn[1]
        self.on_connect.emit(name, url)
        self.txtPath.setText("")

    def _get_current_connection(self):
        if self.tabServer.isEnabled():
            name = self.cbxConnections.currentText()
            url = self.connections[name]
        elif self.tabFile.isEnabled():
            url = self.txtPath.text()
            name = os.path.basename(url)
        else:
            url = self.txtTrexCachePath.text()
            name = os.path.basename(url)
        if name in self._predefined_connections:
            url = url.replace("{token}", self._tokens[name])
        return name, url

    def show(self):
        self.exec_()

    def keep_dialog_open(self):
        return self.chkKeepOpen.isChecked()

    def set_layers(self, layers):
        self.model.removeRows(0, self.model.rowCount())
        for row_index, layer in enumerate(layers):
            for header_index, header in enumerate(self._table_headers.keys()):
                header_value = self._table_headers[header]
                if header_value in layer:
                    value = str(layer[header_value])
                else:
                    value = "-"
                self.model.setItem(row_index, header_index,
                                   QStandardItem(value))
        add_enabled = layers is not None and len(layers) > 0
        self.btnAdd.setEnabled(add_enabled)

    def _edit_connection(self):
        conn = self._get_current_connection()
        self._create_or_update_connection(name=conn[0], url=conn[1])

    def _create_connection(self):
        self._create_or_update_connection("", "")

    def _create_or_update_connection(self, name=None, url=None):
        self.edit_connection_dialog.set_name_and_path(name, url)
        result = self.edit_connection_dialog.exec_()
        if result == QtGui.QDialog.Accepted:
            newname, newurl = self.edit_connection_dialog.get_connection()
            self._set_connection_url(newname, newurl)
            if newname != name:
                self.cbxConnections.addItem(newname)
                self.cbxConnections.setCurrentIndex(len(self.connections) - 1)
            self._save_connections()

    def _handle_connection_change(self, name):
        self.set_layers([])
        enable_connect = False
        enable_edit = False
        if name in self.connections:
            enable_connect = True
            enable_edit = name not in self._predefined_connections
        self.btnConnect.setEnabled(enable_connect)
        self.btnEdit.setEnabled(enable_edit)
        self.btnDelete.setEnabled(enable_edit)
        self.on_connection_change.emit()
 def table(window):
     tw = TableWidget(window, "Enter", foo, useTextEdit=False)
     model = QStandardItemModel(tw)
     model.setHorizontalHeaderLabels([u"foo", u"bar"])
     tw.setModel(model)
     return tw
Exemple #22
0
class ProgramInfoFiles(QWidget, Ui_ProgramInfoFiles):
    def __init__(self, context, update_main_ui_state, set_widget_enabled,
                 is_alive, show_upload_files_wizard, show_download_wizard):
        QWidget.__init__(self)

        self.setupUi(self)

        self.session = context.session
        self.script_manager = context.script_manager
        self.program = context.program
        self.update_main_ui_state = update_main_ui_state
        self.set_widget_enabled = set_widget_enabled
        self.is_alive = is_alive
        self.show_download_wizard = show_download_wizard
        self.bin_directory = posixpath.join(self.program.root_directory, 'bin')
        self.refresh_in_progress = False
        self.any_refresh_in_progress = False  # set from ProgramInfoMain.update_ui_state
        self.available_files = []
        self.available_directories = []
        self.folder_icon = QIcon(load_pixmap('folder-icon.png'))
        self.file_icon = QIcon(load_pixmap('file-icon.png'))
        self.tree_files_model = QStandardItemModel(self)
        self.tree_files_model_header = ['Name', 'Size', 'Last Modified']
        self.tree_files_proxy_model = FilesProxyModel(self)
        self.last_download_directory = get_home_path()

        self.tree_files_model.setHorizontalHeaderLabels(
            self.tree_files_model_header)
        self.tree_files_proxy_model.setSourceModel(self.tree_files_model)
        self.tree_files.setModel(self.tree_files_model)
        self.tree_files.setModel(self.tree_files_proxy_model)
        self.tree_files.setColumnWidth(0, 210)
        self.tree_files.setColumnWidth(1, 85)

        self.tree_files.selectionModel().selectionChanged.connect(
            self.update_ui_state)
        self.tree_files.activated.connect(self.rename_activated_file)
        self.button_upload_files.clicked.connect(show_upload_files_wizard)
        self.button_download_files.clicked.connect(
            self.download_selected_files)
        self.button_rename_file.clicked.connect(self.rename_selected_file)
        self.button_delete_files.clicked.connect(self.delete_selected_files)

        self.label_error.setVisible(False)

    def update_ui_state(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        self.set_widget_enabled(self.button_upload_files,
                                not self.any_refresh_in_progress)
        self.set_widget_enabled(
            self.button_download_files, not self.any_refresh_in_progress
            and selection_count > 0)
        self.set_widget_enabled(
            self.button_rename_file, not self.any_refresh_in_progress
            and selection_count == 1)
        self.set_widget_enabled(
            self.button_delete_files, not self.any_refresh_in_progress
            and selection_count > 0)

    def close_all_dialogs(self):
        pass

    def refresh_files_done(self):
        self.refresh_in_progress = False
        self.update_main_ui_state()

    def refresh_files(self):
        def cb_walk(result):
            okay, message = check_script_result(result, decode_stderr=True)

            if not okay:
                self.label_error.setText('<b>Error:</b> ' + Qt.escape(message))
                self.label_error.setVisible(True)
                self.refresh_files_done()
                return

            self.label_error.setVisible(False)

            def expand_async(data):
                try:
                    walk = json.loads(
                        zlib.decompress(buffer(data)).decode('utf-8'))
                except:
                    walk = None

                if walk == None or not isinstance(walk, dict):
                    available_files = []
                    available_directories = []
                    walk = None
                else:
                    available_files, available_directories = expand_walk_to_lists(
                        walk)

                return walk, available_files, available_directories

            def cb_expand_success(result):
                walk, available_files, available_directories = result

                self.available_files = available_files
                self.available_directories = available_directories

                if walk != None:
                    expand_walk_to_model(walk, self.tree_files_model,
                                         self.folder_icon, self.file_icon)
                else:
                    self.label_error.setText(
                        '<b>Error:</b> Received invalid data')
                    self.label_error.setVisible(True)

                self.tree_files.header().setSortIndicator(0, Qt.AscendingOrder)
                self.refresh_files_done()

            def cb_expand_error():
                self.label_error.setText('<b>Error:</b> Internal async error')
                self.label_error.setVisible(True)
                self.refresh_files_done()

            async_call(expand_async, result.stdout, cb_expand_success,
                       cb_expand_error)

        self.refresh_in_progress = True
        self.update_main_ui_state()

        width1 = self.tree_files.columnWidth(0)
        width2 = self.tree_files.columnWidth(1)

        self.tree_files_model.clear()
        self.tree_files_model.setHorizontalHeaderLabels(
            self.tree_files_model_header)
        self.tree_files.setColumnWidth(0, width1)
        self.tree_files.setColumnWidth(1, width2)

        self.script_manager.execute_script('walk',
                                           cb_walk, [self.bin_directory],
                                           max_length=1024 * 1024,
                                           decode_output_as_utf8=False)

    def get_directly_selected_name_items(self):
        selected_indexes = self.tree_files.selectedIndexes()
        selected_name_items = []

        for selected_index in selected_indexes:
            if selected_index.column() == 0:
                mapped_index = self.tree_files_proxy_model.mapToSource(
                    selected_index)
                selected_name_items.append(
                    self.tree_files_model.itemFromIndex(mapped_index))

        return selected_name_items

    def download_selected_files(self):
        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) == 0:
            return

        downloads = []

        def expand(name_item):
            item_type = name_item.data(USER_ROLE_ITEM_TYPE)

            if item_type == ITEM_TYPE_DIRECTORY:
                for i in range(name_item.rowCount()):
                    expand(name_item.child(i, 0))
            elif item_type == ITEM_TYPE_FILE:
                filename = get_full_item_path(name_item)

                downloads.append(
                    Download(filename, QDir.toNativeSeparators(filename)))

        for selected_name_item in selected_name_items:
            expand(selected_name_item)

        if len(downloads) == 0:
            return

        download_directory = get_existing_directory(
            get_main_window(), 'Download Files', self.last_download_directory)

        if len(download_directory) == 0:
            return

        self.last_download_directory = download_directory

        self.show_download_wizard('files', download_directory, downloads)

    def rename_activated_file(self, index):
        if index.column() == 0 and not self.any_refresh_in_progress:
            mapped_index = self.tree_files_proxy_model.mapToSource(index)
            name_item = self.tree_files_model.itemFromIndex(mapped_index)
            item_type = name_item.data(USER_ROLE_ITEM_TYPE)

            # only rename files via activation, because directories are expanded
            if item_type == ITEM_TYPE_FILE:
                self.rename_item(name_item)

    def rename_selected_file(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        if selection_count != 1:
            return

        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) != 1:
            return

        self.rename_item(selected_name_items[0])

    def rename_item(self, name_item):
        item_type = name_item.data(USER_ROLE_ITEM_TYPE)

        if item_type == ITEM_TYPE_FILE:
            title = 'Rename File'
            type_name = 'file'
        else:
            title = 'Rename Directory'
            type_name = 'directory'

        old_name = name_item.text()

        # get new name
        dialog = ExpandingInputDialog(get_main_window())
        dialog.setModal(True)
        dialog.setWindowTitle(title)
        dialog.setLabelText('Enter new {0} name:'.format(type_name))
        dialog.setInputMode(QInputDialog.TextInput)
        dialog.setTextValue(old_name)
        dialog.setOkButtonText('Rename')

        if dialog.exec_() != QDialog.Accepted:
            return

        new_name = dialog.textValue()

        if new_name == old_name:
            return

        # check that new name is valid
        if len(
                new_name
        ) == 0 or new_name == '.' or new_name == '..' or '/' in new_name:
            QMessageBox.critical(
                get_main_window(), title + ' Error',
                'A {0} name cannot be empty, cannot be one dot [.], cannot be two dots [..] and cannot contain a forward slash [/].'
                .format(type_name))
            return

        # check that new name is not already in use
        name_item_parent = name_item.parent()

        if name_item_parent == None:
            name_item_parent = self.tree_files_model.invisibleRootItem()

        for i in range(name_item_parent.rowCount()):
            if new_name == name_item_parent.child(i).text():
                QMessageBox.critical(
                    get_main_window(), title + ' Error',
                    'The new {0} name is already in use.'.format(type_name))
                return

        absolute_old_name = posixpath.join(self.bin_directory,
                                           get_full_item_path(name_item))
        absolute_new_name = posixpath.join(
            posixpath.split(absolute_old_name)[0], new_name)

        def cb_rename(result):
            if not report_script_result(
                    result, title + ' Error',
                    u'Could not rename {0}'.format(type_name)):
                return

            name_item.setText(new_name)

            if self.tree_files.header().sortIndicatorSection() == 0:
                self.tree_files.header().setSortIndicator(
                    0,
                    self.tree_files.header().sortIndicatorOrder())

        self.script_manager.execute_script(
            'rename', cb_rename, [absolute_old_name, absolute_new_name])

    def delete_selected_files(self):
        button = QMessageBox.question(
            get_main_window(), 'Delete Files',
            'Irreversibly deleting selected files and directories.',
            QMessageBox.Ok, QMessageBox.Cancel)

        if not self.is_alive() or button != QMessageBox.Ok:
            return

        selected_name_items = set(self.get_directly_selected_name_items())

        if len(selected_name_items) == 0:
            return

        script_instance_ref = [None]

        def progress_canceled():
            script_instance = script_instance_ref[0]

            if script_instance == None:
                return

            self.script_manager.abort_script(script_instance)

        progress = ExpandingProgressDialog(self)
        progress.set_progress_text_visible(False)
        progress.setModal(True)
        progress.setWindowTitle('Delete Files')
        progress.setLabelText('Collecting files and directories to delete')
        progress.setRange(0, 0)
        progress.canceled.connect(progress_canceled)
        progress.show()

        files_to_delete = []
        dirs_to_delete = []
        all_done = False

        while not all_done:
            all_done = True

            for selected_name_item in list(selected_name_items):
                item_done = False
                parent = selected_name_item.parent()

                while not item_done and parent != None:
                    if parent in selected_name_items:
                        selected_name_items.remove(selected_name_item)
                        item_done = True
                    else:
                        parent = parent.parent()

                if item_done:
                    all_done = False
                    break

        for selected_name_item in selected_name_items:
            path = get_full_item_path(selected_name_item)
            item_type = selected_name_item.data(USER_ROLE_ITEM_TYPE)

            if item_type == ITEM_TYPE_DIRECTORY:
                dirs_to_delete.append(posixpath.join(self.bin_directory, path))
            else:
                files_to_delete.append(posixpath.join(self.bin_directory,
                                                      path))

        message = 'Deleting '

        if len(files_to_delete) == 1:
            message += '1 file '
        elif len(files_to_delete) > 1:
            message += '{0} files '.format(len(files_to_delete))

        if len(dirs_to_delete) == 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '1 directory'
        elif len(dirs_to_delete) > 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '{0} directories'.format(len(dirs_to_delete))

        progress.setLabelText(message)

        def cb_delete(result):
            script_instance = script_instance_ref[0]

            if script_instance != None:
                aborted = script_instance.abort
            else:
                aborted = False

            script_instance_ref[0] = None

            progress.cancel()
            self.refresh_files()

            if aborted:
                QMessageBox.information(get_main_window(), 'Delete Files',
                                        u'Delete operation was aborted.')
                return

            report_script_result(
                result, 'Delete Files Error',
                'Could not delete selected files/directories:')

        script_instance_ref[0] = self.script_manager.execute_script(
            'delete',
            cb_delete,
            [json.dumps(files_to_delete),
             json.dumps(dirs_to_delete)],
            execute_as_user=True)
    def __init__(self, parent=None):
        super(LayerSelectionPage, self).__init__(parent)
        self.parent = parent

        #convenience link
        self.confconn_link = self.parent.parent.confconn

        #flag top prevent read read action on keyword delete. New logic makes this redundant
        #self.keywordbypass = False

        QToolTip.setFont(QFont('SansSerif', 10))

        #label
        filterlabel = QLabel('Filter')
        availablelabel = QLabel('Available Layers')
        selectionlabel = QLabel('Layer Selections')
        keywordlabel = QLabel('Keyword')
        explainlabel = QLabel(
            "Edit Group assignments using this dialog or to simply initialise the Layer-Config just click 'Finish'"
        )

        #selection buttons
        chooseallbutton = QPushButton('>>')
        chooseallbutton.setFixedWidth(self.XFER_BW)
        chooseallbutton.clicked.connect(self.doChooseAllClickAction)

        choosebutton = QPushButton('>')
        choosebutton.setFixedWidth(self.XFER_BW)
        choosebutton.clicked.connect(self.doChooseClickAction)

        rejectbutton = QPushButton('<')
        rejectbutton.setFixedWidth(self.XFER_BW)
        rejectbutton.clicked.connect(self.doRejectClickAction)

        rejectallbutton = QPushButton('<<')
        rejectallbutton.setFixedWidth(self.XFER_BW)
        rejectallbutton.clicked.connect(self.doRejectAllClickAction)

        #operation buttons
        finishbutton = QPushButton('Finish')
        finishbutton.setToolTip('Finish and Close layer selection dialog')
        finishbutton.clicked.connect(self.parent.close)

        resetbutton = QPushButton('Reset')
        resetbutton.font()
        resetbutton.setToolTip(
            'Read Layer from LDS GetCapabilities request. Overwrites current Layer Config'
        )
        resetbutton.clicked.connect(self.doResetClickAction)

        self.available_sfpm = LDSSFPAvailableModel(self)
        self.selection_sfpm = LDSSFPSelectionModel(self)

        self.available_sfpm.setSourceModel(self.parent.available_model)
        self.selection_sfpm.setSourceModel(self.parent.selection_model)

        #textedits
        filteredit = QLineEdit('')
        filteredit.setToolTip(
            'Filter Available-Layers pane (filter operates across Name and Title fields and accepts Regex expressions)'
        )
        filteredit.textChanged.connect(self.available_sfpm.setActiveFilter)

        self.keywordcombo = QComboBox()
        self.keywordcombo.setToolTip(
            'Select or Add a unique identifier to be saved in layer config (keyword)'
        )
        self.keywordcombo.addItems(list(self.confconn_link.assigned))
        self.keywordcombo.setEditable(True)
        self.keywordcombo.activated.connect(self.doKeyComboChangeAction)

        lgindex = self.confconn_link.getLayerGroupIndex(
            self.confconn_link.lgval, col=1)
        lgentry = self.confconn_link.lglist[lgindex] if LU.assessNone(
            lgindex) else None
        #keywordedit = self.keywordcombo.lineEdit().text().toUtf8().data().decode('utf8')# for writing
        #if no entry or layer indicated then blank
        self.keywordcombo.lineEdit().setText(
            '' if lgentry is None or lgentry[0] == LORG.LAYER else
            lgentry[1])  #self.confconn_link.lgval)#TODO. group only

        #header
        headmodel = QStandardItemModel()
        headmodel.setHorizontalHeaderLabels([
            i[2] for i in self.colparams
        ][:self.parent.available_model.columnCount()])

        headview1 = QHeaderView(Qt.Horizontal)
        headview1.setModel(headmodel)
        headview1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        headview2 = QHeaderView(Qt.Horizontal)
        headview2.setModel(headmodel)
        headview2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)

        #table
        self.available = QTableView()
        self.available.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.available.setSelectionMode(QAbstractItemView.MultiSelection)

        self.selection = QTableView()
        self.selection.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.selection.setSelectionMode(QAbstractItemView.MultiSelection)

        #interesting, must set model after selection attributes but before headers else row selections/headers don't work properly
        self.available.setModel(self.available_sfpm)
        self.selection.setModel(self.selection_sfpm)

        self.available.setSortingEnabled(True)
        self.available.setHorizontalHeader(headview1)

        self.selection.setSortingEnabled(True)
        self.selection.setHorizontalHeader(headview2)

        for cp in self.colparams:
            self.available.setColumnWidth(cp[0], cp[1])
            self.selection.setColumnWidth(cp[0], cp[1])

        self.available.verticalHeader().setVisible(False)
        self.available.horizontalHeader().setVisible(True)

        self.selection.verticalHeader().setVisible(False)
        self.selection.horizontalHeader().setVisible(True)

        #layout
        vbox00 = QVBoxLayout()
        vbox00.addWidget(availablelabel)
        vbox00.addWidget(self.available)

        vbox01 = QVBoxLayout()
        vbox01.addWidget(chooseallbutton)
        vbox01.addWidget(choosebutton)
        vbox01.addWidget(rejectbutton)
        vbox01.addWidget(rejectallbutton)

        vbox02 = QVBoxLayout()
        vbox02.addWidget(selectionlabel)
        vbox02.addWidget(self.selection)

        vbox10 = QVBoxLayout()
        vbox10.addWidget(filterlabel)
        vbox10.addWidget(filteredit)

        hbox12 = QHBoxLayout()
        hbox12.addWidget(keywordlabel)
        hbox12.addStretch(1)
        #hbox12.addWidget(inspbutton)
        #hbox12.addWidget(addbutton)
        #hbox12.addWidget(delbutton)

        vbox12 = QVBoxLayout()
        vbox12.addLayout(hbox12)
        vbox12.addWidget(self.keywordcombo)

        #00|01|02
        #10|11|12
        grid0 = QGridLayout()
        grid0.addLayout(vbox00, 1, 0)
        grid0.addLayout(vbox01, 1, 1)
        grid0.addLayout(vbox02, 1, 2)
        grid0.addLayout(vbox10, 0, 0)
        grid0.addLayout(vbox12, 0, 2)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(resetbutton)
        hbox2.addStretch(1)
        hbox2.addWidget(explainlabel)
        hbox2.addWidget(finishbutton)
        #gbox1.setLayout(hbox2)

        vbox3 = QVBoxLayout()
        vbox3.addLayout(grid0)
        #vbox3.addLayout(hbox3)
        #vbox3.addWidget(line0)
        vbox3.addLayout(hbox2)

        self.setLayout(vbox3)
Exemple #24
0
class MainWindow(QMainWindow, Ui_MainWindow):
    qtcb_enumerate = pyqtSignal(str, str, 'char', type((0,)), type((0,)), int, int)
    qtcb_connected = pyqtSignal(int)
    qtcb_disconnected = pyqtSignal(int)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)

        self.setupUi(self)

        signal.signal(signal.SIGINT, self.exit_brickv)
        signal.signal(signal.SIGTERM, self.exit_brickv)

        self.async_thread = async_start_thread(self)

        self.setWindowTitle("Brick Viewer " + config.BRICKV_VERSION)

        self.tree_view_model_labels = ['Name', 'UID', 'Position', 'FW Version']
        self.tree_view_model = QStandardItemModel(self)
        self.tree_view.setModel(self.tree_view_model)
        self.tree_view.doubleClicked.connect(self.item_double_clicked)
        self.set_tree_view_defaults()

        # Remove dummy tab
        self.tab_widget.removeTab(1)

        self.name = '<unknown>'
        self.uid = '<unknown>'
        self.version = (0, 0, 0)

        self.disconnect_times = []

        self.qtcb_enumerate.connect(self.cb_enumerate)
        self.qtcb_connected.connect(self.cb_connected)
        self.qtcb_disconnected.connect(self.cb_disconnected)

        self.ipcon = IPConnection()
        self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
                                     self.qtcb_enumerate.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
                                     self.qtcb_connected.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_DISCONNECTED,
                                     self.qtcb_disconnected.emit)

        self.current_device_info = None
        self.flashing_window = None
        self.advanced_window = None
        self.delayed_refresh_updates_timer = QTimer()
        self.delayed_refresh_updates_timer.timeout.connect(self.delayed_refresh_updates)
        self.delayed_refresh_updates_timer.setInterval(500)
        self.reset_view()
        self.button_advanced.setDisabled(True)

        self.tab_widget.currentChanged.connect(self.tab_changed)
        self.tab_widget.setMovable(True)
        self.tab_widget.tabBar().installEventFilter(self)

        self.button_connect.clicked.connect(self.connect_clicked)
        self.button_flashing.clicked.connect(self.flashing_clicked)
        self.button_advanced.clicked.connect(self.advanced_clicked)
        self.plugin_manager = PluginManager()

        # host info
        self.host_infos = config.get_host_infos(config.HOST_INFO_COUNT)
        self.host_index_changing = True

        for host_info in self.host_infos:
            self.combo_host.addItem(host_info.host)

        self.last_host = None
        self.combo_host.currentIndexChanged.connect(self.host_index_changed)

        self.spinbox_port.setValue(self.host_infos[0].port)
        self.spinbox_port.valueChanged.connect(self.port_changed)

        self.checkbox_authentication.stateChanged.connect(self.authentication_state_changed)

        self.label_secret.hide()
        self.edit_secret.hide()
        self.edit_secret.setEchoMode(QLineEdit.Password)
        self.edit_secret.textEdited.connect(self.secret_changed)

        self.checkbox_secret_show.hide()
        self.checkbox_secret_show.stateChanged.connect(self.secret_show_state_changed)

        self.checkbox_remember_secret.hide()
        self.checkbox_remember_secret.stateChanged.connect(self.remember_secret_state_changed)

        self.checkbox_authentication.setChecked(self.host_infos[0].use_authentication)
        self.edit_secret.setText(self.host_infos[0].secret)
        self.checkbox_remember_secret.setChecked(self.host_infos[0].remember_secret)

        self.host_index_changing = False

        # auto-reconnect
        self.label_auto_reconnects.hide()
        self.auto_reconnects = 0

        # RED Session losts
        self.label_red_session_losts.hide()
        self.red_session_losts = 0

    # override QMainWindow.closeEvent
    def closeEvent(self, event):
        self.exit_brickv()

    def exit_brickv(self, signal=None, frame=None):
        if self.current_device_info is not None:
            self.current_device_info.plugin.stop_plugin()
            self.current_device_info.plugin.destroy_plugin()

        self.update_current_host_info()
        config.set_host_infos(self.host_infos)

        self.do_disconnect()

        if signal != None and frame != None:
            print("Received SIGINT or SIGTERM, shutting down.")
            sys.exit()

    def host_index_changed(self, i):
        if i < 0:
            return

        self.host_index_changing = True

        self.spinbox_port.setValue(self.host_infos[i].port)
        self.checkbox_authentication.setChecked(self.host_infos[i].use_authentication)
        self.edit_secret.setText(self.host_infos[i].secret)
        self.checkbox_remember_secret.setChecked(self.host_infos[i].remember_secret)

        self.host_index_changing = False

    def port_changed(self, value):
        self.update_current_host_info()

    def authentication_state_changed(self, state):
        visible = state == Qt.Checked

        self.label_secret.setVisible(visible)
        self.edit_secret.setVisible(visible)
        self.checkbox_secret_show.setVisible(visible)
        self.checkbox_remember_secret.setVisible(visible)

        self.update_current_host_info()

    def secret_changed(self):
        self.update_current_host_info()

    def secret_show_state_changed(self, state):
        if state == Qt.Checked:
            self.edit_secret.setEchoMode(QLineEdit.Normal)
        else:
            self.edit_secret.setEchoMode(QLineEdit.Password)

        self.update_current_host_info()

    def remember_secret_state_changed(self, state):
        self.update_current_host_info()

    def tab_changed(self, i):
        if not hasattr(self.tab_widget.widget(i), '_info'):
            new_current_device_info = None
        else:
            new_current_device_info = self.tab_widget.widget(i)._info
            new_current_device_info.plugin.start_plugin()

        # stop the now deselected plugin, if there is one that's running
        if self.current_device_info is not None:
            self.current_device_info.plugin.stop_plugin()

        self.current_device_info = new_current_device_info

    def update_current_host_info(self):
        if self.host_index_changing:
            return

        i = self.combo_host.currentIndex()

        if i < 0:
            return

        #self.host_infos[i].host = self.combo_host.currentText()
        self.host_infos[i].port = self.spinbox_port.value()
        self.host_infos[i].use_authentication = self.checkbox_authentication.isChecked()
        self.host_infos[i].secret = self.edit_secret.text()
        self.host_infos[i].remember_secret = self.checkbox_remember_secret.isChecked()

    def remove_all_device_infos(self):
        for device_info in infos.get_device_infos():
            self.remove_device_info(device_info.uid)

    def remove_device_info(self, uid):
        tab_id = self.tab_for_uid(uid)
        device_info = infos.get_info(uid)

        device_info.plugin.stop_plugin()
        device_info.plugin.destroy_plugin()

        if tab_id >= 0:
            self.tab_widget.removeTab(tab_id)

        # ensure that the widget gets correctly destroyed. otherwise QWidgets
        # tend to leak as Python is not able to collect their PyQt object
        tab_window = device_info.tab_window
        device_info.tab_window = None

        # If we reboot the RED Brick, the tab_window sometimes is
        # already None here
        if tab_window != None:
            tab_window.hide()
            tab_window.setParent(None)

        plugin = device_info.plugin
        device_info.plugin = None

        if plugin != None:
            plugin.hide()
            plugin.setParent(None)

        infos.remove_info(uid)

    def reset_view(self):
        self.tab_widget.setCurrentIndex(0)
        self.remove_all_device_infos()
        self.update_tree_view()

    def do_disconnect(self):
        self.auto_reconnects = 0
        self.label_auto_reconnects.hide()

        self.red_session_losts = 0
        self.label_red_session_losts.hide()

        self.reset_view()
        async_next_session()

        # force garbage collection, to ensure that all plugin related objects
        # got destroyed before disconnect is called. this is especially
        # important for the RED Brick plugin because its relies on releasing
        # the the RED Brick API objects in the __del__ method as a last resort
        # to avoid leaking object references. but this only works if garbage
        # collection is done before disconnect is called
        gc.collect()

        try:
            self.ipcon.disconnect()
        except:
            pass

    def do_authenticate(self, is_auto_reconnect):
        if not self.checkbox_authentication.isChecked():
            return True

        try:
            secret = self.edit_secret.text().encode('ascii')
        except:
            self.do_disconnect()

            QMessageBox.critical(self, 'Connection',
                                 'Authentication secret cannot contain non-ASCII characters.',
                                 QMessageBox.Ok)
            return False

        self.ipcon.set_auto_reconnect(False) # don't auto-reconnect on authentication error

        try:
            self.ipcon.authenticate(secret)
        except:
            self.do_disconnect()

            if is_auto_reconnect:
                extra = ' after auto-reconnect'
            else:
                extra = ''

            QMessageBox.critical(self, 'Connection',
                                 'Could not authenticate' + extra + '. Check secret and ensure ' +
                                 'authentication for Brick Daemon is enabled.',
                                 QMessageBox.Ok)
            return False

        self.ipcon.set_auto_reconnect(True)

        return True

    def flashing_clicked(self):
        if self.flashing_window is None:
            self.flashing_window = FlashingWindow(self)

        self.flashing_window.show()
        self.flashing_window.refresh_updates_clicked()

    def advanced_clicked(self):
        if self.advanced_window is None:
            self.advanced_window = AdvancedWindow(self)

        self.advanced_window.show()

    def connect_clicked(self):
        if self.ipcon.get_connection_state() == IPConnection.CONNECTION_STATE_DISCONNECTED:
            try:
                self.last_host = self.combo_host.currentText()
                self.button_connect.setDisabled(True)
                self.button_connect.setText("Connecting ...")
                self.button_connect.repaint()
                QApplication.processEvents()
                self.ipcon.connect(self.last_host, self.spinbox_port.value())
            except:
                self.button_connect.setDisabled(False)
                self.button_connect.setText("Connect")
                QMessageBox.critical(self, 'Connection',
                                     'Could not connect. Please check host, check ' +
                                     'port and ensure that Brick Daemon is running.')
        else:
            self.do_disconnect()

    def item_double_clicked(self, index):
        uid_index = index.sibling(index.row(), 1)

        if uid_index.isValid():
            uid_text = uid_index.data()
            self.show_plugin(uid_text)

    def create_tab_window(self, device_info, connected_uid, position):
        tab_window = TabWindow(self.tab_widget, device_info.name, self.untab)
        tab_window._info = device_info
        tab_window.set_callback_on_tab(lambda index:
            self.ipcon.get_connection_state() == IPConnection.CONNECTION_STATE_PENDING and \
                self.tab_widget.setTabEnabled(index, False))

        layout = QVBoxLayout(tab_window)
        info_bar = QHBoxLayout()

        # uid
        info_bar.addWidget(QLabel('UID:'))

        label = QLabel('{0}'.format(device_info.uid))
        label.setTextInteractionFlags(Qt.TextSelectableByMouse |
                                      Qt.TextSelectableByKeyboard)

        info_bar.addWidget(label)
        info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # connected uid
        if connected_uid != '0':
            info_bar.addWidget(QLabel('Connected to:'))

            button = QToolButton()
            button.setText(connected_uid)
            button.clicked.connect(lambda: self.show_plugin(connected_uid))

            info_bar.addWidget(button)
            info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # position
        info_bar.addWidget(QLabel('Position:'))
        info_bar.addWidget(QLabel('{0}'.format(position.upper())))

        info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # firmware version
        label_version_name = QLabel('Version:')
        label_version = QLabel('...')

        if not device_info.plugin.has_custom_version(label_version_name, label_version):
            label_version_name.setText('FW Version:')
            label_version.setText(infos.get_version_string(device_info.plugin.firmware_version))

        info_bar.addWidget(label_version_name)
        info_bar.addWidget(label_version)

        info_bar.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # timeouts
        info_bar.addWidget(QLabel('Timeouts:'))
        label_timeouts = QLabel('0')
        info_bar.addWidget(label_timeouts)

        layout.addLayout(info_bar)

        # actions
        actions = device_info.plugin.get_actions()

        if actions != None:
            if type(actions) == QAction:
                button = QPushButton(actions.text())
                button.clicked.connect(actions.trigger)
            else:
                button = QToolButton()
                button.setText(actions[0])
                button.setPopupMode(QToolButton.InstantPopup)
                button.setToolButtonStyle(Qt.ToolButtonTextOnly)
                button.setArrowType(Qt.DownArrow)
                button.setAutoRaise(True)

                menu = QMenu(actions[0])
                button.setMenu(menu)

                for action in actions[1]:
                    menu.addAction(action)

            info_bar.addSpacerItem(QSpacerItem(40, 20, QSizePolicy.Expanding))
            info_bar.addWidget(button)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        device_info.plugin.label_timeouts = label_timeouts
        device_info.plugin.layout().setContentsMargins(0, 0, 0, 0)

        layout.addWidget(line)
        layout.addWidget(device_info.plugin)

        return tab_window

    def tab_move(self, event):
        # visualize rearranging of tabs (if allowed by tab_widget)
        if self.tab_widget.isMovable():
            if event.type() == QEvent.MouseButtonPress and event.button() & Qt.LeftButton:
                QApplication.setOverrideCursor(QCursor(Qt.SizeHorCursor))

            elif event.type() == QEvent.MouseButtonRelease and event.button() & Qt.LeftButton:
                QApplication.restoreOverrideCursor()

        return False

    def untab(self, tab_index):
        tab = self.tab_widget.widget(tab_index)
        tab.untab()
        tab._info.plugin.start_plugin()
        self.tab_widget.setCurrentIndex(0)

    def eventFilter(self, source, event):
        if source is self.tab_widget.tabBar():
            return self.tab_move(event)

        return False

    def tab_for_uid(self, uid):
        for i in range(1, self.tab_widget.count()):
            try:
                if self.tab_widget.widget(i)._info.uid == uid:
                    return i
            except:
                pass

        return -1

    def show_plugin(self, uid):
        i = self.tab_for_uid(uid)
        tab_window = infos.get_info(uid).tab_window

        if i > 0 and self.tab_widget.isTabEnabled(i):
            self.tab_widget.setCurrentIndex(i)

        QApplication.setActiveWindow(tab_window)

        tab_window.show()
        tab_window.activateWindow()
        tab_window.raise_()

    def cb_enumerate(self, uid, connected_uid, position,
                     hardware_version, firmware_version,
                     device_identifier, enumeration_type):
        if self.ipcon.get_connection_state() != IPConnection.CONNECTION_STATE_CONNECTED:
            # ignore enumerate callbacks that arrived after the connection got closed
            return

        if enumeration_type in [IPConnection.ENUMERATION_TYPE_AVAILABLE,
                                IPConnection.ENUMERATION_TYPE_CONNECTED]:
            device_info = infos.get_info(uid)
            something_changed_ref = [False]

            if device_info == None:
                if device_identifier == BrickMaster.DEVICE_IDENTIFIER:
                    device_info = infos.BrickMasterInfo()
                elif device_identifier == BrickRED.DEVICE_IDENTIFIER:
                    device_info = infos.BrickREDInfo()
                elif position in ('a', 'b', 'c', 'd', 'A', 'B', 'C', 'D'):
                    position = position.lower()
                    device_info = infos.BrickletInfo()
                else:
                    device_info = infos.BrickInfo()
                    something_changed_ref[0] = True

            def set_device_info_value(name, value):
                if getattr(device_info, name) != value:
                    setattr(device_info, name, value)
                    something_changed_ref[0] = True

            set_device_info_value('uid', uid)
            set_device_info_value('connected_uid', connected_uid)
            set_device_info_value('position', position)
            set_device_info_value('hardware_version', hardware_version)
            set_device_info_value('firmware_version_installed', firmware_version)
            set_device_info_value('device_identifier', device_identifier)
            set_device_info_value('protocol_version', 2)
            set_device_info_value('enumeration_type', enumeration_type)

            if device_info.type == 'bricklet':
                for brick_info in infos.get_brick_infos():
                    if brick_info.uid == device_info.connected_uid:
                        if brick_info.bricklets[position] != device_info:
                            brick_info.bricklets[position] = device_info
                            something_changed_ref[0] = True
            elif device_info.type == 'brick':
                for bricklet_info in infos.get_bricklet_infos():
                    if bricklet_info.connected_uid == device_info.uid:
                        if device_info.bricklets[bricklet_info.position] != bricklet_info:
                            device_info.bricklets[bricklet_info.position] = bricklet_info
                            something_changed_ref[0] = True

            if device_info.plugin == None:
                plugin = self.plugin_manager.get_plugin(device_identifier, self.ipcon,
                                                        uid, hardware_version, firmware_version)

                device_info.plugin = plugin
                device_info.name = plugin.name
                device_info.url_part = plugin.get_url_part()

                infos.add_info(device_info)

                device_info.tab_window = self.create_tab_window(device_info, connected_uid, position)
                device_info.tab_window.setWindowFlags(Qt.Widget)
                device_info.tab_window.tab()

                something_changed_ref[0] = True

            if something_changed_ref[0]:
                self.update_tree_view()
        elif enumeration_type == IPConnection.ENUMERATION_TYPE_DISCONNECTED:
            for device_info in infos.get_device_infos():
                if device_info.uid == uid:
                    self.tab_widget.setCurrentIndex(0)
                    self.remove_device_info(device_info.uid)

                if device_info.type == 'brick':
                    for port in device_info.bricklets:
                        if device_info.bricklets[port] and device_info.bricklets[port].uid == uid:
                            device_info.bricklets[port] = None

            self.update_tree_view()

    def hack_to_remove_red_brick_tab(self, red_brick_uid):
        for device_info in infos.get_device_infos():
            if device_info.uid == red_brick_uid:
                self.tab_widget.setCurrentIndex(0)
                self.remove_device_info(device_info.uid)

                self.red_session_losts += 1
                self.label_red_session_losts.setText('RED Brick Session Loss Count: {0}'.format(self.red_session_losts))
                self.label_red_session_losts.show()

                break

        self.update_tree_view()

    def cb_connected(self, connect_reason):
        self.disconnect_times = []

        self.update_ui_state()

        if connect_reason == IPConnection.CONNECT_REASON_REQUEST:
            self.auto_reconnects = 0
            self.label_auto_reconnects.hide()

            self.red_session_losts = 0
            self.label_red_session_losts.hide()

            self.ipcon.set_auto_reconnect(True)

            index = self.combo_host.findText(self.last_host)

            if index >= 0:
                self.combo_host.removeItem(index)

                host_info = self.host_infos[index]

                del self.host_infos[index]
                self.host_infos.insert(0, host_info)
            else:
                index = self.combo_host.currentIndex()

                host_info = self.host_infos[index].duplicate()
                host_info.host = self.last_host

                self.host_infos.insert(0, host_info)

            self.combo_host.insertItem(-1, self.last_host)
            self.combo_host.setCurrentIndex(0)

            while self.combo_host.count() > config.HOST_INFO_COUNT:
                self.combo_host.removeItem(self.combo_host.count() - 1)

            if not self.do_authenticate(False):
                return

            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()
        elif connect_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT:
            self.auto_reconnects += 1
            self.label_auto_reconnects.setText('Auto-Reconnect Count: {0}'.format(self.auto_reconnects))
            self.label_auto_reconnects.show()

            if not self.do_authenticate(True):
                return

            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()
        else:
            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()

    def cb_disconnected(self, disconnect_reason):
        if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST:
            self.auto_reconnects = 0
            self.label_auto_reconnects.hide()

            self.red_session_losts = 0
            self.label_red_session_losts.hide()

        if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST or not self.ipcon.get_auto_reconnect():
            self.update_ui_state()
        elif len(self.disconnect_times) >= 3 and self.disconnect_times[-3] < time.time() + 1:
            self.disconnect_times = []
            self.ipcon.set_auto_reconnect(False)
            self.update_ui_state()
            self.reset_view()

            QMessageBox.critical(self, 'Connection',
                                 'Stopped automatic reconnecting due to multiple connection errors in a row.')
        else:
            self.disconnect_times.append(time.time())
            self.update_ui_state(IPConnection.CONNECTION_STATE_PENDING)

    def set_tree_view_defaults(self):
        self.tree_view_model.setHorizontalHeaderLabels(self.tree_view_model_labels)
        self.tree_view.expandAll()
        self.tree_view.setColumnWidth(0, 250)
        self.tree_view.setColumnWidth(1, 85)
        self.tree_view.setColumnWidth(2, 85)
        self.tree_view.setColumnWidth(3, 90)
        self.tree_view.setExpandsOnDoubleClick(False)
        self.tree_view.setSortingEnabled(True)
        self.tree_view.header().setSortIndicator(0, Qt.AscendingOrder)

    def update_ui_state(self, connection_state=None):
        # FIXME: need to call processEvents() otherwise get_connection_state()
        #        might return the wrong value
        QApplication.processEvents()

        if connection_state is None:
            connection_state = self.ipcon.get_connection_state()

        self.button_connect.setDisabled(False)
        self.button_flashing.setDisabled(False)

        if connection_state == IPConnection.CONNECTION_STATE_DISCONNECTED:
            self.button_connect.setText('Connect')
            self.combo_host.setDisabled(False)
            self.spinbox_port.setDisabled(False)
            self.checkbox_authentication.setDisabled(False)
            self.edit_secret.setDisabled(False)
            self.button_advanced.setDisabled(True)
        elif connection_state == IPConnection.CONNECTION_STATE_CONNECTED:
            self.button_connect.setText("Disconnect")
            self.combo_host.setDisabled(True)
            self.spinbox_port.setDisabled(True)
            self.checkbox_authentication.setDisabled(True)
            self.edit_secret.setDisabled(True)
            self.update_advanced_window()

            # restart all pause plugins
            for info in infos.get_device_infos():
                info.plugin.resume_plugin()
        elif connection_state == IPConnection.CONNECTION_STATE_PENDING:
            self.button_connect.setText('Abort Pending Automatic Reconnect')
            self.combo_host.setDisabled(True)
            self.spinbox_port.setDisabled(True)
            self.checkbox_authentication.setDisabled(True)
            self.edit_secret.setDisabled(True)
            self.button_advanced.setDisabled(True)
            self.button_flashing.setDisabled(True)

            # pause all running plugins
            for info in infos.get_device_infos():
                info.plugin.pause_plugin()

        enable = connection_state == IPConnection.CONNECTION_STATE_CONNECTED

        for i in range(1, self.tab_widget.count()):
            self.tab_widget.setTabEnabled(i, enable)

        for device_info in infos.get_device_infos():
            device_info.tab_window.setEnabled(enable)

        QApplication.processEvents()

    def update_tree_view(self):
        self.tree_view_model.clear()

        for info in infos.get_brick_infos():
            parent = [QStandardItem(info.name),
                      QStandardItem(info.uid),
                      QStandardItem(info.position.upper()),
                      QStandardItem('.'.join(map(str, info.firmware_version_installed)))]

            for item in parent:
                item.setFlags(item.flags() & ~Qt.ItemIsEditable)

            self.tree_view_model.appendRow(parent)

            for port in sorted(info.bricklets):
                if info.bricklets[port] and info.bricklets[port].protocol_version == 2:
                    child = [QStandardItem(port.upper() + ': ' + info.bricklets[port].name),
                             QStandardItem(info.bricklets[port].uid),
                             QStandardItem(info.bricklets[port].position.upper()),
                             QStandardItem('.'.join(map(str, info.bricklets[port].firmware_version_installed)))]
                    for item in child:
                        item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    parent[0].appendRow(child)

        self.set_tree_view_defaults()
        self.update_advanced_window()
        self.delayed_refresh_updates_timer.start()

    def update_advanced_window(self):
        self.button_advanced.setEnabled(len(infos.get_brick_infos()) > 0)

    def delayed_refresh_updates(self):
        self.delayed_refresh_updates_timer.stop()

        if self.flashing_window is not None and self.flashing_window.isVisible():
            self.flashing_window.refresh_updates_clicked()
Exemple #25
0
class OWMPR(OWWidget):
    name = 'ModelMap Projection Rank'
    description = 'Ranking projections by estimating projection quality'
    icon = "icons/ModelMap.svg"

    inputs = [('Data', Table, 'set_data', Default)]
    outputs = [('Features', AttributeList)]
    want_main_area = False
    settingsHandler = DomainContextHandler()

    variable_changed = Signal()

    def __init__(self):
        super().__init__()
        self.data = None
        self.progress = None

        self.infoa = gui.widgetLabel(self.controlArea, "No data loaded.")

        self.projectionTable = QTableView()
        self.controlArea.layout().addWidget(self.projectionTable)
        self.projectionTable.setSelectionBehavior(QTableView.SelectRows)
        self.projectionTable.setSelectionMode(QTableView.SingleSelection)
        self.projectionTable.setSortingEnabled(True)

        self.projectionTableModel = QStandardItemModel(self)
        self.projectionTableModel.setHorizontalHeaderLabels(
            ["P-Index", "", ""])
        self.projectionTable.setModel(self.projectionTableModel)

        self.projectionTable.setColumnWidth(0, 90)
        self.projectionTable.sortByColumn(0, Qt.DescendingOrder)
        self.projectionTable.selectionModel().selectionChanged.connect(
            self.on_selection_changed)

        gui.button(self.controlArea,
                   self,
                   "Rank Projections",
                   callback=self.rank,
                   default=True)
        self.resize(370, 600)

    def set_data(self, data):
        self.data = data
        self.infoa.setText("Data set: {}".format(data.name) if self.
                           data else "No data loaded.")

    def rank(self):
        if self.progress:
            return

        disc = Orange.feature.discretization.EqualWidth(n=10)

        ndomain = Orange.data.Domain([
            disc(self.data, attr)
            if type(attr) == Orange.data.variable.ContinuousVariable else attr
            for attr in self.data.domain.attributes
        ], self.data.domain.class_vars)

        t = self.data.from_table(ndomain, self.data)

        attrs = t.domain.attributes

        tables = {}
        l = 0
        self.progress = gui.ProgressBar(self,
                                        len(attrs) * (len(attrs) - 1) / 2)
        for i in range(len(attrs)):
            for j in range(i):
                ct = np.array(
                    contingency.get_contingency(t, attrs[j], attrs[i]))
                pindex, _, _ = p_index(ct)
                tables[i, j] = ct

                item = QStandardItem()
                item.setData(float(pindex), Qt.DisplayRole)
                self.projectionTableModel.setItem(l, 0, item)

                item = QStandardItem()
                item.setData(attrs[i].name, Qt.DisplayRole)
                self.projectionTableModel.setItem(l, 1, item)

                item = QStandardItem()
                item.setData(attrs[j].name, Qt.DisplayRole)
                self.projectionTableModel.setItem(l, 2, item)

                self.progress.advance()
                l += 1

        self.progress.finish()
        self.progress = None

    def on_selection_changed(self, selected, deselected):
        """Called when the ranks view selection changes."""
        a1 = selected.indexes()[1].data().replace('D_', '')
        a2 = selected.indexes()[2].data().replace('D_', '')
        d = self.data.domain
        self.send("Features", AttributeList([d[a1], d[a2]]))
class FormItem(QStandardItem):
    def __init__(self, name, fields, setup):
        super(FormItem, self).__init__(name)
        fields = [("Name", str, name)] + fields
        self.name = lambda: str(self.text())
        self.names, _, _ = zip(*fields)
        self.dtypes = {}
        self.widgets = {}
        self.method_names = []
        self.val_items = {}
        self.expr_items = {}
        self.group_items = {}
        self.setup = setup
        self.params_model = QStandardItemModel()
        self.params_model.itemChanged.connect(self.update_name)
        self.params_model.setHorizontalHeaderLabels(["Name", "Formula", "Evaluated"])
        self.params_widget = QTableView()
        self.params_widget.setModel(self.params_model)
        self.params_widget.setItemDelegate(FormDelegate(self.params_model, self.widgets))
        self.params_widget.verticalHeader().hide()

        for name, item_type, default in fields:
            self.add_field(name, item_type, default)
        self.params_widget.resizeRowsToContents()
        self.context_menu = ActionsMenu([])

        self.params_model.itemChanged.connect(self.notify_group_item_children)

    def notify_group_item_children(self, item):
        method_name = method_style(self.params_model.item(item.row(), 0).text())
        if method_name in self.group_items:
            current_item = self.dtypes[method_name](item.text())
            previous_item = self.dtypes[method_name](self.group_items[method_name])
            self.group_items[method_name] = current_item

            current_item.register_dependency(self)
            previous_item.unregister_dependency(self)


    def add_field(self, word_name, item_type, value):
        word_name = word_style(word_name)
        method_name = method_style(word_name)
        if item_type is int:
            self.dtypes[method_name] = int
            self.widgets[word_name] = lambda: IntVarLineEdit(self.setup)
        elif item_type is float:
            self.dtypes[method_name] = float
            self.widgets[word_name] = lambda: VarLineEdit(self.setup)
        elif isinstance(item_type, bool):
            self.dtypes[method_name] = bool
            self.widgets[word_name] = QCheckBox
        elif isinstance(item_type, (list, tuple)):
            self.dtypes[method_name] = str
            self.widgets[word_name] = \
                lambda grp=item_type, **kwargs: MyComboBox(grp, **kwargs)
        elif isinstance(item_type, GroupItem):
            group = item_type
            value = group.items_list()[0].text()
            self.dtypes[method_name] = lambda i_name, grp=group: grp.item_from_name(i_name)
            self.widgets[word_name] = \
                lambda grp=group, **kwargs: ItemsComboBox(grp, **kwargs)
            self.group_items[method_name] = value
            group.item_from_name(value).register_dependency(self)
        self.expr_items[method_name] = QStandardItem(str(value))
        self.val_items[method_name] = ConstantItem("")
        self.params_model.appendRow([ConstantItem(word_name), self.expr_items[method_name], self.val_items[method_name]])
        self.method_names.append(method_name)

    def set_name(self, name):
        self.setText(name)
        self.params_model.item(0, 1).setText(name)

    def update_name(self):
        self.setText(self.params_model.item(0, 1).text())

    def eval_item(self, item):
        if item in self.method_names:
            dtype = self.dtypes[item]
            text = self.val_items[item].text()
            if text == "":
                text = self.expr_items[item].text()
            return dtype(text)
        else:
            raise AttributeError(item)

    def __getattr__(self, item):
        return self.eval_item(item)
Exemple #27
0
class OWConfusionMatrix(widget.OWWidget):
    name = "Confusion Matrix"
    description = "Shows a confusion matrix."
    icon = "icons/ConfusionMatrix.svg"
    priority = 1001

    inputs = [{
        "name": "Evaluation Results",
        "type": Orange.evaluation.Results,
        "handler": "set_results"
    }]
    outputs = [{"name": "Selected Data", "type": Orange.data.Table}]

    quantities = [
        "Number of instances", "Proportion of predicted",
        "Proportion of actual"
    ]

    selected_learner = settings.Setting([])
    selected_quantity = settings.Setting(0)
    append_predictions = settings.Setting(True)
    append_probabilities = settings.Setting(False)
    autocommit = settings.Setting(True)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.data = None
        self.results = None
        self.learners = []

        box = gui.widgetBox(self.controlArea, "Learners")

        self.learners_box = gui.listBox(box,
                                        self,
                                        "selected_learner",
                                        "learners",
                                        callback=self._learner_changed)
        box = gui.widgetBox(self.controlArea, "Show")

        gui.comboBox(box,
                     self,
                     "selected_quantity",
                     items=self.quantities,
                     callback=self._update)

        box = gui.widgetBox(self.controlArea, "Select")

        gui.button(box,
                   self,
                   "Correct",
                   callback=self.select_correct,
                   autoDefault=False)
        gui.button(box,
                   self,
                   "Misclassified",
                   callback=self.select_wrong,
                   autoDefault=False)
        gui.button(box,
                   self,
                   "None",
                   callback=self.select_none,
                   autoDefault=False)

        self.outputbox = box = gui.widgetBox(self.controlArea, "Output")
        gui.checkBox(box,
                     self,
                     "append_predictions",
                     "Predictions",
                     callback=self._invalidate)
        gui.checkBox(box,
                     self,
                     "append_probabilities",
                     "Probabilities",
                     callback=self._invalidate)

        gui.auto_commit(self.controlArea, self, "autocommit", "Send Data",
                        "Auto send is on")

        grid = QGridLayout()
        grid.setContentsMargins(0, 0, 0, 0)
        grid.addWidget(QLabel("Predicted"), 0, 1, Qt.AlignCenter)
        grid.addWidget(VerticalLabel("Actual Class"), 1, 0, Qt.AlignCenter)

        self.tablemodel = QStandardItemModel()
        self.tableview = QTableView(editTriggers=QTableView.NoEditTriggers)
        self.tableview.setModel(self.tablemodel)
        self.tableview.selectionModel().selectionChanged.connect(
            self._invalidate)
        grid.addWidget(self.tableview, 1, 1)
        self.mainArea.layout().addLayout(grid)

    def set_results(self, results):
        """Set the input results."""

        self.clear()
        self.warning([0, 1])

        data = None
        if results is not None:
            if results.data is not None:
                data = results.data

        if data is not None and \
                not isinstance(data.domain.class_var,
                               Orange.data.DiscreteVariable):
            data = None
            results = None
            self.warning(
                0, "Confusion Matrix cannot be used for regression results.")

        self.results = results
        self.data = data

        if data is not None:
            class_values = data.domain.class_var.values
        elif results is not None:
            raise NotImplementedError

        if results is not None:
            nmodels, ntests = results.predicted.shape
            headers = class_values + [unicodedata.lookup("N-ARY SUMMATION")]

            # NOTE: The 'learner_names' is set in 'Test Learners' widget.
            if hasattr(results, "learner_names"):
                self.learners = results.learner_names
            else:
                self.learners = ["L %i" % (i + 1) for i in range(nmodels)]

            self.tablemodel.setVerticalHeaderLabels(headers)
            self.tablemodel.setHorizontalHeaderLabels(headers)
            self.tablemodel.setRowCount(len(class_values) + 1)
            self.tablemodel.setColumnCount(len(class_values) + 1)
            self.selected_learner = [0]
            self._update()

    def clear(self):
        self.results = None
        self.data = None
        self.tablemodel.clear()
        # Clear learners last. This action will invoke `_learner_changed`
        # method
        self.learners = []

    def select_correct(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()
        for i in range(n):
            index = self.tablemodel.index(i, i)
            selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect)

    def select_wrong(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()

        for i in range(n):
            for j in range(i + 1, n):
                index = self.tablemodel.index(i, j)
                selection.select(index, index)
                index = self.tablemodel.index(j, i)
                selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect)

    def select_none(self):
        self.tableview.selectionModel().clear()

    def commit(self):
        if self.results is not None and self.data is not None \
                and self.selected_learner:
            indices = self.tableview.selectedIndexes()
            indices = {(ind.row(), ind.column()) for ind in indices}
            actual = self.results.actual
            selected_learner = self.selected_learner[0]
            learner_name = self.learners[selected_learner]
            predicted = self.results.predicted[selected_learner]
            selected = [
                i for i, t in enumerate(zip(actual, predicted)) if t in indices
            ]
            row_indices = self.results.row_indices[selected]

            extra = []
            class_var = self.data.domain.class_var
            metas = self.data.domain.metas

            if self.append_predictions:
                predicted = numpy.array(predicted[selected], dtype=object)
                extra.append(predicted.reshape(-1, 1))
                var = Orange.data.DiscreteVariable(
                    "{}({})".format(class_var.name, learner_name),
                    class_var.values)
                metas = metas + (var, )

            if self.append_probabilities and \
                    self.results.probabilities is not None:
                probs = self.results.probabilities[selected_learner, selected]
                extra.append(numpy.array(probs, dtype=object))
                pvars = [
                    Orange.data.ContinuousVariable("p({})".format(value))
                    for value in class_var.values
                ]
                metas = metas + tuple(pvars)

            X = self.data.X[row_indices]
            Y = self.data.Y[row_indices]
            M = self.data.metas[row_indices]
            row_ids = self.data.ids[row_indices]

            M = numpy.hstack((M, ) + tuple(extra))
            domain = Orange.data.Domain(self.data.domain.attributes,
                                        self.data.domain.class_vars, metas)
            data = Orange.data.Table.from_numpy(domain, X, Y, M)
            data.ids = row_ids
            data.name = learner_name

        else:
            data = None

        self.send("Selected Data", data)

    def _invalidate(self):
        self.commit()

    def _learner_changed(self):
        # The selected learner has changed
        self._update()
        self._invalidate()

    def _update(self):
        # Update the displayed confusion matrix
        if self.results is not None and self.selected_learner:
            index = self.selected_learner[0]
            cmatrix = confusion_matrix(self.results, index)
            colsum = cmatrix.sum(axis=0)
            rowsum = cmatrix.sum(axis=1)
            total = rowsum.sum()

            if self.selected_quantity == 0:
                value = lambda i, j: int(cmatrix[i, j])
            elif self.selected_quantity == 1:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i])
                     if colsum[i] else "N/A")
            elif self.selected_quantity == 2:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i])
                     if colsum[i] else "N/A")
            else:
                assert False

            model = self.tablemodel
            for i, row in enumerate(cmatrix):
                for j, _ in enumerate(row):
                    item = model.item(i, j)
                    if item is None:
                        item = QStandardItem()
                    item.setData(value(i, j), Qt.DisplayRole)
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                    model.setItem(i, j, item)

            font = model.invisibleRootItem().font()
            bold_font = QFont(font)
            bold_font.setBold(True)

            def sum_item(value):
                item = QStandardItem()
                item.setData(value, Qt.DisplayRole)
                item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                item.setFlags(Qt.ItemIsEnabled)
                item.setFont(bold_font)
                return item

            N = len(colsum)
            for i in range(N):
                model.setItem(N, i, sum_item(int(colsum[i])))
                model.setItem(i, N, sum_item(int(rowsum[i])))

            model.setItem(N, N, sum_item(int(total)))
class InputDialog(GenericDialog):

    TBL_HEADER_LABEL=["Input Mesh", "Output group name"]

    def __init__(self, parent=None, name="InputDialog", modal=0):
        """
        This initializes a dialog windows to define the input data of
        the plugin function. The input data consist in a list of
        meshes characterizes each by a name, a pointer to the smesh
        servant object, a type and a group name (see data model in the
        inputdata.py).
        """
        GenericDialog.__init__(self, parent, name, modal)
        # Set up the user interface from Designer.
        self.__ui = Ui_InputFrame()
        # BE CAREFULL HERE, the ui form is NOT drawn in the global
        # dialog (already containing some generic widgets) but in the
        # center panel created in the GenericDialog as a void
        # container for the form. The InputFrame form is supposed
        # here to create only the widgets to be placed in the center
        # panel. Then, the setupUi function of this form draws itself
        # in the specified panel, i.e. the panel returned by
        # self.getPanel().
        self.__ui.setupUi(self.getPanel())

        self.setWindowTitle("Specification of input files")

        # The icon are supposed to be located in the plugin folder,
        # i.e. in the same folder than this python module file
        iconfolder=os.path.dirname(os.path.abspath(__file__))
        icon = QIcon()
        icon.addFile(os.path.join(iconfolder,"select.png"))
        self.__ui.btnSmeshObject.setIcon(icon)
        icon = QIcon()
        icon.addFile(os.path.join(iconfolder,"addinput.png"))
        self.__ui.btnAddInput.setIcon(icon)
        icon = QIcon()
        icon.addFile(os.path.join(iconfolder,"deleteinput.png"))
        self.__ui.btnDeleteInput.setIcon(icon)

        # We specify here the items in the combo box (even if already
        # defined in the designer) so that we can be sure of the item
        # indexation.
        self.MESHTYPE_ICONS = {}
        meshTypeIndex = InputData.MESHTYPES.CONCRETE
        self.__ui.cmbMeshType.setItemText(meshTypeIndex, "Béton")
        icon = QIcon()
        icon.addFile(os.path.join(iconfolder,"concrete.png"))
        self.__ui.cmbMeshType.setItemIcon(meshTypeIndex, icon)
        self.MESHTYPE_ICONS[meshTypeIndex] = icon

        meshTypeIndex = InputData.MESHTYPES.STEELBAR
        self.__ui.cmbMeshType.setItemText(meshTypeIndex, "Acier")
        icon = QIcon()
        icon.addFile(os.path.join(iconfolder,"steelbar.png"))
        self.__ui.cmbMeshType.setItemIcon(meshTypeIndex, icon)
        self.MESHTYPE_ICONS[meshTypeIndex] = icon
        
        # The click on btnSmeshObject (signal clicked() emitted by the
        # button btnSmeshObject) is connected to the slot
        # onSelectSmeshObject, etc ...
        self.connect(self.__ui.btnSmeshObject, SIGNAL('clicked()'), self.onSelectSmeshObject )
        self.connect(self.__ui.btnAddInput,    SIGNAL('clicked()'), self.onAddInput )
        self.connect(self.__ui.btnDeleteInput, SIGNAL('clicked()'), self.onDeleteInput )

        # Set up the model of the Qt table list
        self.__inputModel = QStandardItemModel(0,2)
        self.__inputModel.setHorizontalHeaderLabels(InputDialog.TBL_HEADER_LABEL)
        self.__ui.tblListInput.setModel(self.__inputModel)
        self.__ui.tblListInput.verticalHeader().hide()
        self.__ui.tblListInput.horizontalHeader().setStretchLastSection(True)
        # Note that the type is not display explicitly in the Qt table
        # because it is specified using an icon on the text of the
        # name item. 

        # Note that PADDER does not support group name longer than 8
        # characters. We apply then this limit in the gui field.
        self.__ui.txtGroupName.setMaxLength(GROUPNAME_MAXLENGTH)

        self.clear()

        self.smeshStudyTool = SMeshStudyTools()

    def clear(self):
        """
        This function clears the data gui area and associated values.
        """
        self.__ui.txtSmeshObject.setText("")
        self.__ui.txtGroupName.setText("")
        self.__inputModel.clear()
        self.__inputModel.setHorizontalHeaderLabels(InputDialog.TBL_HEADER_LABEL)
        if not DEBUG_MODE:
            self.__ui.txtSmeshObject.setEnabled(False)
            self.__ui.btnAddInput.setEnabled(False)
        self.__selectedMesh = None
        self.__dictInputData = {}
        self.__nbConcreteMesh = 0
        self.__nbSteelbarMesh = 0

    def accept(self):
        """
        This function is the slot connected to the button OK
        """
        # The dialog is raised in a non modal mode to get
        # interactivity with the parents windows. Then we have to emit
        # a signal to warn the parent observer that the dialog has
        # been validated so that it can process the event
        GenericDialog.accept(self)
        if self.wasOk():
            self.emit(SIGNAL('inputValidated()'))

    def onSelectSmeshObject(self):
        '''
        This function is the slot connected on the mesh selection
        button. It memorizes the selected mesh and put its name in the
        text field of the dialog box.
        '''
        mySObject, myEntry = guihelper.getSObjectSelected()
        if CORBA.is_nil(mySObject):
            self.__ui.txtSmeshObject.setText("You must choose a mesh")
            self.__ui.txtGroupName.setText("")
            self.__ui.txtSmeshObject.setEnabled(False)
            self.__ui.btnAddInput.setEnabled(False)
            self.__selectedMesh = None
            return

        self.smeshStudyTool.updateStudy(studyedit.getActiveStudyId())
        self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
        if CORBA.is_nil(self.__selectedMesh):
            self.__ui.txtSmeshObject.setText("The selected object is not a mesh")
            self.__ui.txtGroupName.setText("")
            self.__ui.txtSmeshObject.setEnabled(False)
            self.__ui.btnAddInput.setEnabled(False)
            self.__selectedMesh = None
            return
        myName = mySObject.GetName()
        self.__ui.txtSmeshObject.setText(myName)
        self.__ui.txtSmeshObject.setEnabled(True)
        self.__ui.btnAddInput.setEnabled(True)

        # We can suggest a default group name from the mesh name
        self.__ui.txtGroupName.setText(myName)

    def onAddInput(self):
        """
        This function is the slot connected to the Add button. It
        creates a new entry in the list of input data, or updates this
        entry if it already exists.
        """
        meshName   = str(self.__ui.txtSmeshObject.text().trimmed())
        meshObject = self.__selectedMesh
        meshType   = self.__ui.cmbMeshType.currentIndex()
        groupName  = str(self.__ui.txtGroupName.text().trimmed())

        self.__addInputInGui(meshName, meshObject, meshType, groupName)
        self.__addInputInMap(meshName, meshObject, meshType, groupName)

    def __addInputInGui(self, meshName, meshObject, meshType, groupName):
        """
        This function adds an entry with the specified data int the
        GUI table (for data visualization purpose).
        """
        # The mesh name is used as the key index in the model. We have
        # to check first if this item already exists in the list.
        tblItems = self.__inputModel.findItems(meshName)
        row = self.__inputModel.rowCount()
        if not tblItems:
            tblItems = []
            tblItems.append(QStandardItem()) # input mesh name
            tblItems.append(QStandardItem()) # output group name
        else:
            row = tblItems[0].index().row()
            tblItems.append(self.__inputModel.item(row,1))

        tblItems[0].setText(meshName)
        tblItems[0].setIcon(self.MESHTYPE_ICONS[meshType])
        tblItems[1].setText(groupName)
        self.__inputModel.setItem(row,0,tblItems[0])
        self.__inputModel.setItem(row,1,tblItems[1])
        self.__ui.tblListInput.setCurrentIndex(tblItems[0].index())

    def __addInputInMap(self, meshName, meshObject, meshType, groupName):
        """
        This function adds an entry with the specified data in the
        internal map (for data management purpose).
        """
        # if the entry already exists, we remove it to replace by a
        # new one
        if self.__dictInputData.has_key(meshName):
            self.__delInputFromMap(meshName)
        
        inputData = InputData()
        inputData.meshName   = meshName
        inputData.meshObject = meshObject
        inputData.meshType   = meshType
        inputData.groupName  = groupName
        # The key of the map is the mesh name
        self.__dictInputData[meshName] = inputData
        if inputData.meshType == InputData.MESHTYPES.CONCRETE:
            self.__nbConcreteMesh += 1
        else:
            self.__nbSteelbarMesh += 1

        print inputData
        print "meshType = ",inputData.meshType
        print "nb concrete mesh ",self.__nbConcreteMesh
        print "nb steelbar mesh ",self.__nbSteelbarMesh
            

    def onDeleteInput(self):
        """
        This function is the slot connected to the Delete button. It
        remove from the data list the entry selected in the Qt table.
        """
        selectedIdx = self.__ui.tblListInput.selectedIndexes()
        if selectedIdx:
            row  = selectedIdx[0].row()
            tblItem  = self.__inputModel.item(row,0)
            meshName = str(tblItem.text())
            self.__inputModel.takeRow(row)
            # Don't forget to remove this entry from the mesh object
            # internal dictionnary
            self.__delInputFromMap(meshName)

    def __delInputFromMap(self, meshName):
        """
        This function removes the specified entry from the internal
        map (for data management purpose) 
        """
        inputData = self.__dictInputData.pop(meshName)
        if inputData.meshType == InputData.MESHTYPES.CONCRETE:
            self.__nbConcreteMesh -= 1
        else:
            self.__nbSteelbarMesh -= 1

        print inputData
        print "nb concrete mesh ",self.__nbConcreteMesh
        print "nb steelbar mesh ",self.__nbSteelbarMesh


    def setData(self, listInputData=[]):
        """
        This function fills the dialog widgets with values provided by
        the specified data list.
        """
        self.clear()
        for inputData in listInputData:

            meshName   = inputData.meshName
            meshObject = inputData.meshObject
            meshType   = inputData.meshType
            groupName  = inputData.groupName
            
            self.__addInputInGui(meshName, meshObject, meshType, groupName)
            self.__addInputInMap(meshName, meshObject, meshType, groupName)

            if not DEBUG_MODE:
                self.onSelectSmeshObject()

    def getData(self):
        """
        This function returns a list of InputData that corresponds to
        the data in the dialog widgets of the current dialog.
        """
        # Note that the values() function returns a copy of the list
        # of values.
        return self.__dictInputData.values()
        
    def checkData(self):
        """
        This function checks if the data are valid, from the dialog
        window point of view.
        """
        if self.__nbConcreteMesh == 0 and self.__nbSteelbarMesh == 0:
            self.checkDataMessage = "You must define at least one mesh (CONCRETE or STEELBAR)"
            return False        
        if self.__nbConcreteMesh > 1:
            self.checkDataMessage  = "You define multiple CONCRETE meshes."
            self.checkDataMessage += "You should verify first that your version of PADDER support this configuration."
            # just warn the user, but don't block
            QMessageBox.information(self, "Info", self.checkDataMessage)
            return True

        return True
Exemple #29
0
class LogDialog(QDialogWithDpi):
    """LogDialog for the Freeseer project.

    It is the dialog window for the log.
    There is an instance for every FreeseerApp.
    It has a LogHandler which calls LogDialog's
    message() method when a new log message is received.
    The call to message() causes a call to add_entry()
    which adds the information to a new row in the table.
    """
    def __init__(self, parent=None):
        super(LogDialog, self).__init__(parent)

        self.resize(800, 500)

        self.app = QApplication.instance()

        icon = QIcon()
        icon.addPixmap(QPixmap(_fromUtf8(":/freeseer/logo.png")), QIcon.Normal,
                       QIcon.Off)
        self.setWindowIcon(icon)

        layout = QVBoxLayout()
        self.setLayout(layout)

        self.level = 0
        self.handler = LogHandler()

        self.table_model = QStandardItemModel(0, 5)
        header_names = ["Date", "Level", "Module", "Message", "LevelNo"]
        date_column = header_names.index("Date")
        level_column = header_names.index("Level")
        module_column = header_names.index("Module")
        self.level_num_column = header_names.index("LevelNo")
        self.table_model.setHorizontalHeaderLabels(header_names)

        self.table_view = QTableView()
        self.table_view.setModel(self.table_model)
        self.table_view.horizontalHeader().setStretchLastSection(True)
        self.table_view.setColumnWidth(date_column,
                                       self.set_width_with_dpi(125))
        self.table_view.setColumnWidth(level_column,
                                       self.set_width_with_dpi(60))
        self.table_view.setColumnWidth(module_column,
                                       self.set_width_with_dpi(250))
        self.table_view.setColumnHidden(self.level_num_column, True)
        self.table_view.setShowGrid(False)
        self.table_view.horizontalHeader().setClickable(False)
        self.table_view.verticalHeader().hide()
        self.table_view.setStyleSheet("""Qtable_view::item {
            border-bottom: 1px solid lightgrey;
            selection-background-color: white;
            selection-color: black;
            }""")

        top_panel = QHBoxLayout()
        self.log_levels = ["Debug", "Info", "Warning", "Error"]
        self.level_colors = ["#3E4C85", "#269629", "#B0AB21", "#B32020"]

        self.levels_label = QLabel("Filter Level: ")
        self.levels_label.setStyleSheet("QLabel { font-weight: bold }")
        self.current_level_label = QLabel(self.log_levels[0])
        self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(
            self.level_colors[0]))
        self.clear_button = QPushButton("Clear Log")
        self.levels_slider = QSlider(Qt.Horizontal)
        self.levels_slider.setStyleSheet("""
        QSlider::handle:horizontal {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #FFFFFF, stop:1 #E3E3E3);
            border: 1px solid #707070;
            width: 10px;
            margin-top: -4px;
            margin-bottom: -4px;
            border-radius: 4px;
        }

        QSlider::handle:horizontal:hover {
            background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                stop:0 #DEDEDE, stop:1 #C9C9C9);
            border: 1px solid #4F4F4F;
            border-radius: 4px;
        }

        QSlider::sub-page:horizontal {
            background: qlineargradient(x1: 0, y1: 0,    x2: 0, y2: 1,
                stop: 0 #BFBFBF, stop: 1 #9E9E9E);
            background: qlineargradient(x1: 0, y1: 0.2, x2: 1, y2: 1,
                stop: 0 #9E9E9E, stop: 1 #858585);
            border: 1px solid #777;
            height: 10px;
            border-radius: 4px;
        }

        QSlider::add-page:horizontal {
            background: #fff;
            border: 1px solid #707070;
            height: 10px;
            border-radius: 4px;
        }""")
        self.levels_slider.setRange(0, len(self.log_levels) - 1)
        self.levels_slider.setTickPosition(QSlider.TicksBelow)
        self.levels_slider.setTickInterval(1)

        top_panel.addSpacerItem(self.qspacer_item_with_dpi(10, 0))
        top_panel.addWidget(self.levels_label, 3)
        top_panel.addWidget(self.current_level_label, 2)
        top_panel.addWidget(self.levels_slider, 8)
        top_panel.addSpacerItem(self.qspacer_item_with_dpi(25, 0))
        top_panel.addWidget(self.clear_button, 10)

        layout.addLayout(top_panel)
        layout.addWidget(self.table_view)

        self.connect(self.clear_button, SIGNAL('clicked()'),
                     functools.partial(self.table_model.setRowCount, 0))
        self.connect(self.levels_slider, SIGNAL('valueChanged(int)'),
                     self.slider_set_level)

        self.setWindowTitle("Log")
        self.handler.add_listener(self)

    def __del__(self):
        self.handler.remove_listener(self)

    def retranslate(self):
        self.setWindowTitle(self.app.translate("LogDialog", "Log"))
        self.clear_button.setText(self.app.translate("LogDialog", "Clear Log"))
        self.levels_label.setText("{}: ".format(
            self.app.translate("LogDialog", "Filter Level")))

    def message(self, message):
        """Passes the log fields to add_entry()

        It is called by LogHandler when a log message is received"""
        self.add_entry(message["time"], message["level"],
                       message["full_module_name"], message["message"],
                       str(message["levelno"]))

    def add_entry(self, date, level, module, message, levelno):
        """Adds the given fields to a new row in the log table

        It is called by message() when a log message is received"""
        items = [
            QStandardItem(date),
            QStandardItem(level),
            QStandardItem(module),
            QStandardItem(message),
            QStandardItem(levelno)
        ]
        for item in items:
            item.setEditable(False)
        self.table_model.appendRow(items)

    def slider_set_level(self, level):
        self.current_level_label.setText(self.log_levels[level])
        self.current_level_label.setStyleSheet("QLabel {{ color: {} }}".format(
            self.level_colors[level]))
        self.set_level(level + 1)

    def set_level(self, level):
        """Sets the current level of the LogDialog.

        Level is based on the selection made in the levels_combo_box.
        It hides all messages with a lower level."""
        self.level = level * 10
        for i in range(self.table_model.rowCount()):
            if int(str(self.table_model.item(
                    i, self.level_num_column).text())) < self.level:
                self.table_view.setRowHidden(i, True)
            else:
                self.table_view.setRowHidden(i, False)
Exemple #30
0
def get_gds_model(progress=lambda val: None):
    """
    Initialize and return a GDS datasets model.

    :param progress: A progress callback.
    :rval tuple:
        A tuple of (QStandardItemModel, geo.GDSInfo, [geo.GDS])

    .. note::
        The returned QStandardItemModel's thread affinity is set to
        the GUI thread.

    """
    progress(1)
    info = geo.GDSInfo()
    search_keys = ["dataset_id", "title", "platform_organism", "description"]
    cache_dir = serverfiles.localpath(geo.DOMAIN)
    gds_link = "http://www.ncbi.nlm.nih.gov/sites/GDSbrowser?acc={0}"
    pm_link = "http://www.ncbi.nlm.nih.gov/pubmed/{0}"
    gds_list = []

    def is_cached(gds):
        return os.path.exists(
            os.path.join(cache_dir, gds["dataset_id"]) + ".soft.gz")

    def item(displayvalue, item_values={}):
        item = QStandardItem()
        item.setData(displayvalue, Qt.DisplayRole)
        for role, value in item_values.items():
            item.setData(value, role)
        return item

    def gds_to_row(gds):
        #: Text for easier full search.
        search_text = " | ".join(
            [gds.get(key, "").lower() for key in search_keys])
        row = [
            item(" " if is_cached(gds) else "", {TextFilterRole: search_text}),
            item(gds["dataset_id"],
                 {LinkRole: gds_link.format(gds["dataset_id"])}),
            item(gds["title"]),
            item(gds["platform_organism"]),
            item(len(gds["samples"])),
            item(gds["feature_count"]),
            item(gds["gene_count"]),
            item(len(gds["subsets"])),
            item(
                gds.get("pubmed_id", ""), {
                    LinkRole:
                    pm_link.format(gds["pubmed_id"])
                    if gds.get("pubmed_id") else None
                })
        ]
        return row

    model = QStandardItemModel()
    model.setHorizontalHeaderLabels([
        "", "ID", "Title", "Organism", "Samples", "Features", "Genes",
        "Subsets", "PubMedID"
    ])
    progress(20)
    for gds in info.values():
        model.appendRow(gds_to_row(gds))

        gds_list.append(gds)

    progress(50)

    if QThread.currentThread() is not QCoreApplication.instance().thread():
        model.moveToThread(QCoreApplication.instance().thread())
    return model, info, gds_list
class ProgramInfoFiles(QWidget, Ui_ProgramInfoFiles):
    def __init__(self, context, update_main_ui_state, set_widget_enabled, is_alive, show_upload_files_wizard, show_download_wizard):
        QWidget.__init__(self)

        self.setupUi(self)

        self.session                 = context.session
        self.script_manager          = context.script_manager
        self.program                 = context.program
        self.update_main_ui_state    = update_main_ui_state
        self.set_widget_enabled      = set_widget_enabled
        self.is_alive                = is_alive
        self.show_download_wizard    = show_download_wizard
        self.bin_directory           = posixpath.join(self.program.root_directory, 'bin')
        self.refresh_in_progress     = False
        self.any_refresh_in_progress = False # set from ProgramInfoMain.update_ui_state
        self.available_files         = []
        self.available_directories   = []
        self.folder_icon             = QIcon(load_pixmap('folder-icon.png'))
        self.file_icon               = QIcon(load_pixmap('file-icon.png'))
        self.tree_files_model        = QStandardItemModel(self)
        self.tree_files_model_header = ['Name', 'Size', 'Last Modified']
        self.tree_files_proxy_model  = FilesProxyModel(self)
        self.last_download_directory = get_home_path()

        self.tree_files_model.setHorizontalHeaderLabels(self.tree_files_model_header)
        self.tree_files_proxy_model.setSourceModel(self.tree_files_model)
        self.tree_files.setModel(self.tree_files_model)
        self.tree_files.setModel(self.tree_files_proxy_model)
        self.tree_files.setColumnWidth(0, 210)
        self.tree_files.setColumnWidth(1, 85)

        self.tree_files.selectionModel().selectionChanged.connect(self.update_ui_state)
        self.tree_files.activated.connect(self.rename_activated_file)
        self.button_upload_files.clicked.connect(show_upload_files_wizard)
        self.button_download_files.clicked.connect(self.download_selected_files)
        self.button_rename_file.clicked.connect(self.rename_selected_file)
        self.button_change_file_permissions.clicked.connect(self.change_permissions_of_selected_file)
        self.button_delete_files.clicked.connect(self.delete_selected_files)

        self.label_error.setVisible(False)

    def update_ui_state(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        self.set_widget_enabled(self.button_upload_files, not self.any_refresh_in_progress)
        self.set_widget_enabled(self.button_download_files, not self.any_refresh_in_progress and selection_count > 0)
        self.set_widget_enabled(self.button_rename_file, not self.any_refresh_in_progress and selection_count == 1)
        self.set_widget_enabled(self.button_change_file_permissions, not self.any_refresh_in_progress and selection_count == 1)
        self.set_widget_enabled(self.button_delete_files, not self.any_refresh_in_progress and selection_count > 0)

    def close_all_dialogs(self):
        pass

    def refresh_files_done(self):
        self.refresh_in_progress = False
        self.update_main_ui_state()

    def refresh_files(self):
        def cb_walk(result):
            okay, message = check_script_result(result, decode_stderr=True)

            if not okay:
                self.label_error.setText('<b>Error:</b> ' + Qt.escape(message))
                self.label_error.setVisible(True)
                self.refresh_files_done()
                return

            self.label_error.setVisible(False)

            def expand_async(data):
                try:
                    walk = json.loads(zlib.decompress(buffer(data)).decode('utf-8'))
                except:
                    walk = None

                if walk == None or not isinstance(walk, dict):
                    available_files       = []
                    available_directories = []
                    walk                  = None
                else:
                    available_files, available_directories = expand_walk_to_lists(walk)

                return walk, available_files, available_directories

            def cb_expand_success(result):
                walk, available_files, available_directories = result

                self.available_files       = available_files
                self.available_directories = available_directories

                if walk != None:
                    expand_walk_to_model(walk, self.tree_files_model, self.folder_icon, self.file_icon)
                else:
                    self.label_error.setText('<b>Error:</b> Received invalid data')
                    self.label_error.setVisible(True)

                self.tree_files.header().setSortIndicator(0, Qt.AscendingOrder)
                self.refresh_files_done()

            def cb_expand_error():
                self.label_error.setText('<b>Error:</b> Internal async error')
                self.label_error.setVisible(True)
                self.refresh_files_done()

            async_call(expand_async, result.stdout, cb_expand_success, cb_expand_error)

        self.refresh_in_progress = True
        self.update_main_ui_state()

        width1 = self.tree_files.columnWidth(0)
        width2 = self.tree_files.columnWidth(1)

        self.tree_files_model.clear()
        self.tree_files_model.setHorizontalHeaderLabels(self.tree_files_model_header)
        self.tree_files.setColumnWidth(0, width1)
        self.tree_files.setColumnWidth(1, width2)

        self.script_manager.execute_script('walk', cb_walk,
                                           [self.bin_directory], max_length=1024*1024,
                                           decode_output_as_utf8=False)

    def get_directly_selected_name_items(self):
        selected_indexes    = self.tree_files.selectedIndexes()
        selected_name_items = []

        for selected_index in selected_indexes:
            if selected_index.column() == 0:
                mapped_index = self.tree_files_proxy_model.mapToSource(selected_index)
                selected_name_items.append(self.tree_files_model.itemFromIndex(mapped_index))

        return selected_name_items

    def download_selected_files(self):
        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) == 0:
            return

        downloads = []

        def expand(name_item):
            item_type = name_item.data(USER_ROLE_ITEM_TYPE)

            if item_type == ITEM_TYPE_DIRECTORY:
                for i in range(name_item.rowCount()):
                    expand(name_item.child(i, 0))
            elif item_type == ITEM_TYPE_FILE:
                filename = get_full_item_path(name_item)

                downloads.append(Download(filename, QDir.toNativeSeparators(filename)))

        for selected_name_item in selected_name_items:
            expand(selected_name_item)

        if len(downloads) == 0:
            return

        download_directory = get_existing_directory(get_main_window(), 'Download Files',
                                                    self.last_download_directory)

        if len(download_directory) == 0:
            return

        self.last_download_directory = download_directory

        self.show_download_wizard('files', download_directory, downloads)

    def rename_activated_file(self, index):
        if index.column() == 0 and not self.any_refresh_in_progress:
            mapped_index = self.tree_files_proxy_model.mapToSource(index)
            name_item    = self.tree_files_model.itemFromIndex(mapped_index)
            item_type    = name_item.data(USER_ROLE_ITEM_TYPE)

            # only rename files via activation, because directories are expanded
            if item_type == ITEM_TYPE_FILE:
                self.rename_item(name_item)

    def rename_selected_file(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        if selection_count != 1:
            return

        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) != 1:
            return

        self.rename_item(selected_name_items[0])

    def rename_item(self, name_item):
        item_type = name_item.data(USER_ROLE_ITEM_TYPE)

        if item_type == ITEM_TYPE_FILE:
            title     = 'Rename File'
            type_name = 'file'
        else:
            title     = 'Rename Directory'
            type_name = 'directory'

        old_name = name_item.text()

        # get new name
        dialog = ExpandingInputDialog(get_main_window())
        dialog.setModal(True)
        dialog.setWindowTitle(title)
        dialog.setLabelText('Enter new {0} name:'.format(type_name))
        dialog.setInputMode(QInputDialog.TextInput)
        dialog.setTextValue(old_name)
        dialog.setOkButtonText('Rename')

        if dialog.exec_() != QDialog.Accepted:
            return

        new_name = dialog.textValue()

        if new_name == old_name:
            return

        # check that new name is valid
        if len(new_name) == 0 or new_name == '.' or new_name == '..' or '/' in new_name:
            QMessageBox.critical(get_main_window(), title + ' Error',
                                 'A {0} name cannot be empty, cannot be one dot [.], cannot be two dots [..] and cannot contain a forward slash [/].'
                                 .format(type_name))
            return

        # check that new name is not already in use
        name_item_parent = name_item.parent()

        if name_item_parent == None:
            name_item_parent = self.tree_files_model.invisibleRootItem()

        for i in range(name_item_parent.rowCount()):
            if new_name == name_item_parent.child(i).text():
                QMessageBox.critical(get_main_window(), title + ' Error',
                                     'The new {0} name is already in use.'.format(type_name))
                return

        absolute_old_name = posixpath.join(self.bin_directory, get_full_item_path(name_item))
        absolute_new_name = posixpath.join(posixpath.split(absolute_old_name)[0], new_name)

        def cb_rename(result):
            if not report_script_result(result, title + ' Error', u'Could not rename {0}'.format(type_name)):
                return

            name_item.setText(new_name)

            if self.tree_files.header().sortIndicatorSection() == 0:
                self.tree_files.header().setSortIndicator(0, self.tree_files.header().sortIndicatorOrder())

        self.script_manager.execute_script('rename', cb_rename,
                                           [absolute_old_name, absolute_new_name])

    def change_permissions_of_selected_file(self):
        selection_count = len(self.tree_files.selectionModel().selectedRows())

        if selection_count != 1:
            return

        selected_name_items = self.get_directly_selected_name_items()

        if len(selected_name_items) != 1:
            return

        name_item = selected_name_items[0]
        item_type = name_item.data(USER_ROLE_ITEM_TYPE)
        old_permissions = name_item.data(USER_ROLE_PERMISSIONS)

        if item_type == ITEM_TYPE_FILE:
            title     = 'Change File Permissions'
            type_name = 'file'
        else:
            title     = 'Change Directory Permissions'
            type_name = 'directory'

        dialog = ProgramInfoFilesPermissions(get_main_window(), title, old_permissions)

        if dialog.exec_() != QDialog.Accepted:
            return

        new_permissions = dialog.get_permissions()

        if new_permissions == (old_permissions & 0o777):
            return

        absolute_name = posixpath.join(self.bin_directory, get_full_item_path(name_item))

        def cb_change_permissions(result):
            if not report_script_result(result, title + ' Error', u'Could change {0} permissions'.format(type_name)):
                return

            name_item.setData(new_permissions, USER_ROLE_PERMISSIONS)

        self.script_manager.execute_script('change_permissions', cb_change_permissions,
                                           [absolute_name, str(new_permissions)])

    def delete_selected_files(self):
        button = QMessageBox.question(get_main_window(), 'Delete Files',
                                      'Irreversibly deleting selected files and directories.',
                                      QMessageBox.Ok, QMessageBox.Cancel)

        if not self.is_alive() or button != QMessageBox.Ok:
            return

        selected_name_items = set(self.get_directly_selected_name_items())

        if len(selected_name_items) == 0:
            return

        script_instance_ref = [None]

        def progress_canceled():
            script_instance = script_instance_ref[0]

            if script_instance == None:
                return

            self.script_manager.abort_script(script_instance)

        progress = ExpandingProgressDialog(self)
        progress.set_progress_text_visible(False)
        progress.setModal(True)
        progress.setWindowTitle('Delete Files')
        progress.setLabelText('Collecting files and directories to delete')
        progress.setRange(0, 0)
        progress.canceled.connect(progress_canceled)
        progress.show()

        files_to_delete = []
        dirs_to_delete  = []
        all_done        = False

        while not all_done:
            all_done = True

            for selected_name_item in list(selected_name_items):
                item_done = False
                parent = selected_name_item.parent()

                while not item_done and parent != None:
                    if parent in selected_name_items:
                        selected_name_items.remove(selected_name_item)
                        item_done = True
                    else:
                        parent = parent.parent()

                if item_done:
                    all_done = False
                    break

        for selected_name_item in selected_name_items:
            path      = get_full_item_path(selected_name_item)
            item_type = selected_name_item.data(USER_ROLE_ITEM_TYPE)

            if item_type == ITEM_TYPE_DIRECTORY:
                dirs_to_delete.append(posixpath.join(self.bin_directory, path))
            else:
                files_to_delete.append(posixpath.join(self.bin_directory, path))

        message = 'Deleting '

        if len(files_to_delete) == 1:
            message += '1 file '
        elif len(files_to_delete) > 1:
            message += '{0} files '.format(len(files_to_delete))

        if len(dirs_to_delete) == 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '1 directory'
        elif len(dirs_to_delete) > 1:
            if len(files_to_delete) > 0:
                message += 'and '

            message += '{0} directories'.format(len(dirs_to_delete))

        progress.setLabelText(message)

        def cb_delete(result):
            script_instance = script_instance_ref[0]

            if script_instance != None:
                aborted = script_instance.abort
            else:
                aborted = False

            script_instance_ref[0] = None

            progress.cancel()
            self.refresh_files()

            if aborted:
                QMessageBox.information(get_main_window(), 'Delete Files',
                                        u'Delete operation was aborted.')
                return

            report_script_result(result, 'Delete Files Error', 'Could not delete selected files/directories:')

        script_instance_ref[0] = self.script_manager.execute_script('delete', cb_delete,
                                                                    [json.dumps(files_to_delete), json.dumps(dirs_to_delete)],
                                                                    execute_as_user=True)
Exemple #32
0
    def randomize_groups(self):
        #participant_list_form = Participant_list()
        #participant_list_form.show()
        #participant_list_form.ui3.label.setText("sdsdfdsf")
        #ex2.ui.label_6.setText("test")
        participant_list_form = ex3
        # participant_list_form = Participant_list()
        # participant_list_form.show()
        tv = participant_list_form.ui3.tableView

        # set the table model
        tablemdata = 0
        #tabledata.append([2, 2, 2, 2, 2])
        # tabledata.remove([0])
        # tabledata.append([1, 1, 1, 1, 1])
        # table.model().layoutChanged.emit()
        tablemodel = MyTableModel(tabledata, header, self)
        rowcount = int(tablemodel.rowCount(None))
        tvmodel = tv.model()
        nums = [x+1 for x in range(rowcount)]
        random.shuffle(nums)

        print nums

        #iterating list





        #print i+1 % groups_to_create

        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # init widgets
        view = ex8.ui8.treeView
        view.setSelectionBehavior(QAbstractItemView.SelectRows)
        model = QStandardItemModel()
        model.setHorizontalHeaderLabels(header)
        view.setModel(model)
        view.setUniformRowHeights(True)
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # populate data

        groups_to_create = int(self.ui.lineEdit.text())
        participants_in_group = int(self.ui.lineEdit_2.text())
        divider = 0
        group = 1
        parent1 = QStandardItem('Grupa {}'.format(group))
        for i, val in enumerate(nums):

            if divider == participants_in_group:
                divider = 0
                group = group + 1
                parent1 = QStandardItem('Grupa {}'.format(group))
            divider = divider + 1
            if val != 0:
                print "Grupa " + str(group) + " Osoby: " + str(val)
                self.tableindex_id = tablemodel.index (val-1,1)
                self.tableindex_surname = tablemodel.index (val-1,2)
                child1 = QStandardItem(str(val)+' '+" ")
                child2 = QStandardItem(str(tablemodel.data(self.tableindex_id,  Qt.DisplayRole)))
                child3 = QStandardItem(str(tablemodel.data(self.tableindex_surname,  Qt.DisplayRole)))
                parent1.appendRow([child1, child2, child3])


                model.appendRow(parent1)
                # span container columns
                view.setFirstColumnSpanned(i, view.rootIndex(), True)


        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # expand third container
        index = model.indexFromItem(parent1)
        view.expand(index)
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        # select last row
        selmod = view.selectionModel()
        index2 = model.indexFromItem(child3)
        selmod.select(index2, QItemSelectionModel.Select | QItemSelectionModel.Rows)
        # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        print i+1
        if i+1 > 3:
            print i / groups_to_create
        else:
            print i / groups_to_create

        #index = tablemodel.index(row, 1)

        print nums
Exemple #33
0
    class VizRank(OWWidget):
        name = "Rank projections (Scatter Plot)"

        want_control_area = False

        def __init__(self, parent_widget):
            super().__init__()
            self.parent_widget = parent_widget
            self.running = False
            self.progress = None
            self.k = 10

            self.projectionTable = QTableView()
            self.mainArea.layout().addWidget(self.projectionTable)
            self.projectionTable.setSelectionBehavior(QTableView.SelectRows)
            self.projectionTable.setSelectionMode(QTableView.SingleSelection)
            self.projectionTable.setSortingEnabled(True)
            self.projectionTableModel = QStandardItemModel(self)
            self.projectionTable.setModel(self.projectionTableModel)
            self.projectionTable.selectionModel().selectionChanged.connect(
                self.on_selection_changed)

            self.button = gui.button(self.mainArea,
                                     self,
                                     "Start evaluation",
                                     callback=self.toggle,
                                     default=True)
            self.resize(380, 512)
            self._initialize()

        def _initialize(self):
            self.running = False
            self.projectionTableModel.clear()
            self.projectionTableModel.setHorizontalHeaderLabels(
                ["Score", "Feature 1", "Feature 2"])
            self.projectionTable.setColumnWidth(0, 60)
            self.projectionTable.setColumnWidth(1, 120)
            self.projectionTable.setColumnWidth(2, 120)
            self.button.setText("Start evaluation")
            self.button.setEnabled(False)
            self.pause = False
            self.data = None
            self.attrs = []
            self.scores = []
            self.i, self.j = 0, 0
            if self.progress:
                self.progress.finish()
            self.progress = None

            self.information(0)
            if self.parent_widget.data:
                if not self.parent_widget.data.domain.class_var:
                    self.information(
                        0, "Data with a class variable is required.")
                    return
                if len(self.parent_widget.data.domain.attributes) < 2:
                    self.information(0,
                                     'At least 2 unique features are needed.')
                    return
                if len(self.parent_widget.data) < 2:
                    self.information(0, 'At least 2 instances are needed.')
                    return
                self.button.setEnabled(True)

        def on_selection_changed(self, selected, deselected):
            """Called when the ranks view selection changes."""
            a1 = selected.indexes()[1].data()
            a2 = selected.indexes()[2].data()
            self.parent_widget.update_attr(attributes=(a1, a2))

        def toggle(self):
            self.running ^= 1
            if self.running:
                self.button.setText("Pause")
                self.run()
            else:
                self.button.setText("Continue")
                self.button.setEnabled(False)

        def run(self):
            graph = self.parent_widget.graph
            y_full = self.parent_widget.data.Y
            if not self.attrs:
                self.attrs = self.score_heuristic()
            if not self.progress:
                self.progress = gui.ProgressBar(
                    self,
                    len(self.attrs) * (len(self.attrs) - 1) / 2)
            for i in range(self.i, len(self.attrs)):
                ind1 = graph.attribute_name_index[self.attrs[i]]
                for j in range(self.j, i):
                    if not self.running:
                        self.i, self.j = i, j
                        if not self.projectionTable.selectedIndexes():
                            self.projectionTable.selectRow(0)
                        self.button.setEnabled(True)
                        return
                    ind2 = graph.attribute_name_index[self.attrs[j]]
                    X = graph.scaled_data[[ind1, ind2], :]
                    valid = graph.get_valid_list([ind1, ind2])
                    X = X[:, valid].T
                    if X.shape[0] < self.k:
                        self.progress.advance()
                        continue
                    y = y_full[valid]
                    n_neighbors = min(self.k, len(X) - 1)
                    knn = NearestNeighbors(n_neighbors=n_neighbors).fit(X)
                    ind = knn.kneighbors(return_distance=False)
                    if self.parent_widget.data.domain.has_discrete_class:
                        score = np.sum(y[ind] == y.reshape(-1, 1)) / (
                            len(y_full) * n_neighbors)
                    else:
                        score = r2_score(y, np.mean(
                            y[ind], axis=1)) * (len(y) / len(y_full))
                    pos = bisect_left(self.scores, score)
                    self.projectionTableModel.insertRow(
                        len(self.scores) - pos, [
                            QStandardItem("{:.4f}".format(score)),
                            QStandardItem(self.attrs[j]),
                            QStandardItem(self.attrs[i])
                        ])
                    self.scores.insert(pos, score)
                    self.progress.advance()
                self.j = 0
            self.progress.finish()
            if not self.projectionTable.selectedIndexes():
                self.projectionTable.selectRow(0)
            self.button.setText("Finished")
            self.button.setEnabled(False)

        def score_heuristic(self):
            X = self.parent_widget.graph.scaled_data.T
            Y = self.parent_widget.data.Y
            dom = Domain(
                [ContinuousVariable(str(i)) for i in range(X.shape[1])],
                self.parent_widget.data.domain.class_vars)
            data = Table(dom, X, Y)
            relief = ReliefF if isinstance(dom.class_var,
                                           DiscreteVariable) else RReliefF
            weights = relief(n_iterations=100, k_nearest=self.k)(data)
            attrs = sorted(zip(
                weights,
                (x.name for x in self.parent_widget.data.domain.attributes)),
                           reverse=True)
            return [a for _, a in attrs]
Exemple #34
0
class SetupDialog(QDialog, Ui_SetupDialog):
    """
        Function and Event handling class for the Ui_SetupDialog.
    """
    def __init__(self, parent):
        QDialog.__init__(self, parent)

        self._gui_logger = GUILogger("GUILogger", logging.INFO)
        self._gui_job = None
        EventLogger.add_logger(self._gui_logger)

        # FIXME better way to find interval and uids in tree_widget?!
        self.__tree_interval_tooltip = "Update interval in seconds"
        self.__tree_uid_tooltip = "UID cannot be empty"
        self.data_logger_thread = None
        self.tab_debug_warning = False

        self.device_dialog = None

        self.host_infos = None
        self.last_host = None
        self.host_index_changing = None

        self.setupUi(self)

        self.model_data = QStandardItemModel(self)
        self.model_data.setHorizontalHeaderLabels(
            ['Time', 'Name', 'UID', 'Var', 'Raw', 'Unit'])
        self.table_data.setModel(self.model_data)
        self.table_data.setColumnWidth(0, 160)
        self.table_data.setColumnWidth(1, 170)
        self.table_data.setColumnWidth(2, 50)
        self.table_data.setColumnWidth(3, 110)
        self.table_data.setColumnWidth(4, 70)
        self.table_data.setColumnWidth(5, 100)

        self.model_devices = QStandardItemModel(self)
        self.model_devices.setHorizontalHeaderLabels(['Device', 'Value'])
        self.tree_devices.setModel(self.model_devices)
        self.tree_devices.setColumnWidth(0, 300)

        self.widget_initialization()

        self.btn_start_logging.setIcon(
            QIcon(load_pixmap('data_logger/start-icon.png')))

        timestamp = int(time.time())
        self.edit_csv_file_name.setText(
            os.path.join(get_home_path(),
                         'logger_data_{0}.csv'.format(timestamp)))
        self.edit_log_file_name.setText(
            os.path.join(get_home_path(),
                         'logger_debug_{0}.log'.format(timestamp)))

        self.combo_data_time_format.addItem(
            utils.timestamp_to_de(timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de')
        self.combo_data_time_format.addItem(
            utils.timestamp_to_us(timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us')
        self.combo_data_time_format.addItem(
            utils.timestamp_to_iso(timestamp) + ' (ISO 8601)', 'iso')
        self.combo_data_time_format.addItem(
            utils.timestamp_to_unix(timestamp) + ' (Unix)', 'unix')

        self.combo_debug_time_format.addItem(
            utils.timestamp_to_de(timestamp) + ' (DD.MM.YYYY HH:MM:SS)', 'de')
        self.combo_debug_time_format.addItem(
            utils.timestamp_to_us(timestamp) + ' (MM/DD/YYYY HH:MM:SS)', 'us')
        self.combo_debug_time_format.addItem(
            utils.timestamp_to_iso(timestamp) + ' (ISO 8601)', 'iso')
        self.combo_debug_time_format.addItem(
            utils.timestamp_to_unix(timestamp) + ' (Unix)', 'unix')

        self.combo_log_level.addItem('Debug', 'debug')
        self.combo_log_level.addItem('Info', 'info')
        self.combo_log_level.addItem('Warning', 'warning')
        self.combo_log_level.addItem('Error', 'error')
        self.combo_log_level.addItem('Critical', 'critical')
        self.combo_log_level.setCurrentIndex(0)  # debug

        self.combo_debug_level.addItem('Debug', logging.DEBUG)
        self.combo_debug_level.addItem('Info', logging.INFO)
        self.combo_debug_level.addItem('Warning', logging.WARNING)
        self.combo_debug_level.addItem('Error', logging.ERROR)
        self.combo_debug_level.addItem('Critical', logging.CRITICAL)
        self.combo_debug_level.setCurrentIndex(1)  # info

        self.update_ui_state()

    def update_ui_state(self):
        data_to_csv_file = self.check_data_to_csv_file.isChecked()
        debug_to_log_file = self.check_debug_to_log_file.isChecked()

        self.label_csv_file_name.setVisible(data_to_csv_file)
        self.edit_csv_file_name.setVisible(data_to_csv_file)
        self.btn_browse_csv_file_name.setVisible(data_to_csv_file)

        self.label_log_file_name.setVisible(debug_to_log_file)
        self.edit_log_file_name.setVisible(debug_to_log_file)
        self.btn_browse_log_file_name.setVisible(debug_to_log_file)
        self.label_log_level.setVisible(debug_to_log_file)
        self.combo_log_level.setVisible(debug_to_log_file)

    def widget_initialization(self):
        """
            Sets default values for some widgets
        """
        # Login data
        self.host_info_initialization()

        self.signal_initialization()

    def signal_initialization(self):
        """
            Init of all important Signals and connections.
        """
        # Buttons
        self.btn_start_logging.clicked.connect(self.btn_start_logging_clicked)
        self.btn_save_config.clicked.connect(self.btn_save_config_clicked)
        self.btn_load_config.clicked.connect(self.btn_load_config_clicked)
        self.check_data_to_csv_file.stateChanged.connect(self.update_ui_state)
        self.check_debug_to_log_file.stateChanged.connect(self.update_ui_state)
        self.btn_browse_csv_file_name.clicked.connect(
            self.btn_browse_csv_file_name_clicked)
        self.btn_browse_log_file_name.clicked.connect(
            self.btn_browse_log_file_name_clicked)
        self.btn_clear_debug.clicked.connect(self.btn_clear_debug_clicked)
        self.combo_debug_level.currentIndexChanged.connect(
            self.combo_debug_level_changed)
        self.btn_add_device.clicked.connect(self.btn_add_device_clicked)
        self.btn_remove_device.clicked.connect(self.btn_remove_device_clicked)
        self.btn_remove_all_devices.clicked.connect(
            self.btn_remove_all_devices_clicked)

        self.tab_widget.currentChanged.connect(self.tab_reset_warning)
        self.btn_clear_data.clicked.connect(self.btn_clear_data_clicked)

        self.connect(self._gui_logger,
                     QtCore.SIGNAL(GUILogger.SIGNAL_NEW_MESSAGE),
                     self.add_debug_message)
        self.connect(self._gui_logger,
                     QtCore.SIGNAL(GUILogger.SIGNAL_NEW_MESSAGE_TAB_HIGHLIGHT),
                     self.highlight_debug_tab)

        self.combo_host.currentIndexChanged.connect(self._host_index_changed)
        self.spin_port.valueChanged.connect(self._port_changed)

    def host_info_initialization(self):
        """
            initialize host by getting information out of brickv.config
        """
        self.host_infos = config.get_host_infos(config.HOST_INFO_COUNT)
        self.host_index_changing = True

        for host_info in self.host_infos:
            self.combo_host.addItem(host_info.host)

        self.last_host = None
        self.combo_host.setCurrentIndex(0)
        self.spin_port.setValue(self.host_infos[0].port)
        self.host_index_changing = False

    def btn_start_logging_clicked(self):
        """
            Start/Stop of the logging process
        """
        if (self.data_logger_thread
                is not None) and (not self.data_logger_thread.stopped):
            self.btn_start_logging.clicked.disconnect()

            self.data_logger_thread.stop()
            self._reset_stop()

        elif self.data_logger_thread is None:
            from brickv.data_logger import main

            self._gui_job = GuiDataJob(name="GuiData-Writer")
            self.connect(self._gui_job,
                         QtCore.SIGNAL(GuiDataJob.SIGNAL_NEW_DATA),
                         self.table_add_row)

            self.data_logger_thread = main.main(
                None, GuiConfigHandler.create_config(self), self._gui_job)

            if self.data_logger_thread is not None:
                self.btn_start_logging.setText("Stop Logging")
                self.btn_start_logging.setIcon(
                    QIcon(load_pixmap('data_logger/stop-icon.png')))
                self.tab_devices.setEnabled(False)
                self.tab_setup.setEnabled(False)
                self.tab_widget.setCurrentIndex(
                    self.tab_widget.indexOf(self.tab_data))
                self.tab_reset_warning()

    def _reset_stop(self):
        self.tab_devices.setEnabled(True)
        self.tab_setup.setEnabled(True)
        self.btn_start_logging.setText("Start Logging")
        self.btn_start_logging.setIcon(
            QIcon(load_pixmap('data_logger/start-icon.png')))

        self.disconnect(self._gui_job,
                        QtCore.SIGNAL(GuiDataJob.SIGNAL_NEW_DATA),
                        self.table_add_row)
        self.data_logger_thread = None
        self._gui_job = None

        self.btn_start_logging.clicked.connect(self.btn_start_logging_clicked)

    def btn_save_config_clicked(self):
        filename = get_save_file_name(get_main_window(), 'Save Config',
                                      get_home_path(), 'JSON Files (*.json)')

        if len(filename) == 0:
            return

        if not filename.lower().endswith('.json'):
            filename += '.json'

        config = GuiConfigHandler.create_config(self)

        if not save_config(config, filename):
            QMessageBox.warning(
                get_main_window(), 'Save Config',
                'Could not save config to file! See Debug tab for details.',
                QMessageBox.Ok)

    def btn_load_config_clicked(self):
        filename = get_open_file_name(get_main_window(), 'Load Config',
                                      get_home_path(), 'JSON Files (*.json)')

        if len(filename) == 0:
            return

        config = load_and_validate_config(filename)

        if config == None:
            QMessageBox.warning(
                get_main_window(), 'Load Config',
                'Could not load config from file! See Debug tab for details.',
                QMessageBox.Ok)
            return

        self.update_setup_tab(config)
        self.update_devices_tab(config)

    def btn_browse_csv_file_name_clicked(self):
        if len(self.edit_csv_file_name.text()) > 0:
            last_dir = os.path.dirname(
                os.path.realpath(self.edit_csv_file_name.text()))
        else:
            last_dir = get_home_path()

        filename = get_save_file_name(get_main_window(), 'Choose CSV File',
                                      last_dir, "CSV Files (*.csv)")

        if len(filename) > 0:
            if not filename.lower().endswith('.csv'):
                filename += '.csv'

            self.edit_csv_file_name.setText(filename)

    def btn_browse_log_file_name_clicked(self):
        if len(self.edit_log_file_name.text()) > 0:
            last_dir = os.path.dirname(
                os.path.realpath(self.edit_log_file_name.text()))
        else:
            last_dir = get_home_path()

        filename = get_save_file_name(get_main_window(), 'Choose Log File',
                                      last_dir, "Log Files (*.log)")

        if len(filename) > 0:
            if not filename.lower().endswith('.log'):
                filename += '.log'

            self.edit_log_file_name.setText(filename)

    def btn_add_device_clicked(self):
        """
            Opens the DeviceDialog in Add-Mode.
        """
        if self.device_dialog is None:
            self.device_dialog = DeviceDialog(self)

        self.device_dialog.btn_refresh_clicked()
        self.device_dialog.show()

    def btn_remove_device_clicked(self):
        selection = self.tree_devices.selectionModel().selectedIndexes()

        while len(selection) > 0:
            index = selection[0]

            while index.parent() != self.model_devices.invisibleRootItem(
            ).index():
                index = index.parent()

            self.model_devices.removeRows(index.row(), 1)

            # get new selection, because row removal might invalid indices
            selection = self.tree_devices.selectionModel().selectedIndexes()

    def btn_remove_all_devices_clicked(self):
        self.model_devices.removeRows(0, self.model_devices.rowCount())

    def btn_clear_data_clicked(self):
        self.model_data.removeRows(0, self.model_data.rowCount())

    def tab_reset_warning(self):
        """
            Resets the Warning @ the debug tab.
        """
        if not self.tab_debug_warning or self.tab_widget.currentWidget(
        ).objectName() != self.tab_debug.objectName():
            return

        self.tab_debug_warning = False

        self.tab_set(self.tab_widget.indexOf(self.tab_debug),
                     self.palette().color(QPalette.WindowText), None)

    def combo_debug_level_changed(self):
        """
            Changes the log level dynamically.
        """
        self._gui_logger.level = self.combo_debug_level.itemData(
            self.combo_debug_level.currentIndex())

    def tab_set(self, tab_index, color, icon=None):
        """
            Sets the font Color and an icon, if given, at a specific tab.
        """
        from PyQt4.QtGui import QIcon

        self.tab_widget.tabBar().setTabTextColor(tab_index, color)
        if icon is not None:
            self.tab_widget.setTabIcon(tab_index, QIcon(icon))
        else:
            self.tab_widget.setTabIcon(tab_index, QIcon())

    def _host_index_changed(self, i):
        """
            Persists host information changes like in brickv.mainwindow
            Changes port if the host was changed
        """
        if i < 0:
            return

        self.host_index_changing = True
        self.spin_port.setValue(self.host_infos[i].port)
        self.host_index_changing = False

    def _port_changed(self, value):
        """
            Persists host information changes like in brickv.mainwindow
        """
        if self.host_index_changing:
            return

        i = self.combo_host.currentIndex()
        if i < 0:
            return

        self.host_infos[i].port = self.spin_port.value()

    def update_setup_tab(self, config):
        EventLogger.debug('Updating setup tab from config')

        self.combo_host.setEditText(config['hosts']['default']['name'])
        self.spin_port.setValue(config['hosts']['default']['port'])

        self.combo_data_time_format.setCurrentIndex(
            max(
                self.combo_data_time_format.findData(
                    config['data']['time_format']), 0))
        self.check_data_to_csv_file.setChecked(
            config['data']['csv']['enabled'])
        self.edit_csv_file_name.setText(
            config['data']['csv']['file_name'].decode('utf-8'))

        self.combo_debug_time_format.setCurrentIndex(
            max(
                self.combo_debug_time_format.findData(
                    config['debug']['time_format']), 0))
        self.check_debug_to_log_file.setChecked(
            config['debug']['log']['enabled'])
        self.edit_log_file_name.setText(
            config['debug']['log']['file_name'].decode('utf-8'))
        self.combo_log_level.setCurrentIndex(
            max(
                self.combo_debug_time_format.findData(
                    config['debug']['log']['level']), 0))

    def update_devices_tab(self, config):
        EventLogger.debug('Updating devices tab from config')

        self.model_devices.removeRows(0, self.model_data.rowCount())

        for device in config['devices']:
            self.add_device_to_tree(device)

    def add_device_to_tree(self, device):
        # check if device is already added
        if len(device['uid']) > 0:
            for row in range(self.model_devices.rowCount()):
                existing_name = self.model_devices.item(row, 0).text()
                exisitng_uid = self.tree_devices.indexWidget(
                    self.model_devices.item(row, 1).index()).text()

                if device['name'] == existing_name and device[
                        'uid'] == exisitng_uid:
                    EventLogger.info(
                        'Ignoring duplicate device "{0}" with UID "{1}"'.
                        format(device['name'], device['uid']))
                    return

        # add device
        name_item = QStandardItem(device['name'])
        uid_item = QStandardItem('')

        self.model_devices.appendRow([name_item, uid_item])

        edit_uid = QLineEdit()
        edit_uid.setPlaceholderText('Enter UID')
        edit_uid.setValidator(
            QRegExpValidator(QRegExp(
                '^[{0}]{{1,6}}$'.format(BASE58))))  # FIXME: use stricter logic
        edit_uid.setText(device['uid'])

        self.tree_devices.setIndexWidget(uid_item.index(), edit_uid)

        value_specs = device_specs[device['name']]['values']
        parent_item = QStandardItem('Values')

        name_item.appendRow([parent_item, QStandardItem('')])
        self.tree_devices.expand(parent_item.index())

        # add values
        for value_spec in value_specs:
            value_name_item = QStandardItem(value_spec['name'])
            value_interval_item = QStandardItem('')

            parent_item.appendRow([value_name_item, value_interval_item])

            spinbox_interval = QSpinBox()
            spinbox_interval.setRange(0, (1 << 31) - 1)
            spinbox_interval.setSingleStep(1)
            spinbox_interval.setValue(
                device['values'][value_spec['name']]['interval'])
            spinbox_interval.setSuffix(' seconds')

            self.tree_devices.setIndexWidget(value_interval_item.index(),
                                             spinbox_interval)

            if value_spec['subvalues'] != None:
                for subvalue_name in value_spec['subvalues']:
                    subvalue_name_item = QStandardItem(subvalue_name)
                    subvalue_check_item = QStandardItem('')

                    value_name_item.appendRow(
                        [subvalue_name_item, subvalue_check_item])

                    check_subvalue = QCheckBox()
                    check_subvalue.setChecked(device['values'][
                        value_spec['name']]['subvalues'][subvalue_name])

                    self.tree_devices.setIndexWidget(
                        subvalue_check_item.index(), check_subvalue)

        self.tree_devices.expand(name_item.index())

        # add options
        option_specs = device_specs[device['name']]['options']

        if option_specs != None:
            parent_item = QStandardItem('Options')

            name_item.appendRow([parent_item, QStandardItem('')])

            for option_spec in option_specs:
                option_name_item = QStandardItem(option_spec['name'])
                option_widget_item = QStandardItem('')

                parent_item.appendRow([option_name_item, option_widget_item])

                if option_spec['type'] == 'choice':
                    widget_option_value = QComboBox()

                    for option_value_spec in option_spec['values']:
                        widget_option_value.addItem(
                            option_value_spec[0].decode('utf-8'),
                            option_value_spec[1])

                    widget_option_value.setCurrentIndex(
                        widget_option_value.findText(device['options'][
                            option_spec['name']]['value'].decode('utf-8')))
                elif option_spec['type'] == 'int':
                    widget_option_value = QSpinBox()
                    widget_option_value.setRange(option_spec['minimum'],
                                                 option_spec['maximum'])
                    widget_option_value.setSuffix(option_spec['suffix'])
                    widget_option_value.setValue(
                        device['options'][option_spec['name']]['value'])
                elif option_spec['type'] == 'bool':
                    widget_option_value = QCheckBox()
                    widget_option_value.setChecked(
                        device['options'][option_spec['name']]['value'])

                self.tree_devices.setIndexWidget(option_widget_item.index(),
                                                 widget_option_value)

    def add_debug_message(self, message):
        self.text_debug.append(message)

        while self.text_debug.document().blockCount() > 1000:
            cursor = QTextCursor(self.text_debug.document().begin())
            cursor.select(QTextCursor.BlockUnderCursor)
            cursor.movePosition(QTextCursor.Right, QTextCursor.KeepAnchor)
            cursor.removeSelectedText()

        if self.checkbox_debug_auto_scroll.isChecked():
            self.text_debug.verticalScrollBar().setValue(
                self.text_debug.verticalScrollBar().maximum())

    def btn_clear_debug_clicked(self):
        self.text_debug.clear()

    def highlight_debug_tab(self):
        """
            SIGNAL function:
            Highlight the debug tab when an error occurs.
        """
        if not self.tab_debug_warning and self.tab_widget.currentWidget(
        ).objectName() != self.tab_debug.objectName():
            self.tab_debug_warning = True
            self.tab_set(
                self.tab_widget.indexOf(self.tab_debug), QColor(255, 0, 0),
                os.path.join(get_resources_path(), "warning-icon.png"))

    def table_add_row(self, csv_data):
        """
            SIGNAL function:
            Adds new CSV Data into the Table.
        """
        rows = self.model_data.rowCount()

        while rows >= 1000:
            self.model_data.removeRow(0)
            rows = self.model_data.rowCount()

        row_number = None

        if rows > 0:
            try:
                row_number = int(
                    self.model_data.headerData(rows - 1, Qt.Vertical))
            except ValueError:
                pass

        self.model_data.appendRow([
            QStandardItem(csv_data.timestamp),
            QStandardItem(csv_data.name),
            QStandardItem(csv_data.uid),
            QStandardItem(csv_data.var_name),
            QStandardItem(str(csv_data.raw_data)),
            QStandardItem(csv_data.var_unit.decode('utf-8'))
        ])

        if row_number != None:
            self.model_data.setHeaderData(rows, Qt.Vertical,
                                          str(row_number + 1))

        if self.checkbox_data_auto_scroll.isChecked():
            self.table_data.scrollToBottom()
class ObstacleTable(QSortFilterProxyModel):

    MocMultiplier = 1
    SelectionMode = SelectionModeType.Automatic

    def __init__(self, surfacesList, fileWriter=None):
        QSortFilterProxyModel.__init__(self)
        ObstacleTable.SelectionMode = SelectionModeType.Automatic
        self.manualPolygon = None
        self.surfacesList = surfacesList
        self.surfaceType = None
        self.source = QStandardItemModel()
        self.setSourceModel(self.source)
        #         tableView.hideColumn(self.IndexObjectId)
        #         tableView.hideColumn(self.IndexLayerId)
        #         tableView.hideColumn(self.IndexX)
        #         tableView.hideColumn(self.IndexY)
        #         tableView.hideColumn(self.IndexLat)
        #         tableView.hideColumn(self.IndexLon)
        #         tableView.hideColumn(self.IndexSurface)
        self.hideColumnLabels = [
            ObstacleTableColumnType.ObjectId, ObstacleTableColumnType.LayerId,
            ObstacleTableColumnType.X, ObstacleTableColumnType.Y,
            ObstacleTableColumnType.Lat, ObstacleTableColumnType.Lon,
            ObstacleTableColumnType.Surface
        ]

        self.fixedColumnLabels = [
            ObstacleTableColumnType.ObjectId, ObstacleTableColumnType.LayerId,
            ObstacleTableColumnType.Name, ObstacleTableColumnType.X,
            ObstacleTableColumnType.Y, ObstacleTableColumnType.Lat,
            ObstacleTableColumnType.Lon, ObstacleTableColumnType.AltM,
            ObstacleTableColumnType.AltFt, ObstacleTableColumnType.TreesM,
            ObstacleTableColumnType.TreesFt
        ]

        self.IndexObjectId = 0
        self.IndexLayerId = 1
        self.IndexName = 2
        self.IndexX = 3
        self.IndexY = 4
        self.IndexLat = 5
        self.IndexLon = 6
        self.IndexAltM = 7
        self.IndexAltFt = 8
        self.IndexTreesM = 9
        self.IndexTreesFt = 10
        self.IndexOcaM = -1
        self.IndexOcaFt = -1
        self.IndexOchM = -1
        self.IndexOchFt = -1
        self.IndexObstArea = -1
        self.IndexDistInSecM = -1
        self.IndexMocAppliedM = -1
        self.IndexMocAppliedFt = -1
        self.IndexMocMultiplier = -1
        self.IndexMocReqM = -1
        self.IndexMocReqFt = -1
        self.IndexDoM = -1
        self.IndexDrM = -1
        self.IndexDzM = -1
        self.IndexDxM = -1
        self.IndexDsocM = -1
        self.IndexHeightLossM = -1
        self.IndexHeightLossFt = -1
        self.IndexAcAltM = -1
        self.IndexAcAltFt = -1
        self.IndexAltReqM = -1
        self.IndexAltReqFt = -1
        self.IndexCritical = -1
        self.IndexMACG = -1
        self.IndexPDG = -1
        self.IndexSurfAltM = -1
        self.IndexSurfAltFt = -1
        self.IndexDifferenceM = -1
        self.IndexDifferenceFt = -1
        self.IndexIlsX = -1
        self.IndexIlsY = -1
        self.IndexEqAltM = -1
        self.IndexEqAltFt = -1
        self.IndexSurfaceName = -1
        self.IndexDisregardable = -1
        self.IndexCloseIn = -1
        self.IndexTag = -1
        self.IndexSurface = -1
        self.IndexArea = -1
        self.IndexHLAppliedM = -1
        self.setHeaderLabels()
        self.setFilterKeyColumn(self.IndexSurface)
        self.setSortRole(Qt.UserRole + 1)
        self.layoutChanged.connect(self.setVerticalHeader)
        self.btnLocate = None
        self.tblObstacles = None

    def FilterDisregardableObstacles(self, state):
        if state:
            self.setFilterKeyColumn(self.IndexDisregardable)
            self.setFilterFixedString("Yes")
            self.setFilterKeyColumn(self.IndexSurface)

    def setSurfaceType(self, surfaceType):
        self.surfaceType = surfaceType

    def setFilterFixedString(self, filterString):
        QSortFilterProxyModel.setFilterFixedString(self, filterString)
        self.setVerticalHeader()
        if self.btnLocate != None and self.tblObstacles != None:
            selectedIndexes = self.tblObstacles.selectedIndexes()
            if len(selectedIndexes) == 0:
                self.btnLocate.setEnabled(False)
            else:
                self.btnLocate.setEnabled(True)

    def setLocateBtn(self, btnLocate):
        self.btnLocate = btnLocate
        self.btnLocate.setEnabled(False)
        self.btnLocate.clicked.connect(self.btnLocateClicked)

    def btnLocateClicked(self):
        if self.tblObstacles == None:
            return
        selectedIndexes = self.tblObstacles.selectedIndexes()
        self.locate(selectedIndexes)

    def tblObstaclesClicked(self, idx):
        if len(self.tblObstacles.selectedIndexes()) > 0:
            self.btnLocate.setEnabled(True)

    def setTableView(self, tblObstacles):
        self.tblObstacles = tblObstacles
        self.tblObstacles.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.tblObstacles.setSortingEnabled(True)
        self.tblObstacles.clicked.connect(self.tblObstaclesClicked)
        self.tblObstacles.verticalHeader().sectionClicked.connect(
            self.tblObstaclesClicked)
        pass

    def setHeaderLabels(self):
        #         print self.setHeaderData(1, Qt.Vertical, 1, Qt.DisplayRole)
        pass

    def setVerticalHeader(self):
        for i in range(self.rowCount()):
            self.setHeaderData(i, Qt.Vertical, i + 1, Qt.DisplayRole)

    def setHiddenColumns(self, tableView):
        tableView.hideColumn(self.IndexObjectId)
        tableView.hideColumn(self.IndexLayerId)
        tableView.hideColumn(self.IndexX)
        tableView.hideColumn(self.IndexY)
        tableView.hideColumn(self.IndexLat)
        tableView.hideColumn(self.IndexLon)
        tableView.hideColumn(self.IndexSurface)

    def getExtentForLocate(self, sourceRow):
        extent = None
        surfaceType = None
        if self.IndexSurface < 0:
            surfaceType = self.surfaceType
        else:
            surfaceType = self.source.item(sourceRow, self.IndexSurface).text()
        surfaceLayers = QgisHelper.getSurfaceLayers(self.surfaceType)
        for sfLayer in surfaceLayers:
            lId = sfLayer.name()
            if lId.contains(surfaceType):
                extent = sfLayer.extent()
                break
        return extent

    def clear(self):
        self.source.clear()
        self.source.setHorizontalHeaderLabels(self.fixedColumnLabels)
#         self.setHeaderLabels()

    def locate(self, selectedRowIndexes):
        if selectedRowIndexes == None or len(selectedRowIndexes) <= 0:
            return
        sourceRow = self.mapToSource(selectedRowIndexes[0]).row()
        objectId = int(self.source.item(sourceRow, self.IndexObjectId).text())
        layerId = self.source.item(sourceRow, self.IndexLayerId).text()
        QgisHelper.selectFeature(layerId, objectId)
        layer = QgsMapLayerRegistry.instance().mapLayer(layerId)
        crs = define._canvas.mapSettings().destinationCrs()
        if crs.mapUnits() == QGis.Meters:
            x = float(self.source.item(sourceRow, self.IndexX).text())
            y = float(self.source.item(sourceRow, self.IndexY).text())
            extent = QgsRectangle(x - 350, y - 350, x + 350, y + 350)
        else:
            x, result1 = self.source.item(sourceRow,
                                          self.IndexLon).data().toDouble()
            y, result2 = self.source.item(sourceRow,
                                          self.IndexLat).data().toDouble()
            extent = QgsRectangle(x - 0.005, y - 0.005, x + 0.005, y + 0.005)
        point = QgsPoint(x, y)
        # extent = self.getExtentForLocate(sourceRow)

        if extent is None:
            return

        QgisHelper.zoomExtent(point, extent, 2)
        pass

    def loadObstacles(self, surfaceLayers):
        if self.source.rowCount() > 0:
            self.source.clear()
            self.source.setHorizontalHeaderLabels(self.fixedColumnLabels)
        demEvaluateAg = None
        existingDemFlag = False
        obstacleLayersDEM = QgisHelper.getSurfaceLayers(SurfaceTypes.DEM)
        obstacleLayers = QgisHelper.getSurfaceLayers(SurfaceTypes.Obstacles)
        if obstacleLayersDEM != None and len(obstacleLayersDEM) > 0:
            if QMessageBox.question(
                    None, "Question",
                    "Do you want to use DEM for evaluating Obstacle?",
                    QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes:
                self.loadObstaclesDEM(obstacleLayersDEM, surfaceLayers)
        if obstacleLayers != None and len(obstacleLayers) > 0:
            #             if QMessageBox.question(None, "Question", "Do you want to use DEM for evaluating Obstacle?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.No:
            self.loadObstaclesVector(obstacleLayers, surfaceLayers)
        return True

    def loadObstaclesDEM(self, obstacleLayersDEM, surfaceLayers):
        progressMessageBar = define._messagBar.createMessage(
            "Loading DEM Obstacles...")
        self.progress = QProgressBar()
        self.progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        progressMessageBar.layout().addWidget(self.progress)
        define._messagBar.pushWidget(progressMessageBar,
                                     define._messagBar.INFO)
        maxium = 0
        offset = 0.0
        self.progress.setValue(0)
        wCount = 0
        hCount = 0
        for ly in obstacleLayersDEM:
            demDataProvider = ly.dataProvider()
            boundDem = demDataProvider.extent()
            xMin = boundDem.xMinimum()
            xMax = boundDem.xMaximum()
            yMin = boundDem.yMinimum()
            yMax = boundDem.yMaximum()
            bound = QgisHelper.getIntersectExtent(
                ly, QgsGeometry.fromRect(boundDem), surfaceLayers)
            #             boundGeom = QgsGeometry.fromRect(bound)
            if bound == None:
                continue
            block = ly.dataProvider().block(0, ly.extent(), ly.width(),
                                            ly.height())
            xMinimum = ly.dataProvider().extent().xMinimum()
            yMaximum = ly.dataProvider().extent().yMaximum()
            yMinimum = ly.dataProvider().extent().yMinimum()
            xMaximum = ly.dataProvider().extent().xMaximum()

            xOffSet = ly.extent().width() / ly.width()
            yOffSet = ly.extent().height() / ly.height()
            offset = xOffSet
            if bound.xMinimum() < xMinimum:
                wStartNumber = 0
                xStartValue = xMinimum
            else:
                wStartNumber = int((bound.xMinimum() - xMinimum) / xOffSet)
                xStartValue = bound.xMinimum()
            if yMaximum < bound.yMaximum():
                hStartNumber = 0
                yStartValue = yMaximum
            else:
                hStartNumber = int((yMaximum - bound.yMaximum()) / yOffSet)
                yStartValue = bound.yMaximum()

            if bound.xMaximum() > xMaximum:
                xEndValue = xMaximum
            else:
                xEndValue = bound.xMaximum()
            if yMinimum > bound.yMinimum():
                yEndValue = yMinimum
            else:
                yEndValue = bound.yMinimum()
            wCount = int(math.fabs(xEndValue - xStartValue) / xOffSet)
            hCount = int(math.fabs(yEndValue - yStartValue) / yOffSet)

            pixelCount = hCount
            maxium += pixelCount

        cellSizeWnd = cellsizeWnd(offset, wCount * hCount, maxium * 0.04)
        cellSizeWnd.setWindowTitle("Input Cell Size")
        result = cellSizeWnd.exec_()
        cellRate = 1
        if result == 1:
            offset = cellSizeWnd.cellsize
            maxium = cellSizeWnd.cellCount + 2
            cellRate = cellSizeWnd.cellRate


#             print cellSizeWnd.textedit1.text()

        if maxium == 0:
            return False
        self.progress.setMaximum(maxium)

        trees = define._treesDEM
        tolerance = define._toleranceDEM

        for obstacleLayer in obstacleLayersDEM:
            obstacleUnits = obstacleLayer.crs().mapUnits()
            demDataProvider = obstacleLayer.dataProvider()
            boundDem = demDataProvider.extent()
            bound = QgisHelper.getIntersectExtent(
                obstacleLayer, QgsGeometry.fromRect(boundDem), surfaceLayers)
            if bound == None:
                continue
            boundGeom = QgsGeometry.fromRect(bound)
            if not boundGeom.intersects(QgsGeometry.fromRect(boundDem)):
                continue
            block = obstacleLayer.dataProvider().block(1,
                                                       obstacleLayer.extent(),
                                                       obstacleLayer.width(),
                                                       obstacleLayer.height())
            xMinimum = obstacleLayer.extent().xMinimum()
            yMaximum = obstacleLayer.extent().yMaximum()
            yMinimum = obstacleLayer.extent().yMinimum()
            xMaximum = obstacleLayer.extent().xMaximum()

            xOffSet = obstacleLayer.extent().width() / obstacleLayer.width()
            yOffSet = obstacleLayer.extent().height() / obstacleLayer.height()

            if bound.xMinimum() < xMinimum:
                hStartNumber = 0
                xStartValue = xMinimum
            else:
                hStartNumber = int((bound.xMinimum() - xMinimum) / xOffSet)
                xStartValue = bound.xMinimum()
            if yMaximum < bound.yMaximum():
                wStartNumber = 0
                yStartValue = yMaximum
            else:
                wStartNumber = int((yMaximum - bound.yMaximum()) / yOffSet)
                yStartValue = bound.yMaximum()

            if bound.xMaximum() > xMaximum:
                xEndValue = xMaximum
            else:
                xEndValue = bound.xMaximum()
            if yMinimum > bound.yMinimum():
                yEndValue = yMinimum
            else:
                yEndValue = bound.yMinimum()
            wCount = int(math.fabs(xEndValue - xStartValue) / offset)
            hCount = int(math.fabs(yEndValue - yStartValue) / offset)

            xPixelWidth = 0.0
            yPixelWidth = 0.0
            featureID = 0
            # i = 0
            # k = 0
            # altitudeList = []
            # self.progress.setValue(0)
            # while i  <=  hCount - 1:
            #     j = 0
            #     while j <= wCount - 1:
            #         if block.isNoData(j * int(cellRate) + wStartNumber, i* int(cellRate) + hStartNumber):
            #             self.progress.setValue(k)
            #             QApplication.processEvents()
            #             j += 1
            #             k += 1
            #             altitudeList.append(None)
            #             continue
            #         altitude = block.value(j * int(cellRate) + wStartNumber, i * int(cellRate) + hStartNumber)
            #         altitudeList.append(altitude)
            #         self.progress.setValue(k)
            #         QApplication.processEvents()
            #         j += 1
            #         k += 1
            #     i += 1

            i = 0
            k = 0
            name = "DEM"
            semiXoffset = xOffSet / 2
            semiYoffset = yOffSet / 2
            while i <= hCount - 1:
                j = 0
                while j <= wCount - 1:
                    if block.isNoData(j * cellRate + wStartNumber,
                                      i * cellRate + hStartNumber):
                        self.progress.setValue(k)
                        QApplication.processEvents()
                        j += 1
                        k += 1
                        continue
                    altitude = block.value(j * cellRate + wStartNumber,
                                           i * cellRate + hStartNumber)
                    # # if block.isNoData(j * int(cellRate) + wStartNumber, i* int(cellRate) + hStartNumber):
                    # #     j += 1
                    # #     self.progress.setValue(self.progress.value() + 1)
                    # #     QApplication.processEvents()
                    # #     continue
                    # # altitude = block.value(j* int(cellRate) + wStartNumber, i* int(cellRate)+ hStartNumber)
                    # altitude = altitudeList[k]
                    # if altitude == None:
                    #     self.progress.setValue(k)
                    #     QApplication.processEvents()
                    #     j += 1
                    #     k += 1
                    #     continue

                    point = QgsPoint(
                        xStartValue + (i * cellRate) * xOffSet + semiXoffset,
                        yStartValue - (j * cellRate - 1) * yOffSet -
                        semiYoffset)
                    position = Point3D()
                    positionDegree = Point3D()

                    if define._canvas.mapUnits() == QGis.Meters:
                        if define._canvas.mapSettings().destinationCrs(
                        ) != obstacleLayer.crs():
                            position = QgisHelper.CrsTransformPoint(
                                point.x(), point.y(), obstacleLayer.crs(),
                                define._canvas.mapSettings().destinationCrs(),
                                altitude)
                        else:
                            position = Point3D(point.x(), point.y(), altitude)
                    else:
                        if define._canvas.mapSettings().destinationCrs(
                        ) != obstacleLayer.crs():
                            positionDegree = QgisHelper.CrsTransformPoint(
                                point.x(), point.y(), obstacleLayer.crs(),
                                define._canvas.mapSettings().destinationCrs(),
                                altitude)
                        else:
                            positionDegree = Point3D(point.x(), point.y(),
                                                     altitude)
                    obstacle = Obstacle(name, position, obstacleLayer.id(),
                                        featureID, None, trees,
                                        ObstacleTable.MocMultiplier, tolerance)
                    obstacle.positionDegree = positionDegree
                    if self.manualPolygon != None:
                        if not self.manualPolygon.contains(obstacle.Position):
                            continue
                    self.checkObstacle(obstacle)
                    self.progress.setValue(k)
                    QApplication.processEvents()
                    j += 1
                    featureID += 1
                    k += 1
                i += 1
        self.progress.setValue(maxium)
        define._messagBar.hide()
        self.manualPolygon = None

    def loadObstaclesVector(self, obstacleLayers, surfaceLayers):
        progressMessageBar = define._messagBar.createMessage(
            "Loading Vector Obstacles...")
        self.progress = QProgressBar()
        self.progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        progressMessageBar.layout().addWidget(self.progress)
        define._messagBar.pushWidget(progressMessageBar,
                                     define._messagBar.INFO)
        maxium = 0
        self.progress.setValue(0)
        for ly in obstacleLayers:
            maxium += ly.featureCount()

        if maxium == 0:
            return False
        self.progress.setMaximum(maxium)

        for obstacleLayer in obstacleLayers:
            obstacleUnits = obstacleLayer.crs().mapUnits()
            features = QgisHelper.getFeaturesInLayerExtent(
                define._canvas, obstacleLayer, surfaceLayers,
                SelectionModeType.Automatic)
            #             print len(features)
            for feature in features:
                name = feature.attribute("Name").toString()
                altitude = feature.attribute("Altitude").toFloat()[0]
                trees = define._trees
                tolerance = define._tolerance
                point = feature.geometry().asPoint()
                position = Point3D()
                positionDegree = Point3D()
                if define._canvas.mapUnits() == QGis.Meters:
                    if define._canvas.mapSettings().destinationCrs(
                    ) != obstacleLayer.crs():
                        position = QgisHelper.CrsTransformPoint(
                            point.x(), point.y(), obstacleLayer.crs(),
                            define._canvas.mapSettings().destinationCrs(),
                            altitude)
                    else:
                        position = Point3D(point.x(), point.y(), altitude)
                else:
                    if define._canvas.mapSettings().destinationCrs(
                    ) != obstacleLayer.crs():
                        positionDegree = QgisHelper.CrsTransformPoint(
                            point.x(), point.y(), obstacleLayer.crs(),
                            define._canvas.mapSettings().destinationCrs(),
                            altitude)
                    else:
                        positionDegree = Point3D(point.x(), point.y(),
                                                 altitude)
                featureId = feature.id()
                layerId = obstacleLayer.id()
                obstacle = Obstacle(name, position, layerId, featureId, None,
                                    trees, ObstacleTable.MocMultiplier,
                                    tolerance)
                obstacle.positionDegree = positionDegree
                #                 obstacle.positionDegree = positionDegree
                self.checkObstacle(obstacle)
                self.progress.setValue(self.progress.value() + 1)
                QApplication.processEvents()
            QApplication.processEvents()
        self.progress.setValue(maxium)
        define._messagBar.hide()
        self.manualPolygon = None

    def addObstacleToModel(self, obstacle, checkResult=None):
        standardItemList = []
        # obstacle.positionDegree = QgisHelper.Meter2Degree(obstacle.Position.x(), obstacle.Position.y())
        standardItem = QStandardItem(str(obstacle.featureId))
        standardItem.setData(obstacle.featureId)
        standardItemList.append(standardItem)

        standardItem = QStandardItem(str(obstacle.layerId))
        standardItem.setData(obstacle.layerId)
        standardItemList.append(standardItem)

        standardItem = QStandardItem(str(obstacle.name))
        standardItem.setData(obstacle.name)
        standardItemList.append(standardItem)

        standardItem = QStandardItem(str(obstacle.Position.x()))
        standardItem.setData(obstacle.Position.x())
        standardItemList.append(standardItem)

        standardItem = QStandardItem(str(obstacle.Position.y()))
        standardItem.setData(obstacle.Position.y())
        standardItemList.append(standardItem)

        value = QVariant(QgisHelper.strDegree(obstacle.positionDegree.y()))
        standardItem = QStandardItem(value.toString())
        standardItem.setData(obstacle.positionDegree.y())
        standardItemList.append(standardItem)
        strV = QgisHelper.strDegree(obstacle.positionDegree.y())

        value = QVariant(QgisHelper.strDegree(obstacle.positionDegree.x()))
        standardItem = QStandardItem(value.toString())
        standardItem.setData(obstacle.positionDegree.x())
        standardItemList.append(standardItem)

        standardItem = QStandardItem(str(obstacle.Position.z()))
        standardItem.setData(obstacle.Position.z())
        standardItemList.append(standardItem)

        standardItem = QStandardItem(
            str(Unit.ConvertMeterToFeet(obstacle.Position.z())))
        standardItem.setData(Unit.ConvertMeterToFeet(obstacle.Position.z()))
        standardItemList.append(standardItem)

        standardItem = QStandardItem(str(obstacle.trees))
        standardItem.setData(obstacle.trees)
        standardItemList.append(standardItem)

        standardItem = QStandardItem(
            str(Unit.ConvertMeterToFeet(obstacle.trees)))
        standardItem.setData(Unit.ConvertMeterToFeet(obstacle.trees))
        standardItemList.append(standardItem)

        #         for i in range(len(standardItemList), self.source.columnCount()):
        #             standardItemList.append(QStandardItem("None"))

        self.source.appendRow(standardItemList)

        standardItem = QStandardItem(str(obstacle.mocMultiplier))
        standardItem.setData(obstacle.mocMultiplier)
        self.source.setItem(self.source.rowCount() - 1,
                            self.IndexMocMultiplier, standardItem)

    def checkObstacle(self, obstacle):
        pass

    def CompareObstacleRows(self, newRow, row, ignore):
        pass

    def method_0(self, obstacle_0):
        colCount = self.columnCount()
        objectId = range(colCount)

        objectId[0] = (obstacle_0.featureId)
        objectId[1] = (obstacle_0.name)
        objectId[2] = (obstacle_0.position.x())
        objectId[3] = (obstacle_0.position.y())
        objectId[4] = (obstacle_0.Position.z())
        position = obstacle_0.position
        objectId[6] = (Unit.ConvertMeterToFeet(position.z()))
        objectId[7] = (obstacle_0.trees)
        objectId[8] = (Unit.ConvertMeterToFeet(obstacle_0.Trees))
        if (self.IndexMocMultiplier > -1):
            objectId[self.IndexMocMultiplier] = obstacle_0.MocMultiplier

        return objectId

    def method_1(self, object_0):
        pass
Exemple #36
0
class OWKMeans(widget.OWWidget):
    name = "k-Means"
    description = "k-means clustering algorithm with silhouette-based " \
                  "quality estimation."
    icon = "icons/KMeans.svg"
    priority = 2100

    inputs = [("Data", Table, "set_data")]

    outputs = [("Annotated Data", Table, widget.Default),
               ("Centroids", Table)]

    INIT_KMEANS, INIT_RANDOM = range(2)
    INIT_METHODS = "Initialize with KMeans++", "Random initialization"

    SILHOUETTE, INTERCLUSTER, DISTANCES = range(3)
    SCORING_METHODS = [("Silhouette", lambda km: km.silhouette, False),
                       ("Inter-cluster distance",
                        lambda km: km.inter_cluster, True),
                       ("Distance to centroids",
                        lambda km: km.inertia, True)]

    OUTPUT_CLASS, OUTPUT_ATTRIBUTE, OUTPUT_META = range(3)
    OUTPUT_METHODS = ("Class", "Feature", "Meta")

    resizing_enabled = False

    k = Setting(8)
    k_from = Setting(2)
    k_to = Setting(8)
    optimize_k = Setting(False)
    max_iterations = Setting(300)
    n_init = Setting(10)
    smart_init = Setting(INIT_KMEANS)
    scoring = Setting(SILHOUETTE)
    append_cluster_ids = Setting(True)
    place_cluster_ids = Setting(OUTPUT_CLASS)
    output_name = Setting("Cluster")
    auto_run = Setting(False)

    def __init__(self):
        super().__init__()

        self.data = None
        self.km = None
        self.optimization_runs = []

        box = gui.widgetBox(self.controlArea, "Number of Clusters")
        layout = QGridLayout()
        bg = gui.radioButtonsInBox(
            box, self, "optimize_k", [], orientation=layout,
            callback=self.update)
        layout.addWidget(
            gui.appendRadioButton(bg, "Fixed", addToLayout=False),
            1, 1)
        sb = gui.widgetBox(None, margin=0, orientation="horizontal")
        self.fixedSpinBox = gui.spin(
            sb, self, "k", minv=2, maxv=30,
            controlWidth=60, alignment=Qt.AlignRight, callback=self.update_k)
        gui.rubber(sb)
        layout.addWidget(sb, 1, 2)

        layout.addWidget(
            gui.appendRadioButton(bg, "Optimized", addToLayout=False), 2, 1)
        ftobox = gui.widgetBox(None, orientation="horizontal")
        ftobox.layout().setMargin(0)
        layout.addWidget(ftobox)
        gui.spin(
            ftobox, self, "k_from", minv=2, maxv=29,
            controlWidth=60, alignment=Qt.AlignRight,
            callback=self.update_from)
        gui.widgetLabel(ftobox, "  To: ")
        self.fixedSpinBox = gui.spin(
            ftobox, self, "k_to", minv=3, maxv=30,
            controlWidth=60, alignment=Qt.AlignRight,
            callback=self.update_to)
        gui.rubber(ftobox)

        layout.addWidget(gui.widgetLabel(None, "Scoring: "),
                         5, 1, Qt.AlignRight)
        layout.addWidget(
            gui.comboBox(
                None, self, "scoring", label="Scoring",
                items=list(zip(*self.SCORING_METHODS))[0],
                callback=self.update), 5, 2)

        box = gui.widgetBox(self.controlArea, "Initialization")
        gui.comboBox(
            box, self, "smart_init", items=self.INIT_METHODS,
            callback=self.update)

        layout = QGridLayout()
        box2 = gui.widgetBox(box, orientation=layout)
        box2.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        layout.addWidget(gui.widgetLabel(None, "Re-runs: "),
                         0, 0, Qt.AlignLeft)
        sb = gui.widgetBox(None, margin=0, orientation="horizontal")
        layout.addWidget(sb, 0, 1)
        gui.lineEdit(
            sb, self, "n_init", controlWidth=60,
            valueType=int, validator=QIntValidator(),
            callback=self.update)
        layout.addWidget(gui.widgetLabel(None, "Maximal iterations: "),
                         1, 0, Qt.AlignLeft)
        sb = gui.widgetBox(None, margin=0, orientation="horizontal")
        layout.addWidget(sb, 1, 1)
        gui.lineEdit(sb, self, "max_iterations",
                     controlWidth=60, valueType=int,
                     validator=QIntValidator(),
                     callback=self.update)

        box = gui.widgetBox(self.controlArea, "Output")
        gui.comboBox(box, self, "place_cluster_ids",
                     label="Append cluster id as ", orientation="horizontal",
                     callback=self.send_data, items=self.OUTPUT_METHODS)
        gui.lineEdit(box, self, "output_name",
                     label="Name ", orientation="horizontal",
                     callback=self.send_data)

        gui.auto_commit(self.controlArea, self, "auto_run", "Run",
                        checkbox_label="Run after any change  ",
                        orientation="horizontal")
        gui.rubber(self.controlArea)

        self.table_model = QStandardItemModel(self)
        self.table_model.setHorizontalHeaderLabels(["k", "Score"])
        self.table_model.setColumnCount(2)

        self.table_box = gui.widgetBox(
            self.mainArea, "Optimization Report", addSpace=0)
        table = self.table_view = QTableView(self.table_box)
        table.setHorizontalScrollMode(QTableView.ScrollPerPixel)
        table.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        table.setSelectionMode(QTableView.SingleSelection)
        table.setSelectionBehavior(QTableView.SelectRows)
        table.verticalHeader().hide()
        table.setItemDelegateForColumn(1, gui.TableBarItem(self))
        table.setModel(self.table_model)
        table.selectionModel().selectionChanged.connect(
            self.table_item_selected)
        table.setColumnWidth(0, 40)
        table.setColumnWidth(1, 120)
        table.horizontalHeader().setStretchLastSection(True)

        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred)
        self.mainArea.setSizePolicy(QSizePolicy.Maximum,
                                    QSizePolicy.Preferred)
        self.table_box.setSizePolicy(QSizePolicy.Fixed,
                                     QSizePolicy.MinimumExpanding)
        self.table_view.setSizePolicy(QSizePolicy.Preferred,
                                      QSizePolicy.MinimumExpanding)
        self.table_box.layout().addWidget(self.table_view)
        self.hide_show_opt_results()

    def adjustSize(self):
        self.ensurePolished()
        s = self.sizeHint()
        self.resize(s)

    def hide_show_opt_results(self):
        [self.mainArea.hide, self.mainArea.show][self.optimize_k]()
        QTimer.singleShot(100, self.adjustSize)

    def sizeHint(self):
        s = self.controlArea.sizeHint()
        if self.optimize_k and not self.mainArea.isHidden():
            s.setWidth(s.width() + self.mainArea.sizeHint().width() +
                       4 * self.childrenRect().x())
        return s

    def update_k(self):
        self.optimize_k = False
        self.update()

    def update_from(self):
        self.k_to = max(self.k_from + 1, self.k_to)
        self.optimize_k = True
        self.update()

    def update_to(self):
        self.k_from = min(self.k_from, self.k_to - 1)
        self.optimize_k = True
        self.update()

    def set_optimization(self):
        self.updateOptimizationGui()
        self.update()

    def check_data_size(self, n):
        if n > len(self.data):
            self.error("Not enough unique data instances ({}) for given "
                       "number of clusters ({}).".format(len(self.data), n))
            return False
        return True

    def run_optimization(self):
        # Disabling is needed since this function is not reentrant
        # Fast clicking on, say, "To: " causes multiple calls
        try:
            self.controlArea.setDisabled(True)
            self.optimization_runs = []
            if self.check_data_size(self.k_to):
                self.optimization_runs = []
                kmeans = KMeans(
                    init=['random', 'k-means++'][self.smart_init],
                    n_init=self.n_init,
                    max_iter=self.max_iterations)
                with self.progressBar(self.k_to - self.k_from + 1) as progress:
                    for k in range(self.k_from, self.k_to + 1):
                        progress.advance()
                        kmeans.params["n_clusters"] = k
                        self.optimization_runs.append((k, kmeans(self.data)))
        finally:
            self.controlArea.setDisabled(False)
        self.show_results()
        self.send_data()


    def cluster(self):
        if not self.check_data_size(self.k):
            return
        self.km = KMeans(
            n_clusters=self.k,
            init=['random', 'k-means++'][self.smart_init],
            n_init=self.n_init,
            max_iter=self.max_iterations)(self.data)
        self.send_data()

    def run(self):
        self.error()
        if not self.data:
            return
        if self.optimize_k:
            self.run_optimization()
        else:
            self.cluster()

    commit = run

    def show_results(self):
        minimize = self.SCORING_METHODS[self.scoring][2]
        k_scores = [(k, self.SCORING_METHODS[self.scoring][1](run)) for
                    k, run in self.optimization_runs]
        scores = list(zip(*k_scores))[1]
        if minimize:
            best_score, worst_score = min(scores), max(scores)
        else:
            best_score, worst_score = max(scores), min(scores)

        best_run = scores.index(best_score)
        score_span = (best_score - worst_score) or 1
        max_score = max(scores)
        nplaces = min(5, int(abs(math.log(max(max_score, 1e-10)))) + 2)
        fmt = "{{:.{}}}".format(nplaces)
        model = self.table_model
        model.setRowCount(len(k_scores))
        for i, (k, score) in enumerate(k_scores):
            item = model.item(i, 0)
            if item is None:
                item = QStandardItem()
            item.setData(k, Qt.DisplayRole)
            item.setTextAlignment(Qt.AlignCenter)
            model.setItem(i, 0, item)
            item = model.item(i, 1)
            if item is None:
                item = QStandardItem()
            item.setData(fmt.format(score), Qt.DisplayRole)
            bar_ratio = 0.95 * (score - worst_score) / score_span
            item.setData(bar_ratio, gui.TableBarItem.BarRole)
            model.setItem(i, 1, item)
        self.table_view.resizeRowsToContents()

        self.table_view.selectRow(best_run)
        self.table_view.show()
        if minimize:
            self.table_box.setTitle("Scoring (smaller is better)")
        else:
            self.table_box.setTitle("Scoring (bigger is better)")
        QTimer.singleShot(0, self.adjustSize)

    def update(self):
        self.hide_show_opt_results()
        self.run()

    def selected_row(self):
        indices = self.table_view.selectedIndexes()
        rows = {ind.row() for ind in indices}
        if len(rows) == 1:
            return rows.pop()

    def table_item_selected(self):
        row = self.selected_row()
        if row is not None:
            self.send_data(row)

    def send_data(self, row=None):
        if self.optimize_k:
            if row is None:
                row = self.selected_row()
            km = self.optimization_runs[row][1]
        else:
            km = self.km
        if not self.data or not km:
            self.send("Annotated Data", None)
            self.send("Centroids", None)
            return

        clust_var = DiscreteVariable(
            self.output_name, values=["C%d" % (x + 1) for x in range(km.k)])
        clust_ids = km(self.data)
        domain = self.data.domain
        attributes, classes = domain.attributes, domain.class_vars
        meta_attrs = domain.metas
        if self.place_cluster_ids == self.OUTPUT_CLASS:
            if classes:
                meta_attrs += classes
            classes = [clust_var]
        elif self.place_cluster_ids == self.OUTPUT_ATTRIBUTE:
            attributes += (clust_var, )
        else:
            meta_attrs += (clust_var, )

        domain = Domain(attributes, classes, meta_attrs)
        new_table = Table.from_table(domain, self.data)
        new_table.get_column_view(clust_var)[0][:] = clust_ids.X.ravel()

        centroids = Table(Domain(km.pre_domain.attributes), km.centroids)

        self.send("Annotated Data", new_table)
        self.send("Centroids", centroids)

    @check_sql_input
    def set_data(self, data):
        self.data = data
        if data is None:
            self.table_model.setRowCount(0)
        else:
            self.data = data
            self.run()

    def send_report(self):
        self.report_items((
            ("Number of clusters",
             self.optimization_runs[self.selected_row()][1].k
             if self.optimize_k else self.k),
            ("Optimization",
             self.optimize_k != 0 and
             "{}, {} re-runs limited to {} steps".format(
                 self.INIT_METHODS[self.smart_init].lower(),
                 self.n_init, self.max_iterations)),
            ("Cluster ID in output",
             self.append_cluster_ids and
             "'{}' (as {})".format(
                 self.output_name,
                 self.OUTPUT_METHODS[self.place_cluster_ids].lower()))
        ))
        if self.data:
            self.report_data("Data", self.data)
            if self.optimize_k:
                self.report_table(
                    "Scoring by {}".format(self.SCORING_METHODS[self.scoring][0]
                                           ),
                    self.table_view)
Exemple #37
0
class ClusterWidget(QSplitter):
    def __init__(self, peaks, parent=None):
        QSplitter.__init__(self, Qt.Vertical, parent)
        self.peaks = peaks
        self.choosenOne = [pe for pe in self.peaks if pe is not None][0]
        #self.peakModel = QStandardItemModel()
        self.identificationModel = QStandardItemModel()
        self.setupUi()
        self.setModel()
        self.connect(self.calcCorr, SIGNAL('pressed()'), self.setRankValue)
        #self.setRankValue()

    def setupUi(self):
        self.widget = MSView(
            MSQtCanvas(self.peaks,
                       "peaks@%s" % str(self.peaks[0]),
                       labels={
                           'bottom': 'RT(s)',
                           'left': 'INTENSITY'
                       },
                       flags='peak'))
        self.tableView = QTableView()
        self.tableView.horizontalHeader().setStretchLastSection(True)
        self.tableView.setSortingEnabled(True)

        self.corr = QLabel("Nan")
        self.calcCorr = QPushButton("r_coef:")
        #v = QVBoxLayout(self)
        self.addWidget(self.widget)

        self.wid = QWidget()
        vb = QVBoxLayout()
        vb.addWidget(self.calcCorr)
        vb.addWidget(self.corr)
        hb = QHBoxLayout(self.wid)
        #if self.choosenOne.formulas:
        hb.addWidget(self.tableView)
        #else:
        #    hb.addWidget(QLabel("Identification not performed yet..."))
        hb.addLayout(vb)
        self.addWidget(self.wid)

    def setModel(self):
        from gui.MetBaseGui import MSStandardItem
        #we assume that the different peaks have the same identifiers
        #TODO: may have to merge several stuffs later
        if self.choosenOne.formulas:
            self.identificationModel.setHorizontalHeaderLabels(
                ["score", "formula", "diff mass", "names"])
            for i, f in enumerate(self.choosenOne.formulas.iterkeys()):

                self.identificationModel.setItem(
                    i, 0,
                    MSStandardItem(str(self.choosenOne.formulas[f]["score"])))
                self.identificationModel.setItem(i, 1, QStandardItem(str(f)))
                self.identificationModel.setItem(
                    i, 2,
                    MSStandardItem(str(
                        self.choosenOne.formulas[f]["diffmass"])))
                self.identificationModel.setItem(
                    i, 3, QStandardItem(self.choosenOne.formulas[f]["names"]))
                if self.choosenOne.formulas[f]["names"] != 'Not Found':
                    for j in xrange(4):
                        self.identificationModel.item(i, j).setBackground(
                            QBrush(Qt.green))
                else:
                    for j in xrange(4):
                        self.identificationModel.item(i, j).setBackground(
                            QBrush(Qt.red))
            self.tableView.setModel(self.identificationModel)

    def setRankValue(self):
        #m = qApp.instance().model
        #m.pearsonIntraCalculation()
        #peaks =[]
        #for spl in m:
        #    peaks+=[p.r_coef for p in spl.mappedPeaks if p.r_coef]
        #if not self.choosenOne.r_coef:
        self.choosenOne.pCalcBasedOnPeakShape()
        #from _bisect import bisect_left
        #x = bisect_left(sorted(peaks), self.choosenOne.r_coef)
        s = '<br><b>%f</b></br>' % np.round(self.choosenOne.r_coef, 4)
        #s+='<br><b>Rank: </b>%d</br>'%abs(len(peaks)-x)
        self.corr.setText(s)
class dbmanagerUI(QMainWindow, ui_dbmanager.Ui_dbmanagerUI):
    """Main UI for MASAR database manager."""
    def __init__(self):
        """"""
        super(dbmanagerUI, self).__init__()
        self.setupUi(self)
        self.statusbar.showMessage("Ready")

        exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit Masar Configuration Manager.')
        exitAction.triggered.connect(QtGui.qApp.quit)

        self.groupdatabasemenubar()

        #default database source, could be 0: SQLite, 1: MongoDB, and 2: MySQL
        self.dbsource = None

        self.defaultdbinfo = self._loadmasarconfig()
        self.usedefaultdb = True

        self.comboxboxSignalMapper = QtCore.QSignalMapper(self)
        self.comboxboxSignalMapper.mapped[QtGui.QWidget].connect(self.comboboxSignalMapperMapped)

        self.pushbuttonSignalMapper = QtCore.QSignalMapper(self)
        self.pushbuttonSignalMapper.mapped[QtGui.QWidget].connect(self.pushbuttonSignalMapperMapped)

        self.showpvbuttonSignalMapper = QtCore.QSignalMapper(self)
        self.showpvbuttonSignalMapper.mapped[QtGui.QWidget].connect(self.showpvbuttonSignalMapperMapped)

        self.choosepvbuttonSignalMapper = QtCore.QSignalMapper(self)
        self.choosepvbuttonSignalMapper.mapped[QtGui.QWidget].connect(self.choosepvbuttonSignalMapperMapped)

        self.currentselectedrow4config = -1

        self.selectedsystem = "Others"

        # self.pvgrouptreeview = QTreeView()
        self.pvGroupTreeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.pvgroupmodel = QStandardItemModel()
        # self.pvgroupmodel.setHorizontalHeaderLabels(['id', 'date', 'version', "description"])
        self.pvgroupmodel.setHorizontalHeaderLabels(["PV Groups"])
        self.pvGroupTreeView.setModel(self.pvgroupmodel)
        self.pvGroupTreeView.setUniformRowHeights(True)

    @QtCore.pyqtSlot(QtGui.QWidget)
    def comboboxSignalMapperMapped(self, comboBox):
        if self.masarConfigTableWidget.cellWidget(comboBox.row, comboBox.column + 1).isEnabled():
            self.masarConfigTableWidget.cellWidget(comboBox.row, comboBox.column + 1).setEnabled(False)
            button = self.masarConfigTableWidget.cellWidget(comboBox.row, comboBox.column + 1)
            palette = QtGui.QPalette(button.palette())  # make a copy of the palette
            palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor('grey'))
            button.setPalette(palette)
        else:
            self.masarConfigTableWidget.cellWidget(comboBox.row, comboBox.column + 1).setEnabled(True)
            button = self.masarConfigTableWidget.cellWidget(comboBox.row, comboBox.column + 1)
            palette = QtGui.QPalette(button.palette())  # make a copy of the palette
            palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor('red'))
            button.setPalette(palette)

    @QtCore.pyqtSlot(QtGui.QWidget)
    def pushbuttonSignalMapperMapped(self, pushbutton):
        configstatus = str(self.masarConfigTableWidget.cellWidget(pushbutton.row, pushbutton.column-1).currentText())
        cid = str(self.masarConfigTableWidget.item(pushbutton.row, 0).text())
        cname = str(self.masarConfigTableWidget.item(pushbutton.row, 1).text())

        if self.updatemasarconfigstatus(configstatus, cid, configname=cname):
            palette = QtGui.QPalette(pushbutton.palette())  # make a copy of the palette
            palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor('grey'))
            pushbutton.setPalette(palette)
            pushbutton.setEnabled(False)

    @QtCore.pyqtSlot(QtGui.QWidget)
    def showpvbuttonSignalMapperMapped(self, showpvbutton):
        if self.newConfigTableWidget.item(showpvbutton.row, showpvbutton.column + 2) is None:
            raise RuntimeError("Unknown pv file")
        pvfilename = self.newConfigTableWidget.item(showpvbutton.row, showpvbutton.column + 2).text()
        if not os.path.isfile(pvfilename):
            raise RuntimeError("Invalid pv file name for (row, col): (%s, %s)" % (showpvbutton.row,
                                                                                  showpvbutton.column + 2))

        text = ", ".join(np.loadtxt(str(pvfilename), dtype=str, comments="#"))
        if self.newConfigTableWidget.item(showpvbutton.row, 0) is not None:
            head = self.newConfigTableWidget.item(showpvbutton.row, 0).text()
        else:
            head = ""
        msg = QMessageBox(self,
                          windowTitle='PVs for group %s' % head,
                          text="The following PVs to be added:")
        msg.setDetailedText(text)
        msg.exec_()

    @QtCore.pyqtSlot(QtGui.QWidget)
    def choosepvbuttonSignalMapperMapped(self, chhosepvbutton):
        self.newConfigTableWidget.setItem(chhosepvbutton.row,
                                          chhosepvbutton.column+1,
                                          QTableWidgetItem(QFileDialog.getOpenFileName(self, "Open File")))

    def _loadmasarconfig(self):
        cf = ConfigParser.SafeConfigParser()
        cf.read([
            os.path.expanduser('~/.masarservice.conf'),
            '/etc/masarservice.conf',
            'masarservice.conf',
            "%s/masarservice.conf" % os.path.abspath(os.path.dirname(__file__))
        ])
        return cf

    def groupdatabasemenubar(self):
        """Group 3 Databases menu together to make selection exclusive."""
        group = QtGui.QActionGroup(self)
        self.actionSQLite.setActionGroup(group)
        self.actionMongoDB.setActionGroup(group)
        self.actionMySQL.setActionGroup(group)

    def actionsqlitemenu(self):
        """Answer action when SQLite is selected."""
        if self.actionSQLite.isChecked():
            self.dbsource = 0
            self.defaultsqlitedb()
            self.listPvGroupPushButton.setEnabled(True)

    def actionmongodbmenu(self):
        """Answer action when MongoDB is selected."""
        if self.actionMongoDB.isChecked():
            self.dbsource = 1
            self.defaultmongodb()
            self.listPvGroupPushButton.setEnabled(False)

    def actionmysqlmenu(self):
        """Answer action when MySQL is selected."""
        if self.actionMySQL.isChecked():
            QMessageBox.warning(self, 'Warning', "MySQL support not implemented yet.")
            self.actionMySQL.setChecked(False)
            if self.dbsource == 0:
                self.actionSQLite.setChecked(True)
            elif self.dbsource == 1:
                self.actionMongoDB.setChecked(True)

    def showdefaultdbinfo(self):
        """"""
        if self.dbsource == 0:
            self.defaultsqlitedb()
        elif self.dbsource == 1:
            self.defaultmongodb()
        elif self.dbsource == 2:
            QMessageBox.warning(self, 'Warning', "MySQL support not implemented yet.")

    def defaultsqlitedb(self):
        """"""
        if self.defaultdbinfo.has_section("sqlite"):
            self.databaseDefault.setText(self.defaultdbinfo.get("sqlite", "database"))
            self.hostDefault.clear()
            self.portDefault.clear()
            self.userDefault.clear()

    def defaultmongodb(self):
        """"""
        if self.defaultdbinfo.has_section("mongodb"):
            self.databaseDefault.setText(self.defaultdbinfo.get("mongodb", "database"))
            self.hostDefault.setText(self.defaultdbinfo.get("mongodb", "host"))
            self.portDefault.setText(self.defaultdbinfo.get("mongodb", "port"))
            self.userDefault.setText(self.defaultdbinfo.get("mongodb", "username"))

    def getdatabasename(self):
        """"""
        self.database = self.databaseLineEdit.text()

    def getdatabaseport(self):
        """"""
        self.databaseport = self.databaseportLineEdit.text()

    def getdatabasehost(self):
        """"""
        self.databasehost = self.databaseHostLineEdit.text()

    def getdatabasepw(self):
        """"""
        self.databasepw = self.databasePwLineEdit.text()

    def showmasarconfigs(self):
        """"""
        result = None
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                # masardb = str(self.databaseDefault.text())
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite
            conn = pymasarsqlite.utils.connect()
            result = pymasarsqlite.service.retrieveServiceConfigs(conn, servicename="masar")
            pymasarsqlite.utils.close(conn)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo
            mongoconn, collection = pymasarmongo.db.utils.conn(host=host, port=port, db=database)
            resultdict = pymasarmongo.pymasarmongo.pymasar.retrieveconfig(mongoconn, collection)
            pymasarmongo.db.utils.close(mongoconn)

            result = [['id', 'name', 'desc', 'date', 'version', 'status']]
            for res in resultdict:
                result.append([res['configidx'],
                               res['name'],
                               res['desc'],
                               res['created_on'],
                               res['version'],
                               res['status']])
                               # res['system']

        if result is not None:
            self._setconfigtable(result)

    def choosedbsrc(self, bool):
        """Choose DB source"""
        if bool:
            self.usedefaultdb = True
        else:
            self.usedefaultdb = False

    def _setconfigtable(self, content):
        """"""
        # head = self.masarConfigTableWidget.horizontalHeader()
        self.masarConfigTableWidget.clearContents()
        # self.masarConfigTableWidget.setHorizontalHeaderLabels(head)

        if len(content) > 1:
            self.masarConfigTableWidget.setRowCount(len(content)-1)

            n = 0
            data = sorted(content[1:], key=itemgetter(0), reverse=True)
            for res in data:
                m = 0
                for item in res:
                    if not isinstance(item, basestring):
                        item = str(item)
                    if item:
                        if m == 5:
                            newitem = QtGui.QComboBox()
                            newitem.addItem("active")
                            newitem.addItem("inactive")
                            if item == "active":
                                newitem.setCurrentIndex(0)
                            else:
                                newitem.setCurrentIndex(1)

                            newitem.row = n
                            newitem.column = m
                            self.masarConfigTableWidget.setCellWidget(n, m, newitem)
                            self.comboxboxSignalMapper.setMapping(newitem, newitem)
                            newitem.currentIndexChanged.connect(self.comboxboxSignalMapper.map)

                            updatebutton = QtGui.QPushButton()
                            updatebutton.setText("Update")
                            updatebutton.setEnabled(False)
                            updatebutton.row = n
                            updatebutton.column = m+1
                            self.pushbuttonSignalMapper.setMapping(updatebutton, updatebutton)
                            self.masarConfigTableWidget.setCellWidget(n, m+1, updatebutton)
                            updatebutton.clicked.connect(self.pushbuttonSignalMapper.map)
                        else:
                            newitem = QTableWidgetItem(item)
                            newitem.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                            self.masarConfigTableWidget.setItem(n, m, newitem)
                    m += 1
                n += 1

            self.masarConfigTableWidget.resizeColumnsToContents()

    def updatemasarconfigstatus(self, configstatus, cid, configname=None):
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite

            conn = pymasarsqlite.utils.connect()
            pymasarsqlite.service.updateServiceConfigStatus(conn, cid, status=configstatus)
            pymasarsqlite.utils.save(conn)
            pymasarsqlite.utils.close(conn)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo

            mongoconn, collection = pymasarmongo.db.utils.conn(host=host, port=port, db=database)
            pymasarmongo.pymasarmongo.pymasar.updateconfig(mongoconn, collection, configname,
                                                           configidx=int(cid), status=configstatus)
            pymasarmongo.db.utils.close(mongoconn)

        return True

    def addnewpvgrouprow(self):
        """Add a new row to add pv group to MASAR configuration"""
        print ("""Add a new row to add pv group to MASAR configuration""")
        currowcount = self.newConfigTableWidget.rowCount()
        self.newConfigTableWidget.setRowCount(currowcount + 1)

        showpvbutton = QtGui.QPushButton()
        showpvbutton.setText("Show PVs")
        showpvbutton.setEnabled(True)
        showpvbutton.row = currowcount
        showpvbutton.column = 2
        self.showpvbuttonSignalMapper.setMapping(showpvbutton, showpvbutton)
        self.newConfigTableWidget.setCellWidget(currowcount, showpvbutton.column, showpvbutton)
        showpvbutton.clicked.connect(self.showpvbuttonSignalMapper.map)

        choosepvbutton = QtGui.QPushButton()
        choosepvbutton.setText("PV File")
        choosepvbutton.setEnabled(True)
        choosepvbutton.row = currowcount
        choosepvbutton.column = 3
        self.choosepvbuttonSignalMapper.setMapping(choosepvbutton, choosepvbutton)
        self.newConfigTableWidget.setCellWidget(currowcount, choosepvbutton.column, choosepvbutton)
        choosepvbutton.clicked.connect(self.choosepvbuttonSignalMapper.map)

    def removepvgrouprow(self):
        """Remove selected pv group from the configuration to be added into MASAR database"""
        if self.currentselectedrow4config == -1:
            raise RuntimeError("No pv group selected.")
        rownametobedelete = self.newConfigTableWidget.item(self.currentselectedrow4config, 0)
        if rownametobedelete is not None:
            rownametobedelete = rownametobedelete.text()
        self.newConfigTableWidget.removeRow(self.currentselectedrow4config)
        if rownametobedelete is not None:
            print ("Successfully delete pv group: ", rownametobedelete)
        else:
            print ("Successfully delete row: ", self.currentselectedrow4config)
        self.currentselectedrow4config = -1

    def savemasarsqlite(self):
        """"""
        # get data from sqlite
        if self.usedefaultdb:
            masardb = str(self.databaseDefault.toPlainText())
        else:
            masardb = str(self.databaseLineEdit.text())

        if masardb != "":
            os.environ["MASAR_SQLITE_DB"] = masardb
        else:
            QMessageBox.warning(self, "Warning",
                                "Cannot find MASAR SQLite Database")
            return

        import pymasarsqlite
        conn = pymasarsqlite.utils.connect()
        existedresult = pymasarsqlite.service.retrieveServiceConfigs(conn, servicename="masar")

        newcfgdata = self._getnewconfigurationdata(existedresult)
        if newcfgdata is None:
            QMessageBox.warning(self, "Warning",
                                "Not enough information for a new configuration.")
            return
        newcfgname = newcfgdata[0]
        desc = newcfgdata[1]
        msystem = newcfgdata[2]
        # config data format: [[name], [desc], [pv files]]
        cfgdata = newcfgdata[3]

        if newcfgname is None or msystem is None or newcfgdata is None:
            # Nothing to be added.
            QMessageBox.warning(self, "Warning",
                                "No name or system is given, or empty configuration data.")
            return

        for i in range(len(cfgdata[0])):
            if cfgdata[0][i] is None:
                QMessageBox.warning(self, "Warning", "Wrong PV group name")
                return

            if cfgdata[2][i] is not None and os.path.isfile(cfgdata[2][i]):
                pvs = list(np.loadtxt(cfgdata[2][i], dtype=str, comments="#"))
                if len(pvs) > 0:
                    for j, pv in enumerate(pvs):
                        pvs[j] = pv.strip()
                    pymasarsqlite.pvgroup.savePvGroup(conn, cfgdata[0][i], func=cfgdata[1][i])
                    pymasarsqlite.pvgroup.saveGroupPvs(conn, cfgdata[0][i], pvs)

        try:
            pymasarsqlite.service.saveServiceConfig(conn, "masar", newcfgname, configdesc=desc, system=msystem)
            pymasarsqlite.service.saveServicePvGroup(conn, newcfgname, cfgdata[0])
        except Exception as e:
            QMessageBox.warning(self, "Error", e.message)
            return

        pymasarsqlite.utils.save(conn)
        QMessageBox.information(self, "Congratulation", "A new configuration has been added successfully.")
        pymasarsqlite.utils.close(conn)

    def savemasarmongodb(self):
        """"""
        # get data from mongodb
        if self.usedefaultdb:
            database = str(self.databaseDefault.toPlainText())
            host = str(self.hostDefault.toPlainText())
            port = str(self.portDefault.toPlainText())
        else:
            database = str(self.databaseLineEdit.text())
            host = str(self.databaseHostLineEdit.text())
            port = str(self.databasePortLineEdit.text())

        import pymasarmongo

        mongoconn, collection = pymasarmongo.db.utils.conn(host=host, port=port, db=database)
        existedresult = pymasarmongo.pymasarmongo.pymasar.retrieveconfig(mongoconn, collection)
        existedcfg = []
        for res in existedresult:
            existedcfg.append([res['configidx'],
                               res['name'],
                               res['desc'],
                               res['created_on'],
                               res['version'],
                               res['status']])
        newcfgdata = self._getnewconfigurationdata(existedcfg)
        if newcfgdata is None:
            # Nothing to be added.
            raise ValueError("Empty configuration.")

        newcfgname = newcfgdata[0]
        desc = newcfgdata[1]
        msystem = newcfgdata[2]
        # config data format: [[name], [desc], [pv files]]
        cfgdata = newcfgdata[3]
        pvs = []
        for pvf in cfgdata[2]:
            if pvf is not None and os.path.isfile(pvf):
                pvs += list(np.loadtxt(pvf, dtype=str, comments="#"))
        if pvs:
            for i, pv in enumerate(pvs):
                pvs[i] = pv.strip()
            pymasarmongo.pymasarmongo.pymasar.saveconfig(mongoconn, collection, newcfgname,
                                                         desc=desc,
                                                         system=msystem,
                                                         pvlist={"names": pvs})
            QMessageBox.information(self, "Congratulation", "A new configuration has been added successfully.")
        else:
            QMessageBox.warning(self, "Warning", "No PVs available for the new configuration.")

        pymasarmongo.db.utils.close(mongoconn)

    def submitmasarconfig(self):
        """submit a new configuration to MASAR database"""
        if self.dbsource is None:
            QMessageBox.warning(self, "Warning",
                                "Unknown database source.\nPlease select which database should be use.")
            return
        if self.dbsource == 0:
            self.savemasarsqlite()
        elif self.dbsource == 1:
            self.savemasarmongodb()

    def _getnewconfigurationdata(self, existedresult):
        """"""
        newcfgname = self.newConfigurationLineEdit.text()
        if newcfgname is None or str(newcfgname) == "":
            QMessageBox.warning(self, "Warning",
                                "Name of configuration is empty.")
            return None
        elif str(newcfgname) in np.array(existedresult)[:, 1]:
            QMessageBox.warning(self, "Warning",
                                "Configuration (%s) exists already." % str(newcfgname))
            return None
        else:
            newcfgname = str(newcfgname)
        desc = self.newConfigurationDescription.text()
        if str(desc) == "":
            desc = None
        else:
            desc = str(desc)

        msystem = str(self.systemComboBox.currentText())
        if msystem == "Others":
            msystem = self.systemLineEdit.text()
            if msystem is None or str(msystem) == "":
                QMessageBox.warning(self, "Warning",
                                    "System for configuration (%s) not specified yet." % str(newcfgname))
                return None
            else:
                msystem = str(msystem)

        pvgroups = self.newConfigTableWidget.rowCount()
        if pvgroups == 0:
            QMessageBox.warning(self, "Warning",
                                "No PV founded for new configuration (%s)." % str(newcfgname))
            return None

        pvgroupnames = []
        pvgroupdescs = []
        pvgroupfiles = []
        for count in range(pvgroups):
            # Collect PV group name information
            if self.newConfigTableWidget.item(count, 0) is not None and str(self.newConfigTableWidget.item(count, 0).text()) != "":
                pvgname = str(self.newConfigTableWidget.item(count, 0).text())
                if pvgname in pvgroupnames:
                    QMessageBox.warning(self, "Warning",
                                        "Duplicated pv group name: %s." % str(pvgname))
                    return None
                pvgroupnames.append(pvgname)
            elif self.newConfigTableWidget.item(count, 4) is None or str(self.newConfigTableWidget.item(count, 4)) == "":
                continue
            elif self.dbsource == 1:
                pvgroupnames.append(None)
            else:
                QMessageBox.warning(self, "Warning",
                                    "Empty pv group name.")
                return None
                # reply = QMessageBox.question(self, "Message",
                #                              "pv group name not specified for row {}.\nContinue?".format(count),
                #                              QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                # if reply == QMessageBox.Yes:
                #     pvgroupnames.append(None)
                # else:
                #     return None

            # Collection PV group descriptions
            if self.newConfigTableWidget.item(count, 1) is not None:
                pvgroupdescs.append(str(self.newConfigTableWidget.item(count, 1).text()))
            else:
                pvgroupdescs.append(None)

            # PV files for the pv group.
            if self.newConfigTableWidget.item(count, 4) is not None:
                pvgroupfiles.append(str(self.newConfigTableWidget.item(count, 4).text()))
            else:
                pvgroupfiles.append(None)

        if pvgroupfiles:
            return newcfgname, desc, msystem, [pvgroupnames, pvgroupdescs, pvgroupfiles]
        else:
            return None

    def currentselectedrow(self, row, col):
        """Cache current selected row in MASAR configuration Table Widget."""
        self.currentselectedrow4config = row

    def updateselectedsystem(self, system):
        """Update selected system if value changed"""
        self.selectedsystem = str(system)

    def updatesystemcombobox(self):
        """Update selected system if value changed"""
        self.systemComboBox.clear()
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                # masardb = str(self.databaseDefault.text())
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite

            conn = pymasarsqlite.utils.connect()
            result = pymasarsqlite.service.retrieveServiceConfigProps(conn, propname="system", servicename="masar")
            index = 0
            if len(result) > 1:
                res = sorted(set(list(np.array(result[1:])[:, 3])))
                #for res in result[1:]:
                self.systemComboBox.addItems(res)
                index = len(res)
            self.systemComboBox.addItem("Others")
            self.systemComboBox.setCurrentIndex(index)
            pymasarsqlite.utils.close(conn)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo

            mongoconn, collection = pymasarmongo.db.utils.conn(host=host, port=port, db=database)

            result = pymasarmongo.pymasarmongo.pymasar.retrieveconfig(mongoconn, collection)
            pymasarmongo.db.utils.close(mongoconn)

            results = []
            for res in result:
                if res["system"] not in results:
                    results.append(res["system"])
            res = sorted(set(results))
            self.systemComboBox.addItems(res)
            index = len(res)
            self.systemComboBox.addItem("Others")
            self.systemComboBox.setCurrentIndex(index)

    def listpvgroups(self):
        """"""
        self.pvgroupmodel.clear()
        self.pvgroupmodel.setHorizontalHeaderLabels(["PV Groups"])
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                # masardb = str(self.databaseDefault.text())
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite

            conn = pymasarsqlite.utils.connect()
            result = pymasarsqlite.pvgroup.retrievePvGroups(conn)
            if len(result) > 0:
                result = sorted(result, key=itemgetter(0), reverse=True)
            for res in result:
                parent1 = QStandardItem(res[1])
                child1 = QStandardItem('id: {}'.format(res[0]))
                child2 = QStandardItem('description: {}'.format(res[2]))
                child3 = QStandardItem('date: {}'.format(res[3]))
                child4 = QStandardItem('version: {}'.format(res[4]))
                parent1.appendColumn([child1, child2, child3, child4])
                self.pvgroupmodel.appendRow(parent1)
            selmod = self.pvGroupTreeView.selectionModel()
            index2 = self.pvgroupmodel.indexFromItem(child3)
            selmod.select(index2, QItemSelectionModel.Select | QItemSelectionModel.Rows)
            pymasarsqlite.utils.close(conn)

            self.pvGroupTreeView.setContextMenuPolicy(Qt.CustomContextMenu)
            self.pvGroupTreeView.clicked.connect(self.showpvsinpvgroup)
            # self.connect(self.pvGroupTreeView,
            #              QtCore.SIGNAL("clicked(QModelIndex)"),
            #              #QtCore.SIGNAL("customContextMenuRequested(const QPoint &)"),
            #              self.doMenu)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo

    def showpvsinpvgroup(self, point):
        if point.model().itemFromIndex(point).child(0) is None:
            return
        reply = QMessageBox.question(self, 'Message',
                                     "show all pvs belong to group {} ?".format(point.model().
                                                                                itemFromIndex(point).
                                                                                text()),
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            pvgroupidx = int(str(point.model().itemFromIndex(point).child(0).text().split(":")[1]).strip())

            # msg = QMessageBox(self)
            msg = ShowPvMessageBox()
            msg.setWindowTitle('PVs for group {}'.format(point.model().itemFromIndex(point).text()))
            msg.setText("Click show details to see all pvs.")
            # windowTitle = 'PVs for group {}'.format(point.model().itemFromIndex(point).text())

            if self.dbsource == 0:
                # get data from sqlite
                if self.usedefaultdb:
                    # masardb = str(self.databaseDefault.text())
                    masardb = str(self.databaseDefault.toPlainText())
                else:
                    masardb = str(self.databaseLineEdit.text())

                if masardb != "":
                    os.environ["MASAR_SQLITE_DB"] = masardb
                else:
                    raise RuntimeError("Cannot find MASAR SQLite Database")

                import pymasarsqlite

                conn = pymasarsqlite.utils.connect()
                result = pymasarsqlite.pvgroup.retrieveGroupPvs(conn, pvgroupidx)
                text = "\n".join(list(np.array(result)[:, 0]))
                msg.setDetailedText(text)
                msg.exec_()

            elif self.dbsource == 1:
                # get data from mongodb
                if self.usedefaultdb:
                    database = str(self.databaseDefault.toPlainText())
                    host = str(self.hostDefault.toPlainText())
                    port = str(self.portDefault.toPlainText())
                else:
                    database = str(self.databaseLineEdit.text())
                    host = str(self.databaseHostLineEdit.text())
                    port = str(self.databasePortLineEdit.text())

                import pymasarmongo
Exemple #39
0
class OWTestLearners(widget.OWWidget):
    name = "Test Learners"
    description = "Cross-validation accuracy estimation."
    icon = "icons/TestLearners1.svg"
    priority = 100

    inputs = [("Learner", Orange.classification.Learner,
               "set_learner", widget.Multiple),
              ("Data", Orange.data.Table, "set_train_data", widget.Default),
              ("Test Data", Orange.data.Table, "set_test_data")]

    outputs = [("Evaluation Results", Orange.evaluation.Results)]

    settingsHandler = settings.ClassValuesContextHandler()

    #: Resampling/testing types
    KFold, LeaveOneOut, Bootstrap, TestOnTrain, TestOnTest = 0, 1, 2, 3, 4

    #: Selected resampling type
    resampling = settings.Setting(0)
    #: Number of folds for K-fold cross validation
    k_folds = settings.Setting(10)
    #: Number of repeats for bootstrap sampling
    n_repeat = settings.Setting(10)
    #: Bootstrap sampling p
    sample_p = settings.Setting(75)

    class_selection = settings.ContextSetting("(None)")

    def __init__(self, parent=None):
        super().__init__(parent)

        self.train_data = None
        self.test_data = None

        #: An Ordered dictionary with current inputs and their testing
        #: results.
        self.learners = OrderedDict()

        sbox = gui.widgetBox(self.controlArea, "Sampling")
        rbox = gui.radioButtons(
            sbox, self, "resampling", callback=self._param_changed
        )
        gui.appendRadioButton(rbox, "Cross validation")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox, self, "k_folds", 2, 50, label="Number of folds:",
                 callback=self.kfold_changed)
        gui.appendRadioButton(rbox, "Leave one out")
        gui.appendRadioButton(rbox, "Random sampling")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox, self, "n_repeat", 2, 50, label="Repeat train/test",
                 callback=self.bootstrap_changed)
        gui.widgetLabel(ibox, "Relative training set size:")
        gui.hSlider(ibox, self, "sample_p", minValue=1, maxValue=100,
                    ticks=20, vertical=False, labelFormat="%d %%",
                    callback=self.bootstrap_changed)

        gui.appendRadioButton(rbox, "Test on train data")
        gui.appendRadioButton(rbox, "Test on test data")

        rbox.layout().addSpacing(5)
        gui.button(rbox, self, "Apply", callback=self.apply)

        self.cbox = gui.widgetBox(self.controlArea, "Target class")
        self.class_selection_combo = gui.comboBox(self.cbox, self, "class_selection",
             items=[],
             callback=self._select_class,
             sendSelectedValue=True, valueType=str)

        gui.rubber(self.controlArea)


        self.view = QTreeView(
            rootIsDecorated=False,
            uniformRowHeights=True,
            wordWrap=True,
            editTriggers=QTreeView.NoEditTriggers
        )
        header = self.view.header()
        header.setResizeMode(QHeaderView.ResizeToContents)
        header.setDefaultAlignment(Qt.AlignCenter)
        header.setStretchLastSection(False)

        self.result_model = QStandardItemModel()
        self.view.setModel(self.result_model)
        self.view.setItemDelegate(ItemDelegate())
        self._update_header()
        box = gui.widgetBox(self.mainArea, "Evaluation Results")
        box.layout().addWidget(self.view)

    def set_learner(self, learner, key):
        if key in self.learners and learner is None:
            del self.learners[key]
        else:
            self.learners[key] = Input(learner, None, ())
        self._update_stats_model()

    def set_train_data(self, data):
        self.error(0)
        if data and not data.domain.class_var:
            self.error(0, "Train data input requires a class variable")
            data = None

        self.train_data = data
        self.closeContext()
        if data is not None:
            self.openContext(data.domain.class_var)
            self._update_header()
        self._update_class_selection()
        self._invalidate()

    def set_test_data(self, data):
        self.error(1)
        if data and not data.domain.class_var:
            self.error(1, "Test data input requires a class variable")
            data = None

        self.test_data = data
        if self.resampling == OWTestLearners.TestOnTest:
            self._invalidate()

    def handleNewSignals(self):
        self.update_results()
        self.commit()

    def kfold_changed(self):
        self.resampling = OWTestLearners.KFold
        self._param_changed()

    def bootstrap_changed(self):
        self.resampling = OWTestLearners.Bootstrap
        self._param_changed()

    def _param_changed(self):
        self._invalidate()

    def update_results(self):
        self.warning([1, 2])
        self.error(2)

        if self.train_data is None:
            return

        if self.resampling == OWTestLearners.TestOnTest:
            if self.test_data is None:
                self.warning(2, "Missing separate test data input")
                return

            elif self.test_data.domain.class_var != \
                    self.train_data.domain.class_var:
                self.error(2, ("Inconsistent class variable between test " +
                               "and train data sets"))
                return

        # items in need of an update
        items = [(key, input) for key, input in self.learners.items()
                 if input.results is None]
        learners = [input.learner for _, input in items]

        self.setStatusMessage("Running")
        if self.test_data is not None and \
                self.resampling != OWTestLearners.TestOnTest:
            self.warning(1, "Test data is present but unused. "
                            "Select 'Test on test data' to use it.")

        # TODO: Test each learner individually
        try:
            if self.resampling == OWTestLearners.KFold:
                results = Orange.evaluation.CrossValidation(
                    self.train_data, learners, k=self.k_folds, store_data=True
                )
            elif self.resampling == OWTestLearners.LeaveOneOut:
                results = Orange.evaluation.LeaveOneOut(
                    self.train_data, learners, store_data=True
                )
            elif self.resampling == OWTestLearners.Bootstrap:
                p = self.sample_p / 100.0
                results = Orange.evaluation.Bootstrap(
                    self.train_data, learners, n_resamples=self.n_repeat, p=p,
                    store_data=True
                )
            elif self.resampling == OWTestLearners.TestOnTrain:
                results = Orange.evaluation.TestOnTrainingData(
                    self.train_data, learners, store_data=True
                )
            elif self.resampling == OWTestLearners.TestOnTest:
                if self.test_data is None:
                    return
                results = Orange.evaluation.TestOnTestData(
                    self.train_data, self.test_data, learners, store_data=True
                )
            else:
                assert False
        except Exception as e:
            self.error(2, str(e))
            return

        self.results = results
        results = list(split_by_model(results))

        class_var = self.train_data.domain.class_var

        if class_var.is_discrete:
            stats = [classification_stats(self.one_vs_rest(res)) for res in results]
        else:
            stats = [regression_stats(res) for res in results]

        self._update_header()

        for (key, input), res, stat in zip(items, results, stats):
            self.learners[key] = input._replace(results=res, stats=stat)

        self.setStatusMessage("")

        self._update_stats_model()


    def _update_header(self):
        headers = ["Method"]
        if self.train_data is not None:
            if self.train_data.domain.class_var.is_discrete:
                headers.extend(classification_stats.headers)
            else:
                headers.extend(regression_stats.headers)
        for i in reversed(range(len(headers),
                                self.result_model.columnCount())):
            self.result_model.takeColumn(i)

        self.result_model.setHorizontalHeaderLabels(headers)

    def _update_stats_model(self):
        model = self.view.model()

        for r in reversed(range(model.rowCount())):
            model.takeRow(r)

        for input in self.learners.values():
            name = learner_name(input.learner)
            row = []
            head = QStandardItem()
            head.setData(name, Qt.DisplayRole)
            row.append(head)
            for stat in input.stats:
                item = QStandardItem()
                item.setData(" {:.3f} ".format(stat[0]), Qt.DisplayRole)
                row.append(item)
            model.appendRow(row)

    def _update_class_selection(self):
        self.class_selection_combo.clear()
        if not self.train_data:
            return
        if self.train_data.domain.class_var.is_discrete:
            self.cbox.setVisible(True)
            values = self.train_data.domain.class_var.values
            self.class_selection_combo.addItem("(None)")
            self.class_selection_combo.addItems(values)

            class_index = 0
            if self.class_selection in self.train_data.domain.class_var.values:
                    class_index = self.train_data.domain.class_var.values.index(self.class_selection)+1
            else:
                self.class_selection = '(None)'

            self.class_selection_combo.setCurrentIndex(class_index)
            self.previous_class_selection = "(None)"
        else:
            self.cbox.setVisible(False)

    def one_vs_rest(self, res):
        if self.class_selection != '(None)' and self.class_selection != 0:
            class_ = self.train_data.domain.class_var.values.index(self.class_selection)
            actual = res.actual == class_
            predicted = res.predicted == class_
            return Results(
                nmethods=1, domain=self.train_data.domain,
                actual=actual, predicted=predicted)
        else:
            return res

    def _select_class(self):
        if self.previous_class_selection == self.class_selection:
            return

        results = list(split_by_model(self.results))

        items = [(key, input) for key, input in self.learners.items()]
        learners = [input.learner for _, input in items]

        class_var = self.train_data.domain.class_var
        if class_var.is_discrete:
            stats = [classification_stats(self.one_vs_rest(res)) for res in results]
        else:
            stats = [regression_stats(res) for res in results]

        for (key, input), res, stat in zip(items, results, stats):
            self.learners[key] = input._replace(results=res, stats=stat)

        self.setStatusMessage("")

        self._update_stats_model()
        self.previous_class_selection = self.class_selection

    def _invalidate(self, which=None):
        if which is None:
            which = self.learners.keys()

        all_keys = list(self.learners.keys())
        model = self.view.model()

        for key in which:
            self.learners[key] = \
                self.learners[key]._replace(results=None, stats=None)

            if key in self.learners:
                row = all_keys.index(key)
                for c in range(1, model.columnCount()):
                    item = model.item(row, c)
                    if item is not None:
                        item.setData(None, Qt.DisplayRole)

    def apply(self):
        self.update_results()
        self.commit()

    def commit(self):
        results = [val.results for val in self.learners.values()
                   if val.results is not None]
        if results:
            combined = results_merge(results)
            combined.learner_names = [learner_name(val.learner)
                                     for val in self.learners.values()]
        else:
            combined = None
        self.send("Evaluation Results", combined)
    def __init__(self, parent=None):
        super(LayerSelectionPage, self).__init__(parent)
        self.parent = parent
        
        #convenience link
        self.confconn_link = self.parent.parent.confconn
        
        #flag top prevent read read action on keyword delete. New logic makes this redundant
        #self.keywordbypass = False

        QToolTip.setFont(QFont('SansSerif', 10))
        
        #label
        filterlabel = QLabel('Filter')
        availablelabel = QLabel('Available Layers')
        selectionlabel = QLabel('Layer Selections')
        keywordlabel = QLabel('Keyword')
        explainlabel = QLabel("Edit Group assignments using this dialog or to simply initialise the Layer-Config just click 'Finish'")
        
        #selection buttons
        chooseallbutton = QPushButton('>>')
        chooseallbutton.setFixedWidth(self.XFER_BW)
        chooseallbutton.clicked.connect(self.doChooseAllClickAction)
        
        choosebutton = QPushButton('>')
        choosebutton.setFixedWidth(self.XFER_BW)
        choosebutton.clicked.connect(self.doChooseClickAction)
        
        rejectbutton = QPushButton('<')
        rejectbutton.setFixedWidth(self.XFER_BW)
        rejectbutton.clicked.connect(self.doRejectClickAction)
        
        rejectallbutton = QPushButton('<<')
        rejectallbutton.setFixedWidth(self.XFER_BW)
        rejectallbutton.clicked.connect(self.doRejectAllClickAction)
        
        #operation buttons        
        finishbutton = QPushButton('Finish')
        finishbutton.setToolTip('Finish and Close layer selection dialog')
        finishbutton.clicked.connect(self.parent.close)
        
        resetbutton = QPushButton('Reset')
        resetbutton.font()
        resetbutton.setToolTip('Read Layer from LDS GetCapabilities request. Overwrites current Layer Config')       
        resetbutton.clicked.connect(self.doResetClickAction)
        
        self.available_sfpm = LDSSFPAvailableModel(self)
        self.selection_sfpm = LDSSFPSelectionModel(self)
        
        self.available_sfpm.setSourceModel(self.parent.available_model)
        self.selection_sfpm.setSourceModel(self.parent.selection_model)
        
        #textedits
        filteredit = QLineEdit('')
        filteredit.setToolTip('Filter Available-Layers pane (filter operates across Name and Title fields and accepts Regex expressions)')       
        filteredit.textChanged.connect(self.available_sfpm.setActiveFilter)
        
        self.keywordcombo = QComboBox()
        self.keywordcombo.setToolTip('Select or Add a unique identifier to be saved in layer config (keyword)')
        self.keywordcombo.addItems(list(self.confconn_link.assigned))
        self.keywordcombo.setEditable(True)
        self.keywordcombo.activated.connect(self.doKeyComboChangeAction)
        
        lgindex = self.confconn_link.getLayerGroupIndex(self.confconn_link.lgval,col=1)
        lgentry = self.confconn_link.lglist[lgindex] if LU.assessNone(lgindex) else None
        #keywordedit = self.keywordcombo.lineEdit().text().toUtf8().data().decode('utf8')# for writing
        #if no entry or layer indicated then blank 
        self.keywordcombo.lineEdit().setText('' if lgentry is None or lgentry[0]==LORG.LAYER else lgentry[1])#self.confconn_link.lgval)#TODO. group only
        
        #header
        headmodel = QStandardItemModel()
        headmodel.setHorizontalHeaderLabels([i[2] for i in self.colparams][:self.parent.available_model.columnCount()])
        
        headview1 = QHeaderView(Qt.Horizontal)
        headview1.setModel(headmodel)
        headview1.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) 
        
        headview2 = QHeaderView(Qt.Horizontal)
        headview2.setModel(headmodel)
        headview2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)            

        #table
        self.available = QTableView()
        self.available.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.available.setSelectionMode(QAbstractItemView.MultiSelection)       
        
        self.selection = QTableView()
        self.selection.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.selection.setSelectionMode(QAbstractItemView.MultiSelection)
        
        #interesting, must set model after selection attributes but before headers else row selections/headers don't work properly
        self.available.setModel(self.available_sfpm)
        self.selection.setModel(self.selection_sfpm)
        
        self.available.setSortingEnabled(True)
        self.available.setHorizontalHeader(headview1)
        
        self.selection.setSortingEnabled(True)
        self.selection.setHorizontalHeader(headview2)

        for cp in self.colparams:
            self.available.setColumnWidth(cp[0],cp[1])
            self.selection.setColumnWidth(cp[0],cp[1])

        self.available.verticalHeader().setVisible(False)
        self.available.horizontalHeader().setVisible(True)
        
        self.selection.verticalHeader().setVisible(False)
        self.selection.horizontalHeader().setVisible(True)
        
        
        #layout  
        vbox00 = QVBoxLayout()
        vbox00.addWidget(availablelabel)
        vbox00.addWidget(self.available)
        
        vbox01 = QVBoxLayout()
        vbox01.addWidget(chooseallbutton)
        vbox01.addWidget(choosebutton)
        vbox01.addWidget(rejectbutton)
        vbox01.addWidget(rejectallbutton)
        
        vbox02 = QVBoxLayout()
        vbox02.addWidget(selectionlabel)
        vbox02.addWidget(self.selection)

        
        vbox10 = QVBoxLayout()
        vbox10.addWidget(filterlabel)
        vbox10.addWidget(filteredit)
        
        hbox12 = QHBoxLayout()
        hbox12.addWidget(keywordlabel)
        hbox12.addStretch(1)
        #hbox12.addWidget(inspbutton)
        #hbox12.addWidget(addbutton)
        #hbox12.addWidget(delbutton)
        
        vbox12 = QVBoxLayout()
        vbox12.addLayout(hbox12)
        vbox12.addWidget(self.keywordcombo)
                
        #00|01|02
        #10|11|12
        grid0 = QGridLayout()
        grid0.addLayout(vbox00,1,0)
        grid0.addLayout(vbox01,1,1)
        grid0.addLayout(vbox02,1,2)
        grid0.addLayout(vbox10,0,0)
        grid0.addLayout(vbox12,0,2)
        
        
        hbox2 = QHBoxLayout()
        hbox2.addWidget(resetbutton)
        hbox2.addStretch(1)
        hbox2.addWidget(explainlabel)
        hbox2.addWidget(finishbutton)
        #gbox1.setLayout(hbox2)
        
        
        
        vbox3 = QVBoxLayout()
        vbox3.addLayout(grid0)
        #vbox3.addLayout(hbox3)
        #vbox3.addWidget(line0)
        vbox3.addLayout(hbox2)
        
        self.setLayout(vbox3)
Exemple #41
0
class OWMPR(OWWidget):
    name = 'ModelMap Projection Rank'
    description = 'Ranking projections by estimating projection quality'
    icon = "icons/ModelMap.svg"

    inputs = [('Data', Table, 'set_data', Default)]
    outputs = [('Features', AttributeList)]
    want_main_area = False
    settingsHandler = DomainContextHandler()

    variable_changed = Signal()

    def __init__(self):
        super().__init__()
        self.data = None
        self.progress = None

        self.infoa = gui.widgetLabel(self.controlArea, "No data loaded.")

        self.projectionTable = QTableView()
        self.controlArea.layout().addWidget(self.projectionTable)
        self.projectionTable.setSelectionBehavior(QTableView.SelectRows)
        self.projectionTable.setSelectionMode(QTableView.SingleSelection)
        self.projectionTable.setSortingEnabled(True)

        self.projectionTableModel = QStandardItemModel(self)
        self.projectionTableModel.setHorizontalHeaderLabels(["P-Index", "", ""])
        self.projectionTable.setModel(self.projectionTableModel)

        self.projectionTable.setColumnWidth(0, 90)
        self.projectionTable.sortByColumn(0, Qt.DescendingOrder)
        self.projectionTable.selectionModel().selectionChanged.connect(self.on_selection_changed)

        gui.button(self.controlArea, self, "Rank Projections", callback=self.rank, default=True)
        self.resize(370, 600)

    def set_data(self, data):
        self.data = data
        self.infoa.setText("Data set: {}".format(data.name) if self.data else "No data loaded.")

    def rank(self):
        if self.progress:
            return

        disc = Orange.preprocess.discretize.EqualWidth(n=10)

        ndomain = Orange.data.Domain(
                [disc(self.data, attr) if type(attr) == Orange.data.variable.ContinuousVariable
                 else attr for attr in self.data.domain.attributes], self.data.domain.class_vars)

        t = self.data.from_table(ndomain, self.data)

        attrs = t.domain.attributes

        tables = {}
        l = 0
        self.progress = gui.ProgressBar(self, len(attrs) * (len(attrs) - 1) / 2)
        for i in range(len(attrs)):
            for j in range(i):
                ct = np.array(contingency.get_contingency(t, attrs[j], attrs[i]))
                pindex, _, _ = p_index(ct)
                tables[i, j] = ct

                item = QStandardItem()
                item.setData(float(pindex), Qt.DisplayRole)
                self.projectionTableModel.setItem(l, 0, item)

                item = QStandardItem()
                item.setData(attrs[i].name, Qt.DisplayRole)
                self.projectionTableModel.setItem(l, 1, item)

                item = QStandardItem()
                item.setData(attrs[j].name, Qt.DisplayRole)
                self.projectionTableModel.setItem(l, 2, item)

                self.progress.advance()
                l += 1

        self.progress.finish()
        self.progress = None

    def on_selection_changed(self, selected, deselected):
        """Called when the ranks view selection changes."""
        a1 = selected.indexes()[1].data().replace('D_', '')
        a2 = selected.indexes()[2].data().replace('D_', '')
        d = self.data.domain
        self.send("Features", AttributeList([d[a1], d[a2]]))
Exemple #42
0
class OWConfusionMatrix(widget.OWWidget):
    name = "Confusion Matrix"
    description = "Shows a confusion matrix."
    icon = "icons/ConfusionMatrix.svg"
    priority = 1001

    inputs = [{"name": "Evaluation Results",
               "type": Orange.evaluation.testing.Results,
               "handler": "set_results"}]
    outputs = [{"name": "Selected Data",
                "type": Orange.data.Table}]

    quantities = ["Number of instances",
                  "Observed and expected instances",
                  "Proportion of predicted",
                  "Proportion of true"]

    selected_learner = settings.Setting([])
    selected_quantity = settings.Setting(0)
    append_predictions = settings.Setting(True)
    append_probabilities = settings.Setting(False)
    autocommit = settings.Setting(True)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.results = None
        self.learners = []
        self._invalidated = False

        box = gui.widgetBox(self.controlArea, "Learners")

        self.learners_box = gui.listBox(
            box, self, "selected_learner", "learners",
            callback=self._learner_changed
        )
        box = gui.widgetBox(self.controlArea, "Show")

        combo = gui.comboBox(box, self, "selected_quantity",
                             items=self.quantities,
                             callback=self._update)

        box = gui.widgetBox(self.controlArea, "Selection")

        gui.button(box, self, "Correct",
                   callback=self.select_correct, autoDefault=False)
        gui.button(box, self, "Misclassified",
                   callback=self.select_wrong, autoDefault=False)
        gui.button(box, self, "None",
                   callback=self.select_none, autoDefault=False)

        self.outputbox = box = gui.widgetBox(self.controlArea, "Output")
        gui.checkBox(box, self, "append_predictions",
                     "Append class predictions", callback=self._invalidate)
        gui.checkBox(box, self, "append_probabilities",
                     "Append predicted class probabilities",
                     callback=self._invalidate)

        b = gui.button(box, self, "Commit", callback=self.commit, default=True)
        cb = gui.checkBox(box, self, "autocommit", "Commit automatically")
        gui.setStopper(self, b, cb, "_invalidated", callback=self.commit)

        grid = QGridLayout()
        grid.setContentsMargins(0, 0, 0, 0)
        grid.addWidget(QLabel("Predicted"), 0, 1, Qt.AlignCenter)
        grid.addWidget(VerticalLabel("Correct Class"), 1, 0, Qt.AlignCenter)

        self.tablemodel = QStandardItemModel()
        self.tableview = QTableView(
            editTriggers=QTableView.NoEditTriggers,
        )
        self.tableview.setModel(self.tablemodel)
        self.tableview.selectionModel().selectionChanged.connect(
            self._invalidate
        )
        grid.addWidget(self.tableview, 1, 1)
        self.mainArea.layout().addLayout(grid)

    def set_results(self, results):
        """Set the input results."""

        self.clear()
        self.warning([0, 1])

        data = None
        if results is not None:
            if results.data is not None:
                data = results.data

        if data is not None and \
                not isinstance(data.domain.class_var,
                               Orange.data.DiscreteVariable):
            data = None
            results = None
            self.warning(
                0, "Confusion Matrix cannot be used for regression results.")

        self.results = results
        self.data = data

        if data is not None:
            class_values = data.domain.class_var.values
        elif results is not None:
            raise NotImplementedError

        if results is not None:
            nmodels, ntests = results.predicted.shape
            headers = class_values + [unicodedata.lookup("N-ARY SUMMATION")]

            # NOTE: The 'fitter_names' is set in 'Test Learners' widget.
            if hasattr(results, "fitter_names"):
                self.learners = results.fitter_names
            else:
                self.learners = ["L %i" % (i + 1) for i in range(nmodels)]

            self.tablemodel.setVerticalHeaderLabels(headers)
            self.tablemodel.setHorizontalHeaderLabels(headers)
            self.tablemodel.setRowCount(len(class_values) + 1)
            self.tablemodel.setColumnCount(len(class_values) + 1)
            self.selected_learner = [0]
            self._update()

    def clear(self):
        self.learners = []
        self.results = None
        self.data = None
        self.tablemodel.clear()

    def select_correct(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()
        for i in range(n):
            index = self.tablemodel.index(i, i)
            selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect
        )

    def select_wrong(self):
        selection = QItemSelection()
        n = self.tablemodel.rowCount()

        for i in range(n):
            for j in range(i + 1, n):
                index = self.tablemodel.index(i, j)
                selection.select(index, index)
                index = self.tablemodel.index(j, i)
                selection.select(index, index)

        self.tableview.selectionModel().select(
            selection, QItemSelectionModel.ClearAndSelect
        )

    def select_none(self):
        self.tableview.selectionModel().clear()

    def commit(self):
        if self.results and self.data:
            indices = self.tableview.selectedIndexes()
            indices = {(ind.row(), ind.column()) for ind in indices}
            actual = self.results.actual
            selected_learner = self.selected_learner[0]
            learner_name = self.learners[selected_learner]
            predicted = self.results.predicted[selected_learner]
            selected = [i for i, t in enumerate(zip(actual, predicted))
                        if t in indices]
            row_indices = self.results.row_indices[selected]

            extra = []
            class_var = self.data.domain.class_var
            metas = self.data.domain.metas

            if self.append_predictions:
                predicted = numpy.array(predicted[selected], dtype=object)
                extra.append(predicted.reshape(-1, 1))
                var = Orange.data.DiscreteVariable(
                    "{}({})".format(class_var.name, learner_name),
                    class_var.values
                )
                metas = metas + (var,)

            if self.append_probabilities and \
                    self.results.probabilities is not None:
                probs = self.results.probabilities[selected_learner, selected]
                extra.append(numpy.array(probs, dtype=object))
                pvars = [Orange.data.ContinuousVariable("p({})".format(value))
                         for value in class_var.values]
                metas = metas + tuple(pvars)

            X = self.data.X[row_indices]
            Y = self.data.Y[row_indices]
            M = self.data.metas[row_indices]

            M = numpy.hstack((M,) + tuple(extra))
            domain = Orange.data.Domain(
                self.data.domain.attributes,
                self.data.domain.class_vars,
                metas
            )

            data = Orange.data.Table.from_numpy(domain, X, Y, M)

        else:
            data = None

        self.send("Selected Data", data)
        self._invalidated = False

    def _invalidate(self):
        if self.autocommit:
            self.commit()
        else:
            self._invalidated = True

    def _learner_changed(self):
        # The selected learner has changed
        self._update()

    def _update(self):
        # Update the displayed confusion matrix
        if self.results is not None and self.selected_learner:
            index = self.selected_learner[0]
            cmatrix = confusion_matrix(self.results, index)
            colsum = cmatrix.sum(axis=0)
            rowsum = cmatrix.sum(axis=1)
            total = rowsum.sum()

            if self.selected_quantity == 0:
                value = lambda i, j: int(cmatrix[i, j])
            elif self.selected_quantity == 1:
                priors = numpy.outer(rowsum, colsum) / total
                value = lambda i, j: \
                    "{} / {:5.3f}".format(cmatrix[i, j], priors[i, j])
            elif self.selected_quantity == 2:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / colsum[i])
                     if colsum[i] else "N/A")
            elif self.selected_quantity == 3:
                value = lambda i, j: \
                    ("{:2.1f} %".format(100 * cmatrix[i, j] / rowsum[i])
                     if colsum[i] else "N/A")
            else:
                assert False

            model = self.tablemodel
            for i, row in enumerate(cmatrix):
                for j, _ in enumerate(row):
                    item = model.item(i, j)
                    if item is None:
                        item = QStandardItem()
                    item.setData(value(i, j), Qt.DisplayRole)
                    item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                    item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
                    model.setItem(i, j, item)

            font = model.invisibleRootItem().font()
            bold_font = QFont(font)
            bold_font.setBold(True)

            def sum_item(value):
                item = QStandardItem()
                item.setData(value, Qt.DisplayRole)
                item.setTextAlignment(Qt.AlignRight | Qt.AlignVCenter)
                item.setFlags(Qt.ItemIsEnabled)
                item.setFont(bold_font)
                return item

            N = len(colsum)
            for i in range(N):
                model.setItem(N, i, sum_item(int(colsum[i])))
                model.setItem(i, N, sum_item(int(rowsum[i])))

            model.setItem(N, N, sum_item(int(total)))
Exemple #43
0
window.show()

tray = QSystemTrayIcon(icon)
menu = QMenu()
actionShow = QAction("Show Leopard Flower", menu)
actionExit = QAction("Exit", menu)
menu.addAction(actionShow)
menu.addAction(actionExit)
tray.setContextMenu(menu)
tray.show()
actionShow.triggered.connect(window.show)
actionExit.triggered.connect(window.realQuit)

modelAll = QStandardItemModel()
modelAll.setHorizontalHeaderLabels(
    ("Name", "Process ID", "Permissions", "Full path", "Incoming allowed",
     "Outgoing allowed", "Incoming denied", "Outgoing denied"))
modelActive = QStandardItemModel()
modelActive.setHorizontalHeaderLabels(
    ("Name", "Process ID", "Permissions", "Full path", "Incoming allowed",
     "Outgoing allowed", "Incoming denied", "Outgoing denied"))
window.tableView.setModel(modelAll)
dialogOut = myDialogOut()
dialogOut.setWindowTitle("Leopard Flower firewall")
dialogIn = myDialogIn()
dialogIn.setWindowTitle("Leopard Flower firewall")
prefs_dialog = mForm()

ruleslock = Lock()
msgq_init()
sys.exit(app.exec_())
Exemple #44
0
class MSMainWindow(QMainWindow):
    """Gui of the main window"""

    # MAX_RECENT_FILES = 10
    # start putting links spyder numpy scipy et tutti quanti
    links = (
        "http://numpy.scipy.org/",
        "http://packages.python.org/spyder/",
        "http://www.riverbankcomputing.co.uk/software/pyqt/intro",
    )

    pluginPath = path.normcase("pluginmanager/plugins/")

    def __init__(self, availablePlugins):
        """
        Constructor with all the models needed setup menus
        
        """
        QMainWindow.__init__(self)
        self.setDockOptions(QMainWindow.VerticalTabs | QMainWindow.AnimatedDocks)
        self.plugins = availablePlugins
        self.pluginsInst = []
        settings = QSettings(
            "INRA/INSA", "-".join([QApplication.instance().APPLICATION_NAME_STR, QApplication.instance().VERSION_STR])
        )
        self.recentFiles = list(settings.value("RecentFiles").toStringList())
        self.setStyleSheet(stylesheet)
        self.pipeline = MSPipelineToolBar("Pipeline toolbar", parent=self)
        self.addToolBar(0x1, self.pipeline)

        self._setupModels()
        self._setupUi()
        self._setupMenus()

    def _setupModels(self):
        """
        Warning:Causes segfault when horizontal labels set to True
        
        on aura peu etre a la fin un model par sampleList c'est ce qui parait
        le plus logique
        
        """
        # drag and drop table sample
        self.sampleModel = QStandardItemModel(self)
        self.sampleModel.setHorizontalHeaderLabels(["Sample", "Class"])
        # treeView1
        self.spectraModel = QStandardItemModel(self)
        # treeview2
        self.peakModel = QStandardItemModel(self)
        # treeview3
        self.clusterModel = QStandardItemModel(self)

    def _setupMenus(self):
        # file
        self.fileMenu = QMenu("&File")
        self.fileMenu.setTearOffEnabled(True)
        self.op = QMenu("&Open...", self.fileMenu)
        self.op.setIcon(QIcon(path.normcase("gui/icons/fileopen.png")))

        open_ = QAction("&Open rawfiles", self)
        open_.setToolTip("Open an mzXML or netCDF file")
        open_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_O))
        open_icon = QIcon(path.normcase("gui/icons/fileopen.png"))
        open_.setIcon(open_icon)
        self.op.addAction(open_)

        load_ = QAction("&Open projects...", self)
        load_.setToolTip("load binary file containing saved objects")
        load_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        load_icon = QIcon(QPixmap(path.normcase("gui/icons/project_open.png")))
        load_.setIcon(load_icon)
        self.op.addAction(load_)

        self.fileMenu.addMenu(self.op)

        save_ = QAction("&Save...", self)
        save_.setToolTip("save the actual application model")
        save_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_S))
        save_icon = QIcon(path.normcase("gui/icons/save_all.png"))
        save_.setIcon(save_icon)
        self.fileMenu.addAction(save_)

        pkl = QAction("&load a peaklist", self)  # TODO:load peaklist
        pkl.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_P))
        pkl.setToolTip("load a peaklist and process it")
        pkl.setIcon(QIcon(path.normcase("gui/icons/featuredetect.png")))
        self.fileMenu.addAction(pkl)

        convert_ = QAction("&Convert...", self)
        convert_.setEnabled(False)
        convert_.setToolTip("Convert a .wiff file if Analyst(c) is installed")
        convert_icon = QIcon(path.normcase("gui/icons/goto.png"))
        convert_.setIcon(convert_icon)
        self.fileMenu.addAction(convert_)

        a = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Launch a batch")
        a.setEnabled(False)

        b = self.fileMenu.addAction(QIcon(path.normcase("gui/icons/process.png")), "&Merge")
        b.setToolTip("Merge MRM file")
        # b.setEnabled(False)

        self.fileMenu.addSeparator()
        #
        #        for i in xrange(self.MAX_RECENT_FILES):
        #            a = QAction('', self)
        #            a.setVisible(False)
        #            self.fileMenu.addAction(a)
        #
        #        for i in xrange(min(self.MAX_RECENT_FILES, len(self.recentFiles))):
        #            self.fileMenu.actions()[5+i].setVisible(True)
        #            self.fileMenu.actions()[5+i].setText(self.recentFiles[i].split('/')[-1])

        exit_action = QAction("&Exit", self)
        exit_action.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_Q))
        exit_action.setIcon(QIcon(QPixmap(path.normcase("gui/icons/exit.png"))))
        self.fileMenu.addAction(exit_action)

        self.menuBar().addMenu(self.fileMenu)

        self.editMenu = QMenu("&Edit")
        self.editMenu.setTearOffEnabled(True)
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_undo.png")), "&Undo...")
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/edit_redo.png")), "&Redo...")
        self.editMenu.actions()[0].setEnabled(False)
        self.editMenu.actions()[1].setEnabled(False)
        self.editMenu.addSeparator()
        self.editMenu.addAction(QIcon(path.normcase("gui/icons/run.png")), "&Preferences")
        self.exportMenu = QMenu("&Export...")
        self.exportMenu.setIcon(QIcon(path.normcase("gui/icons/file_export.png")))
        self.exportMenu.addAction("&Peaklist")
        self.exportMenu.addAction("&Clusters intensity matrix")
        self.editMenu.addMenu(self.exportMenu)
        self.menuBar().addMenu(self.editMenu)

        # view
        self.viewMenu = QMenu("&View")
        self.viewMenu.setTearOffEnabled(True)
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/window_duplicate")),
            "&Cascade View",
            self.mdiArea.cascadeSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_K),
        )
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/view_icon")),
            "&Title View",
            self.mdiArea.tileSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_N),
        )
        self.viewMenu.addAction(
            QIcon(path.normcase("gui/icons/stop_process.png")),
            "&Close all subWindows",
            self.mdiArea.closeAllSubWindows,
            QKeySequence(Qt.CTRL + Qt.Key_W),
        )

        self.plotting = QMenu("&Plotting...")
        self.plotting.setIcon(QIcon(QPixmap(path.normcase("gui/icons/plot.png"))))
        self.plotting.addAction("&3D Plot")
        # self.plotting.addAction("&Cytoscape web")
        self.plotting.addAction("&Spectrogram Plot")

        # self.multiplePlot = QAction("&Visualize Raw/Treated Data", self)
        # self.multiplePlot.setCheckable(True)
        # self.multiplePlot.setEnabled(False)
        # self.sub_plot_.addAction(self.multiplePlot)

        self.viewMenu.addMenu(self.plotting)
        self.viewMenu.addSeparator()
        self.show_hide = QMenu("&Show/Hide")
        m = self.createPopupMenu()
        m.setTitle("&Show/Hide")
        self.viewMenu.addMenu(m)
        # self.pref = QMenu("&Preferences")

        # self.pref.addAction(self.multiplePlot)
        # self.viewMenu.addMenu(self.pref)
        self.menuBar().addMenu(self.viewMenu)

        # algorithm
        self.algoMenu = QMenu("&Algorithm")
        self.algoMenu.setTearOffEnabled(True)
        self.preProcessing = QMenu("&PreProcessing(experimental)")
        self.preProcessing.addAction("&Smoothing raw data...")
        self.preProcessing.addAction("&Cut off raw data...")
        self.preProcessing.addAction("&Calibration (mz dimension)")
        self.preProcessing.addAction("&Resize sample...")

        self.algoMenu.addMenu(self.preProcessing)

        self.peakPickingMenu = QMenu("&Peack Picking & Alignement(XCMS)", self)
        self.peakPickingMenu.setIcon(QIcon(path.normcase("gui/icons/pickedpeakicon.png")))

        matched = QAction("&MatchedFiltered", self)
        matched.setIcon(QIcon(path.normcase("gui/icons/RLogo")))
        matched.setToolTip("Peak Detection and Integration using MatchedFiltered algorithm")
        self.peakPickingMenu.addAction(matched)

        centwave = QAction("&CentWave", self)
        centwave.setIcon(QIcon(path.normcase("gui/icons/RLogo")))
        centwave.setToolTip("Peak Detection and Integration using CentWave algorithm")
        self.peakPickingMenu.addAction(centwave)
        # peak_.setShortcut(.QKeySequence(CTRL + Key_P))
        # peak_icon=.QIcon(.QPixmap(path.normcase("gui/icons/pickedpeakicon.png")))
        # peak_.setIcon(peak_icon)
        self.algoMenu.addMenu(self.peakPickingMenu)

        self.alignment = QMenu("&Alignment")
        self.alignment.setIcon(QIcon(path.normcase("gui/icons/format_indent_more.png")))
        self.alignment.addAction("&Polynomial fitting(exp)")
        self.alignment.addAction("&DynamicTimeWarping")
        self.alignment.addAction("&ObiWarp")
        self.alignment.actions()[2].setEnabled(False)
        self.algoMenu.addMenu(self.alignment)

        self.algoMenu.addAction("Normalization")

        clust_ = QAction("&Clustering", self)
        clust_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_L))
        clust_icon = QIcon(QPixmap(path.normcase("gui/icons/cluster.png")))
        clust_.setIcon(clust_icon)
        self.algoMenu.addAction(clust_)

        id_ = QAction("&Identification", self)
        id_.setShortcut(QKeySequence(Qt.CTRL + Qt.Key_I))
        id_.setToolTip("Try to identify peaks with several methods")
        id_.setIcon(QIcon(QPixmap(path.normcase("gui/icons/findcompound.png"))))
        self.algoMenu.addAction(id_)
        self.menuBar().addMenu(self.algoMenu)

        # tools
        self.toolsMenu = QMenu("&Tools")
        self.toolsMenu.setTearOffEnabled(True)
        web = QAction("&Web Browser", self)
        web.setIcon(QIcon(QPixmap(path.normcase("gui/icons/applications_internet.png"))))
        self.toolsMenu.addAction(web)
        # cyto = QAction("&cytoscape", self)
        # cyto_icon =QIcon(QPixmap(path.normcase("gui/icons/cytoscape.jpeg")))
        # cyto.setIcon(cyto_icon)
        # self.toolsMenu.addAction(cyto)
        editor = QAction("&Editor", self)
        editor.setIcon(QIcon(QPixmap(path.normcase("gui/icons/document_sign.png"))))
        self.toolsMenu.addAction(editor)
        pet = QAction("&Short Periodic Table", self)
        pet.setIcon(QIcon(QPixmap(path.normcase("gui/icons/pet.jpg"))))
        self.toolsMenu.addAction(pet)
        self.menuBar().addMenu(self.toolsMenu)

        # plugins
        self.pluginMenu = QMenu("&Plugins")
        self.pluginMenu.setTearOffEnabled(True)
        instPl = QAction("&Install a plugin", self)
        instPl.setIcon(QIcon(path.normcase("gui/icons/pluginInstall.png")))
        self.pluginMenu.addAction(instPl)
        self.launchingMenu = QMenu("&Launch PLugins", self)
        self.launchingMenu.setIcon(QIcon(path.normcase("gui/icons/plugin")))

        for plug in self.plugins:
            # fullname="".join([self.pluginPath, str(plug)])
            mod = imp.load_source(self.__module__, plug)
            if mod.autoActivation:
                qApp = QApplication.instance()
                name = getattr(mod, "className")
                cls = getattr(mod, name)
                p = cls(qApp.model, self, parent=self)
                # p=qApp.pluginManager.loadPlugin(qApp.model, self, plug.split('/')[-1])
                self.pluginsInst.append(p)
            else:
                self.launchingMenu.addAction(plug.split("/")[-1])
        self.pluginMenu.addMenu(self.launchingMenu)
        self.pluginMenu.addAction(QIcon(path.normcase("gui/icons/process_stop.png")), "&Remove loaded Plugin")
        self.menuBar().addMenu(self.pluginMenu)

        # about
        self.aboutMenu = QMenu("&About")
        self.aboutMenu.setTearOffEnabled(True)
        metms = QAction(QIcon(path.normcase("gui/icons/deluge.png")), "&about metMS...", self)
        self.aboutMenu.addAction(metms)

        pyqt = QAction("&about PyQt4...", self)
        pyqt_icon = QIcon(QPixmap(path.normcase("gui/icons/logo_QT4.png")))
        pyqt.setIcon(pyqt_icon)
        self.aboutMenu.addAction(pyqt)
        metms = QAction("&metMS Documentation", self)
        metms_icon = QIcon(QPixmap(path.normcase("gui/icons/deluge.png")))
        metms.setIcon(metms_icon)
        self.aboutMenu.addAction(metms)
        self.menuBar().addMenu(self.aboutMenu)

    def _setupUi(self, background=None):
        """        
        Make the GUI
        
        """
        # mdi
        self.mdiArea = MSMdiArea(self)
        self.mdiArea.setBackground(QBrush(QPixmap(path.normcase("gui/icons/blac2.png"))))  # QColor(Qt.blue).darker()))
        self.setCentralWidget(self.mdiArea)

        # sample dock widget
        self.sampleDockWidget = QDockWidget("Samples", self)
        # sampleWidget = QWidget()
        self.sampleTableView = MSDragFromTableView()
        self.sampleTableView.setModel(self.sampleModel)
        self.sampleTableView.setSelectionBehavior(1)
        self.sampleTableView.verticalHeader().hide()
        self.sampleTableView.verticalHeader().setDefaultSectionSize(15)
        self.sampleTableView.horizontalHeader().setDefaultSectionSize(150)

        self.sampleDockWidget.setWidget(self.sampleTableView)  # sampleWidget)
        self.sampleDockWidget.visible = True

        # workflow dock
        self.workflowDockWidget = QDockWidget("Visualizer", self)
        self.workflowDockWidget.visible = True

        a = QWidget(self)
        v = QVBoxLayout(a)
        q = QToolBar()
        # self.workingSample = QLabel("Working Sample:None")
        # q.addWidget(self.workingSample)
        q.addWidget(QLabel("ppm :"))
        self.ppmEditer = QDoubleSpinBox()
        self.usePpm = QCheckBox("use ?")
        q.addWidget(self.ppmEditer)
        q.addWidget(self.usePpm)

        q.addSeparator()

        self.removeButton = QToolButton(self)
        self.removeButton.setIcon(QIcon(path.normcase("gui/icons/delete.png")))
        q.addWidget(self.removeButton)

        self.markAsGood = QAction(QIcon(path.normcase("gui/icons/button_ok.png")), "mark peak as good", self)
        self.markAsBad = QAction(QIcon(path.normcase("gui/icons/stop.png")), "mark peak as bad", self)
        self.hideItem = QAction(QIcon(path.normcase("gui/icons/list_remove.png")), "Hide Item", self)

        q.addAction(self.markAsGood)
        q.addAction(self.markAsBad)
        q.addAction(self.hideItem)
        v.addWidget(q)

        self.tabWidget = QTabWidget()
        self.tab = QWidget()
        verticalLayout = QVBoxLayout(self.tab)
        self.treeView = MSToDropTableView()
        self.treeView.verticalHeader().setDefaultSectionSize(20)

        self.treeView.setModel(self.spectraModel)
        self.spectraLabel = QLabel("Sample: None")
        verticalLayout.addWidget(self.treeView)
        verticalLayout.addWidget(self.spectraLabel)
        self.tabWidget.addTab(self.tab, QIcon(path.normcase("gui/icons/spectrumicon.png")), "Spectra")

        self.tab_2 = QWidget()
        verticalLayout_4 = QVBoxLayout(self.tab_2)
        self.treeView_2 = MSToDropTableView()  # MSTreeView(self.tab_2)# QTableView(self)#
        self.treeView_2.verticalHeader().setDefaultSectionSize(20)
        self.treeView_2.setModel(self.peakModel)
        self.peakLabel = QLabel("Sample: None")
        verticalLayout_4.addWidget(self.treeView_2)
        verticalLayout_4.addWidget(self.peakLabel)
        self.tabWidget.addTab(self.tab_2, QIcon(path.normcase("gui/icons/peakicon.png")), "Peaks List")

        self.tab_3 = QWidget()
        verticalLayout_5 = QVBoxLayout(self.tab_3)
        self.treeView_3 = MSToDropTreeView()
        self.treeView_3.setAnimated(True)
        self.treeView_3.setModel(self.clusterModel)
        self.clusterLabel = QLabel("Sample: None")
        verticalLayout_5.addWidget(self.treeView_3)
        verticalLayout_5.addWidget(self.clusterLabel)
        self.tabWidget.addTab(self.tab_3, QIcon(path.normcase("gui/icons/clustering.png")), "Clusters")

        self.tabWidget.setCurrentIndex(0)

        for l in (self.spectraLabel, self.peakLabel, self.clusterLabel):
            l.setAutoFillBackground(True)

        v.addWidget(self.tabWidget)
        self.workflowDockWidget.setWidget(a)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.workflowDockWidget)

        from gui.MetBaseGui import MSIsoCalculator

        self.isoCalc = MSIsoCalculator(self)
        self.isoCalcDockWidget = QDockWidget("isotopes calculation", self)
        self.isoCalcDockWidget.setWidget(self.isoCalc)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.isoCalcDockWidget)
        self.isoCalcDockWidget.setVisible(False)
        self.isoCalcDockWidget.visible = False

        from gui.MetBaseGui import FormulaGenerator

        self.generator = FormulaGenerator(self)
        self.generatorDockWidget = QDockWidget("formula generator", self)
        self.generatorDockWidget.setWidget(self.generator)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.generatorDockWidget)
        self.generatorDockWidget.setVisible(False)
        self.generatorDockWidget.visible = False

        self.compoundTreeView = MSCompoundTreeView(self)
        self.compoundDockWidget = QDockWidget("Compounds", self)
        self.compoundDockWidget.setWidget(self.compoundTreeView)
        self.addDockWidget(Qt.DockWidgetArea(0x2), self.compoundDockWidget)
        self.compoundDockWidget.setVisible(False)
        self.compoundDockWidget.visible = False

        self.comparativeTableView = QTableView(self)
        self.comparativeTableView.horizontalHeader().setStretchLastSection(True)
        self.comparativeTableView.verticalHeader().setDefaultSectionSize(20)
        self.comparativeDock = QDockWidget("Comparative View", self)
        self.comparativeDock.setWidget(self.comparativeTableView)
        self.addDockWidget(Qt.DockWidgetArea(0x8), self.comparativeDock)
        self.comparativeDock.setVisible(False)
        self.comparativeDock.visible = False

        self.tabifyDockWidget(self.compoundDockWidget, self.isoCalcDockWidget)
        self.tabifyDockWidget(self.isoCalcDockWidget, self.workflowDockWidget)
        self.tabifyDockWidget(self.workflowDockWidget, self.generatorDockWidget)
        # set the end

        # WARNING: possible that the internal shell widget cause random segfault
        # with the error of QObject::killTimers...? not sure !
        self.shell = QWidget()  # InternalShell(namespace={'metms': QApplication.instance()},
        #              parent=self,
        #              multithreaded=False)
        self.shellDock = QDockWidget("Python Shell", self)
        self.shellDock.setWindowIcon(QIcon(path.normcase("gui/icons/stop.png")))
        self.shellDock.setWidget(self.shell)
        self.shellDock.setMinimumWidth(255)
        self.shellDock.visible = True
        self.addDockWidget(0x2, self.shellDock)

        self.addDockWidget(0x2, self.sampleDockWidget)
        self.tabifyDockWidget(self.shellDock, self.sampleDockWidget)

        self.pb = QProgressBar(self)
        self.pb.setMaximumWidth(245)

        self.stopProcess = QToolButton(self)
        self.stopProcess.setIcon(QIcon(path.normcase("gui/icons/process_stop.png")))
        m = QMenu()
        # self.connect(m, SIGNAL('triggered(QAction*'), QApplication.instance().taskManager.abortByName)
        self.stopProcess.setMenu(m)
        self.stopProcess.setPopupMode(1)  # Menu Button
        # self.connect(self.stopProcess, SIGNAL("clicked()"), self.stopThread)

        self.statusBar().addPermanentWidget(self.stopProcess)
        self.statusBar().addPermanentWidget(self.pb)

    def updateStopProcessMenu(self):
        """
        update the menu of the stop process
        button, based directly on the processes
        stored by the task manager
        
        """
        self.stopProcess.menu().clear()
        for c in QApplication.instance().taskManager:
            self.stopProcess.menu().addAction(c.title)

        # QApplication.instance().taskManager.abort(QApplication.instance().taskManager[-1])

    def addMdiSubWindow(self, plot, title="", showMaximized=False):
        """ 
        Allow addition of new window in the mdiarea
        
        """
        win = self.mdiArea.addSubWindow(plot)
        # print "widget parent", plot.parent()
        win.setAttribute(Qt.WA_DeleteOnClose)
        # win.connect(win, SIGNAL('destroyed(QObject *)'), self.testdestroy)
        # plot.setParent(win)
        win.setWindowTitle(title)
        if showMaximized:
            win.showMaximized()
        else:
            win.resize(400, 300)
        win.show()
        return win

    def updateTreeView(self):
        """
        Tree View update switch spectre/chromato
        
        """
        if self.treeView.model() == self.spectraModel:
            self.treeView.setModel(self.chromaModel)
            self.tabWidget.setTabText(0, "Chroma")
        else:
            self.treeView.setModel(self.spectraModel)
            # self.treeView.setSelectionMode(1)
            self.tabWidget.setTabText(0, "Spectra")

    def addTreeViewModel(self, model1, model2):
        """Add a model """
        self.chromaModel.appendRow(model1)
        self.spectraModel.appendRow(model2)

    def _actionHovered(self, action):
        """emulate tooltip cause they do not work that much"""
        tip = action.toolTip()
        QToolTip.showText(QCursor.pos(), tip)

    def showErrorMessage(self, title, string):
        QMessageBox.critical(self, title, string, 0, 0)

    def showWarningMessage(self, title, string):
        return QMessageBox.warning(self, title, string, QMessageBox.Ok | QMessageBox.Cancel)

    def showInformationMessage(self, title, string):
        QMessageBox.information(self, title, string, 0)

    def updateProgressBar(self, i):
        """update the value of the progress bar for all the treatment"""

        self.pb.setValue(min(i, 100))

    def to_indetermined_mode(self):
        self.pb.setMaximum(0)

    def to_determined_mode(self):
        self.pb.setMaximum(100)

    def showInStatusBar(self, string, time=5000):
        self.statusBar().showMessage(string, time)

    def addInterpreterDock(self, shell):
        self.shellDock = QDockWidget(self)
        self.shellDock.setWidget(shell)
        self.shellDock.setWindowTitle("shell")
        self.addDockWidget(0x2, self.shellDock)

    def showMetMSInformation(self):

        QMessageBox.about(
            self,
            self.tr("About %1").arg("metMS"),
            self.tr(
                """<b>%1 %2</b>
            <br>metabolite Mass Spectrometry
            <p>Copyright &copy; 2010 Marco INSA, INRA
            <br>Licensed under the terms of the CeciLL License
            <p>Developed and maintained by Marco
            <br>Bug reports and feature requests: 
            <a href="http://github.com/jerkos/metms">metMS site</a><br>
            Discussions around the project: 
            <a href="http://groups.google.com/group/spyderlib">Google Group</a>
            <p>This project is part of the BRIDGE project
            <p>Python %3, Qt %4, PyQt %5"""
            )
            .arg("metMS")
            .arg(__version__)
            .arg(platform.python_version())
            .arg(QT_VERSION_STR)
            .arg(PYQT_VERSION_STR),
        )
Exemple #45
0
class OWTestLearners(widget.OWWidget):
    name = "Test & Score"
    description = "Cross-validation accuracy estimation."
    icon = "icons/TestLearners1.svg"
    priority = 100

    inputs = [("Learner", Learner, "set_learner", widget.Multiple),
              ("Data", Table, "set_train_data", widget.Default),
              ("Test Data", Table, "set_test_data"),
              ("Preprocessor", Preprocess, "set_preprocessor")]

    outputs = [("Predictions", Orange.data.Table),
               ("Evaluation Results", Orange.evaluation.Results)]

    settingsHandler = settings.ClassValuesContextHandler()

    #: Resampling/testing types
    KFold, ShuffleSplit, LeaveOneOut, TestOnTrain, TestOnTest = 0, 1, 2, 3, 4

    #: Selected resampling type
    resampling = settings.Setting(0)
    #: Number of folds for K-fold cross validation
    k_folds = settings.Setting(10)
    #: Stratified sampling for K-fold
    cv_stratified = settings.Setting(True)
    #: Number of repeats for ShuffleSplit sampling
    n_repeat = settings.Setting(10)
    #: ShuffleSplit sampling p
    sample_p = settings.Setting(75)
    #: Stratified sampling for Random Sampling
    shuffle_stratified = settings.Setting(True)

    TARGET_AVERAGE = "(Average over classes)"
    class_selection = settings.ContextSetting(TARGET_AVERAGE)

    def __init__(self):
        super().__init__()

        self.data = None
        self.test_data = None
        self.preprocessor = None
        self.train_data_missing_vals = False
        self.test_data_missing_vals = False

        #: An Ordered dictionary with current inputs and their testing
        #: results.
        self.learners = OrderedDict()

        sbox = gui.widgetBox(self.controlArea, "Sampling")
        rbox = gui.radioButtons(sbox,
                                self,
                                "resampling",
                                callback=self._param_changed)

        gui.appendRadioButton(rbox, "Cross validation")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox,
                 self,
                 "k_folds",
                 2,
                 50,
                 label="Number of folds:",
                 callback=self.kfold_changed)
        gui.checkBox(ibox,
                     self,
                     "cv_stratified",
                     "Stratified",
                     callback=self.kfold_changed)

        gui.appendRadioButton(rbox, "Random sampling")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox,
                 self,
                 "n_repeat",
                 2,
                 50,
                 label="Repeat train/test",
                 callback=self.shuffle_split_changed)
        gui.widgetLabel(ibox, "Relative training set size:")
        gui.hSlider(ibox,
                    self,
                    "sample_p",
                    minValue=1,
                    maxValue=99,
                    ticks=20,
                    vertical=False,
                    labelFormat="%d %%",
                    callback=self.shuffle_split_changed)
        gui.checkBox(ibox,
                     self,
                     "shuffle_stratified",
                     "Stratified",
                     callback=self.shuffle_split_changed)

        gui.appendRadioButton(rbox, "Leave one out")

        gui.appendRadioButton(rbox, "Test on train data")
        gui.appendRadioButton(rbox, "Test on test data")

        rbox.layout().addSpacing(5)
        self.apply_button = gui.button(rbox,
                                       self,
                                       "Apply",
                                       callback=self.apply,
                                       default=True)

        self.cbox = gui.widgetBox(self.controlArea, "Target class")
        self.class_selection_combo = gui.comboBox(
            self.cbox,
            self,
            "class_selection",
            items=[],
            sendSelectedValue=True,
            valueType=str,
            callback=self._on_target_class_changed,
            contentsLength=8)

        gui.rubber(self.controlArea)

        self.view = QTreeView(rootIsDecorated=False,
                              uniformRowHeights=True,
                              wordWrap=True,
                              editTriggers=QTreeView.NoEditTriggers)
        header = self.view.header()
        header.setResizeMode(QHeaderView.ResizeToContents)
        header.setDefaultAlignment(Qt.AlignCenter)
        header.setStretchLastSection(False)

        self.result_model = QStandardItemModel(self)
        self.result_model.setHorizontalHeaderLabels(["Method"])
        self.view.setModel(self.result_model)
        self.view.setItemDelegate(ItemDelegate())

        box = gui.widgetBox(self.mainArea, "Evaluation Results")
        box.layout().addWidget(self.view)

    def sizeHint(self):
        return QSize(780, 1)

    def set_learner(self, learner, key):
        """
        Set the input `learner` for `key`.
        """
        if key in self.learners and learner is None:
            # Removed
            del self.learners[key]
        else:
            self.learners[key] = Input(learner, None, None)
            self._invalidate([key])

    def set_train_data(self, data):
        """
        Set the input training dataset.
        """
        self.error(0)
        self.information(0)
        if data and not data.domain.class_var:
            self.error(0, "Train data input requires a class variable")
            data = None

        if isinstance(data, SqlTable):
            if data.approx_len() < AUTO_DL_LIMIT:
                data = Table(data)
            else:
                self.information(0, "Train data has been sampled")
                data_sample = data.sample_time(1, no_cache=True)
                data_sample.download_data(AUTO_DL_LIMIT, partial=True)
                data = Table(data_sample)

        self.warning(4)
        self.train_data_missing_vals = data is not None and \
                                       np.isnan(data.Y).any()
        if self.train_data_missing_vals or self.test_data_missing_vals:
            self.warning(
                4,
                self._get_missing_data_warning(self.train_data_missing_vals,
                                               self.test_data_missing_vals))
            if data:
                data = RemoveNaNClasses(data)

        self.data = data
        self.closeContext()
        if data is not None:
            self._update_class_selection()
            self.openContext(data.domain.class_var)
        self._invalidate()

    def set_test_data(self, data):
        """
        Set the input separate testing dataset.
        """
        self.error(1)
        self.information(1)
        if data and not data.domain.class_var:
            self.error(1, "Test data input requires a class variable")
            data = None

        if isinstance(data, SqlTable):
            if data.approx_len() < AUTO_DL_LIMIT:
                data = Table(data)
            else:
                self.information(1, "Test data has been sampled")
                data_sample = data.sample_time(1, no_cache=True)
                data_sample.download_data(AUTO_DL_LIMIT, partial=True)
                data = Table(data_sample)

        self.warning(4)
        self.test_data_missing_vals = data is not None and \
                                      np.isnan(data.Y).any()
        if self.train_data_missing_vals or self.test_data_missing_vals:
            self.warning(
                4,
                self._get_missing_data_warning(self.train_data_missing_vals,
                                               self.test_data_missing_vals))
            if data:
                data = RemoveNaNClasses(data)

        self.test_data = data
        if self.resampling == OWTestLearners.TestOnTest:
            self._invalidate()

    def _get_missing_data_warning(self, train_missing, test_missing):
        return "Instances with unknown target values were removed from{}data"\
            .format(train_missing * test_missing * " "
                    or train_missing * " train " or test_missing * " test ")

    def set_preprocessor(self, preproc):
        """
        Set the input preprocessor to apply on the training data.
        """
        self.preprocessor = preproc
        self._invalidate()

    def handleNewSignals(self):
        """Reimplemented from OWWidget.handleNewSignals."""
        self._update_class_selection()
        self.apply()

    def kfold_changed(self):
        self.resampling = OWTestLearners.KFold
        self._param_changed()

    def shuffle_split_changed(self):
        self.resampling = OWTestLearners.ShuffleSplit
        self._param_changed()

    def _param_changed(self):
        self._invalidate()

    def _update_results(self):
        """
        Run/evaluate the learners.
        """
        self.warning([1, 2])
        self.error([2, 4])
        if self.data is None:
            return

        class_var = self.data.domain.class_var

        if self.resampling == OWTestLearners.TestOnTest:
            if self.test_data is None:
                self.warning(2, "Missing separate test data input")
                return
            elif self.test_data.domain.class_var != class_var:
                self.error(2, ("Inconsistent class variable between test " +
                               "and train data sets"))
                return

        # items in need of an update
        items = [(key, slot) for key, slot in self.learners.items()
                 if slot.results is None]
        learners = [slot.learner for _, slot in items]
        if len(items) == 0:
            return

        if self.test_data is not None and \
                self.resampling != OWTestLearners.TestOnTest:
            self.warning(
                1, "Test data is present but unused. "
                "Select 'Test on test data' to use it.")

        rstate = 42

        def update_progress(finished):
            self.progressBarSet(100 * finished)

        common_args = dict(store_data=True,
                           preprocessor=self.preprocessor,
                           callback=update_progress)
        self.setStatusMessage("Running")

        with self.progressBar():
            try:
                if self.resampling == OWTestLearners.KFold:
                    if len(self.data) < self.k_folds:
                        self.error(4, "Number of folds exceeds the data size")
                        return

                    warnings = []
                    results = Orange.evaluation.CrossValidation(
                        self.data,
                        learners,
                        k=self.k_folds,
                        random_state=rstate,
                        warnings=warnings,
                        **common_args)
                    if warnings:
                        self.warning(2, warnings[0])
                elif self.resampling == OWTestLearners.LeaveOneOut:
                    results = Orange.evaluation.LeaveOneOut(
                        self.data, learners, **common_args)
                elif self.resampling == OWTestLearners.ShuffleSplit:
                    train_size = self.sample_p / 100
                    results = Orange.evaluation.ShuffleSplit(
                        self.data,
                        learners,
                        n_resamples=self.n_repeat,
                        train_size=train_size,
                        test_size=None,
                        stratified=self.shuffle_stratified,
                        random_state=rstate,
                        **common_args)
                elif self.resampling == OWTestLearners.TestOnTrain:
                    results = Orange.evaluation.TestOnTrainingData(
                        self.data, learners, **common_args)
                elif self.resampling == OWTestLearners.TestOnTest:
                    results = Orange.evaluation.TestOnTestData(
                        self.data, self.test_data, learners, **common_args)
                else:
                    assert False
            except RuntimeError as e:
                self.error(2, str(e))
                self.setStatusMessage("")
                return

        learner_key = {
            slot.learner: key
            for key, slot in self.learners.items()
        }
        for learner, result in zip(learners, split_by_model(results)):
            stats = None
            if class_var.is_discrete:
                scorers = classification_stats.scores
            elif class_var.is_continuous:
                scorers = regression_stats.scores
            else:
                scorers = None
            if scorers:
                ex = result.failed[0]
                if ex:
                    stats = [Try.Fail(ex)] * len(scorers)
                    result = Try.Fail(ex)
                else:
                    stats = [Try(lambda: score(result)) for score in scorers]
                    result = Try.Success(result)
            key = learner_key[learner]
            self.learners[key] = \
                self.learners[key]._replace(results=result, stats=stats)

        self.setStatusMessage("")

    def _update_header(self):
        # Set the correct horizontal header labels on the results_model.
        headers = ["Method"]
        if self.data is not None:
            if self.data.domain.has_discrete_class:
                headers.extend(classification_stats.headers)
            else:
                headers.extend(regression_stats.headers)

        # remove possible extra columns from the model.
        for i in reversed(range(len(headers),
                                self.result_model.columnCount())):
            self.result_model.takeColumn(i)

        self.result_model.setHorizontalHeaderLabels(headers)

    def _update_stats_model(self):
        # Update the results_model with up to date scores.
        # Note: The target class specific scores (if requested) are
        # computed as needed in this method.
        model = self.view.model()
        # clear the table model, but preserving the header labels
        for r in reversed(range(model.rowCount())):
            model.takeRow(r)

        target_index = None
        if self.data is not None:
            class_var = self.data.domain.class_var
            if self.data.domain.has_discrete_class and \
                            self.class_selection != self.TARGET_AVERAGE:
                target_index = class_var.values.index(self.class_selection)
        else:
            class_var = None

        errors = []
        has_missing_scores = False

        for key, slot in self.learners.items():
            name = learner_name(slot.learner)
            head = QStandardItem(name)
            head.setData(key, Qt.UserRole)
            if isinstance(slot.results, Try.Fail):
                head.setToolTip(str(slot.results.exception))
                head.setText("{} (error)".format(name))
                head.setForeground(QtGui.QBrush(Qt.red))
                errors.append("{name} failed with error:\n"
                              "{exc.__class__.__name__}: {exc!s}".format(
                                  name=name, exc=slot.results.exception))

            row = [head]

            if class_var is not None and class_var.is_discrete and \
                    target_index is not None:
                if slot.results is not None and slot.results.success:
                    ovr_results = results_one_vs_rest(slot.results.value,
                                                      target_index)

                    stats = [
                        Try(lambda: score(ovr_results))
                        for score in classification_stats.scores
                    ]
                else:
                    stats = None
            else:
                stats = slot.stats

            if stats is not None:
                for stat in stats:
                    item = QStandardItem()
                    if stat.success:
                        item.setText("{:.3f}".format(stat.value[0]))
                    else:
                        item.setToolTip(str(stat.exception))
                        has_missing_scores = True
                    row.append(item)

            model.appendRow(row)

        if errors:
            self.error(3, "\n".join(errors))
        else:
            self.error(3)

        if has_missing_scores:
            self.warning(3, "Some scores could not be computed")
        else:
            self.warning(3)

    def _update_class_selection(self):
        self.class_selection_combo.setCurrentIndex(-1)
        self.class_selection_combo.clear()
        if not self.data:
            return

        if self.data.domain.has_discrete_class:
            self.cbox.setVisible(True)
            class_var = self.data.domain.class_var
            items = [self.TARGET_AVERAGE] + class_var.values
            self.class_selection_combo.addItems(items)

            class_index = 0
            if self.class_selection in class_var.values:
                class_index = class_var.values.index(self.class_selection) + 1

            self.class_selection_combo.setCurrentIndex(class_index)
            self.class_selection = items[class_index]
        else:
            self.cbox.setVisible(False)

    def _on_target_class_changed(self):
        self._update_stats_model()

    def _invalidate(self, which=None):
        # Invalidate learner results for `which` input keys
        # (if None then all learner results are invalidated)
        if which is None:
            which = self.learners.keys()

        model = self.view.model()
        statmodelkeys = [
            model.item(row, 0).data(Qt.UserRole)
            for row in range(model.rowCount())
        ]

        for key in which:
            self.learners[key] = \
                self.learners[key]._replace(results=None, stats=None)

            if key in statmodelkeys:
                row = statmodelkeys.index(key)
                for c in range(1, model.columnCount()):
                    item = model.item(row, c)
                    if item is not None:
                        item.setData(None, Qt.DisplayRole)
                        item.setData(None, Qt.ToolTipRole)

        self.apply_button.setEnabled(True)

    def apply(self):
        self.apply_button.setEnabled(False)
        self._update_header()
        # Update the view to display the model names
        self._update_stats_model()
        self._update_results()
        self._update_stats_model()
        self.commit()

    def commit(self):
        valid = [
            slot for slot in self.learners.values()
            if slot.results is not None and slot.results.success
        ]
        if valid:
            # Evaluation results
            combined = results_merge([slot.results.value for slot in valid])
            combined.learner_names = [
                learner_name(slot.learner) for slot in valid
            ]

            # Predictions & Probabilities
            predictions = combined.get_augmented_data(combined.learner_names)
        else:
            combined = None
            predictions = None
        self.send("Evaluation Results", combined)
        self.send("Predictions", predictions)

    def send_report(self):
        if not self.data or not self.learners:
            return
        if self.resampling == self.KFold:
            stratified = 'Stratified ' if self.cv_stratified else ''
            items = [
                ("Sampling type",
                 "{}{}-fold Cross validation".format(stratified, self.k_folds))
            ]
        elif self.resampling == self.LeaveOneOut:
            items = [("Sampling type", "Leave one out")]
        elif self.resampling == self.ShuffleSplit:
            stratified = 'Stratified ' if self.shuffle_stratified else ''
            items = [
                ("Sampling type",
                 "{}Shuffle split, {} random samples with {}% data ".format(
                     stratified, self.n_repeat, self.sample_p))
            ]
        elif self.resampling == self.TestOnTrain:
            items = [("Sampling type", "No sampling, test on training data")]
        elif self.resampling == self.TestOnTest:
            items = [("Sampling type", "No sampling, test on testing data")]
        else:
            items = []
        if self.data.domain.has_discrete_class:
            items += [("Target class", self.class_selection.strip("()"))]
        if items:
            self.report_items("Settings", items)
        self.report_table("Scores", self.view)
Exemple #46
0
class FlashingWindow(QDialog, Ui_Flashing):
    def __init__(self, parent):
        QDialog.__init__(self, parent)

        self.setupUi(self)

        self.tool_infos = {}
        self.firmware_infos = {}
        self.plugin_infos = {}
        self.brick_infos = []
        self.refresh_updates_pending = False

        self.parent = parent
        self.tab_widget.currentChanged.connect(self.tab_changed)
        self.button_serial_port_refresh.clicked.connect(self.refresh_serial_ports)
        self.combo_firmware.currentIndexChanged.connect(self.firmware_changed)
        self.button_firmware_save.clicked.connect(self.firmware_save_clicked)
        self.button_firmware_browse.clicked.connect(self.firmware_browse_clicked)
        self.button_uid_load.clicked.connect(self.uid_load_clicked)
        self.button_uid_save.clicked.connect(self.uid_save_clicked)
        self.combo_brick.currentIndexChanged.connect(self.brick_changed)
        self.combo_port.currentIndexChanged.connect(self.port_changed)
        self.combo_plugin.currentIndexChanged.connect(self.plugin_changed)
        self.button_plugin_save.clicked.connect(self.plugin_save_clicked)
        self.button_plugin_browse.clicked.connect(self.plugin_browse_clicked)

        infos.get_infos_changed_signal().connect(self.update_bricks)

        self.update_tool_label.hide()
        self.no_connection_label.hide()

        self.refresh_serial_ports()

        self.combo_firmware.addItem(CUSTOM)
        self.combo_firmware.setDisabled(True)
        self.firmware_changed(0)

        self.combo_plugin.addItem(CUSTOM)
        self.combo_plugin.setDisabled(True)
        self.plugin_changed(0)

        self.brick_changed(0)

        self.update_tree_view_model_labels = ['Name', 'UID', 'Installed', 'Latest']
        self.update_tree_view_model = QStandardItemModel(self)
        self.update_tree_view.setModel(self.update_tree_view_model)
        self.update_tree_view.setSortingEnabled(True)
        self.update_tree_view.header().setSortIndicator(0, Qt.AscendingOrder)

        self.update_button_refresh.clicked.connect(self.refresh_updates_clicked)
        self.update_button_bricklets.clicked.connect(self.auto_update_bricklets_clicked)

        self.update_ui_state()
        self.update_bricks()

    def refresh_latest_version_info(self, progress):
        self.tool_infos = {}
        self.firmware_infos = {}
        self.plugin_infos = {}

        self.combo_firmware.clear()
        self.combo_plugin.clear()
        self.combo_firmware.setDisabled(False)
        self.combo_plugin.setDisabled(False)

        progress.setLabelText('Discovering latest versions on tinkerforge.com')
        progress.setMaximum(0)
        progress.setValue(0)
        progress.show()

        okay = True

        try:
            response = urllib2.urlopen(LATEST_VERSIONS_URL, timeout=10)
            latest_versions_data = response.read()
            response.close()
        except urllib2.URLError:
            okay = False
            progress.cancel()
            self.combo_firmware.setDisabled(True)
            self.combo_plugin.setDisabled(True)
            self.popup_fail('Updates / Flashing', 'Latest version information on tinkerforge.com is not available (error code 1). Please report this to [email protected].\n\nFirmwares and plugins can be flashed from local files only.')

        if okay:
            def report_malformed(error_code):
                progress.cancel()
                self.combo_firmware.setDisabled(True)
                self.combo_plugin.setDisabled(True)
                self.popup_fail('Updates / Flashing', 'Latest version information on tinkerforge.com is malformed (error code {0}). Please report this to [email protected].\n\nFirmwares and plugins can be flashed from local files only.'.format(error_code))

            for line in latest_versions_data.split('\n'):
                line = line.strip()

                if len(line) < 1:
                    continue

                parts = line.split(':')

                if len(parts) != 3:
                    okay = False
                    report_malformed(2)
                    break

                latest_version_parts = parts[2].split('.')

                if len(latest_version_parts) != 3:
                    okay = False
                    report_malformed(3)
                    break

                try:
                    latest_version = int(latest_version_parts[0]), int(latest_version_parts[1]), int(latest_version_parts[2])
                except:
                    okay = False
                    report_malformed(4)
                    break

                if parts[0] == 'tools':
                    tool_info = infos.ToolInfo()
                    tool_info.firmware_version_latest = latest_version

                    self.tool_infos[parts[1]] = tool_info
                elif parts[0] == 'bricks':
                    self.refresh_firmware_info(parts[1], latest_version)
                elif parts[0] == 'bricklets':
                    self.refresh_plugin_info(parts[1], latest_version)

        if okay:
            # update combo_firmware
            if len(self.firmware_infos) > 0:
                self.combo_firmware.addItem(SELECT)
                self.combo_firmware.insertSeparator(self.combo_firmware.count())

            for firmware_info in sorted(self.firmware_infos.values(), key=lambda x: x.name):
                name = '{0} ({1}.{2}.{3})'.format(firmware_info.name, *firmware_info.firmware_version_latest)
                self.combo_firmware.addItem(name, firmware_info.url_part)

            if self.combo_firmware.count() > 0:
                self.combo_firmware.insertSeparator(self.combo_firmware.count())

            # update combo_plugin
            if len(self.plugin_infos) > 0:
                self.combo_plugin.addItem(SELECT)
                self.combo_plugin.insertSeparator(self.combo_plugin.count())

            for plugin_info in sorted(self.plugin_infos.values(), key=lambda x: x.name):
                name = '{0} ({1}.{2}.{3})'.format(plugin_info.name, *plugin_info.firmware_version_latest)
                self.combo_plugin.addItem(name, plugin_info.url_part)

            if self.combo_plugin.count() > 0:
                self.combo_plugin.insertSeparator(self.combo_plugin.count())

        self.combo_firmware.addItem(CUSTOM)
        self.firmware_changed(0)

        self.combo_plugin.addItem(CUSTOM)
        self.plugin_changed(0)

        self.update_ui_state()

    def refresh_firmware_info(self, url_part, latest_version):
        name = url_part

        if name in ['dc', 'imu']:
            name = name.upper()
        else:
            words = name.split('_')
            parts = []
            for word in words:
                parts.append(word[0].upper() + word[1:])
            name = ' '.join(parts)

        firmware_info = infos.FirmwareInfo()
        firmware_info.name = name
        firmware_info.url_part = url_part
        firmware_info.firmware_version_latest = latest_version

        self.firmware_infos[url_part] = firmware_info

    def refresh_plugin_info(self, url_part, latest_version):
        name = url_part

        if name in ['gps', 'ptc']:
            name = name.upper()
        elif name.startswith('lcd_'):
            name = name.replace('lcd_', 'LCD_')
            if url_part.startswith('lcd_20x4_'):
                name = name.replace('_v11', '_1.1').replace('_v12', '_1.2')
        elif name.startswith('io'):
            name = name.replace('io', 'IO-')
        elif name.endswith('_ir'):
            name = name.replace('_ir', '_IR')
        elif name.endswith('_us'):
            name = name.replace('_us', '_US')
        elif name.startswith('led_'):
            name = name.replace('led_', 'LED_')
        elif name.endswith('_v2'):
            name = name.replace('_v2', '_2.0')

        words = name.split('_')
        parts = []

        for word in words:
            parts.append(word[0].upper() + word[1:])

        name = ' '.join(parts)
        name = name.replace('Voltage Current', 'Voltage/Current')
        name = name.replace('Nfc Rfid', 'NFC/RFID')
        name = name.replace('0 20ma', '0-20mA')

        plugin_info = infos.PluginInfo()
        plugin_info.name = name
        plugin_info.url_part = url_part
        plugin_info.firmware_version_latest = latest_version

        self.plugin_infos[url_part] = plugin_info

    def update_bricks(self):
        self.brick_infos = []
        self.combo_brick.clear()
        items = {}

        for info in infos.get_brick_infos():
            items[info.get_combo_item()] = info

        for item in sorted(items.keys()):
            self.brick_infos.append(items[item])
            self.combo_brick.addItem(item)

        if self.combo_brick.count() == 0:
            self.combo_brick.addItem(NO_BRICK)

        self.update_ui_state()

    def create_progress_bar(self, title):
        progress = QProgressDialog(self)
        progress.setAutoClose(False)
        progress.setWindowTitle(title)
        progress.setCancelButton(None)
        progress.setWindowModality(Qt.WindowModal)
        return progress

    def popup_ok(self, title, message):
        QMessageBox.information(self, title, message, QMessageBox.Ok)

    def popup_fail(self, title, message):
        QMessageBox.critical(self, title, message, QMessageBox.Ok)

    def refresh_serial_ports(self):
        progress = self.create_progress_bar('Discovering')
        current_text = self.combo_serial_port.currentText()
        self.combo_serial_port.clear()

        try:
            progress.setLabelText('Discovering serial ports')
            progress.setMaximum(0)
            progress.setValue(0)
            progress.show()

            ports = get_serial_ports()
        except:
            progress.cancel()
            self.combo_serial_port.addItem(NO_BOOTLOADER)
            self.update_ui_state()
            self.popup_fail('Brick', 'Could not discover serial ports')
        else:
            preferred_index = None

            for port in ports:
                if preferred_index is None:
                    if 'ttyACM' in port[0] or \
                       'ttyUSB' in port[0] or \
                       'usbmodemfd' in port[0] or \
                       'AT91 USB to Serial Converter' in port[1] or \
                       'GPS Camera Detect' in port[1]:
                        preferred_index = self.combo_serial_port.count()

                if len(port[1]) > 0 and port[0] != port[1]:
                    self.combo_serial_port.addItem(u'{0} - {1}'.format(port[0], port[1]), port[0])
                else:
                    self.combo_serial_port.addItem(port[0], port[0])

            if self.combo_serial_port.count() == 0:
                self.combo_serial_port.addItem(NO_BOOTLOADER)
            elif preferred_index is not None:
                self.combo_serial_port.setCurrentIndex(preferred_index)
            else:
                index = self.combo_serial_port.findText(current_text)
                if index >= 0:
                    self.combo_serial_port.setCurrentIndex(index)

            self.update_ui_state()

        progress.cancel()

    def update_ui_state(self):
        is_firmware_select = self.combo_firmware.currentText() == SELECT
        is_firmware_custom = self.combo_firmware.currentText() == CUSTOM
        is_no_bootloader = self.combo_serial_port.currentText() == NO_BOOTLOADER
        has_bricklet_ports = self.combo_port.count() > 0
        self.combo_serial_port.setEnabled(not is_no_bootloader)
        self.combo_port.setEnabled(has_bricklet_ports)
        self.combo_plugin.setEnabled(has_bricklet_ports and self.combo_plugin.count() > 1)
        self.button_firmware_save.setEnabled(not is_firmware_select and not is_no_bootloader)
        self.edit_custom_firmware.setEnabled(is_firmware_custom)
        self.button_firmware_browse.setEnabled(is_firmware_custom)
        self.edit_uid.setEnabled(has_bricklet_ports)
        self.button_uid_load.setEnabled(has_bricklet_ports)
        self.button_uid_save.setEnabled(has_bricklet_ports)

        is_plugin_select = self.combo_plugin.currentText() == SELECT
        is_plugin_custom = self.combo_plugin.currentText() == CUSTOM
        is_no_brick = self.combo_brick.currentText() == NO_BRICK
        self.combo_brick.setEnabled(not is_no_brick)
        self.button_plugin_save.setEnabled(not is_plugin_select and not is_no_brick)
        self.edit_custom_plugin.setEnabled(is_plugin_custom)
        self.button_plugin_browse.setEnabled(is_plugin_custom)

        self.tab_widget.setTabEnabled(2, len(self.brick_infos) > 0)

    def firmware_changed(self, index):
        self.update_ui_state()

    def firmware_browse_clicked(self):
        if len(self.edit_custom_firmware.text()) > 0:
            last_dir = os.path.dirname(os.path.realpath(self.edit_custom_firmware.text()))
        else:
            last_dir = get_home_path()

        filename = get_open_file_name(get_main_window(), 'Open Firmware', last_dir, '*.bin')

        if len(filename) > 0:
            self.edit_custom_firmware.setText(filename)

    def firmware_save_clicked(self):
        port_name = self.combo_serial_port.itemData(self.combo_serial_port.currentIndex())

        try:
            samba = SAMBA(port_name)
        except SAMBAException as e:
            self.refresh_serial_ports()
            self.popup_fail('Brick', 'Could not connect to Brick: {0}'.format(str(e)))
            return
        except SerialException as e:
            self.refresh_serial_ports()
            self.popup_fail('Brick', str(e)[0].upper() + str(e)[1:])
            return
        except:
            self.refresh_serial_ports()
            self.popup_fail('Brick', 'Could not connect to Brick')
            return

        progress = ProgressWrapper(self.create_progress_bar('Flashing'))
        samba.progress = progress
        current_text = self.combo_firmware.currentText()

        # Get firmware
        name = None
        version = None

        if current_text == SELECT:
            return
        elif current_text == CUSTOM:
            firmware_file_name = self.edit_custom_firmware.text()

            try:
                with open(firmware_file_name, 'rb') as f:
                    firmware = f.read()
            except IOError:
                progress.cancel()
                self.popup_fail('Brick', 'Could not read firmware file')
                return
        else:
            url_part = self.combo_firmware.itemData(self.combo_firmware.currentIndex())
            name = self.firmware_infos[url_part].name
            version = self.firmware_infos[url_part].firmware_version_latest

            progress.reset('Downloading {0} Brick firmware {1}.{2}.{3}'.format(name, *version), 0)

            response = None

            try:
                response = urllib2.urlopen(FIRMWARE_URL + 'bricks/{0}/brick_{0}_firmware_{1}_{2}_{3}.bin'.format(url_part, *version), timeout=10)
            except urllib2.URLError:
                pass

            beta = 5

            while response is None and beta > 0:
                try:
                    response = urllib2.urlopen(FIRMWARE_URL + 'bricks/{0}/brick_{0}_firmware_{2}_{3}_{4}_beta{1}.bin'.format(url_part, beta, *version), timeout=10)
                except urllib2.URLError:
                    beta -= 1

            if response is None:
                progress.cancel()
                self.popup_fail('Brick', 'Could not download {0} Brick firmware {1}.{2}.{3}'.format(name, *version))
                return

            try:
                length = int(response.headers['Content-Length'])
                progress.setMaximum(length)
                progress.update(0)
                QApplication.processEvents()
                firmware = ''
                chunk = response.read(1024)

                while len(chunk) > 0:
                    firmware += chunk
                    progress.update(len(firmware))
                    chunk = response.read(1024)

                response.close()
            except urllib2.URLError:
                progress.cancel()
                self.popup_fail('Brick', 'Could not download {0} Brick firmware {1}.{2}.{3}'.format(name, *version))
                return

        # Get IMU UID
        imu_uid = None
        imu_calibration = None
        lock_imu_calibration_pages = False

        if name == 'IMU':
            # IMU 1.0.9 and earlier have a bug in their flash locking that makes
            # them unlook the wrong pages. Therefore, the calibration pages
            # must not be locked for this versions
            if version[1] > 0 or (version[1] == 0 and version[2] > 9):
                lock_imu_calibration_pages = True

            try:
                imu_uid = base58encode(uid64_to_uid32(samba.read_uid64()))
            except SerialException as e:
                progress.cancel()
                self.popup_fail('Brick', 'Could read UID of IMU Brick: {0}'.format(str(e)))
                return
            except:
                progress.cancel()
                self.popup_fail('Brick', 'Could read UID of IMU Brick')
                return

            result = QMessageBox.question(self, 'IMU Brick',
                                          'Restore factory calibration for IMU Brick [{0}] from tinkerforge.com?'.format(imu_uid),
                                          QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes)

            # Download IMU calibration
            if result == QMessageBox.Yes:
                progress.reset('Downloading factory calibration for IMU Brick', 0)

                try:
                    imu_calibration_text = ''
                    response = urllib2.urlopen(IMU_CALIBRATION_URL + '{0}.txt'.format(imu_uid), timeout=10)
                    chunk = response.read(1024)

                    while len(chunk) > 0:
                        imu_calibration_text += chunk
                        chunk = response.read(1024)

                    response.close()
                except urllib2.HTTPError as e:
                    if e.code == 404:
                        imu_calibration_text = None
                        self.popup_ok('IMU Brick', 'No factory calibration for IMU Brick [{0}] available'.format(imu_uid))
                    else:
                        progress.cancel()
                        self.popup_fail('IMU Brick', 'Could not download factory calibration for IMU Brick [{0}]'.format(imu_uid))
                        return
                except urllib2.URLError:
                    progress.cancel()
                    self.popup_fail('IMU Brick', 'Could not download factory calibration for IMU Brick [{0}]'.format(imu_uid))
                    return

                if imu_calibration_text is not None:
                    if len(imu_calibration_text) == 0:
                        progress.cancel()
                        self.popup_fail('IMU Brick', 'Could not download factory calibration for IMU Brick [{0}]'.format(imu_uid))
                        return

                    try:
                        imu_calibration_matrix = parse_imu_calibration(imu_calibration_text)

                        # Ensure proper temperature relation
                        if imu_calibration_matrix[5][1][7] <= imu_calibration_matrix[5][1][3]:
                            imu_calibration_matrix[5][1][7] = imu_calibration_matrix[5][1][3] + 1

                        imu_calibration_array = imu_calibration_matrix[0][1][:6] + \
                                                imu_calibration_matrix[1][1][:3] + \
                                                imu_calibration_matrix[2][1][:6] + \
                                                imu_calibration_matrix[3][1][:3] + \
                                                imu_calibration_matrix[4][1][:6] + \
                                                imu_calibration_matrix[5][1][:8]

                        imu_calibration = struct.pack('<32h', *imu_calibration_array)
                    except:
                        progress.cancel()
                        self.popup_fail('IMU Brick', 'Could not parse factory calibration for IMU Brick [{0}]'.format(imu_uid))
                        return

        # Flash firmware
        def report_result(reboot_okay):
            if current_text == CUSTOM:
                if reboot_okay:
                    message = 'Successfully restarted Brick!'
                else:
                    message = 'Manual restart of Brick required!'
            else:
                if reboot_okay:
                    message = 'Successfully restarted {0} Brick!'.format(name)
                else:
                    message = 'Manual restart of {0} Brick required!'.format(name)

            if current_text == CUSTOM:
                self.popup_ok('Brick', 'Successfully flashed firmware.\n' + message)
            elif imu_calibration is not None:
                self.popup_ok('Brick', 'Successfully flashed {0} Brick firmware {1}.{2}.{3}.\n'.format(name, *version) +
                                       'Successfully restored factory calibration.\n' + message)
            else:
                self.popup_ok('Brick', 'Successfully flashed {0} Brick firmware {1}.{2}.{3}.\n'.format(name, *version) +
                                       message)

        try:
            samba.flash(firmware, imu_calibration, lock_imu_calibration_pages)
            # close serial device before showing dialog, otherwise exchanging
            # the brick while the dialog is open will force it to show up as ttyACM1
            samba = None
            progress.cancel()
            report_result(True)
        except SAMBARebootError as e:
            samba = None
            progress.cancel()
            self.refresh_serial_ports()
            report_result(False)
        except SAMBAException as e:
            samba = None
            progress.cancel()
            self.refresh_serial_ports()
            self.popup_fail('Brick', 'Could not flash Brick: {0}'.format(str(e)))
        except SerialException as e:
            samba = None
            progress.cancel()
            self.refresh_serial_ports()
            self.popup_fail('Brick', 'Could not flash Brick: {0}'.format(str(e)))
        except:
            samba = None
            progress.cancel()
            self.refresh_serial_ports()
            self.popup_fail('Brick', 'Could not flash Brick')

    def uid_save_clicked(self):
        device, port = self.current_device_and_port()
        uid = self.edit_uid.text()

        if len(uid) == 0:
            self.popup_fail('Bricklet', 'UID cannot be empty')
            return

        for c in uid:
            if c not in BASE58:
                self.popup_fail('Bricklet', "UID cannot contain '{0}'".format(c))
                return

        try:
            if base58decode(uid) > 0xFFFFFFFF:
                self.popup_fail('Bricklet', 'UID is too long')
                return
        except:
            self.popup_fail('Bricklet', 'UID is invalid')
            return

        try:
            self.parent.ipcon.write_bricklet_uid(device, port, uid)
        except Error as e:
            self.popup_fail('Bricklet', 'Could not write UID: ' + error_to_name(e))
            return

        try:
            uid_read = self.parent.ipcon.read_bricklet_uid(device, port)
        except Error as e:
            self.popup_fail('Bricklet', 'Could not read written UID: ' + error_to_name(e))
            return

        if uid == uid_read:
            self.popup_ok('Bricklet', 'Successfully wrote UID.\nNew UID will be used after reset of the connected Brick.')
        else:
            self.popup_fail('Bricklet', 'Could not write UID: Verification failed')

    def uid_load_clicked(self):
        device, port = self.current_device_and_port()
        try:
            uid = self.parent.ipcon.read_bricklet_uid(device, port)
        except Error as e:
            self.edit_uid.setText('')
            self.popup_fail('Bricklet', 'Could not read UID: ' + error_to_name(e))
            return

        self.edit_uid.setText(uid)

    def brick_changed(self, index):
        self.combo_port.clear()

        if index < 0 or len(self.brick_infos) == 0:
            self.combo_port.addItems(['A', 'B', 'C', 'D'])
            return

        brick_info = self.brick_infos[index]

        for key in sorted(brick_info.bricklets.keys()):
            bricklet_info = brick_info.bricklets[key]

            if bricklet_info is None:
                self.combo_port.addItem(key.upper())
            else:
                name = '{0}: {1}'.format(key.upper(), bricklet_info.get_combo_item())
                self.combo_port.addItem(name, bricklet_info.url_part)

        self.update_ui_state()

    def port_changed(self, index):
        self.edit_uid.setText('')

        if index < 0:
            self.combo_plugin.setCurrentIndex(0)
            return

        url_part = self.combo_port.itemData(index)

        if url_part == None or len(url_part) == 0:
            self.combo_plugin.setCurrentIndex(0)
            return

        i = self.combo_plugin.findData(url_part)

        if i < 0:
            self.combo_plugin.setCurrentIndex(0)
        else:
            self.combo_plugin.setCurrentIndex(i)

        b = self.combo_brick.currentIndex()
        p = self.combo_port.currentIndex()

        if b < 0 or p < 0:
            return

        self.edit_uid.setText(self.brick_infos[b].bricklets[('a', 'b', 'c', 'd')[p]].uid)

    def plugin_changed(self, index):
        self.update_ui_state()

    def download_bricklet_plugin(self, progress, url_part, name, version, popup=False):
        progress.setLabelText('Downloading {0} Bricklet plugin {1}.{2}.{3}'.format(name, *version))
        progress.setMaximum(0)
        progress.show()

        response = None

        try:
            response = urllib2.urlopen(FIRMWARE_URL + 'bricklets/{0}/bricklet_{0}_firmware_{1}_{2}_{3}.bin'.format(url_part, *version), timeout=10)
        except urllib2.URLError:
            pass

        beta = 5

        while response is None and beta > 0:
            try:
                response = urllib2.urlopen(FIRMWARE_URL + 'bricklets/{0}/bricklet_{0}_firmware_{2}_{3}_{4}_beta{1}.bin'.format(url_part, beta, *version), timeout=10)
            except urllib2.URLError:
                beta -= 1

        if response is None:
            progress.cancel()
            if popup:
                self.popup_fail('Bricklet', 'Could not download {0} Bricklet plugin {1}.{2}.{3}'.format(name, *version))
            return None

        try:
            length = int(response.headers['Content-Length'])
            progress.setMaximum(length)
            progress.setValue(0)
            QApplication.processEvents()
            plugin = []
            chunk = response.read(256)

            while len(chunk) > 0:
                plugin += map(ord, chunk) # Convert plugin to list of bytes
                progress.setValue(len(plugin))
                chunk = response.read(256)

            response.close()
        except urllib2.URLError:
            progress.cancel()
            if popup:
                self.popup_fail('Bricklet', 'Could not download {0} Bricklet plugin {1}.{2}.{3}'.format(name, *version))
            return None

        return plugin

    def write_bricklet_plugin(self, plugin, device, port, name, progress, popup=True):
        # Write
        progress.setLabelText('Writing plugin: ' + name)
        progress.setMaximum(0)
        progress.setValue(0)
        progress.show()

        plugin_chunks = []
        offset = 0

        while offset < len(plugin):
            chunk = plugin[offset:offset + IPConnection.PLUGIN_CHUNK_SIZE]

            if len(chunk) < IPConnection.PLUGIN_CHUNK_SIZE:
                chunk += [0] * (IPConnection.PLUGIN_CHUNK_SIZE - len(chunk))

            plugin_chunks.append(chunk)
            offset += IPConnection.PLUGIN_CHUNK_SIZE

        progress.setMaximum(len(plugin_chunks))

        position = 0

        for chunk in plugin_chunks:
            try:
                self.parent.ipcon.write_bricklet_plugin(device, port, position, chunk)
            except Error as e:
                progress.cancel()
                if popup:
                    self.popup_fail('Bricklet', 'Could not write Bricklet plugin: ' + error_to_name(e))
                return False

            position += 1
            progress.setValue(position)

            time.sleep(0.015)
            QApplication.processEvents()

        time.sleep(0.1)

        # Verify
        progress.setLabelText('Verifying written plugin: ' + name)
        progress.setMaximum(len(plugin_chunks))
        progress.setValue(0)
        progress.show()

        time.sleep(0.1)
        position = 0

        for chunk in plugin_chunks:
            try:
                read_chunk = list(self.parent.ipcon.read_bricklet_plugin(device, port, position))
            except Error as e:
                progress.cancel()
                if popup:
                    self.popup_fail('Bricklet', 'Could not read Bricklet plugin back for verification: ' + error_to_name(e))
                return False

            if read_chunk != chunk:
                progress.cancel()
                if popup:
                    self.popup_fail('Bricklet', 'Could not flash Bricklet plugin: Verification error')
                return False

            position += 1
            progress.setValue(position)

            time.sleep(0.015)
            QApplication.processEvents()

        return True

    def plugin_save_clicked(self):
        progress = self.create_progress_bar('Flashing')
        current_text = self.combo_plugin.currentText()

        # Get plugin
        if current_text == SELECT:
            return
        elif current_text == CUSTOM:
            plugin_file_name = self.edit_custom_plugin.text()

            try:
                with open(plugin_file_name, 'rb') as f:
                    plugin = map(ord, f.read()) # Convert plugin to list of bytes
            except IOError:
                progress.cancel()
                self.popup_fail('Bricklet', 'Could not read plugin file')
                return
        else:
            url_part = self.combo_plugin.itemData(self.combo_plugin.currentIndex())
            name = self.plugin_infos[url_part].name
            version = self.plugin_infos[url_part].firmware_version_latest
            plugin = self.download_bricklet_plugin(progress, url_part, name, version)

            if not plugin:
                return

        # Flash plugin
        device, port = self.current_device_and_port()

        if current_text == CUSTOM:
            if not self.write_bricklet_plugin(plugin, device, port, os.path.split(plugin_file_name)[-1], progress):
                return
        else:
            if not self.write_bricklet_plugin(plugin, device, port, name, progress):
                return

        progress.cancel()

        if current_text == CUSTOM:
            self.popup_ok('Bricklet', 'Successfully flashed plugin.\nNew plugin will be used after reset of the connected Brick.')
        else:
            self.popup_ok('Bricklet', 'Successfully flashed {0} Bricklet plugin {1}.{2}.{3}.\nNew plugin will be used after reset of the connected Brick.'.format(name, *version))

    def current_device_and_port(self):
        port_names = ['a', 'b', 'c', 'd']

        return (self.current_device(),
                port_names[self.combo_port.currentIndex()])

    def current_device(self):
        try:
            return self.brick_infos[self.combo_brick.currentIndex()].plugin.device
        except:
            return None

    def plugin_browse_clicked(self):
        last_dir = get_home_path()

        if len(self.edit_custom_plugin.text()) > 0:
            last_dir = os.path.dirname(os.path.realpath(self.edit_custom_plugin.text()))

        filename = get_open_file_name(get_main_window(), 'Open Plugin', last_dir, '*.bin')

        if len(filename) > 0:
            self.edit_custom_plugin.setText(filename)

    def auto_update_bricklets_clicked(self):
        def brick_for_bricklet(bricklet):
            for device_info in infos.get_brick_infos():
                if bricklet.position in device_info.bricklets and \
                   device_info.bricklets[bricklet.position] == bricklet:
                    return device_info

        progress = self.create_progress_bar('Auto-Updating Bricklets')

        bricks_to_reset = set()

        for device_info in infos.get_device_infos():
            if device_info.type == 'bricklet':
                if device_info.protocol_version == 2 and device_info.firmware_version_installed < device_info.firmware_version_latest:
                    plugin = self.download_bricklet_plugin(progress, device_info.url_part, device_info.name, device_info.firmware_version_latest)

                    if not plugin:
                        progress.cancel()
                        self.refresh_updates_clicked()
                        return

                    brick = brick_for_bricklet(device_info)
                    if self.write_bricklet_plugin(plugin, brick.plugin.device, device_info.position, device_info.name, progress):
                        bricks_to_reset.add(brick)
                    else:
                        progress.cancel()
                        self.refresh_updates_clicked()
                        return
            elif device_info.type == 'brick':
                for port in device_info.bricklets:
                    if not device_info.bricklets[port]:
                        continue

                    if device_info.bricklets[port].protocol_version == 1 and \
                       device_info.bricklets[port].firmware_version_installed < device_info.bricklets[port].firmware_version_latest:
                        plugin = self.download_bricklet_plugin(progress, device_info.bricklets[port].url_part,
                                                               device_info.bricklets[port].name,
                                                               device_info.bricklets[port].firmware_version_latest)

                        if not plugin:
                            progress.cancel()
                            self.refresh_updates_clicked()
                            return

                        brick = brick_for_bricklet(device_info.bricklets[port])
                        if self.write_bricklet_plugin(plugin, brick.plugin.device, port, device_info.bricklets[port].name, progress):
                            bricks_to_reset.add(brick)
                        else:
                            progress.cancel()
                            self.refresh_updates_clicked()
                            return

        for brick in bricks_to_reset:
            try:
                brick.plugin.device.reset()
            except:
                pass

        progress.setLabelText('Waiting for Bricks to reset')
        progress.setMaximum(400)
        progress.setValue(0)

        for i in range(400):
            time.sleep(0.03)
            progress.setValue(i)

        progress.cancel()

    def tab_changed(self, i):
        if i == 0 and self.refresh_updates_pending:
            self.refresh_updates_clicked()
        elif i == 2:
            self.brick_changed(self.combo_brick.currentIndex())
            self.port_changed(self.combo_port.currentIndex())

    def refresh_updates_clicked(self):
        if self.tab_widget.currentIndex() != 0:
            self.refresh_updates_pending = True
            return

        self.update_button_refresh.setDisabled(True)

        self.refresh_updates_pending = False

        url_part_proto1_map = {
            # 'name': 'url_part'
            'Ambient Light Bricklet': 'ambient_light',
            'Analog In Bricklet': 'analog_in',
            'Analog Out Bricklet': 'analog_out',
            'Barometer Bricklet': 'barometer',
            'Current12 Bricklet': 'current12',
            'Current25 Bricklet': 'current25',
            'Distance IR Bricklet': 'distance_ir',
            'Dual Relay Bricklet': 'dual_relay',
            'GPS Bricklet': 'gps',
            'Humidity Bricklet': 'humidity',
            'Industrial Digital In 4 Bricklet': 'industrial_digital_in_4',
            'Industrial Digital Out 4 Bricklet': 'industrial_digital_out_4',
            'Industrial Quad Relay Bricklet': 'industrial_quad_relay',
            'IO-16 Bricklet': 'io16',
            'IO-4 Bricklet': 'io4',
            'Joystick Bricklet': 'joystick',
            'LCD 16x2 Bricklet': 'lcd_16x2',
            'LCD 20x4 Bricklet': 'lcd_20x4_v11',
            'Linear Poti Bricklet': 'linear_poti',
            'Piezo Buzzer Bricklet': 'piezo_buzzer',
            'Rotary Poti Bricklet': 'rotary_poti',
            'Temperature Bricklet': 'temperature',
            'Temperature-IR Bricklet': 'temperature_ir',
            'Voltage Bricklet': 'voltage',
            'Voltage/Current Bricklet': 'voltage_current',
        }

        progress = self.create_progress_bar('Discovering')
        okay = True

        try:
            urllib2.urlopen(FIRMWARE_URL, timeout=10).read()
            self.no_connection_label.hide()
        except urllib2.URLError:
            okay = False
            progress.cancel()
            self.no_connection_label.show()
            return

        if okay:
            self.refresh_latest_version_info(progress)

        def get_color_for_device(device):
            if device.firmware_version_installed >= device.firmware_version_latest:
                return None, False

            if device.firmware_version_installed[0] <= 1:
                return QBrush(Qt.red), True

            return QBrush(QColor(255, 160, 55)), True

        try:
            infos.get_info(infos.UID_BRICKV).firmware_version_latest = self.tool_infos['brickv'].firmware_version_latest
        except:
            infos.get_info(infos.UID_BRICKV).firmware_version_latest = (0, 0, 0)

        for device_info in infos.get_device_infos():
            if device_info.type == 'brick':
                try:
                    device_info.firmware_version_latest = self.firmware_infos[device_info.url_part].firmware_version_latest
                except:
                    device_info.firmware_version_latest = (0, 0, 0)
            elif device_info.type == 'bricklet':
                try:
                    device_info.firmware_version_latest = self.plugin_infos[device_info.url_part].firmware_version_latest
                except:
                    device_info.firmware_version_latest = (0, 0, 0)

        progress.cancel()

        self.update_tree_view_model.clear()
        self.update_tree_view_model.setHorizontalHeaderLabels(self.update_tree_view_model_labels)

        is_update = False
        protocol1_errors = set()
        items = []

        for device_info in infos.get_infos():
            if device_info.type == 'brick':
                parent = [QStandardItem(device_info.name),
                          QStandardItem(device_info.uid),
                          QStandardItem(get_version_string(device_info.firmware_version_installed)),
                          QStandardItem(get_version_string(device_info.firmware_version_latest))]

                color, update = get_color_for_device(device_info)
                if update:
                    is_update = True
                for item in parent:
                    item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    item.setData(color, Qt.BackgroundRole)
                parent[0].setData(device_info.uid, Qt.UserRole)
                items.append(parent)

                for port in device_info.bricklets:
                    if not device_info.bricklets[port] or device_info.bricklets[port].protocol_version == 1:
                        try:
                            protv, fw, name = device_info.plugin.device.get_protocol1_bricklet_name(port)
                        except:
                            protocol1_errors.add(device_info.uid)
                            child = [QStandardItem(port.upper() + ': Protocol 1.0 Bricklet with Error'),
                                     QStandardItem(''),
                                     QStandardItem(''),
                                     QStandardItem('')]

                            for item in child:
                                item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                                item.setData(QBrush(Qt.magenta), Qt.BackgroundRole)
                            parent[0].appendRow(child)
                            continue

                        if protv == 1:
                            # Hack for LCD 20x4 Bricklet (name is not set early enough in firmware)
                            if fw == (1, 1, 1) and name == '':
                                name = 'LCD 20x4 Bricklet'
                            bricklet_info = infos.BrickletInfo()
                            bricklet_info.protocol_version = 1
                            bricklet_info.name = name
                            bricklet_info.position = port
                            bricklet_info.firmware_version_installed = tuple(fw)

                            device_info.bricklets[port] = bricklet_info
                            for key in url_part_proto1_map:
                                if key in device_info.bricklets[port].name:
                                    bricklet_info.url_part = url_part_proto1_map[key]
                                    break

                            try:
                                bricklet_info.firmware_version_latest = self.plugin_infos[bricklet_info.url_part].firmware_version_latest
                            except KeyError:
                                pass

                    if device_info.bricklets[port]:
                        child = [QStandardItem(port.upper() + ': ' + device_info.bricklets[port].name),
                                 QStandardItem(device_info.bricklets[port].uid),
                                 QStandardItem(get_version_string(device_info.bricklets[port].firmware_version_installed)),
                                 QStandardItem(get_version_string(device_info.bricklets[port].firmware_version_latest))]

                        color, update = get_color_for_device(device_info.bricklets[port])
                        if update:
                            is_update = True
                        for item in child:
                            item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                            item.setData(color, Qt.BackgroundRole)
                        parent[0].appendRow(child)

            elif device_info.type == 'tool' and 'Brick Viewer' in device_info.name:
                parent = [QStandardItem(device_info.name),
                          QStandardItem(''),
                          QStandardItem(get_version_string(device_info.firmware_version_installed)),
                          QStandardItem(get_version_string(device_info.firmware_version_latest))]

                color, update = get_color_for_device(device_info)
                if update:
                    self.update_tool_label.show()
                else:
                    self.update_tool_label.hide()

                for item in parent:
                    item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                    item.setData(color, Qt.BackgroundRole)
                items.append(parent)

        t = 0
        if len(protocol1_errors) > 0:
            # if there were protocol1 errors give the enumerate callback a
            # chance to update the infos to have correct information to filter
            # out false-positive protocol1 errors that were detected due to
            # fast USB unplug
            t = 200
        QTimer.singleShot(t, lambda: self.refresh_updates_clicked_second_step(is_update, items, protocol1_errors))

    def refresh_updates_clicked_second_step(self, is_update, items, protocol1_errors):
        protocol1_error_still_there = False

        # filter out false-positive protocol1 errors
        for device_uid in protocol1_errors:
            if infos.get_info(device_uid) != None:
                protocol1_error_still_there = True
                continue

            for i in range(len(items)):
                if items[i][0].data(Qt.UserRole) == device_uid:
                    del items[i]
                    break

        for item in items:
            self.update_tree_view_model.appendRow(item)

        self.update_tree_view.expandAll()
        self.update_tree_view.setColumnWidth(0, 260)
        self.update_tree_view.setColumnWidth(1, 75)
        self.update_tree_view.setColumnWidth(2, 75)
        self.update_tree_view.setColumnWidth(3, 75)
        self.update_tree_view.setSortingEnabled(True)
        self.update_tree_view.header().setSortIndicator(0, Qt.AscendingOrder)

        if is_update:
            self.update_button_bricklets.setEnabled(True)
        else:
            self.update_button_bricklets.setEnabled(False)

        self.brick_changed(self.combo_brick.currentIndex())

        self.update_button_refresh.setDisabled(False)

        if protocol1_error_still_there:
            message = """
There was an error during the auto-detection of Bricklets with Protocol 1.0 plugins. Those cannot be updated automatically, but you can update them manually:

- Disconnect the affected Bricklets from their Brick and restart the Brick without the Bricklets.
- Ensure that the Brick shows up correctly.
- Connect the Bricklet to the Brick again, while the Brick is already running.
- Select the "Bricklet" tab and update the plugin manually.
"""
            QMessageBox.critical(self, "Bricklet with Error", message, QMessageBox.Ok)
Exemple #47
0
def get_gds_model(progress=lambda val: None):
    """
    Initialize and return a GDS datasets model.

    :param progress: A progress callback.
    :rval tuple:
        A tuple of (QStandardItemModel, geo.GDSInfo, [geo.GDS])

    .. note::
        The returned QStandardItemModel's thread affinity is set to
        the GUI thread.

    """
    progress(1)
    info = geo.GDSInfo()
    search_keys = ["dataset_id", "title", "platform_organism", "description"]
    cache_dir = serverfiles.localpath(geo.DOMAIN)
    gds_link = "http://www.ncbi.nlm.nih.gov/sites/GDSbrowser?acc={0}"
    pm_link = "http://www.ncbi.nlm.nih.gov/pubmed/{0}"
    gds_list = []

    def is_cached(gds):
        return os.path.exists(os.path.join(cache_dir, gds["dataset_id"]) +
                              ".soft.gz")

    def item(displayvalue, item_values={}):
        item = QStandardItem()
        item.setData(displayvalue, Qt.DisplayRole)
        for role, value in item_values.items():
            item.setData(value, role)
        return item

    def gds_to_row(gds):
        #: Text for easier full search.
        search_text = " | ".join([gds.get(key, "").lower()
                                  for key in search_keys])
        row = [
            item(" " if is_cached(gds) else "",
                 {TextFilterRole: search_text}),
            item(gds["dataset_id"],
                 {LinkRole: gds_link.format(gds["dataset_id"])}),
            item(gds["title"]),
            item(gds["platform_organism"]),
            item(len(gds["samples"])),
            item(gds["feature_count"]),
            item(gds["gene_count"]),
            item(len(gds["subsets"])),
            item(gds.get("pubmed_id", ""),
                 {LinkRole: pm_link.format(gds["pubmed_id"])
                            if gds.get("pubmed_id")
                            else None})
        ]
        return row

    model = QStandardItemModel()
    model.setHorizontalHeaderLabels(
        ["", "ID", "Title", "Organism", "Samples", "Features",
         "Genes", "Subsets", "PubMedID"]
    )
    progress(20)
    for gds in info.values():
        model.appendRow(gds_to_row(gds))

        gds_list.append(gds)

    progress(50)

    if QThread.currentThread() is not QCoreApplication.instance().thread():
        model.moveToThread(QCoreApplication.instance().thread())
    return model, info, gds_list
Exemple #48
0
class OWTestLearners(widget.OWWidget):
    name = "Test Learners"
    description = ""
    icon = "icons/TestLearners1.svg"
    priority = 100

    inputs = [("Learner", Orange.classification.Learner,
               "set_learner", widget.Multiple),
              ("Data", Orange.data.Table, "set_train_data", widget.Default),
              ("Test Data", Orange.data.Table, "set_test_data")]

    outputs = [("Evaluation Results", testing.Results)]

    #: Resampling/testing types
    KFold, LeaveOneOut, Bootstrap, TestOnTrain, TestOnTest = 0, 1, 2, 3, 4

    #: Selected resampling type
    resampling = settings.Setting(0)
    #: Number of folds for K-fold cross validation
    k_folds = settings.Setting(10)
    #: Number of repeats for bootstrap sampling
    n_repeat = settings.Setting(10)
    #: Bootstrap sampling p
    sample_p = settings.Setting(75)

    def __init__(self, parent=None):
        super().__init__(parent)

        self.train_data = None
        self.test_data = None

        #: An Ordered dictionary with current inputs and their testing
        #: results.
        self.learners = OrderedDict()

        sbox = gui.widgetBox(self.controlArea, "Sampling")
        rbox = gui.radioButtons(
            sbox, self, "resampling", callback=self._param_changed
        )
        gui.appendRadioButton(rbox, "Cross validation")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox, self, "k_folds", 2, 50, label="Number of folds:",
                 callback=self.kfold_changed)
        gui.appendRadioButton(rbox, "Leave one out")
        gui.appendRadioButton(rbox, "Random sampling")
        ibox = gui.indentedBox(rbox)
        gui.spin(ibox, self, "n_repeat", 2, 50, label="Repeat train/test",
                 callback=self.bootstrap_changed)
        gui.widgetLabel(ibox, "Relative training set size:")
        gui.hSlider(ibox, self, "sample_p", minValue=1, maxValue=100,
                    ticks=20, vertical=False, labelFormat="%d %%",
                    callback=self.bootstrap_changed)

        gui.appendRadioButton(rbox, "Test on train data")
        gui.appendRadioButton(rbox, "Test on test data")

        rbox.layout().addSpacing(5)
        gui.button(rbox, self, "Apply", callback=self.apply)

        gui.rubber(self.controlArea)

        self.view = QTreeView(
            rootIsDecorated=False,
            uniformRowHeights=True,
            wordWrap=True,
            editTriggers=QTreeView.NoEditTriggers
        )
        header = self.view.header()
        header.setResizeMode(QHeaderView.ResizeToContents)
        header.setDefaultAlignment(Qt.AlignCenter)
        header.setStretchLastSection(False)

        self.result_model = QStandardItemModel()
        self.view.setModel(self.result_model)
        self.view.setItemDelegate(ItemDelegate())
        self._update_header()
        box = gui.widgetBox(self.mainArea, "Evaluation Results")
        box.layout().addWidget(self.view)

    def set_learner(self, learner, key):
        if key in self.learners and learner is None:
            del self.learners[key]
        else:
            self.learners[key] = Input(learner, None, ())
        self._update_stats_model()

    def set_train_data(self, data):
        self.error(0)
        if data is not None:
            if data.domain.class_var is None:
                self.error(0, "Train data input requires a class variable")
                data = None

        self.train_data = data
        self._update_header()
        self._invalidate()

    def set_test_data(self, data):
        self.error(1)
        if data is not None:
            if data.domain.class_var is None:
                self.error(1, "Test data input requires a class variable")
                data = None

        self.test_data = data
        if self.resampling == OWTestLearners.TestOnTest:
            self._invalidate()

    def handleNewSignals(self):
        self.update_results()
        self.commit()

    def kfold_changed(self):
        self.resampling = OWTestLearners.KFold
        self._param_changed()

    def bootstrap_changed(self):
        self.resampling = OWTestLearners.Bootstrap
        self._param_changed()

    def _param_changed(self):
        self._invalidate()

    def update_results(self):
        self.warning([1, 2])
        self.error(2)

        if self.train_data is None:
            return

        if self.resampling == OWTestLearners.TestOnTest:
            if self.test_data is None:
                self.warning(2, "Missing separate test data input")
                return

            elif self.test_data.domain.class_var != \
                    self.train_data.domain.class_var:
                self.error(2, ("Inconsistent class variable between test " +
                               "and train data sets"))
                return

        # items in need of an update
        items = [(key, input) for key, input in self.learners.items()
                 if input.results is None]
        learners = [input.learner for _, input in items]

        self.setStatusMessage("Running")
        if self.test_data is not None and \
                self.resampling != OWTestLearners.TestOnTest:
            self.warning(1, "Test data is present but unused. "
                            "Select 'Test on test data' to use it.")

        # TODO: Test each learner individually

        if self.resampling == OWTestLearners.KFold:
            results = testing.CrossValidation(
                self.train_data, learners, k=self.k_folds, store_data=True
            )
        elif self.resampling == OWTestLearners.LeaveOneOut:
            results = testing.LeaveOneOut(
                self.train_data, learners, store_data=True
            )
        elif self.resampling == OWTestLearners.Bootstrap:
            p = self.sample_p / 100.0
            results = testing.Bootstrap(
                self.train_data, learners, n_resamples=self.n_repeat, p=p,
                store_data=True
            )
        elif self.resampling == OWTestLearners.TestOnTrain:
            results = testing.TestOnTrainingData(
                self.train_data, learners, store_data=True
            )
        elif self.resampling == OWTestLearners.TestOnTest:
            if self.test_data is None:
                return
            results = testing.TestOnTestData(
                self.train_data, self.test_data, learners, store_data=True
            )
        else:
            assert False

        results = list(split_by_model(results))
        class_var = self.train_data.domain.class_var
        
        if is_discrete(class_var):
            test_stats = classification_stats
        else:
            test_stats = regression_stats
        
        self._update_header()
        
        stats = [test_stats(res) for res in results]
        for (key, input), res, stat in zip(items, results, stats):
            self.learners[key] = input._replace(results=res, stats=stat)

        self.setStatusMessage("")
        
        self._update_stats_model()

    def _update_header(self):
        headers = ["Method"]
        if self.train_data is not None:
            if is_discrete(self.train_data.domain.class_var):
                headers.extend(classification_stats.headers)
            else:
                headers.extend(regression_stats.headers)
        for i in reversed(range(len(headers),
                                self.result_model.columnCount())):
            self.result_model.takeColumn(i)

        self.result_model.setHorizontalHeaderLabels(headers)

    def _update_stats_model(self):
        model = self.view.model()

        for r in reversed(range(model.rowCount())):
            model.takeRow(r)

        for input in self.learners.values():
            name = learner_name(input.learner)
            row = []
            head = QStandardItem()
            head.setData(name, Qt.DisplayRole)
            row.append(head)
            for stat in input.stats:
                item = QStandardItem()
                item.setData(" {:.3f} ".format(stat[0]), Qt.DisplayRole)
                row.append(item)
            model.appendRow(row)

    def _invalidate(self, which=None):
        if which is None:
            which = self.learners.keys()

        all_keys = list(self.learners.keys())
        model = self.view.model()

        for key in which:
            self.learners[key] = \
                self.learners[key]._replace(results=None, stats=None)

            if key in self.learners:
                row = all_keys.index(key)
                for c in range(1, model.columnCount()):
                    item = model.item(row, c)
                    if item is not None:
                        item.setData(None, Qt.DisplayRole)

    def apply(self):
        self.update_results()
        self.commit()

    def commit(self):
        results = [val.results for val in self.learners.values()
                   if val.results is not None]
        if results:
            combined = results_merge(results)
            combined.learner_names = [learner_name(val.learner)
                                     for val in self.learners.values()]
        else:
            combined = None
        self.send("Evaluation Results", combined)
Exemple #49
0
class MainWindow(QMainWindow, Ui_MainWindow):
    qtcb_enumerate = pyqtSignal(str, str, 'char', type((0,)), type((0,)), int, int)
    qtcb_connected = pyqtSignal(int)
    qtcb_disconnected = pyqtSignal(int)

    def __init__(self, parent=None):
        QMainWindow.__init__(self, parent)
        self.setupUi(self)
        self.setWindowIcon(QIcon(os.path.join(get_program_path(), "brickv-icon.png")))
        signal.signal(signal.SIGINT, self.exit_brickv)
        signal.signal(signal.SIGTERM, self.exit_brickv)

        self.async_thread = async_start_thread(self)

        self.setWindowTitle("Brick Viewer " + config.BRICKV_VERSION)

        self.tree_view_model_labels = ['Name', 'UID', 'FW Version']
        self.tree_view_model = QStandardItemModel()
        self.tree_view.setModel(self.tree_view_model)
        self.tree_view.doubleClicked.connect(self.item_double_clicked)
        self.set_tree_view_defaults()

        # Remove dummy tab
        self.tab_widget.removeTab(1)
        self.last_tab = 0

        self.name = '<unknown>'
        self.uid = '<unknown>'
        self.version = (0, 0, 0)

        self.disconnect_times = []

        self.qtcb_enumerate.connect(self.cb_enumerate)
        self.qtcb_connected.connect(self.cb_connected)
        self.qtcb_disconnected.connect(self.cb_disconnected)

        self.ipcon = IPConnection()
        self.ipcon.set_auto_reauthenticate(False)
        self.ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE,
                                     self.qtcb_enumerate.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_CONNECTED,
                                     self.qtcb_connected.emit)
        self.ipcon.register_callback(IPConnection.CALLBACK_DISCONNECTED,
                                     self.qtcb_disconnected.emit)

        self.flashing_window = None
        self.advanced_window = None
        self.delayed_refresh_updates_timer = QTimer()
        self.delayed_refresh_updates_timer.timeout.connect(self.delayed_refresh_updates)
        self.delayed_refresh_updates_timer.setInterval(500)
        self.reset_view()
        self.button_advanced.setDisabled(True)

        self.tab_widget.currentChanged.connect(self.tab_changed)
        self.button_connect.pressed.connect(self.connect_pressed)
        self.button_flashing.pressed.connect(self.flashing_pressed)
        self.button_advanced.pressed.connect(self.advanced_pressed)
        self.plugin_manager = PluginManager()

        self.combo_host.addItem(config.get_host())
        self.combo_host.addItems(config.get_host_history(HOST_HISTORY_SIZE - 1))
        self.spinbox_port.setValue(config.get_port())

        self.last_host = self.combo_host.currentText()
        self.last_port = self.spinbox_port.value()

        self.checkbox_authentication.stateChanged.connect(self.authentication_state_changed)

        self.label_secret.hide()

        self.edit_secret.hide()
        self.edit_secret.setEchoMode(QLineEdit.Password)

        self.checkbox_secret_show.hide()
        self.checkbox_secret_show.stateChanged.connect(self.secret_show_state_changed)

        self.checkbox_remember_secret.hide()

        if config.get_use_authentication():
            self.checkbox_authentication.setCheckState(Qt.Checked)

        if config.get_remember_secret():
            self.edit_secret.setText(config.get_secret())
            self.checkbox_remember_secret.setCheckState(Qt.Checked)

        self.label_auto_reconnects.hide()
        self.auto_reconnects = 0

    def closeEvent(self, event):
        self.exit_brickv()

    def exit_brickv(self, signl=None, frme=None):
        try:
            uid = self.tab_widget.widget(self.last_tab)._uid
            infos.infos[uid].plugin.stop()
        except:
            pass

        host = str(self.combo_host.currentText())
        history = []

        for i in range(self.combo_host.count()):
            h = str(self.combo_host.itemText(i))

            if h != host and h not in history:
                history.append(h)

        config.set_host(host)
        config.set_host_history(history[:HOST_HISTORY_SIZE - 1])
        config.set_port(self.spinbox_port.value())
        config.set_use_authentication(self.checkbox_authentication.isChecked())

        remember_secret = self.checkbox_remember_secret.isChecked()

        config.set_remember_secret(remember_secret)

        if remember_secret:
            config.set_secret(str(self.edit_secret.text()))
        else:
            config.set_secret(config.DEFAULT_SECRET)

        self.reset_view()

        try:
            self.ipcon.disconnect()
        except:
            pass

        if signl != None and frme != None:
            print "Received SIGINT or SIGTERM, shutting down."
            sys.exit()

    def start(self):
        pass

    def stop(self):
        pass

    def destroy(self):
        pass

    def authentication_state_changed(self, state):
        visible = state == Qt.Checked

        self.label_secret.setVisible(visible)
        self.edit_secret.setVisible(visible)
        self.checkbox_secret_show.setVisible(visible)
        self.checkbox_remember_secret.setVisible(visible)

    def secret_show_state_changed(self, state):
        if state == Qt.Checked:
            self.edit_secret.setEchoMode(QLineEdit.Normal)
        else:
            self.edit_secret.setEchoMode(QLineEdit.Password)

    def tab_changed(self, i):
        try:
            uid = self.tab_widget.widget(i)._uid
            infos.infos[uid].plugin.start()
        except:
            pass

        try:
            uid = self.tab_widget.widget(self.last_tab)._uid
            infos.infos[uid].plugin.stop()
        except:
            pass

        self.last_tab = i

    def reset_view(self):
        self.tab_widget.setCurrentIndex(0)

        keys_to_remove = []
        for key in infos.infos:
            if infos.infos[key].type in ('brick', 'bricklet'):
                try:
                    infos.infos[key].plugin.stop()
                except:
                    pass

                try:
                    infos.infos[key].plugin.destroy()
                except:
                    pass
                keys_to_remove.append(key)

        for key in keys_to_remove:
            try:
                infos.infos.pop(key)
            except:
                pass

        for i in reversed(range(1, self.tab_widget.count())):
            self.tab_widget.removeTab(i)

        self.update_tree_view()

    def do_disconnect(self):
        self.auto_reconnects = 0
        self.label_auto_reconnects.hide()

        self.reset_view()
        async_next_session()

        try:
            self.ipcon.disconnect()
        except:
            pass

    def do_authenticate(self, is_auto_reconnect):
        if not self.checkbox_authentication.isChecked():
            return True

        try:
            secret = str(self.edit_secret.text()).encode('ascii')
        except:
            self.do_disconnect()

            QMessageBox.critical(self, 'Connection',
                                 'Authentication secret cannot contain non-ASCII characters.',
                                 QMessageBox.Ok)
            return False

        self.ipcon.set_auto_reconnect(False) # don't auto-reconnect on authentication error

        try:
            self.ipcon.authenticate(secret)
        except:
            self.do_disconnect()

            if is_auto_reconnect:
                extra = ' after auto-reconnect'
            else:
                extra = ''

            QMessageBox.critical(self, 'Connection',
                                 'Could not authenticate' + extra + '. Check secret and ensure ' +
                                 'authentication for Brick Daemon is enabled.',
                                 QMessageBox.Ok)
            return False

        self.ipcon.set_auto_reconnect(True)

        return True

    def flashing_pressed(self):
        first = False

        if self.flashing_window is None:
            first = True
            self.flashing_window = FlashingWindow(self)

        self.update_flashing_window()
        self.flashing_window.show()
        self.flashing_window.refresh_updates_pressed()

    def advanced_pressed(self):
        if self.advanced_window is None:
            self.advanced_window = AdvancedWindow(self)

        self.update_advanced_window()
        self.advanced_window.show()

    def connect_pressed(self):
        if self.ipcon.get_connection_state() == IPConnection.CONNECTION_STATE_DISCONNECTED:
            try:
                self.last_host = self.combo_host.currentText()
                self.last_port = self.spinbox_port.value()
                self.button_connect.setDisabled(True)
                self.button_connect.setText("Connecting ...")
                self.button_connect.repaint()
                QApplication.processEvents()
                self.ipcon.connect(self.last_host, self.last_port)
            except:
                self.button_connect.setDisabled(False)
                self.button_connect.setText("Connect")
                QMessageBox.critical(self, 'Connection',
                                     'Could not connect. Please check host, check ' +
                                     'port and ensure that Brick Daemon is running.')
        else:
            self.do_disconnect()

    def item_double_clicked(self, index):
        text = str(index.data().toString())
        i = self.tab_for_uid(text)
        if i > 0:
            self.tab_widget.setCurrentIndex(i)

    def connected_uid_pressed(self, connected_uid):
        i = self.tab_for_uid(connected_uid)
        if i > 0:
            self.tab_widget.setCurrentIndex(i)

    def create_plugin_container(self, plugin, connected_uid, position):
        container = QWidget()
        container._uid = plugin.uid
        layout = QVBoxLayout(container)
        info = QHBoxLayout()

        # uid
        info.addWidget(QLabel('UID:'))
        label = QLabel('{0}'.format(plugin.uid))
        label.setTextInteractionFlags(Qt.TextSelectableByMouse |
                                      Qt.TextSelectableByKeyboard)
        info.addWidget(label)

        info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # connected uid
        if connected_uid != '0':
            info.addWidget(QLabel('Connected to:'))
            button = QToolButton()
            button.setText(connected_uid)
            button.pressed.connect(lambda: self.connected_uid_pressed(connected_uid))
            info.addWidget(button)

            info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # position
        info.addWidget(QLabel('Position:'))
        info.addWidget(QLabel('{0}'.format(position.upper())))

        info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # firmware version
        info.addWidget(QLabel('FW Version:'))
        info.addWidget(QLabel('{0}'.format(plugin.version_str)))

        info.addSpacerItem(QSpacerItem(1, 1, QSizePolicy.Expanding))

        # timeouts
        info.addWidget(QLabel('Timeouts:'))
        label_timeouts = QLabel('0')
        info.addWidget(label_timeouts)

        layout.addLayout(info)

        if plugin.is_brick():
            button = QPushButton('Reset')
            if plugin.has_reset_device():
                button.clicked.connect(plugin.reset_device)
            else:
                button.setDisabled(True)
            info.addSpacerItem(QSpacerItem(40, 20, QSizePolicy.Expanding))
            info.addWidget(button)

        line = QFrame()
        line.setFrameShape(QFrame.HLine)
        line.setFrameShadow(QFrame.Sunken)

        plugin.label_timeouts = label_timeouts
        plugin.layout().setContentsMargins(0, 0, 0, 0)

        layout.addWidget(line)
        layout.addWidget(plugin)

        return container

    def tab_for_uid(self, uid):
        for i in range(1, self.tab_widget.count()):
            try:
                widget = self.tab_widget.widget(i)
                if widget._uid == uid:
                    return i
            except:
                pass

        return -1

    def cb_enumerate(self, uid, connected_uid, position,
                     hardware_version, firmware_version,
                     device_identifier, enumeration_type):
        if self.ipcon.get_connection_state() != IPConnection.CONNECTION_STATE_CONNECTED:
            # ignore enumerate callbacks that arrived after the connection got closed
            return

        if enumeration_type in [IPConnection.ENUMERATION_TYPE_AVAILABLE,
                                IPConnection.ENUMERATION_TYPE_CONNECTED]:
            if device_identifier == BrickMaster.DEVICE_IDENTIFIER:
                info = infos.BrickMasterInfo()
            elif position in ('a', 'b', 'c', 'd', 'A', 'B', 'C', 'D'):
                position = position.lower()
                info = infos.BrickletInfo()
            else:
                info = infos.BrickInfo()

            if uid in infos.infos:
                info = infos.infos[uid]
            else:
                infos.infos[uid] = info

            for device in infos.infos.values():
                if device.type == 'brick':
                    if info.type == 'bricklet':
                        if device.uid == connected_uid:
                            device.bricklets[position] = info
                if device.type == 'bricklet':
                    if info.type == 'brick':
                        if uid == device.connected_uid:
                            info.bricklets[device.position] = device

            info.uid = uid
            info.connected_uid = connected_uid
            info.position = position
            info.hardware_version = hardware_version
            info.firmware_version_installed = firmware_version
            info.device_identifier = device_identifier
            info.protocol_version = 2
            info.enumeration_type = enumeration_type

            for device in infos.infos.values():
                if device.type in ('brick', 'bricklet'):
                    if device.uid == uid and device.plugin != None:
                        return

            plugin = self.plugin_manager.get_plugin(device_identifier, self.ipcon,
                                                    uid, firmware_version)

            if plugin is not None:
                info.plugin = plugin
                if plugin.is_hardware_version_relevant(hardware_version):
                    info.name = '{0} {1}.{2}'.format(plugin.name,
                                                     hardware_version[0],
                                                     hardware_version[1])
                else:
                    info.name = plugin.name

                info.url_part = plugin.get_url_part()

                c = self.create_plugin_container(plugin, connected_uid, position)
                info.plugin_container = c
                self.tab_widget.addTab(c, info.name)
        elif enumeration_type == IPConnection.ENUMERATION_TYPE_DISCONNECTED:
            for device_info in infos.infos.values():
                if device_info.type in ('brick', 'bricklet'):
                    if device_info.uid == uid:
                        try:
                            self.tab_widget.setCurrentIndex(0)
                            if device_info.plugin:
                                try:
                                    device_info.plugin.stop()
                                except:
                                    pass

                                try:
                                    device_info.plugin.destroy()
                                except:
                                    pass

                            i = self.tab_for_uid(device_info.uid)
                            self.tab_widget.removeTab(i)
                        except:
                            pass

                if device_info.type == 'brick':
                    for port in device_info.bricklets:
                        if device_info.bricklets[port]:
                            if device_info.bricklets[port].uid == uid:
                                device_info.bricklets[port] = None

                try:
                    infos.infos.pop(uid)
                except:
                    pass

        self.update_tree_view()

    def cb_connected(self, connect_reason):
        self.disconnect_times = []

        self.update_ui_state()

        if connect_reason == IPConnection.CONNECT_REASON_REQUEST:
            self.auto_reconnects = 0
            self.label_auto_reconnects.hide()

            self.ipcon.set_auto_reconnect(True)

            index = self.combo_host.findText(self.last_host)
            if index >= 0:
                self.combo_host.removeItem(index)
            self.combo_host.insertItem(-1, self.last_host)
            self.combo_host.setCurrentIndex(0)

            while self.combo_host.count() > HOST_HISTORY_SIZE:
                self.combo_host.removeItem(self.combo_host.count() - 1)

            if not self.do_authenticate(False):
                return

            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()
        elif connect_reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT:
            self.auto_reconnects += 1
            self.label_auto_reconnects.setText('Auto-Reconnect Count: {0}'.format(self.auto_reconnects))
            self.label_auto_reconnects.show()

            if not self.do_authenticate(True):
                return

            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()
        else:
            try:
                self.ipcon.enumerate()
            except:
                self.update_ui_state()

    def cb_disconnected(self, disconnect_reason):
        if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST:
            self.auto_reconnects = 0
            self.label_auto_reconnects.hide()

        if disconnect_reason == IPConnection.DISCONNECT_REASON_REQUEST or not self.ipcon.get_auto_reconnect():
            self.update_ui_state()
        elif len(self.disconnect_times) >= 3 and self.disconnect_times[-3] < time.time() + 1:
            self.disconnect_times = []
            self.ipcon.set_auto_reconnect(False)
            self.update_ui_state()
            self.reset_view()

            QMessageBox.critical(self, 'Connection',
                                 'Stopped automatic reconnecting due to multiple connection errors in a row.',
                                 QMessageBox.Ok)
        else:
            self.disconnect_times.append(time.time())
            self.update_ui_state(IPConnection.CONNECTION_STATE_PENDING)

    def set_tree_view_defaults(self):
        self.tree_view_model.setHorizontalHeaderLabels(self.tree_view_model_labels)
        self.tree_view.expandAll()
        self.tree_view.setColumnWidth(0, 260)
        self.tree_view.setColumnWidth(1, 75)
        self.tree_view.setColumnWidth(2, 85)
        self.tree_view.setSortingEnabled(True)
        self.tree_view.header().setSortIndicator(0, Qt.AscendingOrder)

    def update_ui_state(self, connection_state=None):
        # FIXME: need to call processEvents() otherwise get_connection_state()
        #        might return the wrong value
        QApplication.processEvents()

        if connection_state is None:
            connection_state = self.ipcon.get_connection_state()

        self.button_connect.setDisabled(False)
        self.button_flashing.setDisabled(False)

        if connection_state == IPConnection.CONNECTION_STATE_DISCONNECTED:
            self.button_connect.setText('Connect')
            self.combo_host.setDisabled(False)
            self.spinbox_port.setDisabled(False)
            self.checkbox_authentication.setDisabled(False)
            self.edit_secret.setDisabled(False)
            self.button_advanced.setDisabled(True)
        elif connection_state == IPConnection.CONNECTION_STATE_CONNECTED:
            self.button_connect.setText("Disconnect")
            self.combo_host.setDisabled(True)
            self.spinbox_port.setDisabled(True)
            self.checkbox_authentication.setDisabled(True)
            self.edit_secret.setDisabled(True)
            self.update_advanced_window(False)
        elif connection_state == IPConnection.CONNECTION_STATE_PENDING:
            self.button_connect.setText('Abort Pending Automatic Reconnect')
            self.combo_host.setDisabled(True)
            self.spinbox_port.setDisabled(True)
            self.checkbox_authentication.setDisabled(True)
            self.edit_secret.setDisabled(True)
            self.button_advanced.setDisabled(True)
            self.button_flashing.setDisabled(True)

        enable = connection_state == IPConnection.CONNECTION_STATE_CONNECTED
        for i in range(1, self.tab_widget.count()):
            self.tab_widget.setTabEnabled(i, enable)

        QApplication.processEvents()

    def update_tree_view(self):
        self.tree_view_model.clear()

        for device_info in sorted(infos.infos.values(), cmp=lambda x, y: cmp(x.name, y.name)):
            if device_info.type == 'brick':
                parent = [QStandardItem(device_info.name),
                          QStandardItem(device_info.uid),
                          QStandardItem('.'.join(map(str, device_info.firmware_version_installed)))]
                for item in parent:
                    item.setFlags(item.flags() & ~Qt.ItemIsEditable)

                self.tree_view_model.appendRow(parent)
                for port in sorted(device_info.bricklets):
                    if device_info.bricklets[port] and device_info.bricklets[port].protocol_version == 2:
                        child = [QStandardItem(port.upper() + ': ' +device_info.bricklets[port].name),
                                 QStandardItem(device_info.bricklets[port].uid),
                                 QStandardItem('.'.join(map(str, device_info.bricklets[port].firmware_version_installed)))]
                        for item in child:
                            item.setFlags(item.flags() & ~Qt.ItemIsEditable)
                        parent[0].appendRow(child)

        self.set_tree_view_defaults()
        self.update_flashing_window()
        self.update_advanced_window()
        self.delayed_refresh_updates_timer.start()

    def update_flashing_window(self):
        if self.flashing_window is not None:
            self.flashing_window.update_bricks()

    def update_advanced_window(self, update_window=True):
        has_brick = False

        for info in infos.infos.values():
            if info.type == 'brick':
                has_brick = True

        self.button_advanced.setEnabled(has_brick)

        if self.advanced_window is not None and update_window:
            self.advanced_window.update_bricks()

    def delayed_refresh_updates(self):
        self.delayed_refresh_updates_timer.stop()

        if self.flashing_window is not None and self.flashing_window.isVisible():
            self.flashing_window.refresh_updates_pressed()
    class VizRank(OWWidget):
        name = "Rank projections (Scatter Plot)"

        def __init__(self, parent_widget):
            super().__init__()
            self.parent_widget = parent_widget
            self.want_control_area = False
            self.running = False
            self.progress = None
            self.k = 10

            self.projectionTable = QTableView()
            self.mainArea.layout().addWidget(self.projectionTable)
            self.projectionTable.setSelectionBehavior(QTableView.SelectRows)
            self.projectionTable.setSelectionMode(QTableView.SingleSelection)
            self.projectionTable.setSortingEnabled(True)
            self.projectionTableModel = QStandardItemModel(self)
            self.projectionTable.setModel(self.projectionTableModel)
            self.projectionTable.selectionModel().selectionChanged.connect(
                self.on_selection_changed)

            self.button = gui.button(self.mainArea, self, "Start evaluation",
                                     callback=self.toggle, default=True)
            self.resize(380, 512)
            self._initialize()

        def _initialize(self):
            self.running = False
            self.projectionTableModel.clear()
            self.projectionTableModel.setHorizontalHeaderLabels(
                ["Score", "Feature 1", "Feature 2"])
            self.projectionTable.setColumnWidth(0, 60)
            self.projectionTable.setColumnWidth(1, 120)
            self.projectionTable.setColumnWidth(2, 120)
            self.button.setText("Start evaluation")
            self.button.setEnabled(False)
            self.pause = False
            self.data = None
            self.attrs = []
            self.scores = []
            self.i, self.j = 0, 0
            if self.progress:
                self.progress.finish()
            self.progress = None


            self.information(0)
            if self.parent_widget.data:
                if not self.parent_widget.data.domain.class_var:
                    self.information(
                        0, "Data with a class variable is required.")
                    return
                if len(self.parent_widget.data.domain.attributes) < 2:
                    self.information(
                        0, 'At least 2 unique features are needed.')
                    return
                self.button.setEnabled(True)

        def on_selection_changed(self, selected, deselected):
            """Called when the ranks view selection changes."""
            a1 = selected.indexes()[1].data()
            a2 = selected.indexes()[2].data()
            self.parent_widget.update_attr(attributes=(a1, a2))

        def toggle(self):
            self.running ^= 1
            if self.running:
                self.button.setText("Pause")
                self.run()
            else:
                self.button.setText("Continue")
                self.button.setEnabled(False)

        def run(self):
            graph = self.parent_widget.graph
            y_full = self.parent_widget.data.Y
            norm = 1 / (len(y_full) * self.k)
            if not self.attrs:
                self.attrs = self.score_heuristic()
            if not self.progress:
                self.progress = gui.ProgressBar(
                    self, len(self.attrs) * (len(self.attrs) - 1) / 2)
            for i in range(self.i, len(self.attrs)):
                ind1 = graph.attribute_name_index[self.attrs[i]]
                for j in range(self.j, i):
                    if not self.running:
                        self.i, self.j = i, j
                        if not self.projectionTable.selectedIndexes():
                            self.projectionTable.selectRow(0)
                        self.button.setEnabled(True)
                        return
                    ind2 = graph.attribute_name_index[self.attrs[j]]
                    X = graph.scaled_data[[ind1, ind2], :]
                    valid = graph.get_valid_list([ind1, ind2])
                    X = X[:, valid].T
                    y = y_full[valid]
                    knn = NearestNeighbors(n_neighbors=self.k).fit(X)
                    ind = knn.kneighbors(return_distance=False)
                    score = norm * np.sum(y[ind] == y.reshape(-1, 1))
                    pos = bisect_left(self.scores, score)
                    self.projectionTableModel.insertRow(
                        len(self.scores) - pos,
                        [QStandardItem("{:.4f}".format(score)),
                         QStandardItem(self.attrs[j]),
                         QStandardItem(self.attrs[i])])
                    self.scores.insert(pos, score)
                    self.progress.advance()
                self.j = 0
            self.progress.finish()
            if not self.projectionTable.selectedIndexes():
                self.projectionTable.selectRow(0)
            self.button.setText("Finished")
            self.button.setEnabled(False)

        def score_heuristic(self):
            X = self.parent_widget.graph.scaled_data.T
            Y = self.parent_widget.data.Y
            dom = Orange.data.Domain([ContinuousVariable(str(i))
                                      for i in range(X.shape[1])],
                                     self.parent_widget.data.domain.class_vars)
            data = Orange.data.Table(dom, X, Y)
            weights = ReliefF(n_iterations=100, k_nearest=self.k)(data)
            attrs = sorted(
                zip(weights,
                    (x.name for x in self.parent_widget.data.domain.attributes)
                    ),
                reverse=True)
            return [a for _, a in attrs]
def main(icon_spec):
    app = QApplication(sys.argv)

    main_window = QMainWindow()

    def sigint_handler(*args):
        main_window.close()
    signal.signal(signal.SIGINT, sigint_handler)
    # the timer enables triggering the sigint_handler
    signal_timer = QTimer()
    signal_timer.start(100)
    signal_timer.timeout.connect(lambda: None)

    tool_bar = QToolBar()
    main_window.addToolBar(Qt.TopToolBarArea, tool_bar)

    table_view = QTableView()
    table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
    table_view.setSelectionMode(QAbstractItemView.SingleSelection)
    table_view.setSortingEnabled(True)
    main_window.setCentralWidget(table_view)

    proxy_model = QSortFilterProxyModel()
    proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
    proxy_model.setFilterKeyColumn(1)
    table_view.setModel(proxy_model)
    proxy_model.layoutChanged.connect(table_view.resizeRowsToContents)

    item_model = QStandardItemModel()
    proxy_model.setSourceModel(item_model)

    # get all icons and their available sizes
    QIcon.setThemeName("gnome")
    icons = []
    all_sizes = set([])
    for context, icon_names in icon_spec:
        for icon_name in icon_names:
            icon = QIcon.fromTheme(icon_name)
            sizes = []
            for size in icon.availableSizes():
                size = (size.width(), size.height())
                sizes.append(size)
                all_sizes.add(size)
            sizes.sort()
            icons.append({
                'context': context,
                'icon_name': icon_name,
                'icon': icon,
                'sizes': sizes,
            })
    all_sizes = list(all_sizes)
    all_sizes.sort()

    # input field for filter
    def filter_changed(value):
        proxy_model.setFilterRegExp(value)
        table_view.resizeRowsToContents()
    filter_line_edit = QLineEdit()
    filter_line_edit.setMaximumWidth(200)
    filter_line_edit.setPlaceholderText('Filter name')
    filter_line_edit.setToolTip('Filter name optionally using regular expressions (' + QKeySequence(QKeySequence.Find).toString() + ')')
    filter_line_edit.textChanged.connect(filter_changed)
    tool_bar.addWidget(filter_line_edit)

    # actions to toggle visibility of available sizes/columns 
    def action_toggled(index):
        column = 2 + index
        table_view.setColumnHidden(column, not table_view.isColumnHidden(column))
        table_view.resizeColumnsToContents()
        table_view.resizeRowsToContents()
    signal_mapper = QSignalMapper()
    for i, size in enumerate(all_sizes):
        action = QAction('%dx%d' % size, tool_bar)
        action.setCheckable(True)
        action.setChecked(True)
        tool_bar.addAction(action)
        action.toggled.connect(signal_mapper.map)
        signal_mapper.setMapping(action, i)
        # set tool tip and handle key sequence
        tool_tip = 'Toggle visibility of column'
        if i < 10:
            digit = ('%d' % (i + 1))[-1]
            tool_tip += ' (%s)' % QKeySequence('Ctrl+%s' % digit).toString()
        action.setToolTip(tool_tip)
    signal_mapper.mapped.connect(action_toggled)

    # label columns
    header_labels = ['context', 'name']
    for width, height in all_sizes:
        header_labels.append('%dx%d' % (width, height))
    item_model.setColumnCount(len(header_labels))
    item_model.setHorizontalHeaderLabels(header_labels)

    # fill rows
    item_model.setRowCount(len(icons))
    for row, icon_data in enumerate(icons):
        # context
        item = QStandardItem(icon_data['context'])
        item.setFlags(item.flags() ^ Qt.ItemIsEditable)
        item_model.setItem(row, 0, item)
        # icon name
        item = QStandardItem(icon_data['icon_name'])
        item.setFlags(item.flags() ^ Qt.ItemIsEditable)
        item_model.setItem(row, 1, item)
        for index_in_all_sizes, size in enumerate(all_sizes):
            column = 2 + index_in_all_sizes
            if size in icon_data['sizes']:
                # icon as pixmap to keep specific size
                item = QStandardItem('')
                pixmap = icon_data['icon'].pixmap(size[0], size[1])
                item.setData(pixmap, Qt.DecorationRole)
                item.setFlags(item.flags() ^ Qt.ItemIsEditable)
                item_model.setItem(row, column, item)
            else:
                # single space to be sortable against icons
                item = QStandardItem(' ')
                item.setFlags(item.flags() ^ Qt.ItemIsEditable)
                item_model.setItem(row, column, item)

    table_view.resizeColumnsToContents()
    # manually set row heights because resizeRowsToContents is not working properly
    for row, icon_data in enumerate(icons):
        if len(icon_data['sizes']) > 0:
            max_size = icon_data['sizes'][-1]
            table_view.setRowHeight(row, max_size[1])

    # enable focus find (ctrl+f) and toggle columns (ctrl+NUM)
    def main_window_keyPressEvent(self, event, old_keyPressEvent=QMainWindow.keyPressEvent):
        if event.matches(QKeySequence.Find):
            filter_line_edit.setFocus()
            return
        if event.modifiers() == Qt.ControlModifier and event.key() >= Qt.Key_0 and event.key() <= Qt.Key_9:
            index = event.key() - Qt.Key_1
            if event.key() == Qt.Key_0:
                index += 10
            action = signal_mapper.mapping(index)
            if action:
                action.toggle()
                return
        old_keyPressEvent(self, event)
    main_window.keyPressEvent = new.instancemethod(main_window_keyPressEvent, table_view, None)

    # enable copy (ctrl+c) name of icon to clipboard
    def table_view_keyPressEvent(self, event, old_keyPressEvent=QTableView.keyPressEvent):
        if event.matches(QKeySequence.Copy):
            selection_model = self.selectionModel()
            if selection_model.hasSelection():
                index = selection_model.selectedRows()[0]
                source_index = self.model().mapToSource(index)
                item = self.model().sourceModel().item(source_index.row(), 1)
                icon_name = item.data(Qt.EditRole)
                app.clipboard().setText(icon_name.toString())
                return
        old_keyPressEvent(self, event)
    table_view.keyPressEvent = new.instancemethod(table_view_keyPressEvent, table_view, None)
    print 'Icon Theme: ', QIcon.themeName()

    print 'Theme Search Paths:'
    for item in QIcon.themeSearchPaths():
        print item
    main_window.showMaximized()
    return app.exec_()
class dbmanagerUI(QMainWindow, ui_dbmanager.Ui_dbmanagerUI):
    """Main UI for MASAR database manager."""
    def __init__(self):
        """"""
        super(dbmanagerUI, self).__init__()
        self.setupUi(self)
        self.statusbar.showMessage("Ready")

        exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), '&Exit', self)
        exitAction.setShortcut('Ctrl+Q')
        exitAction.setStatusTip('Exit Masar Configuration Manager.')
        exitAction.triggered.connect(QtGui.qApp.quit)

        self.groupdatabasemenubar()

        #default database source, could be 0: SQLite, 1: MongoDB, and 2: MySQL
        self.dbsource = None

        self.defaultdbinfo = self._loadmasarconfig()
        self.usedefaultdb = True

        self.comboxboxSignalMapper = QtCore.QSignalMapper(self)
        self.comboxboxSignalMapper.mapped[QtGui.QWidget].connect(
            self.comboboxSignalMapperMapped)

        self.pushbuttonSignalMapper = QtCore.QSignalMapper(self)
        self.pushbuttonSignalMapper.mapped[QtGui.QWidget].connect(
            self.pushbuttonSignalMapperMapped)

        self.showpvbuttonSignalMapper = QtCore.QSignalMapper(self)
        self.showpvbuttonSignalMapper.mapped[QtGui.QWidget].connect(
            self.showpvbuttonSignalMapperMapped)

        self.choosepvbuttonSignalMapper = QtCore.QSignalMapper(self)
        self.choosepvbuttonSignalMapper.mapped[QtGui.QWidget].connect(
            self.choosepvbuttonSignalMapperMapped)

        self.currentselectedrow4config = -1

        self.selectedsystem = "Others"

        # self.pvgrouptreeview = QTreeView()
        self.pvGroupTreeView.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.pvgroupmodel = QStandardItemModel()
        # self.pvgroupmodel.setHorizontalHeaderLabels(['id', 'date', 'version', "description"])
        self.pvgroupmodel.setHorizontalHeaderLabels(["PV Groups"])
        self.pvGroupTreeView.setModel(self.pvgroupmodel)
        self.pvGroupTreeView.setUniformRowHeights(True)

    @QtCore.pyqtSlot(QtGui.QWidget)
    def comboboxSignalMapperMapped(self, comboBox):
        if self.masarConfigTableWidget.cellWidget(
                comboBox.row, comboBox.column + 1).isEnabled():
            self.masarConfigTableWidget.cellWidget(
                comboBox.row, comboBox.column + 1).setEnabled(False)
            button = self.masarConfigTableWidget.cellWidget(
                comboBox.row, comboBox.column + 1)
            palette = QtGui.QPalette(
                button.palette())  # make a copy of the palette
            palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor('grey'))
            button.setPalette(palette)
        else:
            self.masarConfigTableWidget.cellWidget(
                comboBox.row, comboBox.column + 1).setEnabled(True)
            button = self.masarConfigTableWidget.cellWidget(
                comboBox.row, comboBox.column + 1)
            palette = QtGui.QPalette(
                button.palette())  # make a copy of the palette
            palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor('red'))
            button.setPalette(palette)

    @QtCore.pyqtSlot(QtGui.QWidget)
    def pushbuttonSignalMapperMapped(self, pushbutton):
        configstatus = str(
            self.masarConfigTableWidget.cellWidget(
                pushbutton.row, pushbutton.column - 1).currentText())
        cid = str(self.masarConfigTableWidget.item(pushbutton.row, 0).text())
        cname = str(self.masarConfigTableWidget.item(pushbutton.row, 1).text())

        if self.updatemasarconfigstatus(configstatus, cid, configname=cname):
            palette = QtGui.QPalette(
                pushbutton.palette())  # make a copy of the palette
            palette.setColor(QtGui.QPalette.ButtonText, QtGui.QColor('grey'))
            pushbutton.setPalette(palette)
            pushbutton.setEnabled(False)

    @QtCore.pyqtSlot(QtGui.QWidget)
    def showpvbuttonSignalMapperMapped(self, showpvbutton):
        if self.newConfigTableWidget.item(showpvbutton.row,
                                          showpvbutton.column + 2) is None:
            raise RuntimeError("Unknown pv file")
        pvfilename = self.newConfigTableWidget.item(
            showpvbutton.row, showpvbutton.column + 2).text()
        if not os.path.isfile(pvfilename):
            raise RuntimeError(
                "Invalid pv file name for (row, col): (%s, %s)" %
                (showpvbutton.row, showpvbutton.column + 2))

        text = ", ".join(np.loadtxt(str(pvfilename), dtype=str, comments="#"))
        if self.newConfigTableWidget.item(showpvbutton.row, 0) is not None:
            head = self.newConfigTableWidget.item(showpvbutton.row, 0).text()
        else:
            head = ""
        msg = QMessageBox(self,
                          windowTitle='PVs for group %s' % head,
                          text="The following PVs to be added:")
        msg.setDetailedText(text)
        msg.exec_()

    @QtCore.pyqtSlot(QtGui.QWidget)
    def choosepvbuttonSignalMapperMapped(self, chhosepvbutton):
        self.newConfigTableWidget.setItem(
            chhosepvbutton.row, chhosepvbutton.column + 1,
            QTableWidgetItem(QFileDialog.getOpenFileName(self, "Open File")))

    def _loadmasarconfig(self):
        cf = ConfigParser.SafeConfigParser()
        cf.read([
            os.path.expanduser('~/.masarservice.conf'),
            '/etc/masarservice.conf', 'masarservice.conf',
            "%s/masarservice.conf" % os.path.abspath(os.path.dirname(__file__))
        ])
        return cf

    def groupdatabasemenubar(self):
        """Group 3 Databases menu together to make selection exclusive."""
        group = QtGui.QActionGroup(self)
        self.actionSQLite.setActionGroup(group)
        self.actionMongoDB.setActionGroup(group)
        self.actionMySQL.setActionGroup(group)

    def actionsqlitemenu(self):
        """Answer action when SQLite is selected."""
        if self.actionSQLite.isChecked():
            self.dbsource = 0
            self.defaultsqlitedb()
            self.listPvGroupPushButton.setEnabled(True)

    def actionmongodbmenu(self):
        """Answer action when MongoDB is selected."""
        if self.actionMongoDB.isChecked():
            self.dbsource = 1
            self.defaultmongodb()
            self.listPvGroupPushButton.setEnabled(False)

    def actionmysqlmenu(self):
        """Answer action when MySQL is selected."""
        if self.actionMySQL.isChecked():
            QMessageBox.warning(self, 'Warning',
                                "MySQL support not implemented yet.")
            self.actionMySQL.setChecked(False)
            if self.dbsource == 0:
                self.actionSQLite.setChecked(True)
            elif self.dbsource == 1:
                self.actionMongoDB.setChecked(True)

    def showdefaultdbinfo(self):
        """"""
        if self.dbsource == 0:
            self.defaultsqlitedb()
        elif self.dbsource == 1:
            self.defaultmongodb()
        elif self.dbsource == 2:
            QMessageBox.warning(self, 'Warning',
                                "MySQL support not implemented yet.")

    def defaultsqlitedb(self):
        """"""
        if self.defaultdbinfo.has_section("sqlite"):
            self.databaseDefault.setText(
                self.defaultdbinfo.get("sqlite", "database"))
            self.hostDefault.clear()
            self.portDefault.clear()
            self.userDefault.clear()

    def defaultmongodb(self):
        """"""
        if self.defaultdbinfo.has_section("mongodb"):
            self.databaseDefault.setText(
                self.defaultdbinfo.get("mongodb", "database"))
            self.hostDefault.setText(self.defaultdbinfo.get("mongodb", "host"))
            self.portDefault.setText(self.defaultdbinfo.get("mongodb", "port"))
            self.userDefault.setText(
                self.defaultdbinfo.get("mongodb", "username"))

    def getdatabasename(self):
        """"""
        self.database = self.databaseLineEdit.text()

    def getdatabaseport(self):
        """"""
        self.databaseport = self.databaseportLineEdit.text()

    def getdatabasehost(self):
        """"""
        self.databasehost = self.databaseHostLineEdit.text()

    def getdatabasepw(self):
        """"""
        self.databasepw = self.databasePwLineEdit.text()

    def showmasarconfigs(self):
        """"""
        result = None
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                # masardb = str(self.databaseDefault.text())
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite
            conn = pymasarsqlite.utils.connect()
            result = pymasarsqlite.service.retrieveServiceConfigs(
                conn, servicename="masar")
            pymasarsqlite.utils.close(conn)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo
            mongoconn, collection = pymasarmongo.db.utils.conn(host=host,
                                                               port=port,
                                                               db=database)
            resultdict = pymasarmongo.pymasarmongo.pymasar.retrieveconfig(
                mongoconn, collection)
            pymasarmongo.db.utils.close(mongoconn)

            result = [['id', 'name', 'desc', 'date', 'version', 'status']]
            for res in resultdict:
                result.append([
                    res['configidx'], res['name'], res['desc'],
                    res['created_on'], res['version'], res['status']
                ])
                # res['system']

        if result is not None:
            self._setconfigtable(result)

    def choosedbsrc(self, bool):
        """Choose DB source"""
        if bool:
            self.usedefaultdb = True
        else:
            self.usedefaultdb = False

    def _setconfigtable(self, content):
        """"""
        # head = self.masarConfigTableWidget.horizontalHeader()
        self.masarConfigTableWidget.clearContents()
        # self.masarConfigTableWidget.setHorizontalHeaderLabels(head)

        if len(content) > 1:
            self.masarConfigTableWidget.setRowCount(len(content) - 1)

            n = 0
            data = sorted(content[1:], key=itemgetter(0), reverse=True)
            for res in data:
                m = 0
                for item in res:
                    if not isinstance(item, basestring):
                        item = str(item)
                    if item:
                        if m == 5:
                            newitem = QtGui.QComboBox()
                            newitem.addItem("active")
                            newitem.addItem("inactive")
                            if item == "active":
                                newitem.setCurrentIndex(0)
                            else:
                                newitem.setCurrentIndex(1)

                            newitem.row = n
                            newitem.column = m
                            self.masarConfigTableWidget.setCellWidget(
                                n, m, newitem)
                            self.comboxboxSignalMapper.setMapping(
                                newitem, newitem)
                            newitem.currentIndexChanged.connect(
                                self.comboxboxSignalMapper.map)

                            updatebutton = QtGui.QPushButton()
                            updatebutton.setText("Update")
                            updatebutton.setEnabled(False)
                            updatebutton.row = n
                            updatebutton.column = m + 1
                            self.pushbuttonSignalMapper.setMapping(
                                updatebutton, updatebutton)
                            self.masarConfigTableWidget.setCellWidget(
                                n, m + 1, updatebutton)
                            updatebutton.clicked.connect(
                                self.pushbuttonSignalMapper.map)
                        else:
                            newitem = QTableWidgetItem(item)
                            newitem.setFlags(Qt.ItemIsEnabled
                                             | Qt.ItemIsSelectable)
                            self.masarConfigTableWidget.setItem(n, m, newitem)
                    m += 1
                n += 1

            self.masarConfigTableWidget.resizeColumnsToContents()

    def updatemasarconfigstatus(self, configstatus, cid, configname=None):
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite

            conn = pymasarsqlite.utils.connect()
            pymasarsqlite.service.updateServiceConfigStatus(
                conn, cid, status=configstatus)
            pymasarsqlite.utils.save(conn)
            pymasarsqlite.utils.close(conn)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo

            mongoconn, collection = pymasarmongo.db.utils.conn(host=host,
                                                               port=port,
                                                               db=database)
            pymasarmongo.pymasarmongo.pymasar.updateconfig(mongoconn,
                                                           collection,
                                                           configname,
                                                           configidx=int(cid),
                                                           status=configstatus)
            pymasarmongo.db.utils.close(mongoconn)

        return True

    def addnewpvgrouprow(self):
        """Add a new row to add pv group to MASAR configuration"""
        print("""Add a new row to add pv group to MASAR configuration""")
        currowcount = self.newConfigTableWidget.rowCount()
        self.newConfigTableWidget.setRowCount(currowcount + 1)

        showpvbutton = QtGui.QPushButton()
        showpvbutton.setText("Show PVs")
        showpvbutton.setEnabled(True)
        showpvbutton.row = currowcount
        showpvbutton.column = 2
        self.showpvbuttonSignalMapper.setMapping(showpvbutton, showpvbutton)
        self.newConfigTableWidget.setCellWidget(currowcount,
                                                showpvbutton.column,
                                                showpvbutton)
        showpvbutton.clicked.connect(self.showpvbuttonSignalMapper.map)

        choosepvbutton = QtGui.QPushButton()
        choosepvbutton.setText("PV File")
        choosepvbutton.setEnabled(True)
        choosepvbutton.row = currowcount
        choosepvbutton.column = 3
        self.choosepvbuttonSignalMapper.setMapping(choosepvbutton,
                                                   choosepvbutton)
        self.newConfigTableWidget.setCellWidget(currowcount,
                                                choosepvbutton.column,
                                                choosepvbutton)
        choosepvbutton.clicked.connect(self.choosepvbuttonSignalMapper.map)

    def removepvgrouprow(self):
        """Remove selected pv group from the configuration to be added into MASAR database"""
        if self.currentselectedrow4config == -1:
            raise RuntimeError("No pv group selected.")
        rownametobedelete = self.newConfigTableWidget.item(
            self.currentselectedrow4config, 0)
        if rownametobedelete is not None:
            rownametobedelete = rownametobedelete.text()
        self.newConfigTableWidget.removeRow(self.currentselectedrow4config)
        if rownametobedelete is not None:
            print("Successfully delete pv group: ", rownametobedelete)
        else:
            print("Successfully delete row: ", self.currentselectedrow4config)
        self.currentselectedrow4config = -1

    def savemasarsqlite(self):
        """"""
        # get data from sqlite
        if self.usedefaultdb:
            masardb = str(self.databaseDefault.toPlainText())
        else:
            masardb = str(self.databaseLineEdit.text())

        if masardb != "":
            os.environ["MASAR_SQLITE_DB"] = masardb
        else:
            QMessageBox.warning(self, "Warning",
                                "Cannot find MASAR SQLite Database")
            return

        import pymasarsqlite
        conn = pymasarsqlite.utils.connect()
        existedresult = pymasarsqlite.service.retrieveServiceConfigs(
            conn, servicename="masar")

        newcfgdata = self._getnewconfigurationdata(existedresult)
        if newcfgdata is None:
            QMessageBox.warning(
                self, "Warning",
                "Not enough information for a new configuration.")
            return
        newcfgname = newcfgdata[0]
        desc = newcfgdata[1]
        msystem = newcfgdata[2]
        # config data format: [[name], [desc], [pv files]]
        cfgdata = newcfgdata[3]

        if newcfgname is None or msystem is None or newcfgdata is None:
            # Nothing to be added.
            QMessageBox.warning(
                self, "Warning",
                "No name or system is given, or empty configuration data.")
            return

        for i in range(len(cfgdata[0])):
            if cfgdata[0][i] is None:
                QMessageBox.warning(self, "Warning", "Wrong PV group name")
                return

            if cfgdata[2][i] is not None and os.path.isfile(cfgdata[2][i]):
                pvs = list(np.loadtxt(cfgdata[2][i], dtype=str, comments="#"))
                if len(pvs) > 0:
                    for j, pv in enumerate(pvs):
                        pvs[j] = pv.strip()
                    pymasarsqlite.pvgroup.savePvGroup(conn,
                                                      cfgdata[0][i],
                                                      func=cfgdata[1][i])
                    pymasarsqlite.pvgroup.saveGroupPvs(conn, cfgdata[0][i],
                                                       pvs)

        try:
            pymasarsqlite.service.saveServiceConfig(conn,
                                                    "masar",
                                                    newcfgname,
                                                    configdesc=desc,
                                                    system=msystem)
            pymasarsqlite.service.saveServicePvGroup(conn, newcfgname,
                                                     cfgdata[0])
        except Exception as e:
            QMessageBox.warning(self, "Error", e.message)
            return

        pymasarsqlite.utils.save(conn)
        QMessageBox.information(
            self, "Congratulation",
            "A new configuration has been added successfully.")
        pymasarsqlite.utils.close(conn)

    def savemasarmongodb(self):
        """"""
        # get data from mongodb
        if self.usedefaultdb:
            database = str(self.databaseDefault.toPlainText())
            host = str(self.hostDefault.toPlainText())
            port = str(self.portDefault.toPlainText())
        else:
            database = str(self.databaseLineEdit.text())
            host = str(self.databaseHostLineEdit.text())
            port = str(self.databasePortLineEdit.text())

        import pymasarmongo

        mongoconn, collection = pymasarmongo.db.utils.conn(host=host,
                                                           port=port,
                                                           db=database)
        existedresult = pymasarmongo.pymasarmongo.pymasar.retrieveconfig(
            mongoconn, collection)
        existedcfg = []
        for res in existedresult:
            existedcfg.append([
                res['configidx'], res['name'], res['desc'], res['created_on'],
                res['version'], res['status']
            ])
        newcfgdata = self._getnewconfigurationdata(existedcfg)
        if newcfgdata is None:
            # Nothing to be added.
            raise ValueError("Empty configuration.")

        newcfgname = newcfgdata[0]
        desc = newcfgdata[1]
        msystem = newcfgdata[2]
        # config data format: [[name], [desc], [pv files]]
        cfgdata = newcfgdata[3]
        pvs = []
        for pvf in cfgdata[2]:
            if pvf is not None and os.path.isfile(pvf):
                pvs += list(np.loadtxt(pvf, dtype=str, comments="#"))
        if pvs:
            for i, pv in enumerate(pvs):
                pvs[i] = pv.strip()
            pymasarmongo.pymasarmongo.pymasar.saveconfig(mongoconn,
                                                         collection,
                                                         newcfgname,
                                                         desc=desc,
                                                         system=msystem,
                                                         pvlist={"names": pvs})
            QMessageBox.information(
                self, "Congratulation",
                "A new configuration has been added successfully.")
        else:
            QMessageBox.warning(self, "Warning",
                                "No PVs available for the new configuration.")

        pymasarmongo.db.utils.close(mongoconn)

    def submitmasarconfig(self):
        """submit a new configuration to MASAR database"""
        if self.dbsource is None:
            QMessageBox.warning(
                self, "Warning",
                "Unknown database source.\nPlease select which database should be use."
            )
            return
        if self.dbsource == 0:
            self.savemasarsqlite()
        elif self.dbsource == 1:
            self.savemasarmongodb()

    def _getnewconfigurationdata(self, existedresult):
        """"""
        newcfgname = self.newConfigurationLineEdit.text()
        if newcfgname is None or str(newcfgname) == "":
            QMessageBox.warning(self, "Warning",
                                "Name of configuration is empty.")
            return None
        elif str(newcfgname) in np.array(existedresult)[:, 1]:
            QMessageBox.warning(
                self, "Warning",
                "Configuration (%s) exists already." % str(newcfgname))
            return None
        else:
            newcfgname = str(newcfgname)
        desc = self.newConfigurationDescription.text()
        if str(desc) == "":
            desc = None
        else:
            desc = str(desc)

        msystem = str(self.systemComboBox.currentText())
        if msystem == "Others":
            msystem = self.systemLineEdit.text()
            if msystem is None or str(msystem) == "":
                QMessageBox.warning(
                    self, "Warning",
                    "System for configuration (%s) not specified yet." %
                    str(newcfgname))
                return None
            else:
                msystem = str(msystem)

        pvgroups = self.newConfigTableWidget.rowCount()
        if pvgroups == 0:
            QMessageBox.warning(
                self, "Warning",
                "No PV founded for new configuration (%s)." % str(newcfgname))
            return None

        pvgroupnames = []
        pvgroupdescs = []
        pvgroupfiles = []
        for count in range(pvgroups):
            # Collect PV group name information
            if self.newConfigTableWidget.item(count, 0) is not None and str(
                    self.newConfigTableWidget.item(count, 0).text()) != "":
                pvgname = str(self.newConfigTableWidget.item(count, 0).text())
                if pvgname in pvgroupnames:
                    QMessageBox.warning(
                        self, "Warning",
                        "Duplicated pv group name: %s." % str(pvgname))
                    return None
                pvgroupnames.append(pvgname)
            elif self.newConfigTableWidget.item(count, 4) is None or str(
                    self.newConfigTableWidget.item(count, 4)) == "":
                continue
            elif self.dbsource == 1:
                pvgroupnames.append(None)
            else:
                QMessageBox.warning(self, "Warning", "Empty pv group name.")
                return None
                # reply = QMessageBox.question(self, "Message",
                #                              "pv group name not specified for row {}.\nContinue?".format(count),
                #                              QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                # if reply == QMessageBox.Yes:
                #     pvgroupnames.append(None)
                # else:
                #     return None

            # Collection PV group descriptions
            if self.newConfigTableWidget.item(count, 1) is not None:
                pvgroupdescs.append(
                    str(self.newConfigTableWidget.item(count, 1).text()))
            else:
                pvgroupdescs.append(None)

            # PV files for the pv group.
            if self.newConfigTableWidget.item(count, 4) is not None:
                pvgroupfiles.append(
                    str(self.newConfigTableWidget.item(count, 4).text()))
            else:
                pvgroupfiles.append(None)

        if pvgroupfiles:
            return newcfgname, desc, msystem, [
                pvgroupnames, pvgroupdescs, pvgroupfiles
            ]
        else:
            return None

    def currentselectedrow(self, row, col):
        """Cache current selected row in MASAR configuration Table Widget."""
        self.currentselectedrow4config = row

    def updateselectedsystem(self, system):
        """Update selected system if value changed"""
        self.selectedsystem = str(system)

    def updatesystemcombobox(self):
        """Update selected system if value changed"""
        self.systemComboBox.clear()
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                # masardb = str(self.databaseDefault.text())
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite

            conn = pymasarsqlite.utils.connect()
            result = pymasarsqlite.service.retrieveServiceConfigProps(
                conn, propname="system", servicename="masar")
            index = 0
            if len(result) > 1:
                res = sorted(set(list(np.array(result[1:])[:, 3])))
                #for res in result[1:]:
                self.systemComboBox.addItems(res)
                index = len(res)
            self.systemComboBox.addItem("Others")
            self.systemComboBox.setCurrentIndex(index)
            pymasarsqlite.utils.close(conn)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo

            mongoconn, collection = pymasarmongo.db.utils.conn(host=host,
                                                               port=port,
                                                               db=database)

            result = pymasarmongo.pymasarmongo.pymasar.retrieveconfig(
                mongoconn, collection)
            pymasarmongo.db.utils.close(mongoconn)

            results = []
            for res in result:
                if res["system"] not in results:
                    results.append(res["system"])
            res = sorted(set(results))
            self.systemComboBox.addItems(res)
            index = len(res)
            self.systemComboBox.addItem("Others")
            self.systemComboBox.setCurrentIndex(index)

    def listpvgroups(self):
        """"""
        self.pvgroupmodel.clear()
        self.pvgroupmodel.setHorizontalHeaderLabels(["PV Groups"])
        if self.dbsource == 0:
            # get data from sqlite
            if self.usedefaultdb:
                # masardb = str(self.databaseDefault.text())
                masardb = str(self.databaseDefault.toPlainText())
            else:
                masardb = str(self.databaseLineEdit.text())

            if masardb != "":
                os.environ["MASAR_SQLITE_DB"] = masardb
            else:
                raise RuntimeError("Cannot find MASAR SQLite Database")

            import pymasarsqlite

            conn = pymasarsqlite.utils.connect()
            result = pymasarsqlite.pvgroup.retrievePvGroups(conn)
            if len(result) > 0:
                result = sorted(result, key=itemgetter(0), reverse=True)
            for res in result:
                parent1 = QStandardItem(res[1])
                child1 = QStandardItem('id: {}'.format(res[0]))
                child2 = QStandardItem('description: {}'.format(res[2]))
                child3 = QStandardItem('date: {}'.format(res[3]))
                child4 = QStandardItem('version: {}'.format(res[4]))
                parent1.appendColumn([child1, child2, child3, child4])
                self.pvgroupmodel.appendRow(parent1)
            selmod = self.pvGroupTreeView.selectionModel()
            index2 = self.pvgroupmodel.indexFromItem(child3)
            selmod.select(
                index2, QItemSelectionModel.Select | QItemSelectionModel.Rows)
            pymasarsqlite.utils.close(conn)

            self.pvGroupTreeView.setContextMenuPolicy(Qt.CustomContextMenu)
            self.pvGroupTreeView.clicked.connect(self.showpvsinpvgroup)
            # self.connect(self.pvGroupTreeView,
            #              QtCore.SIGNAL("clicked(QModelIndex)"),
            #              #QtCore.SIGNAL("customContextMenuRequested(const QPoint &)"),
            #              self.doMenu)

        elif self.dbsource == 1:
            # get data from mongodb
            if self.usedefaultdb:
                database = str(self.databaseDefault.toPlainText())
                host = str(self.hostDefault.toPlainText())
                port = str(self.portDefault.toPlainText())
            else:
                database = str(self.databaseLineEdit.text())
                host = str(self.databaseHostLineEdit.text())
                port = str(self.databasePortLineEdit.text())

            import pymasarmongo

    def showpvsinpvgroup(self, point):
        if point.model().itemFromIndex(point).child(0) is None:
            return
        reply = QMessageBox.question(
            self, 'Message', "show all pvs belong to group {} ?".format(
                point.model().itemFromIndex(point).text()),
            QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            pvgroupidx = int(
                str(point.model().itemFromIndex(point).child(0).text().split(
                    ":")[1]).strip())

            # msg = QMessageBox(self)
            msg = ShowPvMessageBox()
            msg.setWindowTitle('PVs for group {}'.format(
                point.model().itemFromIndex(point).text()))
            msg.setText("Click show details to see all pvs.")
            # windowTitle = 'PVs for group {}'.format(point.model().itemFromIndex(point).text())

            if self.dbsource == 0:
                # get data from sqlite
                if self.usedefaultdb:
                    # masardb = str(self.databaseDefault.text())
                    masardb = str(self.databaseDefault.toPlainText())
                else:
                    masardb = str(self.databaseLineEdit.text())

                if masardb != "":
                    os.environ["MASAR_SQLITE_DB"] = masardb
                else:
                    raise RuntimeError("Cannot find MASAR SQLite Database")

                import pymasarsqlite

                conn = pymasarsqlite.utils.connect()
                result = pymasarsqlite.pvgroup.retrieveGroupPvs(
                    conn, pvgroupidx)
                text = "\n".join(list(np.array(result)[:, 0]))
                msg.setDetailedText(text)
                msg.exec_()

            elif self.dbsource == 1:
                # get data from mongodb
                if self.usedefaultdb:
                    database = str(self.databaseDefault.toPlainText())
                    host = str(self.hostDefault.toPlainText())
                    port = str(self.portDefault.toPlainText())
                else:
                    database = str(self.databaseLineEdit.text())
                    host = str(self.databaseHostLineEdit.text())
                    port = str(self.databasePortLineEdit.text())

                import pymasarmongo
class GeoDetermineDlg(FlightPlanBaseDlg):
    HistoryDataP = []
    HistoryDataBD = []
    HistoryDataMV = []

    def __init__(self, parent):
        FlightPlanBaseDlg.__init__(self, parent)
        self.setObjectName("HoldingRnavDlg")
        self.surfaceType = SurfaceTypes.GeoDetermine
        self.initParametersPan()
        self.setWindowTitle(SurfaceTypes.GeoDetermine)
        self.resize(540, 550)
        self.surfaceList = None

        self.date = QDate.currentDate()
        self.model = MagneticModel.WMM2010
        geo = Geo()

        self.resultLayerList = []
        self.resultPoint3d = None

        self.resultLat = None
        self.resultLon = None

    def uiStateInit(self):
        self.ui.grbMostCritical.setVisible(False)
        self.ui.grbResult_2.setVisible(False)
        self.ui.btnUpdateQA.setVisible(False)
        self.ui.btnUpdateQA_2.setVisible(False)
        self.ui.btnExportResult.setVisible(False)
        self.ui.btnEvaluate.setVisible(False)
        self.ui.btnPDTCheck.setVisible(False)
        self.ui.frm_cmbObstSurface.setVisible(False)
        self.ui.tabCtrlGeneral.removeTab(1)

        icon = QIcon()
        icon.addPixmap(QPixmap(("Resource/Calculator.bmp")), QIcon.Normal,
                       QIcon.Off)
        self.ui.btnConstruct.setIcon(icon)
        self.ui.btnConstruct.setToolTip("Calculate")

        return FlightPlanBaseDlg.uiStateInit(self)

    def tblHistory_Click(self, modelIndex):
        if modelIndex != None:
            if self.parametersPanel.tabGeneral.currentIndex() == 0:
                dataList = GeoDetermineDlg.HistoryDataP[modelIndex.row()]

                self.parametersPanel.pnlStartPosP.Point3d = Point3D(
                    float(dataList[1][1]), float(dataList[1][0]))
                self.parametersPanel.pnlVarStartP.Value = float(dataList[1][2])
                self.parametersPanel.txtForwardTP.Value = float(dataList[1][3])
                self.parametersPanel.txtForwardMP.Value = float(dataList[1][4])
                self.parametersPanel.txtDistanceP.Value = Distance(
                    float(dataList[1][5]), DistanceUnits.NM)
                self.parametersPanel.pnlVarFinishP.Value = float(
                    dataList[1][9])

                self.method_29_P()
                self.resultModelP.setItem(0, 0,
                                          QStandardItem(Captions.LATITUDE))
                self.resultModelP.setItem(0, 1, QStandardItem(dataList[1][7]))

                self.resultModelP.setItem(1, 0,
                                          QStandardItem(Captions.LONGITUDE))
                self.resultModelP.setItem(1, 1, QStandardItem(dataList[1][8]))

                self.resultModelP.setItem(
                    2, 0, QStandardItem(Captions.REVERSE_TRUE_BEARING))
                self.resultModelP.setItem(2, 1, QStandardItem(dataList[1][10]))

                self.resultModelP.setItem(
                    3, 0, QStandardItem(Captions.REVERSE_MAGNETIC_BEARING))
                self.resultModelP.setItem(3, 1, QStandardItem(dataList[1][11]))
            elif self.parametersPanel.tabGeneral.currentIndex() == 1:
                dataList = GeoDetermineDlg.HistoryDataBD[modelIndex.row()]

                self.parametersPanel.pnlStartPosBD.ID = dataList[1][0]
                self.parametersPanel.pnlStartPosBD.Point3d = Point3D(
                    float(dataList[1][2]), float(dataList[1][1]))
                self.parametersPanel.pnlVarStartBD.Value = float(
                    dataList[1][3])
                self.parametersPanel.pnlFinishPosBD.ID = dataList[1][4]
                self.parametersPanel.pnlFinishPosBD.Point3d = Point3D(
                    float(dataList[1][6]), float(dataList[1][5]))
                self.parametersPanel.pnlVarFinishBD.Value = float(
                    dataList[1][7])

                self.method_31_BD()
                self.resultModelBD.setItem(
                    0, 0, QStandardItem(Captions.FORWARD_TRUE_BEARING))
                self.resultModelBD.setItem(0, 1, QStandardItem(dataList[1][8]))

                self.resultModelBD.setItem(
                    1, 0, QStandardItem(Captions.FORWARD_MAGNETIC_BEARING))
                self.resultModelBD.setItem(1, 1, QStandardItem(dataList[1][9]))

                self.resultModelBD.setItem(
                    2, 0, QStandardItem(Captions.REVERSE_TRUE_BEARING))
                self.resultModelBD.setItem(2, 1,
                                           QStandardItem(dataList[1][10]))

                self.resultModelBD.setItem(
                    3, 0, QStandardItem(Captions.REVERSE_MAGNETIC_BEARING))
                self.resultModelBD.setItem(3, 1,
                                           QStandardItem(dataList[1][11]))

                self.resultModelBD.setItem(
                    2, 0, QStandardItem(Captions.DISTANCE_BETWEEN_POSITIONS))
                self.resultModelBD.setItem(2, 1,
                                           QStandardItem(dataList[1][12]))

                self.resultModelBD.setItem(
                    3, 0, QStandardItem(Captions.DISTANCE_BETWEEN_POSITIONS))
                self.resultModelBD.setItem(3, 1,
                                           QStandardItem(dataList[1][13]))
            else:
                dataList = GeoDetermineDlg.HistoryDataMV[modelIndex.row()]

                self.parametersPanel.pnlPositionMVD.Point3d = Point3D(
                    float(dataList[1][1]), float(dataList[1][0]))
                self.parametersPanel.pnlPositionMVD.txtAltitudeM.setText(
                    dataList[1][2])
                self.parametersPanel.txtResult.Value = dataList[1][6]

    def calculateP(self):
        degree = None
        degree1 = None
        degree2 = None
        degree3 = None
        num = None
        result, degree, degree1 = self.parametersPanel.pnlStartPosP.method_3()
        if (result):
            # self.pnlVarStart.Value.smethod_17();
            num1 = float(self.parametersPanel.pnlVarFinishP.Value)
            value = float(self.parametersPanel.txtForwardTP.Value)
            value1 = float(self.parametersPanel.txtForwardTP.Value)
            distance = self.parametersPanel.txtDistanceP.Value
            result, degree2, degree3, num = Geo.smethod_6(
                self.parametersPanel.cmbCalculationTypeP.SelectedItem, degree,
                degree1, value, distance)
            if (result):
                num2 = MathHelper.smethod_3(num - num1)
                self.method_29_P()
                self.resultPoint3d = Point3D(degree3, degree2)

                self.resultLat = degree2
                self.resultLon = degree3

                latStr = Degrees(degree2, None, None,
                                 DegreesType.Latitude).ToString()

                self.resultModelP.setItem(0, 0,
                                          QStandardItem(Captions.LATITUDE))
                self.resultModelP.setItem(0, 1, QStandardItem(latStr))

                lonStr = Degrees(degree3, None, None,
                                 DegreesType.Longitude).ToString()
                if String.Str2QString(lonStr).mid(0, 1) == "0":
                    lonStr = String.Str2QString(lonStr).mid(
                        1,
                        String.Str2QString(lonStr).length() - 1)

                self.resultModelP.setItem(1, 0,
                                          QStandardItem(Captions.LONGITUDE))
                self.resultModelP.setItem(1, 1, QStandardItem(lonStr))

                self.resultModelP.setItem(
                    2, 0, QStandardItem(Captions.REVERSE_TRUE_BEARING))
                self.resultModelP.setItem(2, 1,
                                          QStandardItem(str(round(num, 4))))

                self.resultModelP.setItem(
                    3, 0, QStandardItem(Captions.REVERSE_MAGNETIC_BEARING))
                self.resultModelP.setItem(3, 1,
                                          QStandardItem(str(round(num2, 4))))

                dataList = []
                dataList.append([
                    "Latitude (Start)", "Longitude (Start)",
                    "Variation (Start)", "Forward (° T)", "Forward (° M)",
                    "Distance (nm)", "Distance (km)", "Latitude (Finish)",
                    "Longitude (Finish)", "Variation (Finish)",
                    "Reverse (° T)", "Reverse (° M)"
                ])
                dataList.append([
                    str(degree),
                    str(degree1),
                    str(self.parametersPanel.pnlVarStartP.Value),
                    str(self.parametersPanel.txtForwardTP.Value),
                    str(self.parametersPanel.txtForwardMP.Value),
                    str(distance.NauticalMiles),
                    str(distance.Kilometres),
                    str(degree2),
                    str(degree3),
                    str(self.parametersPanel.pnlVarFinishP.Value),
                    str(round(num, 4)),
                    str(round(num2, 4))
                ])
                GeoDetermineDlg.HistoryDataP.append(dataList)
                self.setDataInHistoryModel(dataList)
                self.method_28_P(degree2, degree3)

    def calculateBD(self):
        degree = None
        degree1 = None
        degree2 = None
        degree3 = None
        num = None
        result, degree, degree1 = self.parametersPanel.pnlStartPosBD.method_3()
        if (result):
            num2 = self.parametersPanel.pnlVarStartBD.Value
            result1, degree2, degree3 = self.parametersPanel.pnlFinishPosBD.method_3(
            )
            if (result1):
                num3 = self.parametersPanel.pnlVarFinishBD.Value
                result2, distance, num, num1 = Geo.smethod_4(
                    self.parametersPanel.cmbCalculationTypeBD.SelectedItem,
                    degree, degree1, degree2, degree3)
                if define._units == QGis.Meters:
                    QgisHelper.convertMeasureUnits(QGis.Degrees)
                    distance = Distance(
                        MathHelper.calcDistance(
                            self.parametersPanel.pnlStartPosBD.Point3d,
                            self.parametersPanel.pnlFinishPosBD.Point3d))
                    QgisHelper.convertMeasureUnits(QGis.Meters)
                else:
                    distance = Distance(
                        MathHelper.calcDistance(
                            self.parametersPanel.pnlStartPosBD.Point3d,
                            self.parametersPanel.pnlFinishPosBD.Point3d))
                if result2:
                    num4 = MathHelper.smethod_3(num - num2)
                    num5 = MathHelper.smethod_3(num1 - num3)
                    self.method_31_BD()

                    self.resultModelBD.setItem(
                        0, 0, QStandardItem(Captions.FORWARD_TRUE_BEARING))
                    self.resultModelBD.setItem(
                        0, 1, QStandardItem(str(round(num, 4))))

                    self.resultModelBD.setItem(
                        1, 0, QStandardItem(Captions.FORWARD_MAGNETIC_BEARING))
                    self.resultModelBD.setItem(
                        1, 1, QStandardItem(str(round(num4, 4))))

                    self.resultModelBD.setItem(
                        2, 0, QStandardItem(Captions.REVERSE_TRUE_BEARING))
                    self.resultModelBD.setItem(
                        2, 1, QStandardItem(str(round(num1, 4))))

                    self.resultModelBD.setItem(
                        3, 0, QStandardItem(Captions.REVERSE_MAGNETIC_BEARING))
                    self.resultModelBD.setItem(
                        3, 1, QStandardItem(str(round(num5, 4))))

                    self.resultModelBD.setItem(
                        4, 0,
                        QStandardItem(Captions.DISTANCE_BETWEEN_POSITIONS))
                    self.resultModelBD.setItem(
                        4, 1,
                        QStandardItem(
                            str(round(distance.NauticalMiles, 4)) + " nm"))

                    self.resultModelBD.setItem(
                        5, 0,
                        QStandardItem(Captions.DISTANCE_BETWEEN_POSITIONS))
                    self.resultModelBD.setItem(
                        5, 1,
                        QStandardItem(
                            str(round(distance.Kilometres, 4)) + " km"))

                    dataList = []
                    dataList.append([
                        "ID (Start)", "Latitude (Start)", "Longitude (Start)",
                        "Variation (Start)", "ID (Finish)",
                        "Latitude (Finish)", "Longitude (Finish)",
                        "Variation (Finish)", "Forward (° T)", "Forward (° M)",
                        "Reverse (° T)", "Reverse (° M)", "Distance (nm)",
                        "Distance (km)"
                    ])
                    dataList.append([
                        self.parametersPanel.pnlStartPosBD.ID,
                        str(degree),
                        str(degree1),
                        str(self.parametersPanel.pnlVarStartBD.Value),
                        self.parametersPanel.pnlFinishPosBD.ID,
                        str(degree2),
                        str(degree3),
                        str(self.parametersPanel.pnlVarFinishBD.Value),
                        str(num),
                        str(num4),
                        str(round(num, 4)),
                        str(round(num2, 4)),
                        str(distance.NauticalMiles),
                        str(distance.Kilometres)
                    ])
                    GeoDetermineDlg.HistoryDataBD.append(dataList)
                    self.setDataInHistoryModel(dataList)
                    self.method_28_BD()

    def calculateMVD(self):
        degree = None
        degree1 = None
        degree2 = None

        result, degree, degree1 = self.parametersPanel.pnlPositionMVD.method_3(
        )
        # position.method_1(out degree, out degree1);
        altitude = self.parametersPanel.pnlPositionMVD.Altitude()
        result, degree2 = Geo.smethod_7(
            degree, degree1, altitude,
            self.parametersPanel.cmbModel.SelectedIndex,
            self.parametersPanel.dtpDate.date())
        if (result):
            self.parametersPanel.txtResult.Value = str(round(
                degree2, 4))  #.method_1(Formats.VariationFormat);
            date = self.parametersPanel.dtpDate.date()
            dataList = []
            dataList.append([
                "Latitude", "Longitude", "Altitude  (m)", "Altitude (ft)",
                "Date", "Magnetic Model", "Magnetic Variation"
            ])
            dataList.append([
                str(degree),
                str(degree1),
                str(altitude.Metres),
                str(altitude.Feet),
                date.toString(), self.parametersPanel.cmbModel.SelectedItem,
                self.parametersPanel.txtResult.Value
            ])
            GeoDetermineDlg.HistoryDataMV.append(dataList)
            self.setDataInHistoryModel(dataList)

    def autoCalcFinishMagVar(self):
        try:
            if self.parametersPanel.chbAutoFinishMagVar.Checked:
                finishPt = None
                finishLat = None
                finishLon = None
                degree3 = None
                num = None
                result, degree, degree1 = self.parametersPanel.pnlStartPosP.method_3(
                )
                if (result):
                    value = float(self.parametersPanel.txtForwardTP.Value)
                    value1 = float(self.parametersPanel.txtForwardTP.Value)
                    distance = self.parametersPanel.txtDistanceP.Value
                    result1, degree2, degree3, num = Geo.smethod_6(
                        self.parametersPanel.cmbCalculationTypeP.SelectedItem,
                        degree, degree1, value, distance)
                    if (result1):
                        finishPt = Point3D(degree3, degree2)

                        finishLat = degree2
                        finishLon = degree3
                if finishPt != None and self.model != None and self.date != None:
                    # result, degree, degree1 = self.parametersPanel.pnlStartPosP.method_3();
                    result2, degree2 = Geo.smethod_7(finishLat, finishLon,
                                                     Altitude(0), self.model,
                                                     self.date)
                    if (result2):
                        degree2 = round(degree2, 2)
                        self.parametersPanel.pnlVarFinishP.Value = degree2
        except:
            pass

    def btnConstruct_Click(self):
        # flag = FlightPlanBaseDlg.btnConstruct_Click(self)
        # if not flag:
        #     return
        if self.parametersPanel.tabGeneral.currentIndex() == 0:
            self.autoCalcFinishMagVar()
            self.calculateP()

        elif self.parametersPanel.tabGeneral.currentIndex() == 1:
            self.calculateBD()
        else:
            self.calculateMVD()

    def initParametersPan(self):
        ui = Ui_GeoDetermine()
        self.parametersPanel = ui
        FlightPlanBaseDlg.initParametersPan(self)

        self.parametersPanel.pnlStartPosP = PositionPanel(
            self.parametersPanel.gbStartPosP, None, None, "Degree")
        # self.parametersPanel.pnlStartPosP.degreeFormat = "ddmmss.ssssH"
        self.parametersPanel.pnlStartPosP.alwwaysShowString = "Degree"
        #         self.parametersPanel.pnlWaypoint.groupBox.setTitle("FAWP")
        self.parametersPanel.pnlStartPosP.btnCalculater.hide()
        self.parametersPanel.pnlStartPosP.hideframe_Altitude()
        # self.parametersPanel.pnlStartPosP.showframe_ID()
        self.parametersPanel.pnlStartPosP.setObjectName("pnlStartPosP")
        self.connect(self.parametersPanel.pnlStartPosP,
                     SIGNAL("positionChanged"), self.autoCalcFinishMagVar)

        ui.verticalLayout_gbStartPosP.addWidget(
            self.parametersPanel.pnlStartPosP)

        self.parametersPanel.pnlVarStartP = DegreesBoxPanel(self)
        self.parametersPanel.pnlVarStartP.CaptionLabel = "Magnetic Variation"
        self.connect(self.parametersPanel.pnlVarStartP,
                     SIGNAL("btnDegreeBoxPanel_clicked"), self.method_32_P)
        self.connect(self.parametersPanel.pnlVarStartP,
                     SIGNAL("txtDegreeBox_textChanged"),
                     self.txtDegreeBox_textChangedP)
        ui.verticalLayout_gbStartPosP.addWidget(
            self.parametersPanel.pnlVarStartP)

        self.parametersPanel.pnlVarFinishP = DegreesBoxPanel(self)
        self.parametersPanel.pnlVarFinishP.ButtonVisible = False
        self.parametersPanel.pnlVarFinishP.Enabled = False
        self.parametersPanel.pnlVarFinishP.CaptionLabel = "Magnetic Variation at Finish"
        ui.vLayout_grbParametersP.insertWidget(
            1, self.parametersPanel.pnlVarFinishP)
        # self.connect(self.parametersPanel.pnlVarStartP, SIGNAL("btnDegreeBoxPanel_clicked"), self.method_32_P)

        self.parametersPanel.pnlStartPosBD = PositionPanel(
            self.parametersPanel.gbFinishPosBD, None, None, "Degree")
        #         self.parametersPanel.pnlStartPosBD.groupBox.setTitle("FAWP")
        #         self.parametersPanel.pnlStartPosBD.degreeFormat = "ddmmss.ssssH"
        self.parametersPanel.pnlStartPosBD.alwwaysShowString = "Degree"
        self.parametersPanel.pnlStartPosBD.btnCalculater.hide()
        self.parametersPanel.pnlStartPosBD.hideframe_Altitude()
        self.parametersPanel.pnlStartPosBD.showframe_ID()
        self.parametersPanel.pnlStartPosBD.setObjectName("pnlStartPosBD")
        ui.verticalLayout_gbStartPosBD.insertWidget(
            0, self.parametersPanel.pnlStartPosBD)
        self.connect(self.parametersPanel.pnlStartPosBD,
                     SIGNAL("positionChanged"), self.positionChangedStartBD)

        self.parametersPanel.pnlVarStartBD = DegreesBoxPanel(self)
        self.parametersPanel.pnlVarStartBD.CaptionLabel = "Magnetic Variation"
        # self.parametersPanel.pnlVarStartBD.Enabled = False
        self.connect(self.parametersPanel.pnlVarStartBD,
                     SIGNAL("btnDegreeBoxPanel_clicked"), self.method_34_BD)
        # self.connect(self.parametersPanel.pnlVarStartBD, SIGNAL("txtDegreeBox_textChanged"), self.txtDegreeBox_textChangedP)
        ui.verticalLayout_gbStartPosBD.addWidget(
            self.parametersPanel.pnlVarStartBD)

        self.parametersPanel.pnlFinishPosBD = PositionPanel(
            self.parametersPanel.gbFinishPosBD, None, None, "Degree")
        #         self.parametersPanel.pnlStartPosBD.groupBox.setTitle("FAWP")
        #         self.parametersPanel.pnlFinishPosBD.degreeFormat = "ddmmss.ssssH"
        self.parametersPanel.pnlFinishPosBD.alwwaysShowString = "Degree"
        self.parametersPanel.pnlFinishPosBD.btnCalculater.hide()
        self.parametersPanel.pnlFinishPosBD.hideframe_Altitude()
        self.parametersPanel.pnlFinishPosBD.showframe_ID()
        self.parametersPanel.pnlFinishPosBD.setObjectName("pnlFinishPosBD")
        ui.verticalLayout_gbFinishPosBD.insertWidget(
            0, self.parametersPanel.pnlFinishPosBD)
        self.connect(self.parametersPanel.pnlFinishPosBD,
                     SIGNAL("positionChanged"), self.positionChangedFinishBD)

        self.parametersPanel.pnlVarFinishBD = DegreesBoxPanel(self)
        self.parametersPanel.pnlVarFinishBD.CaptionLabel = "Magnetic Variation"
        # self.parametersPanel.pnlVarFinishBD.Enabled = False
        self.connect(self.parametersPanel.pnlVarFinishBD,
                     SIGNAL("btnDegreeBoxPanel_clicked"), self.method_36_BD)
        # self.connect(self.parametersPanel.pnlVarFinishBD, SIGNAL("txtDegreeBox_textChanged"), self.txtDegreeBox_textChangedP)
        ui.verticalLayout_gbFinishPosBD.addWidget(
            self.parametersPanel.pnlVarFinishBD)

        self.parametersPanel.pnlPositionMVD = PositionPanel(
            self.parametersPanel.tabGeoDetermineMV, None, None, "Degree")
        self.parametersPanel.pnlPositionMVD.groupBox.setTitle("Position")
        self.parametersPanel.pnlPositionMVD.alwwaysShowString = "Degree"
        self.parametersPanel.pnlPositionMVD.btnCalculater.hide()
        self.parametersPanel.pnlPositionMVD.setObjectName("pnlPositionMVD")
        ui.verticalLayout_3.insertWidget(0,
                                         self.parametersPanel.pnlPositionMVD)
        self.connect(self.parametersPanel.pnlPositionMVD,
                     SIGNAL("positionChanged"), self.method_28_MVD)

        self.connect(self.parametersPanel.txtForwardTP, SIGNAL("Event_0"),
                     self.txtForwardTP_textChanged)
        self.connect(self.parametersPanel.chbAutoFinishMagVar,
                     SIGNAL("Event_0"), self.chbAutoFinishMagVar_clicked)
        self.connect(self.parametersPanel.txtDistanceP, SIGNAL("Event_0"),
                     self.autoCalcFinishMagVar)

        self.connect(self.parametersPanel.txtForwardMP, SIGNAL("Event_0"),
                     self.txtForwardMP_textChanged)
        self.parametersPanel.btnResultP.clicked.connect(
            self.btnResultP_clicked)
        self.parametersPanel.tabGeneral.currentChanged.connect(
            self.tabGeneral_CurrentChanged)
        self.parametersPanel.chbAutoVarBD.clicked.connect(
            self.chbAutoVarBD_clicked)
        self.parametersPanel.dtpDate.dateChanged.connect(self.method_28_MVD)
        self.connect(self.parametersPanel.cmbModel, SIGNAL("Event_0"),
                     self.method_28_MVD)
        self.parametersPanel.btnDtpDate.clicked.connect(
            self.btnDtpDate_clicked)

        self.resultModelP = QStandardItemModel()
        self.parametersPanel.tblResultP.setModel(self.resultModelP)

        self.resultModelBD = QStandardItemModel()
        self.parametersPanel.tblResultBD.setModel(self.resultModelBD)

        self.ttt = 0
        self.txtForwardTP_textChanged()

        self.setHistoryData()

        self.autoVarSet = False
        self.dateBD = QDate.currentDate()
        self.modelBD = MagneticModel.WMM2010
        self.parametersPanel.btnResultBD.setVisible(False)

        self.parametersPanel.dtpDate.setDate(QDate.currentDate())

        self.calendar = QCalendarWidget()
        self.calendar.clicked.connect(self.calendar_clicked)

        self.menu = QMenu()
        layout = QVBoxLayout(self.menu)
        layout.addWidget(self.calendar)

    def chbAutoFinishMagVar_clicked(self):
        if self.parametersPanel.chbAutoFinishMagVar.Checked:
            self.parametersPanel.pnlVarFinishP.Enabled = False
        else:
            self.parametersPanel.pnlVarFinishP.Enabled = True

    def calendar_clicked(self, date):
        self.parametersPanel.dtpDate.setDate(date)

    def btnDtpDate_clicked(self):
        rcRect = self.parametersPanel.btnDtpDate.geometry()
        ptPoint = rcRect.bottomLeft()
        self.menu.exec_(self.mapToGlobal(ptPoint))

    def positionChangedStartBD(self):
        if (self.parametersPanel.chbAutoVarBD.isChecked() and self.autoVarSet):
            self.method_29_BD()
        self.method_31_BD()

    def positionChangedFinishBD(self):
        if (self.parametersPanel.chbAutoVarBD.isChecked() and self.autoVarSet):
            self.method_30_BD()
        self.method_31_BD()

    def chbAutoVarBD_clicked(self):
        if (self.parametersPanel.chbAutoVarBD.isChecked()
                and not self.autoVarSet):
            result, self.dateBD, self.modelBD = DlgMagneticVariationParameters.smethod_0(
                self.dateBD, self.modelBD)
            self.parametersPanel.chbAutoVarBD.setChecked(result)
            self.autoVarSet = self.parametersPanel.chbAutoVarBD.isChecked()
        if (self.parametersPanel.chbAutoVarBD.isChecked()):
            self.method_29_BD()
            self.method_30_BD()
        self.method_31_BD()

    def tabGeneral_CurrentChanged(self):
        if self.parametersPanel.tabGeneral.currentIndex() == 0:
            self.stdItemModelHistory.clear()
            if len(GeoDetermineDlg.HistoryDataP) > 0:
                self.setDataInHistoryModel(GeoDetermineDlg.HistoryDataP, True)
                pass
        elif self.parametersPanel.tabGeneral.currentIndex() == 1:
            self.stdItemModelHistory.clear()
            if len(GeoDetermineDlg.HistoryDataBD) > 0:
                self.setDataInHistoryModel(GeoDetermineDlg.HistoryDataBD, True)
                pass
        else:
            self.stdItemModelHistory.clear()
            if len(GeoDetermineDlg.HistoryDataMV) > 0:
                self.setDataInHistoryModel(GeoDetermineDlg.HistoryDataMV, True)
                pass

    def setHistoryData(self):
        if len(self.HistoryDataP) > 0:
            self.setDataInHistoryModel(GeoDetermineDlg.HistoryDataP, True)
            pass

    def btnResultP_clicked(self):
        self.resultModelP.clear()
        self.parametersPanel.pnlVarStartP.Value = self.parametersPanel.pnlVarFinishP.Value
        self.parametersPanel.pnlVarFinishP.Value = 0.0
        self.parametersPanel.pnlStartPosP.Point3d = self.resultPoint3d

    def txtForwardTP_textChanged(self):
        if self.ttt == 0:
            self.ttt = 1
        if self.ttt == 2:
            self.ttt = 0
        if self.ttt == 1:
            try:
                value = float(self.parametersPanel.txtForwardTP.Value)
                self.parametersPanel.txtForwardMP.Value = MathHelper.smethod_3(
                    value - float(self.parametersPanel.pnlVarStartP.Value))
                self.autoCalcFinishMagVar()
            except:
                self.parametersPanel.txtForwardMP.Value = 0.0

    def txtForwardMP_textChanged(self):
        if self.ttt == 0:
            self.ttt = 2
        if self.ttt == 1:
            self.ttt = 0
        if self.ttt == 2:
            try:
                value = float(self.parametersPanel.txtForwardMP.Value)
                self.parametersPanel.txtForwardTP.Value = MathHelper.smethod_3(
                    value + float(self.parametersPanel.pnlVarStartP.Value))
            except:
                self.parametersPanel.txtForwardTP.Value = 0.0

    def txtDegreeBox_textChangedP(self):

        try:
            value = float(self.parametersPanel.txtForwardTP.Value)
            self.parametersPanel.txtForwardMP.Value = MathHelper.smethod_3(
                value - float(self.parametersPanel.pnlVarStartP.Value))
        except:
            self.parametersPanel.txtForwardMP.Value = 0.0

    def method_28_P(self, degrees_Lat, degrees_Lon):
        point3d = None
        point3d1 = None
        self.surfaceType = SurfaceTypes.GeoDeterminePosition
        flag = FlightPlanBaseDlg.btnConstruct_Click(self)
        if not flag:
            return
        if define._units == QGis.Meters:
            point3d0 = self.parametersPanel.pnlStartPosP.Point3d

            point3d = QgisHelper.CrsTransformPoint(point3d0.get_X(),
                                                   point3d0.get_Y(),
                                                   define._latLonCrs,
                                                   define._xyCrs)
            point3d1 = QgisHelper.CrsTransformPoint(degrees_Lon, degrees_Lat,
                                                    define._latLonCrs,
                                                    define._xyCrs)
        else:
            point3d = self.parametersPanel.pnlStartPosP.Point3d
            point3d1 = Point3D(degrees_Lon, degrees_Lat)

        constructionLayer = None
        mapUnits = define._canvas.mapUnits()
        if self.parametersPanel.chbMarkPointsP.isChecked():
            constructionLayer = AcadHelper.createVectorLayer(
                SurfaceTypes.GeoDeterminePosition + "_MarkPoint", QGis.Point)
            AcadHelper.setGeometryAndAttributesInLayer(constructionLayer,
                                                       point3d)
            AcadHelper.setGeometryAndAttributesInLayer(constructionLayer,
                                                       point3d1)

            # if mapUnits == QGis.Meters:
            #     constructionLayer = QgsVectorLayer("point?crs=%s"%define._xyCrs.authid (), SurfaceTypes.GeoDeterminePosition + "_MarkPoint", "memory")
            # else:
            #     constructionLayer = QgsVectorLayer("point?crs=%s"%define._latLonCrs.authid (), SurfaceTypes.GeoDeterminePosition + " MarkPoint", "memory")
            #
            # shpPath = ""
            # if define.obstaclePath != None:
            #     shpPath = define.obstaclePath
            # elif define.xmlPath != None:
            #     shpPath = define.xmlPath
            # else:
            #     shpPath = define.appPath
            # er = QgsVectorFileWriter.writeAsVectorFormat(constructionLayer, shpPath + "/" + SurfaceTypes.GeoDeterminePosition + "_MarkPoint" + ".shp", "utf-8", constructionLayer.crs())
            # constructionLayer = QgsVectorLayer(shpPath + "/" + SurfaceTypes.GeoDeterminePosition + "_MarkPoint" + ".shp", SurfaceTypes.GeoDeterminePosition + " MarkPoint", "ogr")
            #
            # constructionLayer.startEditing()
            #
            # feature = QgsFeature()
            # feature.setGeometry(QgsGeometry.fromPoint(point3d))
            # constructionLayer.addFeature(feature)
            # feature.setGeometry(QgsGeometry.fromPoint(point3d1))
            # constructionLayer.addFeature(feature)
            # constructionLayer.commitChanges()
            QgisHelper.appendToCanvas(define._canvas, [constructionLayer],
                                      SurfaceTypes.GeoDeterminePosition)

            self.resultLayerList.append(constructionLayer)
        if self.parametersPanel.chbDrawLineP.isChecked():
            constructionLayer1 = AcadHelper.createVectorLayer(
                SurfaceTypes.GeoDeterminePosition + "_Line", QGis.Line)
            AcadHelper.setGeometryAndAttributesInLayer(constructionLayer1,
                                                       [point3d, point3d1])
            QgisHelper.appendToCanvas(define._canvas, [constructionLayer1],
                                      SurfaceTypes.GeoDeterminePosition)
            self.resultLayerList.append(constructionLayer1)

    def method_28_BD(self):
        point3d = None
        point3d1 = None
        self.surfaceType = SurfaceTypes.GeoDetermineBD
        flag = FlightPlanBaseDlg.btnConstruct_Click(self)
        if not flag:
            return
        if define._units == QGis.Meters:
            point3d0 = self.parametersPanel.pnlStartPosBD.Point3d
            point3dF0 = self.parametersPanel.pnlFinishPosBD.Point3d

            point3d = QgisHelper.CrsTransformPoint(point3d0.get_X(),
                                                   point3d0.get_Y(),
                                                   define._latLonCrs,
                                                   define._xyCrs)
            point3d1 = QgisHelper.CrsTransformPoint(point3dF0.get_X(),
                                                    point3dF0.get_Y(),
                                                    define._latLonCrs,
                                                    define._xyCrs)
        else:
            point3d = self.parametersPanel.pnlStartPosBD.Point3d
            point3d1 = self.parametersPanel.pnlFinishPosBD.Point3d

        constructionLayer = None
        mapUnits = define._canvas.mapUnits()
        if self.parametersPanel.chbMarkPointsBD.isChecked():
            constructionLayer = AcadHelper.createVectorLayer(
                SurfaceTypes.GeoDetermineBD + "_MarkPoint", QGis.Point)
            AcadHelper.setGeometryAndAttributesInLayer(constructionLayer,
                                                       point3d)
            AcadHelper.setGeometryAndAttributesInLayer(constructionLayer,
                                                       point3d1)

            # if mapUnits == QGis.Meters:
            #     constructionLayer = QgsVectorLayer("point?crs=%s"%define._xyCrs.authid (), SurfaceTypes.GeoDetermineBD + "_MarkPoint", "memory")
            # else:
            #     constructionLayer = QgsVectorLayer("point?crs=%s"%define._latLonCrs.authid (), SurfaceTypes.GeoDetermineBD + " MarkPoint", "memory")
            #
            # shpPath = ""
            # if define.obstaclePath != None:
            #     shpPath = define.obstaclePath
            # elif define.xmlPath != None:
            #     shpPath = define.xmlPath
            # else:
            #     shpPath = define.appPath
            # er = QgsVectorFileWriter.writeAsVectorFormat(constructionLayer, shpPath + "/" + QString(SurfaceTypes.GeoDetermineBD).replace(" ", "") + "_MarkPoint" + ".shp", "utf-8", constructionLayer.crs())
            # constructionLayer = QgsVectorLayer(shpPath + "/" + QString(SurfaceTypes.GeoDetermineBD).replace(" ", "") + "_MarkPoint" + ".shp", SurfaceTypes.GeoDetermineBD + " MarkPoint", "ogr")
            #
            # constructionLayer.startEditing()
            #
            #
            # feature = QgsFeature()
            # feature.setGeometry(QgsGeometry.fromPoint(point3d))
            # constructionLayer.addFeature(feature)
            # feature.setGeometry(QgsGeometry.fromPoint(point3d1))
            # constructionLayer.addFeature(feature)
            # constructionLayer.commitChanges()
            QgisHelper.appendToCanvas(define._canvas, [constructionLayer],
                                      SurfaceTypes.GeoDetermineBD)
            self.resultLayerList.append(constructionLayer)
        if self.parametersPanel.chbDrawLineBD.isChecked():
            constructionLayer = AcadHelper.createVectorLayer(
                SurfaceTypes.GeoDetermineBD + "_Line", QGis.Line)
            AcadHelper.setGeometryAndAttributesInLayer(constructionLayer,
                                                       [point3d, point3d1])
            QgisHelper.appendToCanvas(define._canvas, [constructionLayer],
                                      SurfaceTypes.GeoDetermineBD)
            self.resultLayerList.append(constructionLayer)

    def method_28_MVD(self):
        self.parametersPanel.txtResult.Value = ""

    def method_29_P(self):
        self.resultModelP.clear()
        self.resultModelP.setHorizontalHeaderLabels(["Type", "Value"])

    def method_29_BD(self):
        degree = None
        degree1 = None
        degree2 = None
        if (self.parametersPanel.pnlStartPosBD.IsValid()):

            result, degree, degree1 = self.parametersPanel.pnlStartPosBD.method_3(
            )
            result, degree2 = Geo.smethod_7(degree, degree1, Altitude(0),
                                            self.modelBD, self.dateBD)
            if (result):
                degree2 = round(degree2, 2)
                self.parametersPanel.pnlVarStartBD.Value = degree2

    def method_30_BD(self):
        degree = None
        degree1 = None
        degree2 = None
        if (self.parametersPanel.pnlFinishPosBD.IsValid()):

            result, degree, degree1 = self.parametersPanel.pnlFinishPosBD.method_3(
            )
            result, degree2 = Geo.smethod_7(degree, degree1, Altitude(0),
                                            self.modelBD, self.dateBD)
            if (result):
                degree2 = round(degree2, 2)
                self.parametersPanel.pnlVarFinishBD.Value = degree2

    def method_31_BD(self):
        self.resultModelBD.clear()
        self.resultModelBD.setHorizontalHeaderLabels(["Type", "Value"])

    def method_32_P(self):
        startPos = self.parametersPanel.pnlStartPosP.Point3d
        result, self.date, self.model = DlgMagneticVariationParameters.smethod_0(
            self.date, self.model)
        if self.parametersPanel.pnlStartPosP.IsValid() and result:
            result, degree, degree1 = self.parametersPanel.pnlStartPosP.method_3(
            )
            result, degree2 = Geo.smethod_7(degree, degree1, Altitude(0),
                                            self.model, self.date)
            if (result):
                degree2 = round(degree2, 2)
                self.parametersPanel.pnlVarStartP.Value = degree2
                try:
                    self.parametersPanel.txtForwardMP.Value = MathHelper.smethod_3(
                        float(self.parametersPanel.txtForwardTP.Value) -
                        degree2)
                except:
                    self.parametersPanel.txtForwardMP.Value = 0.0
                self.method_29_P()

    def method_34_BD(self):
        startPos = self.parametersPanel.pnlStartPosBD.Point3d
        result, self.dateBD, self.modelBD = DlgMagneticVariationParameters.smethod_0(
            self.dateBD, self.modelBD)
        if self.parametersPanel.pnlStartPosBD.IsValid() and result:
            self.method_29_BD()
            self.method_31_BD()

    def method_36_BD(self):
        startPos = self.parametersPanel.pnlFinishPosBD.Point3d
        result, self.dateBD, self.modelBD = DlgMagneticVariationParameters.smethod_0(
            self.dateBD, self.modelBD)
        if self.parametersPanel.pnlFinishPosBD.IsValid() and result:
            self.method_30_BD()
            self.method_31_BD()
Exemple #54
0
class Regression_PLOT_PyQt(QDialog):
    """
    This calss return a PyQt GUI with a regression plot
    """
    def __init__(self, Minerals=None, string=None, flag=None):
        super(Regression_PLOT_PyQt, self).__init__()
        if string is not None:
            self.stringK, self.stringG, self.stringRho, self.user_input = string
        else:
            self.stringK = None
            self.stringG = None
            self.stringRho = None
            self.user_input = False
        self.resize(1400, 600)
        self.Minerals = Minerals

        self.dirty = False
        #self.user_input = user_input

        self.Minerals.original_flag()
        self.Minerals.read_data()
        self.table = QTableView()
        self.model = QStandardItemModel(25, 7, self)
        self.model.setHorizontalHeaderLabels([
            'flag', 'Water Content', 'Iron Content', 'K (Gpa)', 'G (Gpa)',
            'Rho (g/cm³)', 'Reference'
        ])
        for i in range(len(self.Minerals.Flag)):
            a = self.Minerals.Return_original_data(i)
            for j in range(0, 7):
                item = QStandardItem(str(a[j]))
                self.model.setItem(i, j, item)
                if j != 0:
                    item.setFlags(Qt.ItemIsEnabled)
                    item.setBackground(QColor(211, 211, 211))

        if flag is not None:
            self.Minerals.change_flag(flag)
            for i in range(len(self.Minerals.Flag)):
                item = QStandardItem(str(self.Minerals.Flag[i]))
                self.model.setItem(i, 0, item)

        self.table.setModel(self.model)

        self.button = QPushButton('Update and use in thermoelastic model')
        self.button.clicked.connect(self.Update)
        self.button.setAutoDefault(False)
        self.button1 = QPushButton('Add data file ')
        self.button1.clicked.connect(self.Export)
        self.button1.setAutoDefault(False)
        self.layout = QGridLayout()

        self.label = QLabel()
        self.label.setText('''
        Please input equation, Water: water content (wt%) and Fe: iron content (mol%)
        for example -2.41*Water-30*Fe+81,K'=4.1,  
        ''')

        self.Kinput_formula = QLineEdit()
        self.Ginput_formula = QLineEdit()
        self.Rhoinput_formula = QLineEdit()
        if self.stringK is not None:
            self.Kinput_formula.setText(self.stringK)
            self.Ginput_formula.setText(self.stringG)
            self.Rhoinput_formula.setText(self.stringRho)
            self.Userinput()
        else:
            self.Kinput_formula.setText(
                self.Minerals.Show_fit_function(self.Minerals.function_K()[0],
                                                self.Minerals.function_K()[1],
                                                "K'",
                                                error=False))
            self.Ginput_formula.setText(
                self.Minerals.Show_fit_function(self.Minerals.function_G()[0],
                                                self.Minerals.function_G()[1],
                                                "G'",
                                                error=False))
            self.Rhoinput_formula.setText(
                self.Minerals.Show_fit_function(
                    self.Minerals.function_Rho()[0],
                    self.Minerals.function_Rho()[1],
                    '',
                    error=False))
        self.Kinput_formula.returnPressed.connect(self.Kformula)
        self.Ginput_formula.returnPressed.connect(self.Gformula)
        self.Rhoinput_formula.returnPressed.connect(self.Rhoformula)
        #self.connect(self.Kinput_formula,SIGNAL("returnPressed()"),self.Kformula)
        #self.connect(self.Ginput_formula,SIGNAL("returnPressed()"),self.Gformula)
        #self.connect(self.Rhoinput_formula,SIGNAL("returnPressed()"),self.Rhoformula)

        self.user_change_confrim = QPushButton('Change to user input')
        self.user_change_confrim.clicked.connect(self.Userinput)
        self.user_change_confrim.setAutoDefault(False)

        self.extension = QWidget()
        self.extensionLayout = QGridLayout()
        self.extensionLayout.setContentsMargins(0, 0, 0, 0)

        labelK = QLabel()
        labelK.setText('K<sub>0</sub>=')
        labelG = QLabel()
        labelG.setText('G<sub>0</sub>=')
        labelRho = QLabel()
        labelRho.setText('Rho<sub>0</sub>=')

        self.extensionLayout.addWidget(labelK, 0, 0, 1, 3)
        self.extensionLayout.addWidget(labelG, 1, 0, 1, 3)
        self.extensionLayout.addWidget(labelRho, 2, 0, 1, 3)
        self.extensionLayout.addWidget(self.Kinput_formula, 0, 1, 1, 3)
        self.extensionLayout.addWidget(self.Ginput_formula, 1, 1, 1, 3)
        self.extensionLayout.addWidget(self.Rhoinput_formula, 2, 1, 1, 3)
        self.extensionLayout.addWidget(self.user_change_confrim, 3, 0, 9, 4)

        self.extension.setLayout(self.extensionLayout)

        self.check_change = QCheckBox("user input")
        self.check_change.setChecked(False)
        self.check_change.toggled.connect(self.extension.setVisible)

        #self.PLOT(switch=True)
        self.PLOT()
        self.layout.addWidget(self.table, 0, 1, 1, 17)
        self.layout.addWidget(self.button, 2, 0, 1, 9)
        self.layout.addWidget(self.button1, 2, 9, 1, 9)
        self.layout.addWidget(self.check_change, 3, 0, 1, 1)
        self.layout.addWidget(self.label, 3, 3, 1, 5)
        self.layout.addWidget(self.extension, 4, 0, 1, 9)
        self.setLayout(self.layout)

        self.extension.hide()

    def Kformula(self):
        self.stringK = str(self.Kinput_formula.text())
        self.K0 = np.array(
            re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?",
                       self.stringK))
        return self.K0, self.stringK

    def Gformula(self):
        self.stringG = str(self.Ginput_formula.text())
        self.G0 = np.array(
            re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?",
                       self.stringG))
        return self.G0, self.stringG

    def Rhoformula(self):
        self.stringRho = str(self.Rhoinput_formula.text())
        self.Rho0 = np.array(
            re.findall(r"[+-]? *(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?",
                       self.stringRho))
        return self.Rho0, self.stringRho

    def Userinput(self):
        self.Minerals.User_Change(self.Kformula(), self.Gformula(),
                                  self.Rhoformula())
        self.user_input = True
        self.PLOT()

    def PLOT(self, switch=True):
        if self.dirty == False:
            #self.Minerals.Clean_content()
            params = []
            for i in range(20):
                index = self.model.index(i, 0)
                try:
                    aa = (float(self.model.itemData(index)[0]))
                    #print (aa)
                    params.append(aa)
                except:
                    break
            #print (params)
            self.Minerals.Change_data_from_table(params)
            #print ('wf')
        else:
            self.model.setHorizontalHeaderLabels([
                'flag', 'Water Content', 'Iron Content', 'K (Gpa)', 'G (Gpa)',
                'Rho (g/cm3)', 'Reference'
            ])
            for i in range(len(self.Minerals.Flag)):
                #a=self.Minerals.Return_original_data(i)
                item = QStandardItem(str(self.Minerals.Flag[i]))
                self.model.setItem(i, 0, item)


#==============================================================================
#                 for j in range(1,7):
#                     item = QStandardItem(str(a[j]))
#                     self.model.setItem(i, j,item)
#                     if j != 0:
#                         item.setFlags(Qt.ItemIsEnabled)
#                         item.setBackground(QColor(211,211,211))
#==============================================================================

#print (self.Minerals.Change)

        if self.user_input == False:
            self.a, self.b, self.c = self.Minerals.PLOT(return_fig=False)
            #print (self.Minerals.number_of_data)
            self.Kinput_formula.setText(
                self.Minerals.Show_fit_function(self.Minerals.function_K()[0],
                                                self.Minerals.function_K()[1],
                                                "K'",
                                                error=False))
            self.Ginput_formula.setText(
                self.Minerals.Show_fit_function(self.Minerals.function_G()[0],
                                                self.Minerals.function_G()[1],
                                                "G'",
                                                error=False))
            self.Rhoinput_formula.setText(
                self.Minerals.Show_fit_function(
                    self.Minerals.function_Rho()[0],
                    self.Minerals.function_Rho()[1],
                    '',
                    error=False))

        else:
            self.a, self.b, self.c = self.Minerals.PLOT_input_formula(
                return_fig=False)

        self.canvas1 = FigureCanvas3D(self.a)
        self.canvas2 = FigureCanvas3D(self.b)
        self.canvas3 = FigureCanvas3D(self.c)
        self.canvas1.mpl_connect('pick_event', self.onpick)
        self.canvas2.mpl_connect('pick_event', self.onpick)
        self.canvas3.mpl_connect('pick_event', self.onpick)

        self.toolbar1 = NavigationToolbar(self.canvas1, self)
        self.toolbar2 = NavigationToolbar(self.canvas2, self)
        self.toolbar3 = NavigationToolbar(self.canvas3, self)

        self.layout1_widget = QWidget()
        self.layout1 = QGridLayout(self.layout1_widget)
        self.layout1_widget.setFixedSize(600, 600)
        self.layout1.addWidget(self.canvas1, 0, 1, 5, 5)
        self.layout1.addWidget(self.toolbar1, 5, 1, 1, 5)
        self.layout1.addWidget(self.canvas2, 6, 1, 5, 5)
        self.layout1.addWidget(self.toolbar2, 11, 1, 1, 5)
        self.layout1.addWidget(self.canvas3, 12, 1, 5, 5)
        self.layout1.addWidget(self.toolbar3, 17, 1, 1, 5)
        self.layout.addWidget(self.layout1_widget, 0, 0, 1, 1)

    def onpick(self, event):
        try:
            for i in range(6):
                self.model.item(self.ind,
                                i + 1).setBackground(QColor(211, 211, 211))
        except:
            pass

        count = -1
        for j in range(len((self.Minerals.Flag))):
            if self.Minerals.Flag[j] == 1:
                count += 1
                if count == event.ind[0]:
                    self.ind = j
                    break
        #print (self.ind)
        #self.ind = event.ind
        for i in range(6):
            self.model.item(self.ind,
                            i + 1).setBackground(QColor(111, 111, 111))

    def Update(self):
        self.user_input = False
        self.dirty = False
        self.check_change.setChecked(False)
        self.PLOT()

    def Export(self):
        self.dirty = True
        dialog = TextEditor(name=self.Minerals.name)
        if dialog.exec_():
            pass
        self.Minerals.read_data()
        self.PLOT()

    def ReturnString(self):
        aa = self.Minerals.Flag
        bb = str(int(aa[0]))
        for i in range(1, len(aa)):
            bb += str(int(aa[i]))
        return [self.stringK, self.stringG, self.stringRho,
                self.user_input], bb
Exemple #55
0
def main(icon_spec):
    app = QApplication(sys.argv)

    main_window = QMainWindow()

    def sigint_handler(*args):
        main_window.close()

    signal.signal(signal.SIGINT, sigint_handler)
    # the timer enables triggering the sigint_handler
    signal_timer = QTimer()
    signal_timer.start(100)
    signal_timer.timeout.connect(lambda: None)

    tool_bar = QToolBar()
    main_window.addToolBar(Qt.TopToolBarArea, tool_bar)

    table_view = QTableView()
    table_view.setSelectionBehavior(QAbstractItemView.SelectRows)
    table_view.setSelectionMode(QAbstractItemView.SingleSelection)
    table_view.setSortingEnabled(True)
    main_window.setCentralWidget(table_view)

    proxy_model = QSortFilterProxyModel()
    proxy_model.setFilterCaseSensitivity(Qt.CaseInsensitive)
    proxy_model.setFilterKeyColumn(1)
    table_view.setModel(proxy_model)
    proxy_model.layoutChanged.connect(table_view.resizeRowsToContents)

    item_model = QStandardItemModel()
    proxy_model.setSourceModel(item_model)

    # get all icons and their available sizes
    QIcon.setThemeName("gnome")
    icons = []
    all_sizes = set([])
    for context, icon_names in icon_spec:
        for icon_name in icon_names:
            icon = QIcon.fromTheme(icon_name)
            sizes = []
            for size in icon.availableSizes():
                size = (size.width(), size.height())
                sizes.append(size)
                all_sizes.add(size)
            sizes.sort()
            icons.append({
                'context': context,
                'icon_name': icon_name,
                'icon': icon,
                'sizes': sizes,
            })
    all_sizes = list(all_sizes)
    all_sizes.sort()

    # input field for filter
    def filter_changed(value):
        proxy_model.setFilterRegExp(value)
        table_view.resizeRowsToContents()

    filter_line_edit = QLineEdit()
    filter_line_edit.setMaximumWidth(200)
    filter_line_edit.setPlaceholderText('Filter name')
    filter_line_edit.setToolTip(
        'Filter name optionally using regular expressions (' +
        QKeySequence(QKeySequence.Find).toString() + ')')
    filter_line_edit.textChanged.connect(filter_changed)
    tool_bar.addWidget(filter_line_edit)

    # actions to toggle visibility of available sizes/columns
    def action_toggled(index):
        column = 2 + index
        table_view.setColumnHidden(column,
                                   not table_view.isColumnHidden(column))
        table_view.resizeColumnsToContents()
        table_view.resizeRowsToContents()

    signal_mapper = QSignalMapper()
    for i, size in enumerate(all_sizes):
        action = QAction('%dx%d' % size, tool_bar)
        action.setCheckable(True)
        action.setChecked(True)
        tool_bar.addAction(action)
        action.toggled.connect(signal_mapper.map)
        signal_mapper.setMapping(action, i)
        # set tool tip and handle key sequence
        tool_tip = 'Toggle visibility of column'
        if i < 10:
            digit = ('%d' % (i + 1))[-1]
            tool_tip += ' (%s)' % QKeySequence('Ctrl+%s' % digit).toString()
        action.setToolTip(tool_tip)
    signal_mapper.mapped.connect(action_toggled)

    # label columns
    header_labels = ['context', 'name']
    for width, height in all_sizes:
        header_labels.append('%dx%d' % (width, height))
    item_model.setColumnCount(len(header_labels))
    item_model.setHorizontalHeaderLabels(header_labels)

    # fill rows
    item_model.setRowCount(len(icons))
    for row, icon_data in enumerate(icons):
        # context
        item = QStandardItem(icon_data['context'])
        item.setFlags(item.flags() ^ Qt.ItemIsEditable)
        item_model.setItem(row, 0, item)
        # icon name
        item = QStandardItem(icon_data['icon_name'])
        item.setFlags(item.flags() ^ Qt.ItemIsEditable)
        item_model.setItem(row, 1, item)
        for index_in_all_sizes, size in enumerate(all_sizes):
            column = 2 + index_in_all_sizes
            if size in icon_data['sizes']:
                # icon as pixmap to keep specific size
                item = QStandardItem('')
                pixmap = icon_data['icon'].pixmap(size[0], size[1])
                item.setData(pixmap, Qt.DecorationRole)
                item.setFlags(item.flags() ^ Qt.ItemIsEditable)
                item_model.setItem(row, column, item)
            else:
                # single space to be sortable against icons
                item = QStandardItem(' ')
                item.setFlags(item.flags() ^ Qt.ItemIsEditable)
                item_model.setItem(row, column, item)

    table_view.resizeColumnsToContents()
    # manually set row heights because resizeRowsToContents is not working properly
    for row, icon_data in enumerate(icons):
        if len(icon_data['sizes']) > 0:
            max_size = icon_data['sizes'][-1]
            table_view.setRowHeight(row, max_size[1])

    # enable focus find (ctrl+f) and toggle columns (ctrl+NUM)
    def main_window_keyPressEvent(self,
                                  event,
                                  old_keyPressEvent=QMainWindow.keyPressEvent):
        if event.matches(QKeySequence.Find):
            filter_line_edit.setFocus()
            return
        if event.modifiers() == Qt.ControlModifier and event.key(
        ) >= Qt.Key_0 and event.key() <= Qt.Key_9:
            index = event.key() - Qt.Key_1
            if event.key() == Qt.Key_0:
                index += 10
            action = signal_mapper.mapping(index)
            if action:
                action.toggle()
                return
        old_keyPressEvent(self, event)

    main_window.keyPressEvent = new.instancemethod(main_window_keyPressEvent,
                                                   table_view, None)

    # enable copy (ctrl+c) name of icon to clipboard
    def table_view_keyPressEvent(self,
                                 event,
                                 old_keyPressEvent=QTableView.keyPressEvent):
        if event.matches(QKeySequence.Copy):
            selection_model = self.selectionModel()
            if selection_model.hasSelection():
                index = selection_model.selectedRows()[0]
                source_index = self.model().mapToSource(index)
                item = self.model().sourceModel().item(source_index.row(), 1)
                icon_name = item.data(Qt.EditRole)
                app.clipboard().setText(icon_name.toString())
                return
        old_keyPressEvent(self, event)

    table_view.keyPressEvent = new.instancemethod(table_view_keyPressEvent,
                                                  table_view, None)
    print 'Icon Theme: ', QIcon.themeName()

    print 'Theme Search Paths:'
    for item in QIcon.themeSearchPaths():
        print item
    main_window.showMaximized()
    return app.exec_()
Exemple #56
0
class ConfigDialog(BASE, WIDGET):

    def __init__(self, toolbox):
        super(ConfigDialog, self).__init__(None)
        self.setupUi(self)

        self.toolbox = toolbox
        self.groupIcon = QIcon()
        self.groupIcon.addPixmap(self.style().standardPixmap(
            QStyle.SP_DirClosedIcon), QIcon.Normal, QIcon.Off)
        self.groupIcon.addPixmap(self.style().standardPixmap(
            QStyle.SP_DirOpenIcon), QIcon.Normal, QIcon.On)

        if hasattr(self.searchBox, 'setPlaceholderText'):
            self.searchBox.setPlaceholderText(self.tr('Search...'))

        self.model = QStandardItemModel()
        self.tree.setModel(self.model)

        self.delegate = SettingDelegate()
        self.tree.setItemDelegateForColumn(1, self.delegate)

        self.searchBox.textChanged.connect(self.fillTree)

        self.fillTree()

        self.tree.expanded.connect(self.adjustColumns)

    def fillTree(self):
        self.items = {}
        self.model.clear()
        self.model.setHorizontalHeaderLabels([self.tr('Setting'),
                                              self.tr('Value')])

        text = unicode(self.searchBox.text())
        settings = ProcessingConfig.getSettings()

        rootItem = self.model.invisibleRootItem()
        priorityKeys = [self.tr('General'), self.tr('Models'), self.tr('Scripts')]
        for group in priorityKeys:
            groupItem = QStandardItem(group)
            icon = ProcessingConfig.getGroupIcon(group)
            groupItem.setIcon(icon)
            groupItem.setEditable(False)
            emptyItem = QStandardItem()
            emptyItem.setEditable(False)
            rootItem.insertRow(0, [groupItem, emptyItem])
            for setting in settings[group]:
                if setting.hidden:
                    continue

                if text == '' or text.lower() in setting.description.lower():
                    labelItem = QStandardItem(setting.description)
                    labelItem.setIcon(icon)
                    labelItem.setEditable(False)
                    self.items[setting] = SettingItem(setting)
                    groupItem.insertRow(0, [labelItem, self.items[setting]])

            if text != '':
                self.tree.expand(groupItem.index())

        providersItem = QStandardItem(self.tr('Providers'))
        icon = QIcon(os.path.join(pluginPath, 'images', 'alg.png'))
        providersItem.setIcon(icon)
        providersItem.setEditable(False)
        emptyItem = QStandardItem()
        emptyItem.setEditable(False)
        rootItem.insertRow(0, [providersItem, emptyItem])
        for group in settings.keys():
            if group in priorityKeys:
                continue

            groupItem = QStandardItem(group)
            icon = ProcessingConfig.getGroupIcon(group)
            groupItem.setIcon(icon)
            groupItem.setEditable(False)
            for setting in settings[group]:
                if setting.hidden:
                    continue

                if text == '' or text.lower() in setting.description.lower():
                    labelItem = QStandardItem(setting.description)
                    labelItem.setIcon(icon)
                    labelItem.setEditable(False)
                    self.items[setting] = SettingItem(setting)
                    groupItem.insertRow(0, [labelItem, self.items[setting]])

            emptyItem = QStandardItem()
            emptyItem.setEditable(False)
            providersItem.appendRow([groupItem, emptyItem])

        self.tree.sortByColumn(0, Qt.AscendingOrder)
        self.adjustColumns()

    def accept(self):
        for setting in self.items.keys():
            if isinstance(setting.value, bool):
                setting.value = self.items[setting].checkState() == Qt.Checked
            elif isinstance(setting.value, (float, int, long)):
                value = unicode(self.items[setting].text())
                try:
                    value = float(value)
                    setting.value = value
                except ValueError:
                    QMessageBox.critical(self, self.tr('Wrong value'),
                                         self.tr('Wrong parameter value:\n%1') % value)
                    return
            else:
                setting.value = unicode(self.items[setting].text())
            setting.save()
        Processing.updateAlgsList()

        QDialog.accept(self)

    def adjustColumns(self):
        self.tree.resizeColumnToContents(0)
        self.tree.resizeColumnToContents(1)
class SharedSqlQueries:
    """QGIS Plugin Implementation."""

    def __init__(self, iface):
        """Constructor.

        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        self.iface = iface

        # initialize plugin directory
        self.plugin_dir = os.path.dirname(__file__)

        # initialize locale UNUSED
        # locale = QSettings().value('locale/userLocale')[0:2]
        # locale_path = os.path.join(
        #     self.plugin_dir,
        #     'i18n',
        #     'SharedSqlQueries_{}.qm'.format(locale))
        #
        # if os.path.exists(locale_path):
        #     self.translator = QTranslator()
        #     self.translator.load(locale_path)
        #
        #     if qVersion() > '4.3.3':
        #         QCoreApplication.installTranslator(self.translator)

        # Declare instance attributes
        self.actions = []
        self.menu = self.tr(u'&Shared SQL Queries')

        self.toolbar = self.iface.addToolBar(u'SharedSqlQueries')
        self.toolbar.setObjectName(u'SharedSqlQueries')

        #print "** INITIALIZING SharedSqlQueries"

        #self.dockwidget = None

        #combo of queries files
        self.comboxQueries = None

        self.config = None
        self.queriesFolder = None
        self.dbrequest = None

        self.selectedQueryPath = None

        self.pluginIsActive = False

    # init related to config file. Return False if no config.json has been found
    def init_config(self):

        #just once
        if self.config is not None:
            return True

        #config file (in plugin directory) :
        configpath = os.path.dirname(__file__) + '/config.json'
        try:
            self.config = JsonFile(configpath)
        except IOError:
            # copy default config json if it does not exist
            self.errorMessage(self.tr(
                u"No config.json file found ! A default one is created but you have to edit it (in your plugin directory)"))
            configpath_default = os.path.dirname(__file__) + '/config_default.json'
            copyfile(configpath_default, configpath)
            return False

        self.queriesFolder = self.config.value("queries_folder")

        #database
        self.dbrequest = Connection(self.config.value("bdpostgis"))

        return True


    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.

        We implement this ourselves since we do not inherit QObject.

        :param message: String for translation.
        :type message: str, QString

        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        #return QCoreApplication.translate('SharedSqlQueries', message)

        return translate.tr(message) #simplier


    def add_action(
        self,
        icon_path,
        text,
        callback,
        enabled_flag=True,
        add_to_menu=True,
        add_to_toolbar=True,
        status_tip=None,
        whats_this=None,
        parent=None):
        """Add a toolbar icon to the toolbar.

        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str

        :param text: Text that should be shown in menu items for this action.
        :type text: str

        :param callback: Function to be called when the action is triggered.
        :type callback: function

        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool

        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool

        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool

        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str

        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget

        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.

        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """

        icon = QIcon(icon_path)
        action = QAction(icon, text, parent)
        action.triggered.connect(callback)
        action.setEnabled(enabled_flag)

        if status_tip is not None:
            action.setStatusTip(status_tip)

        if whats_this is not None:
            action.setWhatsThis(whats_this)

        if add_to_toolbar:
            self.toolbar.addAction(action)

        if add_to_menu:
            self.iface.addPluginToMenu(
                self.menu,
                action)

        self.actions.append(action)

        return action


    def initGui(self):
        """Create the menu entries and toolbar icons inside the QGIS GUI."""

        icon_path = ':/plugins/SharedSqlQueries/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'Shared SQL Queries'),
            callback=self.run,
            parent=self.iface.mainWindow())

        #combo of queries files
        self.comboxQueries = QComboBox()
        self.comboxQueries.setMinimumHeight(27)
        self.comboxQueries.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

        # its model :
        self.queriesModel = QStandardItemModel()
        self.comboxQueries.setModel(self.queriesModel)

        # and its view (treeview) :
        self.queriesView = QTreeView()
        self.queriesView.setHeaderHidden(True)
        self.queriesView.setMinimumHeight(300)
        setWidgetWidth(self.comboxQueries, 0, 0) #no visible
        self.comboxQueries.setView(self.queriesView)

        # capture last clicked query
        self.queriesView.activated.connect(self.querySelected)
        self.queriesView.pressed.connect(self.querySelected)




        self.toolbar.addWidget(self.comboxQueries)

        #Run query button
        self.buttonRunQuery = QPushButton(self.tr("Open"))
        setWidgetWidth(self.buttonRunQuery, 0, 0) #no visible
        self.buttonRunQuery.clicked.connect(self.runQuery)

        self.toolbar.addWidget(self.buttonRunQuery)





    #--------------------------------------------------------------------------

    def onClosePlugin(self):
        """Cleanup necessary items here when plugin dockwidget is closed"""

        #print "** CLOSING SharedSqlQueries"

        # disconnects
        #self.dockwidget.closingPlugin.disconnect(self.onClosePlugin)

        self.pluginIsActive = False


    def unload(self):
        """Removes the plugin menu item and icon from QGIS GUI."""

        #print "** UNLOAD SharedSqlQueries"

        for action in self.actions:
            self.iface.removePluginMenu(
                self.tr(u'Shared SQL Queries'),
                action)
            self.iface.removeToolBarIcon(action)
        # remove the toolbar
        del self.toolbar

    #--------------------------------------------------------------------------

    def run(self):
        """Run method that loads and starts the plugin"""

        # look for config file (required at the first run)
        if not self.init_config():
            # invalid config file
            return

        if not self.pluginIsActive:
            self.pluginIsActive = True

            #first init

            #print "** STARTING SharedSqlQueries"

            # dockwidget may not exist if:
            #    first run of plugin
            #    removed on close (see self.onClosePlugin method)
            #if self.dockwidget == None:
                # Create the dockwidget (after translation) and keep reference
            #    self.dockwidget = SharedSqlQueriesDockWidget()

            # connect to provide cleanup on closing of dockwidget
            #self.dockwidget.closingPlugin.connect(self.onClosePlugin)

            # show the dockwidget
            #self.iface.addDockWidget(Qt.TopDockWidgetArea, self.dockwidget)
            #self.dockwidget.show()

        #Togle visibility of toolbar options (set width coz visible is not usable in toolbar)
        show_options = (self.comboxQueries.minimumWidth() == 0)
        if show_options:
            self.updateComboQueries()
            setWidgetWidth(self.comboxQueries, 300, 300)
            setWidgetWidth(self.buttonRunQuery, 0, 120)
        else:
            setWidgetWidth(self.comboxQueries, 0, 0)
            setWidgetWidth(self.buttonRunQuery, 0, 0)


    #display an error
    def errorMessage(self, message):
        self.iface.messageBar().pushMessage(self.tr(u"Error"), message, level=QgsMessageBar.CRITICAL)

    #read file in query folder and show them in combo tree view
    def updateComboQueries(self):
        self.queriesModel.clear()
        self.queriesModel.setHorizontalHeaderLabels(['Files'])

        item = QStandardItem(self.tr(u"Query File"))
        item.setSelectable(False)
        self.queriesModel.appendRow(item)

        # read directories with sql files
        for path, dirs, files in os.walk(self.queriesFolder):
            for rep in dirs:
                item = QStandardItem(rep)
                item.setData(rep, Qt.UserRole)
                item.setSelectable(False)
                self.queriesModel.appendRow(item)
                # in each directory, look for sql files
                for nomfich in glob.glob(self.queriesFolder + "/" + rep + "/*.sql"):
                    fileName, fileExtension = os.path.splitext(os.path.basename(nomfich))

                    # one item found
                    subitem = QStandardItem(fileName)
                    subitem.setData(nomfich, Qt.UserRole)

                    item.appendRow(subitem)



    #last selected query
    def querySelected(self, index):
        item = self.queriesModel.itemFromIndex(index)
        self.selectedQueryPath = item.data(Qt.UserRole)

    #run selected query
    def runQuery(self):
        #print self.comboxQueries.currentText()
        #print self.selectedQueryPath

        try:
            query = CustomSqlQuery(self.selectedQueryPath)
        except UnicodeDecodeError:
            self.errorMessage(self.tr(u"Query File is not UTF8 encoded ! Please convert it to UTF8 !"))
            return
        except SyntaxError as e:
            self.errorMessage(e.text)
            return
        except Exception as e:
            self.errorMessage(str(e))
            return

        # open param dialog
        dialog = QueryParamDialog(self.iface, self.dbrequest, query, self.toolbar)
        if dialog.exec_() == QDialog.Accepted:

            if dialog.errorMessage != "":
                self.errorMessage(dialog.errorMessage)
                return

            # format query as a Qgis readable sql source
            sql = query.updateFinalSql()

            QgsMessageLog.logMessage(sql, "SharedSql", QgsMessageLog.INFO)

            # add the corresponding layer
            try:

                # save query in a memory layer
                if query.headerValue("layer storage") == "memory":
                    layer = self.dbrequest.sqlAddMemoryLayer(sql, query.headerValue("layer name"), query.headerValue("gid"), query.headerValue("geom"))

                # save query directly as a sql layer
                elif query.headerValue("layer storage") == "source":
                    layer = self.dbrequest.sqlAddLayer(sql, query.headerValue("layer name"), query.headerValue("gid"), query.headerValue("geom"))

                # save query in a file layer
                else:
                    type = query.headerValue("layer storage").lower()
                    driver = None
                    if type == "geojson":
                        driver = "GeoJSON"
                    if type == "shp":
                        driver = "ESRI Shapefile"

                    if driver is None:
                        self.errorMessage(self.tr(u"Unknown file type : ") + str(type))
                        return

                    directory = query.headerValue("layer directory")
                    if directory is None:
                        self.errorMessage(self.tr(u"No layer directory parameter found in query !"))
                        return
                    name = query.headerValue("layer name")

                    # new layer name and file name if file already exists
                    filepath = directory + "/" + name + "." + type
                    filecount = 1
                    new_name = name
                    while os.path.exists(filepath):
                        # file already exists
                        filecount += 1
                        new_name = name + "_" + str(filecount)
                        filepath = directory + "/" + new_name + "." + type
                    name = new_name


                    #wait cursor
                    QApplication.setOverrideCursor(Qt.WaitCursor)

                    # add new layer
                    layer = self.dbrequest.sqlAddFileLayer(sql, driver, filepath, name,
                                    query.headerValue("gid"), query.headerValue("geom"))

                    QApplication.setOverrideCursor(Qt.ArrowCursor)



            except SyntaxError as e:
                QApplication.setOverrideCursor(Qt.ArrowCursor)
                # sql is correct but does not fit QGIS requirement (like '%' char)
                self.errorMessage(self.tr(e.text))
                return

            if layer is None:
                self.errorMessage(self.tr(u"Unable to add a layer corresponding to this query !") + sql)
                # sql which is used in layer query
                print makeSqlValidForLayer(sql)
                return

            # if there's a qml style file corresponding to the query, apply it to the newly added layer
            if os.path.exists(query.styleFilePath()):
                layer.loadNamedStyle(query.styleFilePath())