class PhotoViewer(QScrollArea): """ Widget for viewing images by incorporating basic navigation options. """ def __init__(self, parent=None, photo_path=""): QScrollArea.__init__(self, parent) self.setBackgroundRole(QPalette.Dark) self._printer = QPrinter() self._lbl_photo = QLabel() self._lbl_photo.setBackgroundRole(QPalette.Base) self._lbl_photo.setSizePolicy(QSizePolicy.Ignored,QSizePolicy.Ignored) self._lbl_photo.setScaledContents(True) self.setWidget(self._lbl_photo) self._photo_path = photo_path self._ph_image = None self._scale_factor = 1.0 self._aspect_ratio = -1 self._create_actions() if self._photo_path: self.load_document(self._photo_path) def _create_actions(self): """ Create actions for basic image navigation. """ self._zoom_in_act = QAction( QApplication.translate("PhotoViewer","Zoom &In (25%)"), self) self._zoom_in_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl++")) self._zoom_in_act.setEnabled(False) self._zoom_in_act.triggered.connect(self.zoom_in) self._zoom_out_act = QAction( QApplication.translate("PhotoViewer","Zoom &Out (25%)"), self) self._zoom_out_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl+-")) self._zoom_out_act.setEnabled(False) self._zoom_out_act.triggered.connect(self.zoom_out) self._normal_size_act = QAction( QApplication.translate("PhotoViewer","&Normal Size"), self) self._normal_size_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl+S")) self._normal_size_act.setEnabled(False) self._normal_size_act.triggered.connect(self.normal_size) self._fit_to_window_act = QAction( QApplication.translate("PhotoViewer","&Fit to Window"), self) self._fit_to_window_act.setShortcut( QApplication.translate("PhotoViewer","Ctrl+F")) self._fit_to_window_act.setEnabled(False) self._fit_to_window_act.setCheckable(True) self._fit_to_window_act.triggered.connect(self.fit_to_window) self._print_act = QAction( QApplication.translate("PhotoViewer","&Print"), self) self._print_act .setShortcut( QApplication.translate("PhotoViewer","Ctrl+P")) self._print_act .setEnabled(False) self._print_act .triggered.connect(self.print_photo) def zoom_in(self): self.scale_photo(1.25) def zoom_out(self): self.scale_photo(0.8) def normal_size(self): self._lbl_photo.adjustSize() self._scale_factor = 1.0 def fit_to_window(self): fit_to_win = self._fit_to_window_act.isChecked() self.setWidgetResizable(fit_to_win) if not fit_to_win: self.normal_size() self.update_actions() def print_photo(self): print_dialog = QPrintDialog(self._printer,self) if print_dialog.exec_() == QDialog.Accepted: painter = QPainter(self._printer) rect = painter.viewport() size = self._lbl_photo.pixmap().size() size.scale(rect.size(), Qt.KeepAspectRatio) painter.setViewport(rect.x(), rect.y(), size.width(), size.height()) painter.setWindow(self._lbl_photo.pixmap().rect()) painter.drawPixmap(0, 0, self._lbl_photo.pixmap()) def wheelEvent(self, event): """ Zoom the image based on the mouse wheel rotation action. :param event: Event containing the wheel rotation info. :type event: QWheelEvent """ degrees = event.delta() / 8 num_steps = degrees / 15 if num_steps < 0: abs_num_steps = abs(num_steps) zoom_factor = 1 + (abs_num_steps * 0.25) else: zoom_factor = 1 - (num_steps * 0.2) self.scale_photo(zoom_factor) def heightForWidth(self, width): if self._aspect_ratio != -1: return width / self._aspect_ratio else: return -1 def resizeEvent(self, event): """ Event for resizing the widget based on the pixmap's aspect ratio. :param event: Contains event parameters for the resize event. :type event: QResizeEvent """ super(PhotoViewer, self).resizeEvent(event) def update_actions(self): self._zoom_out_act.setEnabled(not self._fit_to_window_act.isChecked()) self._zoom_in_act.setEnabled(not self._fit_to_window_act.isChecked()) self._normal_size_act.setEnabled(not self._fit_to_window_act.isChecked()) def scale_photo(self,factor): """ :param factor: Value by which the image will be increased/decreased in the view. :type factor: float """ if not self._lbl_photo.pixmap().isNull(): self._scale_factor *= factor self._lbl_photo.resize(self._scale_factor * self._lbl_photo.pixmap().size()) self._adjust_scroll_bar(self.horizontalScrollBar(), factor) self._adjust_scroll_bar(self.verticalScrollBar(), factor) self._zoom_in_act.setEnabled(self._scale_factor < 3.0) self._zoom_out_act.setEnabled(self._scale_factor > 0.333) def _adjust_scroll_bar(self, scroll_bar, factor): scroll_bar.setValue(int(factor * scroll_bar.value() + ((factor - 1) * scroll_bar.pageStep()/2))) def load_document(self, photo_path): if photo_path: self._ph_image = QImage(photo_path) if self._ph_image.isNull(): return False self._photo_path = photo_path ph_pixmap = QPixmap.fromImage(self._ph_image) self._lbl_photo.setPixmap(ph_pixmap) self._scale_factor = 1.0 self._aspect_ratio = ph_pixmap.width() / ph_pixmap.height() self._fit_to_window_act.setEnabled(True) self._print_act.setEnabled(True) self._fit_to_window_act.trigger() self.update_actions() return ph_pixmap return True def photo_location(self): """ :returns: Absolute path of the photo in the central document repository. """ return self._photo_path def set_actions(self,menu): """ Add custom actions to the sub-window menu """ menu.addSeparator() menu.addAction(self._zoom_in_act) menu.addAction(self._zoom_out_act) menu.addAction(self._normal_size_act) menu.addAction(self._fit_to_window_act) menu.addSeparator() menu.addAction(self._print_act)
class DMX(COMCUPluginBase, Ui_DMX): qtcb_frame_started = pyqtSignal() qtcb_frame = pyqtSignal(object, int) def __init__(self, *args): COMCUPluginBase.__init__(self, BrickletDMX, *args) self.setupUi(self) self.dmx = self.device self.wait_for_first_read = True self.dmx_overview = DMXOverview(self) self.layout_dmx_overview.insertWidget(1, self.dmx_overview) self.qtcb_frame_started.connect(self.cb_frame_started) self.qtcb_frame.connect(self.cb_frame) self.mode_combobox.currentIndexChanged.connect(self.mode_changed) self.frame_duration_spinbox.valueChanged.connect( self.frame_duration_changed) self.address_spinboxes = [] self.address_slider = [] for i in range(512): spinbox = QSpinBox() spinbox.setMinimum(0) spinbox.setMaximum(255) slider = QSlider(Qt.Horizontal) slider.setMinimum(0) slider.setMaximum(255) spinbox.valueChanged.connect(slider.setValue) slider.valueChanged.connect(spinbox.setValue) def get_frame_value_changed_func(i): return lambda x: self.frame_value_changed(i, x) slider.valueChanged.connect(get_frame_value_changed_func(i)) self.address_table.setCellWidget(i, 0, spinbox) self.address_table.setCellWidget(i, 1, slider) self.address_spinboxes.append(spinbox) self.address_slider.append(slider) self.address_table.horizontalHeader().setStretchLastSection(True) self.address_table.show() self.current_frame = [0] * 512 self.com_led_off_action = QAction('Off', self) self.com_led_off_action.triggered.connect( lambda: self.dmx.set_communication_led_config( BrickletDMX.COMMUNICATION_LED_CONFIG_OFF)) self.com_led_on_action = QAction('On', self) self.com_led_on_action.triggered.connect( lambda: self.dmx.set_communication_led_config( BrickletDMX.COMMUNICATION_LED_CONFIG_ON)) self.com_led_show_heartbeat_action = QAction('Show Heartbeat', self) self.com_led_show_heartbeat_action.triggered.connect( lambda: self.dmx.set_communication_led_config( BrickletDMX.COMMUNICATION_LED_CONFIG_SHOW_HEARTBEAT)) self.com_led_show_communication_action = QAction('Show Com', self) self.com_led_show_communication_action.triggered.connect( lambda: self.dmx.set_communication_led_config( BrickletDMX.COMMUNICATION_LED_CONFIG_SHOW_COMMUNICATION)) self.extra_configs += [(1, 'Com LED:', [ self.com_led_off_action, self.com_led_on_action, self.com_led_show_heartbeat_action, self.com_led_show_communication_action ])] self.error_led_off_action = QAction('Off', self) self.error_led_off_action.triggered.connect( lambda: self.dmx.set_error_led_config(BrickletDMX. ERROR_LED_CONFIG_OFF)) self.error_led_on_action = QAction('On', self) self.error_led_on_action.triggered.connect( lambda: self.dmx.set_error_led_config(BrickletDMX. ERROR_LED_CONFIG_ON)) self.error_led_show_heartbeat_action = QAction('Show Heartbeat', self) self.error_led_show_heartbeat_action.triggered.connect( lambda: self.dmx.set_error_led_config( BrickletDMX.ERROR_LED_CONFIG_SHOW_HEARTBEAT)) self.error_led_show_error_action = QAction('Show Error', self) self.error_led_show_error_action.triggered.connect( lambda: self.dmx.set_error_led_config(BrickletDMX. ERROR_LED_CONFIG_SHOW_ERROR)) self.extra_configs += [(1, 'Error LED:', [ self.error_led_off_action, self.error_led_on_action, self.error_led_show_heartbeat_action, self.error_led_show_error_action ])] def frame_value_changed(self, line, value): self.current_frame[line] = value self.dmx_overview.draw_line(line, value, None, True) def mode_changed(self, index, update=True): if index == 0: for spinbox in self.address_spinboxes: spinbox.setReadOnly(False) for slider in self.address_slider: slider.setEnabled(True) self.frame_duration_label.setVisible(True) self.frame_duration_unit.setVisible(True) self.frame_duration_spinbox.setVisible(True) else: for spinbox in self.address_spinboxes: spinbox.setReadOnly(True) for slider in self.address_slider: slider.setEnabled(False) self.frame_duration_label.setVisible(False) self.frame_duration_unit.setVisible(False) self.frame_duration_spinbox.setVisible(False) if update: self.dmx.set_dmx_mode(index) def frame_duration_changed(self, value): self.dmx.set_frame_duration(value) def handle_new_frame(self, frame): for i, value in enumerate(frame): self.address_spinboxes[i].setValue(value) self.frame_value_changed(i, value) self.wait_for_first_read = False def cb_get_frame_duration(self, frame_duration): self.frame_duration_spinbox.blockSignals(True) self.frame_duration_spinbox.setValue(frame_duration) self.frame_duration_spinbox.blockSignals(False) def cb_get_dmx_mode(self, mode): self.mode_combobox.blockSignals(True) self.mode_combobox.setCurrentIndex(mode) self.mode_changed(mode, False) self.mode_combobox.blockSignals(False) if mode == self.dmx.DMX_MODE_MASTER: async_call(self.dmx.read_frame, None, self.cb_read_frame, self.increase_error_count) def cb_read_frame(self, frame): self.handle_new_frame(frame.frame) def cb_frame_started(self): if not self.wait_for_first_read: async_call(self.dmx.write_frame, self.current_frame, None, self.increase_error_count) def cb_frame(self, frame, frame_number): if frame == None: return self.handle_new_frame(frame) def get_communication_led_config_async(self, config): if config == BrickletDMX.COMMUNICATION_LED_CONFIG_OFF: self.com_led_off_action.trigger() elif config == BrickletDMX.COMMUNICATION_LED_CONFIG_ON: self.com_led_on_action.trigger() elif config == BrickletDMX.COMMUNICATION_LED_CONFIG_SHOW_HEARTBEAT: self.com_led_show_heartbeat_action.trigger() elif config == BrickletDMX.COMMUNICATION_LED_CONFIG_SHOW_COMMUNICATION: self.com_led_show_communication_action.trigger() def get_error_led_config_async(self, config): if config == BrickletDMX.ERROR_LED_CONFIG_OFF: self.error_led_off_action.trigger() elif config == BrickletDMX.ERROR_LED_CONFIG_ON: self.error_led_on_action.trigger() elif config == BrickletDMX.ERROR_LED_CONFIG_SHOW_HEARTBEAT: self.error_led_show_heartbeat_action.trigger() elif config == BrickletDMX.ERROR_LED_CONFIG_SHOW_ERROR: self.error_led_show_error_action.trigger() def start(self): async_call(self.dmx.get_communication_led_config, None, self.get_communication_led_config_async, self.increase_error_count) async_call(self.dmx.get_error_led_config, None, self.get_error_led_config_async, self.increase_error_count) async_call(self.dmx.get_frame_duration, None, self.cb_get_frame_duration, self.increase_error_count) async_call(self.dmx.get_dmx_mode, None, self.cb_get_dmx_mode, self.increase_error_count) self.dmx.register_callback(self.dmx.CALLBACK_FRAME_STARTED, self.qtcb_frame_started.emit) self.dmx.register_callback(self.dmx.CALLBACK_FRAME, self.qtcb_frame.emit) self.dmx.set_frame_callback_config(True, False, True, False) def stop(self): self.dmx.register_callback(self.dmx.CALLBACK_FRAME, None) self.dmx.register_callback(self.dmx.CALLBACK_FRAME_STARTED, None) self.wait_for_first_read = True def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletDMX.DEVICE_IDENTIFIER
class ReadFromFile_ui(QObject): def __init__(self, parent = None): super(ReadFromFile_ui, self).__init__(parent) self.parent = parent self.initUi() self.packetDataUi = None ''' Description: Initialise the Icons and Menu Items to add to the Interface ''' def initUi(self): openPixmap = QPixmap(os.path.dirname(os.path.realpath(__file__)) + '/Open.png') savePixmap = QPixmap(os.path.dirname(os.path.realpath(__file__)) + '/Save.png') openIcon = QIcon(openPixmap) saveIcon = QIcon(savePixmap) self.openToolButton = QToolButton(self.parent) self.saveToolButton = QToolButton(self.parent) self.openToolButton.setIcon(openIcon) self.saveToolButton.setIcon(saveIcon) self.openToolButton.setIconSize(QSize(32, 32)) self.saveToolButton.setIconSize(QSize(32, 32)) self.openToolButton.clicked.connect(self.openToolButtonClicked) self.saveToolButton.clicked.connect(self.saveToolButtonClicked) self.openAction = QAction("Open", self.parent) self.openAction.triggered.connect(self.openToolButtonClicked) self.saveAction = QAction("Save", self.parent) self.saveAction.triggered.connect(self.saveToolButtonClicked) menuCapture = self.parent.GetMenu("File") if menuCapture != None: menuCapture.addAction(self.openAction) menuCapture.addAction(self.saveAction) menuCapture.addSeparator() toolBarCapture = self.parent.GetToolBar("File") if toolBarCapture != None: toolBarCapture.addWidget(self.openToolButton) toolBarCapture.addWidget(self.saveToolButton) ''' Description: On clicking Open Button/Action: Obtain file path and read the pcap file into a list Send the packets read by the reader to be displayed using PacketData_Ui ''' @pyqtSlot() def openToolButtonClicked(self): filename = QFileDialog.getOpenFileName(self.parent, "Load Pcap File", "/home/", "*.pcap") if str(filename) != "": readFromFile = ReadFromFile() readFromFile.setFilename(str(filename)) packets = readFromFile.readPackets() self.packetDataUi = PacketData_ui(self.parent) for packet in packets: self.packetDataUi.AddPacket(packet) ''' Description: On clicking Save Button/Action: Check if current tab is a PacketDataUi. If yes, then get path of the destination file and dump the list in pcap format at the specified destination ''' @pyqtSlot() def saveToolButtonClicked(self): widget = self.parent.GetCurrentTab() if widget != None and isinstance(widget, PacketData_ui): filename = QFileDialog.getSaveFileName(self.parent, "Save Pcap File", "/home/", "*.pcap") strFilename = str(filename) if not strFilename.endswith(".pcap"): strFilename = strFilename + ".pcap" ReadFromFile().saveFile(strFilename, widget.packetList) ''' Description: Wrapper to trigger the Open File action ''' @pyqtSlot() def triggerOpen(self): self.openAction.trigger() ''' Description: Wrapper to trigger the Save file action ''' @pyqtSlot() def triggerSave(self): self.saveAction.trigger()
class QMap(): def __init__(self, iface): self.iface = iface self.actions = [] self.panels= [] self.navtoolbar = self.iface.mapNavToolToolBar() self.mainwindow = self.iface.mainWindow() self.iface.projectRead.connect(self.projectOpened) self.iface.initializationCompleted.connect(self.setupUI) self.actionGroup = QActionGroup(self.mainwindow) self.actionGroup.setExclusive(True) self.menuGroup = QActionGroup(self.mainwindow) self.menuGroup.setExclusive(True) self.movetool = MoveTool(self.iface.mapCanvas(), []) self.infotool = InfoTool(self.iface.mapCanvas()) self.infotool.infoResults.connect(self.showInfoResults) self.report = PopDownReport(self.iface.messageBar()) self.dialogprovider = DialogProvider(iface.mapCanvas(), iface) self.dialogprovider.accepted.connect(self.clearToolRubberBand) self.dialogprovider.rejected.connect(self.clearToolRubberBand) self.edittool = EditTool(self.iface.mapCanvas(),[]) self.edittool.finished.connect(self.openForm) self.edittool.featuresfound.connect(self.showFeatureSelection) self.infodock = InfoDock(self.iface.mainWindow()) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.infodock) self.infodock.hide() self.band = QgsRubberBand(self.iface.mapCanvas()) self.band.setIconSize(20) self.band.setWidth(10) self.band.setColor(QColor(186, 93, 212, 76)) def showFeatureSelection(self, features): listUi = ListFeaturesForm(self.mainwindow) listUi.loadFeatureList(features) listUi.openFeatureForm.connect(self.openForm) listUi.exec_() def showInfoResults(self, results): self.infodock.clearResults() self.infodock.setResults(results) self.infodock.show() self.infodock.repaint() @property def _mapLayers(self): return QgsMapLayerRegistry.instance().mapLayers() def clearToolRubberBand(self): tool = self.iface.mapCanvas().mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def missingLayers(self, layers): def showError(): html = ["<h1>Missing Layers</h1>", "<ul>"] for layer in layers: html.append("<li>{}</li>".format(layer)) html.append("</ul>") self.errorreport.updateHTML("".join(html)) message = "Seems like {} didn't load correctly".format(utils._pluralstring('layer', len(layers))) utils.warning("Missing layers") map(utils.warning, layers) self.widget = self.iface.messageBar().createMessage("Missing Layers", message, QIcon(":/icons/sad")) button = QPushButton(self.widget) button.setCheckable(True) button.setChecked(self.errorreport.isVisible()) button.setText("Show missing layers") button.toggled.connect(showError) button.toggled.connect(functools.partial(self.errorreport.setVisible)) self.widget.destroyed.connect(self.hideReports) self.widget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.widget, QgsMessageBar.WARNING) def excepthook(self, ex_type, value, tb): """ Custom exception hook so that we can handle errors in a nicer way """ where = ''.join(traceback.format_tb(tb)) msg = '{}'.format(value) utils.critical(msg) def showError(): html = """ <html> <body bgcolor="#FFEDED"> <p><b>{}</b></p> <p align="left"><small>{}</small></p> </body> </html> """.format(msg, where) self.errorreport.updateHTML(html) self.widget = self.iface.messageBar().createMessage("oops", "Looks like an error occurred", QIcon(":/icons/sad")) button = QPushButton(self.widget) button.setCheckable(True) button.setChecked(self.errorreport.isVisible()) button.setText("Show error") button.toggled.connect(showError) button.toggled.connect(functools.partial(self.errorreport.setVisible)) self.widget.destroyed.connect(self.hideReports) self.widget.layout().addWidget(button) self.messageBar.pushWidget(self.widget, QgsMessageBar.CRITICAL) def hideReports(self): self.errorreport.setVisible(False) self.report.setVisible(False) def setupUI(self): """ Set up the main QGIS interface items. Called after QGIS has loaded the plugin. """ self.updateAppSize() utils.settings_notify.settings_changed.connect(self.updateAppSize) self.navtoolbar.setMovable(False) self.navtoolbar.setAllowedAreas(Qt.TopToolBarArea) self.mainwindow.insertToolBar(self.toolbar, self.navtoolbar) self.openProjectAction.trigger() def updateAppSize(self): fullscreen = utils.settings.get("fullscreen", False) if fullscreen: self.mainwindow.showFullScreen() else: self.mainwindow.showMaximized() def setMapTool(self, tool): """ Set the current mapview canvas tool tool -- The QgsMapTool to set """ self.iface.mapCanvas().setMapTool(tool) def createToolBars(self): """ Create all the needed toolbars """ self.menutoolbar = QToolBar("Menu", self.mainwindow) self.menutoolbar.setMovable(False) self.menutoolbar.setAllowedAreas(Qt.LeftToolBarArea) self.mainwindow.addToolBar(Qt.LeftToolBarArea, self.menutoolbar) self.toolbar = QToolBar("QMap", self.mainwindow) self.mainwindow.addToolBar(Qt.TopToolBarArea, self.toolbar) self.toolbar.setMovable(False) self.editingtoolbar = FloatingToolBar("Editing", self.toolbar) self.extraaddtoolbar = FloatingToolBar("Extra Add Tools", self.toolbar) self.syncactionstoolbar = FloatingToolBar("Syncing", self.toolbar) self.syncactionstoolbar.setOrientation(Qt.Vertical) def createActions(self): """ Create all the actions """ self.homeAction = (QAction(QIcon(":/icons/zoomfull"), "Default View", self.mainwindow)) self.gpsAction = (GPSAction(QIcon(":/icons/gps"), self.iface.mapCanvas(), self.mainwindow)) self.openProjectAction = (QAction(QIcon(":/icons/open"), "Projects", self.mainwindow)) self.openProjectAction.setCheckable(True) self.configAction = (QAction(QIcon(":/icons/config"), "Settings", self.mainwindow)) self.configAction.setCheckable(True) self.toggleRasterAction = (QAction(QIcon(":/icons/photo"), "Aerial Photos", self.mainwindow)) self.syncAction = QAction(QIcon(":/icons/sync"), "Sync", self.mainwindow) self.syncAction.setVisible(False) self.editattributesaction = QAction(QIcon(":/icons/edit"), "Edit Attributes", self.mainwindow) self.editattributesaction.setCheckable(True) self.editattributesaction.toggled.connect(functools.partial(self.setMapTool, self.edittool)) self.moveaction = QAction(QIcon(":/icons/move"), "Move Feature", self.mainwindow) self.moveaction.setCheckable(True) self.editingmodeaction = QAction(QIcon(":/icons/edittools"), "Edit Tools", self.mainwindow) self.editingmodeaction.setCheckable(True) self.infoaction = QAction(QIcon(":/icons/info"), "Info", self.mainwindow) self.infoaction.setCheckable(True) self.addatgpsaction = QAction(QIcon(":/icons/gpsadd"), "Add at GPS", self.mainwindow) self.edittool.layersupdated.connect(self.editattributesaction.setVisible) self.movetool.layersupdated.connect(self.moveaction.setVisible) self.movetool.layersupdated.connect(self.editingmodeaction.setVisible) def initGui(self): """ Create all the icons and setup the tool bars. Called by QGIS when loading. This is called before setupUI. """ QApplication.setWindowIcon(QIcon(":/branding/logo")) self.mainwindow.findChildren(QMenuBar)[0].setVisible(False) self.mainwindow.setContextMenuPolicy(Qt.PreventContextMenu) self.mainwindow.setWindowTitle("IntraMaps Roam: Mobile Data Collection") # Disable QGIS logging window popups. We do our own logging QgsMessageLog.instance().messageReceived.disconnect() s = """ QToolButton { padding: 6px; color: #4f4f4f; } QToolButton:hover { padding: 6px; background-color: rgb(211, 228, 255); } QToolBar { background: white; } QCheckBox::indicator { width: 40px; height: 40px; } QLabel { color: #4f4f4f; } QDialog { background-color: rgb(255, 255, 255); } QPushButton { border: 1px solid #e1e1e1; padding: 6px; color: #4f4f4f; } QPushButton:hover { border: 1px solid #e1e1e1; padding: 6px; background-color: rgb(211, 228, 255); } QCheckBox { color: #4f4f4f; } QComboBox::drop-down { width: 30px; } QComboBox { border: 1px solid #d3d3d3; } QStackedWidget { background-color: rgb(255, 255, 255); } """ self.mainwindow.setStyleSheet(s) mainwidget = self.mainwindow.centralWidget() mainwidget.setLayout(QGridLayout()) mainwidget.layout().setContentsMargins(0,0,0,0) newlayout = QGridLayout() newlayout.setContentsMargins(0,0,0,0) newlayout.addWidget(self.iface.mapCanvas(), 0,0,2,1) newlayout.addWidget(self.iface.messageBar(), 0,0,1,1) wid = QWidget() wid.setLayout(newlayout) self.stack = QStackedWidget(self.mainwindow) self.messageBar = QgsMessageBar(wid) self.messageBar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed ) self.errorreport = PopDownReport(self.messageBar) mainwidget.layout().addWidget(self.stack, 0,0,2,1) mainwidget.layout().addWidget(self.messageBar, 0,0,1,1) self.helppage = HelpPage() helppath = os.path.join(os.path.dirname(__file__) , 'help',"help.html") self.helppage.setHelpPage(helppath) self.settingswidget = SettingsWidget(self.stack) self.projectwidget = ProjectsWidget() self.projectwidget.requestOpenProject.connect(self.loadProject) self.stack.addWidget(wid) self.stack.addWidget(self.projectwidget) self.stack.addWidget(self.helppage) self.stack.addWidget(self.settingswidget) sys.excepthook = self.excepthook def createSpacer(width=30): widget = QWidget() widget.setMinimumWidth(width) return widget self.createToolBars() self.createActions() spacewidget = createSpacer(60) gpsspacewidget = createSpacer() gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.moveaction.toggled.connect(functools.partial(self.setMapTool, self.movetool)) self.infoaction.toggled.connect(functools.partial(self.setMapTool, self.infotool)) showediting = (functools.partial(self.editingtoolbar.showToolbar, self.editingmodeaction, self.moveaction)) self.editingmodeaction.toggled.connect(showediting) self.addatgpsaction.triggered.connect(self.addAtGPS) self.addatgpsaction.setEnabled(self.gpsAction.isConnected) self.gpsAction.gpsfixed.connect(self.addatgpsaction.setEnabled) self.editingtoolbar.addToActionGroup(self.moveaction) self.actionGroup.addAction(self.editingmodeaction) self.actionGroup.addAction(self.editattributesaction) self.actionGroup.addAction(self.infoaction) self.homeAction.triggered.connect(self.zoomToDefaultView) self.openProjectAction.triggered.connect(self.showOpenProjectDialog) self.openProjectAction.triggered.connect(functools.partial(self.stack.setCurrentIndex, 1)) self.configAction.triggered.connect(functools.partial(self.stack.setCurrentIndex, 3)) self.configAction.triggered.connect(self.settingswidget.populateControls) self.configAction.triggered.connect(self.settingswidget.readSettings) self.toggleRasterAction.triggered.connect(self.toggleRasterLayers) self.navtoolbar.insertAction(self.iface.actionZoomIn(), self.iface.actionTouch()) self.navtoolbar.insertAction(self.iface.actionTouch(), self.homeAction) self.navtoolbar.insertAction(self.iface.actionTouch(), self.iface.actionZoomFullExtent()) self.navtoolbar.insertAction(self.homeAction, self.iface.actionZoomFullExtent()) self.navtoolbar.addAction(self.toggleRasterAction) self.navtoolbar.insertWidget(self.iface.actionZoomFullExtent(), spacewidget) self.toolbar.addAction(self.infoaction) self.toolbar.addAction(self.editingmodeaction) self.toolbar.addAction(self.editattributesaction) self.toolbar.addAction(self.syncAction) self.toolbar.addAction(self.gpsAction) self.toolbar.insertWidget(self.syncAction, gpsspacewidget) self.toolbar.insertSeparator(self.gpsAction) self.extraaddtoolbar.addAction(self.addatgpsaction) self.editingtoolbar.addAction(self.moveaction) self.mapview = QAction(QIcon(":/icons/map"), "Map", self.menutoolbar) self.mapview.setCheckable(True) self.mapview.triggered.connect(functools.partial(self.stack.setCurrentIndex, 0)) self.help = QAction(QIcon(":/icons/help"), "Help", self.menutoolbar) self.help.setCheckable(True) self.help.triggered.connect(functools.partial(self.stack.setCurrentIndex, 2)) self.help.setVisible(False) self.projectlabel = QLabel("Project: <br> None") self.projectlabel.setAlignment(Qt.AlignCenter) self.projectlabel.setStyleSheet(""" QLabel { color: #8c8c8c; font: 10px "Calibri" ; }""") self.userlabel = QLabel("User: <br> {user}".format(user=getpass.getuser())) self.userlabel.setAlignment(Qt.AlignCenter) self.userlabel.setStyleSheet(""" QLabel { color: #8c8c8c; font: 10px "Calibri" ; }""") self.quit = QAction(QIcon(":/icons/quit"), "Quit", self.menutoolbar) self.quit.triggered.connect(self.iface.actionExit().trigger) self.menuGroup.addAction(self.mapview) self.menuGroup.addAction(self.openProjectAction) self.menuGroup.addAction(self.help) self.menuGroup.addAction(self.configAction) self.menutoolbar.addAction(self.mapview) self.menutoolbar.addAction(self.openProjectAction) self.menutoolbar.addAction(self.help) self.menutoolbar.addAction(self.configAction) self.menutoolbar.addAction(self.quit) quitspacewidget = createSpacer() quitspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) labelaction = self.menutoolbar.insertWidget(self.configAction, self.userlabel) self.menutoolbar.insertWidget(labelaction, quitspacewidget) self.menutoolbar.insertWidget(labelaction, self.projectlabel) self.setupIcons() self.stack.currentChanged.connect(self.updateUIState) def updateUIState(self, page): """ Update the UI state to reflect the currently selected page in the stacked widget """ def setToolbarsActive(enabled): toolbars = self.mainwindow.findChildren(QToolBar) for toolbar in toolbars: if toolbar == self.menutoolbar: continue toolbar.setEnabled(enabled) def setPanelsVisible(visible): for panel in self.panels: panel.setVisible(visible) ismapview = page == 0 setToolbarsActive(ismapview) setPanelsVisible(ismapview) self.infodock.hide() def addAtGPS(self): """ Add a record at the current GPS location. """ action = self.actionGroup.checkedAction() if not action: return layer = action.data() if not layer: return point = self.gpsAction.position self.addNewFeature(layer=layer, geometry=point) def zoomToDefaultView(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.iface.mapCanvas().setExtent(self.defaultextent) self.iface.mapCanvas().refresh() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ legend = self.iface.legendInterface() #Freeze the canvas to save on UI refresh self.iface.mapCanvas().freeze() for layer in self._mapLayers.values(): if layer.type() == QgsMapLayer.RasterLayer: isvisible = legend.isLayerVisible(layer) legend.setLayerVisible(layer, not isvisible) self.iface.mapCanvas().freeze(False) self.iface.mapCanvas().refresh() def setupIcons(self): """ Update toolbars to have text and icons, change normal QGIS icons to new style """ toolbars = self.mainwindow.findChildren(QToolBar) for toolbar in toolbars: toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) toolbar.setIconSize(QSize(32, 32)) self.iface.actionTouch().setIconText("Pan") self.iface.actionTouch().setIcon(QIcon(":/icons/pan")) self.iface.actionZoomIn().setIcon(QIcon(":/icons/in")) self.iface.actionZoomOut().setIcon(QIcon(":/icons/out")) self.iface.actionPan().setIcon(QIcon(":/icons/pan")) self.iface.actionZoomFullExtent().setIcon(QIcon(":/icons/home")) self.iface.actionZoomFullExtent().setIconText("Home View") self.actionGroup.addAction(self.iface.actionZoomIn()) self.actionGroup.addAction(self.iface.actionZoomOut()) self.actionGroup.addAction(self.iface.actionTouch()) def projectOpened(self): """ Called when a new project is opened in QGIS. """ for panel in self.panels: self.mainwindow.removeDockWidget(panel) del panel projectpath = QgsProject.instance().fileName() project = QMapProject(os.path.dirname(projectpath), self.iface) self.projectlabel.setText("Project: <br> {}".format(project.name)) self.createFormButtons(projectlayers = project.getConfiguredLayers()) # Enable the raster layers button only if the project contains a raster layer. hasrasters = any(layer.type() for layer in self._mapLayers.values()) self.toggleRasterAction.setEnabled(hasrasters) self.defaultextent = self.iface.mapCanvas().extent() self.connectSyncProviders(project) # Show panels self.panels = list(project.getPanels()) for panel in self.panels: self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea , panel) self.iface.messageBar().popWidget() def captureLayer(self, layer): text = layer.icontext tool = layer.getMaptool(self.iface.mapCanvas()) # Hack until I fix it later if isinstance(tool, PointTool): add = functools.partial(self.addNewFeature, qgslayer) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(functools.partial(self.showToolError, text)) action = QAction(QIcon(layer.icon), text, self.mainwindow) action.setData(layer) action.setCheckable(True) action.toggled.connect(functools.partial(self.setMapTool, tool)) self.toolbar.insertAction(self.editingmodeaction, action) if not tool.isEditTool(): # Connect the GPS tools strip to the action pressed event. showgpstools = (functools.partial(self.extraaddtoolbar.showToolbar, action, None)) action.toggled.connect(showgpstools) self.actionGroup.addAction(action) self.actions.append(action) def editLayer(self, layer): self.edittool.addLayer(layer.QGISLayer) self.edittool.searchRadius = 10 def moveLayer(self, layer): self.movetool.addLayer(layer.QGISLayer) def createFormButtons(self, projectlayers): """ Create buttons for each form that is definded """ # Remove all the old buttons for action in self.actions: self.actionGroup.removeAction(action) self.toolbar.removeAction(action) self.edittool.layers = [] self.movetool.layers = [] capabilitityhandlers = { "capture" : self.captureLayer, "edit" : self.editLayer, "move" : self.moveLayer} for layer in projectlayers: try: qgslayer = QgsMapLayerRegistry.instance().mapLayersByName(layer.name)[0] if qgslayer.type() == QgsMapLayer.RasterLayer: utils.log("We can't support raster layers for data entry") continue layer.QGISLayer = qgslayer except IndexError: utils.log("Layer {} not found in project".format(layer.name)) continue for capability in layer.capabilities: try: capabilitityhandlers[capability](layer) except NoMapToolConfigured: utils.log("No map tool configured") continue except ErrorInMapTool as error: self.iface.messageBar().pushMessage("Error configuring map tool", error.message, level=QgsMessageBar.WARNING) continue def showToolError(self, label, message): self.iface.messageBar().pushMessage(label, message, QgsMessageBar.WARNING) def openForm(self, layer, feature): if not layer.isEditable(): layer.startEditing() self.band.setToGeometry(feature.geometry(), layer) self.dialogprovider.openDialog(feature=feature, layer=layer) self.band.reset() def addNewFeature(self, layer, geometry): fields = layer.pendingFields() feature = QgsFeature() feature.setGeometry( geometry ) feature.initAttributes(fields.count()) feature.setFields(fields) for indx in xrange(fields.count()): feature[indx] = layer.dataProvider().defaultValue(indx) self.openForm(layer, feature) def showOpenProjectDialog(self): """ Show the project selection dialog. """ self.stack.setCurrentIndex(1) self.infodock.hide() path = os.path.join(os.path.dirname(__file__), '..' , 'projects/') projects = getProjects(path, self.iface) self.projectwidget.loadProjectList(projects) def loadProject(self, project): """ Load a project into QGIS. """ utils.log(project) utils.log(project.name) utils.log(project.projectfile) utils.log(project.vaild) (passed, message) = project.onProjectLoad() if not passed: QMessageBox.warning(self.mainwindow, "Project Load Rejected", "Project couldn't be loaded because {}".format(message)) return self.mapview.trigger() self.iface.newProject(False) self.iface.mapCanvas().freeze() self.infodock.clearResults() # No idea why we have to set this each time. Maybe QGIS deletes it for # some reason. self.badLayerHandler = BadLayerHandler(callback=self.missingLayers) QgsProject.instance().setBadLayerHandler( self.badLayerHandler ) self.iface.messageBar().pushMessage("Project Loading","", QgsMessageBar.INFO) QApplication.processEvents() fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) self.iface.mapCanvas().updateScale() self.iface.mapCanvas().freeze(False) self.iface.mapCanvas().refresh() self.mainwindow.setWindowTitle("IntraMaps Roam: Mobile Data Collection") self.iface.projectRead.emit() def unload(self): del self.toolbar def connectSyncProviders(self, project): self.syncactionstoolbar.clear() syncactions = list(project.syncprovders()) # Don't show the sync button if there is no sync providers if not syncactions: self.syncAction.setVisible(False) return self.syncAction.setVisible(True) for provider in syncactions: action = QAction(QIcon(":/icons/sync"), "Sync {}".format(provider.name), self.mainwindow) action.triggered.connect(functools.partial(self.syncProvider, provider)) self.syncactionstoolbar.addAction(action) try: self.syncAction.toggled.disconnect() except TypeError: pass try: self.syncAction.triggered.disconnect() except TypeError: pass if len(syncactions) == 1: # If one provider is set then we just connect the main button. self.syncAction.setCheckable(False) self.syncAction.setText("Sync") self.syncAction.triggered.connect(functools.partial(self.syncProvider, syncactions[0])) else: # the sync button because a sync menu self.syncAction.setCheckable(True) self.syncAction.setText("Sync Menu") showsyncoptions = (functools.partial(self.syncactionstoolbar.showToolbar, self.syncAction, None)) self.syncAction.toggled.connect(showsyncoptions) def syncstarted(self): # Remove the old widget if it's still there. # I don't really like this. Seems hacky. try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass except AttributeError: pass self.iface.messageBar().findChildren(QToolButton)[0].setVisible(False) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync in progress", QIcon(":/icons/syncing")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setText("Status") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) pro = QProgressBar() pro.setMaximum(0) pro.setMinimum(0) self.syncwidget.layout().addWidget(pro) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget, QgsMessageBar.INFO) def synccomplete(self): try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass stylesheet = ("QgsMessageBar { background-color: rgba(239, 255, 233); border: 0px solid #b9cfe4; } " "QLabel,QTextEdit { color: #057f35; } ") closebutton = self.iface.messageBar().findChildren(QToolButton)[0] closebutton.setVisible(True) closebutton.clicked.connect(functools.partial(self.report.setVisible, False)) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync Complete", QIcon(":/icons/syncdone")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setChecked(self.report.isVisible()) button.setText("Sync Report") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) pro = QProgressBar() pro.setMaximum(100) pro.setValue(100) self.syncwidget.layout().addWidget(pro) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget) self.iface.messageBar().setStyleSheet(stylesheet) self.iface.mapCanvas().refresh() def syncerror(self): try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass closebutton = self.iface.messageBar().findChildren(QToolButton)[0] closebutton.setVisible(True) closebutton.clicked.connect(functools.partial(self.report.setVisible, False)) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync Error", QIcon(":/icons/syncfail")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setChecked(self.report.isVisible()) button.setText("Sync Report") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget, QgsMessageBar.CRITICAL) self.iface.mapCanvas().refresh() def syncProvider(self, provider): self.syncAction.toggle() provider.syncStarted.connect(functools.partial(self.syncAction.setEnabled, False)) provider.syncStarted.connect(self.syncstarted) provider.syncComplete.connect(self.synccomplete) provider.syncComplete.connect(functools.partial(self.syncAction.setEnabled, True)) provider.syncComplete.connect(functools.partial(self.report.updateHTML)) provider.syncMessage.connect(self.report.updateHTML) provider.syncError.connect(self.report.updateHTML) provider.syncError.connect(self.syncerror) provider.syncError.connect(functools.partial(self.syncAction.setEnabled, True)) provider.startSync()
def initializeMainGui(): m = uic.loadUi("gui/gui.ui") m.settings = Settings() m.setWindowTitle('ceilingfaan') m.actionExit.triggered.connect(QtGui.qApp.quit) m.actionOpen.triggered.connect(types.MethodType( getfilename, m)) # This is a way to add methods to a class after instantiation. m.actionSettings.triggered.connect(types.MethodType(openSettingsDialog, m)) m.actionSave.triggered.connect(types.MethodType(saveResults, m)) m.saveSettings = saveSettings m.persistant = None m.tiffFig = None m.setGeometry(QtCore.QRect(20, 372, 646, 660)) ########################################################## # Injected by Hyungtae Kim <*****@*****.**>, in Nov 2014, Feb 2015 # Providing a menu to select specific spatial frequency. # m.sfreq_menu = m.menubar.addMenu('Spatial Frequencies') m.tfreq_menu = m.menubar.addMenu('Temporal Frequencies') m.sfreq_action_group = QActionGroup(m, exclusive=True) m.tfreq_action_group = QActionGroup(m, exclusive=True) # m.np_comp_menu = m.menubar.addMenu('Neuropil Compensation') m.np_comp_action_group = QActionGroup(m, exclusive=True) np_actiongroup = m.np_comp_action_group action1 = QAction('off', np_actiongroup, checkable=True, checked=False) # action2 = QAction('double', np_actiongroup, checkable=True, checked=False) action3 = QAction('whole', np_actiongroup, checkable=True, checked=True) TiffFig.bind_neuropil_action(m, np_actiongroup, action1) # TiffFig.bind_neuropil_action(m, np_actiongroup, action2) TiffFig.bind_neuropil_action(m, np_actiongroup, action3) np_actiongroup.addAction(action1) # np_actiongroup.addAction(action2) np_actiongroup.addAction(action3) m.np_comp_menu.addAction(action1) # m.np_comp_menu.addAction(action2) m.np_comp_menu.addAction(action3) action3.trigger() # # ########################################################## # for debug # from ext.menubar import DebugMenubar dmenubar = DebugMenubar(m) debug_menu = m.menubar.addMenu('Debug') debug_menu.addAction('enter...').triggered[()].connect(dmenubar) # ########################################################## ########################################################## # for export # from ext.menubar import ExportMenubar export_menubar = ExportMenubar(m) export_menu = m.menubar.addMenu('Export') export_menu.addAction('Copy response values to clipboard...').triggered[( )].connect(partial(export_menubar.copy_response_values_to_clipboard)) export_menu.addAction('Copy response matrix to clipboard...').triggered[( )].connect(partial(export_menubar.copy_response_matrix_to_clipboard)) m.export_menubar = export_menubar # export_menu.addAction('Copy response values by all SF to clipboard...' # ).triggered[()].connect( # partial(export_menubar.copy_response_all_values_to_clipboard)) # ########################################################## m.show() # from ext.window.neuropil import NeuropilMaskFig # fig = NeuropilMaskFig() # m.fig = fig # fig.show() # plot = fig.addPlot(title = "neuropil mask") # import pyqtgraph as pg # import numpy as np # arr = np.zeros((64, 64), np.uint8) # arr[32,:] = 255 # item = pg.ImageItem(arr) # plot.addItem(item) # debug.enter() return m
class LiveCapture_ui(QObject): def __init__(self, parent=None): super(LiveCapture_ui, self).__init__(parent) self.parent = parent self.initUi() self.liveCapture = None self.packetDataUi = None ''' Description: Initialise the buttons and actions to control the live captring of data graphically. Add corresponding actions/tool buttons to toolbars/menubars of the mainWindow ''' def initUi(self): startPixmap = QPixmap( os.path.dirname(os.path.realpath(__file__)) + '/Start.png') stopPixmap = QPixmap( os.path.dirname(os.path.realpath(__file__)) + '/Stop.png') startIcon = QIcon(startPixmap) stopIcon = QIcon(stopPixmap) self.startToolButton = QToolButton(self.parent) self.stopToolButton = QToolButton(self.parent) self.startToolButton.setIcon(startIcon) self.stopToolButton.setIcon(stopIcon) self.startToolButton.setIconSize(QSize(32, 32)) self.stopToolButton.setIconSize(QSize(32, 32)) self.startToolButton.clicked.connect(self.startToolButtonClicked) self.stopToolButton.clicked.connect(self.stopToolButtonClicked) self.startAction = QAction("Start Live Capturing", self.parent) self.startAction.triggered.connect(self.startToolButtonClicked) self.stopAction = QAction("Stop Live Capture", self.parent) self.stopAction.triggered.connect(self.stopToolButtonClicked) # Setup initial values for the buttons/actions self.startToolButton.setEnabled(True) self.stopToolButton.setDisabled(True) self.startAction.setEnabled(True) self.stopAction.setDisabled(True) # Add Actions to the Menu bar menuCapture = self.parent.GetMenu("Capture") if menuCapture != None: menuCapture.addAction(self.startAction) menuCapture.addAction(self.stopAction) menuCapture.addSeparator() # Add tool buttons to the appropriate tool bar toolBarCapture = self.parent.GetToolBar("Capture") if toolBarCapture != None: toolBarCapture.addWidget(self.startToolButton) toolBarCapture.addWidget(self.stopToolButton) ''' Description: Obtain the interface to capture the data from. Check if user has appropriate privilege levels to start capturing data. Toggle tools in the GUI and initialise the packet capturing/display process in separate threads. ''' @pyqtSlot() def startToolButtonClicked(self): self.liveCapture = LiveCapture() iface = InterfaceSelection(self.parent) ifaceName = iface.GetInterface() if ifaceName == None: return self.liveCapture.setInterface(ifaceName) retVal = self.liveCapture.startLiveCapture() if retVal != -1: self.startToolButton.setDisabled(True) self.stopToolButton.setEnabled(True) self.startAction.setDisabled(True) self.stopAction.setEnabled(True) self.packetDataUi = PacketData_ui(self.parent) getPacketThread = GetPacketThread(self.liveCapture, self.packetDataUi) ''' Description: Notify the capturing thread to stop and toggle the buttons in the GUI ''' @pyqtSlot() def stopToolButtonClicked(self): self.startToolButton.setEnabled(True) self.stopToolButton.setDisabled(True) self.startAction.setEnabled(True) self.stopAction.setDisabled(True) self.liveCapture.stopLiveCapture() ''' Description: Description: Wrapper to trigger the Start capturing ''' def triggerStart(self): self.startAction.trigger() ''' Description: Description: Wrapper to trigger the Stop capturing ''' def triggerStop(self): self.stopAction.trigger()
class COMCUPluginBase(PluginBase): def __init__(self, device_class, ipcon, device_info, override_base_name=None): PluginBase.__init__(self, device_class, ipcon, device_info, override_base_name) self.start_called = False self.has_comcu = True self.cbe_bootloader_mode = CallbackEmulator(self.device.get_bootloader_mode, self.cb_bootloader_mode, self.increase_error_count) self.status_led_off_action = QAction('Off', self) self.status_led_off_action.triggered.connect(lambda: self.device.set_status_led_config(device_class.STATUS_LED_CONFIG_OFF)) self.status_led_on_action = QAction('On', self) self.status_led_on_action.triggered.connect(lambda: self.device.set_status_led_config(device_class.STATUS_LED_CONFIG_ON)) self.status_led_show_heartbeat_action = QAction('Show Heartbeat', self) self.status_led_show_heartbeat_action.triggered.connect(lambda: self.device.set_status_led_config(device_class.STATUS_LED_CONFIG_SHOW_HEARTBEAT)) self.status_led_show_status_action = QAction('Show Status', self) self.status_led_show_status_action.triggered.connect(lambda: self.device.set_status_led_config(device_class.STATUS_LED_CONFIG_SHOW_STATUS)) self.extra_configs = [(0, 'Status LED:', [self.status_led_off_action, self.status_led_on_action, self.status_led_show_heartbeat_action, self.status_led_show_status_action])] self.reset_action = QAction('Reset', self) self.reset_action.triggered.connect(self.remove_and_reset) self.extra_actions = [(0, None, [self.reset_action])] def remove_and_reset(self): get_main_window().remove_device_tab(self.uid) self.device.reset() # overrides PluginBase.get_configs def get_configs(self): return PluginBase.get_configs(self) + self.extra_configs # overrides PluginBase.get_actions def get_actions(self): return PluginBase.get_actions(self) + self.extra_actions def get_status_led_config_async(self, config): if config == self.device_class.STATUS_LED_CONFIG_OFF: self.status_led_off_action.trigger() elif config == self.device_class.STATUS_LED_CONFIG_ON: self.status_led_on_action.trigger() elif config == self.device_class.STATUS_LED_CONFIG_SHOW_HEARTBEAT: self.status_led_show_heartbeat_action.trigger() elif config == self.device_class.STATUS_LED_CONFIG_SHOW_STATUS: self.status_led_show_status_action.trigger() def cb_bootloader_mode(self, mode): if not self.start_called and mode == self.device.BOOTLOADER_MODE_FIRMWARE and self.isVisible(): async_call(self.device.get_status_led_config, None, self.get_status_led_config_async, self.increase_error_count) self.start_called = True self.start() elif mode == self.device.BOOTLOADER_MODE_BOOTLOADER and self.isVisible(): self.stop() self.hide() self.widget_bootloader.show() elif mode == self.device.BOOTLOADER_MODE_FIRMWARE and not self.isVisible(): self.widget_bootloader.hide() self.show() async_call(self.device.get_status_led_config, None, self.get_status_led_config_async, self.increase_error_count) self.start_called = True self.start() def start_comcu(self): self.start_called = False async_call(self.device.get_bootloader_mode, None, self.cb_bootloader_mode, self.increase_error_count) self.cbe_bootloader_mode.set_period(1000) def stop_comcu(self): self.cbe_bootloader_mode.set_period(0) self.stop()
class GPSV2(COMCUPluginBase, Ui_GPSV2): qtcb_pps = pyqtSignal() def __init__(self, *args): COMCUPluginBase.__init__(self, BrickletGPSV2, *args) self.setupUi(self) self.gps = self.device self.cbe_universal = CallbackEmulator(self.get_universal, self.cb_universal, self.increase_error_count) self.cbe_universal_gps = CallbackEmulator(self.get_universal_gps, self.cb_universal_gps, self.increase_error_count) self.cbe_universal_glo = CallbackEmulator(self.get_universal_glo, self.cb_universal_glo, self.increase_error_count) self.qtcb_pps.connect(self.cb_pps) self.gps.register_callback(self.gps.CALLBACK_PULSE_PER_SECOND, self.qtcb_pps.emit) self.format_combobox.currentIndexChanged.connect(self.format_changed) self.show_pos.clicked.connect(self.show_pos_clicked) self.hot_start.clicked.connect(lambda: self.restart_clicked(0)) self.warm_start.clicked.connect(lambda: self.restart_clicked(1)) self.cold_start.clicked.connect(lambda: self.restart_clicked(2)) self.factory_reset.clicked.connect(lambda: self.restart_clicked(3)) self.had_fix = False self.last_lat = 0 self.last_ns = 'U' self.last_long = 0 self.last_ew = 'U' self.gps_counter = 0 self.glo_counter = 0 self.gps_model = QStandardItemModel(32, 3, self) self.gps_table.setModel(self.gps_model) self.gps_model.setHorizontalHeaderItem(0, QStandardItem(u'Elevation (°)')) self.gps_model.setHorizontalHeaderItem(1, QStandardItem(u'Azimuth (°)')) self.gps_model.setHorizontalHeaderItem(2, QStandardItem(u'SNR (dB)')) for i in range(32): self.gps_model.setVerticalHeaderItem( i, QStandardItem(u'Sat ' + str(i + 1))) self.gps_table.horizontalHeader().setResizeMode(QHeaderView.Stretch) self.glo_model = QStandardItemModel(32, 3, self) self.glo_table.setModel(self.glo_model) self.glo_model.setHorizontalHeaderItem(0, QStandardItem(u'Elevation (°)')) self.glo_model.setHorizontalHeaderItem(1, QStandardItem(u'Azimuth (°)')) self.glo_model.setHorizontalHeaderItem(2, QStandardItem(u'SNR (dB)')) for i in range(32): self.glo_model.setVerticalHeaderItem( i, QStandardItem(u'Sat ' + str(i + 1 + 64))) self.glo_table.horizontalHeader().setResizeMode(QHeaderView.Stretch) self.fix_led_off_action = QAction('Off', self) self.fix_led_off_action.triggered.connect( lambda: self.gps.set_fix_led_config(BrickletGPSV2. FIX_LED_CONFIG_OFF)) self.fix_led_on_action = QAction('On', self) self.fix_led_on_action.triggered.connect( lambda: self.gps.set_fix_led_config(BrickletGPSV2.FIX_LED_CONFIG_ON )) self.fix_led_show_heartbeat_action = QAction('Show Heartbeat', self) self.fix_led_show_heartbeat_action.triggered.connect( lambda: self.gps.set_fix_led_config(BrickletGPSV2. FIX_LED_CONFIG_SHOW_HEARTBEAT)) self.fix_led_show_fix_action = QAction('Show Fix', self) self.fix_led_show_fix_action.triggered.connect( lambda: self.gps.set_fix_led_config(BrickletGPSV2. FIX_LED_CONFIG_SHOW_FIX)) self.fix_led_show_pps_action = QAction('Show PPS', self) self.fix_led_show_pps_action.triggered.connect( lambda: self.gps.set_fix_led_config(BrickletGPSV2. FIX_LED_CONFIG_SHOW_PPS)) self.extra_configs += [(1, 'Fix LED:', [ self.fix_led_off_action, self.fix_led_on_action, self.fix_led_show_heartbeat_action, self.fix_led_show_fix_action, self.fix_led_show_pps_action ])] def cb_pps(self): self.fix.setStyleSheet("QLabel { color : green; }") QTimer.singleShot(200, self.cb_pps_off) def cb_pps_off(self): self.fix.setStyleSheet("") def get_universal(self): return self.gps.get_coordinates( ), self.gps.get_status(), self.gps.get_altitude(), self.gps.get_motion( ), self.gps.get_date_time() def get_universal_gps(self): counter = self.gps_counter self.gps_counter = (self.gps_counter + 1) % 33 if counter == 0: return counter, self.gps.get_satellite_system_status( self.gps.SATELLITE_SYSTEM_GPS) else: return counter, self.gps.get_satellite_status( self.gps.SATELLITE_SYSTEM_GPS, counter) def get_universal_glo(self): counter = self.glo_counter self.glo_counter = (self.glo_counter + 1) % 33 if counter == 0: return counter, self.gps.get_satellite_system_status( self.gps.SATELLITE_SYSTEM_GLONASS) else: return counter, self.gps.get_satellite_status( self.gps.SATELLITE_SYSTEM_GLONASS, counter) def cb_universal_gps(self, data): try: counter, x = data if counter == 0: self.update_dop(self.gps_fix, self.gps_dop, self.gps_satallites_used, x) else: self.update_table(self.gps_model, counter, x) except: pass def cb_universal_glo(self, data): try: counter, x = data if counter == 0: self.update_dop(self.glo_fix, self.glo_dop, self.glo_satallites_used, x) else: self.update_table(self.glo_model, counter, x) except: pass def update_dop(self, fix, dop, used, data): if data.fix == 1: fix.setText("No Fix") elif data.fix == 2: fix.setText("2D Fix") elif data.fix == 3: fix.setText("3D Fix") else: fix.setText("Unknown") str_pdop = '%.2f' % (data.pdop / 100.0, ) str_hdop = '%.2f' % (data.hdop / 100.0, ) str_vdop = '%.2f' % (data.vdop / 100.0, ) dop.setText( str(str_vdop) + ' / ' + str(str_hdop) + ' / ' + str(str_pdop)) if len(data.satellite_numbers) == 0: used.setText('None') else: used.setText(', '.join(map(str, data.satellite_numbers))) def update_table(self, table_model, num, data): table_model.setItem(num - 1, 0, QStandardItem(str(data.elevation))) table_model.setItem(num - 1, 1, QStandardItem(str(data.azimuth))) table_model.setItem(num - 1, 2, QStandardItem(str(data.snr))) def cb_universal(self, data): try: coordinates, status, altitude, motion, date_time = data self.cb_coordinates(*coordinates) self.cb_status(*status) self.cb_altitude(*altitude) self.cb_motion(*motion) self.cb_date_time(*date_time) except: pass def show_pos_clicked(self): if self.had_fix: google_str = self.last_ns + self.make_dd_dddddd( self.last_lat, True) + '+' + self.last_ew + self.make_dd_dddddd( self.last_long, True) QDesktopServices.openUrl( QUrl('https://maps.google.com/maps?q=' + google_str)) else: QDesktopServices.openUrl( QUrl('http://www.google.com/moon/')) # :-) def format_changed(self, index): self.cb_coordinates(self.last_lat, self.last_ns, self.last_long, self.last_ew) def restart_clicked(self, restart_type): if restart_type > 0: self.had_fix = False # don't show cached data self.last_lat = 0 self.last_ns = 'U' self.last_long = 0 self.last_ew = 'U' self.satellites_view.setText('0') self.latitude.setText("Unknown") self.ns.setText('U') self.longitude.setText("Unknown") self.ew.setText('U') self.gps_dop.setText("Unknown") self.glo_dop.setText("Unknown") self.gps_satallites_used.setText("None") self.glo_satallites_used.setText("None") self.gps_fix.setText("No Fix") self.glo_fix.setText("No Fix") self.fix.setText("No") for i in range(32): self.gps_model.setItem(i, 0, QStandardItem('0')) self.gps_model.setItem(i, 1, QStandardItem('0')) self.gps_model.setItem(i, 2, QStandardItem('0')) self.glo_model.setItem(i, 0, QStandardItem('0')) self.glo_model.setItem(i, 1, QStandardItem('0')) self.glo_model.setItem(i, 2, QStandardItem('0')) self.altitude.setText("Unknown") self.course.setText("(Unknown)") self.speed.setText("Unknown") if restart_type > 1: self.time.setText("Unknown") self.gps.restart(restart_type) def get_fix_led_config_async(self, config): if config == BrickletGPSV2.FIX_LED_CONFIG_OFF: self.fix_led_off_action.trigger() elif config == BrickletGPSV2.FIX_LED_CONFIG_ON: self.fix_led_on_action.trigger() elif config == BrickletGPSV2.FIX_LED_CONFIG_SHOW_HEARTBEAT: self.fix_led_show_heartbeat_action.trigger() elif config == BrickletGPSV2.FIX_LED_CONFIG_SHOW_FIX: self.fix_led_show_fix_action.trigger() elif config == BrickletGPSV2.FIX_LED_CONFIG_SHOW_PPS: self.fix_led_show_pps_action.trigger() def start(self): async_call(self.gps.get_fix_led_config, None, self.get_fix_led_config_async, self.increase_error_count) self.cbe_universal.set_period(250) self.cbe_universal_gps.set_period(100) self.cbe_universal_glo.set_period(100) def stop(self): self.cbe_universal.set_period(0) self.cbe_universal_gps.set_period(0) self.cbe_universal_glo.set_period(0) def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletGPSV2.DEVICE_IDENTIFIER def make_ddmm_mmmmm(self, degree): dd = degree / 1000000 mm = (degree % 1000000) * 60 / 1000000.0 mmmmm = (mm - int(mm)) * 100000 dd_str = str(dd) mm_str = str(int(mm)) mmmmm_str = str(int(mmmmm + 0.5)) while len(mm_str) < 2: mm_str = '0' + mm_str while len(mmmmm_str) < 5: mmmmm_str = '0' + mmmmm_str return u'{0}° {1}.{2}’'.format(dd_str, mm_str, mmmmm_str) def make_dd_dddddd(self, degree, url=False): if url: return '%2.6f' % (degree / 1000000.0) else: return u'%2.6f°' % (degree / 1000000.0) def make_ddmmss_sss(self, degree): dd = degree / 1000000 mm = (degree % 1000000) * 60 / 1000000.0 ss = (mm - int(mm)) * 60 sss = (ss - int(ss)) * 1000 dd_str = str(dd) mm_str = str(int(mm)) ss_str = str(int(ss)) sss_str = str(int(sss + 0.5)) while len(mm_str) < 2: mm_str = '0' + mm_str while len(ss_str) < 2: ss_str = '0' + ss_str while len(sss_str) < 3: sss_str = '0' + sss_str return u'{0}° {1}’ {2}.{3}’’'.format(dd_str, mm_str, ss_str, sss_str) def cb_coordinates(self, lat, ns, long_, ew): if not self.had_fix: return self.last_lat = lat self.last_ns = ns self.last_long = long_ self.last_ew = ew if not ns in ('N', 'S'): self.latitude.setText("Unknown") self.ns.setText('U') else: self.ns.setText(ns) if self.format_combobox.currentIndex() == 0: self.latitude.setText(self.make_ddmmss_sss(lat)) elif self.format_combobox.currentIndex() == 1: self.latitude.setText(self.make_dd_dddddd(lat)) elif self.format_combobox.currentIndex() == 2: self.latitude.setText(self.make_ddmm_mmmmm(lat)) if not ew in ('E', 'W'): self.longitude.setText("Unknown") self.ew.setText('U') else: self.ew.setText(ew) if self.format_combobox.currentIndex() == 0: self.longitude.setText(self.make_ddmmss_sss(long_)) elif self.format_combobox.currentIndex() == 1: self.longitude.setText(self.make_dd_dddddd(long_)) elif self.format_combobox.currentIndex() == 2: self.longitude.setText(self.make_ddmm_mmmmm(long_)) def cb_status(self, has_fix, satellites_view): if has_fix: self.fix.setText("Yes") self.had_fix = True else: self.fix.setText("No") self.satellites_view.setText(str(satellites_view)) def cb_altitude(self, altitude, geoidal_separation): if not self.had_fix: return self.altitude.setText('%.2f m (Geoidal Separation: %.2f m)' % (altitude / 100.0, geoidal_separation / 100.0)) def cb_motion(self, course, speed): if not self.had_fix: return self.course.setText(u'(%.2f°)' % (course / 100.0, )) self.speed.setText('%.2f km/h' % (speed / 100.0, )) def cb_date_time(self, date, time): yy = date % 100 yy += 2000 date /= 100 mm = date % 100 date /= 100 dd = date time /= 1000 ss = time % 100 time /= 100 mins = time % 100 time /= 100 hh = time try: date_str = str(datetime.datetime(yy, mm, dd, hh, mins, ss)) + " UTC" except: date_str = "Unknown" self.time.setText(date_str)
class ToolBar(QToolBar): """A tool bar.""" def __init__(self, parentWidget, dockWidgetName, iface, pluginDir): """Constructor. Args: parentWidget (QToolBar): A reference to the parent widget. dockWidgetName (str): A name of the dock widget. iface (QgisInterface): A reference to the QgisInterface. pluginDir (QDir): A plugin directory. """ self.dW = parentWidget self.dWName = dockWidgetName self.iface = iface self.pluginDir = pluginDir super(ToolBar, self).__init__(self.dW) self._setup_self() def _setup_self(self): """Sets up self.""" self.setObjectName(u'toolbar') self._build_widgets() def _build_widgets(self): """Builds own widgets.""" self.iface.initializationCompleted.connect(self._set_icon_size) iconsDir = QDir(self.pluginDir.path() + u'/data/icons') self.openTabActionGroup = QActionGroup(self) self.loadVfkAction = QAction(self) self.loadVfkAction.setObjectName(u'loadVfkAction') self.loadVfkAction.setToolTip(u'Načtení VFK souboru') self.loadVfkAction.setCheckable(True) loadVfkIcon = QIcon() loadVfkIcon.addPixmap(QPixmap(iconsDir.filePath(u'loadvfk.png'))) self.loadVfkAction.setIcon(loadVfkIcon) self.openTabActionGroup.addAction(self.loadVfkAction) self.addAction(self.loadVfkAction) self.loadVfkAction.trigger() self.editAction = QAction(self) self.editAction.setObjectName(u'editAction') self.editAction.setToolTip(u'Editace') self.editAction.setCheckable(True) editIcon = QIcon() editIcon.addPixmap(QPixmap(iconsDir.filePath(u'edit.png'))) self.editAction.setIcon(editIcon) self.openTabActionGroup.addAction(self.editAction) self.addAction(self.editAction) self.checkAnalysisAction = QAction(self) self.checkAnalysisAction.setObjectName(u'checkAnalysisAction') self.checkAnalysisAction.setToolTip(u'Kontroly a analýzy') self.checkAnalysisAction.setCheckable(True) checkIcon = QIcon() checkIcon.addPixmap(QPixmap(iconsDir.filePath(u'checkanalysis.png'))) self.checkAnalysisAction.setIcon(checkIcon) self.openTabActionGroup.addAction(self.checkAnalysisAction) self.addAction(self.checkAnalysisAction) self.addSeparator() self.zoomFullExtentAction = self.iface.actionZoomFullExtent() self.addAction(self.zoomFullExtentAction) self.zoomToSelectedAction = self.iface.actionZoomToSelected() self.addAction(self.zoomToSelectedAction) self.selectToolButton = QToolButton(self) self.selectToolButton.setObjectName(u'selectToolButton') self.selectToolButton.setPopupMode(1) self.selectRectangleAction = self.iface.actionSelectRectangle() self.selectToolButton.addAction(self.selectRectangleAction) self.selectPolygonAction = self.iface.actionSelectPolygon() self.selectToolButton.addAction(self.selectPolygonAction) self.selectFreehandAction = self.iface.actionSelectFreehand() self.selectToolButton.addAction(self.selectFreehandAction) self.selectRadiusAction = self.iface.actionSelectRadius() self.selectToolButton.addAction(self.selectRadiusAction) for action in self.iface.attributesToolBar().actions(): if action.objectName() == 'ActionSelect': self.qgisSelectToolButton = action.defaultWidget() break self.qgisSelectToolButton.toggled.connect( self._set_default_action_selectToolButton) self._set_default_action_selectToolButton() self.addWidget(self.selectToolButton) self.selectionToolButton = QToolButton(self) self.selectionToolButton.setObjectName(u'selectionToolButton') self.selectionToolButton.setPopupMode(1) for action in self.iface.attributesToolBar().actions(): if action.objectName() == 'ActionSelection': self.qgisSelectionToolButton = action.defaultWidget() break self.selectionToolButton.addActions( self.qgisSelectionToolButton.actions()) self.selectionToolButton.setDefaultAction( self.qgisSelectionToolButton.defaultAction()) self.addWidget(self.selectionToolButton) for action in self.iface.attributesToolBar().actions(): if action.objectName() == 'mActionDeselectAll': self.deselectAllAction = action break self.addAction(self.deselectAllAction) self.openTableAction = self.iface.actionOpenTable() self.addAction(self.openTableAction) def _set_icon_size(self): """Sets icon size according to the current QGIS settings.""" self.setIconSize(self.iface.mainWindow().iconSize()) def _set_default_action_selectToolButton(self): """Sets selectToolButton's default action.""" self.selectToolButton.setDefaultAction( self.qgisSelectToolButton.defaultAction())
def test_tool_grid(self): w = ToolGrid() w.show() self.app.processEvents() def buttonsOrderedVisual(): # Process layout events so the buttons have right positions self.app.processEvents() buttons = w.findChildren(QToolButton) return sorted(buttons, key=lambda b: (b.y(), b.x())) def buttonsOrderedLogical(): return map(w.buttonForAction, w.actions()) def assertOrdered(): self.assertSequenceEqual(buttonsOrderedLogical(), buttonsOrderedVisual()) action_a = QAction("A", w) action_b = QAction("B", w) action_c = QAction("C", w) action_d = QAction("D", w) w.addAction(action_b) w.insertAction(0, action_a) self.assertSequenceEqual(w.actions(), [action_a, action_b]) assertOrdered() w.addAction(action_d) w.insertAction(action_d, action_c) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_c, action_d]) assertOrdered() w.removeAction(action_c) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_d]) assertOrdered() w.removeAction(action_a) self.assertSequenceEqual(w.actions(), [action_b, action_d]) assertOrdered() w.insertAction(0, action_a) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_d]) assertOrdered() w.setColumnCount(2) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_d]) assertOrdered() w.insertAction(2, action_c) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_c, action_d]) assertOrdered() w.clear() # test no 'before' action edge case w.insertAction(0, action_a) self.assertIs(action_a, w.actions()[0]) w.insertAction(1, action_b) self.assertSequenceEqual(w.actions(), [action_a, action_b]) w.clear() w.setActions([action_a, action_b, action_c, action_d]) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_c, action_d]) assertOrdered() triggered_actions = [] def p(action): print action.text() w.actionTriggered.connect(p) w.actionTriggered.connect(triggered_actions.append) action_a.trigger() w.show() self.app.exec_()
def test_tool_grid(self): w = ToolGrid() w.show() self.app.processEvents() def buttonsOrderedVisual(): # Process layout events so the buttons have right positions self.app.processEvents() buttons = w.findChildren(QToolButton) return sorted(buttons, key=lambda b: (b.y(), b.x())) def buttonsOrderedLogical(): return list(map(w.buttonForAction, w.actions())) def assertOrdered(): self.assertSequenceEqual(buttonsOrderedLogical(), buttonsOrderedVisual()) action_a = QAction("A", w) action_b = QAction("B", w) action_c = QAction("C", w) action_d = QAction("D", w) w.addAction(action_b) w.insertAction(0, action_a) self.assertSequenceEqual(w.actions(), [action_a, action_b]) assertOrdered() w.addAction(action_d) w.insertAction(action_d, action_c) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_c, action_d]) assertOrdered() w.removeAction(action_c) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_d]) assertOrdered() w.removeAction(action_a) self.assertSequenceEqual(w.actions(), [action_b, action_d]) assertOrdered() w.insertAction(0, action_a) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_d]) assertOrdered() w.setColumnCount(2) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_d]) assertOrdered() w.insertAction(2, action_c) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_c, action_d]) assertOrdered() w.clear() # test no 'before' action edge case w.insertAction(0, action_a) self.assertIs(action_a, w.actions()[0]) w.insertAction(1, action_b) self.assertSequenceEqual(w.actions(), [action_a, action_b]) w.clear() w.setActions([action_a, action_b, action_c, action_d]) self.assertSequenceEqual(w.actions(), [action_a, action_b, action_c, action_d]) assertOrdered() triggered_actions = [] def p(action): print(action.text()) w.actionTriggered.connect(p) w.actionTriggered.connect(triggered_actions.append) action_a.trigger() w.show() self.app.exec_()
class CANV2(COMCUPluginBase, Ui_CANV2): qtcb_frame_read = pyqtSignal(int, int, object) def __init__(self, *args): COMCUPluginBase.__init__(self, BrickletCANV2, *args) self.setupUi(self) self.can = self.device self.qtcb_frame_read.connect(self.cb_frame_read) self.can.register_callback(self.can.CALLBACK_FRAME_READ, self.qtcb_frame_read.emit) self.last_filename = os.path.join(get_home_path(), 'can_bricklet_v2_history.log') self.frame_read_callback_was_enabled = False self.tree_frames.header().resizeSection(0, 150) self.tree_frames.header().resizeSection(1, 170) self.tree_frames.header().resizeSection(2, 300) self.tree_frames.header().resizeSection(3, 100) self.edit_data.setValidator(HexValidator(max_bytes=8)) self.combo_frame_type.currentIndexChanged.connect( self.frame_type_changed) self.spin_baud_rate.valueChanged.connect( self.transceiver_configuration_changed) self.spin_sample_point.valueChanged.connect( self.transceiver_configuration_changed) self.combo_transceiver_mode.currentIndexChanged.connect( self.transceiver_configuration_changed) self.spin_write_buffer_size.valueChanged.connect( self.queue_configuration_changed) self.spin_write_buffer_timeout.valueChanged.connect( self.queue_configuration_changed) self.spin_write_backlog_size.valueChanged.connect( self.queue_configuration_changed) self.edit_read_buffer_sizes.textEdited.connect( self.queue_configuration_changed) self.spin_read_backlog_size.valueChanged.connect( self.queue_configuration_changed) for i in range(32): self.combo_filter_buffer.addItem(str(i)) self.combo_filter_buffer.currentIndexChanged.connect( self.read_filter_buffer_changed) self.combo_filter_mode.currentIndexChanged.connect( self.read_filter_mode_changed) self.spin_filter_mask.valueChanged.connect( self.read_filter_configuration_changed) self.spin_filter_identifier.valueChanged.connect( self.read_filter_configuration_changed) self.button_write_frame.clicked.connect(self.write_frame) self.button_clear_history.clicked.connect(self.tree_frames.clear) self.button_save_history.clicked.connect(self.save_history) self.button_save_transceiver_configuration.clicked.connect( self.save_transceiver_configuration) self.button_reset_transceiver_configuration.clicked.connect( self.reset_transceiver_configuration) self.button_save_queue_configuration.clicked.connect( self.save_queue_configuration) self.button_reset_queue_configuration.clicked.connect( self.reset_queue_configuration) self.button_save_read_filter_configuration.clicked.connect( self.save_read_filter_configuration) self.button_reset_read_filter_configuration.clicked.connect( self.reset_read_filter_configuration) self.error_log_timer = QTimer(self) self.error_log_timer.timeout.connect(self.update_error_log) self.error_log_timer.setInterval(1000) self.frame_type_changed() self.read_filter_buffer_changed() self.read_filter_mode_changed() self.read_filter_configuration_changed() self.com_led_off_action = QAction('Off', self) self.com_led_off_action.triggered.connect( lambda: self.can.set_communication_led_config( BrickletCANV2.COMMUNICATION_LED_CONFIG_OFF)) self.com_led_on_action = QAction('On', self) self.com_led_on_action.triggered.connect( lambda: self.can.set_communication_led_config( BrickletCANV2.COMMUNICATION_LED_CONFIG_ON)) self.com_led_show_heartbeat_action = QAction('Show Heartbeat', self) self.com_led_show_heartbeat_action.triggered.connect( lambda: self.can.set_communication_led_config( BrickletCANV2.COMMUNICATION_LED_CONFIG_SHOW_HEARTBEAT)) self.com_led_show_communication_action = QAction('Show Com', self) self.com_led_show_communication_action.triggered.connect( lambda: self.can.set_communication_led_config( BrickletCANV2.COMMUNICATION_LED_CONFIG_SHOW_COMMUNICATION)) self.extra_configs += [(1, 'Com LED:', [ self.com_led_off_action, self.com_led_on_action, self.com_led_show_heartbeat_action, self.com_led_show_communication_action ])] self.error_led_off_action = QAction('Off', self) self.error_led_off_action.triggered.connect( lambda: self.can.set_error_led_config(BrickletCANV2. ERROR_LED_CONFIG_OFF)) self.error_led_on_action = QAction('On', self) self.error_led_on_action.triggered.connect( lambda: self.can.set_error_led_config(BrickletCANV2. ERROR_LED_CONFIG_ON)) self.error_led_show_heartbeat_action = QAction('Show Heartbeat', self) self.error_led_show_heartbeat_action.triggered.connect( lambda: self.can.set_error_led_config( BrickletCANV2.ERROR_LED_CONFIG_SHOW_HEARTBEAT)) self.error_led_show_transceiver_state_action = QAction( 'Show Transceiver State', self) self.error_led_show_transceiver_state_action.triggered.connect( lambda: self.can.set_error_led_config( BrickletCANV2.ERROR_LED_CONFIG_SHOW_TRANSCEIVER_STATE)) self.error_led_show_error_action = QAction('Show Error', self) self.error_led_show_error_action.triggered.connect( lambda: self.can.set_error_led_config(BrickletCANV2. ERROR_LED_CONFIG_SHOW_ERROR)) self.extra_configs += [(1, 'Error LED:', [ self.error_led_off_action, self.error_led_on_action, self.error_led_show_heartbeat_action, self.error_led_show_transceiver_state_action, self.error_led_show_error_action ])] def start(self): async_call(self.can.get_communication_led_config, None, self.get_communication_led_config_async, self.increase_error_count) async_call(self.can.get_error_led_config, None, self.get_error_led_config_async, self.increase_error_count) self.frame_read_callback_was_enabled = False async_call(self.can.get_frame_read_callback_configuration, None, self.get_frame_read_callback_configuration_async, self.increase_error_count) async_call(self.can.get_transceiver_configuration, None, self.get_transceiver_configuration_async, self.increase_error_count) async_call(self.can.get_queue_configuration, None, self.get_queue_configuration_async, self.increase_error_count) def make_get_read_filter_configuration_async_lambda(i): return lambda *args: self.get_read_filter_configuration_async( i, *args) for i in range(32): async_call(self.can.get_read_filter_configuration, i, make_get_read_filter_configuration_async_lambda(i), self.increase_error_count) self.update_error_log() self.error_log_timer.start() def stop(self): self.error_log_timer.stop() if not self.frame_read_callback_was_enabled: try: self.can.set_response_expected( self.can.FUNCTION_SET_FRAME_READ_CALLBACK_CONFIGURATION, False) self.can.set_frame_read_callback_configuration(False) self.can.set_response_expected( self.can.FUNCTION_SET_FRAME_READ_CALLBACK_CONFIGURATION, True) except: pass def destroy(self): pass @staticmethod def has_device_identifier(device_identifier): return device_identifier == BrickletCANV2.DEVICE_IDENTIFIER def get_communication_led_config_async(self, config): if config == BrickletCANV2.COMMUNICATION_LED_CONFIG_OFF: self.com_led_off_action.trigger() elif config == BrickletCANV2.COMMUNICATION_LED_CONFIG_ON: self.com_led_on_action.trigger() elif config == BrickletCANV2.COMMUNICATION_LED_CONFIG_SHOW_HEARTBEAT: self.com_led_show_heartbeat_action.trigger() elif config == BrickletCANV2.COMMUNICATION_LED_CONFIG_SHOW_COMMUNICATION: self.com_led_show_communication_action.trigger() def get_error_led_config_async(self, config): if config == BrickletCANV2.ERROR_LED_CONFIG_OFF: self.error_led_off_action.trigger() elif config == BrickletCANV2.ERROR_LED_CONFIG_ON: self.error_led_on_action.trigger() elif config == BrickletCANV2.ERROR_LED_CONFIG_SHOW_HEARTBEAT: self.error_led_show_heartbeat_action.trigger() elif config == BrickletCANV2.ERROR_LED_CONFIG_SHOW_TRANSCEIVER_STATE: self.error_led_show_transceiver_state_action.trigger() elif config == BrickletCANV2.ERROR_LED_CONFIG_SHOW_ERROR: self.error_led_show_error_action.trigger() def cb_frame_read(self, frame_type, identifier, data): length = len(data) parts = [] max_length = 0 extended = False if frame_type == self.can.FRAME_TYPE_STANDARD_DATA: parts.append('Standard Data') max_length = 8 elif frame_type == self.can.FRAME_TYPE_STANDARD_REMOTE: parts.append('Standard Remote') elif frame_type == self.can.FRAME_TYPE_EXTENDED_DATA: parts.append('Extended Data') max_length = 8 extended = True elif frame_type == self.can.FRAME_TYPE_EXTENDED_REMOTE: parts.append('Extended Remote') extended = True else: parts.append('Unknown') parts.append(self.spin_identifier.textFromValue(identifier)) parts.append(' '.join( ['%02X' % c for c in data[:min(length, max_length)]])) parts.append(str(length)) scroll_bar = self.tree_frames.verticalScrollBar() at_bottom = scroll_bar.value() == scroll_bar.maximum() self.tree_frames.addTopLevelItem(QTreeWidgetItem(parts)) if at_bottom: self.tree_frames.scrollToBottom() def get_frame_read_callback_configuration_async(self, enabled): self.frame_read_callback_was_enabled = enabled self.can.set_frame_read_callback_configuration(True) def get_transceiver_configuration_async(self, config): self.spin_baud_rate.setValue(config.baud_rate) self.spin_sample_point.setValue(config.sample_point / 10.0) self.combo_transceiver_mode.setCurrentIndex(config.transceiver_mode) self.button_save_transceiver_configuration.setEnabled(False) def get_queue_configuration_async(self, config): self.spin_write_buffer_size.setValue(config.write_buffer_size) self.spin_write_buffer_timeout.setValue(config.write_buffer_timeout) self.spin_write_backlog_size.setValue(config.write_backlog_size) self.edit_read_buffer_sizes.setText(','.join( map(str, config.read_buffer_sizes))) self.spin_read_backlog_size.setValue(config.read_backlog_size) self.button_save_queue_configuration.setEnabled(False) def get_read_filter_configuration_async(self, buffer_index, config): self.combo_filter_buffer.setItemData(buffer_index, config) self.read_filter_buffer_changed() self.button_save_read_filter_configuration.setEnabled(False) def get_error_log_async(self, errors): if errors.transceiver_state == BrickletCANV2.TRANSCEIVER_STATE_ACTIVE: self.label_transceiver_state.setText('Active') elif errors.transceiver_state == BrickletCANV2.TRANSCEIVER_STATE_PASSIVE: self.label_transceiver_state.setText('Passive') else: self.label_transceiver_state.setText('Disabled') self.label_transceiver_write_error_level.setText( str(errors.transceiver_write_error_level)) self.label_transceiver_read_error_level.setText( str(errors.transceiver_read_error_level)) self.label_transceiver_stuffing_errors.setText( str(errors.transceiver_stuffing_error_count)) self.label_transceiver_format_errors.setText( str(errors.transceiver_format_error_count)) self.label_transceiver_ack_errors.setText( str(errors.transceiver_ack_error_count)) self.label_transceiver_bit1_errors.setText( str(errors.transceiver_bit1_error_count)) self.label_transceiver_bit0_errors.setText( str(errors.transceiver_bit0_error_count)) self.label_transceiver_crc_errors.setText( str(errors.transceiver_crc_error_count)) self.label_write_buffer_timeouts.setText( str(errors.write_buffer_timeout_error_count)) self.label_read_buffer_overflows.setText(str(errors.read_buffer_overflow_error_count) + ' [' + \ ''.join(map(lambda b: '1' if b else '0', errors.read_buffer_overflow_error_occurred)) + ']') self.label_read_backlog_overflows.setText( str(errors.read_backlog_overflow_error_count)) def frame_type_changed(self): frame_type = self.combo_frame_type.currentIndex() extended = frame_type in [ self.can.FRAME_TYPE_EXTENDED_DATA, self.can.FRAME_TYPE_EXTENDED_REMOTE ] remote = frame_type in [ self.can.FRAME_TYPE_STANDARD_REMOTE, self.can.FRAME_TYPE_EXTENDED_REMOTE ] if extended: self.spin_identifier.setMaximum((1 << 29) - 1) else: self.spin_identifier.setMaximum((1 << 11) - 1) self.edit_data.setEnabled(not remote) self.spin_length.setEnabled(remote) def transceiver_configuration_changed(self): self.button_save_transceiver_configuration.setEnabled(True) def queue_configuration_changed(self): self.button_save_queue_configuration.setEnabled(True) def read_filter_buffer_changed(self): buffer_index = self.combo_filter_buffer.currentIndex() if buffer_index < 0 or self.combo_filter_buffer.itemData( buffer_index) == None: self.combo_filter_mode.setCurrentIndex(0) self.spin_filter_mask.setValue(0) self.spin_filter_identifier.setValue(0) else: config = self.combo_filter_buffer.itemData(buffer_index) self.combo_filter_mode.setCurrentIndex(config.filter_mode) self.spin_filter_mask.setValue(config.filter_mask) self.spin_filter_identifier.setValue(config.filter_identifier) self.read_filter_configuration_changed() self.button_save_read_filter_configuration.setEnabled(False) def read_filter_mode_changed(self): mode = self.combo_filter_mode.currentIndex() if mode == self.can.FILTER_MODE_MATCH_STANDARD_ONLY: self.spin_filter_mask.setMaximum((1 << 11) - 1) self.spin_filter_identifier.setMaximum((1 << 11) - 1) else: self.spin_filter_mask.setMaximum((1 << 29) - 1) self.spin_filter_identifier.setMaximum((1 << 11) - 1) self.spin_filter_mask.setEnabled( mode != self.can.FILTER_MODE_ACCEPT_ALL) self.spin_filter_identifier.setEnabled( mode != self.can.FILTER_MODE_ACCEPT_ALL) self.button_save_read_filter_configuration.setEnabled(True) def read_filter_configuration_changed(self): self.button_save_read_filter_configuration.setEnabled(True) def update_error_log(self): async_call(self.can.get_error_log, None, self.get_error_log_async, self.increase_error_count) def write_frame(self): frame_type = self.combo_frame_type.currentIndex() remote = frame_type in [ self.can.FRAME_TYPE_STANDARD_REMOTE, self.can.FRAME_TYPE_EXTENDED_REMOTE ] identifier = self.spin_identifier.value() data_str = self.edit_data.text().replace(' ', '') if remote: data = [0] * self.spin_length.value() else: data = [] while len(data_str) > 0: data.append(int(data_str[:2], 16)) data_str = data_str[2:] data = data[:15] self.button_write_frame.setEnabled(False) async_call(self.can.write_frame, (frame_type, identifier, data), self.write_frame_async, self.write_frame_error) def write_frame_async(self, success): self.button_write_frame.setEnabled(True) if not success: QMessageBox.critical( get_main_window(), 'Write Frame', 'Could not write frame due to write buffer/backlog overflow.', QMessageBox.Ok) def write_frame_error(self): self.button_write_frame.setEnabled(True) self.increase_error_count() def save_history(self): filename = get_save_file_name(get_main_window(), 'Save History', self.last_filename) if len(filename) == 0: return self.last_filename = filename try: f = open(filename, 'wb') except Exception as e: QMessageBox.critical( get_main_window(), 'Save History Error', u'Could not open {0} for writing:\n\n{1}'.format(filename, e)) return root = self.tree_frames.invisibleRootItem() content = ['Frame Type;Identifier [Hex];Data [Hex];Length\n'] for i in range(root.childCount()): child = root.child(i) row = [] for c in range(child.columnCount()): row.append(child.text(c)) content.append(';'.join(row) + '\n') try: # FIXME: add progress dialog if content is bigger than some megabytes f.write(''.join(content).encode('utf-8')) except Exception as e: QMessageBox.critical( get_main_window(), 'Save History Error', u'Could not write to {0}:\n\n{1}'.format(filename, e)) f.close() def save_transceiver_configuration(self): baud_rate = self.spin_baud_rate.value() sample_point = int(self.spin_sample_point.value() * 10) transceiver_mode = self.combo_transceiver_mode.currentIndex() # FIXME: add validation self.can.set_transceiver_configuration(baud_rate, sample_point, transceiver_mode) self.button_save_transceiver_configuration.setEnabled(False) def reset_transceiver_configuration(self): self.spin_baud_rate.setValue(125000) self.spin_sample_point.setValue(62.5) self.combo_transceiver_mode.setCurrentIndex(0) def save_queue_configuration(self): write_buffer_size = self.spin_write_buffer_size.value() write_buffer_timeout = self.spin_write_buffer_timeout.value() write_backlog_size = self.spin_write_backlog_size.value() read_buffer_sizes_str = self.edit_read_buffer_sizes.text().replace( ' ', '') read_backlog_size = self.spin_read_backlog_size.value() if len(read_buffer_sizes_str) == 0: read_buffer_sizes = [] else: try: read_buffer_sizes = map(int, read_buffer_sizes_str.split(',')) except: QMessageBox.critical( get_main_window(), 'Save Queue Configuration Error', 'Read Buffer Sizes could not be parsed as comma-separated list of integters.' ) return if len(read_buffer_sizes) > 32: QMessageBox.critical( get_main_window(), 'Save Queue Configuration Error', 'More than 32 Read Buffer Sizes specified.') return for read_buffer_size in read_buffer_sizes: if read_buffer_size == 0: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'Read Buffer Sizes cannot be 0.') return if read_buffer_size < -32 or read_buffer_size > 32: QMessageBox.critical( get_main_window(), 'Save Queue Configuration Error', 'Read Buffer Sizes must be in [-32..+32] range.') return if write_buffer_size + sum(map(abs, read_buffer_sizes)) > 32: QMessageBox.critical(get_main_window(), 'Save Queue Configuration Error', 'More than 32 buffers used in total.') return if write_backlog_size + read_backlog_size > 768: QMessageBox.critical( get_main_window(), 'Save Queue Configuration Error', 'Backlog cannot be longer than 768 frames in total.') return # FIXME: add validation self.can.set_queue_configuration(write_buffer_size, write_buffer_timeout, write_backlog_size, read_buffer_sizes, read_backlog_size) self.button_save_queue_configuration.setEnabled(False) def reset_queue_configuration(self): self.spin_write_buffer_size.setValue(8) self.spin_write_buffer_timeout.setValue(0) self.spin_write_backlog_size.setValue(384) self.edit_read_buffer_sizes.setText('16,-8') self.spin_read_backlog_size.setValue(384) def save_read_filter_configuration(self): buffer_index = self.combo_filter_buffer.currentIndex() mode = self.combo_filter_mode.currentIndex() mask = self.spin_filter_mask.value() identifier = self.spin_filter_identifier.value() self.combo_filter_buffer.setItemData( buffer_index, GetReadFilterConfiguration(mode, mask, identifier)) # FIXME: add validation self.can.set_read_filter_configuration(buffer_index, mode, mask, identifier) self.button_save_read_filter_configuration.setEnabled(False) def reset_read_filter_configuration(self): self.combo_filter_mode.setCurrentIndex(0) self.spin_filter_mask.setValue(0) self.spin_filter_identifier.setValue(0)
class LiveCapture_ui(QObject): def __init__(self, parent = None): super(LiveCapture_ui, self).__init__(parent) self.parent = parent self.initUi() self.liveCapture = None self.packetDataUi = None ''' Description: Initialise the buttons and actions to control the live captring of data graphically. Add corresponding actions/tool buttons to toolbars/menubars of the mainWindow ''' def initUi(self): startPixmap = QPixmap(os.path.dirname(os.path.realpath(__file__)) + '/Start.png') stopPixmap = QPixmap(os.path.dirname(os.path.realpath(__file__)) + '/Stop.png') startIcon = QIcon(startPixmap) stopIcon = QIcon(stopPixmap) self.startToolButton = QToolButton(self.parent) self.stopToolButton = QToolButton(self.parent) self.startToolButton.setIcon(startIcon) self.stopToolButton.setIcon(stopIcon) self.startToolButton.setIconSize(QSize(32, 32)) self.stopToolButton.setIconSize(QSize(32, 32)) self.startToolButton.clicked.connect(self.startToolButtonClicked) self.stopToolButton.clicked.connect(self.stopToolButtonClicked) self.startAction = QAction("Start Live Capturing", self.parent) self.startAction.triggered.connect(self.startToolButtonClicked) self.stopAction = QAction("Stop Live Capture", self.parent) self.stopAction.triggered.connect(self.stopToolButtonClicked) # Setup initial values for the buttons/actions self.startToolButton.setEnabled(True) self.stopToolButton.setDisabled(True) self.startAction.setEnabled(True) self.stopAction.setDisabled(True) # Add Actions to the Menu bar menuCapture = self.parent.GetMenu("Capture") if menuCapture != None: menuCapture.addAction(self.startAction) menuCapture.addAction(self.stopAction) menuCapture.addSeparator() # Add tool buttons to the appropriate tool bar toolBarCapture = self.parent.GetToolBar("Capture") if toolBarCapture != None: toolBarCapture.addWidget(self.startToolButton) toolBarCapture.addWidget(self.stopToolButton) ''' Description: Obtain the interface to capture the data from. Check if user has appropriate privilege levels to start capturing data. Toggle tools in the GUI and initialise the packet capturing/display process in separate threads. ''' @pyqtSlot() def startToolButtonClicked(self): self.liveCapture = LiveCapture() iface = InterfaceSelection(self.parent) ifaceName = iface.GetInterface() if ifaceName == None: return self.liveCapture.setInterface(ifaceName) retVal = self.liveCapture.startLiveCapture() if retVal != -1: self.startToolButton.setDisabled(True) self.stopToolButton.setEnabled(True) self.startAction.setDisabled(True) self.stopAction.setEnabled(True) self.packetDataUi = PacketData_ui(self.parent) getPacketThread = GetPacketThread(self.liveCapture, self.packetDataUi) ''' Description: Notify the capturing thread to stop and toggle the buttons in the GUI ''' @pyqtSlot() def stopToolButtonClicked(self): self.startToolButton.setEnabled(True) self.stopToolButton.setDisabled(True) self.startAction.setEnabled(True) self.stopAction.setDisabled(True) self.liveCapture.stopLiveCapture() ''' Description: Description: Wrapper to trigger the Start capturing ''' def triggerStart(self): self.startAction.trigger() ''' Description: Description: Wrapper to trigger the Stop capturing ''' def triggerStop(self): self.stopAction.trigger()
class QMap(): def __init__(self, iface): self.iface = iface self.actions = [] self.panels= [] self.navtoolbar = self.iface.mapNavToolToolBar() self.mainwindow = self.iface.mainWindow() self.iface.projectRead.connect(self.projectOpened) self.iface.initializationCompleted.connect(self.setupUI) self.actionGroup = QActionGroup(self.mainwindow) self.actionGroup.setExclusive(True) self.menuGroup = QActionGroup(self.mainwindow) self.menuGroup.setExclusive(True) self.movetool = MoveTool(self.iface.mapCanvas(), []) self.report = PopDownReport(self.iface.messageBar()) self.dialogprovider = DialogProvider(iface.mapCanvas(), iface) self.dialogprovider.accepted.connect(self.clearToolRubberBand) self.dialogprovider.rejected.connect(self.clearToolRubberBand) self.edittool = EditTool(self.iface.mapCanvas(),[]) self.edittool.finished.connect(self.openForm) @property def _mapLayers(self): return QgsMapLayerRegistry.instance().mapLayers() def clearToolRubberBand(self): tool = self.iface.mapCanvas().mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def missingLayers(self, layers): def showError(): html = ["<h1>Missing Layers</h1>", "<ul>"] for layer in layers: html.append("<li>{}</li>".format(layer)) html.append("</ul>") self.errorreport.updateHTML("".join(html)) message = "Seems like {} didn't load correctly".format(utils._pluralstring('layer', len(layers))) utils.warning("Missing layers") map(utils.warning, layers) self.widget = self.messageBar.createMessage("Missing Layers", message, QIcon(":/icons/sad")) button = QPushButton(self.widget) button.setCheckable(True) button.setChecked(self.errorreport.isVisible()) button.setText("Show missing layers") button.toggled.connect(showError) button.toggled.connect(functools.partial(self.errorreport.setVisible)) self.widget.destroyed.connect(self.hideReports) self.widget.layout().addWidget(button) self.messageBar.pushWidget(self.widget, QgsMessageBar.WARNING) def excepthook(self, ex_type, value, tb): """ Custom exception hook so that we can handle errors in a nicer way """ where = ''.join(traceback.format_tb(tb)) msg = '{}'.format(value) utils.critical(msg) def showError(): html = """ <html> <body bgcolor="#FFEDED"> <p><b>{}</b></p> <p align="left"><small>{}</small></p> </body> </html> """.format(msg, where) self.errorreport.updateHTML(html) self.widget = self.messageBar.createMessage("oops", "Looks like an error occurred", QIcon(":/icons/sad")) button = QPushButton(self.widget) button.setCheckable(True) button.setChecked(self.errorreport.isVisible()) button.setText("Show error") button.toggled.connect(showError) button.toggled.connect(functools.partial(self.errorreport.setVisible)) self.widget.destroyed.connect(self.hideReports) self.widget.layout().addWidget(button) self.messageBar.pushWidget(self.widget, QgsMessageBar.CRITICAL) def hideReports(self): self.errorreport.setVisible(False) self.report.setVisible(False) def setupUI(self): """ Set up the main QGIS interface items. Called after QGIS has loaded the plugin. """ fullscreen = utils.settings["fullscreen"] if fullscreen: self.mainwindow.showFullScreen() else: self.mainwindow.showMaximized() self.navtoolbar.setMovable(False) self.navtoolbar.setAllowedAreas(Qt.TopToolBarArea) self.mainwindow.insertToolBar(self.toolbar, self.navtoolbar) self.openProjectAction.trigger() def setMapTool(self, tool): """ Set the current mapview canvas tool tool -- The QgsMapTool to set """ self.iface.mapCanvas().setMapTool(tool) def createToolBars(self): """ Create all the needed toolbars """ self.menutoolbar = QToolBar("Menu", self.mainwindow) self.menutoolbar.setMovable(False) self.menutoolbar.setAllowedAreas(Qt.LeftToolBarArea) self.mainwindow.addToolBar(Qt.LeftToolBarArea, self.menutoolbar) self.toolbar = QToolBar("QMap", self.mainwindow) self.mainwindow.addToolBar(Qt.TopToolBarArea, self.toolbar) self.toolbar.setMovable(False) self.editingtoolbar = FloatingToolBar("Editing", self.toolbar) self.extraaddtoolbar = FloatingToolBar("Extra Add Tools", self.toolbar) self.syncactionstoolbar = FloatingToolBar("Syncing", self.toolbar) self.syncactionstoolbar.setOrientation(Qt.Vertical) def createActions(self): """ Create all the actions """ self.homeAction = (QAction(QIcon(":/icons/zoomfull"), "Default View", self.mainwindow)) self.gpsAction = (GPSAction(QIcon(":/icons/gps"), self.iface.mapCanvas(), self.mainwindow)) self.openProjectAction = (QAction(QIcon(":/icons/open"), "Projects", self.mainwindow)) self.openProjectAction.setCheckable(True) self.toggleRasterAction = (QAction(QIcon(":/icons/photo"), "Aerial Photos", self.mainwindow)) self.syncAction = QAction(QIcon(":/icons/sync"), "Sync", self.mainwindow) self.syncAction.setVisible(False) self.editattributesaction = QAction(QIcon(":/icons/edit"), "Edit Attributes", self.mainwindow) self.editattributesaction.setCheckable(True) self.editattributesaction.toggled.connect(functools.partial(self.setMapTool, self.edittool)) self.moveaction = QAction(QIcon(":/icons/move"), "Move Feature", self.mainwindow) self.moveaction.setCheckable(True) self.editingmodeaction = QAction(QIcon(":/icons/edittools"), "Editing Tools", self.mainwindow) self.editingmodeaction.setCheckable(True) self.addatgpsaction = QAction(QIcon(":/icons/gpsadd"), "Add at GPS", self.mainwindow) self.edittool.layersupdated.connect(self.editattributesaction.setVisible) self.movetool.layersupdated.connect(self.moveaction.setVisible) self.edittool.layersupdated.connect(self.updateEditTools) self.movetool.layersupdated.connect(self.updateEditTools) def updateEditTools(self, *args): """ Show or hide the Editing Tools button based on the sub tools. """ if self.edittool.layers and self.movetool.layers: self.editingmodeaction.setVisible(True) else: self.editingmodeaction.setVisible(False) def initGui(self): """ Create all the icons and setup the tool bars. Called by QGIS when loading. This is called before setupUI. """ QApplication.setWindowIcon(QIcon(":/branding/logo")) self.mainwindow.findChildren(QMenuBar)[0].setVisible(False) self.mainwindow.setContextMenuPolicy(Qt.PreventContextMenu) self.mainwindow.setWindowTitle("IntraMaps Roam: Mobile Data Collection") # Disable QGIS logging window popups. We do our own logging QgsMessageLog.instance().messageReceived.disconnect() s = """ QToolButton { padding: 6px; color: #4f4f4f; } QToolButton:hover { padding: 6px; background-color: rgb(211, 228, 255); } QToolBar { background: white; } QCheckBox::indicator { width: 40px; height: 40px; } QLabel { color: #4f4f4f; } QDialog { background-color: rgb(255, 255, 255); } QPushButton { border: 1px solid #e1e1e1; padding: 6px; color: #4f4f4f; } QPushButton:hover { border: 1px solid #e1e1e1; padding: 6px; background-color: rgb(211, 228, 255); } QCheckBox { color: #4f4f4f; } QComboBox::drop-down { width: 30px; } """ self.mainwindow.setStyleSheet(s) mainwidget = self.mainwindow.centralWidget() mainwidget.setLayout(QGridLayout()) mainwidget.layout().setContentsMargins(0,0,0,0) newlayout = QGridLayout() newlayout.setContentsMargins(0,0,0,0) newlayout.addWidget(self.iface.mapCanvas(), 0,0,2,1) newlayout.addWidget(self.iface.messageBar(), 0,0,1,1) wid = QWidget() wid.setLayout(newlayout) self.stack = QStackedWidget() self.messageBar = QgsMessageBar(wid) self.messageBar.setSizePolicy( QSizePolicy.Minimum, QSizePolicy.Fixed ) self.errorreport = PopDownReport(self.messageBar) mainwidget.layout().addWidget(self.stack, 0,0,2,1) mainwidget.layout().addWidget(self.messageBar, 0,0,1,1) self.helppage = HelpPage() helppath = os.path.join(os.path.dirname(__file__) , 'help',"help.html") self.helppage.setHelpPage(helppath) self.projectwidget = ProjectsWidget() self.projectwidget.requestOpenProject.connect(self.loadProject) self.stack.addWidget(wid) self.stack.addWidget(self.projectwidget) self.stack.addWidget(self.helppage) sys.excepthook = self.excepthook def createSpacer(width=30): widget = QWidget() widget.setMinimumWidth(width) return widget self.createToolBars() self.createActions() spacewidget = createSpacer(60) gpsspacewidget = createSpacer() gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.moveaction.toggled.connect(functools.partial(self.setMapTool, self.movetool)) showediting = (functools.partial(self.editingtoolbar.showToolbar, self.editingmodeaction, self.editattributesaction)) self.editingmodeaction.toggled.connect(showediting) self.addatgpsaction.triggered.connect(self.addAtGPS) self.addatgpsaction.setEnabled(self.gpsAction.isConnected) self.gpsAction.gpsfixed.connect(self.addatgpsaction.setEnabled) self.editingtoolbar.addToActionGroup(self.editattributesaction) self.editingtoolbar.addToActionGroup(self.moveaction) self.actionGroup.addAction(self.editingmodeaction) self.homeAction.triggered.connect(self.zoomToDefaultView) self.openProjectAction.triggered.connect(self.showOpenProjectDialog) self.openProjectAction.triggered.connect(functools.partial(self.stack.setCurrentIndex, 1)) self.toggleRasterAction.triggered.connect(self.toggleRasterLayers) self.navtoolbar.insertAction(self.iface.actionZoomIn(), self.iface.actionTouch()) self.navtoolbar.insertAction(self.iface.actionTouch(), self.homeAction) self.navtoolbar.insertAction(self.iface.actionTouch(), self.iface.actionZoomFullExtent()) self.navtoolbar.insertAction(self.homeAction, self.iface.actionZoomFullExtent()) self.navtoolbar.addAction(self.toggleRasterAction) self.navtoolbar.insertWidget(self.iface.actionZoomFullExtent(), spacewidget) self.toolbar.addAction(self.editingmodeaction) self.toolbar.addAction(self.syncAction) self.toolbar.addAction(self.gpsAction) self.toolbar.insertWidget(self.syncAction, gpsspacewidget) self.toolbar.insertSeparator(self.gpsAction) self.extraaddtoolbar.addAction(self.addatgpsaction) self.editingtoolbar.addAction(self.editattributesaction) self.editingtoolbar.addAction(self.moveaction) self.mapview = QAction(QIcon(":/icons/map"), "Map", self.menutoolbar) self.mapview.setCheckable(True) self.mapview.triggered.connect(functools.partial(self.stack.setCurrentIndex, 0)) self.help = QAction(QIcon(":/icons/help"), "Help", self.menutoolbar) self.help.setCheckable(True) self.help.triggered.connect(functools.partial(self.stack.setCurrentIndex, 2)) self.help.setVisible(False) self.userlabel = QLabel("Current User <br> {user}".format(user=getpass.getuser())) self.userlabel.setAlignment(Qt.AlignCenter) self.userlabel.setStyleSheet(""" QLabel { color: #8c8c8c; font: 10px "Calibri" ; }""") self.quit = QAction(QIcon(":/icons/quit"), "Quit", self.menutoolbar) self.quit.triggered.connect(self.iface.actionExit().trigger) self.menuGroup.addAction(self.mapview) self.menuGroup.addAction(self.openProjectAction) self.menuGroup.addAction(self.help) self.menutoolbar.addAction(self.mapview) self.menutoolbar.addAction(self.openProjectAction) self.menutoolbar.addAction(self.help) self.menutoolbar.addAction(self.quit) quitspacewidget = createSpacer() quitspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) labelaction = self.menutoolbar.insertWidget(self.quit, self.userlabel) self.menutoolbar.insertWidget(labelaction, quitspacewidget) self.setupIcons() self.stack.currentChanged.connect(self.updateUIState) def updateUIState(self, page): """ Update the UI state to reflect the currently selected page in the stacked widget """ def setToolbarsActive(enabled): toolbars = self.mainwindow.findChildren(QToolBar) for toolbar in toolbars: if toolbar == self.menutoolbar: continue toolbar.setEnabled(enabled) def setPanelsVisible(visible): for panel in self.panels: panel.setVisible(visible) ismapview = page == 0 setToolbarsActive(ismapview) setPanelsVisible(ismapview) def addAtGPS(self): """ Add a record at the current GPS location. """ action = self.actionGroup.checkedAction() if not action: return layer = action.data() if not layer: return point = self.gpsAction.position self.addNewFeature(layer=layer, geometry=point) def zoomToDefaultView(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.iface.mapCanvas().setExtent(self.defaultextent) self.iface.mapCanvas().refresh() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ legend = self.iface.legendInterface() #Freeze the canvas to save on UI refresh self.iface.mapCanvas().freeze() for layer in self._mapLayers.values(): if layer.type() == QgsMapLayer.RasterLayer: isvisible = legend.isLayerVisible(layer) legend.setLayerVisible(layer, not isvisible) self.iface.mapCanvas().freeze(False) self.iface.mapCanvas().refresh() def setupIcons(self): """ Update toolbars to have text and icons, change normal QGIS icons to new style """ toolbars = self.mainwindow.findChildren(QToolBar) for toolbar in toolbars: toolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) toolbar.setIconSize(QSize(32, 32)) self.iface.actionTouch().setIconText("Pan") self.iface.actionTouch().setIcon(QIcon(":/icons/pan")) self.iface.actionZoomIn().setIcon(QIcon(":/icons/in")) self.iface.actionZoomOut().setIcon(QIcon(":/icons/out")) self.iface.actionPan().setIcon(QIcon(":/icons/pan")) self.iface.actionZoomFullExtent().setIcon(QIcon(":/icons/home")) self.iface.actionZoomFullExtent().setIconText("Home View") self.actionGroup.addAction(self.iface.actionZoomIn()) self.actionGroup.addAction(self.iface.actionZoomOut()) self.actionGroup.addAction(self.iface.actionTouch()) def projectOpened(self): """ Called when a new project is opened in QGIS. """ for panel in self.panels: self.mainwindow.removeDockWidget(panel) del panel projectpath = QgsProject.instance().fileName() project = QMapProject(os.path.dirname(projectpath), self.iface) self.createFormButtons(projectlayers = project.getConfiguredLayers()) # Enable the raster layers button only if the project contains a raster layer. hasrasters = any(layer.type() for layer in self._mapLayers.values()) self.toggleRasterAction.setEnabled(hasrasters) self.defaultextent = self.iface.mapCanvas().extent() self.connectSyncProviders(project) # Show panels self.panels = list(project.getPanels()) for panel in self.panels: self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea , panel) self.iface.messageBar().popWidget() def createFormButtons(self, projectlayers): """ Create buttons for each form that is definded """ # Remove all the old buttons for action in self.actions: self.actionGroup.removeAction(action) self.toolbar.removeAction(action) self.edittool.layers = [] self.movetool.layers = [] for layer in projectlayers: try: qgslayer = QgsMapLayerRegistry.instance().mapLayersByName(layer.name)[0] if qgslayer.type() == QgsMapLayer.RasterLayer: utils.log("We can't support raster layers for data entry") continue layer.QGISLayer = qgslayer except KeyError: utils.log("Layer not found in project") continue if 'capture' in layer.capabilities: text = layer.icontext try: tool = layer.getMaptool(self.iface.mapCanvas()) except NoMapToolConfigured: utils.log("No map tool configured") continue except ErrorInMapTool as error: self.messageBar.pushMessage("Error configuring map tool", error.message, level=QgsMessageBar.WARNING) continue # Hack until I fix it later if isinstance(tool, PointTool): add = functools.partial(self.addNewFeature, qgslayer) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) action = QAction(QIcon(layer.icon), text, self.mainwindow) action.setData(layer) action.setCheckable(True) action.toggled.connect(functools.partial(self.setMapTool, tool)) self.toolbar.insertAction(self.editingmodeaction, action) if not tool.isEditTool(): # Connect the GPS tools strip to the action pressed event. showgpstools = (functools.partial(self.extraaddtoolbar.showToolbar, action, None)) action.toggled.connect(showgpstools) self.actionGroup.addAction(action) self.actions.append(action) if 'edit' in layer.capabilities: # TODO Use snapping options from project radius = (QgsTolerance.toleranceInMapUnits( 10, qgslayer, self.iface.mapCanvas().mapRenderer(), QgsTolerance.Pixels)) self.edittool.addLayer(qgslayer) self.edittool.searchRadius = radius if 'move' in layer.capabilities: self.movetool.addLayer(qgslayer) def openForm(self, layer, feature): if not layer.isEditable(): layer.startEditing() self.dialogprovider.openDialog(feature=feature, layer=layer) def addNewFeature(self, layer, geometry): fields = layer.pendingFields() if not layer.isEditable(): layer.startEditing() feature = QgsFeature() feature.setGeometry( geometry ) feature.initAttributes(fields.count()) feature.setFields(fields) for indx in xrange(fields.count()): feature[indx] = layer.dataProvider().defaultValue(indx) self.dialogprovider.openDialog(feature=feature, layer=layer) def showOpenProjectDialog(self): """ Show the project selection dialog. """ self.stack.setCurrentIndex(1) path = os.path.join(os.path.dirname(__file__), '..' , 'projects/') projects = getProjects(path, self.iface) self.projectwidget.loadProjectList(projects) def loadProject(self, project): """ Load a project into QGIS. """ utils.log(project) utils.log(project.name) utils.log(project.projectfile) utils.log(project.vaild) (passed, message) = project.onProjectLoad() if not passed: QMessageBox.warning(self.mainwindow, "Project Load Rejected", "Project couldn't be loaded because {}".format(message)) return self.mapview.trigger() self.iface.newProject(False) self.iface.mapCanvas().freeze() fileinfo = QFileInfo(project.projectfile) self.badLayerHandler = BadLayerHandler(callback=self.missingLayers) QgsProject.instance().setBadLayerHandler( self.badLayerHandler ) self.iface.messageBar().pushMessage("Project Loading","", QgsMessageBar.INFO) QgsProject.instance().read(fileinfo) self.iface.mapCanvas().updateScale() self.iface.mapCanvas().freeze(False) self.iface.mapCanvas().refresh() self.mainwindow.setWindowTitle("IntraMaps Roam: Mobile Data Collection") self.iface.projectRead.emit() def unload(self): del self.toolbar def connectSyncProviders(self, project): self.syncactionstoolbar.clear() syncactions = list(project.getSyncProviders()) # Don't show the sync button if there is no sync providers if not syncactions: self.syncAction.setVisible(False) return self.syncAction.setVisible(True) for provider in syncactions: action = QAction(QIcon(":/icons/sync"), "Sync {}".format(provider.name), self.mainwindow) action.triggered.connect(functools.partial(self.syncProvider, provider)) self.syncactionstoolbar.addAction(action) try: self.syncAction.toggled.disconnect() except TypeError: pass try: self.syncAction.triggered.disconnect() except TypeError: pass if len(syncactions) == 1: # If one provider is set then we just connect the main button. self.syncAction.setCheckable(False) self.syncAction.setText("Sync") self.syncAction.triggered.connect(functools.partial(self.syncProvider, syncactions[0])) else: # the sync button because a sync menu self.syncAction.setCheckable(True) self.syncAction.setText("Sync Menu") showsyncoptions = (functools.partial(self.syncactionstoolbar.showToolbar, self.syncAction, None)) self.syncAction.toggled.connect(showsyncoptions) def syncstarted(self): # Remove the old widget if it's still there. # I don't really like this. Seems hacky. try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass except AttributeError: pass self.iface.messageBar().findChildren(QToolButton)[0].setVisible(False) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync in progress", QIcon(":/icons/syncing")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setText("Status") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) pro = QProgressBar() pro.setMaximum(0) pro.setMinimum(0) self.syncwidget.layout().addWidget(pro) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget, QgsMessageBar.INFO) def synccomplete(self): try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass stylesheet = ("QgsMessageBar { background-color: rgba(239, 255, 233); border: 0px solid #b9cfe4; } " "QLabel,QTextEdit { color: #057f35; } ") closebutton = self.iface.messageBar().findChildren(QToolButton)[0] closebutton.setVisible(True) closebutton.clicked.connect(functools.partial(self.report.setVisible, False)) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync Complete", QIcon(":/icons/syncdone")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setChecked(self.report.isVisible()) button.setText("Sync Report") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) pro = QProgressBar() pro.setMaximum(100) pro.setValue(100) self.syncwidget.layout().addWidget(pro) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget) self.iface.messageBar().setStyleSheet(stylesheet) self.iface.mapCanvas().refresh() def syncerror(self): try: self.iface.messageBar().popWidget(self.syncwidget) except RuntimeError: pass closebutton = self.iface.messageBar().findChildren(QToolButton)[0] closebutton.setVisible(True) closebutton.clicked.connect(functools.partial(self.report.setVisible, False)) self.syncwidget = self.iface.messageBar().createMessage("Syncing", "Sync Error", QIcon(":/icons/syncfail")) button = QPushButton(self.syncwidget) button.setCheckable(True) button.setChecked(self.report.isVisible()) button.setText("Sync Report") button.setIcon(QIcon(":/icons/syncinfo")) button.toggled.connect(functools.partial(self.report.setVisible)) self.syncwidget.layout().addWidget(button) self.iface.messageBar().pushWidget(self.syncwidget, QgsMessageBar.CRITICAL) self.iface.mapCanvas().refresh() def syncProvider(self, provider): self.syncAction.toggle() provider.syncStarted.connect(functools.partial(self.syncAction.setEnabled, False)) provider.syncStarted.connect(self.syncstarted) provider.syncComplete.connect(self.synccomplete) provider.syncComplete.connect(functools.partial(self.syncAction.setEnabled, True)) provider.syncComplete.connect(functools.partial(self.report.updateHTML)) provider.syncMessage.connect(self.report.updateHTML) provider.syncError.connect(self.report.updateHTML) provider.syncError.connect(self.syncerror) provider.syncComplete.connect(functools.partial(self.syncAction.setEnabled, True)) provider.startSync()