예제 #1
0
class GroupPhotoWindow(QMainWindow, Ui_main_win):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)

        self.image_model = QStandardItemModel()
        self.image_list.setModel(self.image_model)

        QObject.connect(self.add_btn, QtCore.SIGNAL('clicked()'),
                        self.on_add_image)
        QObject.connect(self.delete_btn, QtCore.SIGNAL('clicked()'),
                        self.on_remove_image)
        QObject.connect(
            self.image_list.selectionModel(),
            QtCore.SIGNAL(
                'currentChanged (const QModelIndex &, const QModelIndex &)'),
            self.on_row_changed)
        QObject.connect(self.harris_btn, QtCore.SIGNAL('clicked()'),
                        self.on_harris_detect)
        QObject.connect(self.stitch_btn, QtCore.SIGNAL('clicked()'),
                        self.on_stitch)

    def on_add_image(self):
        image_path = QFileDialog.getOpenFileName(
            self, 'Select image', filter='Images (*.png *.jpg *.bmp)')
        ignored, name = os.path.split(unicode(image_path))
        self.image_model.appendRow(
            [QStandardItem(name),
             QStandardItem(image_path)])

    def on_remove_image(self):
        row = self.image_list.selectionModel().currentIndex().row()
        if row == -1:
            return
        self.image_model.removeRows(row, 1)

    def on_row_changed(self, current, previous):
        row = current.row()
        if row == -1:
            file_path = PLACE_HOLDER
        else:
            file_path = self.image_model.item(row, 1).text()
        self.set_pixmap(QPixmap(file_path))

    def on_harris_detect(self):
        row = self.image_list.selectionModel().currentIndex().row()
        if row == -1:
            return
        file_path = self.image_model.item(row, 1).text()

        image_pfm = convert_to_pfm(imread(unicode(file_path)))
        image = image_to_gray(image_pfm)
        kernel = self.ksize_slider.value()
        cornerness = harris_corner(image, ksize=kernel)
        is_corner = cornerness > 0.000001
        suppress = non_max_suppression(cornerness, ksize=kernel)
        result = np.array(is_corner * suppress)
        zero = np.zeros_like(result)
        gray_img = np.dstack((zero, zero, draw_cross(result)))

        self.set_pixmap(
            QPixmap.fromImage(
                image_from_ndarray(np.array(gray_img + image_pfm))))

    def on_stitch(self):
        i = 0
        images = []
        while self.image_model.item(i):
            file_path = self.image_model.item(i, 1).text()
            image = image_to_gray(convert_to_pfm(imread(unicode(file_path))))
            images.append(image)
            i += 1
        stitch(self.ksize_slider.value(), images)

    def set_pixmap(self, pixmap):
        self.image_label.setPixmap(
            pixmap.scaled(self.image_label.size(), QtCore.Qt.KeepAspectRatio))
예제 #2
0
파일: gui.py 프로젝트: imclab/GroupPhoto
class GroupPhotoWindow(QMainWindow, Ui_main_win):

    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)

        self.image_model = QStandardItemModel()
        self.image_list.setModel(self.image_model)

        QObject.connect(self.add_btn, QtCore.SIGNAL('clicked()'), self.on_add_image)
        QObject.connect(self.delete_btn, QtCore.SIGNAL('clicked()'), self.on_remove_image)
        QObject.connect(self.image_list.selectionModel(), QtCore.SIGNAL(
            'currentChanged (const QModelIndex &, const QModelIndex &)'), self.on_row_changed)
        QObject.connect(self.harris_btn, QtCore.SIGNAL('clicked()'), self.on_harris_detect)
        QObject.connect(self.stitch_btn, QtCore.SIGNAL('clicked()'), self.on_stitch)

    def on_add_image(self):
        image_path = QFileDialog.getOpenFileName(self, 'Select image', filter='Images (*.png *.jpg *.bmp)')
        ignored, name = os.path.split(unicode(image_path))
        self.image_model.appendRow([QStandardItem(name), QStandardItem(image_path)])

    def on_remove_image(self):
        row = self.image_list.selectionModel().currentIndex().row()
        if row == -1:
            return
        self.image_model.removeRows(row, 1)

    def on_row_changed(self, current, previous):
        row = current.row()
        if row == -1:
            file_path = PLACE_HOLDER
        else:
            file_path = self.image_model.item(row, 1).text()
        self.set_pixmap(QPixmap(file_path))

    def on_harris_detect(self):
        row = self.image_list.selectionModel().currentIndex().row()
        if row == -1:
            return
        file_path = self.image_model.item(row, 1).text()

        image_pfm = convert_to_pfm(imread(unicode(file_path)))
        image = image_to_gray(image_pfm)
        kernel = self.ksize_slider.value()
        cornerness = harris_corner(image, ksize=kernel)
        is_corner = cornerness > 0.000001
        suppress = non_max_suppression(cornerness, ksize=kernel)
        result = np.array(is_corner * suppress)
        zero = np.zeros_like(result)
        gray_img = np.dstack((zero, zero, draw_cross(result)))

        self.set_pixmap(QPixmap.fromImage(image_from_ndarray(np.array(gray_img + image_pfm))))

    def on_stitch(self):
        i = 0
        images = []
        while self.image_model.item(i):
            file_path = self.image_model.item(i, 1).text()
            image = image_to_gray(convert_to_pfm(imread(unicode(file_path))))
            images.append(image)
            i += 1
        stitch(self.ksize_slider.value(), images)

    def set_pixmap(self, pixmap):
        self.image_label.setPixmap(pixmap.scaled(self.image_label.size(), QtCore.Qt.KeepAspectRatio))
예제 #3
0
class PosiviewProperties(QgsOptionsDialogBase, Ui_PosiviewPropertiesBase):
    '''
    GUI class classdocs for the Configuration dialog
    '''
    applyChanges = pyqtSignal(dict)

    def __init__(self, project, parent=None):
        '''
        Setup dialog widgets with the project properties
        '''
        super(PosiviewProperties, self).__init__("PosiViewProperties", parent)
        self.setupUi(self)
        self.groupBox_6.hide()
        self.initOptionsBase(False)
        self.restoreOptionsBaseUi()
        self.comboBoxParser.addItems(PARSERS)
        self.comboBoxProviderType.addItems(DEVICE_TYPES)
        self.project = project
        self.projectProperties = project.properties()
        self.mToolButtonLoad.setDefaultAction(self.actionLoadConfiguration)
        self.mToolButtonSave.setDefaultAction(self.actionSaveConfiguration)

        self.mobileModel = QStringListModel()
        self.mobileListModel = QStringListModel()
        self.mMobileListView.setModel(self.mobileListModel)
        self.mobileProviderModel = QStandardItemModel()
        self.mobileProviderModel.setHorizontalHeaderLabels(('Provider', 'Filter'))
        self.mMobileProviderTableView.setModel(self.mobileProviderModel)

        self.providerListModel = QStringListModel()
        self.mDataProviderListView.setModel(self.providerListModel)
        self.comboBoxProviders.setModel(self.providerListModel)
        self.setupModelData(self.projectProperties)
        self.setupGeneralData(self.projectProperties)

    def setupModelData(self, properties):
        self.mobileListModel.setStringList(sorted(properties['Mobiles'].keys()))
        self.providerListModel.setStringList(sorted(properties['Provider'].keys()))

    def setupGeneralData(self, properties):
        self.lineEditCruise.setText(properties['Mission']['cruise'])
        self.lineEditDive.setText(properties['Mission']['dive'])
        self.lineEditStation.setText(properties['Mission']['station'])
        self.lineEditRecorderPath.setText(properties['RecorderPath'])
        self.checkBoxAutoRecording.setChecked(properties['AutoRecord'])
        self.spinBoxNotifyDuration.setValue(properties['NotifyDuration'])
        self.checkBoxUtcClock.setChecked((properties['ShowUtcClock']))

    def updateGeneralData(self):
        self.projectProperties['Mission']['cruise'] = self.lineEditCruise.text()
        self.projectProperties['Mission']['dive'] = self.lineEditDive.text()
        self.projectProperties['Mission']['station'] = self.lineEditStation.text()
        self.projectProperties['RecorderPath'] = self.lineEditRecorderPath.text()
        self.projectProperties['AutoRecord'] = self.checkBoxAutoRecording.isChecked()
        self.projectProperties['NotifyDuration'] = self.spinBoxNotifyDuration.value()
        self.projectProperties['ShowUtcClock'] = self.checkBoxUtcClock.isChecked()

    def getColor(self, value):
        try:
            return QColor.fromRgba(int(value))
        except ValueError:
            return QColor(value)

    @pyqtSlot(QAbstractButton, name='on_buttonBox_clicked')
    def onButtonBoxClicked(self, button):
        role = self.buttonBox.buttonRole(button)
        if role == QDialogButtonBox.ApplyRole or role == QDialogButtonBox.AcceptRole:
            self.updateGeneralData()
            self.applyChanges.emit(self.projectProperties)

    @pyqtSlot(name='on_actionSaveConfiguration_triggered')
    def onActionSaveConfigurationTriggered(self):
        ''' Save the current configuration
        '''
        fn = QFileDialog.getSaveFileName(None, 'Save PosiView configuration', '', 'Configuration (*.ini *.conf)')
        self.project.store(fn)

    @pyqtSlot(name='on_actionLoadConfiguration_triggered')
    def onActionLoadConfigurationTriggered(self):
        ''' Load configuration from file
        '''
        fn = QFileDialog.getOpenFileName(None, 'Save PosiView configuration', '', 'Configuration (*.ini *.conf)')
        self.projectProperties = self.project.read(fn)
        self.setupModelData(self.projectProperties)
        self.setupGeneralData(self.projectProperties)

    @pyqtSlot(QModelIndex, name='on_mMobileListView_clicked')
    def editMobile(self, index):
        ''' Populate the widgets with the selected mobiles properties
        '''
        if index.isValid():
            self.populateMobileWidgets(index)

    @pyqtSlot(str, name='on_comboBoxMobileType_currentIndexChanged')
    def mobileTypeChanged(self, mType):
        if mType == 'SHAPE':
#             self.lineEditMobileShape.setText(str(mobile['shape']))
            self.lineEditMobileShape.setEnabled(True)
        else:
            self.lineEditMobileShape.setEnabled(False)

    @pyqtSlot(QModelIndex, name='on_mMobileListView_activated')
    def activated(self, index):
        pass

    @pyqtSlot(name='on_toolButtonAddMobile_clicked')
    def addMobile(self):
        self.mobileListModel.insertRow(self.mobileListModel.rowCount())
        index = self.mobileListModel.index(self.mobileListModel.rowCount() - 1)
        self.lineEditMobileName.setText('NewMobile')
        self.mobileListModel.setData(index, 'NewMobile', Qt.DisplayRole)
        self.mMobileListView.setCurrentIndex(index)
        self.applyMobile()

    @pyqtSlot(name='on_pushButtonApplyMobile_clicked')
    def applyMobile(self):
        index = self.mMobileListView.currentIndex()
        if index.isValid() and not self.lineEditMobileName.text() == '':
            mobile = dict()
            mobile['Name'] = self.lineEditMobileName.text()
            mobile['type'] = self.comboBoxMobileType.currentText()
            try:
                t = eval(self.lineEditMobileShape.text())
                if t.__class__ is tuple or t.__class__ is dict:
                    mobile['shape'] = t
            except SyntaxError:
                mobile['shape'] = ((0.0, -0.5), (0.3, 0.5), (0.0, 0.2), (-0.5, 0.5))
            mobile['length'] = self.doubleSpinBoxMobileLength.value()
            mobile['width'] = self.doubleSpinBoxMobileWidth.value()
            mobile['zValue'] = self.spinBoxZValue.value()
            mobile['color'] = self.mColorButtonMobileColor.color().rgba()
            mobile['fillColor'] = self.mColorButtonMobileFillColor.color().rgba()
            mobile['timeout'] = self.spinBoxMobileTimeout.value() * 1000
            mobile['nofixNotify'] = self.spinBoxMobileNotification.value()
            mobile['trackLength'] = self.spinBoxTrackLength.value()
            mobile['trackColor'] = self.mColorButtonMobileTrackColor.color().rgba()
            provs = dict()
            for r in range(self.mobileProviderModel.rowCount()):
                try:
                    fil = int(self.mobileProviderModel.item(r, 1).data(Qt.DisplayRole))
                except:
                    fil = self.mobileProviderModel.item(r, 1).data(Qt.DisplayRole)
                    if not fil:
                        fil = None
                provs[self.mobileProviderModel.item(r, 0).data(Qt.DisplayRole)] = fil
            mobile['provider'] = provs
            currName = self.mobileListModel.data(index, Qt.DisplayRole)
            if not currName == mobile['Name']:
                del self.projectProperties['Mobiles'][currName]
                self.mobileListModel.setData(index, mobile['Name'], Qt.DisplayRole)
            self.projectProperties['Mobiles'][mobile['Name']] = mobile

    def populateMobileWidgets(self, index):
        mobile = self.projectProperties['Mobiles'][self.mobileListModel.data(index, Qt.DisplayRole)]
        self.lineEditMobileName.setText(mobile.get('Name'))
        self.comboBoxMobileType.setCurrentIndex(self.comboBoxMobileType.findText(mobile.setdefault('type', 'BOX').upper()))
        if mobile['type'] == 'SHAPE':
            self.lineEditMobileShape.setText(str(mobile['shape']))
            self.lineEditMobileShape.setEnabled(True)
        else:
            self.lineEditMobileShape.setEnabled(False)
            self.lineEditMobileShape.clear()
        self.doubleSpinBoxMobileLength.setValue(mobile.get('length', 20.0))
        self.doubleSpinBoxMobileWidth.setValue(mobile.get('width', 5.0))
        self.spinBoxZValue.setValue(mobile.get('zValue', 100))
        self.mColorButtonMobileColor.setColor(self.getColor(mobile.get('color', 'black')))
        self.mColorButtonMobileFillColor.setColor(self.getColor(mobile.get('fillColor', 'green')))
        self.spinBoxMobileTimeout.setValue(mobile.get('timeout', 3000) / 1000)
        self.spinBoxMobileNotification.setValue(mobile.get('nofixNotify', 0))
        self.spinBoxTrackLength.setValue(mobile.get('trackLength', 100))
        self.mColorButtonMobileTrackColor.setColor(self.getColor(mobile.get('trackColor', 'green')))

        r = 0
        self.mobileProviderModel.removeRows(0, self.mobileProviderModel.rowCount())
        if 'provider' in mobile:
            for k, v in mobile['provider'].items():
                prov = QStandardItem(k)
                val = QStandardItem(str(v))
                self.mobileProviderModel.setItem(r, 0, prov)
                self.mobileProviderModel.setItem(r, 1, val)
                r += 1

    @pyqtSlot(name='on_toolButtonRemoveMobile_clicked')
    def removeMobile(self):
        idx = self.mMobileListView.currentIndex()
        if idx.isValid():
            self.projectProperties['Mobiles'].pop(self.mobileListModel.data(idx, Qt.DisplayRole))
            self.mobileListModel.removeRows(idx.row(), 1)
            idx = self.mMobileListView.currentIndex()
            if idx.isValid():
                self.populateMobileWidgets(idx)

    @pyqtSlot(name='on_toolButtonRefreshMobileProvider_clicked')
    def refreshMobileProvider(self):
        prov = self.comboBoxProviders.currentText()
        if prov == '':
            return
        fil = None
        if self.lineEditProviderFilter.text() != '':
            fil = self.lineEditProviderFilter.text()
        items = self.mobileProviderModel.findItems(prov, Qt.MatchExactly, 0)
        if items:
            for item in items:
                self.mobileProviderModel.setItem(item.row(), 1, QStandardItem(fil))
        else:
            self.mobileProviderModel.appendRow([QStandardItem(prov), QStandardItem(fil)])

    @pyqtSlot(name='on_toolButtonRemoveMobileProvider_clicked')
    def removeMobileProvider(self):
        idx = self.mMobileProviderTableView.currentIndex()
        if idx.isValid():
            self.mobileProviderModel.removeRow(idx.row())

    @pyqtSlot(name='on_pushButtonApplyDataProvider_clicked')
    def applyDataProvider(self):
        index = self.mDataProviderListView.currentIndex()
        if index.isValid() and not self.lineEditProviderName.text() == '':
            provider = dict()
            provider['Name'] = self.lineEditProviderName.text()
            provider['DataDeviceType'] = self.comboBoxProviderType.currentText()
            if provider['DataDeviceType'] in NETWORK_TYPES:
                provider['Host'] = self.lineEditProviderHostName.text()
                provider['Port'] = self.spinBoxProviderPort.value()
            provider['Parser'] = self.comboBoxParser.currentText()
            currName = self.providerListModel.data(index, Qt.DisplayRole)
            if not currName == provider['Name']:
                del self.projectProperties['Provider'][currName]
                self.providerListModel.setData(index, provider['Name'], Qt.DisplayRole)
            self.projectProperties['Provider'][provider['Name']] = provider

    @pyqtSlot(QModelIndex, name='on_mDataProviderListView_clicked')
    def editDataProvider(self, index):
        '''
        '''
        if index.isValid():
            self.populateDataProviderWidgets(index)

    def populateDataProviderWidgets(self, index):
        provider = self.projectProperties['Provider'][self.providerListModel.data(index, Qt.DisplayRole)]
        self.lineEditProviderName.setText(provider.get('Name'))
        self.comboBoxProviderType.setCurrentIndex(self.comboBoxProviderType.findText(provider.setdefault('DataDeviceType', 'UDP').upper()))
        if provider['DataDeviceType'] in NETWORK_TYPES:
            self.stackedWidgetDataDevice.setCurrentIndex(0)
            self.lineEditProviderHostName.setText(provider.setdefault('Host', '0.0.0.0'))
            self.spinBoxProviderPort.setValue(int(provider.setdefault('Port', 2000)))

        self.comboBoxParser.setCurrentIndex(self.comboBoxParser.findText(provider.setdefault('Parser', 'NONE').upper()))

    @pyqtSlot(name='on_toolButtonAddDataProvider_clicked')
    def addDataProvider(self):
        self.providerListModel.insertRow(self.providerListModel.rowCount())
        index = self.providerListModel.index(self.providerListModel.rowCount() - 1)
        self.lineEditProviderName.setText('NewDataProvider')
        self.providerListModel.setData(index, 'NewDataProvider', Qt.DisplayRole)
        self.mDataProviderListView.setCurrentIndex(index)
        self.applyDataProvider()

    @pyqtSlot(name='on_toolButtonRemoveDataProvider_clicked')
    def removeDataProvider(self):
        idx = self.mDataProviderListView.currentIndex()
        if idx.isValid():
            self.projectProperties['Provider'].pop(self.providerListModel.data(idx, Qt.DisplayRole))
            self.providerListModel.removeRows(idx.row(), 1)
            idx = self.mDataProviderListView.currentIndex()
            if idx.isValid():
                self.populateDataProviderWidgets(idx)

    @pyqtSlot(name='on_toolButtonSelectLogPath_clicked')
    def selectRecorderPath(self):
        path = QFileDialog.getExistingDirectory(self, self.tr('Select Recorder Path'), self.lineEditRecorderPath.text(),
                                                QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        if path != '':
            self.lineEditRecorderPath.setText(path)

    @pyqtSlot(QPoint, name='on_lineEditMobileShape_customContextMenuRequested')
    def mobileShapeContextMenu(self, pos):
        menu = QMenu(self.lineEditMobileShape)
        vesselAction = menu.addAction(self.tr('Vessel'))
        rovAction = menu.addAction(self.tr('ROV'))
        auvAction = menu.addAction(self.tr('AUV'))
        arrowAction = menu.addAction(self.tr('Arrow'))
        selectedAction = menu.exec_(self.lineEditMobileShape.mapToGlobal(pos))
        if selectedAction == vesselAction:
            self.lineEditMobileShape.setText(u'((0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3))')
        elif selectedAction == rovAction:
            self.lineEditMobileShape.setText(u'((0.3, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3), (-0.3, -0.5))')
        elif selectedAction == auvAction:
            self.lineEditMobileShape.setText(u'((0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3))')
        elif selectedAction == arrowAction:
            self.lineEditMobileShape.setText(u'((0, -0.5), (0.5, 0.5), (0, 0), (-0.5, 0.5))')

    @pyqtSlot(name='on_buttonBox_helpRequested')
    def showHelp(self):
        """Display application help to the user."""
        help_file = os.path.join(os.path.split(os.path.dirname(__file__))[0], 'help', 'index.html')
        QDesktopServices.openUrl(QUrl.fromLocalFile(help_file))
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()
예제 #5
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()
예제 #6
0
class TreeLegend(QObject):

    toggledLegend = pyqtSignal(list)
    descriptionLegend = pyqtSignal(str)

    def __init__(self, treeView):
        def init():
            self.setHeader()
            self.tree.setModel(self.model)
            self.headerView.setMovable(False)
            self.headerView.setClickable(True)
            self.tree.setSelectionMode(0)  # no selection

        super(TreeLegend, self).__init__()
        self.tree = treeView
        #
        self.hasConnect = self.layer = self.legendItems = None
        self.visibleItems = []
        self.model = QStandardItemModel(0, 1)
        self.headerView = self.tree.header()
        #
        init()
        self._connect()

    def __del__(self):
        if self.hasConnect:
            self._connect(False)
        self.model.clear()
        self.layer.legendChanged.disconnect(self.updateLegendItems)

    def _connect(self, isConnect=True):
        ss = [{
            'signal': self.tree.clicked,
            'slot': self.toggleItem
        }, {
            'signal': self.headerView.sectionClicked,
            'slot': self.toggleHeader
        }, {
            'signal': self.headerView.sectionDoubleClicked,
            'slot': self.emitDescription
        }]
        if isConnect:
            self.hasConnect = True
            for item in ss:
                item['signal'].connect(item['slot'])
        else:
            self.hasConnect = False
            for item in ss:
                item['signal'].disconnect(item['slot'])

    def setHeader(self, data=None):
        if data is None:
            self.model.clear()
            nameHeader = 'Select Raster Layer(Palette)'
            font = QFont()
            font.setStrikeOut(False)
            headerModel = QStandardItem(nameHeader)
            headerModel.setData(font, Qt.FontRole)
            tip = "Raster with Palette(Single Band)"
            headerModel.setData(tip, Qt.ToolTipRole)
            self.model.setHorizontalHeaderItem(0, headerModel)
        else:
            headerModel = self.model.horizontalHeaderItem(0)
            label = "%s" % data['name']
            formatMgs = "Layer: %s\nSource: %s\nNumber Class: %d\nWidth: %d\nHeight: %d\nRes.X: %f\nRes.Y: %f\n\n* Double click copy to Clipboard"
            dataMsg = (data['name'], data['source'], data['num_class'],
                       data['width'], data['height'], data['resX'],
                       data['resY'])
            tip = formatMgs % dataMsg
            headerModel.setData(data, Qt.UserRole)
            headerModel.setData(label, Qt.DisplayRole)
            headerModel.setData(tip, Qt.ToolTipRole)

    def setLayer(self, layer):
        self.legendItems = layer.legendSymbologyItems()
        total = len(self.legendItems)
        self.visibleItems = [True for x in range(total)]
        data = {
            'name': layer.name(),
            'source': layer.source(),
            'num_class': total,
            'width': layer.width(),
            'height': layer.height(),
            'resX': layer.rasterUnitsPerPixelX(),
            'resY': layer.rasterUnitsPerPixelY()
        }
        self.setHeader(data)
        #
        if not self.layer is None:
            self.layer.legendChanged.disconnect(self.updateLegendItems)
        layer.legendChanged.connect(self.updateLegendItems)
        self.layer = layer

    def setLegend(self, values):
        def setHeader():
            headerModel = self.model.horizontalHeaderItem(0)
            data = headerModel.data(Qt.UserRole)
            data['num_class'] = len(values)
            self.setHeader(data)

        def createItem(item):
            (pixel, total) = item
            (legend, color) = self.legendItems[pixel]
            name = "[%d] %s" % (pixel, legend)
            tip = "Value pixel: %d\nTotal pixels: %d\nClass name: %s" % (
                pixel, total, legend)
            pix = QPixmap(16, 16)
            pix.fill(color)
            font.setStrikeOut(not self.visibleItems[pixel])
            #
            itemModel = QStandardItem(QIcon(pix), name)
            itemModel.setEditable(False)
            itemModel.setData(font, Qt.FontRole)
            itemModel.setData(tip, Qt.ToolTipRole)
            itemModel.setData(item, Qt.UserRole)
            #
            return itemModel

        setHeader()
        self.model.removeRows(0, self.model.rowCount())
        #
        font = QFont()
        for item in values:
            self.model.appendRow(createItem(item))

    def setEnabled(self, isEnable=True):
        self._connect(isEnable)
        self.tree.setEnabled(isEnable)

    def getLayerName(self):
        headerModel = self.model.horizontalHeaderItem(0)
        return headerModel.data(Qt.UserRole)['name']

    @pyqtSlot()
    def updateLegendItems(self):
        self.legendItems = self.layer.legendSymbologyItems()
        # Refresh legend
        rows = self.model.rowCount()
        row = 0
        while row < rows:
            index = self.model.index(row, 0)
            (pixel, total) = self.model.data(index, Qt.UserRole)
            (legend, color) = self.legendItems[pixel]
            pix = QPixmap(16, 16)
            pix.fill(color)
            self.model.setData(index, QIcon(pix), Qt.DecorationRole)
            row += 1

    @pyqtSlot('QModelIndex')
    def toggleItem(self, index):
        font = index.data(Qt.FontRole)
        strike = not font.strikeOut()
        font.setStrikeOut(strike)
        self.model.setData(index, font, Qt.FontRole)
        #
        (pixel, total) = index.data(Qt.UserRole)
        visible = not strike
        self.visibleItems[pixel] = visible
        #
        self.toggledLegend.emit(self.visibleItems)

    @pyqtSlot(int)
    def toggleHeader(self, logical):
        rowCount = self.model.rowCount()
        if rowCount == 0:
            return

        header = self.model.horizontalHeaderItem(0)
        font = header.data(Qt.FontRole)
        strike = not font.strikeOut()
        font.setStrikeOut(strike)
        header.setData(font, Qt.FontRole)
        #
        items = []
        row = 0
        while row < self.model.rowCount():
            index = self.model.index(row, 0)
            self.model.setData(index, font, Qt.FontRole)
            items.append(index.data(Qt.UserRole))
            row += 1

        visible = not strike
        for item in items:
            (pixel, total) = item
            self.visibleItems[pixel] = visible
        #
        self.toggledLegend.emit(self.visibleItems)

    @pyqtSlot(int)
    def emitDescription(self):
        def getDescription():
            data = self.model.horizontalHeaderItem(0).data(Qt.UserRole)
            formatMgs = "Layer: %s\nSource: %s\nNumber Class: %d\nWidth: %d\nHeight: %d\nRes.X: %f\nRes.Y: %f"
            dataMsg = (data['name'], data['source'], data['num_class'],
                       data['width'], data['height'], data['resX'],
                       data['resY'])
            descHeader = formatMgs % dataMsg
            #
            descItems = ["Value pixel;Total pixels;Class name"]
            rows = self.model.rowCount()
            row = 0
            while row < rows:
                index = self.model.index(row, 0)
                (pixel, total) = self.model.data(index, Qt.UserRole)
                (legend, color) = self.legendItems[pixel]
                descItems.append("%d;%d;%s" % (pixel, total, legend))
                row += 1

            return "%s\n\n%s" % (descHeader, '\n'.join(descItems))

        if self.model.rowCount() > 0:
            self.descriptionLegend.emit(getDescription())
예제 #7
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()
예제 #8
0
class ListPairTableView(QTableView):
    """
    2-column table view that enables pairing of list data through combo boxes.
    """
    def __init__(self, parent=None):
        QTableView.__init__(self, parent)

        self.setEditTriggers(QAbstractItemView.DoubleClicked
                             | QAbstractItemView.SelectedClicked)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)

        self._pair_model = QStandardItemModel(1, 2, self)
        self._pair_model.dataChanged.connect(self._on_pair_data_changed)

        self.setModel(self._pair_model)
        self.horizontalHeader().setResizeMode(QHeaderView.Stretch)

        self._combo_delegate = PairComboBoxDelegate(self)
        self.setItemDelegate(self._combo_delegate)

    def set_header_labels(self, labels):
        """
        Set the table's header labels using labels.
        :param labels: Header labels.
        :type labels: list
        """
        if len(labels) < 2:
            return

        lbls = []
        for i in range(2):
            lbls.append(labels[i])

        self._pair_model.setHorizontalHeaderLabels(lbls)

    def clear_view(self):
        """
        Clears all row pairings in the view.
        """
        rows = self._pair_model.rowCount()
        self._pair_model.removeRows(0, rows)

        #Insert blank row
        self.append_row()

    def append_row(self):
        """
        Add a blank row after the last item in the view.
        """
        items = [QStandardItem(), QStandardItem()]

        self._pair_model.appendRow(items)

    def set_combo_selection(self, selection, empty_item=True):
        """
        Set combo selection for both columns. Any existing rows will be removed
        from the view.
        :param selection: A list containing two sub-lists for each column that
        correspond to the selection list for the combobox in each column.
        :type selection: list
        :param empty_item: True to insert an empty first item in each of the
        column comboboxes.
        :type empty_item: bool
        """
        self._combo_delegate.set_items_pair(selection, empty_item)

        self.clear_view()

    def _on_pair_data_changed(self, old_index, new_index):
        """
        This slot asserts whether selections in both columns in a row have
        been specified. If true, then automatically adds a new empty row
        for additional entries; If false, then the empty is removed from
        the view.
        :param old_index: Model index
        :type old_index: QModelIndex
        :param new_index: Model index
        :type new_index: QModelIndex
        """
        row_state = self.row_data_state(new_index.row())

        row_data = self.row_data(new_index.row())
        if row_state == 0:
            self._pair_model.removeRows(new_index.row(), 1)

            if self._pair_model.rowCount() == 0:
                self.append_row()

        elif row_state == 2:
            if not self.is_last_row_empty():
                self.append_row()

    def is_last_row_empty(self):
        """
        :return: True if the last row in the view does not contain any data,
        False if one or both columns contains data.
        :rtype: bool
        """
        last_row_idx = self._pair_model.rowCount() - 1

        last_row_state = self.row_data_state(last_row_idx)
        if last_row_state == 0:
            return True

        else:
            return False

    def row_data_state(self, row_index):
        """
        :param row_index: Row position
        :type row_index: int
        :return: 0 if data for each of the columns is empty. 1 if one column
        contains data and the other is empty. 2 if both columns contain data.
        :rtype: int
        """
        col_0_val, col_1_val = self.row_data(row_index)

        if col_0_val is None and col_1_val is None:
            return 0

        elif self._is_empty(col_0_val) and not self._is_empty(col_1_val):
            return 1

        elif not self._is_empty(col_0_val) and self._is_empty(col_1_val):
            return 1

        elif self._is_empty(col_0_val) and self._is_empty(col_1_val):
            return 0

        elif not self._is_empty(col_0_val) and not self._is_empty(col_1_val):
            return 2

    def _is_empty(self, val):
        if val is None:
            return True

        else:
            if (isinstance(val, str) or isinstance(val, unicode)) and not val:
                return True

        return False

    def row_data(self, row_index):
        """
        :param row_index: Row position
        :type row_index: int
        :return: Data in both first and second columns for the specified row.
        :rtype: tuple
        """
        if row_index >= 0:
            idx_col_0 = self._pair_model.index(row_index, 0)
            idx_col_1 = self._pair_model.index(row_index, 1)

            val_0 = self._pair_model.data(idx_col_0)
            val_1 = self._pair_model.data(idx_col_1)

            return val_0, val_1

        else:
            return None, None

    def column_pairings(self):
        """
        :return: Collection of column matchings specified as specified by the user.
        :rtype: dict
        """
        col_pairings = {}

        for row_idx in range(self._pair_model.rowCount()):
            if self.row_data_state(row_idx) != 0:
                col_val_0, col_val_1 = self.row_data(row_idx)
                col_pairings[col_val_0] = col_val_1

        return col_pairings
예제 #9
0
class ListPairTableView(QTableView):
    """
    2-column table view that enables pairing of list data through combo boxes.
    """

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

        self.setEditTriggers(QAbstractItemView.DoubleClicked | QAbstractItemView.SelectedClicked)
        self.setSelectionBehavior(QAbstractItemView.SelectRows)

        self._pair_model = QStandardItemModel(1, 2, self)
        self._pair_model.dataChanged.connect(self._on_pair_data_changed)

        self.setModel(self._pair_model)
        self.horizontalHeader().setResizeMode(QHeaderView.Stretch)

        self._combo_delegate = PairComboBoxDelegate(self)
        self.setItemDelegate(self._combo_delegate)

    def set_header_labels(self, labels):
        """
        Set the table's header labels using labels.
        :param labels: Header labels.
        :type labels: list
        """
        if len(labels) < 2:
            return

        lbls = []
        for i in range(2):
            lbls.append(labels[i])

        self._pair_model.setHorizontalHeaderLabels(lbls)

    def clear_view(self):
        """
        Clears all row pairings in the view.
        """
        rows = self._pair_model.rowCount()
        self._pair_model.removeRows(0, rows)

        # Insert blank row
        self.append_row()

    def append_row(self):
        """
        Add a blank row after the last item in the view.
        """
        items = [QStandardItem(), QStandardItem()]

        self._pair_model.appendRow(items)

    def set_combo_selection(self, selection, empty_item=True):
        """
        Set combo selection for both columns. Any existing rows will be removed
        from the view.
        :param selection: A list containing two sub-lists for each column that
        correspond to the selection list for the combobox in each column.
        :type selection: list
        :param empty_item: True to insert an empty first item in each of the
        column comboboxes.
        :type empty_item: bool
        """
        self._combo_delegate.set_items_pair(selection, empty_item)

        self.clear_view()

    def _on_pair_data_changed(self, old_index, new_index):
        """
        This slot asserts whether selections in both columns in a row have
        been specified. If true, then automatically adds a new empty row
        for additional entries; If false, then the empty is removed from
        the view.
        :param old_index: Model index
        :type old_index: QModelIndex
        :param new_index: Model index
        :type new_index: QModelIndex
        """
        row_state = self.row_data_state(new_index.row())

        row_data = self.row_data(new_index.row())
        if row_state == 0:
            self._pair_model.removeRows(new_index.row(), 1)

            if self._pair_model.rowCount() == 0:
                self.append_row()

        elif row_state == 2:
            if not self.is_last_row_empty():
                self.append_row()

    def is_last_row_empty(self):
        """
        :return: True if the last row in the view does not contain any data,
        False if one or both columns contains data.
        :rtype: bool
        """
        last_row_idx = self._pair_model.rowCount() - 1

        last_row_state = self.row_data_state(last_row_idx)
        if last_row_state == 0:
            return True

        else:
            return False

    def row_data_state(self, row_index):
        """
        :param row_index: Row position
        :type row_index: int
        :return: 0 if data for each of the columns is empty. 1 if one column
        contains data and the other is empty. 2 if both columns contain data.
        :rtype: int
        """
        col_0_val, col_1_val = self.row_data(row_index)

        if col_0_val is None and col_1_val is None:
            return 0

        elif self._is_empty(col_0_val) and not self._is_empty(col_1_val):
            return 1

        elif not self._is_empty(col_0_val) and self._is_empty(col_1_val):
            return 1

        elif self._is_empty(col_0_val) and self._is_empty(col_1_val):
            return 0

        elif not self._is_empty(col_0_val) and not self._is_empty(col_1_val):
            return 2

    def _is_empty(self, val):
        if val is None:
            return True

        else:
            if (isinstance(val, str) or isinstance(val, unicode)) and not val:
                return True

        return False

    def row_data(self, row_index):
        """
        :param row_index: Row position
        :type row_index: int
        :return: Data in both first and second columns for the specified row.
        :rtype: tuple
        """
        if row_index >= 0:
            idx_col_0 = self._pair_model.index(row_index, 0)
            idx_col_1 = self._pair_model.index(row_index, 1)

            val_0 = self._pair_model.data(idx_col_0)
            val_1 = self._pair_model.data(idx_col_1)

            return val_0, val_1

        else:
            return None, None

    def column_pairings(self):
        """
        :return: Collection of column matchings specified as specified by the user.
        :rtype: dict
        """
        col_pairings = {}

        for row_idx in range(self._pair_model.rowCount()):
            if self.row_data_state(row_idx) != 0:
                col_val_0, col_val_1 = self.row_data(row_idx)
                col_pairings[col_val_0] = col_val_1

        return col_pairings
예제 #10
0
class PosiviewProperties(QgsOptionsDialogBase, Ui_PosiviewPropertiesBase):
    '''
    GUI class classdocs for the Configuration dialog
    '''
    applyChanges = pyqtSignal(dict)

    def __init__(self, project, parent=None):
        '''
        Setup dialog widgets with the project properties
        '''
        super(PosiviewProperties, self).__init__("PosiViewProperties", parent)
        self.setupUi(self)
        self.groupBox_6.hide()
        self.initOptionsBase(False)
        self.restoreOptionsBaseUi()
        self.comboBoxParser.addItems(PARSERS)
        self.comboBoxProviderType.addItems(DEVICE_TYPES)
        self.project = project
        self.projectProperties = project.properties()
        self.mToolButtonLoad.setDefaultAction(self.actionLoadConfiguration)
        self.mToolButtonSave.setDefaultAction(self.actionSaveConfiguration)

        self.mobileModel = QStringListModel()
        self.mobileListModel = QStringListModel()
        self.mMobileListView.setModel(self.mobileListModel)
        self.mobileProviderModel = QStandardItemModel()
        self.mobileProviderModel.setHorizontalHeaderLabels(
            ('Provider', 'Filter'))
        self.mMobileProviderTableView.setModel(self.mobileProviderModel)

        self.providerListModel = QStringListModel()
        self.mDataProviderListView.setModel(self.providerListModel)
        self.comboBoxProviders.setModel(self.providerListModel)
        self.setupModelData(self.projectProperties)
        self.setupGeneralData(self.projectProperties)

    def setupModelData(self, properties):
        self.mobileListModel.setStringList(sorted(
            properties['Mobiles'].keys()))
        self.providerListModel.setStringList(
            sorted(properties['Provider'].keys()))

    def setupGeneralData(self, properties):
        self.lineEditCruise.setText(properties['Mission']['cruise'])
        self.lineEditDive.setText(properties['Mission']['dive'])
        self.lineEditStation.setText(properties['Mission']['station'])
        self.lineEditRecorderPath.setText(properties['RecorderPath'])
        self.checkBoxAutoRecording.setChecked(properties['AutoRecord'])
        self.spinBoxNotifyDuration.setValue(properties['NotifyDuration'])
        self.checkBoxUtcClock.setChecked((properties['ShowUtcClock']))

    def updateGeneralData(self):
        self.projectProperties['Mission']['cruise'] = self.lineEditCruise.text(
        )
        self.projectProperties['Mission']['dive'] = self.lineEditDive.text()
        self.projectProperties['Mission'][
            'station'] = self.lineEditStation.text()
        self.projectProperties[
            'RecorderPath'] = self.lineEditRecorderPath.text()
        self.projectProperties[
            'AutoRecord'] = self.checkBoxAutoRecording.isChecked()
        self.projectProperties[
            'NotifyDuration'] = self.spinBoxNotifyDuration.value()
        self.projectProperties[
            'ShowUtcClock'] = self.checkBoxUtcClock.isChecked()

    def getColor(self, value):
        try:
            return QColor.fromRgba(int(value))
        except ValueError:
            return QColor(value)

    @pyqtSlot(QAbstractButton, name='on_buttonBox_clicked')
    def onButtonBoxClicked(self, button):
        role = self.buttonBox.buttonRole(button)
        if role == QDialogButtonBox.ApplyRole or role == QDialogButtonBox.AcceptRole:
            self.updateGeneralData()
            self.applyChanges.emit(self.projectProperties)

    @pyqtSlot(name='on_actionSaveConfiguration_triggered')
    def onActionSaveConfigurationTriggered(self):
        ''' Save the current configuration
        '''
        fn = QFileDialog.getSaveFileName(None, 'Save PosiView configuration',
                                         '', 'Configuration (*.ini *.conf)')
        self.project.store(fn)

    @pyqtSlot(name='on_actionLoadConfiguration_triggered')
    def onActionLoadConfigurationTriggered(self):
        ''' Load configuration from file
        '''
        fn = QFileDialog.getOpenFileName(None, 'Save PosiView configuration',
                                         '', 'Configuration (*.ini *.conf)')
        self.projectProperties = self.project.read(fn)
        self.setupModelData(self.projectProperties)
        self.setupGeneralData(self.projectProperties)

    @pyqtSlot(QModelIndex, name='on_mMobileListView_clicked')
    def editMobile(self, index):
        ''' Populate the widgets with the selected mobiles properties
        '''
        if index.isValid():
            self.populateMobileWidgets(index)

    @pyqtSlot(str, name='on_comboBoxMobileType_currentIndexChanged')
    def mobileTypeChanged(self, mType):
        if mType == 'SHAPE':
            self.lineEditMobileShape.setEnabled(True)
        else:
            self.lineEditMobileShape.setEnabled(False)

    @pyqtSlot(QModelIndex, name='on_mMobileListView_activated')
    def activated(self, index):
        pass

    @pyqtSlot(name='on_toolButtonAddMobile_clicked')
    def addMobile(self):
        self.mobileListModel.insertRow(self.mobileListModel.rowCount())
        index = self.mobileListModel.index(self.mobileListModel.rowCount() - 1)
        self.lineEditMobileName.setText('NewMobile')
        self.mobileListModel.setData(index, 'NewMobile', Qt.DisplayRole)
        self.mMobileListView.setCurrentIndex(index)
        self.applyMobile()

    @pyqtSlot(name='on_pushButtonApplyMobile_clicked')
    def applyMobile(self):
        index = self.mMobileListView.currentIndex()
        if index.isValid() and not self.lineEditMobileName.text() == '':
            mobile = dict()
            mobile['Name'] = self.lineEditMobileName.text()
            mobile['type'] = self.comboBoxMobileType.currentText()
            try:
                t = eval(self.lineEditMobileShape.text())
                if t.__class__ is tuple or t.__class__ is dict:
                    mobile['shape'] = t
            except SyntaxError:
                mobile['shape'] = ((0.0, -0.5), (0.3, 0.5), (0.0, 0.2), (-0.5,
                                                                         0.5))
            mobile['length'] = self.doubleSpinBoxMobileLength.value()
            mobile['width'] = self.doubleSpinBoxMobileWidth.value()
            mobile['offsetX'] = self.doubleSpinBoxXOffset.value()
            mobile['offsetY'] = self.doubleSpinBoxYOffset.value()
            mobile['zValue'] = self.spinBoxZValue.value()
            mobile['color'] = self.mColorButtonMobileColor.color().rgba()
            mobile['fillColor'] = self.mColorButtonMobileFillColor.color(
            ).rgba()
            mobile['timeout'] = self.spinBoxMobileTimeout.value() * 1000
            mobile['nofixNotify'] = self.spinBoxMobileNotification.value()
            mobile['trackLength'] = self.spinBoxTrackLength.value()
            mobile['trackColor'] = self.mColorButtonMobileTrackColor.color(
            ).rgba()
            mobile['showLabel'] = self.checkBoxShowLabel.isChecked()
            provs = dict()
            for r in range(self.mobileProviderModel.rowCount()):
                try:
                    fil = int(
                        self.mobileProviderModel.item(r,
                                                      1).data(Qt.DisplayRole))
                except:
                    fil = self.mobileProviderModel.item(r,
                                                        1).data(Qt.DisplayRole)
                    if not fil:
                        fil = None
                provs[self.mobileProviderModel.item(r, 0).data(
                    Qt.DisplayRole)] = fil
            mobile['provider'] = provs
            currName = self.mobileListModel.data(index, Qt.DisplayRole)
            if not currName == mobile['Name']:
                del self.projectProperties['Mobiles'][currName]
                self.mobileListModel.setData(index, mobile['Name'],
                                             Qt.DisplayRole)
            self.projectProperties['Mobiles'][mobile['Name']] = mobile

    def populateMobileWidgets(self, index):
        mobile = self.projectProperties['Mobiles'][self.mobileListModel.data(
            index, Qt.DisplayRole)]
        self.lineEditMobileName.setText(mobile.get('Name'))
        self.comboBoxMobileType.setCurrentIndex(
            self.comboBoxMobileType.findText(
                mobile.setdefault('type', 'BOX').upper()))
        if mobile['type'] == 'SHAPE':
            self.lineEditMobileShape.setText(str(mobile['shape']))
            self.lineEditMobileShape.setEnabled(True)
            self.doubleSpinBoxXOffset.setEnabled(True)
            self.doubleSpinBoxYOffset.setEnabled(True)
        else:
            self.lineEditMobileShape.setEnabled(False)
            self.doubleSpinBoxXOffset.setEnabled(False)
            self.doubleSpinBoxYOffset.setEnabled(False)
            self.lineEditMobileShape.clear()
        self.doubleSpinBoxMobileLength.setValue(mobile.get('length', 20.0))
        self.doubleSpinBoxMobileWidth.setValue(mobile.get('width', 5.0))
        self.doubleSpinBoxXOffset.setValue(mobile.get('offsetX', 0.0))
        self.doubleSpinBoxYOffset.setValue(mobile.get('offsetY', 0.0))
        self.spinBoxZValue.setValue(mobile.get('zValue', 100))
        self.mColorButtonMobileColor.setColor(
            self.getColor(mobile.get('color', 'black')))
        self.mColorButtonMobileFillColor.setColor(
            self.getColor(mobile.get('fillColor', 'green')))
        self.spinBoxMobileTimeout.setValue(mobile.get('timeout', 3000) / 1000)
        self.spinBoxMobileNotification.setValue(mobile.get('nofixNotify', 0))
        self.spinBoxTrackLength.setValue(mobile.get('trackLength', 100))
        self.mColorButtonMobileTrackColor.setColor(
            self.getColor(mobile.get('trackColor', 'green')))
        self.checkBoxShowLabel.setChecked(mobile.get('showLabel', False))
        r = 0
        self.mobileProviderModel.removeRows(
            0, self.mobileProviderModel.rowCount())
        if 'provider' in mobile:
            for k, v in mobile['provider'].items():
                prov = QStandardItem(k)
                val = QStandardItem(str(v))
                self.mobileProviderModel.setItem(r, 0, prov)
                self.mobileProviderModel.setItem(r, 1, val)
                r += 1

    @pyqtSlot(name='on_toolButtonRemoveMobile_clicked')
    def removeMobile(self):
        idx = self.mMobileListView.currentIndex()
        if idx.isValid():
            self.projectProperties['Mobiles'].pop(
                self.mobileListModel.data(idx, Qt.DisplayRole))
            self.mobileListModel.removeRows(idx.row(), 1)
            idx = self.mMobileListView.currentIndex()
            if idx.isValid():
                self.populateMobileWidgets(idx)

    @pyqtSlot(name='on_toolButtonRefreshMobileProvider_clicked')
    def refreshMobileProvider(self):
        prov = self.comboBoxProviders.currentText()
        if prov == '':
            return
        fil = None
        if self.lineEditProviderFilter.text() != '':
            fil = self.lineEditProviderFilter.text()
        items = self.mobileProviderModel.findItems(prov, Qt.MatchExactly, 0)
        if items:
            for item in items:
                self.mobileProviderModel.setItem(item.row(), 1,
                                                 QStandardItem(fil))
        else:
            self.mobileProviderModel.appendRow(
                [QStandardItem(prov), QStandardItem(fil)])

    @pyqtSlot(name='on_toolButtonRemoveMobileProvider_clicked')
    def removeMobileProvider(self):
        idx = self.mMobileProviderTableView.currentIndex()
        if idx.isValid():
            self.mobileProviderModel.removeRow(idx.row())

    @pyqtSlot(name='on_pushButtonApplyDataProvider_clicked')
    def applyDataProvider(self):
        index = self.mDataProviderListView.currentIndex()
        if index.isValid() and not self.lineEditProviderName.text() == '':
            provider = dict()
            provider['Name'] = self.lineEditProviderName.text()
            provider['DataDeviceType'] = self.comboBoxProviderType.currentText(
            )
            if provider['DataDeviceType'] in NETWORK_TYPES:
                provider['Host'] = self.lineEditProviderHostName.text()
                provider['Port'] = self.spinBoxProviderPort.value()
            provider['Parser'] = self.comboBoxParser.currentText()
            currName = self.providerListModel.data(index, Qt.DisplayRole)
            if not currName == provider['Name']:
                del self.projectProperties['Provider'][currName]
                self.providerListModel.setData(index, provider['Name'],
                                               Qt.DisplayRole)
            self.projectProperties['Provider'][provider['Name']] = provider

    @pyqtSlot(QModelIndex, name='on_mDataProviderListView_clicked')
    def editDataProvider(self, index):
        '''
        '''
        if index.isValid():
            self.populateDataProviderWidgets(index)

    def populateDataProviderWidgets(self, index):
        provider = self.projectProperties['Provider'][
            self.providerListModel.data(index, Qt.DisplayRole)]
        self.lineEditProviderName.setText(provider.get('Name'))
        self.comboBoxProviderType.setCurrentIndex(
            self.comboBoxProviderType.findText(
                provider.setdefault('DataDeviceType', 'UDP').upper()))
        if provider['DataDeviceType'] in NETWORK_TYPES:
            self.stackedWidgetDataDevice.setCurrentIndex(0)
            self.lineEditProviderHostName.setText(
                provider.setdefault('Host', '0.0.0.0'))
            self.spinBoxProviderPort.setValue(
                int(provider.setdefault('Port', 2000)))

        self.comboBoxParser.setCurrentIndex(
            self.comboBoxParser.findText(
                provider.setdefault('Parser', 'NONE').upper()))

    @pyqtSlot(name='on_toolButtonAddDataProvider_clicked')
    def addDataProvider(self):
        self.providerListModel.insertRow(self.providerListModel.rowCount())
        index = self.providerListModel.index(
            self.providerListModel.rowCount() - 1)
        self.lineEditProviderName.setText('NewDataProvider')
        self.providerListModel.setData(index, 'NewDataProvider',
                                       Qt.DisplayRole)
        self.mDataProviderListView.setCurrentIndex(index)
        self.applyDataProvider()

    @pyqtSlot(name='on_toolButtonRemoveDataProvider_clicked')
    def removeDataProvider(self):
        idx = self.mDataProviderListView.currentIndex()
        if idx.isValid():
            self.projectProperties['Provider'].pop(
                self.providerListModel.data(idx, Qt.DisplayRole))
            self.providerListModel.removeRows(idx.row(), 1)
            idx = self.mDataProviderListView.currentIndex()
            if idx.isValid():
                self.populateDataProviderWidgets(idx)

    @pyqtSlot(name='on_toolButtonSelectLogPath_clicked')
    def selectRecorderPath(self):
        path = QFileDialog.getExistingDirectory(
            self, self.tr('Select Recorder Path'),
            self.lineEditRecorderPath.text(),
            QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks)
        if path != '':
            self.lineEditRecorderPath.setText(path)

    @pyqtSlot(QPoint, name='on_lineEditMobileShape_customContextMenuRequested')
    def mobileShapeContextMenu(self, pos):
        menu = QMenu(self.lineEditMobileShape)
        vesselAction = menu.addAction(self.tr('Vessel'))
        rovAction = menu.addAction(self.tr('ROV'))
        auvAction = menu.addAction(self.tr('AUV'))
        arrowAction = menu.addAction(self.tr('Arrow'))
        selectedAction = menu.exec_(self.lineEditMobileShape.mapToGlobal(pos))
        if selectedAction == vesselAction:
            self.lineEditMobileShape.setText(
                u'((0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3))'
            )
        elif selectedAction == rovAction:
            self.lineEditMobileShape.setText(
                u'((0.3, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3), (-0.3, -0.5))'
            )
        elif selectedAction == auvAction:
            self.lineEditMobileShape.setText(
                u'((0, -0.5), (0.5, -0.3), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.3))'
            )
        elif selectedAction == arrowAction:
            self.lineEditMobileShape.setText(
                u'((0, -0.5), (0.5, 0.5), (0, 0), (-0.5, 0.5))')

    @pyqtSlot(name='on_buttonBox_helpRequested')
    def showHelp(self):
        """Display application help to the user."""
        help_file = os.path.join(
            os.path.split(os.path.dirname(__file__))[0], 'help', 'index.html')
        QDesktopServices.openUrl(QUrl.fromLocalFile(help_file))
예제 #11
0
class Dialog(QDialog, Ui_nbEditor_dialog):         
    def __init__(self, iface, ml, mc):
        """Constructor for the dialog.
        
        Args:
          iface: QgsInterface instance.
        """
        
        QDialog.__init__(self, iface.mainWindow())                               
                        
        self.setupUi(self)
        
        self.ml = ml
        self.mCanvas = mc         
        self.mRubberBand = QgsRubberBand(self.mCanvas, True)
        self.mRubberBand.reset(QGis.Polygon)
        self.mRubberBand.setColor(Qt.red)
        self.mRubberBand.setWidth(2)
        self.ids = []
        
        self.ini(0)
        
        self.pushCancel.clicked.connect(self.close)
        self.pushOK.clicked.connect(self.convert)
        self.comboBox.addItems(['','Intersections','Touches','Within distance']) 
        
        self.comboBox.currentIndexChanged.connect(self.nbMethod)         
        self.ml.selectionChanged.connect(self.map2tab)
        
        
    def ini(self, n):
        self.model = QStandardItemModel(n, 1)
        self.tableView.setModel(self.model)
        self.model.setHeaderData(0, Qt.Horizontal, 'Neighbouring IDs')
        self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)        
        self.selectionModel = QItemSelectionModel(self.model)
        self.tableView.setSelectionModel(self.selectionModel)
        self.tableView.horizontalHeader().setStretchLastSection(True)    
        self.tableView.selectionModel().selectionChanged.connect(self.tab2map)
        self.progressBar.setValue(0)


    def settings(self):
        self.mod = min(self.ids)
        self.p = 1
        if self.mod==1:
            self.p = 0


    def map2tab(self):
        s = ''
        idx = self.tableView.selectionModel().selectedIndexes()[0]
        ts = str(self.model.itemData(idx)[0])
        
        for fid in sorted(self.ml.selectedFeaturesIds()):
            s += '%s,' % str(int(fid)+self.p)                   
 
        s = s[:-1]
         
        if s!=ts:
            self.model.setData(idx, s)
         
        # in order to handle the symmetry
        if len(s)>len(ts):
             iLst = s.strip().replace(' ', '').split(',')
             jLst = ts.strip().replace(' ', '').split(',')
        else:
             iLst = ts.strip().replace(' ', '').split(',')
             jLst = s.strip().replace(' ', '').split(',')
              
        cent = str(idx.row()+self.p)
        dLst = list(set(iLst)-set(jLst))
          
        for d in dLst:              
            row = int(d)-self.p
            sor = str(self.model.itemData(self.model.index(row, 0))[0])
            eLst = sor.strip().replace(' ', '').split(',')            
            res = ''
            if cent in set(eLst):
                ii = eLst.index(cent)                
                del eLst[ii]
                eLst = sorted(map(int, eLst))                
                for e in eLst:
                    res += '%s,' % e
                res = res[:-1]
            else:
                u = sor + ',%s' % cent
                eLst = sorted(map(int, u.strip().replace(' ', '').split(',')))
                for e in eLst:
                    res += '%s,' % e
                res = res[:-1]                 
                               
            self.model.setData(self.model.index(row, 0, QModelIndex()), res)
                   
                
    def nbWithinDist(self):
        dlg = xdist.Dialog()
        dlg.setModal(True)
        dlg.setWindowTitle("Between two objects")
                
        if dlg.exec_() == QDialog.Accepted:
            lDist = float(dlg.lineEdit.text())
            if lDist==0:
                return

            feat = QgsFeature()
            provider = self.ml.dataProvider()
            e = provider.featureCount()

            self.settings()

            for ne in range(self.mod, e + self.mod):
                feat = QgsFeature()
                geom = QgsGeometry()
                fiter = self.ml.getFeatures(QgsFeatureRequest(ne))
                if fiter.nextFeature(feat):
                    geom = QgsGeometry(feat.geometry())

                neighbours = self.hdist(feat, lDist)
                row = feat.id()-self.mod
                self.model.setData(self.model.index(row, 0, QModelIndex()), neighbours)
                self.progressBar.setValue(100*ne/e)


    def hdist(self, feata, lDist):
        geoma = QgsGeometry(feata.geometry()) 
        feat = QgsFeature()
        provider = self.ml.dataProvider()
        feats = provider.getFeatures()
        self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0)
        self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, provider.featureCount())) 
        ne = 0              
        neighbours = ""
        while feats.nextFeature(feat):
            ne += 1
            self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne)                       
            geomb = QgsGeometry(feat.geometry())            
            if feata.id()!=feat.id():
                if geoma.distance(geomb)<=lDist:
                    neighbours = neighbours + '%s,' % (feat.id()+self.p)
        return neighbours[:-1]            
    
    
    def tab2map(self):        
        QApplication.setOverrideCursor(Qt.WaitCursor)
        
        self.ml.selectionChanged.disconnect(self.map2tab)
        
        idx = self.tableView.selectionModel().selectedIndexes()[0]
        featureId = idx.row() + self.p
        
        s = self.model.itemData(idx)
        lst = s[0].strip().replace(' ', '').split(',')
        
        self.ml.removeSelection()
        
        for sid in lst:
            self.ml.select(int(sid)-self.p)
              
        provider = self.ml.dataProvider()        
        
        feat = QgsFeature()
        layer = QgsVectorLayerCache(self.ml, provider.featureCount())
        layer.featureAtId(idx.row()+self.mod, feat)
        geom = QgsGeometry(feat.geometry())   
        
        self.mRubberBand.setToGeometry(geom, self.ml)
        self.mRubberBand.show()
        
        self.ml.selectionChanged.connect(self.map2tab)
        
        QApplication.restoreOverrideCursor()        
        
        
    def closeEvent(self,event):
        QApplication.setOverrideCursor(Qt.WaitCursor)

        self.ml.selectionChanged.disconnect(self.map2tab)
        self.ml.removeSelection()
        self.mRubberBand.hide()
        self.close()

        QApplication.restoreOverrideCursor()

        
    def convert(self):
        dlg = editor.Dialog()
        dlg.setModal(True)
        dlg.setWindowTitle("Neighbour list in BUGS format")
        num = ""
        adj = ""
        sumNumNeigh = 0
        for row in range(0, self.model.rowCount()):
            ts = self.model.itemData(self.model.index(row, 0))
            lst = ts[0].strip().replace(' ', '').split(',')
            num += '%s, ' % len(lst)
            sumNumNeigh += len(lst)
            lst.reverse()
            sor = ', '.join(lst) + ','
            adj = adj + str(sor) + '\n' 
        
        num = num[:-2]
        adj = adj[:-2]
        
        nblist = 'list(\nnum = c(%s),\nadj = c(%s),\nsumNumNeigh=%s)' % (num, adj, sumNumNeigh)
        dlg.plainTextEdit.appendPlainText(nblist)
        
        dlg.exec_()                


    def nbMethod(self):
        QApplication.setOverrideCursor(Qt.WaitCursor)

        self.ml.selectionChanged.disconnect(self.map2tab)
        self.model.removeRows(0, self.model.rowCount(QModelIndex()), QModelIndex())
        n = self.ml.dataProvider().featureCount()
        self.ini(n)

        self.ids = []

        provider = self.ml.dataProvider()
        feats = provider.getFeatures()
        self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0)
        self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, n))
        ne = 0
        feat = QgsFeature()
        while feats.nextFeature(feat):
            ne += 1
            self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne)
            self.ids.append(feat.id())

        if self.comboBox.currentText()=="Touches":            
            if self.ml.geometryType()==0:
                return
            else:
                self.nbTouches()
        if self.comboBox.currentText()=="Intersections":
            if self.ml.geometryType()==0:
                return
            else:
                self.nbIntersects()
        if self.comboBox.currentText()=="Within distance":
            self.nbWithinDist()

        self.ml.selectionChanged.connect(self.map2tab)

        QApplication.restoreOverrideCursor()
        
            
    def nbTouches(self):                                
        feat = QgsFeature()
        provider = self.ml.dataProvider()
        e = provider.featureCount()

        self.settings()

        for ne in range(self.mod, e + self.mod):
            feat = QgsFeature()
            geom = QgsGeometry()
            fiter = self.ml.getFeatures(QgsFeatureRequest(ne))
            if fiter.nextFeature(feat):
                geom = QgsGeometry(feat.geometry())

            neighbours = self.htouch(feat)
            row = feat.id()-self.mod    
            self.model.setData(self.model.index(row, 0, QModelIndex()), neighbours)
            self.progressBar.setValue(100*ne/e)

         
    def htouch(self, feata):
        geoma = QgsGeometry(feata.geometry()) 
        feat = QgsFeature()
        provider = self.ml.dataProvider()
        feats = provider.getFeatures()
        self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0)
        self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, provider.featureCount())) 
        ne = 0              
        neighbours = ""
        while feats.nextFeature(feat):
            ne += 1
            self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne)                       
            geomb = QgsGeometry(feat.geometry())
            if feata.id()!=feat.id():
                if geoma.touches(geomb)==True:
                    neighbours = neighbours + '%s,' % (feat.id()+self.p)                
        return neighbours[:-1]

    
    def nbIntersects(self):
        feat = QgsFeature()
        provider = self.ml.dataProvider()
        e = provider.featureCount()

        self.settings()

        for ne in range(self.mod, e + self.mod):
            feat = QgsFeature()
            geom = QgsGeometry()
            fiter = self.ml.getFeatures(QgsFeatureRequest(ne))
            if fiter.nextFeature(feat):
                geom = QgsGeometry(feat.geometry())

            neighbours = self.hintersect(feat)
            row = feat.id()-self.mod
            self.model.setData(self.model.index(row, 0, QModelIndex()), neighbours)
            self.progressBar.setValue(100*ne/e)


    def hintersect(self, feata):
        geoma = QgsGeometry(feata.geometry())  
        feat = QgsFeature()
        provider = self.ml.dataProvider()
        feats = provider.getFeatures()
        self.emit(SIGNAL("runStatus(PyQt_PyObject)"), 0)
        self.emit(SIGNAL("runRange(PyQt_PyObject)"), (0, provider.featureCount())) 
        ne = 0              
        neighbours = ""
        while feats.nextFeature(feat):
            ne += 1
            self.emit(SIGNAL("runStatus(PyQt_PyObject)"), ne)                       
            geomb = QgsGeometry(feat.geometry())
            if feata.id()!=feat.id():
                if geoma.intersects(geomb)==True:
                    neighbours = neighbours + '%s,' % (feat.id()+self.p)
        return neighbours[:-1]