def __init__(self, mwHandle): self.mw = mwHandle for x in xrange(2, 20): pin = eval("self.mw.pin%02d" % (x)) menu = QMenu(pin) modeGroup = QActionGroup(self.mw) modeGroup.setExclusive(True) none = menu.addAction("&None") modeGroup.addAction(none) none.triggered.connect(self.clickNone) none.setCheckable(True) none.setChecked(True) input = menu.addAction("&Input") modeGroup.addAction(input) input.triggered.connect(self.clickInput) input.setCheckable(True) output = menu.addAction("&Output") modeGroup.addAction(output) output.triggered.connect(self.clickOutput) output.setCheckable(True) if self.mw.board.pins[x].PWM_CAPABLE: pwm = menu.addAction("&PWM") modeGroup.addAction(pwm) pwm.triggered.connect(self.clickPWM) pwm.setCheckable(True) if self.mw.board.pins[x].type == 2: analogic = menu.addAction(u"&Analógico") modeGroup.addAction(analogic) analogic.triggered.connect(self.clickAnalog) analogic.setCheckable(True) pin.setMenu(menu) pin.setStyleSheet("/* */") # force stylesheet update
def signalConnections(self): #connect signals: self.ui.actionUndo.triggered.connect(self.unDo) self.ui.actionRedo.triggered.connect(self.reDo) self.ui.actionSave_As.triggered.connect(self.saveFileAs) self.ui.actionSave.triggered.connect(self.saveFile) self.ui.actionOpen.triggered.connect(self.openFile) self.ui.actionNew.triggered.connect(self.newFile) self.ui.actionWhatsThis.triggered.connect(self.whatsThis) self.ui.actionCheck_HW_2.triggered.connect(self.checkHW) self.ui.actionUSBHelp.triggered.connect(self.USBHelp) self.ui.actionArduino_IO.triggered.connect(self.ArduinoIOHelp) self.ui.actionAbout.triggered.connect(self.AboutHelp) self.ui.infoButton.clicked.connect(self.parseGrid) #FOR DEBUG BUTTON #self.ui.pushButton.clicked.connect(self.showInfo) #self.ui.pushButton_3.clicked.connect(self.printLadder) #action group for tool buttons: self.connect(self.ui.actionContNO, QtCore.SIGNAL("triggered()"),lambda who="contNO": self.anyButton(who)) self.connect(self.ui.actionContNC, QtCore.SIGNAL("triggered()"),lambda who="contNC": self.anyButton(who)) self.connect(self.ui.actionCoil, QtCore.SIGNAL("triggered()"),lambda who="Coil": self.anyButton(who)) #self.connect(self.ui.actionCoilNot, QtCore.SIGNAL("triggered()"),lambda who="CoilNot": self.anyButton(who)) self.connect(self.ui.actionaddRung, QtCore.SIGNAL("triggered()"),lambda who="addRung": self.anyButton(who)) self.connect(self.ui.actionWiden, QtCore.SIGNAL("triggered()"),lambda who="Widen": self.anyButton(who)) #self.connect(self.ui.actionORbranch, QtCore.SIGNAL("triggered()"),lambda who="blankOR": self.anyButton(who)) self.connect(self.ui.actionDEL, QtCore.SIGNAL("triggered()"),lambda who="Del": self.anyButton(who)) self.connect(self.ui.actionORwire, QtCore.SIGNAL("triggered()"),lambda who="ORwire": self.anyButton(who)) self.connect(self.ui.actionNarrow, QtCore.SIGNAL("triggered()"),lambda who="Narrow": self.anyButton(who)) #self.connect(self.ui.actionRising, QtCore.SIGNAL("triggered()"),lambda who="Rising": self.anyButton(who)) self.connect(self.ui.actionFalling, QtCore.SIGNAL("triggered()"),lambda who="Fall": self.anyButton(who)) self.connect(self.ui.actionTimer, QtCore.SIGNAL("triggered()"),lambda who="Timer": self.anyButton(who)) self.connect(self.ui.actionCounter, QtCore.SIGNAL("triggered()"),lambda who="Counter": self.anyButton(who)) #make a actiongroup so tools are exclusive (only one clicked) toolActionGroup = QActionGroup(self.ui.toolBar)#toolbar is named in _ui.py toolActionGroup.addAction(self.ui.actionContNO) toolActionGroup.addAction(self.ui.actionContNC) toolActionGroup.addAction(self.ui.actionCoil) #toolActionGroup.addAction(self.ui.actionCoilNot) toolActionGroup.addAction(self.ui.actionaddRung) toolActionGroup.addAction(self.ui.actionWiden) #toolActionGroup.addAction(self.ui.actionORbranch) toolActionGroup.addAction(self.ui.actionDEL) toolActionGroup.addAction(self.ui.actionORwire) toolActionGroup.addAction(self.ui.actionNarrow) #toolActionGroup.addAction(self.ui.actionRising) toolActionGroup.addAction(self.ui.actionFalling) toolActionGroup.addAction(self.ui.actionTimer) toolActionGroup.addAction(self.ui.actionCounter) toolActionGroup.setExclusive(True) self.connect(self.ui.actionWaltech, QtCore.SIGNAL("triggered()"),lambda HW="Waltech": self.chooseHW(HW)) self.connect(self.ui.actionArduino, QtCore.SIGNAL("triggered()"),lambda HW="Arduino": self.chooseHW(HW)) hwActionGroup = QActionGroup(self.ui.menuDiagnostics) hwActionGroup.addAction(self.ui.actionWaltech) hwActionGroup.addAction(self.ui.actionArduino)
def create_menu(self, menu_name, menu_actions): """ Creates a menu. Groups them so you can only select one at a time. """ menu_action_group = QActionGroup(self) menu_action_group.setExclusive(True) menubar = self.menuBar() menu = menubar.addMenu(menu_name) for action in menu_actions: menu_action_group.addAction(action) menu.addAction(action)
def create_action_group(parent, actions=[], enabled=True, exclusive=True, visible=True, hovered_slot=None, triggered_slot=None): action_group = QActionGroup(parent) for action in actions: action_group.addAction(action) action_group.setEnabled(enabled) action_group.setExclusive(exclusive) action_group.setVisible(visible) if hovered_slot: action_group.connect(action, SIGNAL('hovered(QAction)'), hovered_slot) if triggered_slot: action_group.connect(action, SIGNAL('triggered(QAction)'), triggered_slot) return action_group
def add_stations(self): self.stations = {} group = QActionGroup(self) group.setExclusive(True) for name in sorted(self.parent.stations.map.keys()): url = self.parent.stations.map[name] self.stations[name] = QAction(str(name), self) self.stations[name].setCheckable(True) self.stations[name].setActionGroup(group) self.stations[name].triggered.connect( lambda _=0, st=(name, url): self.parent.station_changed.emit(st)) self.stations_menu.addAction(self.stations[name])
class MainWindow(QMainWindow, Ui_MainWindow): """The Main window of Luma. """ logger = logging.getLogger(__name__) languages = {} translator = None languageHandler = None currentLanguage = '' def __init__(self, parent=None): """The constructor sets up the MainWindow widget, and connects all necessary signals and slots """ super(MainWindow, self).__init__(parent) self.setupUi(self) # We store the window size to make sure the previous window size # is restored when leaving fullscreen mode. This varible is used # in the toggleFullscreen slot. self.__tmpWinSize = self.size() self.eventFilter = LumaEventFilter(self) self.mainTabs.installEventFilter(self.eventFilter) self.translator = QTranslator() self.languageHandler = LanguageHandler() self.languages = self.languageHandler.availableLanguages #self.__createPluginToolBar() self.__createLoggerWidget() self.__loadSettings() self.__createLanguageOptions() self.setStatusBar(self.statusBar) self.mainTabs.setTabsClosable(True) self.mainTabs.setContextMenuPolicy(Qt.CustomContextMenu) self.mainTabs.customContextMenuRequested.connect( self.__mainTabsContextMenu) self.defaultTabStyle = '' self.lumaHeadStyle = 'background: url(:/icons/luma-gray);\n' + \ 'background-position: bottom right;\n' + \ 'background-attachment: fixed;\n' + \ 'background-repeat: no-repeat;' #Sets up pluginWidget #self in parameter is used to call pluginSelected here... self.pluginWidget = PluginListWidget(self) self.showPlugins() self.welcomeTab = WelcomeTab() self.welcomeTab.textBrowser.setStyleSheet(self.lumaHeadStyle) #This value comes from __loadSettings() #Its a checkbox set in WelcomeTab if self.showWelcomeSettings == 2: self.showWelcome() else: # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) self.actionShowWelcomeTab.setEnabled(True) self.serversChangedMessage = QErrorMessage(self) def __mainTabsContextMenu(self, pos): menu = QMenu() if self.mainTabs.count() > 0: return # The menu is displayed even when the rightclick is not # done over the actual tabs so to avoid confusion the # function is disabled entirey #menu.addAction(QApplication.translate( # "MainWindow", "Close all plugin-tabs"), self.tabCloseAll) else: # If there's no tabs, offer to display the pluginlist menu.addAction(self.actionShowPluginList) menu.exec_(self.mainTabs.mapToGlobal(pos)) def __createPluginToolBar(self): """Creates the pluign toolbar. """ self.pluginToolBar = PluginToolBar(self) self.pluginToolBar.setWindowTitle( QApplication.translate('MainWindow', 'Plugintoolbar', None, QApplication.UnicodeUTF8)) self.pluginToolBar.setObjectName('pluginToolBar') self.addToolBar(self.pluginToolBar) self.pluginToolBar.hide() def __createLoggerWidget(self): """Creates the logger widget. """ self.loggerDockWindow = QDockWidget(self) self.loggerDockWindow.setObjectName('loggerDockWindow') self.loggerDockWindow.visibilityChanged[bool].connect( self.actionShowLogger.setChecked) self.loggerDockWindow.setWindowTitle( QApplication.translate('MainWindow', 'Logger', None, QApplication.UnicodeUTF8)) self.loggerWidget = LoggerWidget(self.loggerDockWindow) self.loggerDockWindow.setWidget(self.loggerWidget) self.addDockWidget(Qt.BottomDockWidgetArea, self.loggerDockWindow) self.loggerDockWindow.hide() def __createLanguageOptions(self): """Creates the language selection in the menubar. """ self.langGroup = QActionGroup(self) self.langGroup.setExclusive(True) self.langGroup.triggered['QAction*'].connect(self.languageChanged) for key, name in self.languages.iteritems(): action = QAction(self) action.setCheckable(True) action.setData(key) action.setText(name[0]) action.setStatusTip(name[1]) action.setActionGroup(self.langGroup) self.menuLanguage.addAction(action) if key == self.currentLanguage: action.setChecked(True) def __loadSettings(self, mainWin=True): """Loads settings from file. :param mainWin: If set to ``False``, neither the values for the window size or the window position will be loaded. This is i.e done when the settings dialog returns 1. :type mainWin: bool """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. if mainWin: self.restoreGeometry(settings.geometry) #self.restoreState(settings.state) # If the geometry saved inticates fullscreen mode, # we need to explicitly set the fullscreen menuaction checkbox if self.isFullScreen(): self.actionFullscreen.setChecked(True) # Logger # Logger # The `allwaysShowLoggerOnStart` a precedence on the # `showLogger` value. if settings.showLoggerOnStart: self.actionShowLogger.setChecked(True) else: self.actionShowLogger.setChecked(settings.showLogger) self.loggerWidget.errorBox.setChecked(settings.showErrors) self.loggerWidget.debugBox.setChecked(settings.showDebug) self.loggerWidget.infoBox.setChecked(settings.showInfo) self.toggleLoggerWindow(self.actionShowLogger.isChecked()) # Language self.loadLanguage(settings.language) #Tabs self.showWelcomeSettings = settings.value("showWelcome", 2).toInt()[0] def __writeSettings(self): """Save settings to file. """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. settings.geometry = self.saveGeometry() #settings.state = self.saveState() # Mainwin #max = self.isMaximized() #settings.maximize = max #if not max: # settings.size = self.size() # settings.position = self.pos() # The global logger settings is managed from the settings dialog. # Logger settings.showLogger = self.actionShowLogger.isChecked() settings.showErrors = self.loggerWidget.errorBox.isChecked() settings.showDebug = self.loggerWidget.debugBox.isChecked() settings.showInfo = self.loggerWidget.infoBox.isChecked() # Language settings.language = self.currentLanguage def __switchTranslator(self, translator, qmFile): """Called when a new language is loaded. :param translator: The translator object to install. :type translator: QTranslator :qmFile: The translation file for the loaded language. :type qmFile: string """ qApp.removeTranslator(translator) if translator.load(qmFile): qApp.installTranslator(translator) def __setTabWidgetStyle(self, stylesheet): self.mainTabs.setStyleSheet(stylesheet) @pyqtSlot('QAction*') @pyqtSlot(int) def languageChanged(self, value): """This slot is called by actions and signals related to application translations. The slot contains validation for those parameters defined by the pyqtSlot meta info in the method header. :param value: Can be either a ``QAction`` or an integer value. I.e. menu actions provide ``QActions`` but a ``QCombobox`` might send it's index. :type value: QAction/int """ locale = None if isinstance(value, int): locale = self.languageSelector.itemData(value).toString() elif isinstance(value, QAction): locale = value.data().toString() #else: # locale = value if locale: self.loadLanguage(locale) def loadLanguage(self, locale): """Loads a language by the given language iso code. :param locale: A twoletter lowercase ISO 639 language code and possibly a twoletter uppercase ISO 3166 country code separeted by a underscore. :type locale: string """ if self.currentLanguage != locale: self.currentLanguage = locale qmFile = self.languageHandler.getQmFile(locale) self.__switchTranslator(self.translator, qmFile) def changeEvent(self, event): """This event is called when a new translator is loaded or the system language (locale) is changed. :param event: The event that generated the `changeEvent`. :type event: QEvent """ if None != event: type = event.type() if QEvent.LanguageChange == type or QEvent.LocaleChange == type: self.retranslateUi(self) self.loggerWidget.retranslateUi(self.loggerWidget) def showAboutLuma(self): """Slot for displaying the about dialog. """ AboutDialog().exec_() @pyqtSlot(bool) def toggleLoggerWindow(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the logger window should be shown or not. :type show: bool """ if show: self.loggerDockWindow.show() else: self.loggerDockWindow.hide() @pyqtSlot(bool) def toggleStatusbar(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the statusbar should be shown or not. :type show: bool """ if show: self.statusBar.show() else: self.statusBar.hide() @pyqtSlot(bool) def toggleFullscreen(self, fullscreen): """Slot for toggling the logger window. :param fullscreen: a boolean value indicating whether to enter fullscreenmode or not. :type fullcreen: bool """ if fullscreen: self.__tmpWinSize = self.size() self.showFullScreen() else: self.showNormal() self.resize(self.__tmpWinSize) def showServerEditor(self): """Slot to display the server editor dialog. """ serverEditor = ServerDialog() r = serverEditor.exec_() if r: #TODO -- only display if plugins open: self.serversChangedMessage.showMessage( QApplication.translate( "MainWindow", "You may need to restart plugins for changes to take effect." )) def showTempPasswordDialog(self): """ Sets overridePassword for a server. Using this one doesn't actually have to enter the password in the ServerDialog (and by extension save to disk). """ serverList = ServerList() # Create a stringlist to be used by the qinputdialog stringList = [] for server in serverList.getTable(): stringList.append(server.name) # Display list of servers (serverString, ok) = QInputDialog.getItem( self, QApplication.translate("MainWindow", "Select server"), QApplication.translate("MainWindow", "Server:"), stringList, editable=False) if ok: server = serverList.getServerObjectByName(serverString) if server != None: # Ask for password (value, ok) = QInputDialog.getText( self, QApplication.translate("MainWindow", "Temporary password"), QApplication.translate("MainWindow", "Enter password:"******"""Slot to display the settings dialog. If the settings dialog returns 1, i.e. the user has clicked the ok button, the loadSettings method is called with mainWin=False, to load the (assumed) newly changed settings. :param tab: The index of the tab to display in the settings dialog. :type tab: int """ #settingsDialog = SettingsDialog(self.currentLanguage, self.languages) settingsDialog = SettingsDialog() if tab < 0: tab = 0 settingsDialog.tabWidget.setCurrentIndex(tab) if settingsDialog.exec_(): self.reloadPlugins() # # We assume that some settings is changed # # if the user clicked the ok button, and # # reloads the application settings # self.__loadSettings(mainWin=False) # # A Hack but it'll do for now # for a in self.langGroup.actions(): # if a.data().toString() == self.currentLanguage: # a.setChecked(True) def configurePlugins(self): """Slot to display the plugins configuration. This currently calls `showSettingsDialog` with tab index set to 2. """ self.showSettingsDialog(1) def reloadPlugins(self): """Slot to reload plugins. """ self.pluginWidget.updatePlugins() def pluginSelected(self, item): """This method will be called from the `PluginListWidget`. """ # Clear the stylesheet when a tab is opened self.__setTabWidgetStyle(self.defaultTabStyle) widget = item.plugin.getPluginWidget(None, self) if platform.system() == "Windows": scroll = QScrollArea() scroll.setWidget(widget) scroll.setWidgetResizable(True) index = self.mainTabs.addTab(scroll, item.icon(), item.plugin.pluginUserString) else: index = self.mainTabs.addTab(widget, item.icon(), item.plugin.pluginUserString) self.mainTabs.setCurrentIndex(index) def tabClose(self, index): """Slot for the signal `tabCloseRequest(int)` for the tabMains. """ widget = self.mainTabs.widget(index) # If the tab closed is one of these, enable the toggle-action if widget == self.pluginWidget: self.actionShowPluginList.setEnabled(True) if widget == self.welcomeTab: self.actionShowWelcomeTab.setEnabled(True) self.mainTabs.removeTab(index) # Unparent the widget since it was reparented by the QTabWidget # so it's garbage collected widget.setParent(None) # In case the widget contained circular references # -- force GC to take care of the objects since there can be # quite many if it was BrowserWidget that was closed. # Can't call it directly since that'll be too soon QTimer.singleShot(1000, self.gc) # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) def gc(self): """Runs Python's garbage-collection manually. Used to make sure circular references are taken care of *now*. """ gc.collect() def showWelcome(self): """Shows the Welcome-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) index = self.mainTabs.addTab( self.welcomeTab, QApplication.translate("MainWindow", "Welcome")) self.mainTabs.setCurrentIndex(index) self.actionShowWelcomeTab.setEnabled(False) def showPlugins(self): """Will show the pluginlistwidget-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) if self.mainTabs.indexOf(self.pluginWidget) == -1: index = self.mainTabs.addTab( self.pluginWidget, QApplication.translate("MainWindow", "Plugins")) self.mainTabs.setCurrentIndex(index) self.actionShowPluginList.setEnabled(False) def closeEvent(self, e): """Overrides the ``QMainWindow.closeEvent`` slot to save settings before we tear down the application. """ self.__writeSettings() QMainWindow.closeEvent(self, e)
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.project = None self.tracking = GPSLogging(GPS) self.canvas_page.set_gps(GPS, self.tracking) self.canvas = self.canvas_page.canvas roam.defaults.canvas = self.canvas self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.actionQuit.triggered.connect(self.exit) self.actionLegend.triggered.connect(self.updatelegend) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.gpswidget.settracking(self.tracking) self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel("User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.gpslabel = createlabel("GPS: Not active") self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer2 = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.showInfoResults) RoamEvents.featureformloaded.connect(self.featureformloaded) GPS.gpsposition.connect(self.update_gps_label) GPS.gpsdisconnected.connect(self.gps_disconnected) self.legendpage.showmap.connect(self.showmap) self.currentselection = {} def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def updatelegend(self): self.legendpage.updatecanvas(self.canvas) def update_gps_label(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area self.gpslabel.setText("GPS: PDOP {} HDOP {} VDOP {}".format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) def gps_disconnected(self): self.gpslabel.setText("GPS Not Active") def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return roam.api.utils.open_keyboard() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def settingsupdated(self, settings): self.show() self.canvas_page.settings_updated(settings) def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = self.currentselection[layer] # Update any features that have changed. for updatedfeature in updated: oldfeatures = [f for f in selectedfeatures if f.id() == updatedfeature.id()] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightfeature(self, layer, feature, features): self.canvas_page.highlight_active_selection(layer, feature, features) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError(QApplication.translate('MainWindowPy','Seems something has gone wrong. Press for more details', None, QApplication.UnicodeUTF8), info) def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self, layer, featureid): self.dataentryfinished() self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.canvas_page.clear_temp_objects() def formrejected(self, message, level): self.dataentryfinished() if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) self.cleartempobjects() def featureformloaded(self, form, feature, project, editmode): self.showdataentry() def openForm(self, form, feature, editmode): """ Open the form that is assigned to the layer """ self.dataentrywidget.openform(feature=feature, form=form, project=self.project, editmode=editmode) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms) self.infodock.show() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ crs = self.canvas_page.init_qgisproject(doc) self.projectOpened() GPS.crs = crs @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) layers = self.project.legendlayersmapping().values() self.legendpage.updateitems(layers) try: gps_loglayer = QgsMapLayerRegistry.instance().mapLayersByName('gps_log')[0] if roam.config.settings.get('gpslogging', True): self.tracking.enable_logging_on(gps_loglayer) except IndexError: roam.utils.info("No gps_log found for GPS logging") self.tracking.clear_logging() self.canvas_page.project_loaded(self.project) self.showmap() @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.close_project() # 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) # Project loading screen self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def close_project(self): """ Close the current open project """ self.tracking.clear_logging() self.dataentrywidget.clear() self.canvas_page.cleanup() QgsMapLayerRegistry.instance().removeAllMapLayers() for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons self.panels = [] self.project = None self.hidedataentry() self.infodock.close() RoamEvents.selectioncleared.emit()
class ToolBox(QFrame): """ A tool box widget. """ # Emitted when a tab is toggled. tabToogled = Signal(int, bool) def setExclusive(self, exclusive): """ Set exclusive tabs (only one tab can be open at a time). """ if self.__exclusive != exclusive: self.__exclusive = exclusive self.__tabActionGroup.setExclusive(exclusive) checked = self.__tabActionGroup.checkedAction() if checked is None: # The action group can be out of sync with the actions state # when switching between exclusive states. actions_checked = [page.action for page in self.__pages if page.action.isChecked()] if actions_checked: checked = actions_checked[0] # Trigger/toggle remaining open pages if exclusive and checked is not None: for page in self.__pages: if checked != page.action and page.action.isChecked(): page.action.trigger() def exclusive(self): """ Are the tabs in the toolbox exclusive. """ return self.__exclusive exclusive_ = Property(bool, fget=exclusive, fset=setExclusive, designable=True, doc="Exclusive tabs") def __init__(self, parent=None, **kwargs): QFrame.__init__(self, parent, **kwargs) self.__pages = [] self.__tabButtonHeight = -1 self.__tabIconSize = QSize() self.__exclusive = False self.__setupUi() def __setupUi(self): layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) # Scroll area for the contents. self.__scrollArea = \ _ToolBoxScrollArea(self, objectName="toolbox-scroll-area") self.__scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.__scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.__scrollArea.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.__scrollArea.setFrameStyle(QScrollArea.NoFrame) self.__scrollArea.setWidgetResizable(True) # A widget with all of the contents. # The tabs/contents are placed in the layout inside this widget self.__contents = QWidget(self.__scrollArea, objectName="toolbox-contents") # The layout where all the tab/pages are placed self.__contentsLayout = QVBoxLayout() self.__contentsLayout.setContentsMargins(0, 0, 0, 0) self.__contentsLayout.setSizeConstraint(QVBoxLayout.SetMinAndMaxSize) self.__contentsLayout.setSpacing(0) self.__contents.setLayout(self.__contentsLayout) self.__scrollArea.setWidget(self.__contents) layout.addWidget(self.__scrollArea) self.setLayout(layout) self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.MinimumExpanding) self.__tabActionGroup = \ QActionGroup(self, objectName="toolbox-tab-action-group") self.__tabActionGroup.setExclusive(self.__exclusive) self.__actionMapper = QSignalMapper(self) self.__actionMapper.mapped[QObject].connect(self.__onTabActionToogled) def setTabButtonHeight(self, height): """ Set the tab button height. """ if self.__tabButtonHeight != height: self.__tabButtonHeight = height for page in self.__pages: page.button.setFixedHeight(height) def tabButtonHeight(self): """ Return the tab button height. """ return self.__tabButtonHeight def setTabIconSize(self, size): """ Set the tab button icon size. """ if self.__tabIconSize != size: self.__tabIconSize = size for page in self.__pages: page.button.setIconSize(size) def tabIconSize(self): """ Return the tab icon size. """ return self.__tabIconSize def tabButton(self, index): """ Return the tab button at `index` """ return self.__pages[index].button def tabAction(self, index): """ Return open/close action for the tab at `index`. """ return self.__pages[index].action def addItem(self, widget, text, icon=None, toolTip=None): """ Append the `widget` in a new tab and return its index. Parameters ---------- widget : :class:`QWidget` A widget to be inserted. The toolbox takes ownership of the widget. text : str Name/title of the new tab. icon : :class:`QIcon`, optional An icon for the tab button. toolTip : str, optional Tool tip for the tab button. """ return self.insertItem(self.count(), widget, text, icon, toolTip) def insertItem(self, index, widget, text, icon=None, toolTip=None): """ Insert the `widget` in a new tab at position `index`. See also -------- ToolBox.addItem """ button = self.createTabButton(widget, text, icon, toolTip) self.__contentsLayout.insertWidget(index * 2, button) self.__contentsLayout.insertWidget(index * 2 + 1, widget) widget.hide() page = _ToolBoxPage(index, widget, button.defaultAction(), button) self.__pages.insert(index, page) for i in range(index + 1, self.count()): self.__pages[i] = self.__pages[i]._replace(index=i) self.__updatePositions() # Show (open) the first tab. if self.count() == 1 and index == 0: page.action.trigger() self.__updateSelected() self.updateGeometry() return index def removeItem(self, index): """ Remove the widget at `index`. .. note:: The widget hidden but is is not deleted. """ self.__contentsLayout.takeAt(2 * index + 1) self.__contentsLayout.takeAt(2 * index) page = self.__pages.pop(index) # Update the page indexes for i in range(index, self.count()): self.__pages[i] = self.__pages[i]._replace(index=i) page.button.deleteLater() # Hide the widget and reparent to self # This follows QToolBox.removeItem page.widget.hide() page.widget.setParent(self) self.__updatePositions() self.__updateSelected() self.updateGeometry() def count(self): """ Return the number of widgets inserted in the toolbox. """ return len(self.__pages) def widget(self, index): """ Return the widget at `index`. """ return self.__pages[index].widget def createTabButton(self, widget, text, icon=None, toolTip=None): """ Create the tab button for `widget`. """ action = QAction(text, self) action.setCheckable(True) if icon: action.setIcon(icon) if toolTip: action.setToolTip(toolTip) self.__tabActionGroup.addAction(action) self.__actionMapper.setMapping(action, action) action.toggled.connect(self.__actionMapper.map) button = ToolBoxTabButton(self, objectName="toolbox-tab-button") button.setDefaultAction(action) button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) button.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) if self.__tabIconSize.isValid(): button.setIconSize(self.__tabIconSize) if self.__tabButtonHeight > 0: button.setFixedHeight(self.__tabButtonHeight) return button def ensureWidgetVisible(self, child, xmargin=50, ymargin=50): """ Scroll the contents so child widget instance is visible inside the viewport. """ self.__scrollArea.ensureWidgetVisible(child, xmargin, ymargin) def sizeHint(self): hint = self.__contentsLayout.sizeHint() if self.count(): # Compute max width of hidden widgets also. scroll = self.__scrollArea scroll_w = scroll.verticalScrollBar().sizeHint().width() frame_w = self.frameWidth() * 2 + scroll.frameWidth() * 2 max_w = max([p.widget.sizeHint().width() for p in self.__pages]) hint = QSize(max(max_w, hint.width()) + scroll_w + frame_w, hint.height()) return QSize(200, 200).expandedTo(hint) def __onTabActionToogled(self, action): page = find(self.__pages, action, key=attrgetter("action")) on = action.isChecked() page.widget.setVisible(on) index = page.index if index > 0: # Update the `previous` tab buttons style hints previous = self.__pages[index - 1].button flag = QStyleOptionToolBoxV2.NextIsSelected if on: previous.selected |= flag else: previous.selected &= ~flag previous.update() if index < self.count() - 1: next = self.__pages[index + 1].button flag = QStyleOptionToolBoxV2.PreviousIsSelected if on: next.selected |= flag else: next.selected &= ~flag next.update() self.tabToogled.emit(index, on) self.__contentsLayout.invalidate() def __updateSelected(self): """Update the tab buttons selected style flags. """ if self.count() == 0: return opt = QStyleOptionToolBoxV2 def update(button, next_sel, prev_sel): if next_sel: button.selected |= opt.NextIsSelected else: button.selected &= ~opt.NextIsSelected if prev_sel: button.selected |= opt.PreviousIsSelected else: button.selected &= ~ opt.PreviousIsSelected button.update() if self.count() == 1: update(self.__pages[0].button, False, False) elif self.count() >= 2: pages = self.__pages for i in range(1, self.count() - 1): update(pages[i].button, pages[i + 1].action.isChecked(), pages[i - 1].action.isChecked()) def __updatePositions(self): """Update the tab buttons position style flags. """ if self.count() == 0: return elif self.count() == 1: self.__pages[0].button.position = QStyleOptionToolBoxV2.OnlyOneTab else: self.__pages[0].button.position = QStyleOptionToolBoxV2.Beginning self.__pages[-1].button.position = QStyleOptionToolBoxV2.End for p in self.__pages[1:-1]: p.button.position = QStyleOptionToolBoxV2.Middle for p in self.__pages: p.button.update()
class FreeseerApp(QMainWindowWithDpi): def __init__(self, config): super(FreeseerApp, self).__init__() self.config = config self.icon = QIcon() self.icon.addPixmap(QPixmap(_fromUtf8(":/freeseer/logo.png")), QIcon.Normal, QIcon.Off) self.setWindowIcon(self.icon) self.aboutDialog = AboutDialog() self.aboutDialog.setModal(True) self.logDialog = LogDialog() # # Translator # self.app = QApplication.instance() self.current_language = None self.uiTranslator = QTranslator() self.uiTranslator.load(":/languages/tr_en_US.qm") self.app.installTranslator(self.uiTranslator) self.langActionGroup = QActionGroup(self) self.langActionGroup.setExclusive(True) QTextCodec.setCodecForTr(QTextCodec.codecForName('utf-8')) self.connect(self.langActionGroup, SIGNAL('triggered(QAction *)'), self.translate) # --- Translator # # Setup Menubar # self.menubar = self.menuBar() self.menubar.setGeometry(self.qrect_with_dpi(0, 0, 500, 50)) self.menubar.setObjectName(_fromUtf8("menubar")) self.menuFile = QMenu(self.menubar) self.menuFile.setObjectName(_fromUtf8("menuFile")) self.menuLanguage = QMenu(self.menubar) self.menuLanguage.setObjectName(_fromUtf8("menuLanguage")) self.menuHelp = QMenu(self.menubar) self.menuHelp.setObjectName(_fromUtf8("menuHelp")) exitIcon = QIcon.fromTheme("application-exit") self.actionExit = QAction(self) self.actionExit.setShortcut("Ctrl+Q") self.actionExit.setObjectName(_fromUtf8("actionExit")) self.actionExit.setIcon(exitIcon) helpIcon = QIcon.fromTheme("help-contents") self.actionOnlineHelp = QAction(self) self.actionOnlineHelp.setObjectName(_fromUtf8("actionOnlineHelp")) self.actionOnlineHelp.setIcon(helpIcon) self.actionAbout = QAction(self) self.actionAbout.setObjectName(_fromUtf8("actionAbout")) self.actionAbout.setIcon(self.icon) self.actionLog = QAction(self) self.actionLog.setObjectName(_fromUtf8("actionLog")) self.actionLog.setShortcut("Ctrl+L") # Actions self.menuFile.addAction(self.actionExit) self.menuHelp.addAction(self.actionAbout) self.menuHelp.addAction(self.actionLog) self.menuHelp.addAction(self.actionOnlineHelp) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuLanguage.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) self.setupLanguageMenu() # --- End Menubar self.connect(self.actionExit, SIGNAL('triggered()'), self.close) self.connect(self.actionAbout, SIGNAL('triggered()'), self.aboutDialog.show) self.connect(self.actionLog, SIGNAL('triggered()'), self.logDialog.show) self.connect(self.actionOnlineHelp, SIGNAL('triggered()'), self.openOnlineHelp) self.retranslateFreeseerApp() self.aboutDialog.aboutWidget.retranslate("en_US") def openOnlineHelp(self): """Opens a link to the Freeseer Online Help""" url = QUrl("http://freeseer.readthedocs.org") QDesktopServices.openUrl(url) def translate(self, action): """Translates the GUI via menu action. When a language is selected from the language menu, this function is called and the language to be changed to is retrieved. """ self.current_language = str(action.data().toString()).strip("tr_").rstrip(".qm") log.info("Switching language to: %s" % action.text()) self.uiTranslator.load(":/languages/tr_%s.qm" % self.current_language) self.app.installTranslator(self.uiTranslator) self.retranslateFreeseerApp() self.aboutDialog.aboutWidget.retranslate(self.current_language) self.retranslate() self.logDialog.retranslate() def retranslate(self): """ Reimplement this function to provide translations to your app. """ pass def retranslateFreeseerApp(self): # # Menubar # self.menuFile.setTitle(self.app.translate("FreeseerApp", "&File")) self.menuLanguage.setTitle(self.app.translate("FreeseerApp", "&Language")) self.menuHelp.setTitle(self.app.translate("FreeseerApp", "&Help")) self.actionExit.setText(self.app.translate("FreeseerApp", "&Quit")) self.actionAbout.setText(self.app.translate("FreeseerApp", "&About")) self.actionLog.setText(self.app.translate("FreeseerApp", "View &Log")) self.actionOnlineHelp.setText(self.app.translate("FreeseerApp", "Online Documentation")) # --- Menubar def setupLanguageMenu(self): self.languages = QDir(":/languages").entryList() if self.current_language is None: self.current_language = QLocale.system().name() # Retrieve Current Locale from the operating system. log.debug("Detected user's locale as %s" % self.current_language) for language in self.languages: translator = QTranslator() # Create a translator to translate Language Display Text. translator.load(":/languages/%s" % language) language_display_text = translator.translate("Translation", "Language Display Text") languageAction = QAction(self) languageAction.setCheckable(True) languageAction.setText(language_display_text) languageAction.setData(language) self.menuLanguage.addAction(languageAction) self.langActionGroup.addAction(languageAction)
class Tool(QToolBar): def __init__(self,parent): QToolBar.__init__(self,parent) self.parent = parent self.action_NewProject = QAction(Icons.newprj, 'Project', self) self.action_NewProject.triggered.connect(self.parent.treeWidget.newProject) self.action_NewProject.setToolTip("Create a New Project") self.action_Open = QAction(Icons.open, 'Open', self) self.action_Open.triggered.connect(self.parent.fileOpen) self.action_Open.setToolTip("Open File") self.action_Save = QAction(Icons.save, 'Save', self) self.action_Save.setShortcut('Ctrl+S') self.action_Save.triggered.connect(self.parent.fileSave) self.action_Save.setToolTip("Save Current File") self.action_SaveAll = QAction(Icons.saveall, 'SaveAll', self) self.action_SaveAll.setShortcut('Ctrl+A') self.action_SaveAll.triggered.connect(self.parent.fileSaveAll) self.action_SaveAll.setToolTip("Save All Files") self.action_Build = QAction(Icons.thread_view, 'Build', self) self.action_Build.setShortcut('Ctrl+B') self.action_Build.triggered.connect(self.parent.build_project) self.action_Debug = QAction(Icons.debug_exec, 'Debug', self) self.action_Refresh = QAction(Icons.refresh_tab, 'Refresh', self) self.action_Refresh.triggered.connect(self.parent.treeWidget.refreshCurrentProject) self.action_Run = QAction(Icons.run, 'Run', self) self.action_Run.setShortcut('Ctrl+R') self.action_Run.triggered.connect(self.parent.adb.run) self.action_RunFile = QAction(Icons.go, 'Cmd', self) self.action_RunFile.triggered.connect(self.parent.openCommand) self.parent.runButton.clicked.connect(self.parent.command.setCmdLine) self.action_Stop = QAction(Icons.stop, 'Stop', self) self.action_Stop.setShortcut('Ctrl+Q') self.action_Stop.triggered.connect(self.parent.adb.stop) self.action_Design = QAction(Icons.color_palette, 'Design', self) self.action_Design.triggered.connect(self.parent.design) self.action_Level = QAction(Icons.cmpC_pal, 'Level', self) self.action_Level.triggered.connect(self.parent.level) self.action_Todo = QAction(Icons.task_set, 'Todo', self) self.action_Todo.triggered.connect(self.parent.todo) self.action_Help = QAction(Icons.toc_open, 'Help', self) self.action_Help.triggered.connect(self.parent.help) self.action_Full = QAction(Icons.fullscreen, 'Full', self) self.action_Full.triggered.connect(self.parent.full) self.action_Stop.setDisabled(True) self.setToolLabel() self.setAllowedAreas(Qt.AllToolBarAreas) #self.setFixedHeight(40) #self.setIconSize(QSize(config.iconSize(),config.iconSize())) ''' Adding all Actions ''' self.addAction(self.action_NewProject) self.addAction(self.action_Open) self.addAction(self.action_Save) self.addAction(self.action_SaveAll) #self.addAction(self.action_Refresh) self.addSeparator() self.addAction(self.action_Build) self.addAction(self.action_Run) #self.addAction(self.action_RunFile) self.addAction(self.action_Stop) self.addAction(self.action_Debug) self.addSeparator() self.addAction(self.action_Design) self.addAction(self.action_Level) self.addAction(self.action_Todo) self.initOptionsMenu() self.addSeparator() self.initStyleMenu() self.initLexerMenu() self.initApiMenu() #self.addAction(self.action_Help) #self.addAction(self.action_Full) self.addSeparator() self.initModeMenu() def colorChange(self, text, color): #print "colorChange ",text,color editStyle = config.readStyle() editStyle[text] = color config.writeStyle(editStyle) for i in range(len(self.parent.files)): self.parent.tabWidget.widget(i).setEditorStyle() def setColors(self,action): print action.text() def changeAll(self): self.colorChange("base", "#ffffff") def setIcon(self,val): config.setIconSize(val) self.setIconSize(QSize(val,val)) def setToolLabel(self): if (config.toolLabel()): self.setToolButtonStyle(Qt.ToolButtonIconOnly) self.setIconSize(QSize(24,24)) else: self.setIconSize(QSize(16,16)) self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) '''Important for multiple callbacks in for loop''' def make_callback(self, text): return lambda:self.colorChange(text) ''' Options Menu ''' def initOptionsMenu(self): men = QMenu() #Threshold Slider self.threshSlider = QSlider() self.threshSlider.setTickPosition(QSlider.TicksLeft) self.threshSlider.setOrientation(Qt.Horizontal) self.threshSlider.setValue(config.thresh()) self.threshSlider.setMinimum(0) self.threshSlider.setMaximum(5) self.threshSlider.valueChanged.connect(self.parent.setThreshold) self.threshSliderAction = QWidgetAction(men) self.threshSliderAction.setDefaultWidget(self.threshSlider) #TabsWidth Slider self.tabsSlider = QSlider() self.tabsSlider.setTickPosition(QSlider.TicksLeft) self.tabsSlider.setOrientation(Qt.Horizontal) self.tabsSlider.setValue(config.tabwidth()) self.tabsSlider.setMinimum(0) self.tabsSlider.setMaximum(8) self.tabsSlider.valueChanged.connect(self.parent.setTabWidth) self.tabsSliderAction = QWidgetAction(men) self.tabsSliderAction.setDefaultWidget(self.tabsSlider) #iconSize Slider self.iconSlider = QSlider() self.iconSlider.setTickPosition(QSlider.TicksLeft) self.iconSlider.setOrientation(Qt.Horizontal) self.iconSlider.setValue(config.iconSize()) self.iconSlider.setMinimum(16) self.iconSlider.setMaximum(32) self.iconSlider.setSingleStep(2) self.iconSlider.valueChanged.connect(self.setIcon) self.iconSliderAction = QWidgetAction(men) self.iconSliderAction.setDefaultWidget(self.iconSlider) '''Font Button''' self.fontCombo = QFontComboBox() self.fontCombo.currentFontChanged.connect(self.parent.setFont) self.fontCombo.setCurrentFont(QFont(config.fontName())) self.fontComboMenu = QWidgetAction(men) self.fontComboMenu.setDefaultWidget(self.fontCombo) '''Font Size''' self.fontSizeCombo = QComboBox() for size in range(1,40): self.fontSizeCombo.addItem(str(size)) self.fontSizeCombo.setCurrentIndex(config.fontSize()) self.fontSizeCombo.currentIndexChanged.connect(self.parent.setFontSize) self.fontSizeComboMenu = QWidgetAction(men) self.fontSizeComboMenu.setDefaultWidget(self.fontSizeCombo) action_Android = QAction(Icons.android,'Android', self) action_Android.triggered.connect(self.parent.android) action_Ant = QAction(Icons.ant_view,'Ant', self) action_Ant.triggered.connect(self.parent.antt) action_Squirrel = QAction(Icons.nut,'Squirrel', self) action_Squirrel.triggered.connect(self.parent.squirrel) action_Ios1 = QAction(Icons.ios,'iOS', self) action_Update = QAction(Icons.update,"Update",self) action_Update.triggered.connect(self.parent.update) action_explorer = QAction("Explorer",self) action_explorer.triggered.connect(self.parent.exp) action_explorer.setCheckable(True) action_explorer.setChecked(True) action_console = QAction("Console",self) action_console.triggered.connect(self.parent.cmd) action_console.setCheckable(True) action_console.setChecked(False) #action_designer = QAction("Designer",self) #action_designer.triggered.connect(self.parent.design) action_Indentation = QAction("Indentation Guides",self) action_Indentation.triggered.connect(self.parent.setIndent) action_Indentation.setCheckable(True) action_Indentation.setChecked(config.indent()) action_WhiteSpace = QAction("WhiteSpace",self) action_WhiteSpace.triggered.connect(self.parent.setWhiteSpace) action_WhiteSpace.setCheckable(True) action_WhiteSpace.setChecked(config.whiteSpace()) action_EndLine = QAction("End of Lines",self) action_EndLine.triggered.connect(self.parent.setEndLine) action_EndLine.setCheckable(True) action_Margin = QAction("Line Numbers",self) action_Margin.triggered.connect(self.parent.setMargin) action_Margin.setCheckable(True) action_Margin.setChecked(config.margin()) action_ToolLabel = QAction("Tool Labels",self) action_ToolLabel.triggered.connect(self.setToolLabel) action_ToolLabel.setCheckable(True) #action_ToolLabel.setChecked(config.toolLabel()) '''Encoding''' encodingGroup = QActionGroup(self) encodingGroup.setExclusive(True) action_Ascii = QAction("Ascii",encodingGroup) action_Ascii.setCheckable(True) action_Unicode = QAction("Unicode",encodingGroup) action_Unicode.setCheckable(False) encodingGroup.addAction(action_Ascii) encodingGroup.addAction(action_Unicode) encodingGroup.selected.connect(self.parent.setEncoding) if(config.encoding() == Encoding.ASCII): action_Ascii.setChecked(True) else: action_Unicode.setChecked(True) men.addAction(action_Update) men.addAction(self.action_Help) men.addAction(self.action_Full) men.addSeparator() men.addAction(action_Android) men.addAction(action_Ant) men.addAction(action_Squirrel) men.addAction(action_Ios1) men.addSeparator() men.addAction(action_explorer) men.addAction(action_console) #men.addAction(action_designer) men.addSeparator() men.addAction(action_Indentation) men.addAction(action_WhiteSpace) men.addAction(action_EndLine) men.addAction(action_Margin) men.addAction(action_ToolLabel) men.addSeparator() men.addActions(encodingGroup.actions()) men.addSeparator() head_font = QLabel("Font---------------------") fnt = head_font.font() fnt.setBold(True) head_font.setFont(fnt) head_fontWidgetAction = QWidgetAction(men) head_fontWidgetAction.setDefaultWidget(head_font) men.addAction(head_fontWidgetAction) men.addAction(self.fontComboMenu) men.addAction(self.fontSizeComboMenu) men.addSeparator() men.addAction(QAction("TabWidth",self)) men.addAction(self.tabsSliderAction) men.addSeparator() men.addAction(QAction("Threshold",self)) men.addAction(self.threshSliderAction) #men.addAction(QAction("Icon Size",self)) #men.addAction(self.iconSliderAction) self.action_Options = QAction(Icons.emblem_system, 'Options', self) self.action_Options.setMenu(men) self.addAction(self.action_Options) ''' Mode Menu ''' def initModeMenu(self): self.modeGroup = QActionGroup(self) self.modeGroup.setExclusive(True) self.modeGroup.selected.connect(self.parent.setMode) self.action_Squirrel = QAction(Icons.nut, 'Squ', self.modeGroup) self.action_Squirrel.setCheckable(True) self.action_Emo = QAction(Icons.emo, 'Emo', self.modeGroup) self.action_Emo.setCheckable(True) self.action_And = QAction(Icons.android, 'Android', self.modeGroup) self.action_And.setCheckable(True) self.action_Ios = QAction(Icons.ios, 'ios', self.modeGroup) self.action_Ios.setCheckable(True) self.modeGroup.addAction(self.action_Squirrel) self.modeGroup.addAction(self.action_Emo) self.modeGroup.addAction(self.action_And) self.modeGroup.addAction(self.action_Ios) self.addActions(self.modeGroup.actions()) if(config.mode() == 0): self.action_Squirrel.setChecked(True) self.action_Build.setEnabled(False) self.action_Run.setEnabled(False) elif(config.mode() == 1): self.action_Emo.setChecked(True) self.action_Build.setEnabled(True) self.action_Run.setEnabled(True) elif(config.mode() == 2): self.action_And.setChecked(True) self.action_Build.setEnabled(True) self.action_Run.setEnabled(True) elif(config.mode() == 3): self.action_Ios.setChecked(True) self.action_Build.setEnabled(False) self.action_Run.setEnabled(False) ''' Style Menu ''' def initStyleMenu(self): editStyle = config.readStyle() self.action_Style = QAction(Icons.style, 'Style', self) men = QMenu(self) men1 = QMenu() self.base = StyleWidget(self,"base",editStyle["base"]) self.back = StyleWidget(self,"back",editStyle["back"]) self.caret = StyleWidget(self,"caret",editStyle["caret"]) self.margin = StyleWidget(self,"margin",editStyle["margin"]) self.marker = StyleWidget(self,"marker",editStyle["marker"]) self.comment = StyleWidget(self,"comment",editStyle["comment"]) self.number = StyleWidget(self,"number",editStyle["number"]) self.keyword = StyleWidget(self,"keyword",editStyle["keyword"]) self.string = StyleWidget(self,"string",editStyle["string"]) self.operator = StyleWidget(self,"operator",editStyle["operator"]) self.connect(self.base, SIGNAL("colorChange"),self.colorChange) self.connect(self.back, SIGNAL("colorChange"),self.colorChange) self.connect(self.caret, SIGNAL("colorChange"),self.colorChange) self.connect(self.margin, SIGNAL("colorChange"),self.colorChange) self.connect(self.marker, SIGNAL("colorChange"),self.colorChange) self.connect(self.comment, SIGNAL("colorChange"),self.colorChange) self.connect(self.number, SIGNAL("colorChange"),self.colorChange) self.connect(self.keyword, SIGNAL("colorChange"),self.colorChange) self.connect(self.string, SIGNAL("colorChange"),self.colorChange) self.connect(self.operator, SIGNAL("colorChange"),self.colorChange) self.baseMenu = QWidgetAction(men) self.baseMenu.setDefaultWidget(self.base) self.backMenu = QWidgetAction(men) self.backMenu.setDefaultWidget(self.back) self.caretMenu = QWidgetAction(men) self.caretMenu.setDefaultWidget(self.caret) self.marginMenu = QWidgetAction(men) self.marginMenu.setDefaultWidget(self.margin) self.markerMenu = QWidgetAction(men) self.markerMenu.setDefaultWidget(self.marker) self.commentMenu = QWidgetAction(men) self.commentMenu.setDefaultWidget(self.comment) self.numberMenu = QWidgetAction(men) self.numberMenu.setDefaultWidget(self.number) self.keywordMenu = QWidgetAction(men) self.keywordMenu.setDefaultWidget(self.keyword) self.stringMenu = QWidgetAction(men) self.stringMenu.setDefaultWidget(self.string) self.operatorMenu = QWidgetAction(men) self.operatorMenu.setDefaultWidget(self.operator) self.styleGroup = QActionGroup(self) self.styleGroup.setExclusive(True) self.styleGroup.selected.connect(self.setColors) self.style1 = QAction("All Hallow's Eve",self.styleGroup) self.style1.setCheckable(True) self.style2 = QAction("Amy",self.styleGroup) self.style2.setCheckable(True) self.style3 = QAction("Aptana Studio",self.styleGroup) self.style3.setCheckable(True) self.style4 = QAction("Bespin",self.styleGroup) self.style4.setCheckable(True) self.style5 = QAction("Blackboard",self.styleGroup) self.style5.setCheckable(True) self.style6 = QAction("Choco",self.styleGroup) self.style6.setCheckable(True) self.style7 = QAction("Cobalt",self.styleGroup) self.style7.setCheckable(True) self.style8 = QAction("Dawn",self.styleGroup) self.style8.setCheckable(True) self.style9 = QAction("Eclipse",self.styleGroup) self.style9.setCheckable(True) self.styleGroup.addAction(self.style1) self.styleGroup.addAction(self.style2) self.styleGroup.addAction(self.style3) self.styleGroup.addAction(self.style4) self.styleGroup.addAction(self.style5) self.styleGroup.addAction(self.style6) self.styleGroup.addAction(self.style7) self.styleGroup.addAction(self.style8) self.styleGroup.addAction(self.style9) men1.addAction(self.baseMenu) men1.addAction(self.backMenu) men1.addAction(self.caretMenu) men1.addAction(self.marginMenu) men1.addAction(self.markerMenu) men1.addAction(self.commentMenu) men1.addAction(self.numberMenu) men1.addAction(self.keywordMenu) men1.addAction(self.stringMenu) men1.addAction(self.operatorMenu) men1.addSeparator() men2 = QMenu(self) men2.setTitle("Styles") men2.addActions(self.styleGroup.actions()) men1.addMenu(men2) self.action_Style.setMenu(men1) self.addAction(self.action_Style) ''' Lexer Menu''' def make_action_lex(self, text): action = QAction(text, self.lexGroup) action.setCheckable(True) return action def initLexerMenu(self): self.action_Lexer = QAction(Icons.file_obj, 'Lexer', self) men = QMenu() self.lexGroup = QActionGroup(self) self.lexGroup.setExclusive(True) self.lexGroup.selected.connect(self.parent.setLexer) #langs = [i for i in dir(Qsci) if i.startswith('QsciLexer')] langs = ['Bash', 'Batch', 'CMake', 'CPP', 'CSS', 'C#','HTML','Java', 'JavaScript', 'Lua', 'Makefile','Python', 'SQL', 'XML', 'YAML'] for l in langs: act = self.make_action_lex(l) self.lexGroup.addAction(act) if(langs.index(l) == 8): #For javascript act.setChecked(True) #print l[9:] # we don't need to print "QsciLexer" before each name men.addActions(self.lexGroup.actions()) self.action_Lexer.setMenu(men) self.addAction(self.action_Lexer) ''' Api Menu ''' def make_action_api(self, text): action = QAction(text, self.apiGroup) action.setCheckable(True) return action def initApiMenu(self): self.action_Api = QAction(Icons.lib, 'Api', self) men = QMenu() self.apiGroup = QActionGroup(self) self.apiGroup.setExclusive(True) self.apiGroup.selected.connect(self.parent.setApi) list = oslistdir(apiDir) apis = [] if(list != None): for i in list: if i.endswith("api"): apis.append(i.replace(".api", "")) if(apis != None): for i in apis: act = self.make_action_api(i) self.apiGroup.addAction(act) if(i == "emo"): #For emo act.setChecked(True) men.addActions(self.apiGroup.actions()) self.action_Api.setMenu(men) self.addAction(self.action_Api)
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()
class FreeseerApp(QMainWindow): def __init__(self): super(FreeseerApp, self).__init__() self.icon = QIcon() self.icon.addPixmap(QPixmap(_fromUtf8(":/freeseer/logo.png")), QIcon.Normal, QIcon.Off) self.setWindowIcon(self.icon) self.aboutDialog = AboutDialog() self.aboutDialog.setModal(True) # # Translator # self.app = QApplication.instance() self.current_language = None self.uiTranslator = QTranslator() self.uiTranslator.load(":/languages/tr_en_US.qm") self.app.installTranslator(self.uiTranslator) self.langActionGroup = QActionGroup(self) self.langActionGroup.setExclusive(True) QTextCodec.setCodecForTr(QTextCodec.codecForName('utf-8')) self.connect(self.langActionGroup, SIGNAL('triggered(QAction *)'), self.translate) # --- Translator # # Setup Menubar # self.menubar = self.menuBar() self.menubar.setGeometry(QRect(0, 0, 500, 50)) self.menubar.setObjectName(_fromUtf8("menubar")) self.menuFile = QMenu(self.menubar) self.menuFile.setObjectName(_fromUtf8("menuFile")) self.menuLanguage = QMenu(self.menubar) self.menuLanguage.setObjectName(_fromUtf8("menuLanguage")) self.menuHelp = QMenu(self.menubar) self.menuHelp.setObjectName(_fromUtf8("menuHelp")) exitIcon = QIcon.fromTheme("application-exit") self.actionExit = QAction(self) self.actionExit.setShortcut("Ctrl+Q") self.actionExit.setObjectName(_fromUtf8("actionExit")) self.actionExit.setIcon(exitIcon) helpIcon = QIcon.fromTheme("help-contents") self.actionOnlineHelp = QAction(self) self.actionOnlineHelp.setObjectName(_fromUtf8("actionOnlineHelp")) self.actionOnlineHelp.setIcon(helpIcon) self.actionAbout = QAction(self) self.actionAbout.setObjectName(_fromUtf8("actionAbout")) self.actionAbout.setIcon(self.icon) # Actions self.menuFile.addAction(self.actionExit) self.menuHelp.addAction(self.actionAbout) self.menuHelp.addAction(self.actionOnlineHelp) self.menubar.addAction(self.menuFile.menuAction()) self.menubar.addAction(self.menuLanguage.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) self.setupLanguageMenu() # --- End Menubar self.connect(self.actionExit, SIGNAL('triggered()'), self.close) self.connect(self.actionAbout, SIGNAL('triggered()'), self.aboutDialog.show) self.connect(self.actionOnlineHelp, SIGNAL('triggered()'), self.openOnlineHelp) self.retranslateFreeseerApp() self.aboutDialog.retranslate("en_US") def openOnlineHelp(self): """Opens a link to the Freeseer Online Help""" url = QUrl("http://freeseer.github.io") QDesktopServices.openUrl(url) def translate(self, action): """Translates the GUI via menu action. When a language is selected from the language menu, this function is called and the language to be changed to is retrieved. """ self.current_language = str( action.data().toString()).strip("tr_").rstrip(".qm") log.info("Switching language to: %s" % action.text()) self.uiTranslator.load(":/languages/tr_%s.qm" % self.current_language) self.retranslateFreeseerApp() self.aboutDialog.retranslate(self.current_language) self.retranslate() def retranslate(self): """ Reimplement this function to provide translations to your app. """ pass def retranslateFreeseerApp(self): # # Menubar # self.menuFile.setTitle(self.app.translate("FreeseerApp", "&File")) self.menuLanguage.setTitle( self.app.translate("FreeseerApp", "&Language")) self.menuHelp.setTitle(self.app.translate("FreeseerApp", "&Help")) self.actionExit.setText(self.app.translate("FreeseerApp", "&Quit")) self.actionAbout.setText(self.app.translate("FreeseerApp", "&About")) self.actionOnlineHelp.setText( self.app.translate("FreeseerApp", "Online Documentation")) # --- Menubar def setupLanguageMenu(self): self.languages = QDir(":/languages").entryList() if self.current_language is None: self.current_language = QLocale.system().name( ) # Retrieve Current Locale from the operating system. log.debug("Detected user's locale as %s" % self.current_language) for language in self.languages: translator = QTranslator( ) # Create a translator to translate Language Display Text. translator.load(":/languages/%s" % language) language_display_text = translator.translate( "Translation", "Language Display Text") languageAction = QAction(self) languageAction.setCheckable(True) languageAction.setText(language_display_text) languageAction.setData(language) self.menuLanguage.addAction(languageAction) self.langActionGroup.addAction(languageAction) if self.current_language == str(language).strip("tr_").rstrip( ".qm"): languageAction.setChecked(True)
class Viewer(ViewerBase, ViewerClass): trackingChanged = pyqtSignal(bool) setLocationTriggered = pyqtSignal() updateFeatures = pyqtSignal(bool) layerChanged = pyqtSignal(QgsMapLayer) clearLine = pyqtSignal() closed = pyqtSignal() def __init__(self, callbackobject, parent=None): """Constructor.""" super(Viewer, self).__init__(parent) self.setupUi(self) self.callbackobject = callbackobject self.frame = self.webview.page().mainFrame() self.actiongroup = QActionGroup(self) self.actiongroup.setExclusive(True) self.actiongroup.triggered.connect(self.action_triggered) self.measuredialog = MeasureDialog(self) self.toolbar = QToolBar() self.qgisTrackButton = self.toolbar.addAction("QGIS Track") self.qgisTrackButton.setIcon(QIcon(":/icons/track")) self.qgisTrackButton.setCheckable(True) self.qgisTrackButton.setChecked(True) self.qgisTrackButton.toggled.connect(self.trackingChanged.emit) self.setlocationaction = self.toolbar.addAction("Set location") self.setlocationaction.setIcon(QIcon(":/icons/location")) self.setlocationaction.triggered.connect(self.setLocationTriggered.emit) self.setlocationaction.setCheckable(True) self.viewfeatures = self.toolbar.addAction("Load QGIS Features") self.viewfeatures.setIcon(QIcon(":/icons/features")) self.viewfeatures.setCheckable(True) self.viewfeatures.setChecked(True) self.viewfeatures.toggled.connect(self.updateFeatures.emit) spacer = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.toolbar.addWidget(spacer) self.measureaction = self.toolbar.addAction("measure") self.measureaction.setObjectName("Measure") self.measureaction.setIcon(QIcon(":/icons/measure")) self.measureaction.setCheckable(True) self.infoaction = self.toolbar.addAction("Info") self.infoaction.setObjectName("Info") self.infoaction.setIcon(QIcon(":/icons/info")) self.infoaction.setCheckable(True) self.selectaction = self.toolbar.addAction("Select") self.selectaction.setObjectName("Select") self.selectaction.setIcon(QIcon(":/icons/select")) self.selectaction.setCheckable(True) self.toolbar.addSeparator() self.deleteaction = self.toolbar.addAction("Delete") self.deleteaction.setIcon(QIcon(":/icons/delete")) self.deleteaction.triggered.connect(self.delete_selected) self.deleteaction.setEnabled(False) self.addaction = self.toolbar.addAction("Add") self.addaction.setObjectName("Add") self.addaction.setIcon(QIcon(":/icons/add")) self.addaction.setCheckable(True) self.moveaction = self.toolbar.addAction("Move") self.moveaction.setObjectName("Move") self.moveaction.setIcon(QIcon(":/icons/move")) self.moveaction.setCheckable(True) self.actiongroup.addAction(self.moveaction) self.actiongroup.addAction(self.addaction) self.actiongroup.addAction(self.infoaction) self.actiongroup.addAction(self.measureaction) self.actiongroup.addAction(self.selectaction) self.activelayercombo = QgsMapLayerComboBox() self.activelayercombo.layerChanged.connect(self.layer_changed) self.activelayeraction = self.toolbar.addWidget(self.activelayercombo) self.activelayercombo.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.activelayercombo.currentIndexChanged.connect(self.index_changed) self.zvaluecheck = QCheckBox() self.zvaluecheck.setChecked(True) self.zvaluecheck.setText("Copy Z value") self.zvaluecheck.setToolTip("Copy Z value from viewer to new features in QGIS. Must have a field named Z to enable") self.zvalueaction = self.toolbar.addWidget(self.zvaluecheck) self.dockWidgetContents.layout().insertWidget(0, self.toolbar) self.webview.settings().setAttribute(QWebSettings.PluginsEnabled, True) self.webview.settings().setAttribute(QWebSettings.JavascriptEnabled, True) self.webview.settings().setAttribute(QWebSettings.DeveloperExtrasEnabled, True) self.frame.setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff) self.frame.setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff) self.frame.javaScriptWindowObjectCleared.connect(self.addcallbackobject) self.measuredialog.modeCombo.currentIndexChanged.connect(self.action_triggered) self.measuredialog.clearButton.clicked.connect(self.clear_line) self.earthmine = EarthmineAPI(self.frame) def closeEvent(self, event): self.closed.emit() super(Viewer, self).closeEvent(event) def index_changed(self, index): if index == -1: self.set_button_states(False, False, False, False) def clear_line(self): self.clearLine.emit() self.earthmine.clearLine() @property def copyZvalue(self): layer = self.active_layer if not layer: return False if layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point: return self.zvaluecheck.isChecked() else: return False @property def geom(self): return self.measuredialog.geom @geom.setter def geom(self, value): self.measuredialog.geom = value self.measuredialog.update_geom_labels() @property def tracking(self): return self.qgisTrackButton.isChecked() @property def mode(self): return self.measuredialog.mode @property def active_layer(self): return self.activelayercombo.currentLayer() def layer_changed(self, layer): if not layer: self.set_button_states(False, False, False, False) return if layer.type() == QgsMapLayer.VectorLayer: enabledselecttools = layer.geometryType() in [QGis.Line, QGis.Point] enableedittools = layer.isEditable() enabledelete = layer.isEditable() and layer.selectedFeatureCount() enablemove = layer.geometryType() == QGis.Point and layer.isEditable() else: enabledselecttools = False enableedittools = False enabledelete = False enablemove = False self.set_button_states(enabledselecttools, enableedittools, enabledelete, enablemove) self.action_triggered() self.layerChanged.emit(layer) def selection_changed(self, layer): if layer == self.active_layer: enabledelete = layer.isEditable() and layer.selectedFeatureCount() self.deleteaction.setEnabled(enabledelete) def set_button_states(self, selecttools, edittools, deleteenabled, moveenabled): actions = [self.selectaction, self.infoaction] for action in actions: action.setEnabled(selecttools) editactions = [self.deleteaction, self.moveaction, self.addaction] for action in editactions: action.setEnabled(edittools) if edittools: self.deleteaction.setEnabled(deleteenabled) self.moveaction.setEnabled(moveenabled) for action in editactions: if action is self.actiongroup.checkedAction() and not action.isEnabled(): self.infoaction.toggle() break layer = self.active_layer if not layer: enablez = False else: enablez = layer.type() == QgsMapLayer.VectorLayer and layer.geometryType() == QGis.Point self.zvalueaction.setEnabled(enablez) @property def current_action_color(self): action = self.actiongroup.checkedAction() color = int("0x00ff00", 16) if action == self.measureaction: if self.mode == "Vertical": color = int("0x0000ff", 16) return color def action_triggered(self, *args): action = self.actiongroup.checkedAction() layer = self.activelayercombo.currentLayer() self.clear_line() if not action: return if not action == self.measureaction and (not layer or not layer.type() == QgsMapLayer.VectorLayer): return color = self.current_action_color actiondata = {} if action == self.measureaction: self.measuredialog.show() actiondata['mode'] = self.mode geomtype = None layerid = None else: self.measuredialog.hide() geomtype = QGis.vectorGeometryType(layer.geometryType()) layerid = layer.id() data = dict(action=action.objectName(), layer=layerid, geom=geomtype, actiondata=actiondata, color=color) self.earthmine.updateAction(data) def active_tool(self): action = self.actiongroup.checkedAction() if not action: return None return action.objectName() def update_current_layer(self, layer): self.activelayercombo.setLayer(layer) def addcallbackobject(self): self.frame.addToJavaScriptWindowObject("qgis", self.callbackobject) def loadviewer(self, url): self.webview.load(url) self.frame.addToJavaScriptWindowObject("qgis", self.callbackobject) def startViewer(self, settings): self.earthmine.startViewer(settings) def set_location(self, point): # # NOTE Set location takes WGS84 make sure you have transformed it first before sending self.earthmine.setLocation(point.x(), point.y()) def clear_features(self): self.earthmine.clearFeatures() def clear_layer_features(self, layerid): self.earthmine.clearLayerObjects(layerid) def remove_feature(self, layerid, featureid): """ :param features: A dict of layerid, id, lat, lng :return: """ self.earthmine.removeFeature(layerid, featureid) def load_features(self, layerdata, features): """ :param features: A dict of layerid, id, lat, lng :return: """ self.earthmine.loadFeatures(layerdata, features) def layer_loaded(self, layerid): return self.earthmine.layerLoaded(layerid) def clear_selection(self, layerid): self.earthmine.clearSelection(layerid) def set_selection(self, layerid, featureids, clearlast=True): self.earthmine.setSelection(layerid, featureids, clearlast) def edit_feature(self, layerid, featureid, nodes): self.earthmine.editFeature(layerid, featureid, nodes) def delete_selected(self): layer = self.active_layer layer.deleteSelectedFeatures()
def __init__(self, parent): SMPluginWidget.__init__(self, parent) self.internal_shell = None # Initialize plugin self.initialize_plugin() self.no_doc_string = _("No documentation available") self._last_console_cb = None self._last_editor_cb = None self.set_default_color_scheme() self.plain_text = PlainText(self) self.rich_text = RichText(self) color_scheme = get_color_scheme(self.get_option("color_scheme_name")) self.set_plain_text_font(self.get_plugin_font(), color_scheme) self.plain_text.editor.toggle_wrap_mode(self.get_option("wrap")) # Add entries to read-only editor context-menu font_action = create_action( self, _("&Font..."), None, "font.png", _("Set font style"), triggered=self.change_font ) self.wrap_action = create_action(self, _("Wrap lines"), toggled=self.toggle_wrap_mode) self.wrap_action.setChecked(self.get_option("wrap")) self.plain_text.editor.readonly_menu.addSeparator() add_actions(self.plain_text.editor.readonly_menu, (font_action, self.wrap_action)) self.set_rich_text_font(self.get_plugin_font("rich_text")) self.shell = None self.external_console = None # locked = disable link with Console self.locked = False self._last_texts = [None, None] self._last_rope_data = None # Object name layout_edit = QHBoxLayout() layout_edit.setContentsMargins(0, 0, 0, 0) txt = _("Source") if sys.platform == "darwin": source_label = QLabel(" " + txt) else: source_label = QLabel(txt) layout_edit.addWidget(source_label) self.source_combo = QComboBox(self) self.source_combo.addItems([_("Console"), _("Editor")]) self.connect(self.source_combo, SIGNAL("currentIndexChanged(int)"), self.source_changed) if not programs.is_module_installed("rope"): self.source_combo.hide() source_label.hide() layout_edit.addWidget(self.source_combo) layout_edit.addSpacing(10) layout_edit.addWidget(QLabel(_("Object"))) self.combo = ObjectComboBox(self) layout_edit.addWidget(self.combo) self.object_edit = QLineEdit(self) self.object_edit.setReadOnly(True) layout_edit.addWidget(self.object_edit) self.combo.setMaxCount(self.get_option("max_history_entries")) self.combo.addItems(self.load_history()) self.connect(self.combo, SIGNAL("valid(bool)"), lambda valid: self.force_refresh()) # Plain text docstring option self.docstring = True self.rich_help = sphinxify is not None and self.get_option("rich_mode", True) self.plain_text_action = create_action(self, _("Plain Text"), toggled=self.toggle_plain_text) # Source code option self.show_source_action = create_action(self, _("Show Source"), toggled=self.toggle_show_source) # Rich text option self.rich_text_action = create_action(self, _("Rich Text"), toggled=self.toggle_rich_text) # Add the help actions to an exclusive QActionGroup help_actions = QActionGroup(self) help_actions.setExclusive(True) help_actions.addAction(self.plain_text_action) help_actions.addAction(self.rich_text_action) # Automatic import option self.auto_import_action = create_action(self, _("Automatic import"), toggled=self.toggle_auto_import) auto_import_state = self.get_option("automatic_import") self.auto_import_action.setChecked(auto_import_state) # Lock checkbox self.locked_button = create_toolbutton(self, triggered=self.toggle_locked) layout_edit.addWidget(self.locked_button) self._update_lock_icon() # Option menu options_button = create_toolbutton(self, text=_("Options"), icon=get_icon("tooloptions.png")) options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) add_actions( menu, [self.rich_text_action, self.plain_text_action, self.show_source_action, None, self.auto_import_action], ) options_button.setMenu(menu) layout_edit.addWidget(options_button) if self.rich_help: self.switch_to_rich_text() else: self.switch_to_plain_text() self.plain_text_action.setChecked(not self.rich_help) self.rich_text_action.setChecked(self.rich_help) self.rich_text_action.setEnabled(sphinxify is not None) self.source_changed() # Main layout layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addLayout(layout_edit) layout.addWidget(self.plain_text) layout.addWidget(self.rich_text) self.setLayout(layout) # Add worker thread for handling rich text rendering if sphinxify is None: self._sphinx_thread = None else: self._sphinx_thread = SphinxThread( text={}, html_text_no_doc=warning(self.no_doc_string), math_option=self.get_option("math") ) self.connect(self._sphinx_thread, SIGNAL("html_ready(QString)"), self._on_sphinx_thread_html_ready) self.connect(self._sphinx_thread, SIGNAL("error_msg(QString)"), self._on_sphinx_thread_error_msg) self._starting_up = True
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) icon = roam_style.iconsize() self.projecttoolbar.setIconSize(QSize(icon, icon)) self.firstshow = True self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) # self.canvas.setInteractive(False) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) if hasattr(self.canvas, 'setParallelRenderingEnabled'): threadcount = QThread.idealThreadCount() threadcount = 2 if threadcount > 2 else 1 QgsApplication.setMaxThreads(threadcount) self.canvas.setParallelRenderingEnabled(True) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) if roam.config.settings.get('north_arrow', False): self.northarrow = NorthArrow(":/icons/north", self.canvas) self.northarrow.setPos(10, 10) self.canvas.scene().addItem(self.northarrow) self.scalebar_enabled = roam.config.settings.get('scale_bar', False) if self.scalebar_enabled: self.scalebar = ScaleBarItem(self.canvas) self.canvas.scene().addItem(self.scalebar) self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu) gpsspacewidget = QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.marker = GPSMarker(self.canvas) self.marker.hide() self.currentfeatureband = CurrentSelection(self.canvas) self.currentfeatureband.setIconSize(30) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 50)) self.currentfeatureband.setOutlineColour(QColor(186, 93, 212)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(165, 111, 212, 75)) self.gpsband.setWidth(5) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.openfeatureform.connect(self.feature_form_loaded) RoamEvents.sync_complete.connect(self.refresh_map) self.connectButtons() def refresh_map(self): self.canvas.refresh() def updatescale(self): self.canvas.zoomScale(1.0 / self.scalewidget.scale()) def init_qgisproject(self, doc): parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) red = QgsProject.instance().readNumEntry("Gui", "/CanvasColorRedPart", 255)[0] green = QgsProject.instance().readNumEntry("Gui", "/CanvasColorGreenPart", 255)[0] blue = QgsProject.instance().readNumEntry("Gui", "/CanvasColorBluePart", 255)[0] color = QColor(red, green, blue) self.canvas.setCanvasColor(color) self.canvas.updateScale() self.canvas.freeze(False) return self.canvas.mapRenderer().destinationCrs() def showEvent(self, *args, **kwargs): if QGis.QGIS_VERSION_INT == 20200 and self.firstshow: self.canvas.refresh() self.canvas.repaint() self.firstshow = False def feature_form_loaded(self, form, feature, *args): self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): self.clear_selection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0)) band.setIconSize(25) band.setWidth(5) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) band.setZValue(self.currentfeatureband.zValue() - 1) for feature in features: band.addGeometry(feature.geometry(), layer) self.canvas.update() def highlight_active_selection(self, layer, feature, features): self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) self.canvas.update() def clear_selection(self): # Clear the main selection rubber band self.canvas.scene().update() self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.canvas.update() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() self.canvas.mapTool().setEditMode(True, feature.geometry()) break self.editfeaturestack.append((form, feature)) self.load_form(form) trigger_default_action() def clear_temp_objects(self): def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging def set_gps(self, gps, logging): self.gps = gps self.gpslogging = logging self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) def gps_update_canvas(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.marker.show() self.marker.setCenter(position) self.marker.quality = gpsinfo.quality def gps_first_fix(self, postion, gpsinfo): zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def gps_disconnected(self): self.marker.hide() def select_data_entry(self): def showformerror(form): pass def actions(): for form in self.project.forms: if not self.form_valid_for_capture(form): continue action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format( form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form", wrap=5) formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): self.project = project self.actionPan.trigger() firstform = self.first_capture_form() if firstform: self.load_form(firstform) self.dataentryselection.setVisible(True) else: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.freeze(False) self.canvas.refresh() if self.scalebar_enabled: self.scalebar.update() self.actionPan.toggle() def setMapTool(self, tool, *args): if tool == self.canvas.mapTool(): return self.canvas.setMapTool(tool) def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24, 24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/select')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def form_valid_for_capture(self, form): if not form.has_geometry: extra = "No geometry information found for the layer {}. Layer might not have loaded correctly".format( form.layername) RoamEvents.raisemessage("Invalid form", "Form {} layer could not be loaded".format( form.name), level=1, extra=extra) return form.has_geometry and self.project.layer_can_capture( form.QGISLayer) def first_capture_form(self): for form in self.project.forms: if self.form_valid_for_capture(form): return form def load_form(self, form): self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) def feature_added(self, featureid): roam.utils.info("QGIS Added feature {}".format(featureid)) def create_capture_buttons(self, form): layer = form.QGISLayer layer.featureAdded.connect(self.feature_added) tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def add_new_feature(self, form, geometry): """ Add a new new feature to the given layer """ # TODO Extract into function. # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if layer.geometryType() in [ QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon ]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass feature = form.new_feature(geometry=geometry) RoamEvents.load_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) self.canvas.mapTool().setEditMode(False, None) def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return # Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def cleanup(self): self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clearCapatureTools() self.canvas.freeze() self.canvas.clear() self.canvas.freeze(False) for action in self.layerbuttons: self.editgroup.removeAction(action)
def __init__(self,parent): QToolBar.__init__(self,parent) self.parent = parent self.action_NewProject = QAction(Icons.newprj, 'Project', self) self.action_NewProject.triggered.connect(self.parent.treeWidget.newProject) self.action_NewProject.setToolTip("Create a New Project") self.action_Open = QAction(Icons.open, 'Open', self) self.action_Open.triggered.connect(self.parent.fileOpen) self.action_Open.setToolTip("Open File") self.action_Save = QAction(Icons.save, 'Save', self) self.action_Save.setShortcut('Ctrl+S') self.action_Save.triggered.connect(self.parent.fileSave) self.action_Save.setToolTip("Save Current File") self.action_SaveAll = QAction(Icons.saveall, 'SaveAll', self) self.action_SaveAll.setShortcut('Ctrl+A') self.action_SaveAll.triggered.connect(self.parent.fileSaveAll) self.action_SaveAll.setToolTip("Save All Files") self.action_Build = QAction(Icons.thread_view, 'Build', self) self.action_Build.setShortcut('Ctrl+B') self.action_Build.triggered.connect(self.parent.build_project) self.action_Debug = QAction(Icons.debug_exec, 'Debug', self) self.action_Refresh = QAction(Icons.refresh_tab, 'Refresh', self) self.action_Refresh.triggered.connect(self.parent.treeWidget.refreshCurrentProject) self.action_Run = QAction(Icons.run, 'Run', self) self.action_Run.setShortcut('Ctrl+R') self.action_Run.triggered.connect(self.parent.adb.run) self.action_RunFile = QAction(Icons.go, 'Cmd', self) self.action_RunFile.triggered.connect(self.parent.openCommand) self.parent.runButton.clicked.connect(self.parent.command.setCmdLine) self.action_Stop = QAction(Icons.stop, 'Stop', self) self.action_Stop.setShortcut('Ctrl+Q') self.action_Stop.triggered.connect(self.parent.adb.stop) self.action_Design = QAction(Icons.color_palette, 'Design', self) self.action_Design.triggered.connect(self.parent.design) self.action_Level = QAction(Icons.cmpC_pal, 'Level', self) self.action_Level.triggered.connect(self.parent.level) self.action_Todo = QAction(Icons.task_set, 'Todo', self) self.action_Todo.triggered.connect(self.parent.todo) self.action_Help = QAction(Icons.toc_open, 'Help', self) self.action_Help.triggered.connect(self.parent.help) men = QMenu() #Threshold Slider self.threshSlider = QSlider() self.threshSlider.setTickPosition(QSlider.TicksLeft) self.threshSlider.setOrientation(Qt.Horizontal) self.threshSlider.setValue(config.thresh()) self.threshSlider.setMinimum(0) self.threshSlider.setMaximum(5) self.threshSlider.valueChanged.connect(self.parent.setThreshold) self.threshSliderAction = QWidgetAction(men) self.threshSliderAction.setDefaultWidget(self.threshSlider) #TabsWidth Slider self.tabsSlider = QSlider() self.tabsSlider.setTickPosition(QSlider.TicksLeft) self.tabsSlider.setOrientation(Qt.Horizontal) self.tabsSlider.setValue(config.tabwidth()) self.tabsSlider.setMinimum(0) self.tabsSlider.setMaximum(8) self.tabsSlider.valueChanged.connect(self.parent.setTabWidth) self.tabsSliderAction = QWidgetAction(men) self.tabsSliderAction.setDefaultWidget(self.tabsSlider) #iconSize Slider self.iconSlider = QSlider() self.iconSlider.setTickPosition(QSlider.TicksLeft) self.iconSlider.setOrientation(Qt.Horizontal) self.iconSlider.setValue(config.iconSize()) self.iconSlider.setMinimum(16) self.iconSlider.setMaximum(32) self.iconSlider.setSingleStep(2) self.iconSlider.valueChanged.connect(self.setIcon) self.iconSliderAction = QWidgetAction(men) self.iconSliderAction.setDefaultWidget(self.iconSlider) '''Font Button''' self.fontCombo = QFontComboBox() self.fontCombo.currentFontChanged.connect(self.parent.setFont) self.fontCombo.setCurrentFont(QFont(config.fontName())) self.fontComboMenu = QWidgetAction(men) self.fontComboMenu.setDefaultWidget(self.fontCombo) '''Font Size''' self.fontSizeCombo = QComboBox() for size in range(1,40): self.fontSizeCombo.addItem(str(size)) self.fontSizeCombo.setCurrentIndex(config.fontSize()) self.fontSizeCombo.currentIndexChanged.connect(self.parent.setFontSize) self.fontSizeComboMenu = QWidgetAction(men) self.fontSizeComboMenu.setDefaultWidget(self.fontSizeCombo) action_explorer = QAction("Show Explorer",self) action_explorer.triggered.connect(self.parent.exp) action_console = QAction("Show Console",self) action_console.triggered.connect(self.parent.cmd) action_designer = QAction("Show Designer",self) action_designer.triggered.connect(self.parent.design) action_Indentation = QAction("Indentation Guides",self) action_Indentation.triggered.connect(self.parent.setIndent) action_WhiteSpace = QAction("Show WhiteSpace",self) action_WhiteSpace.triggered.connect(self.parent.setWhiteSpace) action_EndLine = QAction("Show End of Lines",self) action_EndLine.triggered.connect(self.parent.setEndLine) action_Margin = QAction("Line Numbers",self) action_Margin.triggered.connect(self.parent.setMargin) action_ToolLabel = QAction("Tool Labels",self) action_ToolLabel.triggered.connect(self.setToolLabel) action_Android = QAction(Icons.android,'Android', self) action_Android.triggered.connect(self.parent.android) action_Ant = QAction(Icons.ant_view,'Ant', self) action_Ant.triggered.connect(self.parent.antt) action_Squirrel = QAction(Icons.nut,'Squirrel', self) action_Squirrel.triggered.connect(self.parent.squirrel) action_Ios1 = QAction(Icons.ios,'iOS', self) action_Update = QAction("Update",self) action_Update.triggered.connect(self.parent.update) '''Encoding''' encodingGroup = QActionGroup(self) encodingGroup.setExclusive(True) action_Ascii = QAction("Ascii",encodingGroup) action_Ascii.setCheckable(True) action_Unicode = QAction("Unicode",encodingGroup) action_Unicode.setCheckable(True) encodingGroup.addAction(action_Ascii) encodingGroup.addAction(action_Unicode) encodingGroup.selected.connect(self.parent.setEncoding) if(config.encoding() == Encoding.ASCII): action_Ascii.setChecked(True) else: action_Unicode.setChecked(True) men.addAction(action_Android) men.addAction(action_Ant) men.addAction(action_Squirrel) men.addAction(action_Ios1) men.addAction(action_Update) men.addSeparator() men.addAction(action_explorer) men.addAction(action_console) men.addAction(action_designer) men.addAction(action_Indentation) men.addAction(action_WhiteSpace) men.addAction(action_EndLine) men.addAction(action_Margin) men.addAction(action_ToolLabel) men.addSeparator() men.addActions(encodingGroup.actions()) men.addSeparator() head_font = QLabel("Font---------------------") fnt = head_font.font() fnt.setBold(True) head_font.setFont(fnt) head_fontWidgetAction = QWidgetAction(men) head_fontWidgetAction.setDefaultWidget(head_font) men.addAction(head_fontWidgetAction) men.addAction(self.fontComboMenu) men.addAction(self.fontSizeComboMenu) men.addSeparator() men.addAction(QAction("TabWidth",self)) men.addAction(self.tabsSliderAction) men.addSeparator() men.addAction(QAction("Threshold",self)) men.addAction(self.threshSliderAction) #men.addAction(QAction("Icon Size",self)) #men.addAction(self.iconSliderAction) self.action_Options = QAction(Icons.emblem_system, 'Options', self) self.action_Options.setMenu(men) self.action_Full = QAction(Icons.fullscreen, 'Full', self) self.action_Full.setShortcut('Shift+Enter') self.action_Full.triggered.connect(self.parent.full) self.modeGroup = QActionGroup(self) self.modeGroup.setExclusive(True) self.modeGroup.selected.connect(self.parent.setMode) self.action_Squirrel = QAction(Icons.nut, 'Squ', self.modeGroup) self.action_Squirrel.setCheckable(True) self.action_Emo = QAction(Icons.emo, 'Emo', self.modeGroup) self.action_Emo.setCheckable(True) self.action_And = QAction(Icons.android, 'Android', self.modeGroup) self.action_And.setCheckable(True) self.action_Ios = QAction(Icons.ios, 'ios', self.modeGroup) self.action_Ios.setCheckable(True) self.modeGroup.addAction(self.action_Squirrel) self.modeGroup.addAction(self.action_Emo) self.modeGroup.addAction(self.action_And) self.modeGroup.addAction(self.action_Ios) self.action_Style = QAction(Icons.style, 'Style', self) men1 = QMenu() self.styleslist = [] self.style1 = QAction("All Hallow's Eve",self) self.style1.triggered.connect(lambda:self.parent.style_clicked(1)) self.style1.setCheckable(True) self.style2 = QAction("Amy",self) self.style2.triggered.connect(lambda:self.parent.style_clicked(2)) self.style2.setCheckable(True) self.style3 = QAction("Aptana Studio",self) self.style3.triggered.connect(lambda:self.parent.style_clicked(3)) self.style3.setCheckable(True) self.style4 = QAction("Bespin",self) self.style4.triggered.connect(lambda:self.parent.style_clicked(4)) self.style4.setCheckable(True) self.style5 = QAction("Blackboard",self) self.style5.triggered.connect(lambda:self.parent.style_clicked(5)) self.style5.setCheckable(True) self.style6 = QAction("Choco",self) self.style6.triggered.connect(lambda:self.parent.style_clicked(6)) self.style6.setCheckable(True) self.style7 = QAction("Cobalt",self) self.style7.triggered.connect(lambda:self.parent.style_clicked(7)) self.style7.setCheckable(True) self.style8 = QAction("Dawn",self) self.style8.triggered.connect(lambda:self.parent.style_clicked(8)) self.style8.setCheckable(True) self.style9 = QAction("Eclipse",self) self.style9.triggered.connect(lambda:self.parent.style_clicked(9)) self.style9.setCheckable(True) self.styleslist.append(self.style1) self.styleslist.append(self.style2) self.styleslist.append(self.style3) self.styleslist.append(self.style4) self.styleslist.append(self.style5) self.styleslist.append(self.style6) self.styleslist.append(self.style7) self.styleslist.append(self.style8) self.styleslist.append(self.style9) men1.addActions(self.styleslist) self.action_Style.setMenu(men1) self.styleslist[self.parent.styleIndex].setChecked(True) self.action_Stop.setDisabled(True) self.setToolLabel() self.setAllowedAreas(Qt.AllToolBarAreas) #self.setFixedHeight(40) #self.setIconSize(QSize(config.iconSize(),config.iconSize())) self.addAction(self.action_NewProject) self.addAction(self.action_Open) self.addAction(self.action_Save) self.addAction(self.action_SaveAll) #self.addAction(self.action_Refresh) self.addSeparator() self.addAction(self.action_Build) self.addAction(self.action_Run) self.addAction(self.action_RunFile) self.addAction(self.action_Stop) self.addAction(self.action_Debug) self.addSeparator() self.addAction(self.action_Design) self.addAction(self.action_Level) self.addAction(self.action_Todo) self.addAction(self.action_Options) self.addAction(self.action_Style) self.addSeparator() self.addAction(self.action_Help) self.addAction(self.action_Full) self.addSeparator() self.addActions(self.modeGroup.actions()) if(config.mode() == 0): self.action_Squirrel.setChecked(True) elif(config.mode() == 1): self.action_Emo.setChecked(True) elif(config.mode() == 2): self.action_And.setChecked(True) elif(config.mode() == 3): self.action_Ios.setChecked(True)
class MainWindow(QMainWindow, Ui_MainWindow): """The Main window of Luma. """ logger = logging.getLogger(__name__) languages = {} translator = None languageHandler = None currentLanguage = '' def __init__(self, parent=None): """The constructor sets up the MainWindow widget, and connects all necessary signals and slots """ super(MainWindow, self).__init__(parent) self.setupUi(self) # We store the window size to make sure the previous window size # is restored when leaving fullscreen mode. This varible is used # in the toggleFullscreen slot. self.__tmpWinSize = self.size() self.eventFilter = LumaEventFilter(self) self.mainTabs.installEventFilter(self.eventFilter) self.translator = QTranslator() self.languageHandler = LanguageHandler() self.languages = self.languageHandler.availableLanguages #self.__createPluginToolBar() self.__createLoggerWidget() self.__loadSettings() self.__createLanguageOptions() self.setStatusBar(self.statusBar) self.mainTabs.setTabsClosable(True) self.mainTabs.setContextMenuPolicy(Qt.CustomContextMenu) self.mainTabs.customContextMenuRequested.connect( self.__mainTabsContextMenu) self.defaultTabStyle = '' self.lumaHeadStyle = 'background: url(:/icons/luma-gray);\n' + \ 'background-position: bottom right;\n' + \ 'background-attachment: fixed;\n' + \ 'background-repeat: no-repeat;' #Sets up pluginWidget #self in parameter is used to call pluginSelected here... self.pluginWidget = PluginListWidget(self) self.showPlugins() self.welcomeTab = WelcomeTab() self.welcomeTab.textBrowser.setStyleSheet(self.lumaHeadStyle) #This value comes from __loadSettings() #Its a checkbox set in WelcomeTab if self.showWelcomeSettings == 2: self.showWelcome() else: # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) self.actionShowWelcomeTab.setEnabled(True) self.serversChangedMessage = QErrorMessage(self) def __mainTabsContextMenu(self, pos): menu = QMenu() if self.mainTabs.count() > 0: return # The menu is displayed even when the rightclick is not # done over the actual tabs so to avoid confusion the # function is disabled entirey #menu.addAction(QApplication.translate( # "MainWindow", "Close all plugin-tabs"), self.tabCloseAll) else: # If there's no tabs, offer to display the pluginlist menu.addAction(self.actionShowPluginList) menu.exec_(self.mainTabs.mapToGlobal(pos)) def __createPluginToolBar(self): """Creates the pluign toolbar. """ self.pluginToolBar = PluginToolBar(self) self.pluginToolBar.setWindowTitle(QApplication.translate( 'MainWindow', 'Plugintoolbar', None, QApplication.UnicodeUTF8)) self.pluginToolBar.setObjectName('pluginToolBar') self.addToolBar(self.pluginToolBar) self.pluginToolBar.hide() def __createLoggerWidget(self): """Creates the logger widget. """ self.loggerDockWindow = QDockWidget(self) self.loggerDockWindow.setObjectName('loggerDockWindow') self.loggerDockWindow.visibilityChanged[bool].connect( self.actionShowLogger.setChecked) self.loggerDockWindow.setWindowTitle(QApplication.translate( 'MainWindow', 'Logger', None, QApplication.UnicodeUTF8)) self.loggerWidget = LoggerWidget(self.loggerDockWindow) self.loggerDockWindow.setWidget(self.loggerWidget) self.addDockWidget(Qt.BottomDockWidgetArea, self.loggerDockWindow) self.loggerDockWindow.hide() def __createLanguageOptions(self): """Creates the language selection in the menubar. """ self.langGroup = QActionGroup(self) self.langGroup.setExclusive(True) self.langGroup.triggered['QAction*'].connect(self.languageChanged) for key, name in self.languages.iteritems(): action = QAction(self) action.setCheckable(True) action.setData(key) action.setText(name[0]) action.setStatusTip(name[1]) action.setActionGroup(self.langGroup) self.menuLanguage.addAction(action) if key == self.currentLanguage: action.setChecked(True) def __loadSettings(self, mainWin=True): """Loads settings from file. :param mainWin: If set to ``False``, neither the values for the window size or the window position will be loaded. This is i.e done when the settings dialog returns 1. :type mainWin: bool """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. if mainWin: self.restoreGeometry(settings.geometry) #self.restoreState(settings.state) # If the geometry saved inticates fullscreen mode, # we need to explicitly set the fullscreen menuaction checkbox if self.isFullScreen(): self.actionFullscreen.setChecked(True) # Logger # Logger # The `allwaysShowLoggerOnStart` a precedence on the # `showLogger` value. if settings.showLoggerOnStart: self.actionShowLogger.setChecked(True) else: self.actionShowLogger.setChecked(settings.showLogger) self.loggerWidget.errorBox.setChecked(settings.showErrors) self.loggerWidget.debugBox.setChecked(settings.showDebug) self.loggerWidget.infoBox.setChecked(settings.showInfo) self.toggleLoggerWindow(self.actionShowLogger.isChecked()) # Language self.loadLanguage(settings.language) #Tabs self.showWelcomeSettings = settings.value("showWelcome", 2).toInt()[0] def __writeSettings(self): """Save settings to file. """ settings = Settings() # We might want to use these methods to restore the # application state and geometry. settings.geometry = self.saveGeometry() #settings.state = self.saveState() # Mainwin #max = self.isMaximized() #settings.maximize = max #if not max: # settings.size = self.size() # settings.position = self.pos() # The global logger settings is managed from the settings dialog. # Logger settings.showLogger = self.actionShowLogger.isChecked() settings.showErrors = self.loggerWidget.errorBox.isChecked() settings.showDebug = self.loggerWidget.debugBox.isChecked() settings.showInfo = self.loggerWidget.infoBox.isChecked() # Language settings.language = self.currentLanguage def __switchTranslator(self, translator, qmFile): """Called when a new language is loaded. :param translator: The translator object to install. :type translator: QTranslator :qmFile: The translation file for the loaded language. :type qmFile: string """ qApp.removeTranslator(translator) if translator.load(qmFile): qApp.installTranslator(translator) def __setTabWidgetStyle(self, stylesheet): self.mainTabs.setStyleSheet(stylesheet) @pyqtSlot('QAction*') @pyqtSlot(int) def languageChanged(self, value): """This slot is called by actions and signals related to application translations. The slot contains validation for those parameters defined by the pyqtSlot meta info in the method header. :param value: Can be either a ``QAction`` or an integer value. I.e. menu actions provide ``QActions`` but a ``QCombobox`` might send it's index. :type value: QAction/int """ locale = None if isinstance(value, int): locale = self.languageSelector.itemData(value).toString() elif isinstance(value, QAction): locale = value.data().toString() #else: # locale = value if locale: self.loadLanguage(locale) def loadLanguage(self, locale): """Loads a language by the given language iso code. :param locale: A twoletter lowercase ISO 639 language code and possibly a twoletter uppercase ISO 3166 country code separeted by a underscore. :type locale: string """ if self.currentLanguage != locale: self.currentLanguage = locale qmFile = self.languageHandler.getQmFile(locale) self.__switchTranslator(self.translator, qmFile) def changeEvent(self, event): """This event is called when a new translator is loaded or the system language (locale) is changed. :param event: The event that generated the `changeEvent`. :type event: QEvent """ if None != event: type = event.type() if QEvent.LanguageChange == type or QEvent.LocaleChange == type: self.retranslateUi(self) self.loggerWidget.retranslateUi(self.loggerWidget) def showAboutLuma(self): """Slot for displaying the about dialog. """ AboutDialog().exec_() @pyqtSlot(bool) def toggleLoggerWindow(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the logger window should be shown or not. :type show: bool """ if show: self.loggerDockWindow.show() else: self.loggerDockWindow.hide() @pyqtSlot(bool) def toggleStatusbar(self, show): """Slot for toggling the logger window. :param show: a boolean value indicating whether the statusbar should be shown or not. :type show: bool """ if show: self.statusBar.show() else: self.statusBar.hide() @pyqtSlot(bool) def toggleFullscreen(self, fullscreen): """Slot for toggling the logger window. :param fullscreen: a boolean value indicating whether to enter fullscreenmode or not. :type fullcreen: bool """ if fullscreen: self.__tmpWinSize = self.size() self.showFullScreen() else: self.showNormal() self.resize(self.__tmpWinSize) def showServerEditor(self): """Slot to display the server editor dialog. """ serverEditor = ServerDialog() r = serverEditor.exec_() if r: #TODO -- only display if plugins open: self.serversChangedMessage.showMessage(QApplication.translate( "MainWindow", "You may need to restart plugins for changes to take effect.")) def showTempPasswordDialog(self): """ Sets overridePassword for a server. Using this one doesn't actually have to enter the password in the ServerDialog (and by extension save to disk). """ serverList = ServerList() # Create a stringlist to be used by the qinputdialog stringList = [] for server in serverList.getTable(): stringList.append(server.name) # Display list of servers (serverString, ok) = QInputDialog.getItem( self, QApplication.translate("MainWindow", "Select server"), QApplication.translate("MainWindow", "Server:"), stringList, editable=False ) if ok: server = serverList.getServerObjectByName(serverString) if server != None: # Ask for password (value, ok) = QInputDialog.getText( self, QApplication.translate("MainWindow", "Temporary password"), QApplication.translate("MainWindow", "Enter password:"******"""Slot to display the settings dialog. If the settings dialog returns 1, i.e. the user has clicked the ok button, the loadSettings method is called with mainWin=False, to load the (assumed) newly changed settings. :param tab: The index of the tab to display in the settings dialog. :type tab: int """ #settingsDialog = SettingsDialog(self.currentLanguage, self.languages) settingsDialog = SettingsDialog() if tab < 0: tab = 0 settingsDialog.tabWidget.setCurrentIndex(tab) if settingsDialog.exec_(): self.reloadPlugins() # # We assume that some settings is changed # # if the user clicked the ok button, and # # reloads the application settings # self.__loadSettings(mainWin=False) # # A Hack but it'll do for now # for a in self.langGroup.actions(): # if a.data().toString() == self.currentLanguage: # a.setChecked(True) def configurePlugins(self): """Slot to display the plugins configuration. This currently calls `showSettingsDialog` with tab index set to 2. """ self.showSettingsDialog(1) def reloadPlugins(self): """Slot to reload plugins. """ self.pluginWidget.updatePlugins() def pluginSelected(self, item): """This method will be called from the `PluginListWidget`. """ # Clear the stylesheet when a tab is opened self.__setTabWidgetStyle(self.defaultTabStyle) widget = item.plugin.getPluginWidget(None, self) if platform.system() == "Windows": scroll = QScrollArea() scroll.setWidget(widget) scroll.setWidgetResizable(True) index = self.mainTabs.addTab( scroll, item.icon(), item.plugin.pluginUserString) else: index = self.mainTabs.addTab( widget, item.icon(), item.plugin.pluginUserString) self.mainTabs.setCurrentIndex(index) def tabClose(self, index): """Slot for the signal `tabCloseRequest(int)` for the tabMains. """ widget = self.mainTabs.widget(index) # If the tab closed is one of these, enable the toggle-action if widget == self.pluginWidget: self.actionShowPluginList.setEnabled(True) if widget == self.welcomeTab: self.actionShowWelcomeTab.setEnabled(True) self.mainTabs.removeTab(index) # Unparent the widget since it was reparented by the QTabWidget # so it's garbage collected widget.setParent(None) # In case the widget contained circular references # -- force GC to take care of the objects since there can be # quite many if it was BrowserWidget that was closed. # Can't call it directly since that'll be too soon QTimer.singleShot(1000, self.gc) # Let's do some styling of the tab widget when no tabs are opened if self.mainTabs.currentIndex() == -1: self.__setTabWidgetStyle(self.lumaHeadStyle) def gc(self): """Runs Python's garbage-collection manually. Used to make sure circular references are taken care of *now*. """ gc.collect() def showWelcome(self): """Shows the Welcome-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) index = self.mainTabs.addTab(self.welcomeTab, QApplication.translate("MainWindow", "Welcome")) self.mainTabs.setCurrentIndex(index) self.actionShowWelcomeTab.setEnabled(False) def showPlugins(self): """Will show the pluginlistwidget-tab """ self.__setTabWidgetStyle(self.defaultTabStyle) if self.mainTabs.indexOf(self.pluginWidget) == -1: index = self.mainTabs.addTab( self.pluginWidget, QApplication.translate( "MainWindow", "Plugins")) self.mainTabs.setCurrentIndex(index) self.actionShowPluginList.setEnabled(False) def closeEvent(self, e): """Overrides the ``QMainWindow.closeEvent`` slot to save settings before we tear down the application. """ self.__writeSettings() QMainWindow.closeEvent(self, e)
def __init__(self, parent=None, paths=None): QDialog.__init__(self, parent) QShortcut(QKeySequence("Escape"), self, self.reject) self.setWindowTitle("editR - Help Browser") self.resize(500, 500) self._paths = paths self._port = robjects.r('tools:::httpdPort')[0] if not self._port > 0: robjects.r('tools::startDynamicHelp()') self._port = robjects.r('tools:::httpdPort')[0] self._host = "localhost" self._help = True # by default we don't search, we call help self.tabs = QTabWidget(self) self.tabs.setDocumentMode(True) self.tabs.setTabsClosable(True) self.help_open("/doc/html/Search.html") home_button = QToolButton(self) home_action = QAction("&Home", self) home_action.setToolTip("Return to start page") home_action.setWhatsThis("Return to start page") home_action.setIcon(QIcon(":go-home")) home_button.setDefaultAction(home_action) home_button.setAutoRaise(True) backward_button = QToolButton(self) backward_action = QAction("&Back", self) backward_action.setToolTip("Move to previous page") backward_action.setWhatsThis("Move to previous page") backward_action.setIcon(QIcon(":go-previous")) backward_button.setDefaultAction(backward_action) backward_button.setAutoRaise(True) forward_button = QToolButton(self) forward_action = QAction("&Forward", self) forward_action.setToolTip("Move to next page") forward_action.setWhatsThis("Move to next page") forward_action.setIcon(QIcon(":go-next")) forward_button.setDefaultAction(forward_action) forward_button.setAutoRaise(True) self.search_edit = QLineEdit(self) self.search_edit.setStyleSheet(_fromUtf8( "QLineEdit{" "padding-right: 16px;" "padding-left: 5px;" "background: url(:edit-find-small.png);" "background-position: right;" "background-repeat: no-repeat;" "border: 1px solid grey;" "border-radius: 6.5px;}")) self.setFocusProxy(self.search_edit) self.search_edit.setFocus(True) self.options_tool = QToolButton(self) self.options_tool.setAutoRaise(True) self.options_tool.setIcon(QIcon(":preferences-system.svg")) self.options_tool.setPopupMode(QToolButton.InstantPopup) # create popup menu menu = QMenu("Help options") group = QActionGroup(menu) help_action = QAction(QIcon(":help-contents.svg"), "Help", menu) help_action.setCheckable(True) help_action.setChecked(True) search_action = QAction(QIcon(":edit-find.svg"), "Search", menu) search_action.setCheckable(True) group.addAction(help_action) group.addAction(search_action) group.setExclusive(True) menu.addAction(help_action) menu.addAction(search_action) menu.addSeparator() options = ["Titles","Keywords","Object names","Concepts","Exact match"] for i in range(len(options)): action = QAction(options[i], menu) action.setCheckable(True) action.setChecked(i<3) menu.addAction(action) self.options_tool.setMenu(menu) # create connections home_action.triggered.connect(self.home) forward_action.triggered.connect(self.forward) backward_action.triggered.connect(self.backward) self.search_edit.returnPressed.connect(self.enter_pressed) self.tabs.tabCloseRequested.connect(self.help_close) hbox = QHBoxLayout() # hbox.addStretch() hbox.addWidget(backward_button) hbox.addWidget(home_button) hbox.addWidget(forward_button) # hbox.addStretch() hbox.addWidget(self.search_edit) hbox.addWidget(self.options_tool) vbox = QVBoxLayout(self) vbox.addLayout(hbox) vbox.addWidget(self.tabs)
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) icon = roam_style.iconsize() self.projecttoolbar.setIconSize(QSize(icon, icon)) self.firstshow = True self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.bridge = QgsLayerTreeMapCanvasBridge(QgsProject.instance().layerTreeRoot(), self.canvas) self.bridge.setAutoSetupOnFirstLayer(False) QgsProject.instance().writeProject.connect(self.bridge.writeProject) QgsProject.instance().readProject.connect(self.bridge.readProject) # self.canvas.setInteractive(False) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.snapping = SnappingUtils(self.canvas, self) self.canvas.setSnappingUtils(self.snapping) QgsProject.instance().readProject.connect(self.snapping.readConfigFromProject) if hasattr(self.canvas, 'setParallelRenderingEnabled'): threadcount = QThread.idealThreadCount() threadcount = 2 if threadcount > 2 else 1 QgsApplication.setMaxThreads(threadcount) self.canvas.setParallelRenderingEnabled(True) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) if roam.config.settings.get('north_arrow', False): self.northarrow = NorthArrow(":/icons/north", self.canvas) self.northarrow.setPos(10, 10) self.canvas.scene().addItem(self.northarrow) self.scalebar_enabled = roam.config.settings.get('scale_bar', False) if self.scalebar_enabled: self.scalebar = ScaleBarItem(self.canvas) self.canvas.scene().addItem(self.scalebar) self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu) gpsspacewidget = QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.marker = GPSMarker(self.canvas) self.marker.hide() self.currentfeatureband = CurrentSelection(self.canvas) self.currentfeatureband.setIconSize(30) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 50)) self.currentfeatureband.setOutlineColour(QColor(186, 93, 212)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(165, 111, 212, 75)) self.gpsband.setWidth(5) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.openfeatureform.connect(self.feature_form_loaded) RoamEvents.sync_complete.connect(self.refresh_map) RoamEvents.snappingChanged.connect(self.snapping_changed) self.snappingbutton = QToolButton() self.snappingbutton.setText("Snapping: On") self.snappingbutton.setAutoRaise(True) self.snappingbutton.pressed.connect(self.toggle_snapping) spacer = QWidget() spacer2 = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.scalewidget = QgsScaleComboBox() self.scalebutton = QToolButton() self.scalebutton.setAutoRaise(True) self.scalebutton.setMaximumHeight(self.statusbar.height()) self.scalebutton.pressed.connect(self.selectscale) self.scalebutton.setText("Scale") self.scalelist = BigList(parent=self.canvas, centeronparent=True, showsave=False) self.scalelist.hide() self.scalelist.setlabel("Map Scale") self.scalelist.setmodel(self.scalewidget.model()) self.scalelist.closewidget.connect(self.scalelist.close) self.scalelist.itemselected.connect(self.update_scale_from_item) self.scalelist.itemselected.connect(self.scalelist.close) self.positionlabel = QLabel('') self.gpslabel = QLabel("GPS: Not active") self.statusbar.addWidget(self.snappingbutton) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.statusbar.addPermanentWidget(self.scalebutton) self.canvas.extentsChanged.connect(self.updatestatuslabel) self.canvas.scaleChanged.connect(self.updatestatuslabel) GPS.gpsposition.connect(self.update_gps_label) GPS.gpsdisconnected.connect(self.gps_disconnected) self.connectButtons() def clear_plugins(self): toolbars = self.findChildren(QToolBar) for toolbar in toolbars: if toolbar.property("plugin_toolbar"): self.removeToolBar(toolbar) toolbar.deleteLater() def add_plugins(self, pluginnames): for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'toolbars'): roam.utils.warning("No toolbars() function found in {}".format(name)) continue toolbars = plugin_mod.toolbars() self.load_plugin_toolbars(toolbars) def load_plugin_toolbars(self, toolbars): for ToolBarClass in toolbars: toolbar = ToolBarClass(plugins.api, self) self.addToolBar(Qt.BottomToolBarArea, toolbar) toolbar.setProperty("plugin_toolbar", True) def snapping_changed(self, snapping): """ Called when the snapping settings have changed. Updates the label in the status bar. :param snapping: """ if snapping: self.snappingbutton.setText("Snapping: On") else: self.snappingbutton.setText("Snapping: Off") def toggle_snapping(self): """ Toggle snapping on or off. """ snap = not snapping global snapping snapping = snap RoamEvents.snappingChanged.emit(snapping) def selectscale(self): """ Show the select scale widget. :return: """ self.scalelist.show() def update_scale_from_item(self, index): """ Update the canvas scale from the selected scale item. :param index: The index of the selected item. """ scale, _ = self.scalewidget.toDouble(index.data(Qt.DisplayRole)) self.canvas.zoomScale(1.0 / scale) def update_gps_label(self, position, gpsinfo): """ Update the GPS label in the status bar with the GPS status. :param position: The current GPS position. :param gpsinfo: The current extra GPS information. """ self.gpslabel.setText("GPS: PDOP {0:.2f} HDOP {1:.2f} VDOP {2:.2f}".format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) def gps_disconnected(self): """ Called when the GPS is disconnected. Updates the label in the status bar with the message. :return: """ self.gpslabel.setText("GPS Not Active") def updatestatuslabel(self, *args): """ Update the status bar labels when the information has changed. """ extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) scale = 1.0 / self.canvas.scale() scale = self.scalewidget.toString(scale) self.scalebutton.setText(scale) def refresh_map(self): """ Refresh the map """ self.canvas.refresh() def updatescale(self): """ Update the scale of the map with the current scale from the scale widget :return: """ self.canvas.zoomScale(1.0 / self.scalewidget.scale()) def init_qgisproject(self, doc): """ Called when the project file is read for the firs time. :param doc: The XML doc. :return: The current canvas CRS :note: This method is old and needs to be refactored into something else. """ return self.canvas.mapSettings().destinationCrs() def showEvent(self, *args, **kwargs): """ Handle the show event of the of the map widget. We have to do a little hack here to make the QGIS map refresh. """ if QGis.QGIS_VERSION_INT == 20200 and self.firstshow: self.canvas.refresh() self.canvas.repaint() self.firstshow = False def feature_form_loaded(self, form, feature, *args): """ Called when the feature form is loaded. :param form: The Form object. Holds a reference to the forms layer. :param feature: The current capture feature """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): """ Highlight the selection on the canvas. This updates all selected objects based on the result set. :param results: A dict-of-list of layer-features. """ self.clear_selection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0)) band.setIconSize(25) band.setWidth(5) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) band.setZValue(self.currentfeatureband.zValue() - 1) for feature in features: band.addGeometry(feature.geometry(), layer) self.canvas.update() def highlight_active_selection(self, layer, feature, features): """ Update the current active selected feature. :param layer: The layer of the active feature. :param feature: The active feature. :param features: The other features in the set to show as non active selection. :return: """ self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) self.canvas.update() def clear_selection(self): """ Clear the selection from the canvas. Resets all selection rubbber bands. :return: """ # Clear the main selection rubber band self.canvas.scene().update() self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.canvas.update() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): """ Push a feature on the edit stack so the feature can have the geometry edited. :note: This is a big hack and I don't like it! :param form: The form for the current feature :param feature: The active feature. """ def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() self.canvas.mapTool().setEditMode(True, feature.geometry()) break self.editfeaturestack.append((form, feature)) self.load_form(form) trigger_default_action() def clear_temp_objects(self): """ Clear all temp objects from the canvas. :return: """ def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): """ Called when the settings have been updated in the Roam config. :param settings: A dict of the settings. """ self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging def set_gps(self, gps, logging): """ Set the GPS for the map widget. Connects GPS signals """ self.gps = gps self.gpslogging = logging self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) def gps_update_canvas(self, position, gpsinfo): """ Updates the map canvas based on the GPS position. By default if the GPS is outside the canvas extent the canvas will move to center on the GPS. Can be turned off in settings. :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.marker.show() self.marker.setCenter(position, gpsinfo) def gps_first_fix(self, postion, gpsinfo): """ Called the first time the GPS gets a fix. If set this will zoom to the GPS after the first fix :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): """ Zoom to ta given position on the map.. """ rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def gps_disconnected(self): """ Called when the GPS is disconnected """ self.marker.hide() def select_data_entry(self): """ Open the form selection widget to allow the user to pick the active capture form. """ def showformerror(form): pass def actions(): for form in self.project.forms: if not self.form_valid_for_capture(form): continue action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format(form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form", wrap=5) formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): """ Called when the project is loaded. Main entry point for a loade project. :param project: The Roam project that has been loaded. """ self.project = project self.actionPan.trigger() firstform = self.first_capture_form() if firstform: self.load_form(firstform) self.dataentryselection.setVisible(True) else: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.refresh() projectscales, _ = QgsProject.instance().readBoolEntry("Scales", "/useProjectScales") if projectscales: projectscales, _ = QgsProject.instance().readListEntry("Scales", "/ScalesList") self.scalewidget.updateScales(projectscales) else: scales = ["1:50000", "1:25000", "1:10000", "1:5000", "1:2500", "1:1000", "1:500", "1:250", "1:200", "1:100"] scales = roam.config.settings.get('scales', scales) self.scalewidget.updateScales(scales) if self.scalebar_enabled: self.scalebar.update() self.actionPan.toggle() self.clear_plugins() self.add_plugins(project.enabled_plugins) def setMapTool(self, tool, *args): """ Set the active map tool in the canvas. :param tool: The QgsMapTool to set. """ if tool == self.canvas.mapTool(): return if hasattr(tool, "setSnapping"): tool.setSnapping(snapping) self.canvas.setMapTool(tool) def connectButtons(self): """ Connect the default buttons in the interface. Zoom, pan, etc """ def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24, 24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/select')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def form_valid_for_capture(self, form): """ Check if the given form is valid for capture. :param form: The form to check. :return: True if valid form for capture """ return form.has_geometry and self.project.layer_can_capture(form.QGISLayer) def first_capture_form(self): """ Return the first valid form for capture. """ for form in self.project.forms: if self.form_valid_for_capture(form): return form def load_form(self, form): """ Load the given form so it's the active one for capture :param form: The form to load """ self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) def create_capture_buttons(self, form): """ Create the capture buttons in the toolbar for the given form. :param form: The active form. """ layer = form.QGISLayer tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def add_new_feature(self, form, geometry): """ Add a new new feature to the given layer """ # TODO Extract into function. # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass feature = form.new_feature(geometry=geometry) RoamEvents.load_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) self.canvas.mapTool().setEditMode(False, None) def clearCapatureTools(self): """ Clear the capture tools from the toolbar. :return: True if the capture button was active at the time of clearing. """ captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ # Freeze the canvas to save on UI refresh self.canvas.freeze() tree = QgsProject.instance().layerTreeRoot() for node in tree.findLayers(): if node.layer().type() == QgsMapLayer.RasterLayer: if node.isVisible() == Qt.Checked: state = Qt.Unchecked else: state = Qt.Checked node.setVisible(state) self.canvas.freeze(False) self.canvas.refresh() def cleanup(self): """ Clean up when the project has changed. :return: """ self.bridge.clear() self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clearCapatureTools() self.canvas.freeze() self.canvas.clear() self.canvas.freeze(False) for action in self.layerbuttons: self.editgroup.removeAction(action)
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.canvaslayers = [] self.layerbuttons = [] self.project = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionLegend.triggered.connect(self.updatelegend) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel("User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.gpslabel = createlabel("GPS: Not active") self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer2 = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.connectButtons() self.currentfeatureband = QgsRubberBand(self.canvas) self.currentfeatureband.setIconSize(20) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 76)) self.canvas_page.layout().insertWidget(0, self.projecttoolbar) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.selectdataentry) self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.selectioncleared.connect(self.clearselection) RoamEvents.editgeometry.connect(self.addforedit) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.highlightselection) RoamEvents.selectionchanged.connect(self.showInfoResults) GPS.gpspostion.connect(self.updatecanvasfromgps) GPS.firstfix.connect(self.gpsfirstfix) GPS.gpsdisconnected.connect(self.gpsdisconnected) self.lastgpsposition = None self.marker = GPSMarker(self.canvas) self.marker.hide() self.legendpage.showmap.connect(self.showmap) self.editfeaturestack = [] self.currentselection = {} def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def addforedit(self, form, feature): self.editfeaturestack.append((form, feature)) self.loadform(form) actions = self.getcaptureactions() for action in actions: if action.isdefault: action.trigger() break def updatelegend(self): self.legendpage.updatecanvas(self.canvas) def gpsfirstfix(self, postion, gpsinfo): zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) def updatecanvasfromgps(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.canvas.setExtent(rect) self.canvas.refresh() self.marker.show() self.marker.setCenter(position) self.gpslabel.setText("GPS: PDOP {} HDOP {} VDOP {}".format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) def gpsdisconnected(self): self.marker.hide() self.gpslabel.setText("GPS Not Active") def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return if sys.platform == 'win32': try: programfiles = os.environ['ProgramW6432'] except KeyError: programfiles = os.environ['ProgramFiles'] cmd = r'{path}\Common Files\Microsoft Shared\ink\TabTip.exe'.format(path=programfiles) try: os.startfile(cmd) except WindowsError: roam.config.settings['keyboard'] = False roam.config.save() else: cmd = 'onboard' Popen(cmd) def selectdataentry(self): forms = self.project.forms formpicker = PickActionDialog(msg="Select data entry form") for form in forms: action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format(form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(self.showformerror, form)) else: action.triggered.connect(partial(self.loadform, form)) formpicker.addAction(action) formpicker.exec_() def showformerror(self, form): pass def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def settingsupdated(self, settings): self.show() self.actionGPS.updateGPSPort() def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = self.currentselection[layer] # Update any features that have changed. for updatedfeature in updated: oldfeatures = [f for f in selectedfeatures if f.id() == updatedfeature.id()] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightselection(self, results): self.clearselection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 200)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def clearselection(self): # Clear the main selection rubber band self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.editfeaturestack = [] def highlightfeature(self, layer, feature, features): self.clearselection() self.highlightselection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def dataentrychanged(self, index): self.clearCapatureTools() if not index.isValid(): return modelindex = index # modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) self.dataentryselection.setCurrentIndex(index.row()) self.createCaptureButtons(form) def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError(QApplication.translate('MainWindowPy','Seems something has gone wrong. Press for more details', None, QApplication.UnicodeUTF8), info) def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit) self.actionHome.triggered.connect(self.homeview) self.actionQuit.triggered.connect(self.exit) def getcaptureactions(self): for action in self.projecttoolbar.actions(): if action.property('dataentry'): yield action def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def createCaptureButtons(self, form): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.addNewFeature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def loadform(self, form): self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.createCaptureButtons(form) def clearToolRubberBand(self): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self, layer, featureid): self.dataentryfinished() self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.currentfeatureband.reset() self.clearToolRubberBand() def formrejected(self, message, level): self.dataentryfinished() if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) self.cleartempobjects() def openForm(self, form, feature, editmode): """ Open the form that is assigned to the layer """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) self.showdataentry() self.dataentrywidget.openform(feature=feature, form=form, project=self.project, editmode=editmode) def editfeaturegeometry(self, form, feature, newgeometry): layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() RoamEvents.editgeometry_complete.emit(form, feature) def addNewFeature(self, form, geometry): """ Add a new new feature to the given layer """ layer = form.QGISLayer if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value self.openForm(form, feature, editmode=False) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms) self.infodock.show() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0]; #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0]; #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0]; #color = QColor(red, green, blue); #self.canvas.setCanvasColor(color) self.canvas.updateScale() self.projectOpened() self.canvas.freeze(False) self.canvas.refresh() GPS.crs = self.canvas.mapRenderer().destinationCrs() self.showmap() @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) try: firstform = self.project.forms[0] self.loadform(self.project.forms[0]) self.dataentryselection.setVisible(True) except IndexError: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) self.infoTool.selectionlayers = self.project.selectlayersmapping() layers = self.project.legendlayersmapping().values() self.legendpage.updateitems(layers) self.actionPan.trigger() #noinspection PyArgumentList @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.closeProject() self.canvas.refresh() self.canvas.repaint() RoamEvents.selectioncleared.emit() # 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.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def closeProject(self): """ Close the current open project """ self.clearCapatureTools() self.canvas.freeze() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.clear() self.canvas.freeze(False) for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons for action in self.layerbuttons: self.editgroup.removeAction(action) self.panels = [] self.project = None self.dataentrywidget.clear() self.hidedataentry() self.infodock.close()
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self, roamapp): super(MainWindow, self).__init__() self.setupUi(self) import roam self.projectwidget.project_base = roamapp.projectsroot QgsApplication.instance().setStyleSheet(roam.roam_style.appstyle()) self.menutoolbar.setStyleSheet(roam.roam_style.menubarstyle()) icon = roam.roam_style.iconsize() self.menutoolbar.setIconSize(QSize(icon, icon)) self.projectupdater = ProjectUpdater(projects_base=roamapp.projectsroot) self.projectupdater.foundProjects.connect(self.projectwidget.show_new_updateable) self.projectupdater.projectUpdateStatus.connect(self.projectwidget.update_project_status) self.projectupdater.projectInstalled.connect(self.projectwidget.project_installed) self.projectwidget.search_for_updates.connect(self.search_for_projects) self.projectwidget.projectUpdate.connect(self.projectupdater.update_project) self.projectwidget.projectInstall.connect(self.projectupdater.install_project) self.project = None self.tracking = GPSLogging(GPS) self.canvas_page.set_gps(GPS, self.tracking) self.canvas = self.canvas_page.canvas # self.canvas_page.projecttoolbar.stateChanged.connect(self.menutoolbar.setSmallMode) # self.menutoolbar.stateChanged.connect(self.canvas_page.projecttoolbar.setSmallMode) roam.defaults.canvas = self.canvas self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.projectbuttons = [] self.pluginactions = [] self.actionQuit.triggered.connect(self.exit) self.actionLegend.triggered.connect(self.updatelegend) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.gpswidget.settracking(self.tracking) self.settings = {} self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas) self.dataentrywidget.lastwidgetremoved.connect(self.dataentryfinished) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) RoamEvents.featuresaved.connect(self.featureSaved) RoamEvents.helprequest.connect(self.showhelp) # RoamEvents.deletefeature.connect(self.delete_feature) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.spaceraction = self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.showInfoResults) RoamEvents.show_widget.connect(self.dataentrywidget.add_widget) RoamEvents.closeProject.connect(self.close_project) self.legendpage.showmap.connect(self.showmap) self.currentselection = {} iface = RoamInterface(RoamEvents, GPS, self, self.canvas_page) plugins.api = iface def set_projectbuttons(self, visible): for action in self.projectbuttons: action.setVisible(visible) def loadpages(self, pages): def safe_connect(method, to): try: method.connect(to) except AttributeError: pass for PageClass in pages: action = QAction(self.menutoolbar) text = PageClass.title.ljust(13) action.setIconText(text) action.setIcon(QIcon(PageClass.icon)) action.setCheckable(True) if PageClass.projectpage: action.setVisible(False) self.projectbuttons.append(action) self.menutoolbar.insertAction(self.spaceraction, action) else: self.menutoolbar.insertAction(self.actionProject, action) pagewidget = PageClass(plugins.api, self) safe_connect(RoamEvents.selectionchanged, pagewidget.selection_changed) safe_connect(RoamEvents.projectloaded, pagewidget.project_loaded) pageindex = self.stackedWidget.insertWidget(-1, pagewidget) action.setProperty('page', pageindex) self.pluginactions.append(action) self.menuGroup.addAction(action) def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def updatelegend(self): self.legendpage.updatecanvas(self.canvas) def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return roam.api.utils.open_keyboard() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def delete_featue(self, form, feature): """ Delete the selected feature """ # We have to make the feature form because the user might have setup logic # to handle the delete case featureform = form.create_featureform(feature) try: msg = featureform.deletemessage except AttributeError: msg = 'Do you really want to delete this feature?' if not DeleteFeatureDialog(msg).exec_(): return try: featureform.delete() except DeleteFeatureException as ex: RoamEvents.raisemessage(*ex.error) featureform.featuredeleted(feature) # TODO Fix undo delete stuff # self.show_undo("Feature deleted", "Undo Delete", form, feature) def show_undo(self, title, message, form, feature): item = roam.messagebaritems.UndoMessageItem(title, message, form, feature) item.undo.connect(self.undo_delete) self.bar.pushItem(item) def undo_delete(self, form, feature): # Add the feature back to the layer self.bar.popWidget() layer = form.QGISLayer layer.startEditing() layer.addFeature(feature) layer.commitChanges() def search_for_projects(self): server = roam.config.settings.get('updateserver', '') self.projectupdater.update_server(server, self.projects) def settingsupdated(self, settings): self.settings = settings self.show() self.canvas_page.settings_updated(settings) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) def handle_removed_features(self, layer, layerid, deleted_feature_ids): self.canvas.refresh() self.reloadselection(layer, deleted=deleted_feature_ids) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = [] for selection_layer, features in self.currentselection.iteritems(): if layer.name() == selection_layer.name(): selectedfeatures = features layer = selection_layer break if not selectedfeatures: return # Update any features that have changed. for updatedfeature in updated: oldfeatures = [f for f in selectedfeatures if f.id() == updatedfeature.id()] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightfeature(self, layer, feature, features): self.canvas_page.highlight_active_selection(layer, feature, features) RoamEvents.activeselectionchanged.emit(layer, feature, features) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def raiseerror(self, *exinfo): import errors info = self.bar.pushError(*exinfo) errors.send_exception(exinfo) def showhelp(self, parent, url): help = HelpPage(parent) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuresdeleted(self, layerid, featureids): layer = QgsMapLayerRegistry.instance().mapLayer(layerid) self.reloadselection(layer, deleted=featureids) self.canvas.refresh() def featureSaved(self, *args): #self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def cleartempobjects(self): self.canvas_page.clear_temp_objects() def formrejected(self, message, level): if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) def openForm(self, form, feature, editmode, *args): """ Open the form that is assigned to the layer """ self.showdataentry() self.dataentrywidget.load_feature_form(feature, form, editmode, *args) def editfeaturegeometry(self, form, feature, newgeometry): layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() RoamEvents.editgeometry_complete.emit(form, feature) def exit(self): """ Exit the application. """ self.projectupdater.quit() self.close() def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms, self.project) self.infodock.show() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projects = projects self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) self.search_for_projects() def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ crs = self.canvas_page.init_qgisproject(doc) self.projectOpened() GPS.crs = crs text = "This is a extra bit of info \n but just as a notice" @property def enabled_plugins(self): return self.settings.get('plugins', []) @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) self.clear_plugins() self.add_plugins(self.project.enabled_plugins) layers = self.project.legendlayersmapping().values() self.legendpage.updateitems(layers) gps_loglayer = self.project.gpslog_layer() if gps_loglayer: self.tracking.enable_logging_on(gps_loglayer) else: roam.utils.info("No gps_log found for GPS logging") self.tracking.clear_logging() for layer in roam.api.utils.layers(): if not layer.type() == QgsMapLayer.VectorLayer: continue layer.committedFeaturesRemoved.connect(partial(self.handle_removed_features, layer)) self.canvas_page.project_loaded(self.project) self.showmap() self.set_projectbuttons(True) self.dataentrywidget.project = self.project RoamEvents.projectloaded.emit(self.project) def clear_plugins(self): self.projectbuttons = [] self.projectbuttons.append(self.actionMap) self.projectbuttons.append(self.actionLegend) for action in self.pluginactions: # Remove the page widget, because we make it on each load widget = self.stackedWidget.widget(action.property("page")) self.stackedWidget.removeWidget(widget) if widget: widget.deleteLater() self.menutoolbar.removeAction(action) self.pluginactions = [] def add_plugins(self, pluginnames): for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'pages'): roam.utils.warning("No pages() function found in {}".format(name)) continue pages = plugin_mod.pages() self.loadpages(pages) @roam.utils.timeit def loadProject(self, project): """ Load a project into the application. """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.close_project() # 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) # Project loading screen self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def close_project(self, project=None): """ Close the current open project """ if not project is None and not project == self.project: return RoamEvents.projectClosing.emit() self.tracking.clear_logging() self.dataentrywidget.clear() self.canvas_page.cleanup() QgsMapLayerRegistry.instance().removeAllMapLayers() for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons self.panels = [] oldproject = self.project self.project = None self.set_projectbuttons(False) self.hidedataentry() self.infodock.close() RoamEvents.selectioncleared.emit() RoamEvents.projectClosed.emit(oldproject) self.projectwidget.set_open_project(None)
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.menutoolbar.setStyleSheet(roam.roam_style.menubarstyle) self.project = None self.tracking = GPSLogging(GPS) self.canvas_page.set_gps(GPS, self.tracking) self.canvas = self.canvas_page.canvas roam.defaults.canvas = self.canvas self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionImport) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.projectbuttons = [] self.pluginactions = [] self.actionQuit.triggered.connect(self.exit) self.actionHelp.triggered.connect(self.showhelp2) self.actionLegend.triggered.connect(self.updatelegend) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.gpswidget.settracking(self.tracking) self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.dataentrywidget.lastwidgetremoved.connect(self.dataentryfinished) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) RoamEvents.featuresaved.connect(self.featureSaved) RoamEvents.helprequest.connect(self.showhelp) self.actionProject.triggered.connect(self.closeAnnotation) self.pHelp=os.getcwd() help_p = "help\IntraMaps Roam - Help.pdf" self.pathHelp=os.path.join(self.pHelp,help_p) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel("User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.gpslabel = createlabel("GPS: Not active") self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer2 = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.spaceraction = self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) self.annotationdock=AnnotationDock(self.canvas) self.annotationdock.hide() self.layerlist=LayerList(self.canvas) self.layerlist.hide() RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.showInfoResults) RoamEvents.show_widget.connect(self.dataentrywidget.add_widget) RoamEvents.closeProject.connect(self.close_project) RoamEvents.showAnnotationUi.connect(self.showAnnotationDock) RoamEvents.showLayerListUi.connect(self.showLayerList) GPS.gpsposition.connect(self.update_gps_label) GPS.gpsdisconnected.connect(self.gps_disconnected) self.legendpage.showmap.connect(self.showmap) self.currentselection = {} def showAnnotationDock(self): self.annotationdock.show() def showLayerList(self,canvaslayers): self.layerlist.show(canvaslayers) def closeAnnotation(self): RoamEvents.closeAnnotation.emit() RoamEvents.DestroyLayerList.emit() def set_projectbuttons(self, visible): for action in self.projectbuttons: action.setVisible(visible) def loadpages(self, pages): def safe_connect(method, to): try: method.connect(to) except AttributeError: pass for PageClass in pages: action = QAction(self.menutoolbar) text = PageClass.title.ljust(13) action.setIconText(text) action.setIcon(QIcon(PageClass.icon)) action.setCheckable(True) if PageClass.projectpage: action.setVisible(False) self.projectbuttons.append(action) self.menutoolbar.insertAction(self.spaceraction, action) else: self.menutoolbar.insertAction(self.actionProject, action) iface = RoamInterface(RoamEvents, GPS, self) pagewidget = PageClass(iface, self) safe_connect(RoamEvents.selectionchanged, pagewidget.selection_changed) safe_connect(RoamEvents.projectloaded, pagewidget.project_loaded) pageindex = self.stackedWidget.insertWidget(-1, pagewidget) action.setProperty('page', pageindex) self.pluginactions.append(action) self.menuGroup.addAction(action) def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def updatelegend(self): layers = self.project.legendlayersmapping().values() self.legendpage.show(layers) #self.legendpage.updatecanvas(self.canvas) def update_gps_label(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area self.gpslabel.setText("GPS: PDOP {} HDOP {} VDOP {}".format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) def gps_disconnected(self): self.gpslabel.setText("GPS Not Active") def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return roam.api.utils.open_keyboard() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def settingsupdated(self, settings): self.show() self.canvas_page.settings_updated(settings) def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) def handle_removed_features(self, layer, layerid, deleted_feature_ids): self.canvas.refresh() self.reloadselection(layer, deleted=deleted_feature_ids) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = [] for selection_layer, features in self.currentselection.iteritems(): if layer.name() == selection_layer.name(): selectedfeatures = features layer = selection_layer break if not selectedfeatures: return # Update any features that have changed. for updatedfeature in updated: oldfeatures = [f for f in selectedfeatures if f.id() == updatedfeature.id()] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightfeature(self, layer, feature, features): self.canvas_page.highlight_active_selection(layer, feature, features) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError(QApplication.translate('MainWindowPy','Seems something has gone wrong. Press for more details', None, QApplication.UnicodeUTF8), info) def showhelp(self, parent, url): help = HelpPage(parent) help.setHelpPage(url) help.show() def showhelp2(self): """ def showHTMLReport(title, html, data={}, parent=None): dialog = HtmlViewerDialog(title) dialog.showHTML(html, data) dialog.exec_() showHTMLReport("Help",contentHelp)""" QDesktopServices.openUrl(QUrl.fromLocalFile(self.pathHelp)) def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuresdeleted(self, layerid, featureids): layer = QgsMapLayerRegistry.instance().mapLayer(layerid) self.reloadselection(layer, deleted=featureids) self.canvas.refresh() def featureSaved(self, *args): #self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def cleartempobjects(self): self.canvas_page.clear_temp_objects() def formrejected(self, message, level): if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) def openForm(self, form, feature, editmode, *args): """ Open the form that is assigned to the layer """ self.showdataentry() self.dataentrywidget.load_feature_form(feature, form, editmode, *args) def editfeaturegeometry(self, form, feature, newgeometry): layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() RoamEvents.editgeometry_complete.emit(form, feature) def addNewFeature(self, form, geometry): """ Add a new new feature to the given layer """ layer = form.QGISLayer if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]: geometry.convertToMultiType() try: # TODO: This is a gross hack. We need to move this out into a edit tool with better control. form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass feature = form.new_feature(set_defaults=True) feature.setGeometry(geometry) self.openForm(form, feature, editmode=False) def exit(self): """ Exit the application. """ self.close() def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms, self.project) self.infodock.show() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ crs = self.canvas_page.init_qgisproject(doc) projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) proj=str(self.project.folder) dbpath = proj + "/_data/annotation.sqlite" self.findAnnotationLayer(proj,dbpath) self.projectOpened() GPS.crs = crs def findAnnotationLayer(self, project_path, dbpath): flag=0 if os.path.isfile(dbpath) == False: alert("DB Annotation non trovato, Annotation Tool disattivata") flag=1 elif os.path.isfile(dbpath) == True: layerid=["point20150114085613922","line20150114085613640","polygon20150114085614076"] layer = QgsMapLayerRegistry.instance() for x in layerid: if layer.mapLayer(x)==None: alert ("Uno o piu' layer Annotation non presente, Annotation Tool disattivata") flag=1 break self.CheckAnno(flag) def CheckAnno(self,flag): if flag == 1: RoamEvents.setAnnoDisabled.emit() elif flag == 0: RoamEvents.setAnnoEnabled.emit() @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) self.clear_plugins() self.add_plugins(self.project.enabled_plugins) layers = self.project.legendlayersmapping().values() #self.legendpage.updateitems(layers) gps_loglayer = self.project.gpslog_layer() if gps_loglayer: self.tracking.enable_logging_on(gps_loglayer) else: roam.utils.info("No gps_log found for GPS logging") self.tracking.clear_logging() for layer in roam.api.utils.layers(): if not layer.type() == QgsMapLayer.VectorLayer: continue layer.committedFeaturesRemoved.connect(partial(self.handle_removed_features, layer)) self.canvas_page.project_loaded(self.project) self.showmap() self.set_projectbuttons(True) RoamEvents.projectloaded.emit(self.project) def clear_plugins(self): self.projectbuttons = [] self.projectbuttons.append(self.actionMap) self.projectbuttons.append(self.actionLegend) for action in self.pluginactions: # Remove the page widget, because we make it on each load widget = self.stackedWidget.widget(action.property("page")) self.stackedWidget.removeWidget(widget) widget.deleteLater() self.menutoolbar.removeAction(action) self.pluginactions = [] def add_plugins(self, pluginnames): for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'pages'): roam.utils.warning("No pages() function found in {}".format(name)) continue pages = plugin_mod.pages() self.loadpages(pages) @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.close_project() # 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) # Project loading screen self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def close_project(self, project=None): """ Close the current open project """ if not project is None and not project == self.project: return self.tracking.clear_logging() self.dataentrywidget.clear() self.canvas_page.cleanup() QgsMapLayerRegistry.instance().removeAllMapLayers() for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons self.panels = [] oldproject = self.project self.project = None self.set_projectbuttons(False) self.hidedataentry() self.infodock.close() RoamEvents.selectioncleared.emit() RoamEvents.projectClosed.emit(oldproject) self.projectwidget.set_open_project(None) def closeEvent(self, event): RoamEvents.DestroyLayerList.emit()
class InterfaceTab(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) vbox = QVBoxLayout(self) self._parent = parent self.toolbar_settings = settings.TOOLBAR_ITEMS groupBoxExplorer = QGroupBox(self.tr("Explorer Panel:")) groupBoxGui = QGroupBox(self.tr("GUI Customization:")) groupBoxToolbar = QGroupBox(self.tr("Tool Bar Customization:")) groupBoxLang = QGroupBox(self.tr("Language:")) #Explorer vboxExplorer = QVBoxLayout(groupBoxExplorer) self._checkProjectExplorer = QCheckBox( self.tr("Show Project Explorer.")) self._checkSymbols = QCheckBox(self.tr("Show Symbols List.")) self._checkWebInspetor = QCheckBox(self.tr("Show Web Inspector.")) self._checkFileErrors = QCheckBox(self.tr("Show File Errors.")) vboxExplorer.addWidget(self._checkProjectExplorer) vboxExplorer.addWidget(self._checkSymbols) vboxExplorer.addWidget(self._checkWebInspetor) vboxExplorer.addWidget(self._checkFileErrors) #GUI self._btnCentralRotate = QPushButton( QIcon(resources.IMAGES['splitCPosition']), '') self._btnCentralRotate.setIconSize(QSize(64, 64)) self._btnCentralRotate.setCheckable(True) self._btnPanelsRotate = QPushButton( QIcon(resources.IMAGES['splitMPosition']), '') self._btnPanelsRotate.setIconSize(QSize(64, 64)) self._btnPanelsRotate.setCheckable(True) self._btnCentralOrientation = QPushButton( QIcon(resources.IMAGES['splitCRotate']), '') self._btnCentralOrientation.setIconSize(QSize(64, 64)) self._btnCentralOrientation.setCheckable(True) gridGuiConfig = QGridLayout(groupBoxGui) gridGuiConfig.addWidget(self._btnCentralRotate, 0, 0) gridGuiConfig.addWidget(self._btnPanelsRotate, 0, 1) gridGuiConfig.addWidget(self._btnCentralOrientation, 0, 2) gridGuiConfig.addWidget(QLabel( self.tr("Rotate Central")), 1, 0, Qt.AlignCenter) gridGuiConfig.addWidget(QLabel( self.tr("Rotate Lateral")), 1, 1, Qt.AlignCenter) gridGuiConfig.addWidget(QLabel( self.tr("Central Orientation")), 1, 2, Qt.AlignCenter) #GUI - Toolbar vbox_toolbar = QVBoxLayout(groupBoxToolbar) hbox_select_items = QHBoxLayout() label_toolbar = QLabel(self.tr("Toolbar Items:")) label_toolbar.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hbox_select_items.addWidget(label_toolbar) self._comboToolbarItems = QComboBox() self._load_combo_data(self._comboToolbarItems) self._btnItemAdd = QPushButton( QIcon(resources.IMAGES['add']), '') self._btnItemAdd.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self._btnItemRemove = QPushButton( QIcon(resources.IMAGES['delete']), '') self._btnDefaultItems = QPushButton(self.tr("Default Items")) self._btnDefaultItems.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self._btnItemRemove.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) hbox_select_items.addWidget(self._comboToolbarItems) hbox_select_items.addWidget(self._btnItemAdd) hbox_select_items.addWidget(self._btnItemRemove) hbox_select_items.addWidget(self._btnDefaultItems) vbox_toolbar.addLayout(hbox_select_items) self._toolbar_items = QToolBar() self._toolbar_items.setToolButtonStyle(Qt.ToolButtonIconOnly) styles.set_style(self._toolbar_items, 'toolbar-customization') self._load_toolbar() vbox_toolbar.addWidget(self._toolbar_items) vbox_toolbar.addWidget(QLabel( self.tr("The New Item will be inserted after the item selected."))) #Language vboxLanguage = QVBoxLayout(groupBoxLang) vboxLanguage.addWidget(QLabel(self.tr("Select Language:"))) self._comboLang = QComboBox() self._comboLang.setEnabled(False) vboxLanguage.addWidget(self._comboLang) vboxLanguage.addWidget(QLabel(self.tr('Requires restart...'))) #Load Languages # self.thread = ThreadLangs() # self.connect(self.thread, SIGNAL("finished()"), self.load_langs) # self.thread.start() self._load_langs() # until the thread is working #Settings self._checkProjectExplorer.setChecked( settings.SHOW_PROJECT_EXPLORER) self._checkSymbols.setChecked(settings.SHOW_SYMBOLS_LIST) self._checkWebInspetor.setChecked(settings.SHOW_WEB_INSPECTOR) self._checkFileErrors.setChecked(settings.SHOW_ERRORS_LIST) #ui layout self._btnCentralRotate.setChecked(bin(settings.UI_LAYOUT)[-1] == '1') self._btnPanelsRotate.setChecked(bin( settings.UI_LAYOUT >> 1)[-1] == '1') self._btnCentralOrientation.setChecked( bin(settings.UI_LAYOUT >> 2)[-1] == '1') vbox.addWidget(groupBoxExplorer) vbox.addWidget(groupBoxGui) vbox.addWidget(groupBoxToolbar) vbox.addWidget(groupBoxLang) #Signals self.connect(self._btnCentralRotate, SIGNAL('clicked()'), central_widget.CentralWidget().splitter_central_rotate) self.connect(self._btnPanelsRotate, SIGNAL('clicked()'), central_widget.CentralWidget().splitter_misc_rotate) self.connect(self._btnCentralOrientation, SIGNAL('clicked()'), central_widget.CentralWidget().splitter_central_orientation) self.connect(self._btnItemAdd, SIGNAL("clicked()"), self.toolbar_item_added) self.connect(self._btnItemRemove, SIGNAL("clicked()"), self.toolbar_item_removed) self.connect(self._btnDefaultItems, SIGNAL("clicked()"), self.toolbar_items_default) def toolbar_item_added(self): data = self._comboToolbarItems.itemData( self._comboToolbarItems.currentIndex()) data = str(data.toString()) if data not in self.toolbar_settings or data == 'separator': selected = self.actionGroup.checkedAction() if selected is None: self.toolbar_settings.append(data) else: dataAction = str(selected.data().toString()) self.toolbar_settings.insert( self.toolbar_settings.index(dataAction) + 1, data) self._load_toolbar() def toolbar_item_removed(self): data = self._comboToolbarItems.itemData( self._comboToolbarItems.currentIndex()) data = str(data.toString()) if data in self.toolbar_settings and data != 'separator': self.toolbar_settings.pop(self.toolbar_settings.index(data)) self._load_toolbar() elif data == 'separator': self.toolbar_settings.reverse() self.toolbar_settings.pop(self.toolbar_settings.index(data)) self.toolbar_settings.reverse() self._load_toolbar() def toolbar_items_default(self): self.toolbar_settings = settings.TOOLBAR_ITEMS_DEFAULT self._load_toolbar() def _load_combo_data(self, combo): self.toolbar_items = { 'separator': [QIcon(resources.IMAGES['separator']), 'Add Separtor'], 'new-file': [QIcon(resources.IMAGES['new']), 'New File'], 'new-project': [QIcon(resources.IMAGES['newProj']), 'New Project'], 'save-file': [QIcon(resources.IMAGES['save']), 'Save File'], 'save-as': [QIcon(resources.IMAGES['saveAs']), 'Save As'], 'save-all': [QIcon(resources.IMAGES['saveAll']), 'Save All'], 'save-project': [QIcon(resources.IMAGES['saveAll']), 'Save Project'], 'reload-file': [QIcon(resources.IMAGES['reload-file']), 'Reload File'], 'open-file': [QIcon(resources.IMAGES['open']), 'Open File'], 'open-project': [QIcon(resources.IMAGES['openProj']), 'Open Project'], 'activate-profile': [QIcon(resources.IMAGES['activate-profile']), 'Activate Profile'], 'deactivate-profile': [QIcon(resources.IMAGES['deactivate-profile']), 'Deactivate Profile'], 'print-file': [QIcon(resources.IMAGES['print']), 'Print File'], 'close-file': [self.style().standardIcon(QStyle.SP_DialogCloseButton), 'Close File'], 'close-projects': [self.style().standardIcon(QStyle.SP_DialogCloseButton), 'Close Projects'], 'undo': [QIcon(resources.IMAGES['undo']), 'Undo'], 'redo': [QIcon(resources.IMAGES['redo']), 'Redo'], 'cut': [QIcon(resources.IMAGES['cut']), 'Cut'], 'copy': [QIcon(resources.IMAGES['copy']), 'Copy'], 'paste': [QIcon(resources.IMAGES['paste']), 'Paste'], 'find': [QIcon(resources.IMAGES['find']), 'Find'], 'find-replace': [QIcon(resources.IMAGES['findReplace']), 'Find/Replace'], 'find-files': [QIcon(resources.IMAGES['find']), 'Find In files'], 'code-locator': [QIcon(resources.IMAGES['locator']), 'Code Locator'], 'splith': [QIcon(resources.IMAGES['splitH']), 'Split Horizontally'], 'splitv': [QIcon(resources.IMAGES['splitV']), 'Split Vertically'], 'follow-mode': [QIcon(resources.IMAGES['follow']), 'Follow Mode'], 'zoom-in': [QIcon(resources.IMAGES['zoom-in']), 'Zoom In'], 'zoom-out': [QIcon(resources.IMAGES['zoom-out']), 'Zoom Out'], 'indent-more': [QIcon(resources.IMAGES['indent-more']), 'Indent More'], 'indent-less': [QIcon(resources.IMAGES['indent-less']), 'Indent Less'], 'comment': [QIcon(resources.IMAGES['comment-code']), 'Comment'], 'uncomment': [QIcon(resources.IMAGES['uncomment-code']), 'Uncomment'], 'go-to-definition': [QIcon(resources.IMAGES['go-to-definition']), 'Go To Definition'], 'insert-import': [QIcon(resources.IMAGES['insert-import']), 'Insert Import'], 'run-project': [QIcon(resources.IMAGES['play']), 'Run Project'], 'run-file': [QIcon(resources.IMAGES['file-run']), 'Run File'], 'stop': [QIcon(resources.IMAGES['stop']), 'Stop'], 'preview-web': [QIcon(resources.IMAGES['preview-web']), 'Preview Web']} for item in self.toolbar_items: combo.addItem(self.toolbar_items[item][0], self.toolbar_items[item][1], item) combo.model().sort(0) def _load_toolbar(self): self._toolbar_items.clear() self.actionGroup = QActionGroup(self) self.actionGroup.setExclusive(True) for item in self.toolbar_settings: if item == 'separator': self._toolbar_items.addSeparator() else: action = self._toolbar_items.addAction( self.toolbar_items[item][0], self.toolbar_items[item][1]) action.setData(item) action.setCheckable(True) self.actionGroup.addAction(action) def _load_langs(self): # self.disconnect(self.thread, SIGNAL("finished()"), self.load_langs) self._langs = file_manager.get_files_from_folder( resources.LANGS, '.qm') self._langs = ['english'] + \ [file_manager.get_module_name(lang) for lang in self._langs] # if not self.thread.langs.keys() and len(self.langs) > 1: # self.comboLang.addItems(self.langs) # else: # self.comboLang.addItems(['english'] + self.thread.langs.keys()) if(self._comboLang.count() > 1): self._comboLang.setEnabled(True) index = self._comboLang.findText(settings.LANGUAGE) self._comboLang.setCurrentIndex(index) def save(self): settings.TOOLBAR_ITEMS = self.toolbar_settings lang = self._comboLang.currentText() if lang not in self._langs: #TODO # self.parent().overlay.show() # core.download_lang(self.thread.langs[str(lang)]) pass lang = unicode(lang) self._parent.overlay.hide() qsettings = QSettings() qsettings.beginGroup('preferences') qsettings.beginGroup('interface') qsettings.setValue('showProjectExplorer', self._checkProjectExplorer.isChecked()) settings.SHOW_PROJECT_EXPLORER = self._checkProjectExplorer.isChecked() if settings.SHOW_PROJECT_EXPLORER: explorer_container.ExplorerContainer().add_tab_projects() else: explorer_container.ExplorerContainer().remove_tab_projects() qsettings.setValue('showSymbolsList', self._checkSymbols.isChecked()) settings.SHOW_SYMBOLS_LIST = self._checkSymbols.isChecked() if settings.SHOW_SYMBOLS_LIST: explorer_container.ExplorerContainer().add_tab_symbols() else: explorer_container.ExplorerContainer().remove_tab_symbols() qsettings.setValue('showWebInspector', self._checkWebInspetor.isChecked()) settings.SHOW_WEB_INSPECTOR = self._checkWebInspetor.isChecked() if settings.SHOW_WEB_INSPECTOR: explorer_container.ExplorerContainer().add_tab_inspector() else: explorer_container.ExplorerContainer().remove_tab_inspector() qsettings.setValue('showErrorsList', self._checkFileErrors.isChecked()) settings.SHOW_ERRORS_LIST = self._checkFileErrors.isChecked() if settings.SHOW_ERRORS_LIST: explorer_container.ExplorerContainer().add_tab_errors() else: explorer_container.ExplorerContainer().remove_tab_errors() #ui layout uiLayout = 1 if self._btnCentralRotate.isChecked() else 0 uiLayout += 2 if self._btnPanelsRotate.isChecked() else 0 uiLayout += 4 if self._btnCentralOrientation.isChecked() else 0 qsettings.setValue('uiLayout', uiLayout) qsettings.setValue('toolbar', settings.TOOLBAR_ITEMS) qsettings.setValue('language', lang) lang = unicode(lang + '.qm') settings.LANGUAGE = os.path.join(resources.LANGS, lang) qsettings.endGroup() qsettings.endGroup() actions.Actions().reload_toolbar()
class MainWindow(QMainWindow, Ui_MainWindow): """docstring for MainWindow.""" def __init__(self, parent=None): super(MainWindow, self).__init__() self._csvFilePath = "" self.serialport = serial.Serial() self.receiver_thread = readerThread(self) self.receiver_thread.setPort(self.serialport) self._localEcho = None self.setupUi(self) self.setCorner(Qt.TopLeftCorner, Qt.LeftDockWidgetArea) self.setCorner(Qt.BottomLeftCorner, Qt.LeftDockWidgetArea) font = QtGui.QFont() font.setFamily(EDITOR_FONT) font.setPointSize(10) self.txtEdtOutput.setFont(font) self.txtEdtInput.setFont(font) self.quickSendTable.setFont(font) if UI_FONT is not None: font = QtGui.QFont() font.setFamily(UI_FONT) font.setPointSize(9) self.dockWidget_PortConfig.setFont(font) self.dockWidget_SendHex.setFont(font) self.dockWidget_QuickSend.setFont(font) self.setupFlatUi() self.onEnumPorts() icon = QtGui.QIcon(":/icon.ico") self.setWindowIcon(icon) self.actionAbout.setIcon(icon) icon = QtGui.QIcon(":/qt_logo_16.ico") self.actionAbout_Qt.setIcon(icon) self._viewGroup = QActionGroup(self) self._viewGroup.addAction(self.actionAscii) self._viewGroup.addAction(self.actionHex_lowercase) self._viewGroup.addAction(self.actionHEX_UPPERCASE) self._viewGroup.setExclusive(True) # bind events self.actionOpen_Cmd_File.triggered.connect(self.openCSV) self.actionSave_Log.triggered.connect(self.onSaveLog) self.actionExit.triggered.connect(self.onExit) self.actionOpen.triggered.connect(self.openPort) self.actionClose.triggered.connect(self.closePort) self.actionPort_Config_Panel.triggered.connect(self.onTogglePrtCfgPnl) self.actionQuick_Send_Panel.triggered.connect(self.onToggleQckSndPnl) self.actionSend_Hex_Panel.triggered.connect(self.onToggleHexPnl) self.dockWidget_PortConfig.visibilityChanged.connect(self.onVisiblePrtCfgPnl) self.dockWidget_QuickSend.visibilityChanged.connect(self.onVisibleQckSndPnl) self.dockWidget_SendHex.visibilityChanged.connect(self.onVisibleHexPnl) self.actionLocal_Echo.triggered.connect(self.onLocalEcho) self.actionAlways_On_Top.triggered.connect(self.onAlwaysOnTop) self.actionAscii.triggered.connect(self.onViewChanged) self.actionHex_lowercase.triggered.connect(self.onViewChanged) self.actionHEX_UPPERCASE.triggered.connect(self.onViewChanged) self.actionAbout.triggered.connect(self.onAbout) self.actionAbout_Qt.triggered.connect(self.onAboutQt) self.btnOpen.clicked.connect(self.onOpen) self.btnClear.clicked.connect(self.onClear) self.btnSaveLog.clicked.connect(self.onSaveLog) self.btnEnumPorts.clicked.connect(self.onEnumPorts) self.btnSendHex.clicked.connect(self.sendHex) self.receiver_thread.read.connect(self.receive) self.receiver_thread.exception.connect(self.readerExcept) self._signalMap = QSignalMapper(self) self._signalMap.mapped[int].connect(self.tableClick) # initial action self.actionHEX_UPPERCASE.setChecked(True) self.receiver_thread.setViewMode(VIEWMODE_HEX_UPPERCASE) self.initQuickSend() self.restoreLayout() self.moveScreenCenter() self.syncMenu() if self.isMaximized(): self.setMaximizeButton("restore") else: self.setMaximizeButton("maximize") self.LoadSettings() def setupFlatUi(self): self._dragPos = self.pos() self._isDragging = False self.setMouseTracking(True) self.setWindowFlags(Qt.FramelessWindowHint) self.setStyleSheet(""" QWidget { background-color:#99d9ea; /*background-image: url(:/background.png);*/ outline: 1px solid #0057ff; } QLabel { color:#202020; font-size:13px; font-family:Century; } QComboBox { color:#202020; font-size:13px; font-family:Century Schoolbook; } QComboBox { border: none; padding: 1px 18px 1px 3px; } QComboBox:editable { background: white; } QComboBox:!editable, QComboBox::drop-down:editable { background: #62c7e0; } QComboBox:!editable:hover, QComboBox::drop-down:editable:hover { background: #c7eaf3; } QComboBox:!editable:pressed, QComboBox::drop-down:editable:pressed { background: #35b6d7; } QComboBox:on { padding-top: 3px; padding-left: 4px; } QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 16px; border: none; } QComboBox::down-arrow { image: url(:/downarrow.png); } QComboBox::down-arrow:on { image: url(:/uparrow.png); } QGroupBox { color:#202020; font-size:12px; font-family:Century Schoolbook; border: 1px solid gray; margin-top: 15px; } QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left:5px; top:3px; } QCheckBox { color:#202020; spacing: 5px; font-size:12px; font-family:Century Schoolbook; } QCheckBox::indicator:unchecked { image: url(:/checkbox_unchecked.png); } QCheckBox::indicator:unchecked:hover { image: url(:/checkbox_unchecked_hover.png); } QCheckBox::indicator:unchecked:pressed { image: url(:/checkbox_unchecked_pressed.png); } QCheckBox::indicator:checked { image: url(:/checkbox_checked.png); } QCheckBox::indicator:checked:hover { image: url(:/checkbox_checked_hover.png); } QCheckBox::indicator:checked:pressed { image: url(:/checkbox_checked_pressed.png); } QScrollBar:horizontal { background-color:#99d9ea; border: none; height: 15px; margin: 0px 20px 0 20px; } QScrollBar::handle:horizontal { background: #61b9e1; min-width: 20px; } QScrollBar::add-line:horizontal { image: url(:/rightarrow.png); border: none; background: #7ecfe4; width: 20px; subcontrol-position: right; subcontrol-origin: margin; } QScrollBar::sub-line:horizontal { image: url(:/leftarrow.png); border: none; background: #7ecfe4; width: 20px; subcontrol-position: left; subcontrol-origin: margin; } QScrollBar:vertical { background-color:#99d9ea; border: none; width: 15px; margin: 20px 0px 20px 0px; } QScrollBar::handle::vertical { background: #61b9e1; min-height: 20px; } QScrollBar::add-line::vertical { image: url(:/downarrow.png); border: none; background: #7ecfe4; height: 20px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line::vertical { image: url(:/uparrow.png); border: none; background: #7ecfe4; height: 20px; subcontrol-position: top; subcontrol-origin: margin; } QTableView { background-color: white; /*selection-background-color: #FF92BB;*/ border: 1px solid #eeeeee; color: #2f2f2f; } QTableView::focus { /*border: 1px solid #2a7fff;*/ } QTableView QTableCornerButton::section { border: none; border-right: 1px solid #eeeeee; border-bottom: 1px solid #eeeeee; background-color: #8ae6d2; } QTableView QWidget { background-color: white; } QTableView::item:focus { border: 1px red; background-color: transparent; color: #2f2f2f; } QHeaderView::section { border: none; border-right: 1px solid #eeeeee; border-bottom: 1px solid #eeeeee; padding-left: 2px; padding-right: 2px; color: #444444; background-color: #8ae6d2; } QTextEdit { background-color:white; color:#2f2f2f; border: 1px solid white; } QTextEdit::focus { border: 1px solid #2a7fff; } QPushButton { background-color:#30a7b8; border:none; color:#ffffff; font-size:14px; font-family:Century Schoolbook; } QPushButton:hover { background-color:#51c0d1; } QPushButton:pressed { background-color:#3a9ecc; } QMenuBar { color: #2f2f2f; } QMenuBar::item { background-color: transparent; margin: 8px 0px 0px 0px; padding: 1px 8px 1px 8px; height: 15px; } QMenuBar::item:selected { background: #51c0d1; } QMenuBar::item:pressed { } QMenu { color: #2f2f2f; } QMenu { margin: 2px; } QMenu::item { padding: 2px 25px 2px 21px; border: 1px solid transparent; } QMenu::item:selected { background: #51c0d1; } QMenu::icon { background: transparent; border: 2px inset transparent; } QDockWidget { font-size:13px; font-family:Century; color: #202020; titlebar-close-icon: none; titlebar-normal-icon: none; } QDockWidget::title { margin: 0; padding: 2px; subcontrol-origin: content; subcontrol-position: right top; text-align: left; background: #67baed; } QDockWidget::float-button { max-width: 12px; max-height: 12px; background-color:transparent; border:none; image: url(:/restore_inactive.png); } QDockWidget::float-button:hover { background-color:#227582; image: url(:/restore_active.png); } QDockWidget::float-button:pressed { padding: 0; background-color:#14464e; image: url(:/restore_active.png); } QDockWidget::close-button { max-width: 12px; max-height: 12px; background-color:transparent; border:none; image: url(:/close_inactive.png); } QDockWidget::close-button:hover { background-color:#ea5e00; image: url(:/close_active.png); } QDockWidget::close-button:pressed { background-color:#994005; image: url(:/close_active.png); padding: 0; } """) self.dockWidgetContents.setStyleSheet(""" QPushButton { min-height:23px; } """) self.dockWidget_QuickSend.setStyleSheet(""" QPushButton { background-color:#27b798; font-family:Consolas; font-size:12px; min-width:46px; } QPushButton:hover { background-color:#3bd5b4; } QPushButton:pressed { background-color:#1d8770; } """) self.dockWidgetContents_2.setStyleSheet(""" QPushButton { min-height:23px; min-width:50px; } """) w = self.frameGeometry().width() self._minBtn = QPushButton(self) self._minBtn.setGeometry(w-103,0,28,24) self._minBtn.clicked.connect(self.onMinimize) self._minBtn.setStyleSheet(""" QPushButton { background-color:transparent; border:none; outline: none; image: url(:/minimize_inactive.png); } QPushButton:hover { background-color:#227582; image: url(:/minimize_active.png); } QPushButton:pressed { background-color:#14464e; image: url(:/minimize_active.png); } """) self._maxBtn = QPushButton(self) self._maxBtn.setGeometry(w-74,0,28,24) self._maxBtn.clicked.connect(self.onMaximize) self.setMaximizeButton("maximize") self._closeBtn = QPushButton(self) self._closeBtn.setGeometry(w-45,0,36,24) self._closeBtn.clicked.connect(self.onExit) self._closeBtn.setStyleSheet(""" QPushButton { background-color:transparent; border:none; outline: none; image: url(:/close_inactive.png); } QPushButton:hover { background-color:#ea5e00; image: url(:/close_active.png); } QPushButton:pressed { background-color:#994005; image: url(:/close_active.png); } """) def resizeEvent(self, event): w = event.size().width() self._minBtn.move(w-103,0) self._maxBtn.move(w-74,0) self._closeBtn.move(w-45,0) def onMinimize(self): self.showMinimized() def isMaximized(self): return ((self.windowState() == Qt.WindowMaximized)) def onMaximize(self): if self.isMaximized(): self.showNormal() self.setMaximizeButton("maximize") else: self.showMaximized() self.setMaximizeButton("restore") def setMaximizeButton(self, style): if "maximize" == style: self._maxBtn.setStyleSheet(""" QPushButton { background-color:transparent; border:none; outline: none; image: url(:/maximize_inactive.png); } QPushButton:hover { background-color:#227582; image: url(:/maximize_active.png); } QPushButton:pressed { background-color:#14464e; image: url(:/maximize_active.png); } """) elif "restore" == style: self._maxBtn.setStyleSheet(""" QPushButton { background-color:transparent; border:none; outline: none; image: url(:/restore_inactive.png); } QPushButton:hover { background-color:#227582; image: url(:/restore_active.png); } QPushButton:pressed { background-color:#14464e; image: url(:/restore_active.png); } """) def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self._isDragging = True self._dragPos = event.globalPos() - self.pos() event.accept() def mouseMoveEvent(self, event): if event.buttons() == Qt.LeftButton and self._isDragging and not self.isMaximized(): self.move(event.globalPos() - self._dragPos) event.accept() def mouseReleaseEvent(self, event): self._isDragging = False event.accept() def SaveSettings(self): root = ET.Element("MyTerm") GUISettings = ET.SubElement(root, "GUISettings") PortCfg = ET.SubElement(GUISettings, "PortConfig") ET.SubElement(PortCfg, "port").text = self.cmbPort.currentText() ET.SubElement(PortCfg, "baudrate").text = self.cmbBaudRate.currentText() ET.SubElement(PortCfg, "databits").text = self.cmbDataBits.currentText() ET.SubElement(PortCfg, "parity").text = self.cmbParity.currentText() ET.SubElement(PortCfg, "stopbits").text = self.cmbStopBits.currentText() ET.SubElement(PortCfg, "rtscts").text = self.chkRTSCTS.isChecked() and "on" or "off" ET.SubElement(PortCfg, "xonxoff").text = self.chkXonXoff.isChecked() and "on" or "off" View = ET.SubElement(GUISettings, "View") ET.SubElement(View, "LocalEcho").text = self.actionLocal_Echo.isChecked() and "on" or "off" ET.SubElement(View, "ReceiveView").text = self._viewGroup.checkedAction().text() with open(get_config_path('settings.xml'), 'w') as f: f.write('<?xml version="1.0" encoding="UTF-8"?>\n') f.write(ET.tostring(root, encoding='utf-8', pretty_print=True).decode("utf-8")) def LoadSettings(self): if os.path.isfile(get_config_path("settings.xml")): with open(get_config_path("settings.xml"), 'r') as f: tree = safeET.parse(f) port = tree.findtext('GUISettings/PortConfig/port', default='') if port != '': self.cmbPort.setProperty("currentText", port) baudrate = tree.findtext('GUISettings/PortConfig/baudrate', default='38400') if baudrate != '': self.cmbBaudRate.setProperty("currentText", baudrate) databits = tree.findtext('GUISettings/PortConfig/databits', default='8') id = self.cmbDataBits.findText(databits) if id >= 0: self.cmbDataBits.setCurrentIndex(id) parity = tree.findtext('GUISettings/PortConfig/parity', default='None') id = self.cmbParity.findText(parity) if id >= 0: self.cmbParity.setCurrentIndex(id) stopbits = tree.findtext('GUISettings/PortConfig/stopbits', default='1') id = self.cmbStopBits.findText(stopbits) if id >= 0: self.cmbStopBits.setCurrentIndex(id) rtscts = tree.findtext('GUISettings/PortConfig/rtscts', default='off') if 'on' == rtscts: self.chkRTSCTS.setChecked(True) else: self.chkRTSCTS.setChecked(False) xonxoff = tree.findtext('GUISettings/PortConfig/xonxoff', default='off') if 'on' == xonxoff: self.chkXonXoff.setChecked(True) else: self.chkXonXoff.setChecked(False) LocalEcho = tree.findtext('GUISettings/View/LocalEcho', default='off') if 'on' == LocalEcho: self.actionLocal_Echo.setChecked(True) self._localEcho = True else: self.actionLocal_Echo.setChecked(False) self._localEcho = False ReceiveView = tree.findtext('GUISettings/View/ReceiveView', default='HEX(UPPERCASE)') if 'Ascii' in ReceiveView: self.actionAscii.setChecked(True) elif 'lowercase' in ReceiveView: self.actionHex_lowercase.setChecked(True) elif 'UPPERCASE' in ReceiveView: self.actionHEX_UPPERCASE.setChecked(True) def closeEvent(self, event): self.saveLayout() self.saveCSV() self.SaveSettings() event.accept() def tableClick(self, row): self.sendTableRow(row) def initQuickSend(self): #self.quickSendTable.horizontalHeader().setDefaultSectionSize(40) #self.quickSendTable.horizontalHeader().setMinimumSectionSize(25) self.quickSendTable.setRowCount(50) self.quickSendTable.setColumnCount(20) for row in range(50): item = QPushButton(str("Send")) item.clicked.connect(self._signalMap.map) self._signalMap.setMapping(item, row) self.quickSendTable.setCellWidget(row, 0, item) self.quickSendTable.setRowHeight(row, 20) if os.path.isfile(get_config_path('QckSndBckup.csv')): self.loadCSV(get_config_path('QckSndBckup.csv')) self.quickSendTable.resizeColumnsToContents() def openCSV(self): fileName = QFileDialog.getOpenFileName(self, "Select a file", os.getcwd(), "CSV Files (*.csv)") if fileName: self.loadCSV(fileName, notifyExcept = True) def saveCSV(self): # scan table rows = self.quickSendTable.rowCount() cols = self.quickSendTable.columnCount() tmp_data = [[self.quickSendTable.item(row, col) is not None and self.quickSendTable.item(row, col).text() or '' for col in range(1, cols)] for row in range(rows)] data = [] # delete trailing blanks for row in tmp_data: for idx, d in enumerate(row[::-1]): if '' != d: break new_row = row[:len(row) - idx] data.append(new_row) #import pprint #pprint.pprint(data, width=120, compact=True) # write to file with open(get_config_path('QckSndBckup.csv'), 'w') as csvfile: csvwriter = csv.writer(csvfile, delimiter=',', lineterminator='\n') csvwriter.writerows(data) def loadCSV(self, path, notifyExcept = False): data = [] set_rows = 0 set_cols = 0 try: with open(path) as csvfile: csvData = csv.reader(csvfile) for row in csvData: data.append(row) set_rows = set_rows + 1 if len(row) > set_cols: set_cols = len(row) except IOError as e: print("({})".format(e)) if notifyExcept: QMessageBox.critical(self, "Open failed", str(e), QMessageBox.Close) return rows = self.quickSendTable.rowCount() cols = self.quickSendTable.columnCount() # clear table for col in range(cols): for row in range(rows): self.quickSendTable.setItem(row, col, QTableWidgetItem("")) self._csvFilePath = path if (cols - 1) < set_cols: # first colume is used by the "send" buttons. cols = set_cols + 10 self.quickSendTable.setColumnCount(cols) if rows < set_rows: rows = set_rows + 20 self.quickSendTable.setRowCount(rows) for row, rowdat in enumerate(data): if len(rowdat) > 0: for col, cell in enumerate(rowdat, 1): self.quickSendTable.setItem(row, col, QTableWidgetItem(str(cell))) self.quickSendTable.resizeColumnsToContents() #self.quickSendTable.resizeRowsToContents() def sendTableRow(self, row): cols = self.quickSendTable.columnCount() try: data = ['0' + self.quickSendTable.item(row, col).text() for col in range(1, cols) if self.quickSendTable.item(row, col) is not None and self.quickSendTable.item(row, col).text() is not ''] except: print("Exception in get table data(row = %d)" % (row + 1)) else: tmp = [d[-2] + d[-1] for d in data if len(d) >= 2] for t in tmp: if not is_hex(t): QMessageBox.critical(self, "Error", "'%s' is not hexadecimal." % (t), QMessageBox.Close) return h = [int(t, 16) for t in tmp] self.transmitHex(h) def sendHex(self): hexStr = self.txtEdtInput.toPlainText() hexStr = ''.join(hexStr.split(" ")) hexarray = [] for i in range(0, len(hexStr), 2): hexarray.append(int(hexStr[i:i+2], 16)) self.transmitHex(hexarray) def readerExcept(self, e): self.closePort() QMessageBox.critical(self, "Read failed", str(e), QMessageBox.Close) def timestamp(self): return datetime.datetime.now().time().isoformat()[:-3] def receive(self, data): self.appendOutputText("\n%s R<-:%s" % (self.timestamp(), data)) def appendOutputText(self, data, color=Qt.black): # the qEditText's "append" methon will add a unnecessary newline. # self.txtEdtOutput.append(data.decode('utf-8')) tc=self.txtEdtOutput.textColor() self.txtEdtOutput.moveCursor(QtGui.QTextCursor.End) self.txtEdtOutput.setTextColor(QtGui.QColor(color)) self.txtEdtOutput.insertPlainText(data) self.txtEdtOutput.moveCursor(QtGui.QTextCursor.End) self.txtEdtOutput.setTextColor(tc) def transmitHex(self, hexarray): if len(hexarray) > 0: byteArray = bytearray(hexarray) if self.serialport.isOpen(): try: self.serialport.write(byteArray) except serial.SerialException as e: print("Exception in transmitHex(%s)" % repr(hexarray)) QMessageBox.critical(self, "Exception in transmitHex", str(e), QMessageBox.Close) else: # self.txCount += len( b ) # self.frame.statusbar.SetStatusText('Tx:%d' % self.txCount, 2) text = ''.join(['%02X ' % i for i in hexarray]) self.appendOutputText("\n%s T->:%s" % (self.timestamp(), text), Qt.blue) def GetPort(self): return self.cmbPort.currentText() def GetDataBits(self): s = self.cmbDataBits.currentText() if s == '5': return serial.FIVEBITS elif s == '6': return serial.SIXBITS elif s == '7': return serial.SEVENBITS elif s == '8': return serial.EIGHTBITS def GetParity(self): s = self.cmbParity.currentText() if s == 'None': return serial.PARITY_NONE elif s == 'Even': return serial.PARITY_EVEN elif s == 'Odd': return serial.PARITY_ODD elif s == 'Mark': return serial.PARITY_MARK elif s == 'Space': return serial.PARITY_SPACE def GetStopBits(self): s = self.cmbStopBits.currentText() if s == '1': return serial.STOPBITS_ONE elif s == '1.5': return serial.STOPBITS_ONE_POINT_FIVE elif s == '2': return serial.STOPBITS_TWO def openPort(self): if self.serialport.isOpen(): return _port = self.GetPort() if '' == _port: QMessageBox.information(self, "Invalid parameters", "Port is empty.") return _baudrate = self.cmbBaudRate.currentText() if '' == _baudrate: QMessageBox.information(self, "Invalid parameters", "Baudrate is empty.") return self.serialport.port = _port self.serialport.baudrate = _baudrate self.serialport.bytesize = self.GetDataBits() self.serialport.stopbits = self.GetStopBits() self.serialport.parity = self.GetParity() self.serialport.rtscts = self.chkRTSCTS.isChecked() self.serialport.xonxoff = self.chkXonXoff.isChecked() # self.serialport.timeout = THREAD_TIMEOUT # self.serialport.writeTimeout = SERIAL_WRITE_TIMEOUT try: self.serialport.open() except serial.SerialException as e: QMessageBox.critical(self, "Could not open serial port", str(e), QMessageBox.Close) else: self._start_reader() self.setWindowTitle("%s on %s [%s, %s%s%s%s%s]" % ( appInfo.title, self.serialport.portstr, self.serialport.baudrate, self.serialport.bytesize, self.serialport.parity, self.serialport.stopbits, self.serialport.rtscts and ' RTS/CTS' or '', self.serialport.xonxoff and ' Xon/Xoff' or '', ) ) pal = self.btnOpen.palette() pal.setColor(QtGui.QPalette.Button, QtGui.QColor(0,0xff,0x7f)) self.btnOpen.setAutoFillBackground(True) self.btnOpen.setPalette(pal) self.btnOpen.setText('Close') self.btnOpen.update() def closePort(self): if self.serialport.isOpen(): self._stop_reader() self.serialport.close() self.setWindowTitle(appInfo.title) pal = self.btnOpen.style().standardPalette() self.btnOpen.setAutoFillBackground(True) self.btnOpen.setPalette(pal) self.btnOpen.setText('Open') self.btnOpen.update() def _start_reader(self): """Start reader thread""" self.receiver_thread.start() def _stop_reader(self): """Stop reader thread only, wait for clean exit of thread""" self.receiver_thread.join() def onTogglePrtCfgPnl(self): if self.actionPort_Config_Panel.isChecked(): self.dockWidget_PortConfig.show() else: self.dockWidget_PortConfig.hide() def onToggleQckSndPnl(self): if self.actionQuick_Send_Panel.isChecked(): self.dockWidget_QuickSend.show() else: self.dockWidget_QuickSend.hide() def onToggleHexPnl(self): if self.actionSend_Hex_Panel.isChecked(): self.dockWidget_SendHex.show() else: self.dockWidget_SendHex.hide() def onVisiblePrtCfgPnl(self, visible): self.actionPort_Config_Panel.setChecked(visible) def onVisibleQckSndPnl(self, visible): self.actionQuick_Send_Panel.setChecked(visible) def onVisibleHexPnl(self, visible): self.actionSend_Hex_Panel.setChecked(visible) def onLocalEcho(self): self._localEcho = self.actionLocal_Echo.isChecked() def onAlwaysOnTop(self): if self.actionAlways_On_Top.isChecked(): style = self.windowFlags() self.setWindowFlags(style|Qt.WindowStaysOnTopHint) self.show() else: style = self.windowFlags() self.setWindowFlags(style & ~Qt.WindowStaysOnTopHint) self.show() def onOpen(self): if self.serialport.isOpen(): self.closePort() else: self.openPort() def onClear(self): self.txtEdtOutput.clear() def onSaveLog(self): fileName = QFileDialog.getSaveFileName(self, "Save as", os.getcwd(), "Log files (*.log);;Text files (*.txt);;All files (*.*)") if fileName: import codecs f = codecs.open(fileName, 'w', 'utf-8') f.write(self.txtEdtOutput.toPlainText()) f.close() def moveScreenCenter(self): w = self.frameGeometry().width() h = self.frameGeometry().height() desktop = QDesktopWidget() screenW = desktop.screen().width() screenH = desktop.screen().height() self.setGeometry((screenW-w)/2, (screenH-h)/2, w, h) def onEnumPorts(self): for p in enum_ports(): self.cmbPort.addItem(p) # self.cmbPort.update() def onAbout(self): q = QWidget() icon = QtGui.QIcon(":/icon.ico") q.setWindowIcon(icon) QMessageBox.about(q, "About MyTerm", appInfo.aboutme) def onAboutQt(self): QMessageBox.aboutQt(None) def onExit(self): if self.serialport.isOpen(): self.closePort() self.close() def restoreLayout(self): if os.path.isfile(get_config_path("layout.dat")): try: f=open(get_config_path("layout.dat"), 'rb') geometry, state=pickle.load(f) self.restoreGeometry(geometry) self.restoreState(state) except Exception as e: print("Exception on restoreLayout, {}".format(e)) else: try: f=QFile(':/default_layout.dat') f.open(QIODevice.ReadOnly) geometry, state=pickle.loads(f.readAll()) self.restoreGeometry(geometry) self.restoreState(state) except Exception as e: print("Exception on restoreLayout, {}".format(e)) def saveLayout(self): with open(get_config_path("layout.dat"), 'wb') as f: pickle.dump((self.saveGeometry(), self.saveState()), f) def syncMenu(self): self.actionPort_Config_Panel.setChecked(not self.dockWidget_PortConfig.isHidden()) self.actionQuick_Send_Panel.setChecked(not self.dockWidget_QuickSend.isHidden()) self.actionSend_Hex_Panel.setChecked(not self.dockWidget_SendHex.isHidden()) def onViewChanged(self): checked = self._viewGroup.checkedAction() if checked is None: self.actionHEX_UPPERCASE.setChecked(True) self.receiver_thread.setViewMode(VIEWMODE_HEX_UPPERCASE) else: if 'Ascii' in checked.text(): self.receiver_thread.setViewMode(VIEWMODE_ASCII) elif 'lowercase' in checked.text(): self.receiver_thread.setViewMode(VIEWMODE_HEX_LOWERCASE) elif 'UPPERCASE' in checked.text(): self.receiver_thread.setViewMode(VIEWMODE_HEX_UPPERCASE)
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()
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) icon = roam_style.iconsize() self.projecttoolbar.setIconSize(QSize(icon, icon)) self.current_form = None self.last_form = None self.firstshow = True self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.bridge = QgsLayerTreeMapCanvasBridge( QgsProject.instance().layerTreeRoot(), self.canvas) self.bridge.setAutoSetupOnFirstLayer(False) QgsProject.instance().writeProject.connect(self.bridge.writeProject) QgsProject.instance().readProject.connect(self.bridge.readProject) # self.canvas.setInteractive(False) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.snapping = SnappingUtils(self.canvas, self) self.canvas.setSnappingUtils(self.snapping) QgsProject.instance().readProject.connect( self.snapping.readConfigFromProject) if hasattr(self.canvas, 'setParallelRenderingEnabled'): threadcount = QThread.idealThreadCount() threadcount = 2 if threadcount > 2 else 1 QgsApplication.setMaxThreads(threadcount) self.canvas.setParallelRenderingEnabled(True) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) if roam.config.settings.get('north_arrow', False): self.northarrow = NorthArrow(":/icons/north", self.canvas) self.northarrow.setPos(10, 10) self.canvas.scene().addItem(self.northarrow) smallmode = roam.config.settings.get("smallmode", False) self.projecttoolbar.setSmallMode(smallmode) self.scalebar_enabled = roam.config.settings.get('scale_bar', False) if self.scalebar_enabled: self.scalebar = ScaleBarItem(self.canvas) self.canvas.scene().addItem(self.scalebar) self.projecttoolbar.setContextMenuPolicy(Qt.CustomContextMenu) gpsspacewidget = QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget( self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction( self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.marker = GPSMarker(self.canvas) self.marker.hide() self.currentfeatureband = CurrentSelection(self.canvas) self.currentfeatureband.setIconSize(30) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 50)) self.currentfeatureband.setOutlineColour(QColor(186, 93, 212)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(165, 111, 212, 75)) self.gpsband.setWidth(5) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.openfeatureform.connect(self.feature_form_loaded) RoamEvents.sync_complete.connect(self.refresh_map) RoamEvents.snappingChanged.connect(self.snapping_changed) self.snappingbutton = QToolButton() self.snappingbutton.setText("Snapping: On") self.snappingbutton.setAutoRaise(True) self.snappingbutton.pressed.connect(self.toggle_snapping) spacer = QWidget() spacer2 = QWidget() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.scalewidget = QgsScaleComboBox() self.scalebutton = QToolButton() self.scalebutton.setAutoRaise(True) self.scalebutton.setMaximumHeight(self.statusbar.height()) self.scalebutton.pressed.connect(self.selectscale) self.scalebutton.setText("Scale") self.scalelist = BigList(parent=self.canvas, centeronparent=True, showsave=False) self.scalelist.hide() self.scalelist.setlabel("Map Scale") self.scalelist.setmodel(self.scalewidget.model()) self.scalelist.closewidget.connect(self.scalelist.close) self.scalelist.itemselected.connect(self.update_scale_from_item) self.scalelist.itemselected.connect(self.scalelist.close) self.positionlabel = QLabel('') self.gpslabel = QLabel("GPS: Not active") self.gpslabelposition = QLabel("") self.statusbar.addWidget(self.snappingbutton) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.statusbar.addWidget(self.gpslabelposition) self.statusbar.addPermanentWidget(self.scalebutton) self.canvas.extentsChanged.connect(self.updatestatuslabel) self.canvas.scaleChanged.connect(self.updatestatuslabel) GPS.gpsposition.connect(self.update_gps_label) GPS.gpsdisconnected.connect(self.gps_disconnected) self.connectButtons() def clear_plugins(self): toolbars = self.findChildren(QToolBar) for toolbar in toolbars: if toolbar.property("plugin_toolbar"): toolbar.unload() self.removeToolBar(toolbar) toolbar.deleteLater() def add_plugins(self, pluginnames): for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'toolbars'): roam.utils.warning( "No toolbars() function found in {}".format(name)) continue toolbars = plugin_mod.toolbars() self.load_plugin_toolbars(toolbars) def load_plugin_toolbars(self, toolbars): for ToolBarClass in toolbars: toolbar = ToolBarClass(plugins.api, self) self.addToolBar(Qt.BottomToolBarArea, toolbar) toolbar.setProperty("plugin_toolbar", True) def snapping_changed(self, snapping): """ Called when the snapping settings have changed. Updates the label in the status bar. :param snapping: """ if snapping: self.snappingbutton.setText("Snapping: On") else: self.snappingbutton.setText("Snapping: Off") def toggle_snapping(self): """ Toggle snapping on or off. """ global snapping snap = not snapping snapping = snap RoamEvents.snappingChanged.emit(snapping) def selectscale(self): """ Show the select scale widget. :return: """ self.scalelist.show() def update_scale_from_item(self, index): """ Update the canvas scale from the selected scale item. :param index: The index of the selected item. """ scale, _ = self.scalewidget.toDouble(index.data(Qt.DisplayRole)) self.canvas.zoomScale(1.0 / scale) def update_gps_label(self, position, gpsinfo): """ Update the GPS label in the status bar with the GPS status. :param position: The current GPS position. :param gpsinfo: The current extra GPS information. """ self.gpslabel.setText( "GPS: PDOP <b>{0:.2f}</b> HDOP <b>{1:.2f}</b> VDOP <b>{2:.2f}</b>" .format(gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) places = roam.config.settings.get("gpsplaces", 8) self.gpslabelposition.setText( "X <b>{x:.{places}f}</b> Y <b>{y:.{places}f}</b>".format( x=position.x(), y=position.y(), places=places)) def gps_disconnected(self): """ Called when the GPS is disconnected. Updates the label in the status bar with the message. :return: """ self.gpslabel.setText("GPS Not Active") self.gpslabelposition.setText("") def zoom_to_feature(self, feature): box = feature.geometry().boundingBox() xmin, xmax, ymin, ymax = box.xMinimum(), box.xMaximum(), box.yMinimum( ), box.yMaximum() xmin -= 5 xmax += 5 ymin -= 5 ymax += 5 box = QgsRectangle(xmin, ymin, xmax, ymax) self.canvas.setExtent(box) self.canvas.refresh() def updatestatuslabel(self, *args): """ Update the status bar labels when the information has changed. """ extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format( extent.center().toString())) scale = 1.0 / self.canvas.scale() scale = self.scalewidget.toString(scale) self.scalebutton.setText(scale) def refresh_map(self): """ Refresh the map """ self.canvas.refresh() def updatescale(self): """ Update the scale of the map with the current scale from the scale widget :return: """ self.canvas.zoomScale(1.0 / self.scalewidget.scale()) def init_qgisproject(self, doc): """ Called when the project file is read for the firs time. :param doc: The XML doc. :return: The current canvas CRS :note: This method is old and needs to be refactored into something else. """ return self.canvas.mapSettings().destinationCrs() def showEvent(self, *args, **kwargs): """ Handle the show event of the of the map widget. We have to do a little hack here to make the QGIS map refresh. """ if QGis.QGIS_VERSION_INT == 20200 and self.firstshow: self.canvas.refresh() self.canvas.repaint() self.firstshow = False def feature_form_loaded(self, form, feature, *args): """ Called when the feature form is loaded. :param form: The Form object. Holds a reference to the forms layer. :param feature: The current capture feature """ self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): """ Highlight the selection on the canvas. This updates all selected objects based on the result set. :param results: A dict-of-list of layer-features. """ self.clear_selection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0)) band.setIconSize(25) band.setWidth(5) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) band.setZValue(self.currentfeatureband.zValue() - 1) for feature in features: band.addGeometry(feature.geometry(), layer) self.canvas.update() def highlight_active_selection(self, layer, feature, features): """ Update the current active selected feature. :param layer: The layer of the active feature. :param feature: The active feature. :param features: The other features in the set to show as non active selection. :return: """ self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) self.canvas.update() def clear_selection(self): """ Clear the selection from the canvas. Resets all selection rubbber bands. :return: """ # Clear the main selection rubber band self.canvas.scene().update() self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.canvas.update() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): """ Push a feature on the edit stack so the feature can have the geometry edited. :note: This is a big hack and I don't like it! :param form: The form for the current feature :param feature: The active feature. """ def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() self.canvas.mapTool().setEditMode(True, feature.geometry()) break self.editfeaturestack.append((form, feature)) self.save_current_form() self.load_form(form) trigger_default_action() def save_current_form(self): self.last_form = self.current_form def restore_last_form(self): self.load_form(self.last_form) def clear_temp_objects(self): """ Clear all temp objects from the canvas. :return: """ def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): """ Called when the settings have been updated in the Roam config. :param settings: A dict of the settings. """ self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging def set_gps(self, gps, logging): """ Set the GPS for the map widget. Connects GPS signals """ self.gps = gps self.gpslogging = logging self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) def gps_update_canvas(self, position, gpsinfo): """ Updates the map canvas based on the GPS position. By default if the GPS is outside the canvas extent the canvas will move to center on the GPS. Can be turned off in settings. :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.marker.show() self.marker.setCenter(position, gpsinfo) def gps_first_fix(self, postion, gpsinfo): """ Called the first time the GPS gets a fix. If set this will zoom to the GPS after the first fix :param postion: The current GPS position. :param gpsinfo: The extra GPS information """ zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): """ Zoom to ta given position on the map.. """ rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def gps_disconnected(self): """ Called when the GPS is disconnected """ self.marker.hide() def select_data_entry(self): """ Open the form selection widget to allow the user to pick the active capture form. """ def showformerror(form): pass def actions(): for form in self.project.forms: if not self.form_valid_for_capture(form): continue action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format( form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form", wrap=5) formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): """ Called when the project is loaded. Main entry point for a loade project. :param project: The Roam project that has been loaded. """ self.project = project self.actionPan.trigger() firstform = self.first_capture_form() if firstform: self.load_form(firstform) self.dataentryselection.setVisible(True) else: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.refresh() projectscales, _ = QgsProject.instance().readBoolEntry( "Scales", "/useProjectScales") if projectscales: projectscales, _ = QgsProject.instance().readListEntry( "Scales", "/ScalesList") self.scalewidget.updateScales(projectscales) else: scales = [ "1:50000", "1:25000", "1:10000", "1:5000", "1:2500", "1:1000", "1:500", "1:250", "1:200", "1:100" ] scales = roam.config.settings.get('scales', scales) self.scalewidget.updateScales(scales) if self.scalebar_enabled: self.scalebar.update() self.actionPan.toggle() self.clear_plugins() self.add_plugins(project.enabled_plugins) def setMapTool(self, tool, *args): """ Set the active map tool in the canvas. :param tool: The QgsMapTool to set. """ if tool == self.canvas.mapTool(): return if hasattr(tool, "setSnapping"): tool.setSnapping(snapping) self.canvas.setMapTool(tool) def connectButtons(self): """ Connect the default buttons in the interface. Zoom, pan, etc """ def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24, 24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) self.infoTool.setAction(self.actionInfo) self.zoomInTool.setAction(self.actionZoom_In) self.zoomOutTool.setAction(self.actionZoom_Out) self.panTool.setAction(self.actionPan) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/select')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def form_valid_for_capture(self, form): """ Check if the given form is valid for capture. :param form: The form to check. :return: True if valid form for capture """ return form.has_geometry and self.project.layer_can_capture( form.QGISLayer) def first_capture_form(self): """ Return the first valid form for capture. """ for form in self.project.forms: if self.form_valid_for_capture(form): return form def load_form(self, form): """ Load the given form so it's the active one for capture :param form: The form to load """ self.clearCaptureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) self.current_form = form def create_capture_buttons(self, form): """ Create the capture buttons in the toolbar for the given form. :param form: The active form. """ layer = form.QGISLayer tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(self.show_invalid_geometry_message) def show_invalid_geometry_message(self, message): RoamEvents.raisemessage("Invalid geometry capture", message, level=RoamEvents.CRITICAL) def add_new_feature(self, form, geometry): """ Add a new new feature to the given layer """ # TODO Extract into function. # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if layer.geometryType() in [ QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon ]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass feature = form.new_feature(geometry=geometry) RoamEvents.load_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) self.canvas.mapTool().setEditMode(False, None) self.restore_last_form() def clearCaptureTools(self): """ Clear the capture tools from the toolbar. :return: True if the capture button was active at the time of clearing. """ captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ # Freeze the canvas to save on UI refresh self.canvas.freeze() tree = QgsProject.instance().layerTreeRoot() for node in tree.findLayers(): if node.layer().type() == QgsMapLayer.RasterLayer: if node.isVisible() == Qt.Checked: state = Qt.Unchecked else: state = Qt.Checked node.setVisible(state) self.canvas.freeze(False) self.canvas.refresh() def cleanup(self): """ Clean up when the project has changed. :return: """ self.bridge.clear() self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clearCaptureTools() self.canvas.freeze() self.canvas.clear() self.canvas.freeze(False) for action in self.layerbuttons: self.editgroup.removeAction(action)
class MainWindow(mainwindow_widget, mainwindow_base): """ Main application window """ def __init__(self, settings): super(MainWindow, self).__init__() self.setupUi(self) self.settings = settings roam.featureform.settings = settings.settings self.canvaslayers = [] self.layerbuttons = [] self.project = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) self.bar = roam.messagebaritems.MessageBar(self) self.actionMap.setVisible(False) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.triggered.connect(self.updatePage) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) #TODO Extract GPS out into a service and remove UI stuff self.actionGPS = GPSAction(":/icons/gps", self.canvas, self.settings, self) self.projecttoolbar.addAction(self.actionGPS) self.projectwidget = ProjectsWidget(self) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.project_page.layout().addWidget(self.projectwidget) self.syncwidget = SyncWidget() self.syncpage.layout().addWidget(self.syncwidget) self.settingswidget = SettingsWidget(settings, self) self.settings_page.layout().addWidget(self.settingswidget) self.actionSettings.toggled.connect(self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) self.dataentrywidget.openimage.connect(self.openimage) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel("User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.stackedWidget.currentChanged.connect(self.updateUIState) self.panels = [] self.connectButtons() self.band = QgsRubberBand(self.canvas) self.band.setIconSize(20) self.band.setWidth(10) self.band.setColor(QColor(186, 93, 212, 76)) self.canvas_page.layout().insertWidget(0, self.projecttoolbar) self.dataentrymodel = QStandardItemModel(self) self.dataentrycombo = QComboBox(self.projecttoolbar) self.dataentrycombo.setIconSize(QSize(48,48)) self.dataentrycombo.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding) self.dataentrycombo.setSizeAdjustPolicy(QComboBox.AdjustToContents) self.dataentrycombo.setModel(self.dataentrymodel) self.dataentrycomboaction = self.projecttoolbar.insertWidget(self.topspaceraction, self.dataentrycombo) self.dataentrycombo.showPopup = self.selectdataentry self.biglist = BigList(self.canvas) self.biglist.setlabel("Select data entry form") self.biglist.setmodel(self.dataentrymodel) self.biglist.itemselected.connect(self.dataentrychanged) self.biglist.hide() self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.requestopenform.connect(self.openForm) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.resultscleared.connect(self.clearselection) self.infodock.openurl.connect(self.viewurl) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) self.projecttoolbar.toolButtonStyleChanged.connect(self.updatecombo) def selectdataentry(self, ): if self.dataentrycombo.count() == 0: return self.biglist.show() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] except KeyError: # It's not a image so lets just pass it of as a normal # URL QDesktopServices.openUrl(url) return pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def updatecombo(self, *args): self.dataentrycombo.setMinimumHeight(0) def settingsupdated(self, settings): settings.save() self.show() self.actionGPS.updateGPSPort() # eww! roam.featureform.settings = settings.settings def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format(extent.center().toString())) def highlightselection(self, results): for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 150)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def clearselection(self): # Clear the main selection rubber band self.band.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() def highlightfeature(self, layer, feature, features): self.clearselection() self.highlightselection({layer: features}) self.band.setToGeometry(feature.geometry(), layer) def showmap(self): self.actionMap.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def dataentrychanged(self, index): wasactive = self.clearCapatureTools() if not index.isValid(): return modelindex = index # modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) self.dataentrycombo.setCurrentIndex(index.row()) self.createCaptureButtons(form, wasactive) def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError('Seems something has gone wrong. Press for more details', info) def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = TouchMapTool(self.canvas) self.moveTool = MoveTool(self.canvas, []) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionMove, self.moveTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(self.showInfoResults) # The edit toolbutton is currently not being used but leaving it for feature. self.moveTool.layersupdated.connect(self.actionMove.setEnabled) self.moveTool.layersupdated.connect(self.actionEdit_Tools.setEnabled) self.actionGPSFeature.triggered.connect(self.addFeatureAtGPS) self.actionGPSFeature.setEnabled(self.actionGPS.isConnected) self.actionGPS.gpsfixed.connect(self.actionGPSFeature.setEnabled) self.actionHome.triggered.connect(self.homeview) self.actionQuit.triggered.connect(self.exit) def showToolError(self, label, message): self.bar.pushMessage(label, message, QgsMessageBar.WARNING) def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def createCaptureButtons(self, form, wasselected): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) if action.isdefault: action.setChecked(wasselected) if hasattr(tool, 'geometryComplete'): add = partial(self.addNewFeature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showToolError, form.label)) self.projecttoolbar.insertAction(self.topspaceraction, self.actionGPSFeature) self.actionGPSFeature.setVisible(not tool.isEditTool()) def createFormButtons(self, forms): """ Create buttons for each form that is defined """ self.dataentrymodel.clear() self.clearCapatureTools() def captureFeature(form): item = QStandardItem(QIcon(form.icon), form.icontext) item.setData(form, Qt.UserRole + 1) item.setSizeHint(QSize(item.sizeHint().width(), self.projecttoolbar.height())) self.dataentrymodel.appendRow(item) capabilitityhandlers = {"capture": captureFeature} failedforms = [] for form in forms: valid, reasons = form.valid if not valid: roam.utils.log("Form is invalid for data entry because {}".format(reasons)) failedforms.append((form, reasons)) continue for capability in form.capabilities: try: capabilitityhandlers[capability](form) except KeyError: # Just ignore capabilities we don't support yet. continue if failedforms: for form, reasons in failedforms: html = "<h3>{}</h3><br>{}".format(form.label, "<br>".join(reasons)) self.bar.pushMessage("Form errors", "Looks like some forms couldn't be loaded", level=QgsMessageBar.WARNING, extrainfo=html) visible = self.dataentrymodel.rowCount() > 0 self.dataentrycomboaction.setVisible(visible) self.dataentrycombo.setMinimumHeight(self.projecttoolbar.height()) index = self.dataentrymodel.index(0, 0) self.dataentrychanged(index) def addFeatureAtGPS(self): """ Add a record at the current GPS location. """ index = self.dataentrycombo.currentIndex() modelindex = self.dataentrymodel.index(index, 0) form = modelindex.data(Qt.UserRole + 1) point = self.actionGPS.position point = QgsGeometry.fromPoint(point) self.addNewFeature(form=form, geometry=point) def clearToolRubberBand(self): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self): self.dataentryfinished() self.bar.pushMessage("Deleted", "Feature Deleted", QgsMessageBar.INFO, 1) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.band.reset() self.clearToolRubberBand() def formrejected(self, message, level): self.dataentryfinished() if message: self.bar.pushMessage("Form Message", message, level, duration=2) self.cleartempobjects() def openForm(self, form, feature): """ Open the form that is assigned to the layer """ self.band.setToGeometry(feature.geometry(), form.QGISLayer) self.showdataentry() self.dataentrywidget.openform(feature=feature, form=form, project=self.project) def addNewFeature(self, form, geometry): """ Add a new new feature to the given layer """ layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value self.openForm(form, feature) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): self.infodock.clearResults() forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.infodock.setResults(results, forms) self.infodock.show() def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = self.settings.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) def updateUIState(self, page): """ Update the UI state to reflect the currently selected page in the stacked widget """ pass @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) self.canvas.updateScale() self.projectOpened() self.canvas.freeze(False) self.canvas.refresh() self.showmap() @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) self.createFormButtons(forms=self.project.forms) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) # TODO Abstract this out if not self.project.selectlayers: selectionlayers = QgsMapLayerRegistry.instance().mapLayers().values() else: selectionlayers = [] for layername in self.project.selectlayers: try: layer = QgsMapLayerRegistry.instance().mapLayersByName(layername)[0] except IndexError: roam.utils.warning("Can't find QGIS layer for select layer {}".format(layername)) continue selectionlayers.append(layer) self.infoTool.selectionlayers = selectionlayers self.actionPan.trigger() #noinspection PyArgumentList @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.closeProject() self.canvas.refresh() self.canvas.repaint() 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.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format(project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w,h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def closeProject(self): """ Close the current open project """ self.canvas.freeze() QgsMapLayerRegistry.instance().removeAllMapLayers() self.canvas.clear() self.canvas.freeze(False) for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons for action in self.layerbuttons: self.editgroup.removeAction(action) self.dataentrymodel.clear() self.panels = [] self.project = None self.dataentrywidget.clear() self.hidedataentry() self.infodock.close()
def __init__(self, parent): SMPluginWidget.__init__(self, parent) self.internal_shell = None # Initialize plugin self.initialize_plugin() self.no_doc_string = _("No documentation available") self._last_console_cb = None self._last_editor_cb = None self.set_default_color_scheme() self.plain_text = PlainText(self) self.rich_text = RichText(self) color_scheme = get_color_scheme(self.get_option('color_scheme_name')) self.set_plain_text_font(self.get_plugin_font(), color_scheme) self.plain_text.editor.toggle_wrap_mode(self.get_option('wrap')) # Add entries to read-only editor context-menu font_action = create_action(self, _("&Font..."), None, 'font.png', _("Set font style"), triggered=self.change_font) self.wrap_action = create_action(self, _("Wrap lines"), toggled=self.toggle_wrap_mode) self.wrap_action.setChecked(self.get_option('wrap')) self.plain_text.editor.readonly_menu.addSeparator() add_actions(self.plain_text.editor.readonly_menu, (font_action, self.wrap_action)) self.set_rich_text_font(self.get_plugin_font('rich_text')) self.shell = None self.external_console = None # locked = disable link with Console self.locked = False self._last_texts = [None, None] self._last_rope_data = None # Object name layout_edit = QHBoxLayout() layout_edit.setContentsMargins(0, 0, 0, 0) txt = _("Source") if sys.platform == 'darwin': source_label = QLabel(" " + txt) else: source_label = QLabel(txt) layout_edit.addWidget(source_label) self.source_combo = QComboBox(self) self.source_combo.addItems([_("Console"), _("Editor")]) self.connect(self.source_combo, SIGNAL('currentIndexChanged(int)'), self.source_changed) if not programs.is_module_installed('rope'): self.source_combo.hide() source_label.hide() layout_edit.addWidget(self.source_combo) layout_edit.addSpacing(10) layout_edit.addWidget(QLabel(_("Object"))) self.combo = ObjectComboBox(self) layout_edit.addWidget(self.combo) self.object_edit = QLineEdit(self) self.object_edit.setReadOnly(True) layout_edit.addWidget(self.object_edit) self.combo.setMaxCount(self.get_option('max_history_entries')) self.combo.addItems( self.load_history() ) self.connect(self.combo, SIGNAL("valid(bool)"), lambda valid: self.force_refresh()) # Plain text docstring option self.docstring = True self.rich_help = sphinxify is not None \ and self.get_option('rich_mode', True) self.plain_text_action = create_action(self, _("Plain Text"), toggled=self.toggle_plain_text) # Source code option self.show_source_action = create_action(self, _("Show Source"), toggled=self.toggle_show_source) # Rich text option self.rich_text_action = create_action(self, _("Rich Text"), toggled=self.toggle_rich_text) # Add the help actions to an exclusive QActionGroup help_actions = QActionGroup(self) help_actions.setExclusive(True) help_actions.addAction(self.plain_text_action) help_actions.addAction(self.rich_text_action) # Automatic import option self.auto_import_action = create_action(self, _("Automatic import"), toggled=self.toggle_auto_import) auto_import_state = self.get_option('automatic_import') self.auto_import_action.setChecked(auto_import_state) # Lock checkbox self.locked_button = create_toolbutton(self, triggered=self.toggle_locked) layout_edit.addWidget(self.locked_button) self._update_lock_icon() # Option menu options_button = create_toolbutton(self, text=_("Options"), icon=get_icon('tooloptions.png')) options_button.setPopupMode(QToolButton.InstantPopup) menu = QMenu(self) add_actions(menu, [self.rich_text_action, self.plain_text_action, self.show_source_action, None, self.auto_import_action]) options_button.setMenu(menu) layout_edit.addWidget(options_button) if self.rich_help: self.switch_to_rich_text() else: self.switch_to_plain_text() self.plain_text_action.setChecked(not self.rich_help) self.rich_text_action.setChecked(self.rich_help) self.rich_text_action.setEnabled(sphinxify is not None) self.source_changed() # Main layout layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addLayout(layout_edit) layout.addWidget(self.plain_text) layout.addWidget(self.rich_text) self.setLayout(layout) # Add worker thread for handling rich text rendering if sphinxify is None: self._sphinx_thread = None else: self._sphinx_thread = SphinxThread(text={}, html_text_no_doc=warning(self.no_doc_string), math_option=self.get_option('math')) self.connect(self._sphinx_thread, SIGNAL('html_ready(QString)'), self._on_sphinx_thread_html_ready) self.connect(self._sphinx_thread, SIGNAL('error_msg(QString)'), self._on_sphinx_thread_error_msg) self._starting_up = True
def initOptionsMenu(self): men = QMenu() #Threshold Slider self.threshSlider = QSlider() self.threshSlider.setTickPosition(QSlider.TicksLeft) self.threshSlider.setOrientation(Qt.Horizontal) self.threshSlider.setValue(config.thresh()) self.threshSlider.setMinimum(0) self.threshSlider.setMaximum(5) self.threshSlider.valueChanged.connect(self.parent.setThreshold) self.threshSliderAction = QWidgetAction(men) self.threshSliderAction.setDefaultWidget(self.threshSlider) #TabsWidth Slider self.tabsSlider = QSlider() self.tabsSlider.setTickPosition(QSlider.TicksLeft) self.tabsSlider.setOrientation(Qt.Horizontal) self.tabsSlider.setValue(config.tabwidth()) self.tabsSlider.setMinimum(0) self.tabsSlider.setMaximum(8) self.tabsSlider.valueChanged.connect(self.parent.setTabWidth) self.tabsSliderAction = QWidgetAction(men) self.tabsSliderAction.setDefaultWidget(self.tabsSlider) #iconSize Slider self.iconSlider = QSlider() self.iconSlider.setTickPosition(QSlider.TicksLeft) self.iconSlider.setOrientation(Qt.Horizontal) self.iconSlider.setValue(config.iconSize()) self.iconSlider.setMinimum(16) self.iconSlider.setMaximum(32) self.iconSlider.setSingleStep(2) self.iconSlider.valueChanged.connect(self.setIcon) self.iconSliderAction = QWidgetAction(men) self.iconSliderAction.setDefaultWidget(self.iconSlider) '''Font Button''' self.fontCombo = QFontComboBox() self.fontCombo.currentFontChanged.connect(self.parent.setFont) self.fontCombo.setCurrentFont(QFont(config.fontName())) self.fontComboMenu = QWidgetAction(men) self.fontComboMenu.setDefaultWidget(self.fontCombo) '''Font Size''' self.fontSizeCombo = QComboBox() for size in range(1,40): self.fontSizeCombo.addItem(str(size)) self.fontSizeCombo.setCurrentIndex(config.fontSize()) self.fontSizeCombo.currentIndexChanged.connect(self.parent.setFontSize) self.fontSizeComboMenu = QWidgetAction(men) self.fontSizeComboMenu.setDefaultWidget(self.fontSizeCombo) action_Android = QAction(Icons.android,'Android', self) action_Android.triggered.connect(self.parent.android) action_Ant = QAction(Icons.ant_view,'Ant', self) action_Ant.triggered.connect(self.parent.antt) action_Squirrel = QAction(Icons.nut,'Squirrel', self) action_Squirrel.triggered.connect(self.parent.squirrel) action_Ios1 = QAction(Icons.ios,'iOS', self) action_Update = QAction(Icons.update,"Update",self) action_Update.triggered.connect(self.parent.update) action_explorer = QAction("Explorer",self) action_explorer.triggered.connect(self.parent.exp) action_explorer.setCheckable(True) action_explorer.setChecked(True) action_console = QAction("Console",self) action_console.triggered.connect(self.parent.cmd) action_console.setCheckable(True) action_console.setChecked(False) #action_designer = QAction("Designer",self) #action_designer.triggered.connect(self.parent.design) action_Indentation = QAction("Indentation Guides",self) action_Indentation.triggered.connect(self.parent.setIndent) action_Indentation.setCheckable(True) action_Indentation.setChecked(config.indent()) action_WhiteSpace = QAction("WhiteSpace",self) action_WhiteSpace.triggered.connect(self.parent.setWhiteSpace) action_WhiteSpace.setCheckable(True) action_WhiteSpace.setChecked(config.whiteSpace()) action_EndLine = QAction("End of Lines",self) action_EndLine.triggered.connect(self.parent.setEndLine) action_EndLine.setCheckable(True) action_Margin = QAction("Line Numbers",self) action_Margin.triggered.connect(self.parent.setMargin) action_Margin.setCheckable(True) action_Margin.setChecked(config.margin()) action_ToolLabel = QAction("Tool Labels",self) action_ToolLabel.triggered.connect(self.setToolLabel) action_ToolLabel.setCheckable(True) #action_ToolLabel.setChecked(config.toolLabel()) '''Encoding''' encodingGroup = QActionGroup(self) encodingGroup.setExclusive(True) action_Ascii = QAction("Ascii",encodingGroup) action_Ascii.setCheckable(True) action_Unicode = QAction("Unicode",encodingGroup) action_Unicode.setCheckable(False) encodingGroup.addAction(action_Ascii) encodingGroup.addAction(action_Unicode) encodingGroup.selected.connect(self.parent.setEncoding) if(config.encoding() == Encoding.ASCII): action_Ascii.setChecked(True) else: action_Unicode.setChecked(True) men.addAction(action_Update) men.addAction(self.action_Help) men.addAction(self.action_Full) men.addSeparator() men.addAction(action_Android) men.addAction(action_Ant) men.addAction(action_Squirrel) men.addAction(action_Ios1) men.addSeparator() men.addAction(action_explorer) men.addAction(action_console) #men.addAction(action_designer) men.addSeparator() men.addAction(action_Indentation) men.addAction(action_WhiteSpace) men.addAction(action_EndLine) men.addAction(action_Margin) men.addAction(action_ToolLabel) men.addSeparator() men.addActions(encodingGroup.actions()) men.addSeparator() head_font = QLabel("Font---------------------") fnt = head_font.font() fnt.setBold(True) head_font.setFont(fnt) head_fontWidgetAction = QWidgetAction(men) head_fontWidgetAction.setDefaultWidget(head_font) men.addAction(head_fontWidgetAction) men.addAction(self.fontComboMenu) men.addAction(self.fontSizeComboMenu) men.addSeparator() men.addAction(QAction("TabWidth",self)) men.addAction(self.tabsSliderAction) men.addSeparator() men.addAction(QAction("Threshold",self)) men.addAction(self.threshSliderAction) #men.addAction(QAction("Icon Size",self)) #men.addAction(self.iconSliderAction) self.action_Options = QAction(Icons.emblem_system, 'Options', self) self.action_Options.setMenu(men) self.addAction(self.action_Options)
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self, roamapp): super(MainWindow, self).__init__() self.setupUi(self) import roam self.projectwidget.project_base = roamapp.projectsroot QgsApplication.instance().setStyleSheet(roam.roam_style.appstyle()) self.menutoolbar.setStyleSheet(roam.roam_style.menubarstyle()) icon = roam.roam_style.iconsize() self.menutoolbar.setIconSize(QSize(icon, icon)) smallmode = roam.config.settings.get("smallmode", False) self.menutoolbar.setSmallMode(smallmode) self.projectupdater = ProjectUpdater( projects_base=roamapp.projectsroot) self.projectupdater.foundProjects.connect( self.projectwidget.show_new_updateable) self.projectupdater.projectUpdateStatus.connect( self.projectwidget.update_project_status) self.projectupdater.projectInstalled.connect( self.projectwidget.project_installed) self.projectwidget.search_for_updates.connect(self.search_for_projects) self.projectwidget.projectUpdate.connect( self.projectupdater.update_project) self.projectwidget.projectInstall.connect( self.projectupdater.install_project) self.project = None self.tracking = GPSLogging(GPS) self.canvas_page.set_gps(GPS, self.tracking) self.canvas = self.canvas_page.canvas # self.canvas_page.projecttoolbar.stateChanged.connect(self.menutoolbar.setSmallMode) # self.menutoolbar.stateChanged.connect(self.canvas_page.projecttoolbar.setSmallMode) roam.defaults.canvas = self.canvas self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.projectbuttons = [] self.pluginactions = [] self.actionQuit.triggered.connect(self.exit) self.updatelegend() self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.gpswidget.settracking(self.tracking) self.settings = {} self.actionSettings.toggled.connect( self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas) self.dataentrywidget.lastwidgetremoved.connect(self.dataentryfinished) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) RoamEvents.featuresaved.connect(self.featureSaved) RoamEvents.helprequest.connect(self.showhelp) RoamEvents.deletefeature.connect(self.delete_feature) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.spaceraction = self.menutoolbar.insertWidget( self.actionProject, sidespacewidget) self.panels = [] self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.showInfoResults) RoamEvents.show_widget.connect(self.dataentrywidget.add_widget) RoamEvents.closeProject.connect(self.close_project) self.legendpage.showmap.connect(self.showmap) self.currentselection = {} iface = RoamInterface(RoamEvents, GPS, self, self.canvas_page, self) plugins.api = iface def delete_feature(self, form, feature): featureform = form.create_featureform(feature) try: msg = featureform.deletemessage except AttributeError: msg = 'Do you really want to delete this feature?' box = DeleteFeatureDialog(msg) if not box.exec_(): return try: featureform.delete() except featureform.DeleteFeatureException as ex: RoamEvents.raisemessage(*ex.error) return featureform.featuredeleted(feature) def set_projectbuttons(self, visible): for action in self.projectbuttons: action.setVisible(visible) def loadpages(self, pages): def safe_connect(method, to): try: method.connect(to) except AttributeError: pass for PageClass in pages: action = QAction(self.menutoolbar) text = PageClass.title.ljust(13) action.setIconText(text) action.setIcon(QIcon(PageClass.icon)) action.setCheckable(True) if PageClass.projectpage: action.setVisible(False) self.projectbuttons.append(action) self.menutoolbar.insertAction(self.spaceraction, action) else: self.menutoolbar.insertAction(self.actionProject, action) pagewidget = PageClass(plugins.api, self) safe_connect(RoamEvents.selectionchanged, pagewidget.selection_changed) safe_connect(RoamEvents.projectloaded, pagewidget.project_loaded) pageindex = self.stackedWidget.insertWidget(-1, pagewidget) action.setProperty('page', pageindex) self.pluginactions.append(action) self.menuGroup.addAction(action) def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def updatelegend(self): self.legendpage.init(self.canvas) def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return roam.api.utils.open_keyboard() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def delete_featue(self, form, feature): """ Delete the selected feature """ # We have to make the feature form because the user might have setup logic # to handle the delete case featureform = form.create_featureform(feature) try: msg = featureform.deletemessage except AttributeError: msg = 'Do you really want to delete this feature?' if not DeleteFeatureDialog(msg).exec_(): return try: featureform.delete() except DeleteFeatureException as ex: RoamEvents.raisemessage(*ex.error) featureform.featuredeleted(feature) # TODO Fix undo delete stuff # self.show_undo("Feature deleted", "Undo Delete", form, feature) def show_undo(self, title, message, form, feature): item = roam.messagebaritems.UndoMessageItem(title, message, form, feature) item.undo.connect(self.undo_delete) self.bar.pushItem(item) def undo_delete(self, form, feature): # Add the feature back to the layer self.bar.popWidget() layer = form.QGISLayer layer.startEditing() layer.addFeature(feature) layer.commitChanges() def search_for_projects(self): server = roam.config.settings.get('updateserver', '') self.projectupdater.update_server(server, self.projects) def settingsupdated(self, settings): self.settings = settings self.show() self.canvas_page.settings_updated(settings) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) def handle_removed_features(self, layer, layerid, deleted_feature_ids): self.canvas.refresh() self.reloadselection(layer, deleted=deleted_feature_ids) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = [] for selection_layer, features in self.currentselection.iteritems(): if layer.name() == selection_layer.name(): selectedfeatures = features layer = selection_layer break if not selectedfeatures: return # Update any features that have changed. for updatedfeature in updated: oldfeatures = [ f for f in selectedfeatures if f.id() == updatedfeature.id() ] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightfeature(self, layer, feature, features): self.canvas_page.highlight_active_selection(layer, feature, features) RoamEvents.activeselectionchanged.emit(layer, feature, features) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def raiseerror(self, *exinfo): import errors info = self.bar.pushError(*exinfo) errors.send_exception(exinfo) def showhelp(self, parent, url): help = HelpPage(parent) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuresdeleted(self, layerid, featureids): layer = QgsMapLayerRegistry.instance().mapLayer(layerid) self.reloadselection(layer, deleted=featureids) self.canvas.refresh() def featureSaved(self, *args): #self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def cleartempobjects(self): self.canvas_page.clear_temp_objects() def formrejected(self, message, level): if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) def openForm(self, form, feature, editmode, *args): """ Open the form that is assigned to the layer """ self.showdataentry() self.dataentrywidget.load_feature_form(feature, form, editmode, *args) def editfeaturegeometry(self, form, feature, newgeometry): layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() RoamEvents.editgeometry_complete.emit(form, feature) def exit(self): """ Exit the application. """ self.close() def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms, self.project) self.infodock.show() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projects = projects self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) self.search_for_projects() def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ crs = self.canvas_page.init_qgisproject(doc) self.projectOpened() GPS.crs = crs text = "This is a extra bit of info \n but just as a notice" @property def enabled_plugins(self): return self.settings.get('plugins', []) @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) self.clear_plugins() self.add_plugins(self.project.enabled_plugins) layers = self.project.legendlayersmapping().values() self.legendpage.setRoot(QgsProject.instance().layerTreeRoot()) gps_loglayer = self.project.gpslog_layer() if gps_loglayer: self.tracking.enable_logging_on(gps_loglayer) else: roam.utils.info("No gps_log found for GPS logging") self.tracking.clear_logging() for layer in roam.api.utils.layers(): if not layer.type() == QgsMapLayer.VectorLayer: continue layer.committedFeaturesRemoved.connect( partial(self.handle_removed_features, layer)) self.canvas_page.project_loaded(self.project) self.showmap() self.set_projectbuttons(True) self.dataentrywidget.project = self.project RoamEvents.projectloaded.emit(self.project) def clear_plugins(self): self.projectbuttons = [] self.projectbuttons.append(self.actionMap) self.projectbuttons.append(self.actionLegend) for action in self.pluginactions: # Remove the page widget, because we make it on each load widget = self.stackedWidget.widget(action.property("page")) self.stackedWidget.removeWidget(widget) if widget: widget.deleteLater() self.menutoolbar.removeAction(action) self.pluginactions = [] def add_plugins(self, pluginnames): for name in pluginnames: # Get the plugin try: plugin_mod = plugins.loaded_plugins[name] except KeyError: continue if not hasattr(plugin_mod, 'pages'): roam.utils.warning( "No pages() function found in {}".format(name)) continue pages = plugin_mod.pages() self.loadpages(pages) @roam.utils.timeit def loadProject(self, project): """ Load a project into the application. """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.close_project() # 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) # Project loading screen self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format( project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w, h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def close_project(self, project=None): """ Close the current open project """ if not project is None and not project == self.project: return RoamEvents.projectClosing.emit() self.tracking.clear_logging() self.dataentrywidget.clear() self.canvas_page.cleanup() QgsMapLayerRegistry.instance().removeAllMapLayers() for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons self.panels = [] oldproject = self.project self.project = None self.set_projectbuttons(False) self.hidedataentry() self.infodock.close() RoamEvents.selectioncleared.emit() RoamEvents.projectClosed.emit(oldproject) self.projectwidget.set_open_project(None)
class MainWindow(ui_mainwindow.Ui_MainWindow, QMainWindow): """ Main application window """ def __init__(self): super(MainWindow, self).__init__() self.setupUi(self) self.project = None self.tracking = GPSLogging(GPS) self.canvas_page.set_gps(GPS, self.tracking) self.canvas = self.canvas_page.canvas roam.defaults.canvas = self.canvas self.bar = roam.messagebaritems.MessageBar(self.centralwidget) self.actionMap.setVisible(False) self.actionLegend.setVisible(False) self.menuGroup = QActionGroup(self) self.menuGroup.setExclusive(True) self.menuGroup.addAction(self.actionMap) self.menuGroup.addAction(self.actionDataEntry) self.menuGroup.addAction(self.actionLegend) self.menuGroup.addAction(self.actionProject) self.menuGroup.addAction(self.actionSync) self.menuGroup.addAction(self.actionSettings) self.menuGroup.addAction(self.actionGPS) self.menuGroup.triggered.connect(self.updatePage) self.actionQuit.triggered.connect(self.exit) self.actionLegend.triggered.connect(self.updatelegend) self.projectwidget.requestOpenProject.connect(self.loadProject) QgsProject.instance().readProject.connect(self._readProject) self.gpswidget.setgps(GPS) self.gpswidget.settracking(self.tracking) self.actionSettings.toggled.connect( self.settingswidget.populateControls) self.actionSettings.toggled.connect(self.settingswidget.readSettings) self.settingswidget.settingsupdated.connect(self.settingsupdated) self.dataentrywidget = DataEntryWidget(self.canvas, self.bar) self.widgetpage.layout().addWidget(self.dataentrywidget) self.dataentrywidget.rejected.connect(self.formrejected) self.dataentrywidget.featuresaved.connect(self.featureSaved) self.dataentrywidget.featuredeleted.connect(self.featuredeleted) self.dataentrywidget.failedsave.connect(self.failSave) self.dataentrywidget.helprequest.connect(self.showhelp) def createSpacer(width=0, height=0): widget = QWidget() widget.setMinimumWidth(width) widget.setMinimumHeight(height) return widget gpsspacewidget = createSpacer(30) sidespacewidget = createSpacer(30) sidespacewidget2 = createSpacer(height=20) sidespacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sidespacewidget2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) def createlabel(text): style = """ QLabel { color: #706565; font: 14px "Calibri" ; }""" label = QLabel(text) label.setStyleSheet(style) return label self.projectlabel = createlabel("Project: {project}") self.userlabel = createlabel( "User: {user}".format(user=getpass.getuser())) self.positionlabel = createlabel('') self.gpslabel = createlabel("GPS: Not active") self.statusbar.addWidget(self.projectlabel) self.statusbar.addWidget(self.userlabel) spacer = createSpacer() spacer2 = createSpacer() spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) spacer2.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.statusbar.addWidget(spacer) self.statusbar.addWidget(self.positionlabel) self.statusbar.addWidget(spacer2) self.statusbar.addWidget(self.gpslabel) self.menutoolbar.insertWidget(self.actionQuit, sidespacewidget2) self.menutoolbar.insertWidget(self.actionProject, sidespacewidget) self.panels = [] self.centralwidget.layout().addWidget(self.statusbar) self.actionGPSFeature.setProperty('dataentry', True) self.infodock = InfoDock(self.canvas) self.infodock.featureupdated.connect(self.highlightfeature) self.infodock.hide() self.hidedataentry() self.canvas.extentsChanged.connect(self.updatestatuslabel) RoamEvents.openimage.connect(self.openimage) RoamEvents.openurl.connect(self.viewurl) RoamEvents.openfeatureform.connect(self.openForm) RoamEvents.openkeyboard.connect(self.openkeyboard) RoamEvents.editgeometry_complete.connect(self.on_geometryedit) RoamEvents.onShowMessage.connect(self.showUIMessage) RoamEvents.selectionchanged.connect(self.showInfoResults) RoamEvents.featureformloaded.connect(self.featureformloaded) GPS.gpsposition.connect(self.update_gps_label) GPS.gpsdisconnected.connect(self.gps_disconnected) self.legendpage.showmap.connect(self.showmap) self.currentselection = {} def showUIMessage(self, label, message, level=QgsMessageBar.INFO, time=0, extra=''): self.bar.pushMessage(label, message, level, duration=time, extrainfo=extra) def updatelegend(self): self.legendpage.updatecanvas(self.canvas) def update_gps_label(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area self.gpslabel.setText("GPS: PDOP {} HDOP {} VDOP {}".format( gpsinfo.pdop, gpsinfo.hdop, gpsinfo.vdop)) def gps_disconnected(self): self.gpslabel.setText("GPS Not Active") def openkeyboard(self): if not roam.config.settings.get('keyboard', True): return roam.api.utils.open_keyboard() def viewurl(self, url): """ Open a URL in Roam :param url: :return: """ key = url.toString().lstrip('file://') try: # Hack. Eww fix me. data, imagetype = roam.htmlviewer.images[os.path.basename(key)] pix = QPixmap() if imagetype == 'base64': pix.loadFromData(data) else: pix.load(data) self.openimage(pix) except KeyError: pix = QPixmap() pix.load(key) if pix.isNull(): QDesktopServices.openUrl(url) return self.openimage(pix) def openimage(self, pixmap): viewer = ImageViewer(self.stackedWidget) viewer.resize(self.stackedWidget.size()) viewer.openimage(pixmap) def settingsupdated(self, settings): self.show() self.canvas_page.settings_updated(settings) def updatestatuslabel(self): extent = self.canvas.extent() self.positionlabel.setText("Map Center: {}".format( extent.center().toString())) def on_geometryedit(self, form, feature): layer = form.QGISLayer self.reloadselection(layer, updated=[feature]) def reloadselection(self, layer, deleted=[], updated=[]): """ Reload the selection after features have been updated or deleted. :param layer: :param deleted: :param updated: :return: """ selectedfeatures = self.currentselection[layer] # Update any features that have changed. for updatedfeature in updated: oldfeatures = [ f for f in selectedfeatures if f.id() == updatedfeature.id() ] for feature in oldfeatures: self.currentselection[layer].remove(feature) self.currentselection[layer].append(updatedfeature) # Delete any old ones for deletedid in deleted: oldfeatures = [f for f in selectedfeatures if f.id() == deletedid] for feature in oldfeatures: self.currentselection[layer].remove(feature) RoamEvents.selectionchanged.emit(self.currentselection) def highlightfeature(self, layer, feature, features): self.canvas_page.highlight_active_selection(layer, feature, features) def showmap(self): self.actionMap.setVisible(True) self.actionLegend.setVisible(True) self.actionMap.trigger() def hidedataentry(self): self.actionDataEntry.setVisible(False) def showdataentry(self): self.actionDataEntry.setVisible(True) self.actionDataEntry.trigger() def raiseerror(self, *exinfo): info = traceback.format_exception(*exinfo) item = self.bar.pushError( QApplication.translate( 'MainWindowPy', 'Seems something has gone wrong. Press for more details', None, QApplication.UnicodeUTF8), info) def showhelp(self, url): help = HelpPage(self.stackedWidget) help.setHelpPage(url) help.show() def dataentryfinished(self): self.hidedataentry() self.showmap() self.cleartempobjects() self.infodock.refreshcurrent() def featuredeleted(self, layer, featureid): self.dataentryfinished() self.reloadselection(layer, deleted=[featureid]) self.canvas.refresh() def featureSaved(self): self.dataentryfinished() self.canvas.refresh() def failSave(self, messages): self.bar.pushError("Error when saving changes.", messages) def cleartempobjects(self): self.canvas_page.clear_temp_objects() def formrejected(self, message, level): self.dataentryfinished() if message: RoamEvents.raisemessage("Form Message", message, level, duration=2) self.cleartempobjects() def featureformloaded(self, form, feature, project, editmode): self.showdataentry() def openForm(self, form, feature, editmode): """ Open the form that is assigned to the layer """ self.dataentrywidget.openform(feature=feature, form=form, project=self.project, editmode=editmode) def exit(self): """ Exit the application. """ QApplication.exit(0) def showInfoResults(self, results): forms = {} for layer in results.keys(): layername = layer.name() if not layername in forms: forms[layername] = list(self.project.formsforlayer(layername)) self.currentselection = results self.infodock.setResults(results, forms) self.infodock.show() def missingLayers(self, layers): """ Called when layers have failed to load from the current project """ roam.utils.warning("Missing layers") map(roam.utils.warning, layers) missinglayers = roam.messagebaritems.MissingLayerItem(layers, parent=self.bar) self.bar.pushItem(missinglayers) def loadprojects(self, projects): """ Load the given projects into the project list """ projects = list(projects) self.projectwidget.loadProjectList(projects) self.syncwidget.loadprojects(projects) def updatePage(self, action): """ Update the current stack page based on the current selected action """ page = action.property("page") self.stackedWidget.setCurrentIndex(page) def show(self): """ Override show method. Handles showing the app in fullscreen mode or just maximized """ fullscreen = roam.config.settings.get("fullscreen", False) if fullscreen: self.showFullScreen() else: self.showMaximized() def viewprojects(self): self.stackedWidget.setCurrentIndex(1) @roam.utils.timeit def _readProject(self, doc): """ readProject is called by QgsProject once the map layer has been populated with all the layers """ crs = self.canvas_page.init_qgisproject(doc) self.projectOpened() GPS.crs = crs @roam.utils.timeit def projectOpened(self): """ Called when a new project is opened in QGIS. """ projectpath = QgsProject.instance().fileName() self.project = Project.from_folder(os.path.dirname(projectpath)) self.projectlabel.setText("Project: {}".format(self.project.name)) # Show panels for panel in self.project.getPanels(): self.mainwindow.addDockWidget(Qt.BottomDockWidgetArea, panel) self.panels.append(panel) layers = self.project.legendlayersmapping().values() self.legendpage.updateitems(layers) try: gps_loglayer = QgsMapLayerRegistry.instance().mapLayersByName( 'gps_log')[0] if roam.config.settings.get('gpslogging', True): self.tracking.enable_logging_on(gps_loglayer) except IndexError: roam.utils.info("No gps_log found for GPS logging") self.tracking.clear_logging() self.canvas_page.project_loaded(self.project) self.showmap() @roam.utils.timeit def loadProject(self, project): """ Load a project into the application . """ roam.utils.log(project) roam.utils.log(project.name) roam.utils.log(project.projectfile) roam.utils.log(project.valid) (passed, message) = project.onProjectLoad() if not passed: self.bar.pushMessage("Project load rejected", "Sorry this project couldn't" "be loaded. Click for me details.", QgsMessageBar.WARNING, extrainfo=message) return self.actionMap.trigger() self.close_project() # 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) # Project loading screen self.stackedWidget.setCurrentIndex(3) self.projectloading_label.setText("Project {} Loading".format( project.name)) pixmap = QPixmap(project.splash) w = self.projectimage.width() h = self.projectimage.height() self.projectimage.setPixmap(pixmap.scaled(w, h, Qt.KeepAspectRatio)) QApplication.processEvents() QDir.setCurrent(os.path.dirname(project.projectfile)) fileinfo = QFileInfo(project.projectfile) QgsProject.instance().read(fileinfo) def close_project(self): """ Close the current open project """ self.tracking.clear_logging() self.dataentrywidget.clear() self.canvas_page.cleanup() QgsMapLayerRegistry.instance().removeAllMapLayers() for panel in self.panels: self.removeDockWidget(panel) del panel # Remove all the old buttons self.panels = [] self.project = None self.hidedataentry() self.infodock.close() RoamEvents.selectioncleared.emit()
class MainWindow(QtGui.QMainWindow): def __init__(self, mock = None): super(QtGui.QMainWindow, self).__init__() QtGui.QApplication.setStyle(QtGui.QStyleFactory.create("Plastique")); self.setWindowTitle("Mini Yatt") self.mock = mock self.mode = Mode.MANUAL_PLAYER_MODE self.currentCmd = 0 self.setupSocketThread() self.createCentralWidget() self.lineEdit.returnPressed.connect(self.sendData) self.connect(self.thread, QtCore.SIGNAL("newData"), self.readNewData) self.createShortcuts() self.createActions() self.createToolbar() self.createActionGroup() self.createMenus() self.readSettings() self.connect(self.scenarioComboBox, QtCore.SIGNAL("currentIndexChanged( const QString)"), self.selectScenario) for sequenceName in sorted(SequenceFactory().getAllSequenceNames()): print(sequenceName) self.scenarioComboBox.addItem(sequenceName) def subscribeForFilename(self): return "Log.miniyatt" def saveFile(self): filename = self.subscribeForFilename() file = QtCore.QFile(filename) if not file.open(QtCore.QFile.WriteOnly | QtCore.QFile.Text): QtGui.QMessageBox.warning(self, "Application", "Cannot write file %s:\n%s." % (fileName, file.errorString())) return False outf = QtCore.QTextStream(file) outf << self.textEdit.toPlainText() file.close() return True def createToolbar(self): self.fileToolBar = self.addToolBar("ATCommands Toolbar") self.fileToolBar.addAction(self.addAct) def createCentralWidget(self): centralWidget = QWidget() self.setCentralWidget(centralWidget) self.lineEdit = QtGui.QLineEdit() self.textEdit = QtGui.QTextEdit() self.scenarioComboBox = QtGui.QComboBox(self) # currentIndexChanged = self.selectScenario ) self.layout = QtGui.QVBoxLayout() self.layout.addWidget(self.lineEdit) self.layout.addWidget(self.textEdit) self.layout.addWidget(self.scenarioComboBox) centralWidget.setLayout(self.layout) def createAction(self, actionName, atCmd): newActionObject = QAction(actionName, self) newActionObject.setData(atCmd) return newActionObject def setupSocketThread (self): self.socket = None if self.mock == True: QtCore.qDebug("MOCK MODE ON") self.socket = SocketMock() else: try: self.socket = serial.Serial(3,115200) except SerialException as e: QtCore.qDebug("Exception catched!") QtGui.QMessageBox.about(self, "Error", "Socket in use") self.thread = SerialCommunicationThread(self.socket) self.thread.start() def createMenus(self): self.fileMenu = self.menuBar().addMenu("File") self.fileMenu.addAction(self.quitAct) self.fileMenu.addAction(self.saveAct) self.modeMenu = self.menuBar().addMenu("Mode") self.modeActionGroup = QActionGroup(self,triggered=self.modeActionTriggered) self.modeActionGroup.setExclusive(True) allModeList = [] allModeList.append(["Manual Mode", False, Mode.MANUAL_MODE]) allModeList.append(["Manual Player Mode",True,Mode.MANUAL_PLAYER_MODE]) allModeList.append(["Pegasus Mode", False,Mode.PEGASUS_MODE]) for modeData in allModeList: modeActionObject = QAction(modeData[0],self) modeActionObject.setCheckable(True) modeActionObject.setChecked(modeData[1]) modeActionObject.setData(modeData[2]) self.modeActionGroup.addAction(modeActionObject) self.modeMenu.addAction(modeActionObject) def createShortcuts(self): self.shortcut = QShortcut(QKeySequence("Ctrl+O"), self) self.shortcut.activated.connect(self.openFile) self.upArrow = QShortcut(QKeySequence("Up"), self) self.upArrow.activated.connect(self.previousCmd) self.downArrow = QShortcut(QKeySequence("Down"), self) self.downArrow.activated.connect(self.nextCmd) def previousCmd(self): QtCore.qDebug("Hello From Up") self.currentCmd -= 1 def nextCmd(self): QtCore.qDebug("Hello From Down") self.currentCmd += 1 def createActions(self): self.addAct = QAction(QIcon("addIcon16.png"), "Add", self, triggered=self.addButton) #self.addButtonAct = QAction("Add Button",self,triggered=self.addButton) self.quitAct = QAction("Quit", self, shortcut=QKeySequence.Quit, triggered=QtGui.qApp.quit) self.saveAct = QAction("Save", self, shortcut=QKeySequence.Save, triggered=self.saveFile) def modeActionTriggered(self, action): QtCore.qDebug(str(action.data())) ###### PEGASUS MODE ######## if action.data() == Mode.PEGASUS_MODE: QtCore.qDebug("PEGASUS MODE SELECTED - co powinienem dalej zrobic?") self.mode = Mode.PEGASUS_MODE #tutaj przyda sie jakis iterator currentSequence = self.scenarioComboBox.currentText() #self.commands = SequenceFactory().getNewSequence(currentSequence) self.commands = SequenceFactory().getNewSequence("cmu900") self.currentCmd = 0 #TODO ### Wczytaj pierwsza sekwencje timeoutValue = self.commands[0].timeout self.response = deepcopy(self.commands[0].response) QtCore.qDebug("*****") QtCore.qDebug(repr(self.response)) QtCore.qDebug("*****") self.sendDataMsg(self.commands[0].cmd) self.timer = Timer(timeoutValue, self.timeout) self.timer.start() def createActionGroup(self): self.actionGroup=QActionGroup(self,triggered=self.actionGroupTriggered) allActionsItemList = [] allActionsItemList.append(["Bands?", "at^scfg=radio/band"]) allActionsItemList.append(["at^moni", "at^moni"]) allActionsItemList.append(["PIN","at+cpin=9999"]) allActionsItemList.append(["PIN?","at+cpin?"]) allActionsItemList.append(["AT", "AT"]) allActionsItemList.append(["Model","at^siekret=1"]) allActionsItemList.append(["Shutdown","at^smso"]) for actionItem in allActionsItemList: newActionObject = self.createAction(actionItem[0], actionItem[1]) self.actionGroup.addAction(newActionObject) self.fileToolBar.addAction(newActionObject) def selectScenario(self, sequenceName): QtCore.qDebug("Hello From SelectScenario") QtCore.qDebug(sequenceName) self.commands = deepcopy(SequenceFactory().getSequence(sequenceName)) self.currentCmd = 0 self.lineEdit.setText(self.commands[0]) def closeEvent(self, event): self.writeSettings() def readSettings(self): settings = QtCore.QSettings("REC", "MiniYatt") pos = settings.value("pos", QtCore.QPoint(200, 200)) size = settings.value("size", QtCore.QSize(400, 400)) self.resize(size) self.move(pos) def writeSettings(self): settings = QtCore.QSettings("REC", "MiniYatt") settings.setValue("pos", self.pos()) settings.setValue("size", self.size()) def openFile(self): QtCore.qDebug("Hello From Open FIle") def addButton(self): self.addButtonWidget = AddButtonWidget() self.addButtonWidget.setWindowModality(QtCore.Qt.ApplicationModal) self.addButtonWidget.resize(200,200) self.addButtonWidget.show() QtCore.qDebug("Hello From Add Button") def readNewData(self, data): data = data.strip() self.textEdit.append(data) self.textEdit.moveCursor(QtGui.QTextCursor.End) if self.mode == Mode.PEGASUS_MODE: self.sequencePlayer(data) def timeout(self): QtCore.qDebug("TIMEOUT!") def sequencePlayer(self, data): #TODO - poprawic indeksy ### Sprawdz, czy dostales oczekiwane dane QtCore.qDebug("JESTEM w sequencePlayer") QtCore.qDebug(repr(self.response)) QtCore.qDebug(data) if data.find(self.response[0]) >= 0 : if len(self.response) == 1: self.timer.cancel() waitBeforeNext = self.commands[self.currentCmd].waitBeforeNext self.currentCmd += 1 #TRZEBA USTAWIC WSZYSTKIE PARAMETRY DLA NOWEJ KOMENDY #wysylamy i zapominamy - nasluchujemy na odpowiedzi tutaj. self.nextMsg = self.commands[self.currentCmd].cmd self.timeoutValue = self.commands[self.currentCmd].timeout self.response = self.commands[self.currentCmd].response self.timerWaitBeforeNext = Timer(waitBeforeNext, self.sendNext) self.timerWaitBeforeNext.start() else: self.response.pop(0) else: QtCore.qDebug("IGNORE") def sendDataMsg(self, msg): #msg = self.lineEdit.text() QtCore.qDebug("JESTEM W SendDataMsg: " + msg) self.socket.write(str.encode(msg) + b"\r\n") if self.mode == Mode.MANUAL_PLAYER_MODE: self.currentCmd += 1 self.lineEdit.setText(self.commands[self.currentCmd]) else: #addHistory(msg) self.lineEdit.setText("") def sendNext(self): self.sendDataMsg(self.nextMsg) self.timer = Timer(self.timeoutValue, self.timeout) self.timer.start() def sendData(self): QtCore.qDebug("sendData odpalone!") self.sendDataMsg(self.lineEdit.text()) def actionGroupTriggered(self, action): QtCore.qDebug("Hello from actionGroupTriggered") QtCore.qDebug(action.data()) self.socket.write(str.encode(action.data()) + b"\r\n")
class MapWidget(Ui_CanvasWidget, QMainWindow): def __init__(self, parent=None): super(MapWidget, self).__init__(parent) self.setupUi(self) self.firstshow = True self.layerbuttons = [] self.editfeaturestack = [] self.lastgpsposition = None self.project = None self.gps = None self.gpslogging = None self.selectionbands = defaultdict(partial(QgsRubberBand, self.canvas)) self.canvas.setCanvasColor(Qt.white) self.canvas.enableAntiAliasing(True) self.canvas.setWheelAction(QgsMapCanvas.WheelZoomToMouseCursor) if hasattr(self.canvas, 'setParallelRenderingEnabled'): self.canvas.setParallelRenderingEnabled(True) pal = QgsPalLabeling() self.canvas.mapRenderer().setLabelingEngine(pal) self.canvas.setFrameStyle(QFrame.NoFrame) self.editgroup = QActionGroup(self) self.editgroup.setExclusive(True) self.editgroup.addAction(self.actionPan) self.editgroup.addAction(self.actionZoom_In) self.editgroup.addAction(self.actionZoom_Out) self.editgroup.addAction(self.actionInfo) self.actionGPS = GPSAction(":/icons/gps", self.canvas, self) self.projecttoolbar.addAction(self.actionGPS) gpsspacewidget= QWidget() gpsspacewidget.setMinimumWidth(30) gpsspacewidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.topspaceraction = self.projecttoolbar.insertWidget(self.actionGPS, gpsspacewidget) self.dataentryselection = QAction(self.projecttoolbar) self.dataentryaction = self.projecttoolbar.insertAction(self.topspaceraction, self.dataentryselection) self.dataentryselection.triggered.connect(self.select_data_entry) self.marker = GPSMarker(self.canvas) self.marker.hide() self.currentfeatureband = QgsRubberBand(self.canvas) self.currentfeatureband.setIconSize(20) self.currentfeatureband.setWidth(10) self.currentfeatureband.setColor(QColor(186, 93, 212, 76)) self.gpsband = QgsRubberBand(self.canvas) self.gpsband.setColor(QColor(0, 0, 212, 76)) self.gpsband.setWidth(5) RoamEvents.editgeometry.connect(self.queue_feature_for_edit) RoamEvents.selectioncleared.connect(self.clear_selection) RoamEvents.selectionchanged.connect(self.highlight_selection) RoamEvents.featureformloaded.connect(self.feature_form_loaded) self.connectButtons() def init_qgisproject(self, doc): parser = ProjectParser(doc) canvasnode = parser.canvasnode self.canvas.freeze() self.canvas.mapRenderer().readXML(canvasnode) self.canvaslayers = parser.canvaslayers() self.canvas.setLayerSet(self.canvaslayers) #red = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorRedPart", 255 )[0]; #green = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorGreenPart", 255 )[0]; #blue = QgsProject.instance().readNumEntry( "Gui", "/CanvasColorBluePart", 255 )[0]; #color = QColor(red, green, blue); #self.canvas.setCanvasColor(color) self.canvas.updateScale() return self.canvas.mapRenderer().destinationCrs() def showEvent(self, *args, **kwargs): if self.firstshow: self.canvas.refresh() self.canvas.repaint() self.firstshow = False def feature_form_loaded(self, form, feature, project, editmode): self.currentfeatureband.setToGeometry(feature.geometry(), form.QGISLayer) def highlight_selection(self, results): self.clear_selection() for layer, features in results.iteritems(): band = self.selectionbands[layer] band.setColor(QColor(255, 0, 0, 200)) band.setIconSize(20) band.setWidth(2) band.setBrushStyle(Qt.NoBrush) band.reset(layer.geometryType()) for feature in features: band.addGeometry(feature.geometry(), layer) def highlight_active_selection(self, layer, feature, features): self.clear_selection() self.highlight_selection({layer: features}) self.currentfeatureband.setToGeometry(feature.geometry(), layer) def clear_selection(self): # Clear the main selection rubber band self.currentfeatureband.reset() # Clear the rest for band in self.selectionbands.itervalues(): band.reset() self.editfeaturestack = [] def queue_feature_for_edit(self, form, feature): def trigger_default_action(): for action in self.projecttoolbar.actions(): if action.property('dataentry') and action.isdefault: action.trigger() break self.editfeaturestack.append((form, feature)) self.load_form(form) trigger_default_action() def clear_temp_objects(self): def clear_tool_band(): """ Clear the rubber band of the active tool if it has one """ tool = self.canvas.mapTool() try: tool.clearBand() except AttributeError: # No clearBand method found, but that's cool. pass self.currentfeatureband.reset() clear_tool_band() def settings_updated(self, settings): self.actionGPS.updateGPSPort() gpslogging = settings.get('gpslogging', True) if self.gpslogging: self.gpslogging.logging = gpslogging def set_gps(self, gps, logging): self.gps = gps self.gpslogging = logging self.gps.gpsposition.connect(self.gps_update_canvas) self.gps.firstfix.connect(self.gps_first_fix) self.gps.gpsdisconnected.connect(self.gps_disconnected) def gps_update_canvas(self, position, gpsinfo): # Recenter map if we go outside of the 95% of the area if self.gpslogging.logging: self.gpsband.addPoint(position) self.gpsband.show() if roam.config.settings.get('gpscenter', True): if not self.lastgpsposition == position: self.lastposition = position rect = QgsRectangle(position, position) extentlimt = QgsRectangle(self.canvas.extent()) extentlimt.scale(0.95) if not extentlimt.contains(position): self.zoom_to_location(position) self.marker.show() self.marker.setCenter(position) def gps_first_fix(self, postion, gpsinfo): zoomtolocation = roam.config.settings.get('gpszoomonfix', True) if zoomtolocation: self.canvas.zoomScale(1000) self.zoom_to_location(postion) def zoom_to_location(self, position): rect = QgsRectangle(position, position) self.canvas.setExtent(rect) self.canvas.refresh() def gps_disconnected(self): self.marker.hide() def select_data_entry(self): def showformerror(form): pass def actions(): for form in self.project.forms: action = form.createuiaction() valid, failreasons = form.valid if not valid: roam.utils.warning("Form {} failed to load".format(form.label)) roam.utils.warning("Reasons {}".format(failreasons)) action.triggered.connect(partial(showformerror, form)) else: action.triggered.connect(partial(self.load_form, form)) yield action formpicker = PickActionDialog(msg="Select data entry form") formpicker.addactions(actions()) formpicker.exec_() def project_loaded(self, project): self.project = project self.actionPan.trigger() try: firstform = project.forms[0] self.load_form(firstform) self.dataentryselection.setVisible(True) except IndexError: self.dataentryselection.setVisible(False) # Enable the raster layers button only if the project contains a raster layer. layers = QgsMapLayerRegistry.instance().mapLayers().values() hasrasters = any(layer.type() == QgsMapLayer.RasterLayer for layer in layers) self.actionRaster.setEnabled(hasrasters) self.defaultextent = self.canvas.extent() roam.utils.info("Extent: {}".format(self.defaultextent.toString())) self.infoTool.selectionlayers = project.selectlayersmapping() self.canvas.freeze(False) self.canvas.refresh() def setMapTool(self, tool, *args): self.canvas.setMapTool(tool) def connectButtons(self): def connectAction(action, tool): action.toggled.connect(partial(self.setMapTool, tool)) def cursor(name): pix = QPixmap(name) pix = pix.scaled(QSize(24,24)) return QCursor(pix) self.zoomInTool = QgsMapToolZoom(self.canvas, False) self.zoomOutTool = QgsMapToolZoom(self.canvas, True) self.panTool = PanTool(self.canvas) self.infoTool = InfoTool(self.canvas) connectAction(self.actionZoom_In, self.zoomInTool) connectAction(self.actionZoom_Out, self.zoomOutTool) connectAction(self.actionPan, self.panTool) connectAction(self.actionInfo, self.infoTool) self.zoomInTool.setCursor(cursor(':/icons/in')) self.zoomOutTool.setCursor(cursor(':/icons/out')) self.infoTool.setCursor(cursor(':/icons/info')) self.actionRaster.triggered.connect(self.toggleRasterLayers) self.infoTool.infoResults.connect(RoamEvents.selectionchanged.emit) self.actionHome.triggered.connect(self.homeview) def homeview(self): """ Zoom the mapview canvas to the extents the project was opened at i.e. the default extent. """ self.canvas.setExtent(self.defaultextent) self.canvas.refresh() def load_form(self, form): self.clearCapatureTools() self.dataentryselection.setIcon(QIcon(form.icon)) self.dataentryselection.setText(form.icontext) self.create_capture_buttons(form) def create_capture_buttons(self, form): tool = form.getMaptool()(self.canvas) for action in tool.actions: # Create the action here. if action.ismaptool: action.toggled.connect(partial(self.setMapTool, tool)) # Set the action as a data entry button so we can remove it later. action.setProperty("dataentry", True) self.editgroup.addAction(action) self.layerbuttons.append(action) self.projecttoolbar.insertAction(self.topspaceraction, action) action.setChecked(action.isdefault) if hasattr(tool, 'geometryComplete'): add = partial(self.add_new_feature, form) tool.geometryComplete.connect(add) else: tool.finished.connect(self.openForm) tool.error.connect(partial(self.showUIMessage, form.label)) def add_new_feature(self, form, geometry): """ Add a new new feature to the given layer """ # TODO Extract into function. # NOTE This function is doing too much, acts as add and also edit. layer = form.QGISLayer if layer.geometryType() in [QGis.WKBMultiLineString, QGis.WKBMultiPoint, QGis.WKBMultiPolygon]: geometry.convertToMultiType() try: form, feature = self.editfeaturestack.pop() self.editfeaturegeometry(form, feature, newgeometry=geometry) return except IndexError: pass layer = form.QGISLayer fields = layer.pendingFields() feature = QgsFeature(fields) feature.setGeometry(geometry) for index in xrange(fields.count()): pkindexes = layer.dataProvider().pkAttributeIndexes() if index in pkindexes and layer.dataProvider().name() == 'spatialite': continue value = layer.dataProvider().defaultValue(index) feature[index] = value RoamEvents.open_feature_form(form, feature, editmode=False) def editfeaturegeometry(self, form, feature, newgeometry): # TODO Extract into function. layer = form.QGISLayer layer.startEditing() feature.setGeometry(newgeometry) layer.updateFeature(feature) saved = layer.commitChanges() if not saved: map(roam.utils.error, layer.commitErrors()) self.canvas.refresh() self.currentfeatureband.setToGeometry(feature.geometry(), layer) RoamEvents.editgeometry_complete.emit(form, feature) def clearCapatureTools(self): captureselected = False for action in self.projecttoolbar.actions(): if action.objectName() == "capture" and action.isChecked(): captureselected = True if action.property('dataentry'): self.projecttoolbar.removeAction(action) return captureselected def toggleRasterLayers(self): """ Toggle all raster layers on or off. """ if not self.canvaslayers: return #Freeze the canvas to save on UI refresh self.canvas.freeze() for layer in self.canvaslayers: if layer.layer().type() == QgsMapLayer.RasterLayer: layer.setVisible(not layer.isVisible()) # Really!? We have to reload the whole layer set every time? # WAT? self.canvas.setLayerSet(self.canvaslayers) self.canvas.freeze(False) self.canvas.refresh() def cleanup(self): self.gpsband.reset() self.gpsband.hide() self.clear_selection() self.clear_temp_objects() self.clearCapatureTools() self.canvas.freeze() self.canvas.clear() self.canvas.freeze(False) for action in self.layerbuttons: self.editgroup.removeAction(action)
class GazerMainWindow(QMainWindow): """ Main window of Gazer Qt gui. Provides overall layout and menus to access basic functionality. """ def __init__(self, tracking_apis=None): super(GazerMainWindow, self).__init__() # Ete tracking setup self.tracking_apis = tracking_apis if tracking_apis is not None else {} self.tracker = None # Main layout self.render_area = GCImageWidget(None) self.render_area.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored) self.setCentralWidget(self.render_area) # Create actions self.open_action = QAction("&Open...", self, shortcut="Ctrl+O", triggered=self.load_scene_procedure) self.save_action = QAction("&Save...", self, shortcut="Ctrl+S", triggered=self.save_scene) self.import_ifp_action = QAction("&Import Lytro file", self, shortcut="Ctrl+I", triggered=self.import_ifp) self.import_directory_of_images_action = QAction( "&Import from Image Stacks", # NOQA self, shortcut="Ctrl+D", triggered=self.import_directory_of_images) self.export_image_stack_action = QAction( "&Export as Image Stack", # NOQA self, shortcut="Ctrl+E", triggered=self.export_image_stack) self.preferences_action = QAction("&Preferences", self, shortcut="Ctrl+P", triggered=self.open_preferences ) self.exit_action = QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close ) self.cursor_toggle_action = QAction("Toggle debug cursor", self, triggered=self.toggle_cursor, checkable=True, checked=False, ) self.toggle_depthmap_action = QAction("Toggle depthmap", self, triggered=self.toggle_depthmap, checkable=True, checked=False, ) self._make_tracker_select_menu() # Create Menues self.file_menu = QMenu("&File", self) self.file_menu.addAction(self.open_action) self.file_menu.addAction(self.save_action) self.file_menu.addAction(self.import_ifp_action) self.file_menu.addAction(self.export_image_stack_action) self.file_menu.addAction(self.import_directory_of_images_action) self.file_menu.addSeparator() self.file_menu.addAction(self.preferences_action) self.file_menu.addSeparator() self.file_menu.addAction(self.exit_action) # Create Option Menu self.options_menu = QMenu("&Options", self) self.options_menu.addAction(self.cursor_toggle_action) self.options_menu.addAction(self.toggle_depthmap_action) tracker_menu = self.options_menu.addMenu('Select Tracker') tracker_menu.addActions(self.select_tracker_action_group.actions()) # Set default gaze input or mouse simulation if self.select_tracker_action_group.actions(): self.select_tracker_action_group.actions()[0].trigger() else: self.mouse_toggle_action.trigger() # Add menus to menu bar self.menuBar().addMenu(self.file_menu) self.menuBar().addMenu(self.options_menu) # Add help menu help_menu = QMenu("&Help", self) project_url = 'http://deepview.cs.st-andrews.ac.uk' help_menu.addAction(QAction("Project Website", self, triggered=lambda: webbrowser.open( project_url), ) ) help_menu.addAction(QAction("About", self, triggered=self.show_about, ) ) self.menuBar().addMenu(help_menu) # Add handlers for fullscreen mode self._fullscreen = False self.setWindowTitle("Gazer") self.resize(800, 600) def mouseDoubleClickEvent(self, *args, **kwargs): super(GazerMainWindow, self).mouseDoubleClickEvent(*args, **kwargs) self.toggle_fullscreen() def _make_tracker_select_menu(self): self.select_tracker_action_group = QActionGroup(self) self.select_tracker_action_group.setExclusive(True) # Add detected eye trackers for name, api in self.tracking_apis.items(): action = QAction(name, self, triggered=partial(self.select_eye_tracker, name), checkable=True, ) self.select_tracker_action_group.addAction(action) # Add mouse input as fallback mouse_mode = QAction("Mouse", self, triggered=self.toggle_mouse_mode, checkable=True, ) self.select_tracker_action_group.addAction(mouse_mode) def select_eye_tracker(self, tracker_api_key): self.disable_mouse_mode() logger.debug('Selecting tracker {}'.format(tracker_api_key)) if self.tracker: self.tracker.on_event = [] self.tracker = self.tracking_apis.get(tracker_api_key) self.tracker.on_event.append(self.render_area.update_gaze) def toggle_mouse_mode(self): self.render_area.mouse_mode = not self.render_area.mouse_mode def disable_mouse_mode(self): self.render_area.mouse_mode = False def toggle_cursor(self): self.render_area.show_cursor = not self.render_area.show_cursor def toggle_depthmap(self): self.render_area.toggle_depthmap() self.update() def update_scene(self, scene): self.render_area.gc_scene = scene self.render_area.update() def load_scene_procedure(self): """ Starts UI procedure to load scene form .gc file. """ file_name = QFileDialog.getOpenFileName(self, "Open File", QDir.currentPath(), filter="GC File (*.gc)" ) if file_name: self.load_scene_file(str(file_name)) def load_scene_file(self, path): """ Starts asynchronous loading of scene object from a .gc file. Parameters ---------- path: str Path to file that will be loaded. """ scene_load_func = partial(gcio.load_scene, str(path)) loader = BlockingTask(scene_load_func, 'Loading file.', parent=self) loader.load_finished.connect(self.update_scene) loader.start_task() def save_scene(self): file_name = QFileDialog.getSaveFileName(self, "Save File", QDir.currentPath(), filter="GC File (*.gc)", ) if file_name: def task(): with open(file_name, 'wb') as out_file: scene = self.render_area.gc_scene gcio.write_file(out_file, scene) loader = BlockingTask(task, 'Saving file.', parent=self) loader.start_task() def import_ifp(self): """ Starts UI procedure to import a scene from a Lytro raw file. """ if read_ifp is None: QErrorMessage(self).showMessage('Lytro import unavailable.') return extension_filter = "LFP Raw File (*.lfp); LFP XRaw File (*.lfx);" file_name = QFileDialog.getOpenFileName(self.parent(), "Import File", QDir.currentPath(), filter=extension_filter, ) if file_name: self.import_ifp_file(str(file_name)) def import_ifp_file(self, path): """ Starts asynchronous importing of a scene from a Lytro raw file. Parameters ---------- path: str Path to file that will be loaded. """ if read_ifp is None: QErrorMessage(self).showMessage('Lytro import unavailable.') return current_preferences = gazer.preferences.load_preferences() scene_load_func = partial(read_ifp, path, current_preferences) loader = BlockingTask(scene_load_func, 'Importing file.', parent=self) loader.load_finished.connect(self.update_scene) loader.start_task() def import_directory_of_images(self): """ Starts UI procedure to load scene from image stack. """ param = QFileDialog.ShowDirsOnly | QFileDialog.DontResolveSymlinks folder_name = QFileDialog.getExistingDirectory(self, "Open Directory", QDir.currentPath(), param ) if folder_name: self.load_image_stack_folder(str(folder_name)) def load_image_stack_folder(self, path): """ Starts asynchronous loading of scene object from an image stack. Parameters ---------- path: str Path to folder that will be loaded. """ scene_load_func = partial(dir_import.dir_to_scene, path, ) loader = BlockingTask(scene_load_func, 'Importing files.', parent=self) loader.load_finished.connect(self.update_scene) loader.start_task() def export_image_stack(self): folder_name = str(QFileDialog.getExistingDirectory(self, "Select Directory")) if folder_name: export_function = partial(gcio.extract_scene_to_stack, self.render_area.gc_scene, folder_name ) task = BlockingTask(export_function, 'Extracting files.', parent=self, ) task.start_task() def open_preferences(self): # print("Open Preferences!") dialog = PreferencesDialog() dialog.exec_() def event(self, event): if event.type() == QEvent.KeyPress: if event.key() == Qt.Key_F12: self.toggle_fullscreen() return True return super(GazerMainWindow, self).event(event) def toggle_fullscreen(self): if self.isFullScreen(): self.showNormal() else: self.showFullScreen() def update(self, *__args): super(GazerMainWindow, self).update() self.render_area.update() def show_about(self): info_dict = {'version': gazer.__version__, 'copyright_year': '2016'} about_text = """ <p><b>Gazer</b> v{version}</p> <p>© {copyright_year} University of St Andrews </p> <p>Developers <ul style="list-style-type:none"> <li>Michael Mauderer</li> <li>David Morrison</li> <li> Miguel Nacenta</li> </ul> </p> <p>Logo design <ul style="list-style-type:none"> <li>Johannes Lang</li> </ul> </p> """.format(**info_dict) QtGui.QMessageBox.about(self, 'About', about_text)