Example #1
0
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)
Example #2
0
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
Example #3
0
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()
Example #4
0
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()
Example #5
0
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
Example #6
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()
Example #7
0
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()
Example #8
0
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())
Example #10
0
    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_()
Example #11
0
    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_()
Example #12
0
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)
Example #13
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()
Example #14
0
File: qmap.py Project: s-chand/qmap
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()