def _addActionScript(self, filename): icon = QgsApplication.getThemeIcon('processingScript.svg') title = os.path.split(filename)[-1] action = QAction(icon, title, self.iface.mainWindow()) action.setToolTip(filename) action.triggered.connect(self.run) m = self.toolButton.menu() m.addAction(action) self.actionsScript.append(action)
def add_action( self, ico_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None, ): """Add a toolbar icon to the toolbar. :param str icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :param str text: Text that should be shown in menu items for this action. :param function callback: Function to be called when the action is triggered. :param bool enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :param bool add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :param bool add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :param str status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :param QWidget parent: Parent widget for the new action. Defaults None. :param str whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ ico = QIcon(ico_path) action = QAction(ico, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) action.setToolTip("Isogeo (v{})".format(self.plg_version)) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToWebMenu(self.menu, action) self.actions.append(action) return action
def createMenu(self): self.menu.clear() self.menu.setMinimumWidth(self.width()) fill_down_action = QAction(self.tr('Fill Down'), self.menu) fill_down_action.triggered.connect(self.fillDown) fill_down_action.setToolTip(self.tr('Copy the first value down to all other rows')) self.menu.addAction(fill_down_action) calculate_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Calculate by Expression…'), self.menu) calculate_by_expression.setIcon(QgsApplication.getThemeIcon('/mActionCalculateField.svg')) calculate_by_expression.triggered.connect(self.calculateByExpression) calculate_by_expression.setToolTip(self.tr('Calculates parameter values by evaluating an expression')) self.menu.addAction(calculate_by_expression) add_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Add Values by Expression…'), self.menu) add_by_expression.triggered.connect(self.addByExpression) add_by_expression.setToolTip(self.tr('Adds new parameter values by evaluating an expression')) self.menu.addAction(add_by_expression) if isinstance(self.parameterDefinition, (QgsProcessingParameterFile, QgsProcessingParameterMapLayer, QgsProcessingParameterRasterLayer, QgsProcessingParameterMeshLayer, QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource)): self.menu.addSeparator() find_by_pattern_action = QAction(QCoreApplication.translate('BatchPanel', 'Add Files by Pattern…'), self.menu) find_by_pattern_action.triggered.connect(self.addFilesByPattern) find_by_pattern_action.setToolTip(self.tr('Adds files by a file pattern match')) self.menu.addAction(find_by_pattern_action)
def createMenu(self): self.menu.clear() self.menu.setMinimumWidth(self.width()) fill_down_action = QAction(self.tr('Fill Down'), self.menu) fill_down_action.triggered.connect(self.fillDown) fill_down_action.setToolTip(self.tr('Copy the first value down to all other rows')) self.menu.addAction(fill_down_action) calculate_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Calculate by Expression…'), self.menu) calculate_by_expression.setIcon(QgsApplication.getThemeIcon('/mActionCalculateField.svg')) calculate_by_expression.triggered.connect(self.calculateByExpression) calculate_by_expression.setToolTip(self.tr('Calculates parameter values by evaluating an expression')) self.menu.addAction(calculate_by_expression) add_by_expression = QAction(QCoreApplication.translate('BatchPanel', 'Add Values by Expression…'), self.menu) add_by_expression.triggered.connect(self.addByExpression) add_by_expression.setToolTip(self.tr('Adds new parameter values by evaluating an expression')) self.menu.addAction(add_by_expression) if isinstance(self.parameterDefinition, (QgsProcessingParameterFile, QgsProcessingParameterMapLayer, QgsProcessingParameterRasterLayer, QgsProcessingParameterMeshLayer, QgsProcessingParameterVectorLayer, QgsProcessingParameterFeatureSource)): self.menu.addSeparator() find_by_pattern_action = QAction(QCoreApplication.translate('BatchPanel', 'Add Files by Pattern…'), self.menu) find_by_pattern_action.triggered.connect(self.addFilesByPattern) find_by_pattern_action.setToolTip(self.tr('Adds files by a file pattern match')) self.menu.addAction(find_by_pattern_action)
class NavToolbar(NavigationToolbar): updateRequested = pyqtSignal() def __init__(self, canvas, parent=None): NavigationToolbar.__init__(self, canvas, parent) # add toolbutton to change fonts/colors self.fontColorAction = QAction( QIcon(":/pstimeseries_plugin/icons/settings"), "Change fonts and colors", self ) self.fontColorAction.setToolTip( "Change fonts and colors" ) self.insertAction(self.homeAction, self.fontColorAction) self.fontColorAction.triggered.connect(self.openFontColorSettings) self.insertSeparator(self.homeAction) def openFontColorSettings(self): dlg = GraphSettings_Dlg(self) if dlg.exec_(): self.updateRequested.emit()
class NavToolbar(NavigationToolbar): updateRequested = pyqtSignal() def __init__(self, canvas, parent=None): NavigationToolbar.__init__(self, canvas, parent) # add toolbutton to change fonts/colors self.fontColorAction = QAction( QIcon(":/pstimeseries_plugin/icons/settings"), "Change fonts and colors", self) self.fontColorAction.setToolTip("Change fonts and colors") self.insertAction(self.homeAction, self.fontColorAction) self.fontColorAction.triggered.connect(self.openFontColorSettings) self.insertSeparator(self.homeAction) def openFontColorSettings(self): dlg = GraphSettings_Dlg(self) if dlg.exec_(): self.updateRequested.emit()
def testTooltip(self): """" test action tooltips """ action1 = QAction('action1', None) action1.setToolTip('my tooltip') action2 = QAction('action2', None) action2.setToolTip('my multiline\ntooltip') action3 = QAction('action3', None) action3.setToolTip('my tooltip (Ctrl+S)') s = QgsShortcutsManager(None) s.registerAction(action1) s.registerAction(action2) s.registerAction(action3, 'Ctrl+S') self.assertEqual(action1.toolTip(), '<b>my tooltip</b>') self.assertEqual(action2.toolTip(), '<b>my multiline</b><p>tooltip</p>') self.assertEqual(action3.toolTip(), '<b>my tooltip </b> (Ctrl+S)')
class XYZHubConnector(object): """base plugin""" def __init__(self, iface): """init""" import sys print(sys.version) self.iface = iface self.web_menu = "&{name}".format(name=config.PLUGIN_FULL_NAME) self.hasGuiInitialized = False self.init_modules() self.obj = self def initGui(self): """startup""" parent = self.iface.mainWindow() ######## action, button icon = QIcon("%s/%s" % (config.PLUGIN_DIR,"images/xyz.png")) icon_bbox = QIcon("%s/%s" % (config.PLUGIN_DIR,"images/bbox.svg")) self.action_connect = QAction(icon, "XYZ Hub Connection", parent) self.action_connect.setWhatsThis( QCoreApplication.translate(PLUGIN_NAME, "WhatsThis message" )) self.action_connect.setStatusTip( QCoreApplication.translate(PLUGIN_NAME, "status tip message" )) self.action_sync_edit = QAction( QIcon("%s/%s" % (config.PLUGIN_DIR,"images/sync.svg")), "Push changes to XYZ Hub", parent) self.action_clear_cache = QAction( QIcon("%s/%s" % (config.PLUGIN_DIR,"images/delete.svg")), "Clear cache", parent) # self.action_sync_edit.setVisible(False) # disable magic sync self.edit_buffer.config_ui(self.enable_sync_btn) self.cb_layer_selected(self.iface.activeLayer()) ######## CONNECT action, button self.action_connect.triggered.connect(self.open_connection_dialog) self.action_sync_edit.triggered.connect(self.open_sync_edit_dialog) self.action_clear_cache.triggered.connect( self.open_clear_cache_dialog) ######## Add the toolbar + button self.toolbar = self.iface.addToolBar(PLUGIN_NAME) self.toolbar.setObjectName(config.PLUGIN_FULL_NAME) self.actions_menu = [self.action_connect, self.action_sync_edit, self.action_clear_cache] for a in [self.action_connect, self.action_sync_edit]: self.toolbar.addAction(a) for a in self.actions_menu: self.iface.addPluginToWebMenu(self.web_menu, a) # # uncomment to use menu button # tool_btn = QToolButton(self.toolbar) # tool_btn.setDefaultAction(self.action_connect) # tool_btn.setPopupMode(tool_btn.MenuButtonPopup) # self.xyz_widget_action = self.toolbar.addWidget(tool_btn) # uncomment to use menu button # self.toolbar.addAction(self.action_connect) self.action_help = None progress = QProgressBar() progress.setMinimum(0) progress.setMaximum(0) progress.reset() progress.hide() # progress = self.iface.statusBarIface().children()[2] # will be hidden by qgis self.iface.statusBarIface().addPermanentWidget(progress) self.pb = progress # btn_toggle_edit = self.get_btn_toggle_edit() # btn_toggle_edit.toggled.connect(lambda *a: print("toggled", a)) self.hasGuiInitialized = True # unused def get_btn_toggle_edit(self): text_toggle_edit = "toggle editing" toolbar = self.iface.digitizeToolBar() mapping = dict( (w.text().lower() if hasattr(w,"text") else str(i), w) for i, w in enumerate(toolbar.children()) ) return mapping[text_toggle_edit] def new_session(self): self.con_man.reset() self.edit_buffer.reset() self.pending_delete_qnodes.clear() if self.hasGuiInitialized: self.pb.hide() def init_modules(self): if LOG_TO_FILE: QgsApplication.messageLog().messageReceived.connect(cb_log_qgis) #, Qt.QueuedConnection connect_global_error_signal(self.log_err_traceback) # util.init_module() # parent = self.iface.mainWindow() parent = QgsProject.instance() self.secret = Secret(config.USER_PLUGIN_DIR +"/secret.ini") ######## Init xyz modules self.map_basemap_meta = basemap.load_default_xml() self.auth_manager = AuthManager(config.USER_PLUGIN_DIR +"/auth.ini") self.network = NetManager(parent) self.con_man = LoaderManager() self.con_man.config(self.network) self.edit_buffer = EditBuffer() ######## data flow # self.conn_info = SpaceConnectionInfo() ######## token self.token_config = ServerTokenConfig(config.USER_PLUGIN_DIR +"/token.ini", parent) self.token_config.set_default_servers(net_utils.API_URL) self.token_model = self.token_config.get_token_model() self.server_model = self.token_config.get_server_model() ######## CALLBACK self.con_man.ld_pool.signal.progress.connect( self.cb_progress_busy) #, Qt.QueuedConnection self.con_man.ld_pool.signal.finished.connect( self.cb_progress_done) QgsProject.instance().cleared.connect(self.new_session) QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.edit_buffer.remove_layers) # QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.layer_man.remove_layers) # QgsProject.instance().layersAdded.connect( self.edit_buffer.config_connection) self.iface.currentLayerChanged.connect( self.cb_layer_selected) # UNCOMMENT canvas = self.iface.mapCanvas() self.lastRect = bbox_utils.extent_to_rect(bbox_utils.get_bounding_box(canvas)) self.iface.mapCanvas().extentsChanged.connect( self.reload_tile, Qt.QueuedConnection) # handle move, delete xyz layer group self.pending_delete_qnodes = dict() QgsProject.instance().layerTreeRoot().willRemoveChildren.connect(self.cb_qnodes_deleting) QgsProject.instance().layerTreeRoot().removedChildren.connect(self.cb_qnodes_deleted) QgsProject.instance().layerTreeRoot().visibilityChanged.connect(self.cb_qnode_visibility_changed) QgsProject.instance().readProject.connect( self.import_project) self.import_project() def unload_modules(self): # self.con_man.disconnect_ux( self.iface) QgsProject.instance().cleared.disconnect(self.new_session) QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.edit_buffer.remove_layers) # QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.layer_man.remove_layers) # QgsProject.instance().layersAdded.disconnect( self.edit_buffer.config_connection) self.edit_buffer.unload_connection() self.con_man.unload() self.iface.currentLayerChanged.disconnect( self.cb_layer_selected) # UNCOMMENT self.iface.mapCanvas().extentsChanged.disconnect( self.reload_tile) QgsProject.instance().layerTreeRoot().willRemoveChildren.disconnect(self.cb_qnodes_deleting) QgsProject.instance().layerTreeRoot().removedChildren.disconnect(self.cb_qnodes_deleted) QgsProject.instance().layerTreeRoot().visibilityChanged.disconnect(self.cb_qnode_visibility_changed) QgsProject.instance().readProject.disconnect( self.import_project) # utils.disconnect_silent(self.iface.currentLayerChanged) self.secret.deactivate() disconnect_global_error_signal() if LOG_TO_FILE: QgsApplication.messageLog().messageReceived.disconnect(cb_log_qgis) # close_file_logger() pass def unload(self): """teardown""" self.unload_modules() # remove the plugin menu item and icon self.iface.removePluginWebMenu(self.web_menu, self.action_help) self.toolbar.clear() # remove action from custom toolbar (toolbar still exist) self.toolbar.deleteLater() for a in self.actions_menu: self.iface.removePluginWebMenu(self.web_menu, a) # remove progress self.iface.statusBarIface().removeWidget(self.pb) ############### # Callback ############### def cb_layer_selected(self, qlayer): flag_xyz = True if qlayer is not None and is_xyz_supported_layer(qlayer) else False if flag_xyz: self.edit_buffer.config_connection([qlayer]) self.edit_buffer.enable_ui(qlayer.id()) else: msg = "No XYZHub Layer selected" self.enable_sync_btn(False, msg) # disable magic sync # self.action_sync_edit.setEnabled(flag_xyz) def enable_sync_btn(self, flag, msg=""): msg = msg or ("No changes detected since last push" if not flag else "Push changes") self.action_sync_edit.setToolTip(msg) self.action_sync_edit.setEnabled(flag) ############### # Callback of action (main function) ############### def show_info_msgbar(self, title, msg="", dt=3): self.iface.messageBar().pushMessage( config.TAG_PLUGIN, ": ".join([title,msg]), Qgis.Info, dt ) def show_warning_msgbar(self, title, msg="", dt=3): self.iface.messageBar().pushMessage( config.TAG_PLUGIN, ": ".join([title,msg]), Qgis.Warning, dt ) def show_success_msgbar(self, title, msg="", dt=3): self.iface.messageBar().pushMessage( config.TAG_PLUGIN, ": ".join([title,msg]), Qgis.Success, dt ) def make_cb_success(self, title, msg="", dt=3): def _cb_success_msg(): self.show_success_msgbar(title, msg, dt=dt) return _cb_success_msg def make_cb_success_args(self, title, msg="", dt=3): def _cb_success_msg(args): a, kw = parse_qt_args(args) txt = ". ".join(map(str,a)) self.show_success_msgbar(title, txt, dt=dt) return _cb_success_msg def make_cb_info_args(self, title, msg="", dt=3): def _cb_info_msg(args): a, kw = parse_qt_args(args) txt = ". ".join(map(str,a)) self.show_info_msgbar(title, txt, dt=dt) return _cb_info_msg def cb_handle_error_msg(self, e): err = parse_exception_obj(e) if isinstance(err, ChainInterrupt): e0, idx = err.args[0:2] else: e0 = err if isinstance(e0, (net_handler.NetworkError, net_handler.NetworkTimeout)): ok = self.show_net_err(e0) if ok: return elif isinstance(e0, EmptyXYZSpaceError): ret = exec_warning_dialog("XYZ Hub","Requested query returns no features") return elif isinstance(e0, ManualInterrupt): self.log_err_traceback(e0) return self.show_err_msgbar(err) def show_net_err(self, err): reply_tag, status, reason, body, err_str, url = err.args[:6] if reply_tag in ["count", "statistics"]: # too many error # msg = "Network Error: %s: %s. %s"%(status, reason, err_str) return 1 detail = "\n". join(["Request:", url,"","Response:", body]) msg = ( "%s: %s\n"%(status,reason) + "There was a problem connecting to the server" ) if status in [401,403]: msg += ("\n\n" + "Please input valid token with correct permissions." + "\n" + "Token is generated via " + "<a href='https://xyz.api.here.com/token-ui/'>https://xyz.api.here.com/token-ui/</a>") ret = exec_warning_dialog("Network Error",msg, detail) return 1 def show_err_msgbar(self, err): self.iface.messageBar().pushMessage( config.TAG_PLUGIN, repr(err), Qgis.Warning, 3 ) self.log_err_traceback(err) def log_err_traceback(self, err): msg = format_traceback(err) QgsMessageLog.logMessage( msg, config.TAG_PLUGIN, Qgis.Warning) def cb_progress_busy(self, n_active): if n_active > 1: return self.flag_pb_show=True self.cb_progress_refresh() def cb_progress_done(self): self.flag_pb_show=False self.cb_progress_refresh() def cb_progress_refresh(self): if not hasattr(self,"flag_pb_show"): return pb = self.pb if self.flag_pb_show: pb.show() # print_qgis("show",pb) else: pb.hide() # print_qgis("hide") ############### # Action (main function) ############### # UNUSED def refresh_canvas(self): # self.iface.activeLayer().triggerRepaint() self.iface.mapCanvas().refresh() def previous_canvas_extent(self): self.iface.mapCanvas().zoomToPreviousExtent() # def new_main_dialog(self): parent = self.iface.mainWindow() dialog = MainDialog(parent) dialog.config(self.token_model, self.server_model) # dialog.config_secret(self.secret) auth = self.auth_manager.get_auth() dialog.config_basemap(self.map_basemap_meta, auth) con = self.con_man.make_con("create") con.signal.finished.connect( dialog.btn_use.clicked.emit ) # can be optimized !! con.signal.error.connect( self.cb_handle_error_msg ) con = self.con_man.make_con("list") con.signal.results.connect( make_fun_args(dialog.cb_display_spaces) ) con.signal.error.connect( self.cb_handle_error_msg ) con.signal.error.connect( lambda e: dialog.cb_enable_token_ui() ) con.signal.finished.connect( dialog.cb_enable_token_ui ) con.signal.finished.connect( dialog.ui_valid_token ) con = self.con_man.make_con("edit") con.signal.finished.connect( dialog.btn_use.clicked.emit ) con.signal.error.connect( self.cb_handle_error_msg ) con = self.con_man.make_con("delete") con.signal.results.connect( dialog.btn_use.clicked.emit ) con.signal.error.connect( self.cb_handle_error_msg ) con = self.con_man.make_con("stat") con.signal.results.connect( make_fun_args(dialog.cb_display_space_count) ) con.signal.error.connect( self.cb_handle_error_msg ) ############ clear cache btn dialog.signal_clear_cache.connect( self.open_clear_cache_dialog) ############ add map tile btn dialog.signal_add_basemap.connect( self.add_basemap_layer) ############ btn: new, edit, delete space dialog.signal_new_space.connect(self.start_new_space) dialog.signal_edit_space.connect(self.start_edit_space) dialog.signal_del_space.connect(self.start_delete_space) ############ Use Token btn dialog.signal_use_token.connect( lambda a: self.con_man.finish_fast()) dialog.signal_use_token.connect(self.start_use_token) ############ get count dialog.signal_space_count.connect(self.start_count_feat, Qt.QueuedConnection) # queued -> non-blocking ui ############ connect btn # dialog.signal_space_connect.connect(self.start_load_layer) dialog.signal_space_connect.connect(self.start_loading) dialog.signal_space_tile.connect(self.start_load_tile) ############ upload btn dialog.signal_upload_space.connect(self.start_upload_space) return dialog def start_new_space(self, args): con = self.con_man.get_con("create") con.start_args(args) def start_edit_space(self, args): con = self.con_man.get_con("edit") con.start_args(args) def start_delete_space(self, args): con = self.con_man.get_con("delete") con.start_args(args) def start_use_token(self, args): con = self.con_man.get_con("list") con.start_args(args) def start_count_feat(self, args): con = self.con_man.get_con("stat") con.start_args(args) def start_upload_space(self, args): con_upload = UploadLayerController(self.network, n_parallel=2) self.con_man.add_on_demand_controller(con_upload) # con_upload.signal.finished.connect( self.make_cb_success("Uploading finish") ) con_upload.signal.results.connect( self.make_cb_success_args("Uploading finish", dt=4)) con_upload.signal.error.connect( self.cb_handle_error_msg ) con = InitUploadLayerController(self.network) self.con_man.add_on_demand_controller(con) con.signal.results.connect( con_upload.start_args) con.signal.error.connect( self.cb_handle_error_msg ) con.start_args(args) def start_load_layer(self, args): # create new con # config # run ############ connect btn con_load = LoadLayerController(self.network, n_parallel=1) self.con_man.add_on_demand_controller(con_load) # con_load.signal.finished.connect( self.make_cb_success("Loading finish") ) con_load.signal.results.connect( self.make_cb_success_args("Loading finish") ) # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection) con_load.signal.error.connect( self.cb_handle_error_msg ) con_load.start_args(args) # con.signal.results.connect( self.layer_man.add_args) # IMPORTANT def start_load_tile(self, args): # rect = (-180,-90,180,90) # level = 0 a, kw = parse_qt_args(args) kw.update(self.make_tile_params()) # kw["limit"] = 100 ############ connect btn con_load = TileLayerLoader(self.network, n_parallel=1) self.con_man.add_persistent_loader(con_load) # con_load.signal.finished.connect( self.make_cb_success("Tiles loaded") ) con_load.signal.results.connect( self.make_cb_success_args("Tiles loaded", dt=2) ) # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection) con_load.signal.error.connect( self.cb_handle_error_msg ) con_load.start_args( make_qt_args(*a, **kw)) def make_tile_params(self, rect=None, level=None): if not rect: canvas = self.iface.mapCanvas() rect = bbox_utils.extent_to_rect( bbox_utils.get_bounding_box(canvas)) level = tile_utils.get_zoom_for_current_map_scale(canvas) schema = "web" kw = dict() kw["tile_schema"] = schema kw["tile_ids"] = tile_utils.bboxToListColRow(*rect,level, schema=schema) return kw def start_loading(self, args): a, kw = parse_qt_args(args) loading_mode = kw.get("loading_mode") try: con_load = self.make_loader_from_mode(loading_mode) except Exception as e: self.show_err_msgbar(e) return if loading_mode == LOADING_MODES.STATIC: con_load.start_args(args) else: kw.update(self.make_tile_params()) con_load.start_args( make_qt_args(*a, **kw)) def iter_checked_xyz_subnode(self): """ iterate through visible xyz nodes (vector layer and group node) """ root = QgsProject.instance().layerTreeRoot() for vl in root.checkedLayers(): if is_xyz_supported_layer(vl): yield vl for g in iter_group_node(root): if (len(g.findLayers()) == 0 and g.isVisible() and is_xyz_supported_node(g)): yield g def iter_all_xyz_node(self): """ iterate through xyz group nodes """ for qnode in self._iter_all_xyz_node(): yield qnode def iter_update_all_xyz_node(self): """ iterate through xyz group nodes, with meta version check and updated. """ for qnode in self._iter_all_xyz_node(fn_node=updated_xyz_node): yield qnode def _iter_all_xyz_node(self, fn_node=lambda a: None): """ iterate through xyz group nodes, with custom function fn_node applied to every node """ root = QgsProject.instance().layerTreeRoot() for g in iter_group_node(root): fn_node(g) if is_xyz_supported_node(g): yield g def extent_action(self, rect0, rect1): diff = [r0 - r1 for r0,r1 in zip(rect0,rect1)] x_sign = diff[0] * diff[2] y_sign = diff[1] * diff[3] if x_sign >= 0 and y_sign >= 0: # same direction return "pan" elif x_sign < 0 and y_sign < 0: return "zoom" elif x_sign * y_sign == 0 and x_sign + y_sign < 0: return "resize" else: return "unknown" def reload_tile(self): canvas = self.iface.mapCanvas() rect = bbox_utils.extent_to_rect(bbox_utils.get_bounding_box(canvas)) ext_action = self.extent_action(rect,self.lastRect) print_qgis("Extent action: ", ext_action,rect) self.lastRect = rect if ext_action not in ["pan", "zoom"]: return level = tile_utils.get_zoom_for_current_map_scale(canvas) kw = self.make_tile_params(rect, level) # kw["limit"] = 100 lst_con = self._get_lst_reloading_con() for con in lst_con: print_qgis(con.status) print_qgis("loading tile", level, rect) con.restart(**kw) def _get_lst_reloading_con(self): """ Return list of loader to be reload, that has + any vlayer in group is visible + and no vlayer in group is in edit mode """ editing_xid = set() unique_xid = set() for qnode in self.iter_checked_xyz_subnode(): xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID) if xlayer_id in editing_xid: continue if hasattr(qnode, "isEditable") and qnode.isEditable(): editing_xid.add(xlayer_id) continue con = self.con_man.get_interactive_loader(xlayer_id) if (con and con.layer and self.is_all_layer_edit_buffer_empty(con.layer) ): unique_xid.add(xlayer_id) else: continue # print_qgis(editing_xid, unique_xid) # print_qgis(unique_xid.difference(editing_xid)) # print_qgis(self.con_man._layer_ptr) return [ self.con_man.get_interactive_loader(xlayer_id) for xlayer_id in unique_xid.difference(editing_xid) ] def is_all_layer_edit_buffer_empty(self, layer: XYZLayer) -> bool: return all( layer_buffer.is_empty() for layer_buffer in ( self.edit_buffer.get_layer_buffer(vlayer.id()) for vlayer in layer.iter_layer() ) if layer_buffer ) def add_basemap_layer(self, args): a, kw = parse_qt_args(args) meta, app_id, app_code, api_key = a self.auth_manager.save(app_id, app_code, api_key) basemap.add_basemap_layer( meta, app_id, app_code, api_key) ############### # import project function ############### def import_project(self): self.init_all_layer_loader() # # restart static loader once # for con in self.con_man.get_all_static_loader(): # # truncate all feature # con.restart() def make_loader_from_mode(self, loading_mode, layer=None): if loading_mode not in LOADING_MODES: raise InvalidLoadingMode(loading_mode) option = dict(zip(LOADING_MODES, [ (LiveTileLayerLoader, self.con_man.add_persistent_loader, self.make_cb_success_args("Tiles loaded", dt=2)), (TileLayerLoader, self.con_man.add_persistent_loader, self.make_cb_success_args("Tiles loaded", dt=2)), (LoadLayerController, self.con_man.add_static_loader, self.make_cb_success_args("Loading finish", dt=3)) ])).get(loading_mode) if not option: return loader_class, fn_register, cb_success_args = option con_load = loader_class(self.network, n_parallel=1, layer=layer) con_load.signal.results.connect( cb_success_args) con_load.signal.error.connect( self.cb_handle_error_msg ) cb_info = self.make_cb_info_args("Loading status", dt=3) con_load.signal.info.connect( cb_info) ptr = fn_register(con_load) return con_load def init_layer_loader(self, qnode): layer = XYZLayer.load_from_qnode(qnode) loading_mode = layer.loader_params.get("loading_mode") if loading_mode not in LOADING_MODES: # # approach 1: backward compatible, import project # # invalid loading mode default to live # old = loading_mode # loading_mode = LOADING_MODES.LIVE # layer.update_loader_params(loading_mode=loading_mode) # save new loading_mode to layer # # TODO prompt user for handling invalid loading mode layer # self.show_info_msgbar("Import XYZ Layer", # "Undefined loading mode: %s, " % old + # "default to %s loading " % (loading_mode) + # "(layer: %s)" % layer.get_name()) # approach 2: not backward compatible, but no data loss self.show_warning_msgbar("Import XYZ Layer", "Undefined loading mode: %s, " % loading_mode + "loading disabled " + "(layer: %s)" % layer.get_name()) return return self.make_loader_from_mode(loading_mode, layer=layer) def init_all_layer_loader(self): cnt = 0 for qnode in self.iter_update_all_xyz_node(): xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID) con = self.con_man.get_loader(xlayer_id) if con: continue try: con = self.init_layer_loader(qnode) if not con: continue cnt += 1 except Exception as e: self.show_err_msgbar(e) # print_qgis(self.con_man._layer_ptr) self.show_success_msgbar("Import XYZ Layer", "%s XYZ Layer imported"%cnt, dt=2) def cb_qnode_visibility_changed(self, qnode): if qnode.isVisible(): return xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID) con = self.con_man.get_interactive_loader(xlayer_id) if con: con.stop_loading() def cb_qnodes_deleting(self, parent, i0, i1): key = (parent,i0,i1) is_parent_root = not parent.parent() lst = parent.children() for i in range(i0, i1+1): qnode = lst[i] if (is_parent_root and is_xyz_supported_node(qnode)): xlayer_id = get_customProperty_str(qnode, QProps.UNIQUE_ID) self.pending_delete_qnodes.setdefault(key, list()).append(xlayer_id) self.con_man.remove_persistent_loader(xlayer_id) # is possible to handle vlayer delete here # instead of handle in layer.py via callbacks def cb_qnodes_deleted(self, parent, i0, i1): key = (parent,i0,i1) for xlayer_id in self.pending_delete_qnodes.pop(key, list()): self.con_man.remove_persistent_loader(xlayer_id) ############### # Open dialog ############### def open_clear_cache_dialog(self): dialog = ConfirmDialog("Delete cache will make loaded layer unusable !!") ret = dialog.exec_() if ret != dialog.Ok: return utils.clear_cache() def open_connection_dialog(self): dialog = self.new_main_dialog() vlayer = self.iface.activeLayer() dialog.set_layer( vlayer) dialog.exec_() self.con_man.finish_fast() # self.startTime = time.time() def open_sync_edit_dialog(self): vlayer = self.iface.activeLayer() layer_buffer = self.edit_buffer.get_layer_buffer(vlayer.id()) lst_added_feat, removed_ids = layer_buffer.get_sync_feat() conn_info = layer_buffer.get_conn_info() # print_qgis("lst_added_feat: ",lst_added_feat) # print_qgis("removed_feat: ", removed_ids) con = EditSyncController(self.network) self.con_man.add_on_demand_controller(con) con.signal.finished.connect( layer_buffer.sync_complete) con.signal.results.connect( self.make_cb_success_args("Sync edit finish") ) con.signal.error.connect( self.cb_handle_error_msg ) con.start(conn_info, layer_buffer, lst_added_feat, removed_ids)
class DebugVSPlugin(QObject): def __init__(self, iface): super().__init__() self.iface = iface self.ptvsd = None try: import ptvsd self.ptvsd = ptvsd except: pass self.port = 5678 self.host = 'localhost' self.actionsScript = [] self.toolButton = QToolButton() self.toolButton.setMenu(QMenu()) self.toolButton.setPopupMode(QToolButton.MenuButtonPopup) self.toolBtnAction = self.iface.addToolBarWidget(self.toolButton) self.msgBar = iface.messageBar() self.pluginName = 'DebugVS' self.nameActionEnable = 'Enable Debug for Visual Studio' self.action = None # Check exist sys.argv - /ptvsd/.../pydevd_process_net_command if not hasattr(sys, 'argv'): sys.argv = [] def initGui(self): # Action Run icon = QIcon(os.path.join(os.path.dirname(__file__), 'code.svg')) self.actionEnable = QAction(icon, self.nameActionEnable, self.iface.mainWindow()) self.actionEnable.setToolTip(self.nameActionEnable) self.actionEnable.triggered.connect(self.enable) self.iface.addPluginToMenu(f"&{self.nameActionEnable}", self.actionEnable) # Action Load Script title = 'Load script' icon = QgsApplication.getThemeIcon('mActionScriptOpen.svg') self.actionLoad = QAction(icon, title, self.iface.mainWindow()) self.actionLoad.setToolTip(title) self.actionLoad.triggered.connect(self.load) self.iface.addPluginToMenu(f"&{self.nameActionEnable}", self.actionLoad) # m = self.toolButton.menu() m.addAction(self.actionEnable) m.addAction(self.actionLoad) self.toolButton.setDefaultAction(self.actionEnable) def unload(self): for action in [self.actionEnable, self.actionLoad ] + self.actionsScript: self.iface.removePluginMenu(f"&{self.nameActionEnable}", action) self.iface.removeToolBarIcon(action) self.iface.unregisterMainWindowAction(action) self.iface.removeToolBarIcon(self.toolBtnAction) def _addActionScript(self, filename): icon = QgsApplication.getThemeIcon('processingScript.svg') title = os.path.split(filename)[-1] action = QAction(icon, title, self.iface.mainWindow()) action.setToolTip(filename) action.triggered.connect(self.run) m = self.toolButton.menu() m.addAction(action) self.actionsScript.append(action) def _existsActionScript(self, filename): filenames = [a.toolTip() for a in self.actionsScript] return filename in filenames def _checkEnable(self): if not self.ptvsd.is_attached(): self.msgBar.popWidget() msg = f"{self.nameActionEnable} AND attach in Visual Studio Code" self.msgBar.pushWarning(self.pluginName, msg) return False return True @pyqtSlot(bool) def enable(self, checked): self.msgBar.popWidget() if self.ptvsd is None: self.msgBar.pushCritical(self.pluginName, "Need install ptvsd: pip3 install ptvsd") return msgPort = f'"request": "attach", "Port": {self.port}, "host": "{self.host}"' if self.ptvsd.is_attached(): self.msgBar.pushWarning( self.pluginName, f"Remote Debug for Visual Studio is active({msgPort})") return t_, self.port = self.ptvsd.enable_attach(address=(self.host, self.port)) msgPort = f'"request": "attach", "Port": {self.port}, "host": "{self.host}"' self.msgBar.pushInfo( self.pluginName, f"Remote Debug for Visual Studio is running({msgPort})") @pyqtSlot(bool) def load(self, checked): if not self._checkEnable(): return filename, _ = QFileDialog.getOpenFileName(None, 'Debug script', '', 'Python Files (*.py)') if not filename: return self.ptvsd.wait_for_attach() execfile_(filename) if not self._existsActionScript(filename): self._addActionScript(filename) @pyqtSlot(bool) def run(self, checked): if not self._checkEnable(): return action = self.sender() filename = action.toolTip() self.ptvsd.wait_for_attach() execfile_(filename)
class LatLonTools: digitizerDialog = None convertCoordinateDialog = None mapTool = None showMapTool = None copyExtentTool = None def __init__(self, iface): self.iface = iface self.canvas = iface.mapCanvas() self.crossRb = QgsRubberBand(self.canvas, QgsWkbTypes.LineGeometry) self.crossRb.setColor(Qt.red) self.provider = LatLonToolsProvider() self.toolbar = self.iface.addToolBar('Lat Lon Tools Toolbar') self.toolbar.setObjectName('LatLonToolsToolbar') def initGui(self): '''Initialize Lot Lon Tools GUI.''' # Initialize the Settings Dialog box self.settingsDialog = SettingsWidget(self, self.iface, self.iface.mainWindow()) # Add Interface for Coordinate Capturing icon = QIcon(os.path.dirname(__file__) + "/images/copyicon.svg") self.copyAction = QAction(icon, "Copy/Display Coordinate", self.iface.mainWindow()) self.copyAction.setObjectName('latLonToolsCopy') self.copyAction.triggered.connect(self.startCapture) self.copyAction.setCheckable(True) self.toolbar.addAction(self.copyAction) self.iface.addPluginToMenu("Lat Lon Tools", self.copyAction) # Add Interface for External Map icon = QIcon(os.path.dirname(__file__) + "/images/mapicon.png") self.externMapAction = QAction(icon, "Show in External Map", self.iface.mainWindow()) self.externMapAction.setObjectName('latLonToolsExternalMap') self.externMapAction.triggered.connect(self.setShowMapTool) self.externMapAction.setCheckable(True) self.toolbar.addAction(self.externMapAction) self.iface.addPluginToMenu("Lat Lon Tools", self.externMapAction) # Add Interface for Zoom to Coordinate icon = QIcon(os.path.dirname(__file__) + "/images/zoomicon.svg") self.zoomToAction = QAction(icon, "Zoom To Coordinate", self.iface.mainWindow()) self.zoomToAction.setObjectName('latLonToolsZoom') self.zoomToAction.triggered.connect(self.showZoomToDialog) self.toolbar.addAction(self.zoomToAction) self.iface.addPluginToMenu('Lat Lon Tools', self.zoomToAction) self.zoomToDialog = ZoomToLatLon(self, self.iface, self.iface.mainWindow()) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.zoomToDialog) self.zoomToDialog.hide() # Add Interface for Multi point zoom icon = QIcon(os.path.dirname(__file__) + '/images/multizoom.svg') self.multiZoomToAction = QAction(icon, "Multi-location Zoom", self.iface.mainWindow()) self.multiZoomToAction.setObjectName('latLonToolsMultiZoom') self.multiZoomToAction.triggered.connect(self.multiZoomTo) self.toolbar.addAction(self.multiZoomToAction) self.iface.addPluginToMenu('Lat Lon Tools', self.multiZoomToAction) self.multiZoomDialog = MultiZoomWidget(self, self.settingsDialog, self.iface.mainWindow()) self.multiZoomDialog.hide() self.multiZoomDialog.setFloating(True) menu = QMenu() # Add Interface for copying the canvas extent icon = QIcon(os.path.dirname(__file__) + "/images/copycanvas.svg") self.copyCanvasAction = menu.addAction(icon, 'Copy Canvas Extent', self.copyCanvas) self.copyCanvasAction.setObjectName('latLonToolsCopyCanvasExtent') # Add Interface for copying an interactive extent icon = QIcon(os.path.dirname(__file__) + "/images/copyextent.svg") self.copyExtentAction = menu.addAction(icon, 'Copy Selected Area Extent', self.copyExtent) self.copyExtentAction.setCheckable(True) self.copyExtentAction.setObjectName( 'latLonToolsCopySelectedAreaExtent') # Add Interface for copying a layer extent icon = QIcon(os.path.dirname(__file__) + "/images/copylayerextent.svg") self.copyLayerExtentAction = menu.addAction(icon, 'Copy Layer Extent', self.copyLayerExtent) self.copyLayerExtentAction.setObjectName('latLonToolsCopyLayerExtent') # Add Interface for copying the extent of selected features icon = QIcon( os.path.dirname(__file__) + "/images/copyselectedlayerextent.svg") self.copySelectedFeaturesExtentAction = menu.addAction( icon, 'Copy Selected Features Extent', self.copySelectedFeaturesExtent) self.copySelectedFeaturesExtentAction.setObjectName( 'latLonToolsCopySelectedFeaturesExtent') # Add the copy extent tools to the menu icon = QIcon(os.path.dirname(__file__) + '/images/copylayerextent.svg') self.copyExtentsAction = QAction(icon, 'Copy Extents to Clipboard', self.iface.mainWindow()) self.copyExtentsAction.setMenu(menu) self.iface.addPluginToMenu('Lat Lon Tools', self.copyExtentsAction) # Add the copy extent tools to the toolbar self.copyExtentButton = QToolButton() self.copyExtentButton.setMenu(menu) self.copyExtentButton.setDefaultAction(self.copyCanvasAction) self.copyExtentButton.setPopupMode(QToolButton.MenuButtonPopup) self.copyExtentButton.triggered.connect(self.copyExtentTriggered) self.copyExtentToolbar = self.toolbar.addWidget(self.copyExtentButton) # Create the coordinate converter menu icon = QIcon(':/images/themes/default/mIconProjectionEnabled.svg') self.convertCoordinatesAction = QAction(icon, "Coordinate Conversion", self.iface.mainWindow()) self.convertCoordinatesAction.setObjectName( 'latLonToolsCoordinateConversion') self.convertCoordinatesAction.triggered.connect( self.convertCoordinatesTool) self.toolbar.addAction(self.convertCoordinatesAction) self.iface.addPluginToMenu("Lat Lon Tools", self.convertCoordinatesAction) # Create the conversions menu menu = QMenu() icon = QIcon(os.path.dirname(__file__) + '/images/field2geom.svg') action = menu.addAction(icon, "Fields to point layer", self.field2geom) action.setObjectName('latLonToolsField2Geom') icon = QIcon(os.path.dirname(__file__) + '/images/geom2field.svg') action = menu.addAction(icon, "Point layer to fields", self.geom2Field) action.setObjectName('latLonToolsGeom2Field') icon = QIcon(os.path.dirname(__file__) + '/images/pluscodes.svg') action = menu.addAction(icon, "Plus Codes to point layer", self.PlusCodestoLayer) action.setObjectName('latLonToolsPlusCodes2Geom') action = menu.addAction(icon, "Point layer to Plus Codes", self.toPlusCodes) action.setObjectName('latLonToolsGeom2PlusCodes') icon = QIcon(os.path.dirname(__file__) + '/images/mgrs2point.svg') action = menu.addAction(icon, "MGRS to point layer", self.MGRStoLayer) action.setObjectName('latLonToolsMGRS2Geom') icon = QIcon(os.path.dirname(__file__) + '/images/point2mgrs.svg') action = menu.addAction(icon, "Point layer to MGRS", self.toMGRS) action.setObjectName('latLonToolsGeom2MGRS') self.conversionsAction = QAction(icon, "Conversions", self.iface.mainWindow()) self.conversionsAction.setMenu(menu) self.iface.addPluginToMenu('Lat Lon Tools', self.conversionsAction) # Add to Digitize Toolbar icon = QIcon(os.path.dirname(__file__) + '/images/latLonDigitize.svg') self.digitizeAction = QAction(icon, "Lat Lon Digitize", self.iface.mainWindow()) self.digitizeAction.setObjectName('latLonToolsDigitize') self.digitizeAction.triggered.connect(self.digitizeClicked) self.digitizeAction.setEnabled(False) self.toolbar.addAction(self.digitizeAction) self.iface.addPluginToMenu('Lat Lon Tools', self.digitizeAction) # Initialize the Settings Dialog Box settingsicon = QIcon(':/images/themes/default/mActionOptions.svg') self.settingsAction = QAction(settingsicon, "Settings", self.iface.mainWindow()) self.settingsAction.setObjectName('latLonToolsSettings') self.settingsAction.setToolTip('Lat Lon Tools Settings') self.settingsAction.triggered.connect(self.settings) self.toolbar.addAction(self.settingsAction) self.iface.addPluginToMenu('Lat Lon Tools', self.settingsAction) # Help icon = QIcon(os.path.dirname(__file__) + '/images/help.svg') self.helpAction = QAction(icon, "Help", self.iface.mainWindow()) self.helpAction.setObjectName('latLonToolsHelp') self.helpAction.triggered.connect(self.help) self.iface.addPluginToMenu('Lat Lon Tools', self.helpAction) self.iface.currentLayerChanged.connect(self.currentLayerChanged) self.canvas.mapToolSet.connect(self.resetTools) self.enableDigitizeTool() # Add the processing provider QgsApplication.processingRegistry().addProvider(self.provider) InitLatLonFunctions() def resetTools(self, newtool, oldtool): '''Uncheck the Copy Lat Lon tool''' try: if self.mapTool and (oldtool is self.mapTool): self.copyAction.setChecked(False) if self.showMapTool and (oldtool is self.showMapTool): self.externMapAction.setChecked(False) if newtool is self.mapTool: self.copyAction.setChecked(True) if newtool is self.showMapTool: self.externMapAction.setChecked(True) except Exception: pass def unload(self): '''Unload LatLonTools from the QGIS interface''' self.zoomToDialog.removeMarker() self.multiZoomDialog.removeMarkers() if self.mapTool: self.canvas.unsetMapTool(self.mapTool) if self.showMapTool: self.canvas.unsetMapTool(self.showMapTool) self.iface.removePluginMenu('Lat Lon Tools', self.copyAction) self.iface.removePluginMenu('Lat Lon Tools', self.copyExtentsAction) self.iface.removePluginMenu('Lat Lon Tools', self.externMapAction) self.iface.removePluginMenu('Lat Lon Tools', self.zoomToAction) self.iface.removePluginMenu('Lat Lon Tools', self.multiZoomToAction) self.iface.removePluginMenu('Lat Lon Tools', self.convertCoordinatesAction) self.iface.removePluginMenu('Lat Lon Tools', self.conversionsAction) self.iface.removePluginMenu('Lat Lon Tools', self.settingsAction) self.iface.removePluginMenu('Lat Lon Tools', self.helpAction) self.iface.removePluginMenu('Lat Lon Tools', self.digitizeAction) self.iface.removeDockWidget(self.zoomToDialog) self.iface.removeDockWidget(self.multiZoomDialog) # Remove Toolbar Icons self.iface.removeToolBarIcon(self.copyAction) self.iface.removeToolBarIcon(self.copyExtentToolbar) self.iface.removeToolBarIcon(self.zoomToAction) self.iface.removeToolBarIcon(self.externMapAction) self.iface.removeToolBarIcon(self.multiZoomToAction) self.iface.removeToolBarIcon(self.convertCoordinatesAction) self.iface.removeToolBarIcon(self.digitizeAction) del self.toolbar if self.convertCoordinateDialog: self.iface.removeDockWidget(self.convertCoordinateDialog) self.convertCoordinateDialog = None self.zoomToDialog = None self.multiZoomDialog = None self.settingsDialog = None self.showMapTool = None self.mapTool = None self.digitizerDialog = None QgsApplication.processingRegistry().removeProvider(self.provider) UnloadLatLonFunctions() def startCapture(self): '''Set the focus of the copy coordinate tool''' if self.mapTool is None: from .copyLatLonTool import CopyLatLonTool self.mapTool = CopyLatLonTool(self.settingsDialog, self.iface) self.canvas.setMapTool(self.mapTool) def copyExtentTriggered(self, action): self.copyExtentButton.setDefaultAction(action) def copyExtent(self): if self.copyExtentTool is None: from .captureExtent import CaptureExtentTool self.copyExtentTool = CaptureExtentTool(self.iface, self) self.copyExtentTool.setAction(self.copyExtentAction) self.canvas.setMapTool(self.copyExtentTool) def copyLayerExtent(self): layer = self.iface.activeLayer() if not layer or not layer.isValid(): return if isinstance(layer, QgsVectorLayer) and (layer.featureCount() == 0): self.iface.messageBar().pushMessage( "", "This layer has no features - A bounding box cannot be calculated.", level=Qgis.Warning, duration=4) return src_crs = layer.crs() extent = layer.extent() if settings.bBoxCrs == 0: dst_crs = epsg4326 else: dst_crs = self.canvas.mapSettings().destinationCrs() outStr = getExtentString(extent, src_crs, dst_crs) clipboard = QApplication.clipboard() clipboard.setText(outStr) self.iface.messageBar().pushMessage( "", "'{}' copied to the clipboard".format(outStr), level=Qgis.Info, duration=4) def copySelectedFeaturesExtent(self): layer = self.iface.activeLayer() if not layer or not layer.isValid(): return if isinstance(layer, QgsVectorLayer) and (layer.featureCount() == 0): self.iface.messageBar().pushMessage( "", "This layer has no features - A bounding box cannot be calculated.", level=Qgis.Warning, duration=4) return if isinstance(layer, QgsVectorLayer): extent = layer.boundingBoxOfSelected() if extent.isNull(): self.iface.messageBar().pushMessage( "", "No features were selected.", level=Qgis.Warning, duration=4) return else: extent = layer.extent() src_crs = layer.crs() if settings.bBoxCrs == 0: dst_crs = epsg4326 else: dst_crs = self.canvas.mapSettings().destinationCrs() outStr = getExtentString(extent, src_crs, dst_crs) clipboard = QApplication.clipboard() clipboard.setText(outStr) self.iface.messageBar().pushMessage( "", "'{}' copied to the clipboard".format(outStr), level=Qgis.Info, duration=4) def copyCanvas(self): extent = self.iface.mapCanvas().extent() canvas_crs = self.canvas.mapSettings().destinationCrs() if settings.bBoxCrs == 0: dst_crs = epsg4326 else: dst_crs = canvas_crs outStr = getExtentString(extent, canvas_crs, dst_crs) clipboard = QApplication.clipboard() clipboard.setText(outStr) self.iface.messageBar().pushMessage( "", "'{}' copied to the clipboard".format(outStr), level=Qgis.Info, duration=4) def setShowMapTool(self): '''Set the focus of the external map tool.''' if self.showMapTool is None: from .showOnMapTool import ShowOnMapTool self.showMapTool = ShowOnMapTool(self.iface) self.canvas.setMapTool(self.showMapTool) def showZoomToDialog(self): '''Show the zoom to docked widget.''' self.zoomToDialog.show() def convertCoordinatesTool(self): '''Display the Convert Coordinate Tool Dialog box.''' if self.convertCoordinateDialog is None: from .coordinateConverter import CoordinateConverterWidget self.convertCoordinateDialog = CoordinateConverterWidget( self, self.settingsDialog, self.iface, self.iface.mainWindow()) self.convertCoordinateDialog.setFloating(True) self.iface.addDockWidget(Qt.RightDockWidgetArea, self.convertCoordinateDialog) self.convertCoordinateDialog.show() def multiZoomTo(self): '''Display the Multi-zoom to dialog box''' self.multiZoomDialog.show() def field2geom(self): '''Convert layer containing a point x & y coordinate to a new point layer''' processing.execAlgorithmDialog('latlontools:field2geom', {}) def geom2Field(self): '''Convert layer geometry to a text string''' processing.execAlgorithmDialog('latlontools:geom2field', {}) def toMGRS(self): '''Display the to MGRS dialog box''' processing.execAlgorithmDialog('latlontools:point2mgrs', {}) def MGRStoLayer(self): '''Display the to MGRS dialog box''' processing.execAlgorithmDialog('latlontools:mgrs2point', {}) def toPlusCodes(self): processing.execAlgorithmDialog('latlontools:point2pluscodes', {}) def PlusCodestoLayer(self): processing.execAlgorithmDialog('latlontools:pluscodes2point', {}) def settings(self): '''Show the settings dialog box''' self.settingsDialog.show() def help(self): '''Display a help page''' import webbrowser url = QUrl.fromLocalFile(os.path.dirname(__file__) + "/index.html").toString() webbrowser.open(url, new=2) def settingsChanged(self): # Settings may have changed so we need to make sure the zoomToDialog window is configured properly self.zoomToDialog.configure() self.multiZoomDialog.settingsChanged() def zoomTo(self, src_crs, lat, lon): canvas_crs = self.canvas.mapSettings().destinationCrs() transform = QgsCoordinateTransform(src_crs, canvas_crs, QgsProject.instance()) x, y = transform.transform(float(lon), float(lat)) rect = QgsRectangle(x, y, x, y) self.canvas.setExtent(rect) pt = QgsPointXY(x, y) self.highlight(pt) self.canvas.refresh() return pt def highlight(self, point): currExt = self.canvas.extent() leftPt = QgsPoint(currExt.xMinimum(), point.y()) rightPt = QgsPoint(currExt.xMaximum(), point.y()) topPt = QgsPoint(point.x(), currExt.yMaximum()) bottomPt = QgsPoint(point.x(), currExt.yMinimum()) horizLine = QgsGeometry.fromPolyline([leftPt, rightPt]) vertLine = QgsGeometry.fromPolyline([topPt, bottomPt]) self.crossRb.reset(QgsWkbTypes.LineGeometry) self.crossRb.addGeometry(horizLine, None) self.crossRb.addGeometry(vertLine, None) QTimer.singleShot(700, self.resetRubberbands) def resetRubberbands(self): self.crossRb.reset() def digitizeClicked(self): if self.digitizerDialog is None: from .digitizer import DigitizerWidget self.digitizerDialog = DigitizerWidget(self, self.iface, self.iface.mainWindow()) self.digitizerDialog.show() def currentLayerChanged(self): layer = self.iface.activeLayer() if layer is not None: try: layer.editingStarted.disconnect(self.layerEditingChanged) except Exception: pass try: layer.editingStopped.disconnect(self.layerEditingChanged) except Exception: pass if isinstance(layer, QgsVectorLayer): layer.editingStarted.connect(self.layerEditingChanged) layer.editingStopped.connect(self.layerEditingChanged) self.enableDigitizeTool() def layerEditingChanged(self): self.enableDigitizeTool() def enableDigitizeTool(self): self.digitizeAction.setEnabled(False) layer = self.iface.activeLayer() if layer is not None and isinstance(layer, QgsVectorLayer) and ( layer.geometryType() == QgsWkbTypes.PointGeometry) and layer.isEditable(): self.digitizeAction.setEnabled(True) else: if self.digitizerDialog is not None: self.digitizerDialog.close()
def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None, parentMenu=None, withShortcut=False, tooltip=None, parentToolbar=None, parentButton=None, isCheckable=False): """Add a toolbar icon to the InaSAFE toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.menu.addAction(action) if parentMenu: parentMenu.addAction(action) if withShortcut: self.iface.registerMainWindowAction(action, '') if isCheckable: action.setCheckable(True) if tooltip: action.setToolTip(tooltip) if parentToolbar: parentToolbar.addAction(action) if parentButton: parentButton.addAction(action) self.actions.append(action) return action
class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle( QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QgsSettings() self.shell = ShellScintilla(self) self.setFocusProxy(self.shell) self.shellOut = ShellOutputScintilla(self) self.tabEditorWidget = EditorTabWidget(self) # ------------ UI ------------------------------- self.splitterEditor = QSplitter(self) self.splitterEditor.setOrientation(Qt.Horizontal) self.splitterEditor.setHandleWidth(6) self.splitterEditor.setChildrenCollapsible(True) self.shellOutWidget = QWidget(self) self.shellOutWidget.setLayout(QVBoxLayout()) self.shellOutWidget.layout().setContentsMargins(0, 0, 0, 0) self.shellOutWidget.layout().addWidget(self.shellOut) self.splitter = QSplitter(self.splitterEditor) self.splitter.setOrientation(Qt.Vertical) self.splitter.setHandleWidth(3) self.splitter.setChildrenCollapsible(False) self.splitter.addWidget(self.shellOutWidget) self.splitter.addWidget(self.shell) # self.splitterEditor.addWidget(self.tabEditorWidget) self.splitterObj = QSplitter(self.splitterEditor) self.splitterObj.setHandleWidth(3) self.splitterObj.setOrientation(Qt.Horizontal) # self.splitterObj.setSizes([0, 0]) # self.splitterObj.setStretchFactor(0, 1) self.widgetEditor = QWidget(self.splitterObj) self.widgetFind = QWidget(self) self.listClassMethod = QTreeWidget(self.splitterObj) self.listClassMethod.setColumnCount(2) objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector") self.listClassMethod.setHeaderLabels([objInspLabel, '']) self.listClassMethod.setColumnHidden(1, True) self.listClassMethod.setAlternatingRowColors(True) # self.splitterEditor.addWidget(self.widgetEditor) # self.splitterObj.addWidget(self.listClassMethod) # self.splitterObj.addWidget(self.widgetEditor) # Hide side editor on start up self.splitterObj.hide() self.listClassMethod.hide() # Hide search widget on start up self.widgetFind.hide() icon_size = iface.iconSize( dockedToolbar=True) if iface else QSize(16, 16) sizes = self.splitter.sizes() self.splitter.setSizes(sizes) # ----------------Restore Settings------------------------------------ self.restoreSettingsConsole() # ------------------Toolbar Editor------------------------------------- # Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open Script...") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon( QgsApplication.getThemeIcon("console/iconOpenConsole.png")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) openExtEditorBt = QCoreApplication.translate( "PythonConsole", "Open in External Editor") self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) self.openInEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.openInEditorButton.setMenuRole(QAction.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) self.openInEditorButton.setText(openExtEditorBt) # Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon( QgsApplication.getThemeIcon("console/iconSaveConsole.png")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) # Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As...") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon( QgsApplication.getThemeIcon("console/iconSaveAsConsole.png")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) # Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon( QgsApplication.getThemeIcon("mActionEditCut.svg")) self.cutEditorButton.setMenuRole(QAction.PreferencesRole) self.cutEditorButton.setIconVisibleInMenu(True) self.cutEditorButton.setToolTip(cutEditorBt) self.cutEditorButton.setText(cutEditorBt) # Action Copy copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy") self.copyEditorButton = QAction(self) self.copyEditorButton.setCheckable(False) self.copyEditorButton.setEnabled(True) self.copyEditorButton.setIcon( QgsApplication.getThemeIcon("mActionEditCopy.svg")) self.copyEditorButton.setMenuRole(QAction.PreferencesRole) self.copyEditorButton.setIconVisibleInMenu(True) self.copyEditorButton.setToolTip(copyEditorBt) self.copyEditorButton.setText(copyEditorBt) # Action Paste pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste") self.pasteEditorButton = QAction(self) self.pasteEditorButton.setCheckable(False) self.pasteEditorButton.setEnabled(True) self.pasteEditorButton.setIcon( QgsApplication.getThemeIcon("mActionEditPaste.svg")) self.pasteEditorButton.setMenuRole(QAction.PreferencesRole) self.pasteEditorButton.setIconVisibleInMenu(True) self.pasteEditorButton.setToolTip(pasteEditorBt) self.pasteEditorButton.setText(pasteEditorBt) # Action Run Script (subprocess) runScriptEditorBt = QCoreApplication.translate("PythonConsole", "Run script") self.runScriptEditorButton = QAction(self) self.runScriptEditorButton.setCheckable(False) self.runScriptEditorButton.setEnabled(True) self.runScriptEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconRunScriptConsole.png")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) # Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon( QgsApplication.getThemeIcon( "console/iconCommentEditorConsole.png")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) # Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon( QgsApplication.getThemeIcon( "console/iconUncommentEditorConsole.png")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) # Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector...") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled( self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon( QgsApplication.getThemeIcon("console/iconClassBrowserConsole.png")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) # Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon( QgsApplication.getThemeIcon("console/iconSearchEditorConsole.png")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) # ----------------Toolbar Console------------------------------------- # Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show Editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon( QgsApplication.getThemeIcon("console/iconShowEditorConsole.png")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) # Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear Console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon( QgsApplication.getThemeIcon("console/iconClearConsole.png")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) # Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Options...") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon( QgsApplication.getThemeIcon("console/iconSettingsConsole.png")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run Command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon( QgsApplication.getThemeIcon("console/iconRunConsole.png")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) # Help action helpBt = QCoreApplication.translate("PythonConsole", "Help...") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon( QgsApplication.getThemeIcon("console/iconHelpConsole.png")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(icon_size) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(icon_size) self.toolBarEditor.setMovable(False) self.toolBarEditor.setFloatable(False) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addAction(self.openInEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth( self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # ------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.shellOutWidget.layout().insertWidget(0, self.toolBar) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1) # Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find...") self.lineEditFind.setPlaceholderText(placeHolderTxt) self.findNextButton = QToolButton() self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchNextEditorConsole.png")) self.findNextButton.setIconSize(QSize(24, 24)) self.findNextButton.setAutoRaise(True) self.findPrevButton = QToolButton() self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon( QgsApplication.getThemeIcon( "console/iconSearchPrevEditorConsole.png")) self.findPrevButton.setIconSize(QSize(24, 24)) self.findPrevButton.setAutoRaise(True) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.layoutFind.addWidget(self.lineEditFind, 0, 1, 1, 1) self.layoutFind.addWidget(self.findPrevButton, 0, 2, 1, 1) self.layoutFind.addWidget(self.findNextButton, 0, 3, 1, 1) self.layoutFind.addWidget(self.caseSensitive, 0, 4, 1, 1) self.layoutFind.addWidget(self.wholeWord, 0, 5, 1, 1) self.layoutFind.addWidget(self.wrapAround, 0, 6, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.triggered.connect(self._toggleFind) self.objectListButton.toggled.connect(self.toggleObjectListWidget) self.commentEditorButton.triggered.connect(self.commentCode) self.uncommentEditorButton.triggered.connect(self.uncommentCode) self.runScriptEditorButton.triggered.connect(self.runScriptEditor) self.cutEditorButton.triggered.connect(self.cutEditor) self.copyEditorButton.triggered.connect(self.copyEditor) self.pasteEditorButton.triggered.connect(self.pasteEditor) self.showEditorButton.toggled.connect(self.toggleEditor) self.clearButton.triggered.connect(self.shellOut.clearConsole) self.optionsButton.triggered.connect(self.openSettings) self.runButton.triggered.connect(self.shell.entered) self.openFileButton.triggered.connect(self.openScriptFile) self.openInEditorButton.triggered.connect(self.openScriptFileExtEditor) self.saveFileButton.triggered.connect(self.saveScriptFile) self.saveAsFileButton.triggered.connect(self.saveAsScriptFile) self.helpButton.triggered.connect(self.openHelp) self.listClassMethod.itemClicked.connect(self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findNext) self.findNextButton.clicked.connect(self._findNext) self.findPrevButton.clicked.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._openFind) self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor) self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut) self.findNextScut.activated.connect(self._findNext) self.findPreviousScut = QShortcut(QKeySequence.FindPrevious, self.widgetEditor) self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut) self.findPreviousScut.activated.connect(self._findPrev) # Escape on editor hides the find bar self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._closeFind) def _toggleFind(self): self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget() def _openFind(self): self.tabEditorWidget.currentWidget().newEditor.openFindWidget() def _closeFind(self): self.tabEditorWidget.currentWidget().newEditor.closeFindWidget() def _findNext(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findPrev(self): self.tabEditorWidget.currentWidget().newEditor.findText(False) def _textFindChanged(self): if self.lineEditFind.text(): self.findNextButton.setEnabled(True) self.findPrevButton.setEnabled(True) self.tabEditorWidget.currentWidget().newEditor.findText( True, showMessage=False, findFirst=True) else: self.lineEditFind.setStyleSheet('') self.findNextButton.setEnabled(False) self.findPrevButton.setEnabled(False) def onClickGoToLine(self, item, column): tabEditor = self.tabEditorWidget.currentWidget().newEditor if item.text(1) == 'syntaxError': check = tabEditor.syntaxCheck(fromContextMenu=False) if check and not tabEditor.isReadOnly(): self.tabEditorWidget.currentWidget().save() return linenr = int(item.text(1)) itemName = str(item.text(0)) charPos = itemName.find(' ') if charPos != -1: objName = itemName[0:charPos] else: objName = itemName tabEditor.goToLine(objName, linenr) def toggleEditor(self, checked): self.splitterObj.show() if checked else self.splitterObj.hide() if not self.tabEditorWidget: self.tabEditorWidget.enableToolBarEditor(checked) self.tabEditorWidget.restoreTabsOrAddNew() def toggleObjectListWidget(self, checked): self.listClassMethod.show() if checked else self.listClassMethod.hide() def pasteEditor(self): self.tabEditorWidget.currentWidget().newEditor.paste() def cutEditor(self): self.tabEditorWidget.currentWidget().newEditor.cut() def copyEditor(self): self.tabEditorWidget.currentWidget().newEditor.copy() def runScriptEditor(self): self.tabEditorWidget.currentWidget().newEditor.runScriptCode() def commentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True) def uncommentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False) def openScriptFileExtEditor(self): tabWidget = self.tabEditorWidget.currentWidget() path = tabWidget.path import subprocess try: subprocess.Popen([os.environ['EDITOR'], path]) except KeyError: QDesktopServices.openUrl(QUrl.fromLocalFile(path)) def openScriptFile(self): lastDirPath = self.settings.value("pythonConsole/lastDirPath", QDir.homePath()) openFileTr = QCoreApplication.translate("PythonConsole", "Open File") fileList, selected_filter = QFileDialog.getOpenFileNames( self, openFileTr, lastDirPath, "Script file (*.py)") if fileList: for pyFile in fileList: for i in range(self.tabEditorWidget.count()): tabWidget = self.tabEditorWidget.widget(i) if tabWidget.path == pyFile: self.tabEditorWidget.setCurrentWidget(tabWidget) break else: tabName = QFileInfo(pyFile).fileName() self.tabEditorWidget.newTabEditor(tabName, pyFile) lastDirPath = QFileInfo(pyFile).path() self.settings.setValue("pythonConsole/lastDirPath", pyFile) self.updateTabListScript(pyFile, action='append') def saveScriptFile(self): tabWidget = self.tabEditorWidget.currentWidget() try: tabWidget.save() except (IOError, OSError) as error: msgText = QCoreApplication.translate( 'PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format( tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) def saveAsScriptFile(self, index=None): tabWidget = self.tabEditorWidget.currentWidget() if not index: index = self.tabEditorWidget.currentIndex() if not tabWidget.path: fileName = self.tabEditorWidget.tabText(index) + '.py' folder = self.settings.value("pythonConsole/lastDirPath", QDir.home()) pathFileName = os.path.join(folder, fileName) fileNone = True else: pathFileName = tabWidget.path fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") filename, filter = QFileDialog.getSaveFileName(self, saveAsFileTr, pathFileName, "Script file (*.py)") if filename: try: tabWidget.save(filename) except (IOError, OSError) as error: msgText = QCoreApplication.translate( 'PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}' ).format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) if fileNone: tabWidget.path = None else: tabWidget.path = pathFileName return if not fileNone: self.updateTabListScript(pathFileName, action='remove') def openHelp(self): QgsHelp.openHelp("plugins/python_console.html") def openSettings(self): if optionsDialog(self).exec_(): self.shell.refreshSettingsShell() self.shellOut.refreshSettingsOutput() self.tabEditorWidget.refreshSettingsEditor() def callWidgetMessageBar(self, text): self.shellOut.widgetMessageBar(iface, text) def callWidgetMessageBarEditor(self, text, level, timed): self.tabEditorWidget.widgetMessageBar(iface, text, level, timed) def updateTabListScript(self, script, action=None): if action == 'remove': self.tabListScript.remove(script) elif action == 'append': if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] self.settings.setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) self.shell.writeHistoryFile(True) def restoreSettingsConsole(self): storedTabScripts = self.settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts self.splitter.restoreState( self.settings.value("pythonConsole/splitterConsole", QByteArray())) self.splitterEditor.restoreState( self.settings.value("pythonConsole/splitterEditor", QByteArray())) self.splitterObj.restoreState( self.settings.value("pythonConsole/splitterObj", QByteArray()))
class PythonConsoleWidget(QWidget): def __init__(self, parent=None): QWidget.__init__(self, parent) self.setWindowTitle(QCoreApplication.translate("PythonConsole", "Python Console")) self.settings = QgsSettings() self.shell = ShellScintilla(self) self.setFocusProxy(self.shell) self.shellOut = ShellOutputScintilla(self) self.tabEditorWidget = EditorTabWidget(self) # ------------ UI ------------------------------- self.splitterEditor = QSplitter(self) self.splitterEditor.setOrientation(Qt.Horizontal) self.splitterEditor.setHandleWidth(6) self.splitterEditor.setChildrenCollapsible(True) self.shellOutWidget = QWidget(self) self.shellOutWidget.setLayout(QVBoxLayout()) self.shellOutWidget.layout().setContentsMargins(0, 0, 0, 0) self.shellOutWidget.layout().addWidget(self.shellOut) self.splitter = QSplitter(self.splitterEditor) self.splitter.setOrientation(Qt.Vertical) self.splitter.setHandleWidth(3) self.splitter.setChildrenCollapsible(False) self.splitter.addWidget(self.shellOutWidget) self.splitter.addWidget(self.shell) # self.splitterEditor.addWidget(self.tabEditorWidget) self.splitterObj = QSplitter(self.splitterEditor) self.splitterObj.setHandleWidth(3) self.splitterObj.setOrientation(Qt.Horizontal) # self.splitterObj.setSizes([0, 0]) # self.splitterObj.setStretchFactor(0, 1) self.widgetEditor = QWidget(self.splitterObj) self.widgetFind = QWidget(self) self.listClassMethod = QTreeWidget(self.splitterObj) self.listClassMethod.setColumnCount(2) objInspLabel = QCoreApplication.translate("PythonConsole", "Object Inspector") self.listClassMethod.setHeaderLabels([objInspLabel, '']) self.listClassMethod.setColumnHidden(1, True) self.listClassMethod.setAlternatingRowColors(True) # self.splitterEditor.addWidget(self.widgetEditor) # self.splitterObj.addWidget(self.listClassMethod) # self.splitterObj.addWidget(self.widgetEditor) # Hide side editor on start up self.splitterObj.hide() self.listClassMethod.hide() # Hide search widget on start up self.widgetFind.hide() icon_size = iface.iconSize(dockedToolbar=True) if iface else QSize(16, 16) sizes = self.splitter.sizes() self.splitter.setSizes(sizes) # ----------------Restore Settings------------------------------------ self.restoreSettingsConsole() # ------------------Toolbar Editor------------------------------------- # Action for Open File openFileBt = QCoreApplication.translate("PythonConsole", "Open Script…") self.openFileButton = QAction(self) self.openFileButton.setCheckable(False) self.openFileButton.setEnabled(True) self.openFileButton.setIcon(QgsApplication.getThemeIcon("console/iconOpenConsole.svg")) self.openFileButton.setMenuRole(QAction.PreferencesRole) self.openFileButton.setIconVisibleInMenu(True) self.openFileButton.setToolTip(openFileBt) self.openFileButton.setText(openFileBt) openExtEditorBt = QCoreApplication.translate("PythonConsole", "Open in External Editor") self.openInEditorButton = QAction(self) self.openInEditorButton.setCheckable(False) self.openInEditorButton.setEnabled(True) self.openInEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")) self.openInEditorButton.setMenuRole(QAction.PreferencesRole) self.openInEditorButton.setIconVisibleInMenu(True) self.openInEditorButton.setToolTip(openExtEditorBt) self.openInEditorButton.setText(openExtEditorBt) # Action for Save File saveFileBt = QCoreApplication.translate("PythonConsole", "Save") self.saveFileButton = QAction(self) self.saveFileButton.setCheckable(False) self.saveFileButton.setEnabled(False) self.saveFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveConsole.svg")) self.saveFileButton.setMenuRole(QAction.PreferencesRole) self.saveFileButton.setIconVisibleInMenu(True) self.saveFileButton.setToolTip(saveFileBt) self.saveFileButton.setText(saveFileBt) # Action for Save File As saveAsFileBt = QCoreApplication.translate("PythonConsole", "Save As…") self.saveAsFileButton = QAction(self) self.saveAsFileButton.setCheckable(False) self.saveAsFileButton.setEnabled(True) self.saveAsFileButton.setIcon(QgsApplication.getThemeIcon("console/iconSaveAsConsole.svg")) self.saveAsFileButton.setMenuRole(QAction.PreferencesRole) self.saveAsFileButton.setIconVisibleInMenu(True) self.saveAsFileButton.setToolTip(saveAsFileBt) self.saveAsFileButton.setText(saveAsFileBt) # Action Cut cutEditorBt = QCoreApplication.translate("PythonConsole", "Cut") self.cutEditorButton = QAction(self) self.cutEditorButton.setCheckable(False) self.cutEditorButton.setEnabled(True) self.cutEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCut.svg")) self.cutEditorButton.setMenuRole(QAction.PreferencesRole) self.cutEditorButton.setIconVisibleInMenu(True) self.cutEditorButton.setToolTip(cutEditorBt) self.cutEditorButton.setText(cutEditorBt) # Action Copy copyEditorBt = QCoreApplication.translate("PythonConsole", "Copy") self.copyEditorButton = QAction(self) self.copyEditorButton.setCheckable(False) self.copyEditorButton.setEnabled(True) self.copyEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditCopy.svg")) self.copyEditorButton.setMenuRole(QAction.PreferencesRole) self.copyEditorButton.setIconVisibleInMenu(True) self.copyEditorButton.setToolTip(copyEditorBt) self.copyEditorButton.setText(copyEditorBt) # Action Paste pasteEditorBt = QCoreApplication.translate("PythonConsole", "Paste") self.pasteEditorButton = QAction(self) self.pasteEditorButton.setCheckable(False) self.pasteEditorButton.setEnabled(True) self.pasteEditorButton.setIcon(QgsApplication.getThemeIcon("mActionEditPaste.svg")) self.pasteEditorButton.setMenuRole(QAction.PreferencesRole) self.pasteEditorButton.setIconVisibleInMenu(True) self.pasteEditorButton.setToolTip(pasteEditorBt) self.pasteEditorButton.setText(pasteEditorBt) # Action Run Script (subprocess) runScriptEditorBt = QCoreApplication.translate("PythonConsole", "Run Script") self.runScriptEditorButton = QAction(self) self.runScriptEditorButton.setCheckable(False) self.runScriptEditorButton.setEnabled(True) self.runScriptEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconRunScriptConsole.svg")) self.runScriptEditorButton.setMenuRole(QAction.PreferencesRole) self.runScriptEditorButton.setIconVisibleInMenu(True) self.runScriptEditorButton.setToolTip(runScriptEditorBt) self.runScriptEditorButton.setText(runScriptEditorBt) # Action Run Script (subprocess) commentEditorBt = QCoreApplication.translate("PythonConsole", "Comment") self.commentEditorButton = QAction(self) self.commentEditorButton.setCheckable(False) self.commentEditorButton.setEnabled(True) self.commentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconCommentEditorConsole.svg")) self.commentEditorButton.setMenuRole(QAction.PreferencesRole) self.commentEditorButton.setIconVisibleInMenu(True) self.commentEditorButton.setToolTip(commentEditorBt) self.commentEditorButton.setText(commentEditorBt) # Action Run Script (subprocess) uncommentEditorBt = QCoreApplication.translate("PythonConsole", "Uncomment") self.uncommentEditorButton = QAction(self) self.uncommentEditorButton.setCheckable(False) self.uncommentEditorButton.setEnabled(True) self.uncommentEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconUncommentEditorConsole.svg")) self.uncommentEditorButton.setMenuRole(QAction.PreferencesRole) self.uncommentEditorButton.setIconVisibleInMenu(True) self.uncommentEditorButton.setToolTip(uncommentEditorBt) self.uncommentEditorButton.setText(uncommentEditorBt) # Action for Object browser objList = QCoreApplication.translate("PythonConsole", "Object Inspector…") self.objectListButton = QAction(self) self.objectListButton.setCheckable(True) self.objectListButton.setEnabled(self.settings.value("pythonConsole/enableObjectInsp", False, type=bool)) self.objectListButton.setIcon(QgsApplication.getThemeIcon("console/iconClassBrowserConsole.svg")) self.objectListButton.setMenuRole(QAction.PreferencesRole) self.objectListButton.setIconVisibleInMenu(True) self.objectListButton.setToolTip(objList) self.objectListButton.setText(objList) # Action for Find text findText = QCoreApplication.translate("PythonConsole", "Find Text") self.findTextButton = QAction(self) self.findTextButton.setCheckable(True) self.findTextButton.setEnabled(True) self.findTextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchEditorConsole.svg")) self.findTextButton.setMenuRole(QAction.PreferencesRole) self.findTextButton.setIconVisibleInMenu(True) self.findTextButton.setToolTip(findText) self.findTextButton.setText(findText) # ----------------Toolbar Console------------------------------------- # Action Show Editor showEditor = QCoreApplication.translate("PythonConsole", "Show Editor") self.showEditorButton = QAction(self) self.showEditorButton.setEnabled(True) self.showEditorButton.setCheckable(True) self.showEditorButton.setIcon(QgsApplication.getThemeIcon("console/iconShowEditorConsole.svg")) self.showEditorButton.setMenuRole(QAction.PreferencesRole) self.showEditorButton.setIconVisibleInMenu(True) self.showEditorButton.setToolTip(showEditor) self.showEditorButton.setText(showEditor) # Action for Clear button clearBt = QCoreApplication.translate("PythonConsole", "Clear Console") self.clearButton = QAction(self) self.clearButton.setCheckable(False) self.clearButton.setEnabled(True) self.clearButton.setIcon(QgsApplication.getThemeIcon("console/iconClearConsole.svg")) self.clearButton.setMenuRole(QAction.PreferencesRole) self.clearButton.setIconVisibleInMenu(True) self.clearButton.setToolTip(clearBt) self.clearButton.setText(clearBt) # Action for settings optionsBt = QCoreApplication.translate("PythonConsole", "Options…") self.optionsButton = QAction(self) self.optionsButton.setCheckable(False) self.optionsButton.setEnabled(True) self.optionsButton.setIcon(QgsApplication.getThemeIcon("console/iconSettingsConsole.svg")) self.optionsButton.setMenuRole(QAction.PreferencesRole) self.optionsButton.setIconVisibleInMenu(True) self.optionsButton.setToolTip(optionsBt) self.optionsButton.setText(optionsBt) # Action for Run script runBt = QCoreApplication.translate("PythonConsole", "Run Command") self.runButton = QAction(self) self.runButton.setCheckable(False) self.runButton.setEnabled(True) self.runButton.setIcon(QgsApplication.getThemeIcon("console/mIconRunConsole.svg")) self.runButton.setMenuRole(QAction.PreferencesRole) self.runButton.setIconVisibleInMenu(True) self.runButton.setToolTip(runBt) self.runButton.setText(runBt) # Help action helpBt = QCoreApplication.translate("PythonConsole", "Help…") self.helpButton = QAction(self) self.helpButton.setCheckable(False) self.helpButton.setEnabled(True) self.helpButton.setIcon(QgsApplication.getThemeIcon("console/iconHelpConsole.svg")) self.helpButton.setMenuRole(QAction.PreferencesRole) self.helpButton.setIconVisibleInMenu(True) self.helpButton.setToolTip(helpBt) self.helpButton.setText(helpBt) self.toolBar = QToolBar() self.toolBar.setEnabled(True) self.toolBar.setFocusPolicy(Qt.NoFocus) self.toolBar.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBar.setLayoutDirection(Qt.LeftToRight) self.toolBar.setIconSize(icon_size) self.toolBar.setMovable(False) self.toolBar.setFloatable(False) self.toolBar.addAction(self.clearButton) self.toolBar.addAction(self.runButton) self.toolBar.addSeparator() self.toolBar.addAction(self.showEditorButton) self.toolBar.addSeparator() self.toolBar.addAction(self.optionsButton) self.toolBar.addAction(self.helpButton) self.toolBarEditor = QToolBar() self.toolBarEditor.setEnabled(False) self.toolBarEditor.setFocusPolicy(Qt.NoFocus) self.toolBarEditor.setContextMenuPolicy(Qt.DefaultContextMenu) self.toolBarEditor.setLayoutDirection(Qt.LeftToRight) self.toolBarEditor.setIconSize(icon_size) self.toolBarEditor.setMovable(False) self.toolBarEditor.setFloatable(False) self.toolBarEditor.addAction(self.openFileButton) self.toolBarEditor.addAction(self.openInEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.saveFileButton) self.toolBarEditor.addAction(self.saveAsFileButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.runScriptEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.findTextButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.cutEditorButton) self.toolBarEditor.addAction(self.copyEditorButton) self.toolBarEditor.addAction(self.pasteEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.commentEditorButton) self.toolBarEditor.addAction(self.uncommentEditorButton) self.toolBarEditor.addSeparator() self.toolBarEditor.addAction(self.objectListButton) self.widgetButton = QWidget() sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButton.sizePolicy().hasHeightForWidth()) self.widgetButton.setSizePolicy(sizePolicy) self.widgetButtonEditor = QWidget(self.widgetEditor) sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.widgetButtonEditor.sizePolicy().hasHeightForWidth()) self.widgetButtonEditor.setSizePolicy(sizePolicy) sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.shellOut.sizePolicy().hasHeightForWidth()) self.shellOut.setSizePolicy(sizePolicy) self.shellOut.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.shell.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) # ------------ Layout ------------------------------- self.mainLayout = QGridLayout(self) self.mainLayout.setMargin(0) self.mainLayout.setSpacing(0) self.mainLayout.addWidget(self.widgetButton, 0, 0, 1, 1) self.mainLayout.addWidget(self.splitterEditor, 0, 1, 1, 1) self.shellOutWidget.layout().insertWidget(0, self.toolBar) self.layoutEditor = QGridLayout(self.widgetEditor) self.layoutEditor.setMargin(0) self.layoutEditor.setSpacing(0) self.layoutEditor.addWidget(self.toolBarEditor, 0, 1, 1, 1) self.layoutEditor.addWidget(self.widgetButtonEditor, 1, 0, 2, 1) self.layoutEditor.addWidget(self.tabEditorWidget, 1, 1, 1, 1) self.layoutEditor.addWidget(self.widgetFind, 2, 1, 1, 1) # Layout for the find widget self.layoutFind = QGridLayout(self.widgetFind) self.layoutFind.setContentsMargins(0, 0, 0, 0) self.lineEditFind = QgsFilterLineEdit() placeHolderTxt = QCoreApplication.translate("PythonConsole", "Enter text to find…") self.lineEditFind.setPlaceholderText(placeHolderTxt) self.toolBarFindText = QToolBar() self.toolBarFindText.setIconSize(icon_size) self.findNextButton = QAction(self) self.findNextButton.setEnabled(False) toolTipfindNext = QCoreApplication.translate("PythonConsole", "Find Next") self.findNextButton.setToolTip(toolTipfindNext) self.findNextButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchNextEditorConsole.svg")) self.findPrevButton = QAction(self) self.findPrevButton.setEnabled(False) toolTipfindPrev = QCoreApplication.translate("PythonConsole", "Find Previous") self.findPrevButton.setToolTip(toolTipfindPrev) self.findPrevButton.setIcon(QgsApplication.getThemeIcon("console/iconSearchPrevEditorConsole.svg")) self.caseSensitive = QCheckBox() caseSensTr = QCoreApplication.translate("PythonConsole", "Case Sensitive") self.caseSensitive.setText(caseSensTr) self.wholeWord = QCheckBox() wholeWordTr = QCoreApplication.translate("PythonConsole", "Whole Word") self.wholeWord.setText(wholeWordTr) self.wrapAround = QCheckBox() self.wrapAround.setChecked(True) wrapAroundTr = QCoreApplication.translate("PythonConsole", "Wrap Around") self.wrapAround.setText(wrapAroundTr) self.toolBarFindText.addWidget(self.lineEditFind) self.toolBarFindText.addAction(self.findPrevButton) self.toolBarFindText.addAction(self.findNextButton) self.toolBarFindText.addWidget(self.caseSensitive) self.toolBarFindText.addWidget(self.wholeWord) self.toolBarFindText.addWidget(self.wrapAround) self.layoutFind.addWidget(self.toolBarFindText, 0, 1, 1, 1) # ------------ Add first Tab in Editor ------------------------------- # self.tabEditorWidget.newTabEditor(tabName='first', filename=None) # ------------ Signal ------------------------------- self.findTextButton.triggered.connect(self._toggleFind) self.objectListButton.toggled.connect(self.toggleObjectListWidget) self.commentEditorButton.triggered.connect(self.commentCode) self.uncommentEditorButton.triggered.connect(self.uncommentCode) self.runScriptEditorButton.triggered.connect(self.runScriptEditor) self.cutEditorButton.triggered.connect(self.cutEditor) self.copyEditorButton.triggered.connect(self.copyEditor) self.pasteEditorButton.triggered.connect(self.pasteEditor) self.showEditorButton.toggled.connect(self.toggleEditor) self.clearButton.triggered.connect(self.shellOut.clearConsole) self.optionsButton.triggered.connect(self.openSettings) self.runButton.triggered.connect(self.shell.entered) self.openFileButton.triggered.connect(self.openScriptFile) self.openInEditorButton.triggered.connect(self.openScriptFileExtEditor) self.saveFileButton.triggered.connect(self.saveScriptFile) self.saveAsFileButton.triggered.connect(self.saveAsScriptFile) self.helpButton.triggered.connect(self.openHelp) self.listClassMethod.itemClicked.connect(self.onClickGoToLine) self.lineEditFind.returnPressed.connect(self._findNext) self.findNextButton.triggered.connect(self._findNext) self.findPrevButton.triggered.connect(self._findPrev) self.lineEditFind.textChanged.connect(self._textFindChanged) self.findScut = QShortcut(QKeySequence.Find, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._openFind) self.findNextScut = QShortcut(QKeySequence.FindNext, self.widgetEditor) self.findNextScut.setContext(Qt.WidgetWithChildrenShortcut) self.findNextScut.activated.connect(self._findNext) self.findPreviousScut = QShortcut(QKeySequence.FindPrevious, self.widgetEditor) self.findPreviousScut.setContext(Qt.WidgetWithChildrenShortcut) self.findPreviousScut.activated.connect(self._findPrev) # Escape on editor hides the find bar self.findScut = QShortcut(Qt.Key_Escape, self.widgetEditor) self.findScut.setContext(Qt.WidgetWithChildrenShortcut) self.findScut.activated.connect(self._closeFind) def _toggleFind(self): self.tabEditorWidget.currentWidget().newEditor.toggleFindWidget() def _openFind(self): self.tabEditorWidget.currentWidget().newEditor.openFindWidget() def _closeFind(self): self.tabEditorWidget.currentWidget().newEditor.closeFindWidget() def _findNext(self): self.tabEditorWidget.currentWidget().newEditor.findText(True) def _findPrev(self): self.tabEditorWidget.currentWidget().newEditor.findText(False) def _textFindChanged(self): if self.lineEditFind.text(): self.findNextButton.setEnabled(True) self.findPrevButton.setEnabled(True) self.tabEditorWidget.currentWidget().newEditor.findText(True, showMessage=False, findFirst=True) else: self.lineEditFind.setStyleSheet('') self.findNextButton.setEnabled(False) self.findPrevButton.setEnabled(False) def onClickGoToLine(self, item, column): tabEditor = self.tabEditorWidget.currentWidget().newEditor if item.text(1) == 'syntaxError': check = tabEditor.syntaxCheck(fromContextMenu=False) if check and not tabEditor.isReadOnly(): self.tabEditorWidget.currentWidget().save() return linenr = int(item.text(1)) itemName = str(item.text(0)) charPos = itemName.find(' ') if charPos != -1: objName = itemName[0:charPos] else: objName = itemName tabEditor.goToLine(objName, linenr) def toggleEditor(self, checked): self.splitterObj.show() if checked else self.splitterObj.hide() if not self.tabEditorWidget: self.tabEditorWidget.enableToolBarEditor(checked) self.tabEditorWidget.restoreTabsOrAddNew() def toggleObjectListWidget(self, checked): self.listClassMethod.show() if checked else self.listClassMethod.hide() def pasteEditor(self): self.tabEditorWidget.currentWidget().newEditor.paste() def cutEditor(self): self.tabEditorWidget.currentWidget().newEditor.cut() def copyEditor(self): self.tabEditorWidget.currentWidget().newEditor.copy() def runScriptEditor(self): self.tabEditorWidget.currentWidget().newEditor.runScriptCode() def commentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(True) def uncommentCode(self): self.tabEditorWidget.currentWidget().newEditor.commentEditorCode(False) def openScriptFileExtEditor(self): tabWidget = self.tabEditorWidget.currentWidget() path = tabWidget.path import subprocess try: subprocess.Popen([os.environ['EDITOR'], path]) except KeyError: QDesktopServices.openUrl(QUrl.fromLocalFile(path)) def openScriptFile(self): lastDirPath = self.settings.value("pythonConsole/lastDirPath", QDir.homePath()) openFileTr = QCoreApplication.translate("PythonConsole", "Open File") fileList, selected_filter = QFileDialog.getOpenFileNames( self, openFileTr, lastDirPath, "Script file (*.py)") if fileList: for pyFile in fileList: for i in range(self.tabEditorWidget.count()): tabWidget = self.tabEditorWidget.widget(i) if tabWidget.path == pyFile: self.tabEditorWidget.setCurrentWidget(tabWidget) break else: tabName = QFileInfo(pyFile).fileName() self.tabEditorWidget.newTabEditor(tabName, pyFile) lastDirPath = QFileInfo(pyFile).path() self.settings.setValue("pythonConsole/lastDirPath", pyFile) self.updateTabListScript(pyFile, action='append') def saveScriptFile(self): tabWidget = self.tabEditorWidget.currentWidget() try: tabWidget.save() except (IOError, OSError) as error: msgText = QCoreApplication.translate('PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) def saveAsScriptFile(self, index=None): tabWidget = self.tabEditorWidget.currentWidget() if not index: index = self.tabEditorWidget.currentIndex() if not tabWidget.path: fileName = self.tabEditorWidget.tabText(index) + '.py' folder = self.settings.value("pythonConsole/lastDirPath", QDir.homePath()) pathFileName = os.path.join(folder, fileName) fileNone = True else: pathFileName = tabWidget.path fileNone = False saveAsFileTr = QCoreApplication.translate("PythonConsole", "Save File As") filename, filter = QFileDialog.getSaveFileName(self, saveAsFileTr, pathFileName, "Script file (*.py)") if filename: try: tabWidget.save(filename) except (IOError, OSError) as error: msgText = QCoreApplication.translate('PythonConsole', 'The file <b>{0}</b> could not be saved. Error: {1}').format(tabWidget.path, error.strerror) self.callWidgetMessageBarEditor(msgText, 2, False) if fileNone: tabWidget.path = None else: tabWidget.path = pathFileName return if not fileNone: self.updateTabListScript(pathFileName, action='remove') def openHelp(self): QgsHelp.openHelp("plugins/python_console.html") def openSettings(self): if optionsDialog(self).exec_(): self.shell.refreshSettingsShell() self.shellOut.refreshSettingsOutput() self.tabEditorWidget.refreshSettingsEditor() def callWidgetMessageBar(self, text): self.shellOut.widgetMessageBar(iface, text) def callWidgetMessageBarEditor(self, text, level, timed): self.tabEditorWidget.widgetMessageBar(iface, text, level, timed) def updateTabListScript(self, script, action=None): if action == 'remove': self.tabListScript.remove(script) elif action == 'append': if not self.tabListScript: self.tabListScript = [] if script not in self.tabListScript: self.tabListScript.append(script) else: self.tabListScript = [] self.settings.setValue("pythonConsole/tabScripts", self.tabListScript) def saveSettingsConsole(self): self.settings.setValue("pythonConsole/splitterConsole", self.splitter.saveState()) self.settings.setValue("pythonConsole/splitterObj", self.splitterObj.saveState()) self.settings.setValue("pythonConsole/splitterEditor", self.splitterEditor.saveState()) self.shell.writeHistoryFile(True) def restoreSettingsConsole(self): storedTabScripts = self.settings.value("pythonConsole/tabScripts", []) self.tabListScript = storedTabScripts self.splitter.restoreState(self.settings.value("pythonConsole/splitterConsole", QByteArray())) self.splitterEditor.restoreState(self.settings.value("pythonConsole/splitterEditor", QByteArray())) self.splitterObj.restoreState(self.settings.value("pythonConsole/splitterObj", QByteArray()))
class DataPlotly: # pylint: disable=too-many-instance-attributes """QGIS Plugin Implementation.""" VERSION = '2.3' def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize processing provider self.provider = DataPlotlyProvider(plugin_version=DataPlotly.VERSION) # initialize locale locale = QSettings().value('locale/userLocale', 'en_US')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'DataPlotly_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) self.dock_widget = None self.show_dock_action = None self.menu = None self.toolbar = None self.plot_item_metadata = PlotLayoutItemMetadata() self.plot_item_gui_metadata = None QgsApplication.layoutItemRegistry().addLayoutItemType( self.plot_item_metadata) # noinspection PyMethodMayBeStatic def tr(self, message): # pylint: disable=no-self-use """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('DataPlotly', message) def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" self.menu = QMenu(self.tr('&DataPlotly')) self.iface.pluginMenu().addMenu(self.menu) # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar('DataPlotly') self.toolbar.setObjectName('DataPlotly') self.dock_widget = DataPlotlyDock() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock_widget) self.dock_widget.hide() self.show_dock_action = QAction(GuiUtils.get_icon('dataplotly.svg'), self.tr('DataPlotly')) self.show_dock_action.setToolTip(self.tr('Shows the DataPlotly dock')) self.show_dock_action.setCheckable(True) self.dock_widget.setToggleVisibilityAction(self.show_dock_action) self.menu.addAction(self.show_dock_action) self.toolbar.addAction(self.show_dock_action) # Add processing provider self.initProcessing() # Add layout gui utils self.plot_item_gui_metadata = PlotLayoutItemGuiMetadata() QgsGui.layoutItemGuiRegistry().addLayoutItemGuiMetadata( self.plot_item_gui_metadata) def initProcessing(self): """Create the Processing provider""" QgsApplication.processingRegistry().addProvider(self.provider) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" self.show_dock_action.deleteLater() self.show_dock_action = None self.menu.deleteLater() self.menu = None self.toolbar.deleteLater() self.toolbar = None # Remove processing provider QgsApplication.processingRegistry().removeProvider(self.provider) def loadPlotFromDic(self, plot_dic): """ Calls the method to load the DataPlotly dialog with a given dictionary """ self.dock_widget.main_panel.showPlotFromDic(plot_dic) self.dock_widget.setUserVisible(True)
def open_menu(self, pos): """ :type pos: QPoint :return: """ index = self.indexAt(pos) node: PlanetNode = self.model().get_node(index) if (node.node_type() == NodeT.LOAD_MORE and node.parent() == self.model().root): return menu = QMenu() # Single, current Item's index add_menu_section_action('Current item', menu) if node.has_footprint() or node.has_group_footprint(): zoom_fp_act = QAction('Zoom to footprint', menu) # noinspection PyUnresolvedReferences zoom_fp_act.triggered[bool].connect( lambda: self.zoom_to_footprint([node])) menu.addAction(zoom_fp_act) if node.can_load_preview_layer(): prev_layer_act = QAction('Add preview layer to map', menu) # noinspection PyUnresolvedReferences prev_layer_act.triggered[bool].connect( lambda: self.add_preview_groups([node])) if node.child_images_count() > CHILD_COUNT_THRESHOLD_FOR_PREVIEW: prev_layer_act.setEnabled(False) prev_layer_act.setToolTip("The node contains too many images to preview") menu.setToolTipsVisible(True) menu.addAction(prev_layer_act) if node.item_id() and node.has_resource(): copy_id_act = QAction('Copy ID to clipboard', menu) # noinspection PyUnresolvedReferences copy_id_act.triggered[bool].connect( lambda: self.copy_ids_to_clipboard([node])) menu.addAction(copy_id_act) # Selected Items sel_model = self.selectionModel() model = self.model() # Ensure to grab only first column of indexes (or will get duplicates) all_nodes = [model.get_node(i) for i in sel_model.selectedIndexes() if i.column() == 0] log.debug(f'Selected items: {len(all_nodes)}') if len(all_nodes) == 1 and all_nodes[0] == node: menu.exec_(self.viewport().mapToGlobal(pos)) return nodes_have_footprints = \ [node for node in all_nodes if node.has_footprint()] nodes_w_ids = \ [node for node in all_nodes if node.item_id() and node.has_resource()] nodes_can_prev = \ [node for node in all_nodes if node.can_load_preview_layer() and node.has_resource()] if any([nodes_have_footprints, nodes_w_ids, nodes_can_prev]): add_menu_section_action(f'Selected images', menu) if nodes_have_footprints: zoom_fps_act = QAction( f'Zoom to total footprint ' f'({len(nodes_have_footprints)} items)', menu) # noinspection PyUnresolvedReferences zoom_fps_act.triggered[bool].connect( lambda: self.zoom_to_footprint(nodes_have_footprints)) menu.addAction(zoom_fps_act) if nodes_can_prev: prev_layers_act = QAction( f'Add preview layer to map ' f'({len(nodes_can_prev)} items)', menu) # noinspection PyUnresolvedReferences prev_layers_act.triggered[bool].connect( lambda: self.add_preview_groups(nodes_can_prev)) menu.addAction(prev_layers_act) if nodes_w_ids: copy_ids_act = QAction( f'Copy IDs to clipboard ({len(nodes_w_ids)} items)', menu) # noinspection PyUnresolvedReferences copy_ids_act.triggered[bool].connect( lambda: self.copy_ids_to_clipboard(nodes_w_ids)) menu.addAction(copy_ids_act) menu.exec_(self.viewport().mapToGlobal(pos))
class XYZHubConnector(object): """base plugin""" def __init__(self, iface): """init""" import sys print(sys.version) self.iface = iface self.web_menu = "&XYZ Hub Connector" self.init_modules() self.obj = self def initGui(self): """startup""" parent = self.iface.mainWindow() ######## action, button icon = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/xyz.png")) icon_bbox = QIcon("%s/%s" % (config.PLUGIN_DIR, "images/bbox.svg")) self.action_connect = QAction(icon, "XYZ Hub Connection", parent) self.action_connect.setWhatsThis( QCoreApplication.translate(PLUGIN_NAME, "WhatsThis message")) self.action_connect.setStatusTip( QCoreApplication.translate(PLUGIN_NAME, "status tip message")) self.action_sync_edit = QAction( QIcon("%s/%s" % (config.PLUGIN_DIR, "images/sync.svg")), "Push changes to XYZ Hub", parent) self.action_clear_cache = QAction( QIcon("%s/%s" % (config.PLUGIN_DIR, "images/delete.svg")), "Clear cache", parent) # self.action_sync_edit.setVisible(False) # disable magic sync self.edit_buffer.config_ui(self.enable_sync_btn) self.cb_layer_selected(self.iface.activeLayer()) ######## CONNECT action, button self.action_connect.triggered.connect(self.open_connection_dialog) self.action_sync_edit.triggered.connect(self.open_sync_edit_dialog) self.action_clear_cache.triggered.connect(self.open_clear_cache_dialog) ######## Add the toolbar + button self.toolbar = self.iface.addToolBar(PLUGIN_NAME) self.toolbar.setObjectName("XYZ Hub Connector") self.actions_menu = [ self.action_connect, self.action_sync_edit, self.action_clear_cache ] for a in [self.action_connect, self.action_sync_edit]: self.toolbar.addAction(a) for a in self.actions_menu: self.iface.addPluginToWebMenu(self.web_menu, a) # # uncomment to use menu button # tool_btn = QToolButton(self.toolbar) # tool_btn.setDefaultAction(self.action_connect) # tool_btn.setPopupMode(tool_btn.MenuButtonPopup) # self.xyz_widget_action = self.toolbar.addWidget(tool_btn) # uncomment to use menu button # self.toolbar.addAction(self.action_connect) self.action_help = None progress = QProgressBar() progress.setMinimum(0) progress.setMaximum(0) progress.reset() progress.hide() # progress = self.iface.statusBarIface().children()[2] # will be hidden by qgis self.iface.statusBarIface().addPermanentWidget(progress) self.pb = progress def init_modules(self): if LOG_TO_FILE: QgsApplication.messageLog().messageReceived.connect( cb_log_qgis) #, Qt.QueuedConnection # util.init_module() # parent = self.iface.mainWindow() parent = QgsProject.instance() self.secret = Secret(config.USER_PLUGIN_DIR + "/secret.ini") ######## Init xyz modules self.map_basemap_meta = basemap.load_default_xml() self.auth_manager = AuthManager(config.USER_PLUGIN_DIR + "/auth.ini") self.token_model = GroupTokenModel(parent) self.network = NetManager(parent) self.con_man = LoaderManager() self.con_man.config(self.network) self.edit_buffer = EditBuffer() ######## data flow # self.conn_info = SpaceConnectionInfo() ######## token self.token_model.load_ini(config.USER_PLUGIN_DIR + "/token.ini") ######## CALLBACK self.con_man.ld_pool.signal.progress.connect( self.cb_progress_busy) #, Qt.QueuedConnection self.con_man.ld_pool.signal.finished.connect(self.cb_progress_done) QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.edit_buffer.remove_layers) # QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.layer_man.remove_layers) # QgsProject.instance().layersAdded.connect( self.edit_buffer.config_connection) self.iface.currentLayerChanged.connect( self.cb_layer_selected) # UNCOMMENT self.iface.mapCanvas().extentsChanged.connect(self.reload_tile, Qt.QueuedConnection) QgsProject.instance().readProject.connect(self.import_project) self.import_project() def unload_modules(self): # self.con_man.disconnect_ux( self.iface) QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.edit_buffer.remove_layers) # QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.layer_man.remove_layers) # QgsProject.instance().layersAdded.disconnect( self.edit_buffer.config_connection) self.edit_buffer.unload_connection() self.iface.currentLayerChanged.disconnect( self.cb_layer_selected) # UNCOMMENT self.iface.mapCanvas().extentsChanged.disconnect(self.reload_tile) # utils.disconnect_silent(self.iface.currentLayerChanged) self.secret.deactivate() if LOG_TO_FILE: QgsApplication.messageLog().messageReceived.disconnect(cb_log_qgis) # close_file_logger() pass def unload(self): """teardown""" self.unload_modules() # remove the plugin menu item and icon self.iface.removePluginWebMenu(self.web_menu, self.action_help) self.toolbar.clear( ) # remove action from custom toolbar (toolbar still exist) self.toolbar.deleteLater() for a in self.actions_menu: self.iface.removePluginWebMenu(self.web_menu, a) # remove progress self.iface.statusBarIface().removeWidget(self.pb) ############### # Callback ############### def cb_layer_selected(self, qlayer): flag_xyz = True if qlayer is not None and is_xyz_supported_layer( qlayer) else False if flag_xyz: self.edit_buffer.config_connection([qlayer]) self.edit_buffer.enable_ui(qlayer.id()) else: msg = "No XYZHub Layer selected" self.enable_sync_btn(False, msg) # disable magic sync # self.action_sync_edit.setEnabled(flag_xyz) def enable_sync_btn(self, flag, msg=""): msg = msg or ("No changes detected since last push" if not flag else "Push changes") self.action_sync_edit.setToolTip(msg) self.action_sync_edit.setEnabled(flag) ############### # Callback of action (main function) ############### def cb_success_msg(self, title, msg="", dt=5): self.iface.messageBar().pushMessage(config.TAG_PLUGIN, ": ".join([title, msg]), Qgis.Success, dt) def make_cb_success(self, title, msg="", dt=5): def _cb_success_msg(): self.cb_success_msg(title, msg, dt=dt) return _cb_success_msg def make_cb_success_args(self, title, msg="", dt=5): def _cb_success_msg(args): a, kw = parse_qt_args(args) txt = ". ".join(map(str, a)) self.cb_success_msg(title, txt, dt=dt) return _cb_success_msg def cb_handle_error_msg(self, e): err = parse_exception_obj(e) if isinstance(err, ChainInterrupt): e0, idx = err.args[0:2] else: e0 = err if isinstance(e0, (net_handler.NetworkError, net_handler.NetworkTimeout)): ok = self.show_net_err(e0) if ok: return elif isinstance(e0, EmptyXYZSpaceError): ret = exec_warning_dialog("XYZ Hub", "Requested query returns no features") return self.show_err_msgbar(err) def show_net_err(self, err): reply_tag, status, reason, body, err_str, url = err.args[:6] if reply_tag in ["count", "statistics"]: # too many error # msg = "Network Error: %s: %s. %s"%(status, reason, err_str) return 1 detail = "\n".join(["Request:", url, "", "Response:", body]) msg = ("%s: %s\n" % (status, reason) + "There was a problem connecting to the server") if status in [401, 403]: msg += ( "\n\n" + "Please input valid token with correct permissions." + "\n" + "Token is generated via " + "<a href='https://xyz.api.here.com/token-ui/'>https://xyz.api.here.com/token-ui/</a>" ) ret = exec_warning_dialog("Network Error", msg, detail) return 1 def show_err_msgbar(self, err): self.iface.messageBar().pushMessage("Error", repr(err), Qgis.Warning, 3) msg = format_traceback(err) QgsMessageLog.logMessage(msg, config.TAG_PLUGIN, Qgis.Warning) def cb_progress_busy(self, n_active): if n_active > 1: return self.flag_pb_show = True self.cb_progress_refresh() def cb_progress_done(self): self.flag_pb_show = False self.cb_progress_refresh() def cb_progress_refresh(self): if not hasattr(self, "flag_pb_show"): return pb = self.pb if self.flag_pb_show: pb.show() # print_qgis("show",pb) else: pb.hide() # print_qgis("hide") ############### # Action (main function) ############### # UNUSED def refresh_canvas(self): # self.iface.activeLayer().triggerRepaint() self.iface.mapCanvas().refresh() def previous_canvas_extent(self): self.iface.mapCanvas().zoomToPreviousExtent() # def new_main_dialog(self): parent = self.iface.mainWindow() dialog = MainDialog(parent) dialog.config(self.token_model) dialog.config_secret(self.secret) auth = self.auth_manager.get_auth() dialog.config_basemap(self.map_basemap_meta, auth) con = self.con_man.make_con("create") con.signal.finished.connect( dialog.btn_use.clicked.emit) # can be optimized !! con.signal.error.connect(self.cb_handle_error_msg) con = self.con_man.make_con("list") con.signal.results.connect(make_fun_args(dialog.cb_display_spaces)) con.signal.error.connect(self.cb_handle_error_msg) con.signal.error.connect(lambda e: dialog.cb_enable_token_ui()) con.signal.finished.connect(dialog.cb_enable_token_ui) con = self.con_man.make_con("edit") con.signal.finished.connect(dialog.btn_use.clicked.emit) con.signal.error.connect(self.cb_handle_error_msg) con = self.con_man.make_con("delete") con.signal.results.connect(dialog.btn_use.clicked.emit) con.signal.error.connect(self.cb_handle_error_msg) con = self.con_man.make_con("stat") con.signal.results.connect(make_fun_args( dialog.cb_display_space_count)) con.signal.error.connect(self.cb_handle_error_msg) ############ clear cache btn dialog.signal_clear_cache.connect(self.open_clear_cache_dialog) ############ add map tile btn dialog.signal_add_basemap.connect(self.add_basemap_layer) ############ btn: new, edit, delete space dialog.signal_new_space.connect(self.start_new_space) dialog.signal_edit_space.connect(self.start_edit_space) dialog.signal_del_space.connect(self.start_delete_space) ############ Use Token btn dialog.signal_use_token.connect(lambda a: self.con_man.finish_fast()) dialog.signal_use_token.connect(self.start_use_token) ############ get count dialog.signal_space_count.connect( self.start_count_feat, Qt.QueuedConnection) # queued -> non-blocking ui ############ connect btn dialog.signal_space_connect.connect(self.start_load_layer) dialog.signal_space_tile.connect(self.start_load_tile) ############ upload btn dialog.signal_upload_space.connect(self.start_upload_space) return dialog def start_new_space(self, args): con = self.con_man.get_con("create") con.start_args(args) def start_edit_space(self, args): con = self.con_man.get_con("edit") con.start_args(args) def start_delete_space(self, args): con = self.con_man.get_con("delete") con.start_args(args) def start_use_token(self, args): con = self.con_man.get_con("list") con.start_args(args) def start_count_feat(self, args): con = self.con_man.get_con("stat") con.start_args(args) def start_upload_space(self, args): con_upload = UploadLayerController(self.network, n_parallel=2) self.con_man.add_background(con_upload) # con_upload.signal.finished.connect( self.make_cb_success("Uploading finish") ) con_upload.signal.results.connect( self.make_cb_success_args("Uploading finish")) con_upload.signal.error.connect(self.cb_handle_error_msg) con = InitUploadLayerController(self.network) self.con_man.add_background(con) con.signal.results.connect(con_upload.start_args) con.signal.error.connect(self.cb_handle_error_msg) con.start_args(args) def start_load_layer(self, args): # create new con # config # run ############ connect btn con_load = LoadLayerController(self.network, n_parallel=1) self.con_man.add_background(con_load) # con_load.signal.finished.connect( self.make_cb_success("Loading finish") ) con_load.signal.results.connect( self.make_cb_success_args("Loading finish")) # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection) con_load.signal.error.connect(self.cb_handle_error_msg) con_load.start_args(args) # con.signal.results.connect( self.layer_man.add_args) # IMPORTANT def start_load_tile(self, args): canvas = self.iface.mapCanvas() rect = bbox_utils.extend_to_rect(bbox_utils.get_bounding_box(canvas)) level = tile_utils.get_zoom_for_current_map_scale(canvas) # rect = (-180,-90,180,90) # level = 0 a, kw = parse_qt_args(args) kw["tile_schema"] = "here" kw["tile_ids"] = tile_utils.bboxToListColRow(*rect, level) # kw["limit"] = 100 ############ connect btn con_load = TileLayerLoader(self.network, n_parallel=1) self.con_man.add_layer(con_load) # con_load.signal.finished.connect( self.make_cb_success("Tiles loaded") ) con_load.signal.results.connect( self.make_cb_success_args("Tiles loaded", dt=2)) # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection) con_load.signal.error.connect(self.cb_handle_error_msg) con_load.start_args(make_qt_args(*a, **kw)) def reload_tile(self): canvas = self.iface.mapCanvas() rect = bbox_utils.extend_to_rect(bbox_utils.get_bounding_box(canvas)) level = tile_utils.get_zoom_for_current_map_scale(canvas) kw = dict() kw["tile_schema"] = "here" kw["tile_ids"] = tile_utils.bboxToListColRow(*rect, level) # kw["limit"] = 100 unique_con = set() lst_con = list() for qnode in [ vl for vl in QgsProject.instance().layerTreeRoot().checkedLayers( ) if is_xyz_supported_layer(vl) ] + [ g for g in QgsProject.instance().layerTreeRoot().findGroups() if len(g.children()) == 0 and g.isVisible() and is_xyz_supported_node(g) ]: xlayer_id = qnode.customProperty("xyz-hub-id") con = self.con_man.get_from_xyz_layer(xlayer_id) if con is None: continue if con in unique_con: continue lst_con.append(con) unique_con.add(con) # print_qgis(lst_con) # print_qgis(self.con_man._layer_ptr) for con in lst_con: print_qgis(con.status) print_qgis("loading tile", level, rect) con.restart(**kw) def add_basemap_layer(self, args): a, kw = parse_qt_args(args) meta, app_id, app_code = a self.auth_manager.save(app_id, app_code) basemap.add_basemap_layer(meta, app_id, app_code) ############### # import project function ############### def import_project(self): self.init_tile_loader() def init_tile_loader(self): cnt = 0 for qnode in [ g for g in QgsProject.instance().layerTreeRoot().findGroups() if is_xyz_supported_node(g) ]: try: layer = XYZLayer.load_from_qnode(qnode) con_load = TileLayerLoader(self.network, n_parallel=1, layer=layer) ptr = self.con_man.add_layer(con_load) # con_load.signal.finished.connect( self.make_cb_success("Tiles loaded") ) con_load.signal.results.connect( self.make_cb_success_args("Tiles loaded", dt=2)) # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection) con_load.signal.error.connect(self.cb_handle_error_msg) cnt += 1 except: pass # print_qgis(self.con_man._layer_ptr) self.cb_success_msg("Import XYZ Layer", "%s XYZ Layer imported" % cnt, dt=2) ############### # Open dialog ############### def open_clear_cache_dialog(self): dialog = ConfirmDialog( "Delete cache will make loaded layer unusable !!") ret = dialog.exec_() if ret != dialog.Ok: return utils.clear_cache() def open_connection_dialog(self): dialog = self.new_main_dialog() vlayer = self.iface.activeLayer() dialog.set_layer(vlayer) dialog.exec_() self.con_man.finish_fast() # self.startTime = time.time() def open_sync_edit_dialog(self): vlayer = self.iface.activeLayer() layer_buffer = self.edit_buffer.get_layer_buffer(vlayer.id()) lst_added_feat, removed_ids = layer_buffer.get_sync_feat() conn_info = layer_buffer.get_conn_info() # print_qgis("lst_added_feat: ",lst_added_feat) # print_qgis("removed_feat: ", removed_ids) con = EditSyncController(self.network) self.con_man.add_background(con) con.signal.finished.connect(layer_buffer.sync_complete) con.signal.results.connect( self.make_cb_success_args("Sync edit finish")) con.signal.error.connect(self.cb_handle_error_msg) con.start(conn_info, layer_buffer, lst_added_feat, removed_ids)
def createMenu(self): self.menu.clear() self.menu.setMinimumWidth(self.width()) fill_down_action = QAction(self.tr('Fill Down'), self.menu) fill_down_action.triggered.connect(self.fillDown) fill_down_action.setToolTip( self.tr('Copy the first value down to all other rows')) self.menu.addAction(fill_down_action) calculate_by_expression = QAction( QCoreApplication.translate('BatchPanel', 'Calculate by Expression…'), self.menu) calculate_by_expression.setIcon( QgsApplication.getThemeIcon('/mActionCalculateField.svg')) calculate_by_expression.triggered.connect(self.calculateByExpression) calculate_by_expression.setToolTip( self.tr('Calculates parameter values by evaluating an expression')) self.menu.addAction(calculate_by_expression) add_by_expression = QAction( QCoreApplication.translate('BatchPanel', 'Add Values by Expression…'), self.menu) add_by_expression.triggered.connect(self.addByExpression) add_by_expression.setToolTip( self.tr('Adds new parameter values by evaluating an expression')) self.menu.addAction(add_by_expression) if not self.parameterDefinition.isDestination() and isinstance( self.parameterDefinition, QgsFileFilterGenerator): self.menu.addSeparator() find_by_pattern_action = QAction( QCoreApplication.translate('BatchPanel', 'Add Files by Pattern…'), self.menu) find_by_pattern_action.triggered.connect(self.addFilesByPattern) find_by_pattern_action.setToolTip( self.tr('Adds files by a file pattern match')) self.menu.addAction(find_by_pattern_action) select_file_action = QAction( QCoreApplication.translate('BatchInputSelectionPanel', 'Select Files…'), self.menu) select_file_action.triggered.connect(self.showFileSelectionDialog) self.menu.addAction(select_file_action) select_directory_action = QAction( QCoreApplication.translate('BatchInputSelectionPanel', 'Add All Files from a Directory…'), self.menu) select_directory_action.triggered.connect( self.showDirectorySelectionDialog) self.menu.addAction(select_directory_action) if not isinstance(self.parameterDefinition, QgsProcessingParameterFile): select_layer_action = QAction( QCoreApplication.translate('BatchInputSelectionPanel', 'Select from Open Layers…'), self.menu) select_layer_action.triggered.connect( self.showLayerSelectionDialog) self.menu.addAction(select_layer_action)
class Plugin(QGISPluginBase): """docstring for Plugin""" def __init__(self, iface): super(Plugin, self).__init__() self.iface = iface locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.i18nPath, 'plugin_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) def tr(self, message): return QApplication.translate('Plugin', message) def initGui(self): self.paste_geometry_action = QAction(self.tr('Paste Geometry'), self.iface.mainWindow()) self.paste_geometry_action.setIcon( QIcon(os.path.join(self.dir, 'icon.svg'))) self.paste_geometry_action.setShortcut(QKeySequence('Ctrl+Shift+G')) self.paste_geometry_action.setToolTip(self.tr('Paste Geometry')) self.paste_geometry_action.setStatusTip(self.description) self.paste_geometry_action.setEnabled(False) self.paste_geometry_action.triggered.connect(self.pasteGeometry) self.iface.editMenu().insertAction( self.iface.actionDeleteSelected(), self.paste_geometry_action, ) self.iface.digitizeToolBar().insertAction( self.iface.actionDeleteSelected(), self.paste_geometry_action, ) self.iface.currentLayerChanged.connect(self._changeCurrentLayerHandle) self._changeCurrentLayerHandle(self.iface.activeLayer()) def unload(self): self.iface.editMenu().removeAction(self.paste_geometry_action) self.iface.digitizeToolBar().removeAction(self.paste_geometry_action) self.iface.currentLayerChanged.disconnect( self._changeCurrentLayerHandle) def pushMessage(self, title, message, level=QGis23MessageBarLevel.Info): self.iface.messageBar().pushMessage(title, message, level) def pushLog(self, msg, level=QGis23MessageLogLevel.Info): QgsMessageLog.logMessage(msg, self.name, level) def pasteGeometry(self): geoms = self._tryGetFeaturesGeomsFromClipBoard() if len(geoms) > 1: self.pushMessage( self.tr('Paste geometry'), self.tr('Fail to paste. Multiple features in the clipboard.'), QGis23MessageBarLevel.Critical) return if len(geoms) == 0: self.pushMessage( self.tr('Paste geometry'), self.tr('Nothing to paste. No features in the clipboard.'), QGis23MessageBarLevel.Critical) return geom = geoms[0] layer = self.iface.activeLayer() selected_features = layer.selectedFeatures() if len(selected_features) > 1: self.pushMessage( self.tr('Paste geometry'), # 'Multiple features selected. Need only one.', self.tr( 'Multiple features are selected. There should be only one.' ), QGis23MessageBarLevel.Critical) return if len(selected_features) == 0: self.pushMessage( self.tr('Paste geometry'), self.tr('Nowhere to paste. No target feature selected.'), QGis23MessageBarLevel.Critical) return feature = selected_features[0] if feature.geometry().type() != geom.type(): self.pushMessage( self.tr('Paste geometry'), self.tr('Incompatible geometries. Trying to paste %s to %s') % (getGeomtryName( geom.type()), getGeomtryName(feature.geometry().type())), QGis23MessageBarLevel.Critical) return result = layer.changeGeometry(feature.id(), geom) if not result: self.pushMessage( self.tr('Paste geometry'), self.tr('Something is wrong. Can\'t change geometry.'), QGis23MessageBarLevel.Critical) return # This is hack. It is not mandatory instruction. # But without new features not repaint. # May be I made something wrong above self.iface.mapCanvas().refresh() def _tryGetFeaturesGeomsFromClipBoard(self): cb = QApplication.clipboard() clipboard_text = cb.text() if sys.version_info[0] == 2: clipboard_text = clipboard_text.encode('utf-8') reader = csv.DictReader(StringIO(clipboard_text), delimiter='\t') geoms = [] for row in reader: wkt_geom = row.get('wkt_geom') geom = QgsGeometry.fromWkt(wkt_geom) if not geom: self.pushLog('Can\'t create geometry from wkt: %s' % wkt_geom) continue geoms.append(geom) return geoms def _changeCurrentLayerHandle(self, layer): if layer and isinstance(layer, QgsVectorLayer): layer.selectionChanged.connect(self._checkPasteAvalability) layer.editingStarted.connect(self._checkPasteAvalability) layer.editingStopped.connect(self._checkPasteAvalability) self._checkPasteAvalability() def _checkPasteAvalability(self): layer = self.iface.activeLayer() is_available = False if layer and isinstance(layer, QgsVectorLayer) and layer.isEditable(): if len(layer.selectedFeatures()) == 1: is_available = True else: msg = self.tr("Select a target feature!") is_available = False else: msg = self.tr("Start editing a vector layer!") is_available = False if is_available: if len(self._tryGetFeaturesGeomsFromClipBoard()) == 0: msg = self.tr( "Copy feature with the geometry you need to paste first!") is_available = False self.paste_geometry_action.setEnabled(is_available) if is_available: self.paste_geometry_action.setToolTip(self.tr('Paste Geometry')) else: self.paste_geometry_action.setToolTip( "%s. %s" % (self.tr('Paste Geometry'), msg))