class Ui: def __init__(self, app): self._app = app self._layout = QVBoxLayout(app) self._top_separator = Separator(parent=app) self._bottom_separator = Separator(parent=app) self._splitter = QSplitter(app) if use_mac_theme(): self._splitter.setHandleWidth(0) # NOTE: 以位置命名的部件应该只用来组织界面布局,不要 # 给其添加任何功能性的函数 self.top_panel = TopPanel(app, app) self.bottom_panel = BottomPanel(app, app) self._left_panel_container = QScrollArea(app) self._left_panel_container.setWidgetResizable(True) self._left_panel_container.setFrameShape(QFrame.NoFrame) self.left_panel = LeftPanel(self._app, self._left_panel_container) self._left_panel_container.setWidget(self.left_panel) self.right_panel = RightPanel(self._app, self._splitter) self.mpv_widget = MpvOpenGLWidget(self._app) self.mpv_widget.hide() # alias self.magicbox = self.bottom_panel.magicbox self.pc_panel = self.top_panel.pc_panel self.table_container = self.right_panel.table_container self.songs_table = self.right_panel.table_container self.back_btn = self.bottom_panel.back_btn self.forward_btn = self.bottom_panel.forward_btn self.toggle_video_btn = self.pc_panel.toggle_video_btn # 对部件进行一些 UI 层面的初始化 self._splitter.addWidget(self._left_panel_container) self._splitter.addWidget(self.right_panel) self.right_panel.setMinimumWidth(780) self._left_panel_container.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Expanding) self.right_panel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._layout.addWidget(self.bottom_panel) self._layout.addWidget(self._bottom_separator) self._layout.addWidget(self._splitter) self._layout.addWidget(self.mpv_widget) self._layout.addWidget(self._top_separator) self._layout.addWidget(self.top_panel) self._layout.setSpacing(0) self._layout.setContentsMargins(0, 0, 0, 0) self.top_panel.layout().setSpacing(0) self.top_panel.layout().setContentsMargins(0, 0, 0, 0) self.pc_panel.playlist_btn.clicked.connect(self.show_player_playlist) self.pc_panel.mv_btn.clicked.connect(self._play_mv) self.toggle_video_btn.clicked.connect(self._toggle_video_widget) self._app.player.video_format_changed.connect( self.on_video_format_changed) self._app.hotkey_mgr.registe( [QKeySequence('Ctrl+F'), QKeySequence(':'), QKeySequence('Alt+x')], self.magicbox.setFocus) def _play_mv(self): song = self._app.player.current_song url = song.mv.media.url_ahap self._app.player.play(url) self.show_video_widget() def show_player_playlist(self): songs = self._app.playlist.list() self.table_container.show_player_playlist(songs) def on_video_format_changed(self, vformat): if vformat is None: self.hide_video_widget() self.toggle_video_btn.hide() else: self.toggle_video_btn.show() def _toggle_video_widget(self): if self.mpv_widget.isVisible(): self.hide_video_widget() else: self.show_video_widget() def hide_video_widget(self): self.mpv_widget.hide() self._splitter.show() self.bottom_panel.show() self._bottom_separator.show() self.pc_panel.toggle_video_btn.setText('△') def show_video_widget(self): self.bottom_panel.hide() self._bottom_separator.hide() self._splitter.hide() self.mpv_widget.show() self.pc_panel.toggle_video_btn.setText('▽')
class Ui: def __init__(self, app): self._app = app self._layout = QVBoxLayout(app) self._top_separator = Separator(parent=app) self._splitter = QSplitter(app) # NOTE: 以位置命名的部件应该只用来组织界面布局,不要 # 给其添加任何功能性的函数 self.top_panel = TopPanel(app, app) self._left_panel_con = LeftPanel(self._app, ) self.left_panel = self._left_panel_con.p self.right_panel = RightPanel(self._app, self._splitter) self.bottom_panel = self.right_panel.bottom_panel self.mpv_widget = MpvOpenGLWidget(self._app) # alias self.magicbox = self.bottom_panel.magicbox self.pc_panel = self.top_panel.pc_panel self.table_container = self.right_panel.table_container # backward compatible, old name is songs_table_container self.songs_table_container = self.table_container self.songs_table = self.table_container.songs_table self.back_btn = self.bottom_panel.back_btn self.forward_btn = self.bottom_panel.forward_btn self.toggle_video_btn = self.pc_panel.toggle_video_btn self.pc_panel.playlist_btn.clicked.connect( lambda: self._app.browser.goto(uri='/player_playlist')) self.pc_panel.mv_btn.clicked.connect(self._play_mv) self.toggle_video_btn.clicked.connect(self._toggle_video) self._app.player.video_format_changed.connect( self.on_video_format_changed, aioqueue=True) self.show_video_widget() self._app.initialized.connect(lambda app: self.hide_video_widget(), weak=False) self._setup_ui() def _setup_ui(self): self._app.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self._splitter.setHandleWidth(0) self._splitter.addWidget(self._left_panel_con) self._splitter.addWidget(self.right_panel) self.right_panel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) # self._layout.addWidget(self.bottom_panel) self._layout.addWidget(self._splitter) self._layout.addWidget(self.mpv_widget) self._layout.addWidget(self._top_separator) self._layout.addWidget(self.top_panel) self._layout.setSpacing(0) self._layout.setContentsMargins(0, 0, 0, 0) self.top_panel.layout().setSpacing(0) self.top_panel.layout().setContentsMargins(0, 0, 0, 0) self._app.resize(880, 600) def _play_mv(self): song = self._app.player.current_song mv = song.mv if song else None if mv is not None: if mv.meta.support_multi_quality: media, _ = mv.select_media() else: media = mv.media self.toggle_video_btn.show() self.show_video_widget() self._app.player.play(media) def on_video_format_changed(self, vformat): """when video is available, show toggle_video_btn""" if vformat is None: self.hide_video_widget() self.toggle_video_btn.hide() else: self.toggle_video_btn.show() def _toggle_video(self): if self.mpv_widget.isVisible(): self.hide_video_widget() else: self.show_video_widget() def hide_video_widget(self): self.mpv_widget.hide() self._splitter.show() self.bottom_panel.show() self.pc_panel.toggle_video_btn.setText('△') def show_video_widget(self): self.bottom_panel.hide() self._splitter.hide() self.mpv_widget.show() self.pc_panel.toggle_video_btn.setText('▽')
class Ui: def __init__(self, app): self._app = app self._layout = QVBoxLayout(app) self._top_separator = Separator(parent=app) self._bottom_separator = Separator(parent=app) self._splitter = QSplitter(app) # NOTE: 以位置命名的部件应该只用来组织界面布局,不要 # 给其添加任何功能性的函数 self.top_panel = TopPanel(app, app) self.bottom_panel = BottomPanel(app, app) self._left_panel_con = LeftPanel(self._app,) self.left_panel = self._left_panel_con.p self.right_panel = RightPanel(self._app, self._splitter) self.mpv_widget = MpvOpenGLWidget(self._app) self.mpv_widget.hide() # alias self.magicbox = self.bottom_panel.magicbox self.pc_panel = self.top_panel.pc_panel self.table_container = self.right_panel.table_container # backward compatible, old name is songs_table_container self.songs_table_container = self.table_container self.songs_table = self.table_container.songs_table self.back_btn = self.bottom_panel.back_btn self.forward_btn = self.bottom_panel.forward_btn self.toggle_video_btn = self.pc_panel.toggle_video_btn self.pc_panel.playlist_btn.clicked.connect(self.show_player_playlist) self.pc_panel.mv_btn.clicked.connect(self._play_mv) self.toggle_video_btn.clicked.connect(self._toggle_video_widget) self._app.player.video_format_changed.connect( self.on_video_format_changed, aioqueue=True) self._app.hotkey_mgr.registe( [QKeySequence('Ctrl+F'), QKeySequence(':'), QKeySequence('Alt+x')], self.magicbox.setFocus ) self._setup_ui() def _setup_ui(self): self._app.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) self._splitter.setHandleWidth(0) self._splitter.addWidget(self._left_panel_con) self._splitter.addWidget(self.right_panel) self.right_panel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self._left_panel_con.setMinimumWidth(200) self._layout.addWidget(self.bottom_panel) self._layout.addWidget(self._bottom_separator) self._layout.addWidget(self._splitter) self._layout.addWidget(self.mpv_widget) self._layout.addWidget(self._top_separator) self._layout.addWidget(self.top_panel) self._layout.setSpacing(0) self._layout.setContentsMargins(0, 0, 0, 0) self.top_panel.layout().setSpacing(0) self.top_panel.layout().setContentsMargins(0, 0, 0, 0) def _play_mv(self): song = self._app.player.current_song mv = song.mv if song else None if mv is not None: if mv.meta.support_multi_quality: media, _ = mv.select_media() else: media = mv.media self._app.player.play(media) self.show_video_widget() def show_player_playlist(self): self.table_container.show_player_playlist() def on_video_format_changed(self, vformat): if vformat is None: self.hide_video_widget() self.toggle_video_btn.hide() else: self.toggle_video_btn.show() def _toggle_video_widget(self): if self.mpv_widget.isVisible(): self.hide_video_widget() else: self.show_video_widget() def hide_video_widget(self): self.mpv_widget.hide() self._splitter.show() self.bottom_panel.show() self._bottom_separator.show() self.pc_panel.toggle_video_btn.setText('△') def show_video_widget(self): self.bottom_panel.hide() self._bottom_separator.hide() self._splitter.hide() self.mpv_widget.show() self.pc_panel.toggle_video_btn.setText('▽')
class POSM(QMainWindow): def __init__(self): super().__init__() self.setLocale(QLocale(QLocale.English)) self.initUI() self.setAttribute(Qt.WA_AlwaysShowToolTips) sizegrip = QtWidgets.QSizeGrip(self) self.layout.addWidget(sizegrip, 0, QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight) self.record = [None] recordAction = QAction(datetime.datetime.now().strftime('%H:%M:%S'), self) recordAction.triggered.connect(lambda: self.changeMap(0)) self.recordMenu.addAction(recordAction) def initUI(self): self.layout = QHBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.console = InformationalConsole(app) self.horSplitter = QSplitter(Qt.Horizontal) self.horSplitter.setChildrenCollapsible(False) self.editionSplitter = QSplitter(Qt.Vertical) self.editionSplitter.setChildrenCollapsible(False) self.queryUI = QueryUI() self.queryUI.setOnRequestChanged(self.changeCurrentMap) self.editionSplitter.addWidget(self.queryUI) self.queryWidget = QWidget() self.queryWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) self.queryWidget.setLayout(QVBoxLayout()) self.queryWidget.layout().setContentsMargins(0, 0, 0, 0) self.queryWidget.layout().setSpacing(0) self.queryHeader = QLabel("Query") self.queryHeader.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.queryHeader.setFixedHeight(self.queryHeader.sizeHint().height() + 10) self.queryHeader.setContentsMargins(5, 5, 0, 5) self.queryWidget.layout().addWidget(self.queryHeader) self.queryText = CodeEditor() self.qlHighlighter = OverpassQLHighlighter(self.queryText.document()) self.queryText.setReadOnly(True) self.queryWidget.layout().addWidget(self.queryText) self.editionSplitter.addWidget(self.queryWidget) self.horSplitter.addWidget(self.editionSplitter) self.emptyMapPage = QWebEnginePage() self.emptyMapPage.setHtml(EMPTY_HTML) self.manualModePage = QWebEnginePage() soup = bs4.BeautifulSoup(EMPTY_HTML, features="html.parser") js = soup.new_tag("script") js.string = (MANUAL_MODE_JS_SCRIPT % (str([]))) soup.append(js) self.manualModePage.setHtml(str(soup)) self.mapRenderer = QWebEngineView() self.mapRenderer.setMinimumWidth(500) self.mapRenderer.setPage(self.emptyMapPage) self.consoleSplitter = QSplitter(Qt.Vertical) self.consoleSplitter.setChildrenCollapsible(False) self.consoleSplitter.addWidget(self.mapRenderer) self.consoleWidget = QWidget() self.consoleWidget.setLayout(QVBoxLayout()) self.consoleWidget.layout().setContentsMargins(0, 0, 0, 0) self.consoleWidget.layout().setSpacing(0) self.consoleHeader = QLabel("Console") self.consoleHeader.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.consoleHeader.setContentsMargins(5, 5, 0, 5) self.consoleWidget.layout().addWidget(self.consoleHeader) self.consoleWidget.layout().addWidget(self.console) self.consoleSplitter.addWidget(self.consoleWidget) self.horSplitter.addWidget(self.consoleSplitter) self.layout.addWidget(self.horSplitter) self.initMenuBar() centralWidget = QWidget(self) centralWidget.setLayout(self.layout) self.setCentralWidget(centralWidget) self.setWindowTitle('Python Open Street Map') def initMenuBar(self): menubar = self.menuBar() fileMenu = menubar.addMenu('File') openAct = QAction('Open netedit', self) openAct.triggered.connect(self.openNet) fileMenu.addAction(openAct) saveMenu = fileMenu.addMenu("Save") saveOutputAct = QAction('output', self) saveOutputAct.triggered.connect(self.saveNet) saveOutputAct.setShortcut('Ctrl+S') saveMenu.addAction(saveOutputAct) saveQueryAct = QAction('query', self) saveQueryAct.triggered.connect(self.saveQuery) saveQueryAct.setShortcut('Ctrl+Shift+S') saveMenu.addAction(saveQueryAct) saveInteractiveModeAct = QAction('interactive mode', self) saveInteractiveModeAct.triggered.connect(self.saveInteractiveQuery) saveMenu.addAction(saveInteractiveModeAct) openMenu = fileMenu.addMenu("Open") openQuery = QAction('query', self) openQuery.triggered.connect(self.openQuery) openQuery.setShortcut('Ctrl+O') openMenu.addAction(openQuery) openInteractiveMode = QAction('interactive mode', self) openInteractiveMode.triggered.connect(self.openInteractiveQuery) openMenu.addAction(openInteractiveMode) self.recordMenu = openMenu.addMenu("record") runMenu = menubar.addMenu('Run') playAct = QAction('Play', self) playAct.triggered.connect(self.playQuery) playAct.setShortcut('Ctrl+P') runMenu.addAction(playAct) playTableRowAct = QAction('Play row selection', self) playTableRowAct.triggered.connect(self.playTableRow) playTableRowAct.setShortcut('Ctrl+T') runMenu.addAction(playTableRowAct) self.requestMenu = menubar.addMenu('Request') addRequestAct = QAction('Add request', self) addRequestAct.triggered.connect(lambda b: self.addRequest()) addRequestAct.setShortcut('Ctrl+A') self.requestMenu.addAction(addRequestAct) templatesMenu = self.requestMenu.addMenu("Add template") addRoadAct = QAction('Roads', self) addRoadAct.triggered.connect(lambda: self.addTemplate([ OverpassFilter("highway", TagComparison.EQUAL, "", False, True), OverpassFilter("name", TagComparison.EQUAL, "", False, True), OverpassFilter("ref", TagComparison.EQUAL, "", False, True), OverpassFilter("maxspeed", TagComparison.AT_MOST, "120", False, False), OverpassFilter("lanes", TagComparison.EQUAL, "", False, True), OverpassFilter("oneway", TagComparison.EQUAL, "", False, True) ])) templatesMenu.addAction(addRoadAct) addMainRoadAct = QAction('Main roads', self) mainHighways = "^(motorway|trunk|primary|secondary|residential)(_link)?$" everythingButYes = "^(y(e([^s]|$|s.)|[^e]|$)|[^y]|$).*" addMainRoadAct.triggered.connect(lambda: self.addTemplate([ OverpassFilter("highway", TagComparison.EQUAL, mainHighways, False, False), OverpassFilter("construction", TagComparison.HAS_NOT_KEY, "", False, False), OverpassFilter("noexit", TagComparison.EQUAL, "yes", True, True), OverpassFilter("access", TagComparison.EQUAL, everythingButYes, True, False) ])) templatesMenu.addAction(addMainRoadAct) addParkingAct = QAction('Parking', self) addParkingAct.triggered.connect(lambda: self.addTemplate([ OverpassFilter("service", TagComparison.EQUAL, "parking", False, False), OverpassFilter("highway", TagComparison.HAS_KEY, "", False, True) ])) templatesMenu.addAction(addParkingAct) addPedestriansAct = QAction('Pedestrians', self) pedestrianHighway = [ "pedestrian", "footway", "path", "cycleway", "bridleway", "steps", "crossing" ] addPedestriansAct.triggered.connect(lambda: self.addTemplate([ OverpassFilter("highway", TagComparison.IS_ONE_OF, pedestrianHighway, False, True) ])) templatesMenu.addAction(addPedestriansAct) removeRequestAct = QAction('Remove current request', self) removeRequestAct.triggered.connect(self.removeRequest) removeRequestAct.setShortcut('Ctrl+R') self.requestMenu.addAction(removeRequestAct) self.manualModeAct = QAction( 'Switch between interactive and manual mode', self) self.manualModeAct.triggered.connect(self.switchManualMode) self.requestMenu.addAction(self.manualModeAct) self.manualModeMenu = menubar.addMenu('Manual mode') self.manualModeMenu.setEnabled(False) manualModeCleanPolygonAct = QAction('Clean polygon', self) manualModeCleanPolygonAct.triggered.connect( self.cleanManualModePolygon) self.manualModeMenu.addAction(manualModeCleanPolygonAct) manualModeGetPolygonAct = QAction('Polygon coordinates', self) manualModeGetPolygonAct.triggered.connect( lambda: self.manualModePage.runJavaScript( "getPolygons();", self.logManualModePolygonCoords)) self.manualModeMenu.addAction(manualModeGetPolygonAct) windowsMenu = menubar.addMenu('Windows') cleanMapAct = QAction('Clean map', self) cleanMapAct.triggered.connect(self.cleanMap) windowsMenu.addAction(cleanMapAct) self.showHideInteractiveModeAct = QAction('Interactive mode', self) self.showHideInteractiveModeAct.triggered.connect( self.showHideInteractiveMode) windowsMenu.addAction(self.showHideInteractiveModeAct) showHideConsole = QAction('Console', self) showHideConsole.triggered.connect(self.showHideConsole) windowsMenu.addAction(showHideConsole) showHideQuery = QAction('Query', self) showHideQuery.triggered.connect(self.showHideQuery) windowsMenu.addAction(showHideQuery) # ACTIONS def cleanMap(self): if self.queryText.isReadOnly(): if self.queryUI.getCurrentMap() is not None: self.mapRenderer.setPage(self.queryUI.updateMaps(EMPTY_HTML)) else: soup = bs4.BeautifulSoup(EMPTY_HTML, features="html.parser") js = soup.new_tag("script") js.string = (MANUAL_MODE_JS_SCRIPT % (str([]))) soup.append(js) self.manualModePage.setHtml(str(soup)) logging.info("Cleaning map") def changeMap(self, i): if i == 0: if not self.queryText.isReadOnly(): self.switchManualMode() if self.queryText.isReadOnly(): self.queryUI.reset() self.queryText.clear() self.mapRenderer.setPage(self.emptyMapPage) self.queryUI.updateMaps(EMPTY_HTML) elif self.record[i]["interactiveMode"]: if not self.queryText.isReadOnly(): self.switchManualMode() if self.queryText.isReadOnly(): self.queryUI.setQuery(self.record[i]["query"]) self.queryText.setPlainText(self.record[i]["query"].getQL()) self.mapRenderer.setPage( self.queryUI.updateMaps(self.record[i]["html"])) else: if self.queryText.isReadOnly(): self.switchManualMode() if not self.queryText.isReadOnly(): self.queryUI.reset() self.queryText.setPlainText(self.record[i]["query"]) self.manualModePage.setHtml(self.record[i]["html"]) self.mapRenderer.setPage(self.manualModePage) def logManualModePolygonCoords(self, coords): coordsString = " ".join([str(c) for point in coords for c in point]) logging.info("Polygon coordinates:\"{}\"".format(coordsString)) pyperclip.copy(coordsString) logging.debug("LINE") def cleanManualModePolygon(self): logging.info("Cleaning polygon.") self.manualModePage.runJavaScript( "cleanPolygon();", lambda returnValue: logging.debug("LINE")) def showHideInteractiveMode(self): if self.queryUI.isHidden(): if self.editionSplitter.isHidden(): self.editionSplitter.show() self.queryText.hide() self.queryUI.show() logging.info("Showing 'Interactive mode' window.") else: if self.queryText.isHidden(): self.editionSplitter.hide() self.queryUI.hide() logging.info("Hiding 'Interactive mode' window.") logging.debug("LINE") def showHideConsole(self): if self.console.isHidden(): self.console.show() logging.info("Showing 'Console' window.") self.consoleWidget.setMaximumHeight(QWIDGETSIZE_MAX) else: self.console.hide() self.consoleWidget.setMaximumHeight( self.queryHeader.sizeHint().height()) logging.info("Hiding 'Console' window.") logging.debug("LINE") def showHideQuery(self): if self.queryText.isHidden(): if self.editionSplitter.isHidden(): self.editionSplitter.show() self.queryUI.hide() self.queryText.show() logging.info("Showing 'Query' window.") self.queryWidget.setMaximumHeight(QWIDGETSIZE_MAX) else: if self.queryUI.isHidden(): self.editionSplitter.hide() self.queryText.hide() self.queryWidget.setMaximumHeight( self.queryHeader.sizeHint().height()) logging.info("Hiding 'Query' window.") logging.debug("LINE") def switchManualMode(self): if self.queryText.isReadOnly(): reply = QMessageBox.question( self, "Manual mode", "Are you sure?\nThe interactive mode will remain as it is now." ) if reply == QMessageBox.Yes: self.queryText.setReadOnly(False) self.queryUI.hide() for action in self.requestMenu.actions(): action.setEnabled(False) self.manualModeAct.setEnabled(True) self.manualModeMenu.setEnabled(True) self.showHideInteractiveModeAct.setEnabled(False) self.mapRenderer.setPage(self.manualModePage) logging.info("Switching to manual mode.") else: logging.info( "'Switch between interactive and manual mode' cancelled.") else: reply = QMessageBox.question( self, "Interactive mode", "Are you sure?\nThe current query will be removed.") if reply == QMessageBox.Yes: try: self.queryText.clear() self.queryText.setPlainText( self.queryUI.getQuery().getQL()) except BadFilterAttributes as e: logging.error(str(e)) except RuntimeError: logging.warning("Failed to write query.") self.queryText.clear() self.queryText.setPlainText("") self.queryText.setReadOnly(True) self.queryUI.show() for action in self.requestMenu.actions(): action.setEnabled(True) self.manualModeMenu.setEnabled(False) self.showHideInteractiveModeAct.setEnabled(True) self.changeCurrentMap(0) logging.info("Switching to interactive mode.") else: logging.info( "'Switch between interactive and manual mode' cancelled.") logging.info("Showing 'manual mode' polygon.") def addRequest(self, filters=None): self.queryUI.addRequestByFilters(filters) logging.info("Request added.") logging.debug("LINE") def addTemplate(self, filters): logging.info("Template applied.") self.queryUI.addRequestByFilters(filters) def removeRequest(self): reply = QMessageBox.question( self, "Remove current request", "Are you sure? This option is not undoable.") if reply == QMessageBox.Yes: self.queryUI.removeRequest() logging.info("'Remove request' successfully executed.") else: logging.info("'Remove request' cancelled.") logging.debug("LINE") def saveQuery(self): filename, selectedFilter = QFileDialog.getSaveFileName( self, 'Save query', expanduser("~/filename.txt"), "Text files (*.txt)") if filename != "": if self.queryText.isReadOnly(): try: query = self.queryUI.getQuery().getQL() f = open(filename, "w+") f.seek(0) f.truncate() f.write(query) f.close() logging.info("Query saved successfully.") except (RuntimeError, BadFilterAttributes) as e: logging.error(str(e)) except OSError: logging.error( "There was a problem creating the file with the query." ) else: try: f = open(filename, "w+") f.seek(0) f.truncate() f.write(self.queryText.toPlainText()) f.close() logging.info("Query saved successfully.") except OSError: logging.error( "There was a problem creating the file with the query." ) else: logging.info("\"Save query\" canceled.") logging.debug("LINE") def openQuery(self): filename, selectedFilter = QFileDialog.getOpenFileName( self, 'Open query', expanduser("~/filename.txt")) if filename != "": try: if self.queryText.isReadOnly(): self.switchManualMode() f = open(filename, "r") self.queryText.clear() self.queryText.setPlainText(f.read()) f.close() logging.info("File read successfully.") except UnicodeDecodeError: logging.error("The given file is not readable as text.") except OSError: logging.error("There was a problem opening the query file.") else: logging.info("\"Open query\" canceled.") logging.debug("LINE") def saveInteractiveQuery(self): filename, selectedFilter = QFileDialog.getSaveFileName( self, 'Save query', expanduser("~/filename.json"), "JSON files (*.json)") if filename != "": try: query = self.queryUI.getQuery() query.saveToFile(filename) logging.info("Query saved successfully.") except (RuntimeError, BadFilterAttributes) as e: logging.error(str(e)) except OSError: logging.error( "There was a problem creating the file with the query.") else: logging.info("\"Save query\" canceled.") logging.debug("LINE") def openInteractiveQuery(self): filename, selectedFilter = QFileDialog.getOpenFileName( self, 'Open query', expanduser("~/filename.json")) if filename != "": try: self.queryUI.setQuery(OverpassQuery.getFromFile(filename)) if not self.queryText.isReadOnly(): self.switchManualMode() except json.decoder.JSONDecodeError: logging.error( "The given file has not the right format (json). The file could not be opened." ) except UnicodeDecodeError: logging.error( "The given file is not readable as text. The file could not be opened." ) except (TypeError, KeyError): logging.error( "Fields are missing from the file or there are fields with the wrong data type. " "The file could not be opened.") except OSError: logging.error( "There was a problem opening the query file. The file could not be opened." ) else: logging.info("\"Open query\" canceled.") logging.debug("LINE") def saveNet(self): filename, selectedFilter = QFileDialog.getSaveFileName( self, 'Save File', expanduser("~/filenameWithoutExtension")) if filename != "": buildNet(filename) else: logging.info("\"Save File\" canceled.") logging.debug("LINE") return filename def openNet(self): try: filename = self.saveNet() if filename == "": logging.error("Can't open NETEDIT without a file.") else: openNetedit(filename + ".net.xml") logging.info("Opening NETEDIT.") logging.warning( "If NETEDIT is not open in ten seconds, there was an unhandled problem." ) logging.debug("LINE") except OSError: logging.error("Can't find NETEDIT.") except Exception: logging.error(traceback.format_exc()) # POLYGONS def changeCurrentMap(self, i): if self.queryUI.getCurrentMap() is None: self.mapRenderer.setPage(self.emptyMapPage) else: self.mapRenderer.setPage(self.queryUI.getCurrentMap()) def playQuery(self): newRecord = { "interactiveMode": self.queryText.isReadOnly(), "query": self.queryText.toPlainText(), "html": "" } if self.queryText.isReadOnly(): try: query = self.queryUI.getQuery() newRecord["query"] = query self.queryText.setPlainText(query.getQL()) except (RuntimeError, BadFilterAttributes) as e: logging.error(str(e)) return try: html = buildHTMLWithQuery(self.queryText.toPlainText()) if self.queryText.isReadOnly(): self.mapRenderer.setPage(self.queryUI.updateMaps(html)) newRecord["html"] = html else: soup = bs4.BeautifulSoup(html, features="html.parser") js = soup.new_tag("script") js.string = (MANUAL_MODE_JS_SCRIPT % (str([]))) soup.append(js) self.manualModePage.setHtml(str(soup)) newRecord["html"] = str(soup) self.mapRenderer.setPage(self.manualModePage) logging.info("Query drawn.") logging.debug("LINE") self.addRecord(newRecord) except (OverpassRequestException, OsmnxException) as e: logging.error(str(e)) except ox.EmptyOverpassResponse: logging.error("There are no elements with the given query.") except OSError: logging.error( "There was a problem creating the file with the request response." ) except Exception: logging.error(traceback.format_exc()) def addRecord(self, newRecord): self.record.append(newRecord) index = len(self.record) - 1 recordAction = QAction(datetime.datetime.now().strftime('%H:%M:%S'), self) recordAction.triggered.connect(lambda: self.changeMap(index)) self.recordMenu.addAction(recordAction) def playTableRow(self): try: self.mapRenderer.setPage(self.queryUI.updateMapFromRow()) except (OverpassRequestException, OsmnxException) as e: logging.error(str(e)) logging.warning( "Before open NETEDIT you must run a query with the row filters applied." ) except ox.EmptyOverpassResponse: logging.error("There are no elements with the given row.") except OSError: logging.error( "There was a problem creating the file with the row selection." ) except RuntimeError as e: logging.error(str(e)) except Exception: logging.error(traceback.format_exc()) logging.debug("LINE") # EVENTS def closeEvent(self, event): for f in os.listdir(tempDir): os.remove(os.path.join(tempDir, f)) QMainWindow.closeEvent(self, event)