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 ): """Add a toolbar icon to the toolbar.""" 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.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action
class Send2GE: def __init__(self, iface): """Initialize class""" # save reference to QGIS interface self.iface = iface self.plugin_dir = get_file_dir(__file__) def initGui(self): """Initialize graphic user interface""" #create action that will be run by the plugin self.action = QAction( QIcon("%s/icons/cursor2.png" % self.plugin_dir), "Send to Google Earth", self.iface.mainWindow() ) self.action.setWhatsThis("Send to Google Earth") self.action.setStatusTip("Send coordinates of a mouse click to Google Earth") # add plugin menu to Vector toolbar self.iface.addPluginToMenu("Send2GoogleEarth",self.action) # add icon to new menu item in Vector toolbar self.iface.addToolBarIcon(self.action) # connect action to the run method self.action.triggered.connect(self.run) # prepare map tool self.mapTool = Send2GEtool(self.iface) #self.iface.mapCanvas().mapToolSet.connect(self.mapToolChanged) def unload(self): """Actions to run when the plugin is unloaded""" # remove menu and icon from the menu self.iface.removeToolBarIcon(self.action) self.iface.removePluginMenu("Send2GoogleEarth",self.action) if self.iface.mapCanvas().mapTool() == self.mapTool: self.iface.mapCanvas().unsetMapTool(self.mapTool) del self.mapTool def run(self): """Action to run""" # create a string and show it self.iface.mapCanvas().setMapTool(self.mapTool)
def add_action( self, icon_path, text, callback, enabled_flag=True, checkable=False, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, menu=None, parent=None): icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) action.setCheckable(checkable) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if menu is not None: action.setMenu(menu) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToVectorMenu( self.menu, action) self.actions.append(action) return action
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)
def add_menu_action(self, icon_path: str, text: str, callback: Callable, enabled_flag: bool = True, add_to_menu: bool = True, menu_type: str = None, add_to_toolbar: bool = True, status_tip: str = None, whats_this: str = None, parent: QWidget = None) -> QAction: """ Add a toolbar icon to the toolbar, associating it with an action linked to a function called on click; the action is also added to self.actions['menus'] list. Args: 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. text: Text that should be shown in menu items for this action. callback: Function to be called when the action is triggered. enabled_flag: Whether the action should be enabled by default or not. add_to_menu: Whether the action should be added to the menu. menu_type: Type of menu add the action to, other than the main one (None). add_to_toolbar: Whether the action should also be added to the toolbar. status_tip: Optional text to show in a popup when mouse pointer hovers over the action. whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. parent: Parent Qt widget for the new action Returns: The action that was created. """ if not menu_type: logger.debug("Add action \"%s\" to \"plugin\" toolbar menu" % text) else: logger.debug("Add action \"%s\" to \"%s\" toolbar menu" % (text, menu_type)) icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) # Optionally setup "Status" tip dialog if status_tip is not None: action.setStatusTip(status_tip) # Optionally setup "what's this?" tip dialog if whats_this is not None: action.setWhatsThis(whats_this) # Optionally adds plugin menu icon to Plugins toolbar if add_to_toolbar: self.iface.addToolBarIcon(action) # Add menu items to proper plugin category if add_to_menu: if not menu_type: self.iface.addPluginToMenu(self.menu, action) elif menu_type.lower() == "database": self.iface.addPluginToDatabaseMenu(self.menu, action) elif menu_type.lower() == "raster": self.iface.addPluginToRasterMenu(self.menu, action) elif menu_type.lower() == "vector": self.iface.addPluginToVectorMenu(self.menu, action) elif menu_type.lower() == "web": self.iface.addPluginToWebMenu(self.menu, action) else: logger.error("Invalid menu choice") raise RuntimeError("Invalid choice for action adding: %s" % menu_type) # Updates actions array and return inserted elements self.actions['menus'].append(action) return action
class DEMto3D(object): """QGIS Plugin Implementation.""" 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 locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'DEMto3D_{}.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) # Declare instance attributes self.action = None self.menu = '&DEMto3D' self.window = True # noinspection PyMethodMayBeStatic def tr(self, message): """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('DEMto3D', message) def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon = QIcon(":/plugins/DEMto3D/icons/demto3d.png") text = self.tr("DEM 3D printing") parent = self.iface.mainWindow() self.action = QAction(icon, text, parent) self.action.setObjectName(text) self.action.setStatusTip(text) self.action.triggered.connect(self.run) self.iface.addRasterToolBarIcon(self.action) self.iface.addPluginToRasterMenu(self.menu, self.action) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" self.iface.removePluginRasterMenu(self.menu, self.action) self.iface.removeRasterToolBarIcon(self.action) def run(self): layers = self.iface.mapCanvas().layers() raster = False if layers: for layer in layers: if layer.type() == layer.RasterLayer and QgsProject.instance( ).layerTreeRoot().findLayer(layer).isVisible(): raster = True break if raster and self.window: self.window = False demto3d_dlg = DEMto3D_dialog.DEMto3DDialog(self.iface) demto3d_dlg.exec_() canvas = self.iface.mapCanvas() if demto3d_dlg.extent: canvas.scene().removeItem(demto3d_dlg.extent) if demto3d_dlg.divisions: canvas.scene().removeItem(demto3d_dlg.divisions) self.window = True elif not raster: QMessageBox.information( self.iface.mainWindow(), "DEMto3D", self.tr("No visible raster layer loaded")) elif not layers: QMessageBox.information(self.iface.mainWindow(), "DEMto3D", self.tr("No visible raster layer loaded"))
def create_action( icon_path, text, callback, enabled_flag=True, status_tip=None, whats_this=None, parent=None, object_name=None): """ # adapted from RedLayers by E. Ferreguti Create an action. :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 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. :param object_name: Optional name to identify objects during customization :type object_name: str :returns: The action that was created. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) if callback: action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip: action.setStatusTip(status_tip) if whats_this: action.setWhatsThis(whats_this) if object_name: action.setObjectName(object_name) return action
class CreatePoint: """QGIS Plugin Implementation.""" 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 locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'CreatePoint_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Obtaining the map canvas self.canvas = iface.mapCanvas() def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/Create_Point/icon.png' #create action that will be run by the plugin self.action = QAction("Create Point", self.iface.mainWindow()) self.action.setIcon(QIcon(icon_path)) self.action.setWhatsThis("Create Point") self.action.setStatusTip("Click On Map And Draw Point") # add plugin menu to Vector toolbar self.iface.addPluginToMenu("Create_Point", self.action) # add icon to new menu item in Vector toolbar self.iface.addToolBarIcon(self.action) # connect action to the run method self.action.triggered.connect(self.run) # prepare map tool self.mapTool = Map_Tool(self.iface) #self.iface.mapCanvas().mapToolSet.connect(self.mapToolChanged) def unload(self): """Actions to run when the plugin is unloaded""" # remove menu and icon from the menu self.iface.removeToolBarIcon(self.action) self.iface.removePluginMenu("Create_Point", self.action) if self.iface.mapCanvas().mapTool() == self.mapTool: self.iface.mapCanvas().unsetMapTool(self.mapTool) del self.mapTool def run(self): #Check Active Layer Present Or Not self.active_point_layer = self.iface.mapCanvas().currentLayer() if not self.active_point_layer: self.iface.messageBar().pushMessage( "Active Layer", "No Active Layer Found Please Select Point Layer", level=Qgis.Warning) else: self.layer_type = self.active_point_layer.geometryType() if self.layer_type == QgsWkbTypes.PointGeometry: self.iface.mapCanvas().setMapTool(self.mapTool) else: self.iface.messageBar().pushMessage( "Active Layer", "Active Layer Is Not Point Type Layer Please Select Point Layer", level=Qgis.Warning)
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_magic_sync = QAction("Magic Sync (EXPERIMENTAL)", parent) if self.iface.activeLayer() is None: self.action_magic_sync.setEnabled(False) # self.action_magic_sync.setVisible(False) # disable magic sync ######## CONNECT action, button self.action_connect.triggered.connect(self.open_connection_dialog) self.action_magic_sync.triggered.connect(self.open_magic_sync_dialog) ######## Add the toolbar + button self.toolbar = self.iface.addToolBar(PLUGIN_NAME) self.toolbar.setObjectName("XYZ Hub Connector") self.actions = [self.action_connect] for a in self.actions: self.iface.addPluginToWebMenu(self.web_menu, a) # # uncomment to use menu button # tool_btn = QToolButton(self.toolbar) # for a in self.actions: # tool_btn.addAction(a) # 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): # 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.layer = LayerManager(parent, self.iface) self.network = NetManager(parent) self.con_man = LoaderManager() self.con_man.config(self.network) self.layer_man = LayerManager() ######## 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.layer_man.remove) QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.con_man.remove) # self.iface.currentLayerChanged.connect( self.cb_layer_selected) # UNCOMMENT if LOG_TO_FILE: QgsApplication.messageLog().messageReceived.connect(cb_log_qgis) def unload_modules(self): # self.con_man.disconnect_ux( self.iface) QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.layer_man.remove) QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.con_man.remove) # utils.disconnect_silent(self.iface.currentLayerChanged) # self.iface.mapCanvas().extentsChanged.disconnect( self.debug_reload) self.secret.deactivate() # 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: self.iface.removePluginWebMenu(self.web_menu, a) ############### # Callback ############### def cb_layer_selected(self, qlayer): flag_xyz = True if qlayer is not None and self.layer.is_xyz_supported_layer( qlayer) else False # disable magic sync # self.action_magic_sync.setEnabled(flag_xyz) ############### # Callback of action (main function) ############### def cb_success_msg(self, msg, info=""): self.iface.messageBar().pushMessage(msg, info, Qgis.Success, 5) def make_cb_success(self, msg, info=""): def _cb_success_msg(): txt = info self.cb_success_msg(msg, txt) return _cb_success_msg def make_cb_success_args(self, msg, info=""): def _cb_success_msg(args): a, kw = parse_qt_args(args) txt = ". ".join(map(str, a)) self.cb_success_msg(msg, txt) 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] 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 == 403: msg += "\n\n" + "Please make sure that the token has WRITE permission" ret = exec_warning_dialog("Network Error", msg, detail) return 1 def show_err_msgbar(self, err): self.iface.messageBar().pushMessage(TAG_PLUGIN, repr(err), Qgis.Warning, 3) msg = format_traceback(err) QgsMessageLog.logMessage(msg, 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 load_bbox(self, con, args): bbox = bbox_utils.extend_to_bbox( bbox_utils.get_bounding_box(self.iface)) a, kw = parse_qt_args(args) kw["bbox"] = bbox kw["limit"] = 1000 con.start(*a, **kw) # 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) ############ 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 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) ############### # 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() # not used def open_magic_sync_dialog(self): pass
class MetaSearchPlugin(object): """base plugin""" def __init__(self, iface): """init""" self.iface = iface self.context = StaticContext() self.action_run = None self.action_help = None self.dialog = None self.web_menu = '&MetaSearch' def initGui(self): """startup""" # run run_icon = QIcon('%s/%s' % (self.context.ppath, 'images/MetaSearch.png')) self.action_run = QAction(run_icon, 'MetaSearch', self.iface.mainWindow()) self.action_run.setWhatsThis(QCoreApplication.translate('MetaSearch', 'MetaSearch plugin')) self.action_run.setStatusTip(QCoreApplication.translate('MetaSearch', 'Search Metadata Catalogues')) self.action_run.triggered.connect(self.run) self.iface.addWebToolBarIcon(self.action_run) self.iface.addPluginToWebMenu(self.web_menu, self.action_run) # help help_icon = QgsApplication.getThemeIcon('/mActionHelpContents.svg') self.action_help = QAction(help_icon, 'Help', self.iface.mainWindow()) self.action_help.setWhatsThis(QCoreApplication.translate('MetaSearch', 'MetaSearch plugin help')) self.action_help.setStatusTip(QCoreApplication.translate('MetaSearch', 'Get Help on MetaSearch')) self.action_help.triggered.connect(self.help) self.iface.addPluginToWebMenu(self.web_menu, self.action_help) # prefab the dialog but not open it yet self.dialog = MetaSearchDialog(self.iface) def unload(self): """teardown""" # remove the plugin menu item and icon self.iface.removePluginWebMenu(self.web_menu, self.action_run) self.iface.removePluginWebMenu(self.web_menu, self.action_help) self.iface.removeWebToolBarIcon(self.action_run) def run(self): """open MetaSearch""" self.dialog.exec_() def help(self): """open help in user's default web browser""" open_url(get_help_url())
class Plugin(): """The QGIS interface implementation for the InaSAFE plugin. This class acts as the 'glue' between QGIS and our custom logic. It creates a toolbar and menu bar entry and launches the InaSAFE user interface if these are activated. """ def __init__(self, iface): """Class constructor. On instantiation, the plugin instance will be assigned a copy of the QGIS iface object which will allow this plugin to access and manipulate the running QGIS instance that spawned it. :param iface:Quantum GIS iface instance. This instance is automatically passed to the plugin by QGIS when it loads the plugin. :type iface: QgisAppInterface """ # Save reference to the QGIS interface self.iface = iface self.dock_widget = None # Actions self.action_add_layers = None self.action_add_osm_layer = None self.action_add_petabencana_layer = None self.action_batch_runner = None self.action_dock = None self.action_extent_selector = None self.action_field_mapping = None self.action_multi_exposure = None self.action_function_centric_wizard = None self.action_import_dialog = None self.action_keywords_wizard = None self.action_minimum_needs = None self.action_minimum_needs_config = None self.action_multi_buffer = None self.action_options = None self.action_run_tests = None self.action_save_scenario = None self.action_shake_converter = None self.action_show_definitions = None self.action_toggle_rubberbands = None self.action_metadata_converter = None self.translator = None self.toolbar = None self.wizard = None self.actions = [] # list of all QActions we create for InaSAFE self.message_bar_item = None # Flag indicating if toolbar should show only common icons or not self.full_toolbar = False # print self.tr('InaSAFE') # For enable/disable the keyword editor icon self.iface.currentLayerChanged.connect(self.layer_changed) developer_mode = setting('developer_mode', False, expected_type=bool) self.hide_developer_buttons = (inasafe_release_status == 'final' and not developer_mode) # noinspection PyMethodMayBeStatic def tr(self, message): """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('Plugin', message) def add_action(self, action, add_to_toolbar=True, add_to_legend=False): """Add a toolbar icon to the InaSAFE toolbar. :param action: The action that should be added to the toolbar. :type action: QAction :param add_to_toolbar: Flag indicating whether the action should also be added to the InaSAFE toolbar. Defaults to True. :type add_to_toolbar: bool :param add_to_legend: Flag indicating whether the action should also be added to the layer legend menu. Default to False. :type add_to_legend: bool """ # store in the class list of actions for easy plugin unloading self.actions.append(action) self.iface.addPluginToMenu(self.tr('InaSAFE'), action) if add_to_toolbar: self.toolbar.addAction(action) if add_to_legend: # The id is the action name without spaces, tabs ... self.iface.addCustomActionForLayerType(action, self.tr('InaSAFE'), QgsMapLayer.VectorLayer, True) self.iface.addCustomActionForLayerType(action, self.tr('InaSAFE'), QgsMapLayer.RasterLayer, True) def _create_dock_toggle_action(self): """Create action for plugin dockable window (show/hide).""" # pylint: disable=W0201 icon = resources_path('img', 'icons', 'icon.svg') self.action_dock = QAction(QIcon(icon), self.tr('Toggle InaSAFE Dock'), self.iface.mainWindow()) self.action_dock.setObjectName('InaSAFEDockToggle') self.action_dock.setStatusTip(self.tr('Show/hide InaSAFE dock widget')) self.action_dock.setWhatsThis(self.tr('Show/hide InaSAFE dock widget')) self.action_dock.setCheckable(True) self.action_dock.setChecked(True) self.action_dock.triggered.connect(self.toggle_dock_visibility) self.add_action(self.action_dock) # -------------------------------------- # Create action for keywords creation wizard # ------------------------------------- def _create_keywords_wizard_action(self): """Create action for keywords creation wizard.""" icon = resources_path('img', 'icons', 'show-keyword-wizard.svg') self.action_keywords_wizard = QAction( QIcon(icon), self.tr('Keywords Creation Wizard'), self.iface.mainWindow()) self.action_keywords_wizard.setStatusTip( self.tr('Open InaSAFE keywords creation wizard')) self.action_keywords_wizard.setWhatsThis( self.tr('Open InaSAFE keywords creation wizard')) self.action_keywords_wizard.setEnabled(False) self.action_keywords_wizard.triggered.connect( self.show_keywords_wizard) self.add_action(self.action_keywords_wizard, add_to_legend=True) def _create_analysis_wizard_action(self): """Create action for IF-centric wizard.""" icon = resources_path('img', 'icons', 'show-wizard.svg') self.action_function_centric_wizard = QAction( QIcon(icon), self.tr('Impact Function Centric Wizard'), self.iface.mainWindow()) self.action_function_centric_wizard.setStatusTip( self.tr('Open InaSAFE impact function centric wizard')) self.action_function_centric_wizard.setWhatsThis( self.tr('Open InaSAFE impact function centric wizard')) self.action_function_centric_wizard.setEnabled(True) self.action_function_centric_wizard.triggered.connect( self.show_function_centric_wizard) self.add_action(self.action_function_centric_wizard) def _create_options_dialog_action(self): """Create action for options dialog.""" icon = resources_path('img', 'icons', 'configure-inasafe.svg') self.action_options = QAction(QIcon(icon), self.tr('Options'), self.iface.mainWindow()) self.action_options.setStatusTip( self.tr('Open InaSAFE options dialog')) self.action_options.setWhatsThis( self.tr('Open InaSAFE options dialog')) self.action_options.triggered.connect(self.show_options) self.add_action(self.action_options, add_to_toolbar=self.full_toolbar) def _create_minimum_needs_action(self): """Create action for minimum needs dialog.""" icon = resources_path('img', 'icons', 'show-minimum-needs.svg') self.action_minimum_needs = QAction( QIcon(icon), self.tr('Minimum Needs Calculator'), self.iface.mainWindow()) self.action_minimum_needs.setStatusTip( self.tr('Open InaSAFE minimum needs calculator')) self.action_minimum_needs.setWhatsThis( self.tr('Open InaSAFE minimum needs calculator')) self.action_minimum_needs.triggered.connect(self.show_minimum_needs) self.add_action(self.action_minimum_needs, add_to_toolbar=self.full_toolbar) def _create_multi_buffer_action(self): """Create action for multi buffer dialog.""" icon = resources_path('img', 'icons', 'show-multi-buffer.svg') self.action_multi_buffer = QAction(QIcon(icon), self.tr('Multi Buffer'), self.iface.mainWindow()) self.action_multi_buffer.setStatusTip( self.tr('Open InaSAFE multi buffer')) self.action_multi_buffer.setWhatsThis( self.tr('Open InaSAFE multi buffer')) self.action_multi_buffer.triggered.connect(self.show_multi_buffer) self.add_action(self.action_multi_buffer, add_to_toolbar=self.full_toolbar) def _create_minimum_needs_options_action(self): """Create action for global minimum needs dialog.""" icon = resources_path('img', 'icons', 'show-global-minimum-needs.svg') self.action_minimum_needs_config = QAction( QIcon(icon), self.tr('Minimum Needs Configuration'), self.iface.mainWindow()) self.action_minimum_needs_config.setStatusTip( self.tr('Open InaSAFE minimum needs configuration')) self.action_minimum_needs_config.setWhatsThis( self.tr('Open InaSAFE minimum needs configuration')) self.action_minimum_needs_config.triggered.connect( self.show_minimum_needs_configuration) self.add_action(self.action_minimum_needs_config, add_to_toolbar=self.full_toolbar) def _create_shakemap_converter_action(self): """Create action for converter dialog.""" icon = resources_path('img', 'icons', 'show-converter-tool.svg') self.action_shake_converter = QAction(QIcon(icon), self.tr('Shakemap Converter'), self.iface.mainWindow()) self.action_shake_converter.setStatusTip( self.tr('Open InaSAFE Converter')) self.action_shake_converter.setWhatsThis( self.tr('Open InaSAFE Converter')) self.action_shake_converter.triggered.connect( self.show_shakemap_importer) self.add_action(self.action_shake_converter, add_to_toolbar=self.full_toolbar) def _create_batch_runner_action(self): """Create action for batch runner dialog.""" icon = resources_path('img', 'icons', 'show-batch-runner.svg') self.action_batch_runner = QAction(QIcon(icon), self.tr('Batch Runner'), self.iface.mainWindow()) self.action_batch_runner.setStatusTip(self.tr('Open Batch Runner')) self.action_batch_runner.setWhatsThis(self.tr('Open Batch Runner')) self.action_batch_runner.triggered.connect(self.show_batch_runner) self.add_action(self.action_batch_runner, add_to_toolbar=self.full_toolbar) def _create_save_scenario_action(self): """Create action for save scenario dialog.""" icon = resources_path('img', 'icons', 'save-as-scenario.svg') self.action_save_scenario = QAction(QIcon(icon), self.tr('Save Current Scenario'), self.iface.mainWindow()) message = self.tr('Save current scenario to text file') self.action_save_scenario.setStatusTip(message) self.action_save_scenario.setWhatsThis(message) # noinspection PyUnresolvedReferences self.action_save_scenario.triggered.connect(self.save_scenario) self.add_action(self.action_save_scenario, add_to_toolbar=self.full_toolbar) def _create_osm_downloader_action(self): """Create action for import OSM Dialog.""" icon = resources_path('img', 'icons', 'show-osm-download.svg') self.action_import_dialog = QAction( QIcon(icon), self.tr('OpenStreetMap Downloader'), self.iface.mainWindow()) self.action_import_dialog.setStatusTip( self.tr('OpenStreetMap Downloader')) self.action_import_dialog.setWhatsThis( self.tr('OpenStreetMap Downloader')) self.action_import_dialog.triggered.connect(self.show_osm_downloader) self.add_action(self.action_import_dialog, add_to_toolbar=True) def _create_geonode_uploader_action(self): """Create action for Geonode uploader dialog.""" icon = resources_path('img', 'icons', 'geonode.png') label = tr('Geonode Uploader') self.action_geonode = QAction(QIcon(icon), label, self.iface.mainWindow()) self.action_geonode.setStatusTip(label) self.action_geonode.setWhatsThis(label) self.action_geonode.triggered.connect(self.show_geonode_uploader) self.add_action(self.action_geonode, add_to_toolbar=False) def _create_add_osm_layer_action(self): """Create action for import OSM Dialog.""" icon = resources_path('img', 'icons', 'add-osm-tiles-layer.svg') self.action_add_osm_layer = QAction( QIcon(icon), self.tr('Add OpenStreetMap Tile Layer'), self.iface.mainWindow()) self.action_add_osm_layer.setStatusTip( self.tr('Add OpenStreetMap Tile Layer')) self.action_add_osm_layer.setWhatsThis( self.tr('Use this to add an OSM layer to your map. ' 'It needs internet access to function.')) self.action_add_osm_layer.triggered.connect(self.add_osm_layer) self.add_action(self.action_add_osm_layer, add_to_toolbar=True) def _create_show_definitions_action(self): """Create action for showing definitions / help.""" icon = resources_path('img', 'icons', 'show-inasafe-help.svg') self.action_show_definitions = QAction(QIcon(icon), self.tr('InaSAFE Help'), self.iface.mainWindow()) self.action_show_definitions.setStatusTip(self.tr('Show InaSAFE Help')) self.action_show_definitions.setWhatsThis( self. tr('Use this to show a document describing all InaSAFE concepts.')) self.action_show_definitions.triggered.connect(self.show_definitions) self.add_action(self.action_show_definitions, add_to_toolbar=True) def _create_metadata_converter_action(self): """Create action for showing metadata converter dialog.""" icon = resources_path('img', 'icons', 'show-metadata-converter.svg') self.action_metadata_converter = QAction( QIcon(icon), self.tr('InaSAFE Metadata Converter'), self.iface.mainWindow()) self.action_metadata_converter.setStatusTip( self.tr('Convert metadata from version 4.3 to version 3.5.')) self.action_metadata_converter.setWhatsThis( self.tr('Use this tool to convert metadata 4.3 to version 3.5')) self.action_metadata_converter.triggered.connect( self.show_metadata_converter) self.add_action(self.action_metadata_converter, add_to_toolbar=self.full_toolbar) def _create_field_mapping_action(self): """Create action for showing field mapping dialog.""" icon = resources_path('img', 'icons', 'show-mapping-tool.svg') self.action_field_mapping = QAction( QIcon(icon), self.tr('InaSAFE Field Mapping Tool'), self.iface.mainWindow()) self.action_field_mapping.setStatusTip( self.tr('Assign field mapping to layer.')) self.action_field_mapping.setWhatsThis( self.tr('Use this tool to assign field mapping in layer.')) self.action_field_mapping.setEnabled(False) self.action_field_mapping.triggered.connect(self.show_field_mapping) self.add_action(self.action_field_mapping, add_to_toolbar=self.full_toolbar) def _create_multi_exposure_action(self): """Create action for showing the multi exposure tool.""" self.action_multi_exposure = QAction( QIcon(resources_path('img', 'icons', 'show-multi-exposure.svg')), self.tr('InaSAFE Multi Exposure Tool'), self.iface.mainWindow()) self.action_multi_exposure.setStatusTip( self.tr('Open the multi exposure tool.')) self.action_multi_exposure.setWhatsThis( self.tr('Open the multi exposure tool.')) self.action_multi_exposure.setEnabled(True) self.action_multi_exposure.triggered.connect(self.show_multi_exposure) self.add_action(self.action_multi_exposure, add_to_toolbar=self.full_toolbar) def _create_add_petabencana_layer_action(self): """Create action for import OSM Dialog.""" icon = resources_path('img', 'icons', 'add-petabencana-layer.svg') self.action_add_petabencana_layer = QAction( QIcon(icon), self.tr('Add PetaBencana Flood Layer'), self.iface.mainWindow()) self.action_add_petabencana_layer.setStatusTip( self.tr('Add PetaBencana Flood Layer')) self.action_add_petabencana_layer.setWhatsThis( self.tr('Use this to add a PetaBencana layer to your map. ' 'It needs internet access to function.')) self.action_add_petabencana_layer.triggered.connect( self.add_petabencana_layer) self.add_action(self.action_add_petabencana_layer, add_to_toolbar=self.full_toolbar) def _create_rubber_bands_action(self): """Create action for toggling rubber bands.""" icon = resources_path('img', 'icons', 'toggle-rubber-bands.svg') self.action_toggle_rubberbands = QAction( QIcon(icon), self.tr('Toggle Scenario Outlines'), self.iface.mainWindow()) message = self.tr('Toggle rubber bands showing scenario extents.') self.action_toggle_rubberbands.setStatusTip(message) self.action_toggle_rubberbands.setWhatsThis(message) # Set initial state self.action_toggle_rubberbands.setCheckable(True) flag = setting('showRubberBands', False, expected_type=bool) self.action_toggle_rubberbands.setChecked(flag) # noinspection PyUnresolvedReferences self.action_toggle_rubberbands.triggered.connect( self.dock_widget.toggle_rubber_bands) self.add_action(self.action_toggle_rubberbands) def _create_analysis_extent_action(self): """Create action for analysis extent dialog.""" icon = resources_path('img', 'icons', 'set-extents-tool.svg') self.action_extent_selector = QAction(QIcon(icon), self.tr('Set Analysis Area'), self.iface.mainWindow()) self.action_extent_selector.setStatusTip( self.tr('Set the analysis area for InaSAFE')) self.action_extent_selector.setWhatsThis( self.tr('Set the analysis area for InaSAFE')) self.action_extent_selector.triggered.connect( self.show_extent_selector) self.add_action(self.action_extent_selector) def _create_test_layers_action(self): """Create action for adding layers (developer mode, non final only).""" if self.hide_developer_buttons: return icon = resources_path('img', 'icons', 'add-test-layers.svg') self.action_add_layers = QAction(QIcon(icon), self.tr('Add Test Layers'), self.iface.mainWindow()) self.action_add_layers.setStatusTip(self.tr('Add test layers')) self.action_add_layers.setWhatsThis(self.tr('Add test layers')) self.action_add_layers.triggered.connect(self.add_test_layers) self.add_action(self.action_add_layers) def _create_run_test_action(self): """Create action for running tests (developer mode, non final only).""" if self.hide_developer_buttons: return default_package = str(setting('testPackage', 'safe', expected_type=str)) msg = self.tr('Run tests in %s' % default_package) self.test_button = QToolButton() self.test_button.setMenu(QMenu()) self.test_button.setPopupMode(QToolButton.MenuButtonPopup) icon = resources_path('img', 'icons', 'run-tests.svg') self.action_run_tests = QAction(QIcon(icon), msg, self.iface.mainWindow()) self.action_run_tests.setStatusTip(msg) self.action_run_tests.setWhatsThis(msg) self.action_run_tests.triggered.connect(self.run_tests) self.test_button.menu().addAction(self.action_run_tests) self.test_button.setDefaultAction(self.action_run_tests) self.action_select_package = QAction(QIcon(icon), self.tr('Select package'), self.iface.mainWindow()) self.action_select_package.setStatusTip(self.tr('Select Test Package')) self.action_select_package.setWhatsThis(self.tr('Select Test Package')) self.action_select_package.triggered.connect(self.select_test_package) self.test_button.menu().addAction(self.action_select_package) self.toolbar.addWidget(self.test_button) self.add_action(self.action_run_tests, add_to_toolbar=False) self.add_action(self.action_select_package, add_to_toolbar=False) def _create_dock(self): """Create dockwidget and tabify it with the legend.""" # Import dock here as it needs to be imported AFTER i18n is set up from safe.gui.widgets.dock import Dock self.dock_widget = Dock(self.iface) self.dock_widget.setObjectName('InaSAFE-Dock') self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dock_widget) legend_tab = self.iface.mainWindow().findChild(QApplication, 'Legend') if legend_tab: self.iface.mainWindow().tabifyDockWidget(legend_tab, self.dock_widget) self.dock_widget.raise_() # noinspection PyPep8Naming def initGui(self): """Gui initialisation procedure (for QGIS plugin api). .. note:: Don't change the name of this method from initGui! This method is called by QGIS and should be used to set up any graphical user interface elements that should appear in QGIS by default (i.e. before the user performs any explicit action with the plugin). """ self.toolbar = self.iface.addToolBar('InaSAFE') self.toolbar.setObjectName('InaSAFEToolBar') self.dock_widget = None # Now create the actual dock self._create_dock() # And all the menu actions # Configuration Group self._create_dock_toggle_action() self._create_options_dialog_action() self._create_minimum_needs_options_action() self._create_analysis_extent_action() self._create_rubber_bands_action() self._add_spacer_to_menu() self._create_keywords_wizard_action() self._create_analysis_wizard_action() self._add_spacer_to_menu() self._create_field_mapping_action() self._create_multi_exposure_action() self._create_metadata_converter_action() # TODO: temporarily disabled this until we have a fix # issue: https://github.com/inasafe/inasafe/issues/5109 # self._create_osm_downloader_action() self._create_add_osm_layer_action() self._create_add_petabencana_layer_action() self._create_geonode_uploader_action() self._create_shakemap_converter_action() self._create_minimum_needs_action() self._create_multi_buffer_action() self._create_test_layers_action() self._create_run_test_action() self._add_spacer_to_menu() self._create_batch_runner_action() self._create_save_scenario_action() self._add_spacer_to_menu() self._create_show_definitions_action() # Hook up a slot for when the dock is hidden using its close button # or view-panels # self.dock_widget.visibilityChanged.connect(self.toggle_inasafe_action) # Also deal with the fact that on start of QGIS dock may already be # hidden. self.action_dock.setChecked(self.dock_widget.isVisible()) self.iface.initializationCompleted.connect( partial(self.show_welcome_message)) def _add_spacer_to_menu(self): """Create a spacer to the menu to separate action groups.""" separator = QAction(self.iface.mainWindow()) separator.setSeparator(True) self.iface.addPluginToMenu(self.tr('InaSAFE'), separator) @staticmethod def clear_modules(): """Unload inasafe functions and try to return QGIS to before InaSAFE. .. todo:: I think this function can be removed. TS. """ # next lets force remove any inasafe related modules modules = [] for module in sys.modules: if 'inasafe' in module: # Check if it is really one of our modules i.e. exists in the # plugin directory tokens = module.split('.') path = '' for myToken in tokens: path += os.path.sep + myToken parent = os.path.abspath( os.path.join(__file__, os.path.pardir, os.path.pardir)) full_path = os.path.join(parent, path + '.py') if os.path.exists(os.path.abspath(full_path)): LOGGER.debug('Removing: %s' % module) modules.append(module) for module in modules: del (sys.modules[module]) for module in sys.modules: if 'inasafe' in module: print(module) # Lets also clean up all the path additions that were made package_path = os.path.abspath( os.path.join(os.path.dirname(__file__), os.path.pardir)) LOGGER.debug('Path to remove: %s' % package_path) # We use a list comprehension to ensure duplicate entries are removed LOGGER.debug(sys.path) sys.path = [y for y in sys.path if package_path not in y] LOGGER.debug(sys.path) def unload(self): """GUI breakdown procedure (for QGIS plugin api). .. note:: Don't change the name of this method from unload! This method is called by QGIS and should be used to *remove* any graphical user interface elements that should appear in QGIS. """ # Remove the plugin menu item and icon if self.wizard: self.wizard.deleteLater() for myAction in self.actions: self.iface.removePluginMenu(self.tr('InaSAFE'), myAction) self.iface.removeToolBarIcon(myAction) self.iface.removeCustomActionForLayerType(myAction) self.iface.mainWindow().removeDockWidget(self.dock_widget) self.iface.mainWindow().removeToolBar(self.toolbar) self.dock_widget.setVisible(False) self.dock_widget.destroy() self.iface.currentLayerChanged.disconnect(self.layer_changed) # Unload QGIS expressions loaded by the plugin. for qgis_expression in list(qgis_expressions().keys()): QgsExpression.unregisterFunction(qgis_expression) def toggle_inasafe_action(self, checked): """Check or un-check the toggle inaSAFE toolbar button. This slot is called when the user hides the inaSAFE panel using its close button or using view->panels. :param checked: True if the dock should be shown, otherwise False. :type checked: bool """ self.action_dock.setChecked(checked) # Run method that performs all the real work def toggle_dock_visibility(self): """Show or hide the dock widget.""" if self.dock_widget.isVisible(): self.dock_widget.setVisible(False) else: self.dock_widget.setVisible(True) self.dock_widget.raise_() def add_test_layers(self): """Add standard test layers.""" from safe.test.utilities import load_standard_layers load_standard_layers() rect = QgsRectangle(106.806, -6.195, 106.837, -6.167) self.iface.mapCanvas().setExtent(rect) def select_test_package(self): """Select the test package.""" default_package = 'safe' user_package = str( setting('testPackage', default_package, expected_type=str)) test_package, _ = QInputDialog.getText( self.iface.mainWindow(), self.tr('Select the python test package'), self.tr('Select the python test package'), QLineEdit.Normal, user_package) if test_package == '': test_package = default_package set_setting('testPackage', test_package) msg = self.tr('Run tests in %s' % test_package) self.action_run_tests.setWhatsThis(msg) self.action_run_tests.setText(msg) def run_tests(self): """Run unit tests in the python console.""" from qgis.PyQt.QtWidgets import QDockWidget main_window = self.iface.mainWindow() action = main_window.findChild(QAction, 'mActionShowPythonDialog') action.trigger() package = str(setting('testPackage', 'safe', expected_type=str)) for child in main_window.findChildren(QDockWidget, 'PythonConsole'): if child.objectName() == 'PythonConsole': child.show() for widget in child.children(): if 'PythonConsoleWidget' in str(widget.__class__): # print "Console widget found" shell = widget.shell shell.runCommand( 'from inasafe.test_suite import test_package') shell.runCommand('test_package(\'%s\')' % package) break def show_extent_selector(self): """Show the extent selector widget for defining analysis extents.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.extent_selector_dialog import ExtentSelectorDialog widget = ExtentSelectorDialog( self.iface, self.iface.mainWindow(), extent=self.dock_widget.extent.user_extent, crs=self.dock_widget.extent.crs) widget.clear_extent.connect( self.dock_widget.extent.clear_user_analysis_extent) widget.extent_defined.connect( self.dock_widget.define_user_analysis_extent) # This ensures that run button state is updated on dialog close widget.extent_selector_closed.connect( self.dock_widget.validate_impact_function) # Needs to be non modal to support hide -> interact with map -> show widget.show() # non modal def show_minimum_needs(self): """Show the minimum needs dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.minimum_needs.needs_calculator_dialog import ( NeedsCalculatorDialog) dialog = NeedsCalculatorDialog(self.iface.mainWindow()) dialog.exec_() def show_minimum_needs_configuration(self): """Show the minimum needs dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.minimum_needs.needs_manager_dialog import ( NeedsManagerDialog) dialog = NeedsManagerDialog(parent=self.iface.mainWindow(), dock=self.dock_widget) dialog.exec_() # modal def show_options(self): """Show the options dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.options_dialog import OptionsDialog dialog = OptionsDialog(iface=self.iface, parent=self.iface.mainWindow()) dialog.show_option_dialog() if dialog.exec_(): # modal self.dock_widget.read_settings() from safe.gui.widgets.message import getting_started_message send_static_message(self.dock_widget, getting_started_message()) # Issue #4734, make sure to update the combobox after update the # InaSAFE option self.dock_widget.get_layers() def show_welcome_message(self): """Show the welcome message.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.options_dialog import OptionsDialog # Do not show by default show_message = False previous_version = StrictVersion(setting('previous_version')) current_version = StrictVersion(inasafe_version) # Set previous_version to the current inasafe_version set_setting('previous_version', inasafe_version) if setting('always_show_welcome_message', expected_type=bool): # Show if it the setting said so show_message = True elif previous_version < current_version: # Always show if the user installed new version show_message = True # Allow to disable welcome message when running automated tests if os.environ.get('INASAFE_DISABLE_WELCOME_MESSAGE', False): show_message = False if show_message: dialog = OptionsDialog(iface=self.iface, parent=self.iface.mainWindow()) dialog.show_welcome_dialog() if dialog.exec_(): # modal self.dock_widget.read_settings() def show_keywords_wizard(self): """Show the keywords creation wizard.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.wizard.wizard_dialog import WizardDialog if self.iface.activeLayer() is None: return # Don't break an existing wizard session if accidentally clicked if self.wizard and self.wizard.isVisible(): return # Prevent spawning multiple copies since the IFCW is non modal if not self.wizard: self.wizard = WizardDialog(self.iface.mainWindow(), self.iface, self.dock_widget) self.wizard.set_keywords_creation_mode() self.wizard.exec_() # modal def show_function_centric_wizard(self): """Show the function centric wizard.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.wizard.wizard_dialog import WizardDialog # Don't break an existing wizard session if accidentally clicked if self.wizard and self.wizard.isVisible(): return # Prevent spawning multiple copies since it is non modal if not self.wizard: self.wizard = WizardDialog(self.iface.mainWindow(), self.iface, self.dock_widget) self.wizard.set_function_centric_mode() # non-modal in order to hide for selecting user extent self.wizard.show() def show_shakemap_importer(self): """Show the converter dialog.""" # import here only so that it is AFTER i18n set up from safe.gui.tools.shake_grid.shakemap_converter_dialog import ( ShakemapConverterDialog) dialog = ShakemapConverterDialog(self.iface.mainWindow(), self.iface, self.dock_widget) dialog.exec_() # modal def show_multi_buffer(self): """Show the multi buffer tool.""" from safe.gui.tools.multi_buffer_dialog import (MultiBufferDialog) dialog = MultiBufferDialog(self.iface.mainWindow(), self.iface, self.dock_widget) dialog.exec_() # modal def show_osm_downloader(self): """Show the OSM buildings downloader dialog.""" from safe.gui.tools.osm_downloader_dialog import OsmDownloaderDialog dialog = OsmDownloaderDialog(self.iface.mainWindow(), self.iface) # otherwise dialog is never deleted dialog.setAttribute(Qt.WA_DeleteOnClose, True) dialog.show() # non modal def show_geonode_uploader(self): """Show the Geonode uploader dialog.""" from safe.gui.tools.geonode_uploader import GeonodeUploaderDialog dialog = GeonodeUploaderDialog(self.iface.mainWindow()) dialog.show() # non modal def add_osm_layer(self): """Add OSM tile layer to the map. This uses a gdal wrapper around the OSM tile service - see the WorldOSM.gdal file for how it is constructed. """ path = resources_path('osm', 'WorldOSM.gdal') layer = QgsRasterLayer(path, self.tr('OpenStreetMap')) project = QgsProject.instance() # Try to add it as the last layer in the list # False flag prevents layer being added to legend project.addMapLayer(layer, False) root = QgsProject.instance().layerTreeRoot() index = len(root.findLayers()) + 1 # LOGGER.info('Inserting layer %s at position %s' % ( # layer.source(), index)) root.insertLayer(index, layer) project.addMapLayer(layer) def show_definitions(self): """Show InaSAFE Definitions (a report showing all key metadata).""" from safe.utilities.help import show_help from safe.gui.tools.help import definitions_help show_help(definitions_help.definitions_help()) def show_field_mapping(self): """Show InaSAFE Field Mapping.""" from safe.gui.tools.field_mapping_dialog import FieldMappingDialog dialog = FieldMappingDialog( parent=self.iface.mainWindow(), iface=self.iface, ) if dialog.exec_(): # modal LOGGER.debug('Show field mapping accepted') self.dock_widget.layer_changed(self.iface.activeLayer()) else: LOGGER.debug('Show field mapping not accepted') def show_metadata_converter(self): """Show InaSAFE Metadata Converter.""" from safe.gui.tools.metadata_converter_dialog import ( MetadataConverterDialog) dialog = MetadataConverterDialog( parent=self.iface.mainWindow(), iface=self.iface, ) dialog.exec_() def show_multi_exposure(self): """Show InaSAFE Multi Exposure.""" from safe.gui.tools.multi_exposure_dialog import MultiExposureDialog dialog = MultiExposureDialog(self.iface.mainWindow(), self.iface) dialog.exec_() # modal def add_petabencana_layer(self): """Add petabencana layer to the map. This uses the PetaBencana API to fetch the latest floods in JK. See https://data.petabencana.id/floods """ from safe.gui.tools.peta_bencana_dialog import PetaBencanaDialog dialog = PetaBencanaDialog(self.iface.mainWindow(), self.iface) dialog.show() # non modal def show_batch_runner(self): """Show the batch runner dialog.""" from safe.gui.tools.batch.batch_dialog import BatchDialog dialog = BatchDialog(parent=self.iface.mainWindow(), iface=self.iface, dock=self.dock_widget) dialog.exec_() # modal def save_scenario(self): """Save current scenario to text file.""" from safe.gui.tools.save_scenario import SaveScenarioDialog dialog = SaveScenarioDialog(iface=self.iface, dock=self.dock_widget) dialog.save_scenario() def layer_changed(self, layer): """Enable or disable keywords editor icon when active layer changes. :param layer: The layer that is now active. :type layer: QgsMapLayer """ if not layer: enable_keyword_wizard = False elif not hasattr(layer, 'providerType'): enable_keyword_wizard = False elif layer.providerType() == 'wms': enable_keyword_wizard = False else: enable_keyword_wizard = True try: if layer: if is_raster_layer(layer): enable_field_mapping_tool = False else: keywords = KeywordIO().read_keywords(layer) keywords_version = keywords.get('keyword_version') if not keywords_version: supported = False else: supported = ( is_keyword_version_supported(keywords_version)) if not supported: enable_field_mapping_tool = False else: layer_purpose = keywords.get('layer_purpose') if not layer_purpose: enable_field_mapping_tool = False else: if layer_purpose == layer_purpose_exposure['key']: layer_subcategory = keywords.get('exposure') elif layer_purpose == layer_purpose_hazard['key']: layer_subcategory = keywords.get('hazard') else: layer_subcategory = None field_groups = get_field_groups( layer_purpose, layer_subcategory) if len(field_groups) == 0: # No field group, disable field mapping tool. enable_field_mapping_tool = False else: enable_field_mapping_tool = True else: enable_field_mapping_tool = False except (KeywordNotFoundError, NoKeywordsFoundError, MetadataReadError): # No keywords, disable field mapping tool. enable_field_mapping_tool = False self.action_keywords_wizard.setEnabled(enable_keyword_wizard) self.action_field_mapping.setEnabled(enable_field_mapping_tool) def shortcut_f7(self): """Executed when user press F7 - will show the shakemap importer.""" self.show_shakemap_importer()
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): """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.iface.addPluginToVectorMenu( self.menu, action) self.actions.append(action) return action
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, "New 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_clear_cache = QAction("Clear cache", parent) self.action_upload = QAction("Upload to New XYZ Geospace", parent) self.action_basemap = QAction("Add HERE Map Tile", parent) self.action_magic_sync = QAction("Magic Sync (EXPERIMENTAL)", parent) self.action_manage = QAction("Manage XYZ Geospace (EXPERIMENTAL)", parent) self.action_edit = QAction("Edit/Delete XYZ Geospace (EXPERIMENTAL)", parent) if self.iface.activeLayer() is None: # self.action_upload.setEnabled(False) self.action_edit.setEnabled(False) self.action_magic_sync.setEnabled(False) # self.action_magic_sync.setVisible(False) # disable magic sync ######## CONNECT action, button self.action_connect.triggered.connect(self.open_connection_dialog) self.action_manage.triggered.connect(self.open_manage_dialog) self.action_edit.triggered.connect(self.open_edit_dialog) self.action_upload.triggered.connect(self.open_upload_dialog) self.action_magic_sync.triggered.connect(self.open_magic_sync_dialog) self.action_clear_cache.triggered.connect(self.open_clear_cache_dialog) self.action_basemap.triggered.connect(self.open_basemap_dialog) ######## Add the toolbar + button self.toolbar = self.iface.addToolBar(PLUGIN_NAME) self.toolbar.setObjectName("XYZ Hub Connector") tool_btn = QToolButton(self.toolbar) self.actions = [ self.action_connect, self.action_upload, self.action_basemap, self.action_clear_cache ] # , self.action_magic_sync, self.action_manage, self.action_edit for a in self.actions: tool_btn.addAction(a) self.iface.addPluginToWebMenu(self.web_menu, a) tool_btn.setDefaultAction(self.action_connect) tool_btn.setPopupMode(tool_btn.MenuButtonPopup) self.xyz_widget_action = self.toolbar.addWidget(tool_btn) self.action_help = None self.action_reload = QAction(icon_bbox, "Reload BBox", parent) self.action_reload.triggered.connect(self.layer_reload_bbox) self.action_reload.setVisible(False) # disable self.toolbar.addAction(self.action_reload) 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): # util.init_module() # parent = self.iface.mainWindow() parent = QgsProject.instance() ######## Init xyz modules self.map_basemap_meta = basemap.load_default_xml() self.auth_manager = AuthManager(config.PLUGIN_DIR + "/auth.ini") self.token_model = GroupTokenModel(parent) # self.layer = LayerManager(parent, self.iface) self.network = NetManager(parent) self.con_man = ControllerManager() self.layer_man = LayerManager() ######## data flow self.conn_info = SpaceConnectionInfo() ######## token print(config.PLUGIN_DIR) self.token_model.load_ini(config.PLUGIN_DIR + "/token.ini") ######## CALLBACK # self.iface.mapCanvas().extentsChanged.connect( self.debug_reload) # self.con_man.connect_ux( self.iface) # canvas ux # self.con_man.signal.canvas_span.connect( self.loader_reload_bbox) 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.layer_man.remove) QgsProject.instance().layersWillBeRemoved["QStringList"].connect( self.con_man.remove) # self.iface.currentLayerChanged.connect( self.cb_layer_selected) # UNCOMMENT if DEBUG: QgsApplication.messageLog().messageReceived.connect(print_qgis) def unload_modules(self): # self.con_man.disconnect_ux( self.iface) QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.layer_man.remove) QgsProject.instance().layersWillBeRemoved["QStringList"].disconnect( self.con_man.remove) # utils.disconnect_silent(self.iface.currentLayerChanged) # self.con_man.unload() # del self.con_man # self.iface.mapCanvas().extentsChanged.disconnect( self.debug_reload) close_print_qgis() 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: self.iface.removePluginWebMenu(self.web_menu, a) ############### # Callback ############### def cb_layer_selected(self, qlayer): flag_xyz = True if qlayer is not None and self.layer.is_xyz_supported_layer( qlayer) else False # disable magic sync # self.action_magic_sync.setEnabled(flag_xyz) flag_layer = True self.action_upload.setEnabled(flag_layer) self.action_edit.setEnabled(flag_layer) ############### # Callback of action (main function) ############### def cb_success_msg(self, msg, info=""): self.iface.messageBar().pushMessage(msg, info, Qgis.Success, 1) def make_cb_success(self, msg, info=""): def _cb_success_msg(): txt = info self.cb_success_msg(msg, txt) 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] if isinstance(e0, net_handler.NetworkError): ok = self.show_net_err_dialog(e0) if ok: return elif isinstance(e0, loader.EmptyXYZSpaceError): ret = exec_warning_dialog( "Warning", "Requested query returns no features") self.show_err_msgbar(err) def show_net_err_dialog(self, err): assert isinstance(err, net_handler.NetworkError) reply_tag, status, reason, body = err.args[:4] if reply_tag in ["count"]: # too many error return 0 msg = ("%s: %s\n" % (status, reason) + "There was a problem connecting to the server") if status == 403: msg += "\n\n" + "Please make sure that the token has WRITE permission" ret = exec_warning_dialog("Network Error", msg, body) return 1 def show_err_msgbar(self, err): self.iface.messageBar().pushMessage(TAG_PLUGIN, repr(err), Qgis.Warning, 5) msg = format_traceback(err) QgsMessageLog.logMessage(msg, 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) ############### def load_bbox(self, con, args): bbox = bbox_utils.extend_to_bbox( bbox_utils.get_bounding_box(self.iface)) a, kw = parse_qt_args(args) kw["bbox"] = bbox kw["limit"] = 1000 con.start(*a, **kw) def layer_reload_bbox(self): con_bbox_reload = ReloadLayerController_bbox(self.network) self.con_man.add(con_bbox_reload) # con_bbox_reload.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection) con_bbox_reload.signal.finished.connect( self.make_cb_success("Bounding box loading finish")) con_bbox_reload.signal.error.connect(self.cb_handle_error_msg) # TODO: set/get params from vlayer layer_id = self.iface.activeLayer().id() layer = self.layer_man.get(layer_id) self.load_bbox(con_bbox_reload, make_qt_args(layer)) # UNUSED def debug_reload(self): print("debug_reload") def refresh_canvas(self): self.iface.mapCanvas().refresh() # assert False # debug unload module def previous_canvas_extent(self): self.iface.mapCanvas().zoomToPreviousExtent() def open_clear_cache_dialog(self): parent = self.iface.mainWindow() dialog = ConfirmDialog( parent, "Delete cache will make loaded layer unusable !!") ret = dialog.exec_() if ret != dialog.Ok: return utils.clear_cache() def open_connection_dialog(self): parent = self.iface.mainWindow() dialog = ConnectManageSpaceDialog(parent) dialog.config(self.token_model, self.conn_info) ############ edit btn con = EditSpaceController(self.network) self.con_man.add(con) con.signal.finished.connect(dialog.btn_use.clicked.emit) con.signal.error.connect(self.cb_handle_error_msg) dialog.signal_edit_space.connect(con.start_args) ############ delete btn con = DeleteSpaceController(self.network) self.con_man.add(con) con.signal.results.connect(dialog.btn_use.clicked.emit) con.signal.error.connect(self.cb_handle_error_msg) dialog.signal_del_space.connect(con.start_args) ############ Use Token btn con = LoadSpaceController(self.network) self.con_man.add(con) 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) dialog.signal_use_token.connect(con.start_args) ############ get statisitics con = StatSpaceController(self.network) self.con_man.add(con) con.signal.results.connect(make_fun_args( dialog.cb_display_space_count)) con.signal.error.connect(self.cb_handle_error_msg) dialog.signal_space_count.connect(con.start_args) ############ TODO: bbox btn ############ connect btn con_load = loader.ReloadLayerController(self.network, n_parallel=2) self.con_man.add(con_load) # con_load.signal.finished.connect( self.refresh_canvas, Qt.QueuedConnection) con_load.signal.finished.connect( self.make_cb_success("Loading finish")) con_load.signal.error.connect(self.cb_handle_error_msg) dialog.signal_space_connect.connect(con_load.start_args) # con.signal.results.connect( self.layer_man.add_args) # IMPORTANT dialog.exec_() # self.startTime = time.time() def open_manage_dialog(self): pass def open_edit_dialog(self): pass def open_upload_dialog(self): vlayer = self.iface.activeLayer() parent = self.iface.mainWindow() dialog = UploadNewSpaceDialog(parent) dialog.config(self.token_model, self.network, vlayer) ############ Use Token btn con = LoadSpaceController(self.network) self.con_man.add(con) con.signal.results.connect(make_fun_args( dialog.cb_set_valid_token)) # finished signal !? con.signal.error.connect(self.cb_handle_error_msg) con.signal.finished.connect(dialog.cb_enable_token_ui) dialog.signal_use_token.connect(con.start_args) con_upload = UploadLayerController(self.network, n_parallel=2) self.con_man.add(con_upload) con_upload.signal.finished.connect( self.make_cb_success("Uploading finish")) con_upload.signal.error.connect(self.cb_handle_error_msg) con = InitUploadLayerController(self.network) self.con_man.add(con) dialog.signal_upload_new_space.connect(con.start_args) con.signal.results.connect(con_upload.start_args) con.signal.error.connect(self.cb_handle_error_msg) dialog.exec_() def open_magic_sync_dialog(self): pass def open_basemap_dialog(self): parent = self.iface.mainWindow() auth = self.auth_manager.get_auth() dialog = BaseMapDialog(parent) dialog.config(self.map_basemap_meta, auth) dialog.signal_add_basemap.connect(self.add_basemap_layer) dialog.exec_() 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)
class GdalTools: def __init__(self, iface): if not valid: return # Save reference to the QGIS interface self.iface = iface try: self.QgisVersion = unicode(Qgis.QGIS_VERSION_INT) except: self.QgisVersion = unicode(Qgis.qgisVersion)[0] if Qgis.QGIS_VERSION[0:3] < "1.5": # For i18n support userPluginPath = qgis.utils.home_plugin_path + "/GdalTools" systemPluginPath = qgis.utils.sys_plugin_path + "/GdalTools" overrideLocale = QSettings().value("locale/overrideFlag", False, type=bool) if not overrideLocale: localeFullName = QLocale.system().name() else: localeFullName = QSettings().value("locale/userLocale", "", type=str) if QFileInfo(userPluginPath).exists(): translationPath = userPluginPath + "/i18n/GdalTools_" + localeFullName + ".qm" else: translationPath = systemPluginPath + "/i18n/GdalTools_" + localeFullName + ".qm" self.localePath = translationPath if QFileInfo(self.localePath).exists(): self.translator = QTranslator() self.translator.load(self.localePath) QCoreApplication.installTranslator(self.translator) # The list of actions added to menus, so we can remove them when unloading the plugin self._menuActions = [] def initGui(self): if not valid: return if int(self.QgisVersion) < 1: QMessageBox.warning( self.iface.getMainWindow(), "Gdal Tools", QCoreApplication.translate("GdalTools", "QGIS version detected: ") + unicode(self.QgisVersion) + ".xx\n" + QCoreApplication.translate("GdalTools", "This version of Gdal Tools requires at least QGIS version 1.0.0\nPlugin will not be enabled.")) return None from .tools.GdalTools_utils import GdalConfig, LayerRegistry self.GdalVersionNum = GdalConfig.versionNum() LayerRegistry.setIface(self.iface) # find the Raster menu rasterMenu = None menu_bar = self.iface.mainWindow().menuBar() actions = menu_bar.actions() rasterText = QCoreApplication.translate("QgisApp", "&Raster") for a in actions: if a.menu() is not None and a.menu().title() == rasterText: rasterMenu = a.menu() break if rasterMenu is None: # no Raster menu, create and insert it before the Help menu self.menu = QMenu(rasterText, self.iface.mainWindow()) lastAction = actions[len(actions) - 1] menu_bar.insertMenu(lastAction, self.menu) else: self.menu = rasterMenu self._menuActions.append(self.menu.addSeparator()) # projections menu (Warp (Reproject), Assign projection) self.projectionsMenu = QMenu(QCoreApplication.translate("GdalTools", "Projections"), self.iface.mainWindow()) self.projectionsMenu.setObjectName("projectionsMenu") self.warp = QAction(QIcon(":/icons/warp.png"), QCoreApplication.translate("GdalTools", "Warp (Reproject)..."), self.iface.mainWindow()) self.warp.setObjectName("warp") self.warp.setStatusTip(QCoreApplication.translate("GdalTools", "Warp an image into a new coordinate system")) self.warp.triggered.connect(self.doWarp) self.projection = QAction(QIcon(":icons/projection-add.png"), QCoreApplication.translate("GdalTools", "Assign Projection..."), self.iface.mainWindow()) self.projection.setObjectName("projection") self.projection.setStatusTip(QCoreApplication.translate("GdalTools", "Add projection info to the raster")) self.projection.triggered.connect(self.doProjection) self.extractProj = QAction(QIcon(":icons/projection-export.png"), QCoreApplication.translate("GdalTools", "Extract Projection..."), self.iface.mainWindow()) self.extractProj.setObjectName("extractProj") self.extractProj.setStatusTip(QCoreApplication.translate("GdalTools", "Extract projection information from raster(s)")) self.extractProj.triggered.connect(self.doExtractProj) self.projectionsMenu.addActions([self.warp, self.projection, self.extractProj]) # conversion menu (Rasterize (Vector to raster), Polygonize (Raster to vector), Translate, RGB to PCT, PCT to RGB) self.conversionMenu = QMenu(QCoreApplication.translate("GdalTools", "Conversion"), self.iface.mainWindow()) self.conversionMenu.setObjectName("conversionMenu") if self.GdalVersionNum >= 1300: self.rasterize = QAction(QIcon(":/icons/rasterize.png"), QCoreApplication.translate("GdalTools", "Rasterize (Vector to Raster)..."), self.iface.mainWindow()) self.rasterize.setObjectName("rasterize") self.rasterize.setStatusTip(QCoreApplication.translate("GdalTools", "Burns vector geometries into a raster")) self.rasterize.triggered.connect(self.doRasterize) self.conversionMenu.addAction(self.rasterize) if self.GdalVersionNum >= 1600: self.polygonize = QAction(QIcon(":/icons/polygonize.png"), QCoreApplication.translate("GdalTools", "Polygonize (Raster to Vector)..."), self.iface.mainWindow()) self.polygonize.setObjectName("polygonize") self.polygonize.setStatusTip(QCoreApplication.translate("GdalTools", "Produces a polygon feature layer from a raster")) self.polygonize.triggered.connect(self.doPolygonize) self.conversionMenu.addAction(self.polygonize) self.translate = QAction(QIcon(":/icons/translate.png"), QCoreApplication.translate("GdalTools", "Translate (Convert Format)..."), self.iface.mainWindow()) self.translate.setObjectName("translate") self.translate.setStatusTip(QCoreApplication.translate("GdalTools", "Converts raster data between different formats")) self.translate.triggered.connect(self.doTranslate) self.paletted = QAction(QIcon(":icons/24-to-8-bits.png"), QCoreApplication.translate("GdalTools", "RGB to PCT..."), self.iface.mainWindow()) self.paletted.setObjectName("paletted") self.paletted.setStatusTip(QCoreApplication.translate("GdalTools", "Convert a 24bit RGB image to 8bit paletted")) self.paletted.triggered.connect(self.doPaletted) self.rgb = QAction(QIcon(":icons/8-to-24-bits.png"), QCoreApplication.translate("GdalTools", "PCT to RGB..."), self.iface.mainWindow()) self.rgb.setObjectName("rgb") self.rgb.setStatusTip(QCoreApplication.translate("GdalTools", "Convert an 8bit paletted image to 24bit RGB")) self.rgb.triggered.connect(self.doRGB) self.conversionMenu.addActions([self.translate, self.paletted, self.rgb]) # extraction menu (Clipper, Contour) self.extractionMenu = QMenu(QCoreApplication.translate("GdalTools", "Extraction"), self.iface.mainWindow()) self.extractionMenu.setObjectName("extractionMenu") if self.GdalVersionNum >= 1600: self.contour = QAction(QIcon(":/icons/contour.png"), QCoreApplication.translate("GdalTools", "Contour..."), self.iface.mainWindow()) self.contour.setObjectName("contour") self.contour.setStatusTip(QCoreApplication.translate("GdalTools", "Builds vector contour lines from a DEM")) self.contour.triggered.connect(self.doContour) self.extractionMenu.addAction(self.contour) self.clipper = QAction(QIcon(":icons/raster-clip.png"), QCoreApplication.translate("GdalTools", "Clipper..."), self.iface.mainWindow()) self.clipper.setObjectName("clipper") #self.clipper.setStatusTip( QCoreApplication.translate( "GdalTools", "Converts raster data between different formats") ) self.clipper.triggered.connect(self.doClipper) self.extractionMenu.addActions([self.clipper]) # analysis menu (DEM (Terrain model), Grid (Interpolation), Near black, Proximity (Raster distance), Sieve) self.analysisMenu = QMenu(QCoreApplication.translate("GdalTools", "Analysis"), self.iface.mainWindow()) self.analysisMenu.setObjectName("analysisMenu") if self.GdalVersionNum >= 1600: self.sieve = QAction(QIcon(":/icons/sieve.png"), QCoreApplication.translate("GdalTools", "Sieve..."), self.iface.mainWindow()) self.sieve.setObjectName("sieve") self.sieve.setStatusTip(QCoreApplication.translate("GdalTools", "Removes small raster polygons")) self.sieve.triggered.connect(self.doSieve) self.analysisMenu.addAction(self.sieve) if self.GdalVersionNum >= 1500: self.nearBlack = QAction(QIcon(":/icons/nearblack.png"), QCoreApplication.translate("GdalTools", "Near Black..."), self.iface.mainWindow()) self.nearBlack.setObjectName("nearBlack") self.nearBlack.setStatusTip(QCoreApplication.translate("GdalTools", "Convert nearly black/white borders to exact value")) self.nearBlack.triggered.connect(self.doNearBlack) self.analysisMenu.addAction(self.nearBlack) if self.GdalVersionNum >= 1700: self.fillNodata = QAction(QIcon(":/icons/fillnodata.png"), QCoreApplication.translate("GdalTools", "Fill nodata..."), self.iface.mainWindow()) self.fillNodata.setObjectName("fillNodata") self.fillNodata.setStatusTip(QCoreApplication.translate("GdalTools", "Fill raster regions by interpolation from edges")) self.fillNodata.triggered.connect(self.doFillNodata) self.analysisMenu.addAction(self.fillNodata) if self.GdalVersionNum >= 1600: self.proximity = QAction(QIcon(":/icons/proximity.png"), QCoreApplication.translate("GdalTools", "Proximity (Raster Distance)..."), self.iface.mainWindow()) self.proximity.setObjectName("proximity") self.proximity.setStatusTip(QCoreApplication.translate("GdalTools", "Produces a raster proximity map")) self.proximity.triggered.connect(self.doProximity) self.analysisMenu.addAction(self.proximity) if self.GdalVersionNum >= 1500: self.grid = QAction(QIcon(":/icons/grid.png"), QCoreApplication.translate("GdalTools", "Grid (Interpolation)..."), self.iface.mainWindow()) self.grid.setObjectName("grid") self.grid.setStatusTip(QCoreApplication.translate("GdalTools", "Create raster from the scattered data")) self.grid.triggered.connect(self.doGrid) self.analysisMenu.addAction(self.grid) if self.GdalVersionNum >= 1700: self.dem = QAction(QIcon(":icons/dem.png"), QCoreApplication.translate("GdalTools", "DEM (Terrain Models)..."), self.iface.mainWindow()) self.dem.setObjectName("dem") self.dem.setStatusTip(QCoreApplication.translate("GdalTools", "Tool to analyze and visualize DEMs")) self.dem.triggered.connect(self.doDEM) self.analysisMenu.addAction(self.dem) #self.analysisMenu.addActions( [ ] ) # miscellaneous menu (Build overviews (Pyramids), Tile index, Information, Merge, Build Virtual Raster (Catalog)) self.miscellaneousMenu = QMenu(QCoreApplication.translate("GdalTools", "Miscellaneous"), self.iface.mainWindow()) self.miscellaneousMenu.setObjectName("miscellaneousMenu") if self.GdalVersionNum >= 1600: self.buildVRT = QAction(QIcon(":/icons/vrt.png"), QCoreApplication.translate("GdalTools", "Build Virtual Raster (Catalog)..."), self.iface.mainWindow()) self.buildVRT.setObjectName("buildVRT") self.buildVRT.setStatusTip(QCoreApplication.translate("GdalTools", "Builds a VRT from a list of datasets")) self.buildVRT.triggered.connect(self.doBuildVRT) self.miscellaneousMenu.addAction(self.buildVRT) self.merge = QAction(QIcon(":/icons/merge.png"), QCoreApplication.translate("GdalTools", "Merge..."), self.iface.mainWindow()) self.merge.setObjectName("merge") self.merge.setStatusTip(QCoreApplication.translate("GdalTools", "Build a quick mosaic from a set of images")) self.merge.triggered.connect(self.doMerge) self.info = QAction(QIcon(":/icons/raster-info.png"), QCoreApplication.translate("GdalTools", "Information..."), self.iface.mainWindow()) self.info.setObjectName("info") self.info.setStatusTip(QCoreApplication.translate("GdalTools", "Lists information about raster dataset")) self.info.triggered.connect(self.doInfo) self.overview = QAction(QIcon(":icons/raster-overview.png"), QCoreApplication.translate("GdalTools", "Build Overviews (Pyramids)..."), self.iface.mainWindow()) self.overview.setObjectName("overview") self.overview.setStatusTip(QCoreApplication.translate("GdalTools", "Builds or rebuilds overview images")) self.overview.triggered.connect(self.doOverview) self.tileindex = QAction(QIcon(":icons/tiles.png"), QCoreApplication.translate("GdalTools", "Tile Index..."), self.iface.mainWindow()) self.tileindex.setObjectName("tileindex") self.tileindex.setStatusTip(QCoreApplication.translate("GdalTools", "Build a shapefile as a raster tileindex")) self.tileindex.triggered.connect(self.doTileIndex) self.miscellaneousMenu.addActions([self.merge, self.info, self.overview, self.tileindex]) self._menuActions.append(self.menu.addMenu(self.projectionsMenu)) self._menuActions.append(self.menu.addMenu(self.conversionMenu)) self._menuActions.append(self.menu.addMenu(self.extractionMenu)) if not self.analysisMenu.isEmpty(): self._menuActions.append(self.menu.addMenu(self.analysisMenu)) self._menuActions.append(self.menu.addMenu(self.miscellaneousMenu)) self.settings = QAction(QCoreApplication.translate("GdalTools", "GdalTools Settings..."), self.iface.mainWindow()) self.settings.setObjectName("settings") self.settings.setStatusTip(QCoreApplication.translate("GdalTools", "Various settings for Gdal Tools")) self.settings.triggered.connect(self.doSettings) self.menu.addAction(self.settings) self._menuActions.append(self.settings) def unload(self): if not valid: return for a in self._menuActions: self.menu.removeAction(a) def doBuildVRT(self): from .tools.doBuildVRT import GdalToolsDialog as BuildVRT d = BuildVRT(self.iface) self.runToolDialog(d) def doContour(self): from .tools.doContour import GdalToolsDialog as Contour d = Contour(self.iface) self.runToolDialog(d) def doRasterize(self): from .tools.doRasterize import GdalToolsDialog as Rasterize d = Rasterize(self.iface) self.runToolDialog(d) def doPolygonize(self): from .tools.doPolygonize import GdalToolsDialog as Polygonize d = Polygonize(self.iface) self.runToolDialog(d) def doMerge(self): from .tools.doMerge import GdalToolsDialog as Merge d = Merge(self.iface) self.runToolDialog(d) def doSieve(self): from .tools.doSieve import GdalToolsDialog as Sieve d = Sieve(self.iface) self.runToolDialog(d) def doProximity(self): from .tools.doProximity import GdalToolsDialog as Proximity d = Proximity(self.iface) self.runToolDialog(d) def doNearBlack(self): from .tools.doNearBlack import GdalToolsDialog as NearBlack d = NearBlack(self.iface) self.runToolDialog(d) def doFillNodata(self): from .tools.doFillNodata import GdalToolsDialog as FillNodata d = FillNodata(self.iface) self.runToolDialog(d) def doWarp(self): from .tools.doWarp import GdalToolsDialog as Warp d = Warp(self.iface) self.runToolDialog(d) def doGrid(self): from .tools.doGrid import GdalToolsDialog as Grid d = Grid(self.iface) self.runToolDialog(d) def doTranslate(self): from .tools.doTranslate import GdalToolsDialog as Translate d = Translate(self.iface) self.runToolDialog(d) def doInfo(self): from .tools.doInfo import GdalToolsDialog as Info d = Info(self.iface) self.runToolDialog(d) def doProjection(self): from .tools.doProjection import GdalToolsDialog as Projection d = Projection(self.iface) self.runToolDialog(d) def doOverview(self): from .tools.doOverview import GdalToolsDialog as Overview d = Overview(self.iface) self.runToolDialog(d) def doClipper(self): from .tools.doClipper import GdalToolsDialog as Clipper d = Clipper(self.iface) self.runToolDialog(d) def doPaletted(self): from .tools.doRgbPct import GdalToolsDialog as RgbPct d = RgbPct(self.iface) self.runToolDialog(d) def doRGB(self): from .tools.doPctRgb import GdalToolsDialog as PctRgb d = PctRgb(self.iface) self.runToolDialog(d) def doTileIndex(self): from .tools.doTileIndex import GdalToolsDialog as TileIndex d = TileIndex(self.iface) self.runToolDialog(d) def doExtractProj(self): from .tools.doExtractProj import GdalToolsDialog as ExtractProj d = ExtractProj(self.iface) d.exec_() def doDEM(self): from .tools.doDEM import GdalToolsDialog as DEM d = DEM(self.iface) self.runToolDialog(d) def runToolDialog(self, dlg): dlg.show_() dlg.exec_() del dlg def doSettings(self): from .tools.doSettings import GdalToolsSettingsDialog as Settings d = Settings(self.iface) d.exec_()
class Cbers4aDownloader: """Plugin implementation """ def __init__(self, iface): """ Constructor Args: iface (qgis.gui.QgisInterface): a reference to the QGIS GUI interface """ self.iface = iface self.plugin_dir = os.path.dirname(__file__) self.dockwidget = None self.provider = None self.action = None self.name = 'CBERS4A Downloader' self.about = 'Search and download CBERS4A imagery' self.search = None self.collections = None self.result = None self.footprint = QgsRubberBand(iface.mapCanvas(), True) self.mux_grid = None self.wfi_grid = None self.downloading = False self.outputfolder = QgsProject.instance().absolutePath() or gettempdir( ) def initProcessing(self): self.provider = Provider() QgsApplication.processingRegistry().addProvider(self.provider) def initGui(self): """ This method is called by QGIS when the main GUI starts up or when the plugin is enabled in the Plugin Manager. Only want to register the menu items and toolbar buttons here, and connects action with run method. """ self.initProcessing() icon = QIcon(':/plugins/cbers4a/cbers4a.svg') self.action = QAction(icon, self.name, self.iface.mainWindow()) self.action.setWhatsThis(self.about) self.action.setStatusTip(self.about) self.action.setCheckable(True) self.action.triggered.connect(self.run) # for raster menu/toolbar # self.iface.addRasterToolBarIcon(self.action) # self.iface.addPluginToRasterMenu(self.name, self.action) # for plugin menu/toolbar self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu(self.name, self.action) # for custom toolbar # self.toolbar = self.iface.addToolBar('Plugin') # self.toolbar.setObjectName('Plugin') # self.toolbar.addAction(self.action) def unload(self): """ Will be executed when the plugin is disabled. Either in the Plugin Manager or when QGIS shuts down. It removes the previously defined QAction object from the menu and remove the plugin icon from the toolbar. """ # disconnect triggers if self.search is not None: self.iface.mapCanvas().extentsChanged.disconnect( self.update_extent) self.iface.mapCanvas().destinationCrsChanged.disconnect( self.update_extent) self.dockwidget.startdate.dateChanged.disconnect( self.update_startdate) self.dockwidget.enddate.dateChanged.disconnect(self.update_enddate) self.iface.projectRead.disconnect(self.update_outputfolder) self.iface.newProjectCreated.disconnect(self.update_outputfolder) QgsProject.instance().projectSaved.disconnect( self.update_outputfolder) self.dockwidget.limit.valueChanged.disconnect(self.update_limit) self.dockwidget.cloudcover.valueChanged.disconnect( self.update_cloudcover) self.dockwidget.collection.currentIndexChanged.disconnect( self.update_collection) self.dockwidget.searchButton.clicked.disconnect(self.do_search) self.dockwidget.resultsList.itemClicked.disconnect(self.preview) # self.dockwidget.credential.textChanged[str].disconnect(self.credential_changed) # self.dockwidget.credential.editingFinished.disconnect(self.credential_filled) self.dockwidget.tabs.currentChanged[int].disconnect( self.toggle_download_button) self.dockwidget.downloadButton.clicked.disconnect( self.start_download) # footprint pushbutton self.dockwidget.footprint.clicked.disconnect(self.toggle_footprint) # close search session self.search.close() # for raster menu/toolbar # self.iface.removePluginRasterMenu(self.name, self.action) # self.iface.removeRasterToolBarIcon(self.action) # for plugin menu/toolbar self.iface.removeToolBarIcon(self.action) self.iface.removePluginMenu(self.name, self.action) # remove canvas item (footprint) self.iface.mapCanvas().scene().removeItem(self.footprint) if self.dockwidget is not None: self.dockwidget.close() self.dockwidget.visibilityChanged.disconnect( self.visibility_changed) self.iface.removeDockWidget(self.dockwidget) del self.dockwidget # remove custom toolbar # if self.toolbar is not None: # del self.toolbar # remove processing provider QgsApplication.processingRegistry().removeProvider(self.provider) # clean up task try: del globals()['cbers4a_tasks'] except KeyError: pass def run(self): """ Executes the custom plugin functionality. This method is called by the previously defined QAction object (callback), which went into the toolbar icon and the menu entry. """ if self.dockwidget is None: self.dockwidget = DockCbers4aDownloader() self.iface.addDockWidget(Qt.RightDockWidgetArea, self.dockwidget) self.dockwidget.visibilityChanged.connect(self.visibility_changed) self.init() self.dockwidget.show() else: if self.dockwidget.isVisible(): self.dockwidget.footprint.setChecked(False) self.footprint.hide() self.dockwidget.hide() else: self.dockwidget.show() def visibility_changed(self, change): """ Change icon checked status with dockwidget visibility """ self.action.setChecked(change) def get_canvas_extent(self): """ Return a tuple with current extent and crs """ crs = self.iface.mapCanvas().mapSettings().destinationCrs() extent = self.iface.mapCanvas().extent() return extent, crs def update_extent(self): """ Update extent from mapcanvas """ current_extent, current_crs = self.get_canvas_extent() output_crs = QgsCoordinateReferenceSystem('EPSG:4326') # WGS84 transform = QgsCoordinateTransform(current_crs, output_crs, QgsProject.instance()) extent = transform.transformBoundingBox(current_extent) self.dockwidget.north.setText('{0:.6f}'.format(extent.yMaximum())) self.dockwidget.south.setText('{0:.6f}'.format(extent.yMinimum())) self.dockwidget.east.setText('{0:.6f}'.format(extent.xMaximum())) self.dockwidget.west.setText('{0:.6f}'.format(extent.xMinimum())) self.search.bbox([ extent.xMinimum(), extent.yMinimum(), extent.xMaximum(), extent.yMaximum() ]) # also update footprint self.update_footprint() def update_startdate(self, new_date): defaults = QgsSettings() self.dockwidget.enddate.setDate( new_date.addDays(int(defaults.value("cbers4a/timespan", 30)))) self.search.date( self.dockwidget.startdate.date().toString('yyyy-MM-dd'), self.dockwidget.enddate.date().toString('yyyy-MM-dd')) def update_enddate(self, end_date): if end_date <= self.dockwidget.startdate.date(): self.dockwidget.startdate.setDate(end_date.addDays(-1)) self.search.date( self.dockwidget.startdate.date().toString('yyyy-MM-dd'), self.dockwidget.enddate.date().toString('yyyy-MM-dd')) def update_outputfolder(self): """ Update default output folder on new/read project """ self.outputfolder = QgsProject.instance().absolutePath() or gettempdir( ) self.dockwidget.outputfolder.lineEdit().setPlaceholderText( self.outputfolder) def update_limit(self): """ Set max number of scenes in the search """ self.search.limit(self.dockwidget.limit.value()) def update_cloudcover(self): """ Set max cloud cover in the search """ self.search.cloud_cover('<=', self.dockwidget.cloudcover.value()) def update_collection(self): """ Set collection to search in and valid start and end dates for this collection """ collection_id = self.dockwidget.collection.currentText() inpe_collections = { description: id for id, description in self.collections } # set collection to search self.search.collections([inpe_collections[collection_id]]) # set valid minimum dates mindate = self.collections.get_temporal_extent( inpe_collections[collection_id])[0].split('-') year, month, day = int(mindate[0]), int(mindate[1]), int(mindate[2]) self.dockwidget.startdate.setMinimumDate(QDate(year, month, day)) self.dockwidget.enddate.setMinimumDate(QDate(year, month, day)) # set valid maximum dates self.dockwidget.startdate.setMaximumDate(QDate.currentDate()) self.dockwidget.enddate.setMaximumDate(QDate.currentDate()) def do_search(self): """ Run search in INPE STAC Catalog """ self.result = self.search() self.dockwidget.resultsList.clear() # add items to result list # self.dockwidget.resultsList.addItems([str(item) for item in self.result]) icon = QIcon(":/images/themes/default/mIconRaster.svg") for item in self.result: list_item = QListWidgetItem(icon, str(item.id), self.dockwidget.resultsList) self.dockwidget.resultsList.addItem(list_item) if self.result.complete: self.dockwidget.resultsMsg.setText('Returned {0} scenes.'.format( self.result.returned)) else: self.dockwidget.resultsMsg.setText( 'Returned {0} scenes from {1} matched.'.format( self.result.returned, self.result.matched)) self.dockwidget.tabs.setCurrentIndex(1) self.clear_preview() def clear_preview(self): """ Clear preview tab """ self.dockwidget.webView.setHtml('') self.dockwidget.item_id.clear() self.dockwidget.item_date.clear() self.dockwidget.item_cloudcover.clear() self.dockwidget.footprint.setChecked(False) self.footprint.hide() self.dockwidget.footprint.setDisabled(True) self.dockwidget.assetsList.clear() self.dockwidget.assetsList.setDefaultText('') def preview(self, item): """ Preview selected scene """ self.clear_preview() item_id = item.text() self.dockwidget.webView.setHtml(self.result[item_id].html) self.dockwidget.item_id.setText(item_id) self.dockwidget.item_date.setText('{0}'.format( self.result[item_id].date)) self.dockwidget.item_cloudcover.setText('{0:.1f} %'.format( self.result[item_id].cloud_cover)) self.update_footprint() self.dockwidget.footprint.setEnabled(True) self.dockwidget.assetsList.setDefaultText('ALL') self.dockwidget.assetsList.addItems(self.result[item_id].assets) self.dockwidget.tabs.setCurrentIndex(2) def toggle_download_button(self, tab): """ Enable/disable download button and hide footprint on tab change """ if tab == 2: item_id = self.dockwidget.item_id.text() credential = self.dockwidget.credential.text() if item_id and credential: self.dockwidget.downloadButton.setEnabled(True) elif self.downloading: self.dockwidget.downloadButton.setEnabled(True) else: self.dockwidget.downloadButton.setDisabled(True) else: self.dockwidget.footprint.setChecked(False) self.footprint.hide() # update valid maximum dates on tab change self.dockwidget.startdate.setMaximumDate(QDate.currentDate()) self.dockwidget.enddate.setMaximumDate(QDate.currentDate()) def start_download(self): """ Start/cancel task to download item asset(s) """ if self.downloading: globals()['cbers4a_tasks'].cancel() else: item_id = self.dockwidget.item_id.text() sel_assets = self.dockwidget.assetsList.checkedItems() if sel_assets: assets = [asset for asset in sel_assets] else: assets = self.result[item_id].assets # # create the task variable with global scope # workaround for QGIS Issue #28531 # https://gis.stackexchange.com/questions/296175/issues-with-qgstask-and-task-manager/304801#304801 # globals()['cbers4a_tasks'] = QgsTask.fromFunction( 'Download {0}'.format(item_id), self.download_asset, on_finished=self.download_finished, item_id=item_id, assets=assets) # self.info('Starting task to download {} asset(s)'.format(item_id), duration=1) QgsApplication.taskManager().addTask(globals()['cbers4a_tasks']) # lock downloading self.downloading = True self.dockwidget.options.setDisabled(True) self.dockwidget.results.setDisabled(True) self.dockwidget.downloadButton.setText('Cancel Download') self.dockwidget.downloadButton.setStyleSheet( 'background-color: #ff3336') self.dockwidget.assetsList.setDisabled(True) def info(self, msg, level=Qgis.Info, duration=5): """ docstring """ self.iface.messageBar().pushMessage(msg, level, duration) def log(self, msg, level=Qgis.Info): """ docstring """ QgsMessageLog.logMessage(msg, self.name, level) def download_asset(self, task, item_id, assets): """ Task function to download asset(s) for a given item id """ self.log('Started task {}'.format(task.description())) credential = self.dockwidget.credential.text() collection = self.result[item_id].collection outdir = self.dockwidget.outputfolder.lineEdit().text( ) or self.outputfolder session = self.search.session filenames = {} for asset in assets: url = self.result[item_id].url(asset) filename = url.split("/")[-1] outfile = os.path.join(outdir, filename) r = session.get(url, params={ 'email': credential, 'item_id': item_id, 'collection': collection }, stream=True, allow_redirects=True) if r.status_code == 200: total_size = int(r.headers.get('content-length')) size = 0 with open(outfile + '.part', 'wb') as f: for ch in r.iter_content(chunk_size=4096): # page size 4kb if ch: f.write(ch) size = size + len(ch) progress = (size / total_size) * 100 # use task.setProgress to report progress task.setProgress(progress) # check task.isCanceled() to handle cancellation if task.isCanceled(): self.log('Task "{name}" was canceled'.format( name=task.description())) return None os.rename(outfile + '.part', outfile) self.log( f'Task {task.description()}:\nDownloaded file: {outfile} ({size} of {total_size} bytes)' ) filenames[asset] = outfile else: raise Exception('ERROR in ' + url + ' (' + r.reason + ')') return { 'description': item_id, 'filenames': filenames, 'outdir': outdir } def download_finished(self, exception, result=None): """ This is called when download_asset is finished. Exception is not None if download_asset raises an exception. result is the return value of download_asset. """ # VERY SLOW TO DO HERE # def __pszXML(nbands): # specband = '\n'.join([f"""<SpectralBand dstBand="{n+1}">\n</SpectralBand>""" for n in range(nbands)]) # return f"""<VRTDataset subClass="VRTPansharpenedDataset"> # <PansharpeningOptions> # {specband} # </PansharpeningOptions> # </VRTDataset>""" def __add_images(images, description, outdir, msgbar, check, vrt=True, shown=True): if check.isChecked() and vrt: pan = images.pop('pan', None) # take out pan if len(images) > 1: # stack images in a VRT file if there are more than one image left vrtfile = os.path.join(outdir, description + '.vrt') # to sort in r/g/b/nir order here sort(images.keys, key=lambda k: rgbn[k]) _RGBN = {'red': 1, 'green': 2, 'blue': 3, 'nir': 4} images_keys_ordered = sorted(images.keys(), key=lambda k: _RGBN.get(k, 5)) filenames = [images[k] for k in images_keys_ordered ] # filenames list in RGBN order ds = gdal.BuildVRT( vrtfile, filenames, options=gdal.BuildVRTOptions(separate=True, resolution='highest')) for i, bn in enumerate(images_keys_ordered): b = ds.GetRasterBand(i + 1) b.SetDescription(bn) ds.FlushCache() ds = None if pan is None: # nothing to do anymore, add VRT file __add_images({'vrt': vrtfile}, description, outdir, msgbar, check, vrt=False) else: # VERY SLOW TO DO HERE (perhaps as ProcessingProvider?) # nbands = len(images) # if nbands > 2: # may be a setting here for pansharpening choice # pan_ds = gdal.Open(pan) # pansharpened_ds = gdal.CreatePansharpenedVRT(__pszXML(nbands), pan_ds.GetRasterBand(1), # [ds.GetRasterBand(i + 1) for i in range(nbands)]) # pansharpened_filename = os.path.join(outdir, description + '_pansharpened.vrt') # driver = gdal.GetDriverByName('VRT') # driver.CreateCopy(pansharpened_filename, pansharpened_ds, 0) # # add ALL # __add_images({'pansharpened': pansharpened_filename, # 'pan': pan, 'vrt': vrtfile}, description, outdir, msgbar, check, vrt=False, shown=False) # else: # # just add pan and vrt files __add_images({ 'pan': pan, 'vrt': vrtfile }, description, outdir, msgbar, check, vrt=False) else: # do not stack since there are not enough images assert pan is not None # 'pan' should be not 'None' here images.update({'pan': pan}) # restore pan __add_images(images, description, outdir, msgbar, check, vrt=False) else: for k in images.keys(): fn = images[k] name = os.path.basename(fn).split('.')[0] layer = QgsRasterLayer(fn, name) if layer.isValid(): QgsProject.instance().addMapLayer(layer) if not shown: QgsProject.instance().layerTreeRoot().findLayer( layer.id()).setItemVisibilityChecked(shown) msgbar.dismiss() # unlock another downloading self.downloading = False self.dockwidget.options.setEnabled(True) self.dockwidget.results.setEnabled(True) self.dockwidget.downloadButton.setText('Download') self.dockwidget.downloadButton.setStyleSheet( 'background-color: None') # restore default background color self.dockwidget.assetsList.setEnabled(True) if exception is None: if result is None: self.log( 'Finished with no exception and no result (probably manually canceled by the user)', level=Qgis.Warning) else: assets = result['filenames'].keys() images = { asset: result['filenames'][asset] for asset in assets if not asset.lower().endswith(('_xml', 'thumbnail')) } if images: # ask to add image(s) to canvas widget = self.iface.messageBar().createMessage( f"Download {result['description']} finished") button = QPushButton(widget) button.setText('Add image(s)') widget.layout().addWidget(button) check = QCheckBox(widget) check.setText('Stack in VRT file') widget.layout().addWidget(check) if len(images) < 2: check.setDisabled(True) button.clicked.connect( lambda: __add_images(images, result['description'], result['outdir'], widget, check)) self.iface.messageBar().pushWidget(widget, Qgis.Info) else: self.info(f"Download {result['description']} finished") else: self.log("Exception: {}".format(exception), level=Qgis.Critical) raise exception def toggle_footprint(self): """ Toggle footprint image view on canvas """ if self.dockwidget.footprint.isChecked(): self.footprint.show() else: self.footprint.hide() def update_footprint(self): """ Update image footprint (image extent) """ item_id = self.dockwidget.item_id.text() if item_id and self.result is not None: try: if self.result[item_id].sensor == 'WFI': geojson = self.wfi_grid[self.result[item_id].path_row] else: geojson = self.mux_grid[ self.result[item_id].path_row] # MUX and WPAN qgis_geom = QgsGeometry.fromPolygonXY([[ QgsPointXY(pt[0], pt[1]) for pt in geojson['coordinates'][0] ]]) except KeyError: # use bbox xmin, ymin, xmax, ymax = self.result[item_id].bbox qgis_geom = QgsGeometry.fromRect( QgsRectangle(xmin, ymin, xmax, ymax)) self.footprint.setToGeometry( qgis_geom, QgsCoordinateReferenceSystem('EPSG:4326')) defaults = QgsSettings() self.footprint.setStrokeColor( defaults.value("cbers4a/colorstroke", QColor(255, 255, 82))) self.footprint.setWidth(3) self.toggle_footprint() def load_grids(self): """ Load CBERS4A MUX and WFI grids """ # json files json_mux = os.path.join(self.plugin_dir, 'grid/cbers4a_mux.json') json_wfi = os.path.join(self.plugin_dir, 'grid/cbers4a_wfi.json') # read mux grid with open(json_mux) as mux: self.mux_grid = json.load(mux) # read wfi grid with open(json_wfi) as wfi: self.wfi_grid = json.load(wfi) def defaults_settings(self): """ Init plugin settings defaults: - cbers4a/colorstroke - cbers4a/cloudcover - cbers4a/credential - cbers4a/timespan - cbers4a/limit """ s = QgsSettings() if not s.contains("cbers4a/colorstroke"): s.setValue("cbers4a/colorstroke", QColor(255, 255, 82)) s.setValue("cbers4a/cloudcover", 10) s.setValue("cbers4a/credential", '') s.setValue("cbers4a/timespan", 30) s.setValue("cbers4a/limit", 100) def init(self): """ Fill options, default values and connect triggers of the dockwidget """ # init settings self.defaults_settings() # init Search instance self.search = Search() # get collections self.collections = self.search.get_collections() inpe_collections = { description: id for id, description in self.collections } # load grids self.load_grids() # connect triggers self.iface.mapCanvas().extentsChanged.connect(self.update_extent) self.iface.mapCanvas().destinationCrsChanged.connect( self.update_extent) self.dockwidget.startdate.dateChanged.connect(self.update_startdate) self.dockwidget.enddate.dateChanged.connect(self.update_enddate) self.iface.projectRead.connect(self.update_outputfolder) self.iface.newProjectCreated.connect(self.update_outputfolder) QgsProject.instance().projectSaved.connect(self.update_outputfolder) self.dockwidget.limit.valueChanged.connect(self.update_limit) self.dockwidget.cloudcover.valueChanged.connect(self.update_cloudcover) self.dockwidget.collection.currentIndexChanged.connect( self.update_collection) self.dockwidget.searchButton.clicked.connect(self.do_search) self.dockwidget.resultsList.itemClicked.connect(self.preview) # self.dockwidget.credential.textChanged[str].connect(self.credential_changed) # self.dockwidget.credential.editingFinished.connect(self.credential_filled) self.dockwidget.tabs.currentChanged[int].connect( self.toggle_download_button) self.dockwidget.downloadButton.clicked.connect(self.start_download) self.dockwidget.footprint.clicked.connect(self.toggle_footprint) # fill collections combobox self.dockwidget.collection.addItems(inpe_collections.keys()) # set defaults defaults = QgsSettings() self.dockwidget.cloudcover.setValue( int(defaults.value("cbers4a/cloudcover", 10))) self.dockwidget.limit.setValue( int(defaults.value("cbers4a/limit", 100))) self.dockwidget.startdate.setDate(QDate.currentDate().addDays( -int(defaults.value("cbers4a/timespan", 30)))) self.dockwidget.credential.setText( defaults.value("cbers4a/credential", '')) self.update_extent() self.update_outputfolder() # disable download button # self.dockwidget.downloadButton.setDisabled(True) # validate credential (seems email) # self.dockwidget.credential.clear() # validator = QRegExpValidator(QRegExp("[^@]+@[^@]+\.[^@]+")) # self.dockwidget.credential.setValidator(validator) # disable footprint pushbutton self.dockwidget.footprint.setIcon( QIcon(':/images/themes/default/mActionShowSelectedLayers.svg')) self.dockwidget.footprint.setCheckable(True) self.dockwidget.footprint.setDisabled(True) self.dockwidget.downloadButton.setText('Download') self.dockwidget.assetsList.setDefaultText('') # start in first tab self.dockwidget.tabs.setCurrentIndex(0)
def add_action(self, name, icon_path, text, callback, toggle_flag=False, enabled_flag=True, checkable_flag=False, visible_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 name: Objectname of the action. Serves also as key for the stored actions. :type name: str :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 toggle_flag: A flag indicating if the action should connect the toggled or triggered signal by default. Defaults to triggered (False) :type toggle_flag: bool :param checkable_flag: A flag indicating if the action should be checkable by default. Defaults to False. :type checkable: bool :param visible_flag: A flag indicating if the action should be displayed by default. Defaults to True. :type visible: 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.setObjectName(name) if toggle_flag: action.toggled.connect(callback) else: action.triggered.connect(callback) action.setEnabled(enabled_flag) action.setCheckable(checkable_flag) action.setVisible(visible_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.iface.addPluginToMenu(self.menu, action) self.actions[name] = action return action
class MainPlugin(object): def __init__(self, iface): self.name = "groupLayers" self.iface = iface self.project = QgsProject.instance() self.treeBeforeSave = None def initGui(self): self.action = QAction( QIcon(os.path.dirname(os.path.realpath(__file__)) + "/icon.png"), u"Group Layers by similar type (keep visibility)", self.iface.mainWindow() ) self.action.setObjectName("groupAction") self.action.setWhatsThis("Group/ungroup layers by type") self.action.setStatusTip("Group/ungroup layers by type") self.action.setCheckable(True) self.action.triggered.connect(self.run) self.resetAction = QAction("Group and make all layers visible") self.resetAction.triggered.connect(self.run_reset_visibility) # the icon pressed status could be used, but it is already # changed when run method is called, so this is ambiguous # therefore a dedicated boolean status is used self.grouped = False self.groupAdditionalTypes = False self.defSelection = groupHierarchies.keys().__iter__().__next__() self.hierarchyDefinition = groupHierarchies[self.defSelection] # add toolbar button and menu item layersDock = self.iface.mainWindow().findChild(QDockWidget, "Layers") self.layersToolBar = layersDock.widget().layout().itemAt(0).widget() assert isinstance(self.layersToolBar, QToolBar) self.layersToolBar.addAction(self.action) self.menuButton = [btn for btn in self.layersToolBar.children() if isinstance(btn, QToolButton) if self.action in btn.actions()][0] self.buttonMenu = QMenu() self.menuButton.setMenu(self.buttonMenu) self.menuButton.setPopupMode(QToolButton.MenuButtonPopup) self.buttonMenu.addAction(self.action) self.buttonMenu.addAction(self.resetAction) # self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&Group Layers", self.action) self.defSelector = QAction( u"Select hierarchy definitions", self.iface.mainWindow() ) self.defSelector.setObjectName("defSelector") self.defSelector.triggered.connect(self.selectDefs) self.iface.addPluginToMenu("&Group Layers", self.defSelector) # connect hook to reset the plugin state # when a new or existing project is opened self.project.cleared.connect(self.reset_state) self.project.writeProject.connect(self.write) self.project.projectSaved.connect(self.saved) def unload(self): # remove the plugin menu item and icon self.iface.removePluginMenu("&Group Layers", self.action) self.iface.removePluginMenu("&Group Layers", self.defSelector) self.layersToolBar.removeAction(self.action) self.project.cleared.disconnect(self.reset_state) self.project.writeProject.disconnect(self.write) self.project.projectSaved.disconnect(self.saved) try: self.project.layerWasAdded.disconnect(self.add_layer_sync) except Exception: print('could not disconnect add_layer_sync in unload') try: self.project.layerRemoved.disconnect(self.remove_layer_sync) except Exception: print('could not disconnect remove_layer_sync in unload') # self.iface.removeToolBarIcon(self.action) def selectDefs(self): dialog = DefSelectDialog(self.defSelection, self.groupAdditionalTypes) if dialog.exec_(): self.defSelection = dialog.comboBox.currentText() self.hierarchyDefinition = groupHierarchies[self.defSelection] self.groupAdditionalTypes = dialog.checkBox.isChecked() def run(self, checked=False, reset=False): try: if self.grouped: try: self.project.layerWasAdded.disconnect(self.add_layer_sync) except Exception: print('could not disconnect add_layer_sync') try: self.project.layerRemoved.disconnect(self.remove_layer_sync) except Exception: print('could not disconnect remove_layer_sync') self.groupToTree(reset_initial_visibility=reset) self.resetAction.setText("Group and make all layers visible") else: self.treeToGroup(all_visible=reset) self.resetAction.setText("Ungroup and restore initial (ungrouped) visibility") self.project.layerWasAdded.connect(self.add_layer_sync) self.project.layerRemoved.connect(self.remove_layer_sync) except Exception as e: raise(e) finally: # synchronize plugin state with button state in case of exceptions self.grouped = checked def run_reset_visibility(self): self.action.toggle() self.run(checked=self.action.isChecked(), reset=True) def reset_state(self): self.action.setChecked(False) self.grouped = False def write(self): if self.grouped: answer = QMessageBox.question(self.iface.mainWindow(), "Save ungrouped state", "The layers are currently grouped by the " "groupLayers plugin\n\n" "Would you like to save the initial (ungrouped) state?\n" "(save current (grouped) layer tree if answer = NO)", QMessageBox.Yes|QMessageBox.No) if answer == QMessageBox.Yes: self.treeBeforeSave = self.iface.layerTreeCanvasBridge().rootGroup().clone() self.groupToTree(reset_initial_visibility=True) self.iface.messageBar().pushMessage( 'CAUTION: The layer tree has been saved in its original format, ' 'check options if you want to change this behavior.', Qgis.Info ) def saved(self): if self.treeBeforeSave is not None: tempOldTree = self.oldTree self.oldTree = self.treeBeforeSave self.groupToTree(reset_initial_visibility=True) self.oldTree = tempOldTree self.treeBeforeSave = None def add_layer_sync(self, addedLayer): self.oldTree.addLayer(addedLayer) def remove_layer_sync(self, removedLayerId): removedLayer = self.oldTree.findLayer(removedLayerId) self.recursiveRemoveFromGroup(self.oldTree, removedLayer) def recursiveRemoveFromGroup(self, group, layer): group.removeChildNode(layer) for subGroup in group.findGroups(): self.recursiveRemoveFromGroup(subGroup, layer) def initTreeRec(self, hierarchyDefinition, tree): for (k, v) in hierarchyDefinition.items(): if "groupCriteria" in v: tree[k] = {} self.initTreeRec(v["values"], tree[k]) else: tree[k] = [] def treeToGroup(self, all_visible=True): self.layerDict = {} self.treeRoot = self.project.layerTreeRoot() self.initTreeRec(self.hierarchyDefinition['values'], self.layerDict) layerTree = self.iface.layerTreeCanvasBridge().rootGroup() self.oldTree = layerTree.clone() self.parseTreeRec(layerTree) # into self.layerDict self.layerDict = self.cleanTree(self.layerDict) oldLen = len(layerTree.children()) self.layerDictToTree(self.layerDict, layerTree, all_visible) # caution: commented instruction below removes all layers !! # iface.layerTreeCanvasBridge().rootGroup().clear() layerTree.removeChildren(0, oldLen) def groupToTree(self, reset_initial_visibility=True): self.treeRoot = self.project.layerTreeRoot() layerTree = self.iface.layerTreeCanvasBridge().rootGroup() oldLen = len(layerTree.children()) self.insertInto(self.oldTree, layerTree, reset_initial_visibility) layerTree.removeChildren(0, oldLen) def layerDictToTree(self, layerDict, destinationGroup, all_visible): if isinstance(layerDict, dict): for (layerType, layers) in layerDict.items(): grp = destinationGroup.addGroup(layerType) self.layerDictToTree(layers, grp, all_visible) elif isinstance(layerDict, list): for l in layerDict: isVisible = self.treeRoot.findLayer(l).isVisible() node = destinationGroup.addLayer(l) if not all_visible: node.setItemVisibilityChecked(isVisible) else: raise Exception("Tree dictionary has been initialized incorrectly.") def insertInto(self, origin, destination, reset_initial_visibility): for el in origin.children(): if QgsLayerTree.isLayer(el): node = destination.addLayer(el.layer()) node.setItemVisibilityChecked( self.treeRoot.findLayer(el.layer()).isVisible() ) elif QgsLayerTree.isGroup(el): node = destination.addGroup(el.name()) self.insertInto(el, node, reset_initial_visibility) if reset_initial_visibility: # overwrite visibility with previously saved visibility node.setItemVisibilityChecked(el.itemVisibilityChecked()) def parseTreeRec(self, treeLeaf): for el in treeLeaf.children(): if QgsLayerTree.isLayer(el): l = el.layer() self.sortInto(l, self.layerDict, self.hierarchyDefinition) elif QgsLayerTree.isGroup(el): self.parseTreeRec(el) def sortInto(self, layer, destination, definitions): if "groupCriteria" in definitions: groupValue = layer.__getattribute__(definitions["groupCriteria"])() itemFound = False for (label, criteria) in definitions["values"].items(): if groupValue == criteria["value"]: itemFound = True self.sortInto(layer, destination[label], criteria) if not itemFound: if self.groupAdditionalTypes: groupName = "others" else: groupName = str(groupValue) try: destination[groupName].append(layer) except KeyError: destination[groupName] = [layer] else: destination.append(layer) def cleanTree(self, sourceTree): # remove all branches without end leaves if isinstance(sourceTree, dict): groupContents = {} for (layerType, layers) in sourceTree.items(): groupLayers = self.cleanTree(layers) if groupLayers: groupContents[layerType] = groupLayers return groupContents elif isinstance(sourceTree, list): return sourceTree else: raise Exception("Tree dictionary has been initialized incorrectly.")
class PostNAS_Search: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'PostNAS_Search_{}.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) # Create the dialog (after translation) and keep reference self.dlg = PostNAS_SearchDialog(iface=self.iface) self.conf = PostNAS_ConfDialog(iface=self.iface) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&PostNAS_Search') self.searchDockWidget = None self.searchDockWidgetArea = Qt.LeftDockWidgetArea # noinspection PyMethodMayBeStatic def tr(self, message): # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('PostNAS_Search', message) def initGui(self): # Create Conf-Action and Menuentry self.confAction = QAction("Einstellungen", self.iface.mainWindow()) self.confAction.setWhatsThis("Konfiguration der PostNAS-Suche") self.confAction.setStatusTip("Konfiguration der PostNAS-Suche") self.confAction.triggered.connect(self.showConf) if hasattr(self.iface, "addPluginToDatabaseMenu"): self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.confAction) else: self.iface.addPluginToMenu("&PostNAS-Suche", self.confAction) self.toggleSearchAction = QAction(u"Flurstücksuche", self.iface.mainWindow()) self.toggleSearchAction.setWhatsThis( u"Starten/Schliessen der Flurstücksuche") self.toggleSearchAction.setStatusTip( u"Starten/Schliessen der Flurstücksuche") self.toggleSearchAction.triggered.connect(self.toggleWidget) if hasattr(self.iface, "addPluginToDatabaseMenu"): self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.toggleSearchAction) else: self.iface.addPluginToMenu("&PostNAS-Suche", self.toggleSearchAction) self.fulltextindex = QAction(u"Volltextindex erstellen", self.iface.mainWindow()) self.fulltextindex.setWhatsThis( u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen" ) self.fulltextindex.setStatusTip( u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen" ) self.fulltextindex.triggered.connect(self.createFulltextindex) if hasattr(self.iface, "addPluginToDatabaseMenu"): self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.fulltextindex) else: self.iface.addPluginToMenu("&PostNAS-Suche", self.fulltextindex) # Create action that will start plugin configuration self.action = QAction( QIcon(":/plugins/PostNAS_Search/search_24x24.png"), u"Flurstücksuche", self.iface.mainWindow()) self.action.setCheckable(True) # connect the action to the run method self.action.triggered.connect(self.toggleWidget) # Add toolbar button and menu item self.iface.addToolBarIcon(self.action) def toggleWidget(self, event): if self.searchDockWidget == None: self.searchDockWidget = QDockWidget(self.iface.mainWindow()) self.searchDockWidget.setWindowTitle(self.tr(u'Suche')) self.searchDockWidget.setWidget(self.dlg) self.searchDockWidget.closeEvent = self.toggleWidget self.iface.addDockWidget(self.searchDockWidgetArea, self.searchDockWidget) self.action.setChecked(True) else: self.searchDockWidgetArea = self.iface.mainWindow().dockWidgetArea( self.searchDockWidget) self.iface.removeDockWidget(self.searchDockWidget) self.searchDockWidget = None self.action.setChecked(False) def showConf(self): dlg = PostNAS_ConfDialog(self) dlg.exec_() def createFulltextindex(self): dlg = PostNAS_CreateFulltextindex(self) dlg.exec_() def unload(self): # Remove the Toolbar Icon self.iface.removeToolBarIcon(self.action) # Remove DockWidget if self.searchDockWidget != None: self.iface.removeDockWidget(self.searchDockWidget) if hasattr(self.iface, "removePluginDatabaseMenu"): self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.confAction) self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.toggleSearchAction) self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.fulltextindex) else: self.iface.removePluginMenu("&PostNAS-Suche", self.confAction) self.iface.removePluginMenu("&PostNAS-Suche", self.toggleSearchAction) self.iface.removePluginMenu("&PostNAS-Suche", self.fulltextindex) if self.confAction: self.confAction.deleteLater() self.confAction = None if self.toggleSearchAction: self.toggleSearchAction.deleteLater() self.toggleSearchAction = None if self.fulltextindex: self.fulltextindex.deleteLater() self.fulltextindex = None
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)
class QVDistrictesBarris(QObject): __distBarrisCSV = r'Dades\DIST_BARRIS.csv' __zones = r'Dades\Zones.gpkg' def __init__(self): super().__init__() self.labels = [] self.registre = {} # Model self.model = QStandardItemModel() self.llegirZonesGPKG() #self.llegirDistrictesBarrisCSV() # View self.view = QTreeView() self.view.setContextMenuPolicy(Qt.ActionsContextMenu) self.actExpand = QAction("Expandeix/Contreu Tot", self) self.actExpand.setStatusTip("Expand") self.actExpand.triggered.connect(self.expand_all) self.view.addAction(self.actExpand) self.view.setModel(self.model) self.iniView() def expand_all(self): """Expandir o contraer todo el arbol, dependiendo de si detecta que esta extendido o contraido """ if self.view.isExpanded(self.model.index(0, 0, QModelIndex())): self.view.collapseAll() else: self.view.expandAll() def iniView(self): self.view.setHeaderHidden(True) for i in range(self.model.columnCount()): if i == 0: self.view.setColumnHidden(i, False) self.view.resizeColumnToContents(i) self.view.resizeColumnToContents(i) else: self.view.setColumnHidden(i, True) self.view.setEditTriggers(QTreeView.NoEditTriggers) self.expand_all() def llegirZonesGPKG(self): try: QvFuncions.setReadOnlyFile(self.__zones) pathDistrictes = self.__zones + '|layername=districtes' layerDistrictes = QgsVectorLayer(pathDistrictes, 'ogr') pathBarris = self.__zones + '|layername=barris' layerBarris = QgsVectorLayer(pathBarris, 'ogr') rowsDistrictes = layerDistrictes.getFeatures() llistaDistrictes = [] for rowD in rowsDistrictes: #print(rowD.attributes()) #zona = "" num_districte = rowD.attributes()[1] nom_districte = rowD.attributes()[2] num_barri = "" nom_barri = "" geometria = rowD.geometry().boundingBox() x_min = str(geometria.xMinimum()) y_min = str(geometria.yMinimum()) x_max = str(geometria.xMaximum()) y_max = str(geometria.yMaximum()) item = [ num_districte, nom_districte, num_barri, nom_barri, x_min, y_min, x_max, y_max ] llistaDistrictes.append(item) def ordenaPerNumDistricte(elem): return elem[0] llistaDistrictes.sort(key=ordenaPerNumDistricte) #print(llistaDistrictes) rowsBarris = layerBarris.getFeatures() llistaBarris = [] for rowB in rowsBarris: #print(rowB.attributes()) #zona = "" num_districte = rowB.attributes()[3] nom_districte = llistaDistrictes[int(num_districte) - 1][1] num_barri = rowB.attributes()[1] nom_barri = rowB.attributes()[2] geometria = rowB.geometry().boundingBox() x_min = str(geometria.xMinimum()) y_min = str(geometria.yMinimum()) x_max = str(geometria.xMaximum()) y_max = str(geometria.yMaximum()) item = [ num_districte, nom_districte, num_barri, nom_barri, x_min, y_min, x_max, y_max ] llistaBarris.append(item) def ordenaPerNumBarri(elem): return elem[2] llistaBarris.sort(key=ordenaPerNumBarri) #print(llistaBarris) self.labels = [ "ZONA", "DISTRICTE", "NOM_DISTRICTE", "BARRI", "NOM_BARRI", "X_MIN", "Y_MIN", "X_MAX", "Y_MAX" ] root = self.model.invisibleRootItem() self.model.setColumnCount(len(self.labels)) self.model.setHorizontalHeaderLabels(self.labels) #Afegir Barcelona com a arrel de l'arbre bcn_dades = [ "00", "Barcelona", "00", "Barcelona", "419710.0553820258", "4573818.80776309", "436533.35", "4591775.02" ] bcn = [QStandardItem("Barcelona")] for item in bcn_dades: bcn.append(QStandardItem(item)) root.appendRow(bcn) ultimaDistr = -1 itDist = 0 for b in llistaBarris: if ultimaDistr != int(b[0]): #Afegir següent districte dist = [QStandardItem(llistaDistrictes[itDist][1])] for i in range(0, len(llistaDistrictes[itDist])): dist.append(QStandardItem(llistaDistrictes[itDist][i])) bcn[0].appendRow(dist) itDist = itDist + 1 #Afegir següent Barri barri = [QStandardItem(b[3])] for item in b: barri.append(QStandardItem(item)) dist[0].appendRow(barri) ultimaDistr = int(b[0]) return True except: print("Error en construcció de l'arbre de zones") return False # def llegirDistrictesBarrisCSV(self): # try: # first = True # with open(self.__distBarrisCSV, newline='') as csvFile: # reader = csv.DictReader(csvFile, delimiter=';') # root = self.model.invisibleRootItem() # for row in reader: # if first: # Primer registro # self.labels = ['ZONA'] # for item in row: # self.labels.append(item) # self.model.setColumnCount(len(self.labels)) # self.model.setHorizontalHeaderLabels(self.labels) # first = False # if row['BARRI'] == '': # Registro de distrito # dist = [QStandardItem(row['NOM_DISTRICTE'])] # for item in row.values(): # dist.append(QStandardItem(item)) # root.appendRow(dist) # else: # Registro de barrio # barri = [QStandardItem(row['NOM_BARRI'])] # for item in row.values(): # barri.append(QStandardItem(item)) # dist[0].appendRow(barri) # return True # except: # print('QDistrictesBarris.llegirDistrictesBarrisCSV(): ', sys.exc_info()[0], sys.exc_info()[1]) # return False def llegirRegistre(self): try: click = self.view.currentIndex() #Controlarem si s'ha canviat d'índex o no if hasattr(self, 'ultimIndex') and self.ultimIndex == click: return self.registre self.ultimIndex = click self.registre = {} for i in range(self.model.columnCount()): index = click.sibling(click.row(), i) item = self.model.itemFromIndex(index) self.registre[self.labels[i]] = item.text() self.registre['RANG'] = QgsRectangle(float(self.registre['X_MIN']), \ float(self.registre['Y_MIN']), \ float(self.registre['X_MAX']), \ float(self.registre['Y_MAX'])) except: print('QDistrictesBarris.llegirRegistre(): ', sys.exc_info()[0], sys.exc_info()[1]) finally: return self.registre def llegirRang(self): return self.llegirRegistre()['RANG'] def esDistricte(self): return self.llegirRegistre()['BARRI'] == '' def esBarri(self): return not self.esDistricte() def llegirNom(self): if self.esDistricte(): distr = self.llegirRegistre()["NOM_DISTRICTE"] distr_d = distr + "_d" return distr_d else: barri = self.llegirRegistre()["NOM_BARRI"] if barri == "Barcelona": return barri else: barri_b = barri + "_b" return barri_b def llegirID(self): if self.esDistricte(): return self.llegirRegistre()['DISTRICTE'] return self.llegirRegistre()['BARRI']
class GimpSelectionFeaturePlugin(QObject): def __init__(self, iface): super().__init__() self.iface = iface self.name = u"&Gimp Selection Feature" self.dock = self.exitsPluginGimp = None self.translate = Translate( 'gimpselectionfeature' ) def initGui(self): def setExistsPluginGimp(): def getDirPluginGimp(): dirPlugin = None mask = r".*gimp.[0-9]+.[0-9]+/%s" % nameDirPlugin # Linux Format for root, dirs, files in os.walk( dirHome ): if re.match( mask, root.replace('\\', '/'), re.IGNORECASE ): dirPlugin = root break return dirPlugin def copyNewPlugin(): shutil.copy2( gimpPlugin, gimpPluginInstall ) if sys.platform != 'win32': # Add executable st = os.stat( gimpPluginInstall ) os.chmod( gimpPluginInstall, st.st_mode | stat.S_IEXEC ) dirHome = os.path.expanduser('~') nameDirPlugin = "plug-ins" dirPluginGimp = getDirPluginGimp() if dirPluginGimp is None: msg = "Not found diretory 'GIMP' or 'GIMP {}' in '{}'".format( nameDirPlugin, dirHome ) self.exitsPluginGimp = { 'isOk': False, 'msg': msg } return namePlugin = 'socket_server_selection.py' gimpPlugin = os.path.join( os.path.dirname(__file__), namePlugin ) gimpPluginInstall = os.path.join( dirPluginGimp, namePlugin ) if not os.path.exists( gimpPluginInstall ) or not filecmp.cmp( gimpPlugin, gimpPluginInstall ): copyNewPlugin() self.exitsPluginGimp = { 'isOk': True } name = "Gimp Selection Feature" about = QCoreApplication.translate('GimpSelectionFeature', 'Adding selected area in GIMP how a feature in shapefile') icon = QIcon( os.path.join( os.path.dirname(__file__), 'gimpselectionfeature.svg' ) ) self.action = QAction( icon, name, self.iface.mainWindow() ) self.action.setObjectName( name.replace(' ', '') ) self.action.setWhatsThis( about ) self.action.setStatusTip( about ) self.action.setCheckable( True ) self.action.triggered.connect( self.run ) self.iface.addRasterToolBarIcon( self.action ) self.iface.addPluginToRasterMenu( self.name, self.action ) setExistsPluginGimp() if not self.exitsPluginGimp['isOk']: return self.dock = DockWidgetGimpSelectionFeature( self.iface ) self.iface.addDockWidget( Qt.RightDockWidgetArea , self.dock ) self.dock.visibilityChanged.connect( self.dockVisibilityChanged ) def unload(self): self.iface.removeRasterToolBarIcon( self.action ) self.iface.removePluginRasterMenu( self.name, self.action ) if self.exitsPluginGimp['isOk']: self.dock.close() del self.dock self.dock = None del self.action @pyqtSlot() def run(self): if not self.exitsPluginGimp['isOk']: ( t, m ) = ( GimpSelectionFeature.nameModulus, self.exitsPluginGimp['msg'] ) self.iface.messageBar().pushMessage( t, m, Qgis.Critical, 5 ) self.action.setChecked( False ) return if self.dock.isVisible(): self.dock.hide() else: self.dock.show() @pyqtSlot(bool) def dockVisibilityChanged(self, visible): self.action.setChecked( visible )
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): 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: # Adds plugin icon to Plugins toolbar self.iface.addToolBarIcon(action) if add_to_menu: self.iface.addPluginToVectorMenu(self.menu, action) self.actions.append(action) # Connect all actions self.dlg.dirOldButton.clicked.connect(self.select_oldDir) self.dlg.dirNewButton.clicked.connect(self.select_newDir) self.dlg.dirResultButton.clicked.connect(self.select_dirResult) self.dlg.mengdertilcsvButton.clicked.connect(self.getStats) self.dlg.selectdir_MButton.clicked.connect(self.select_output_dirM) self.dlg.skrivtilcsvButton.clicked.connect(self.exportLayers) self.dlg.compareButton.clicked.connect(self.comparefiles) self.dlg.comboBox.currentIndexChanged[str].connect( self.comboBox_itemChanged) self.dlg.addButton.clicked.connect(self.addItem) self.dlg.removeButton.clicked.connect(self.removeItem) self.dlg.clearButton.clicked.connect(self.clearSelection) self.dlg.kommuneCheck.toggled.connect(self.kommuneSelected) self.dlg.checkBox_fritekst.toggled.connect( self.comp_checkbox_handler_free) self.dlg.checkBox_nvdbid.toggled.connect( self.comp_checkbox_handler_nvdbid) self.dlg.checkBox_objekt.toggled.connect( self.comp_checkbox_handler_object) self.dlg.kontraktCheck.toggled.connect(self.kontraktSelected) self.dlg.fylkeBox.currentIndexChanged[str].connect(self.getKommune) self.dlg.fylkeBox.currentIndexChanged[str].connect(self.getKontrakt) self.dlg.fylkeBox.currentIndexChanged.connect( self.fylkeBox_itemChanged) self.dlg.kommuneBox.currentIndexChanged[str].connect( self.kommuneBox_itemChanged) self.dlg.kontraktBox.currentIndexChanged[str].connect( self.kontraktBox_itemChanged) self.dlg.mergeButton.clicked.connect(self.mergeLayers) self.dlg.selectdirButton.clicked.connect(self.select_output_dir) self.dlg.kjorButton.clicked.connect(self.runTask) self.dlg.saveButton.clicked.connect(self.saveAsPreset) self.dlg.vegsystemBox.currentIndexChanged[str].connect( self.vegsystemBox_itemChanged) self.dlg.searchTable.doubleClicked.connect(self.searchPreset) self.dlg.deleteButton.clicked.connect(self.deletePreset) self.dlg.statsButton.clicked.connect(self.loadStats) self.dlg.folderButton.clicked.connect(self.openFolder) getAllAreaData() getAllObjectData() getAllPresetData() self.dlg.vegsystemBox.addItems(returnVegreferanseData()) return action
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): """Add a toolbar icon to the toolbar. Parameters ---------- icon_path : str Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path text : str Text that should be shown in menu items for this action callback : function Function to be called when the action is triggered enabled_flag : bool, optional A flag indicating if the action should be enabled by default (defaults to True) add_to_menu : bool, optional Flag indicating whether the action should also be added to the menu (defaults to True) add_to_toolbar : bool, optional Flag indicating whether the action should also be added to the toolbar (defaults to True) status_tip : str or None, optional Text to show in a popup when mouse pointer hovers over the action (defaults to None) whats_this : str or None, optional Text to show in the status bar when the mouse pointer hovers over the action (defaults to None) parent : QWidget or None, optional Parent widget for the new action (defaults to None) Returns ---------- QAction The action that was created. Note that the action is also added to self.actions list. """ 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: # Adds plugin icon to Plugins toolbar self.iface.addToolBarIcon(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action
class HuntRegister: """QGIS Plugin Implementation.""" 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__) # Check if plugin was started the first time in current QGIS session # Must be set in initGui() to survive plugin reloads self.first_start = None # This plugin depends on alkisplugin self.alkisplugin = None # Members self.alkisToolBar = None # the toolbar instance where the alkisplugin and huntplugin QAction symbols are placed self.alkisSelectAreaLayer = None # QgsVectorLayer selected parcels of alkisplugin self.huntSelectAreaLayer = None # QgsVectorLayer selected parcels of huntplugin # help web view self.helpiew = None # webview containing manuals # All actions are assigned to alter self.huntSelectAreaLayer self.hswapAction = None # single QAction copy selected parcels from alkisplugin to huntplugin self.hAddMarkAction = None # checkable QAction select and unselect parcels self.hlistAction = None # single QAction select parcels by parcel attributes self.hclearAction = None # single QAction unselect all selected parcels self.hownerAction = None # single QAction get parcel certificates for all selected parcels self.hhuntAction = None # single QAction create a hunt register self.hinfoAction = None # single QAction get a basic summary of all selected parcels self.helpAction = None # single QAction open help files webview browser window # self.testAction = None # single QAction used for testing program fragments self.hAddMarkTool = None # click recognizing map tool for self.hAddMarkAction self.core = None # function core for this plugin self.initTimer = QTimer( self.iface ) # timer used to init self.huntSelectAreaLayer dynamically when alkis layers are added self.initTimer.setInterval(1000) # 1 sec interval self.initTimer.timeout.connect(self.initLayers) self.init() # init main instances def init(self): """init main instances""" if (alkisAvailable): try: self.alkisplugin = Alkis.alkisplugin.alkisplugin( self.iface) # create alkisplugin object self.alkisplugin.queryOwnerAction = QAction( None ) # this is used in akisplugin "opendb" and must therefore be set to prevent runtime errors except AttributeError: QMessageBox.critical( None, "Fehler", "norGIS ALKIS-Einbindung zuerst aktivieren und \"JagdKataster\" erneut aktivieren" ) raise AttributeError("alkisplugin not active") else: QMessageBox.critical( None, "Fehler", "norGIS ALKIS-Einbindung installieren und zuerst aktivieren. Dann \"JagdKataster\" erneut aktivieren" ) raise AttributeError("alkisplugin not installed") self.core = HuntCore(self) # function core for this plugin def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" # will be set False in run() self.first_start = True self.helpview = QWebView() self.helpview.resize(1280, 850) self.helpview.setWindowTitle("JagdKataster Anleitungen") help_dir = os.path.join(self.plugin_dir, "help", "build", "html", "index.html") self.helpview.load(QUrl.fromLocalFile(help_dir)) # the toolbar entries of this plugin should be placed alongside the alkisplugin entries # therefore the alkisplugin toolbar is derived tBars = self.iface.mainWindow().findChildren( QToolBar) # get all toolbars from main window self.alkisToolBar = next( (n for n in tBars if n.objectName() == "norGIS_ALKIS_Toolbar"), None ) # find the instance of alkisplugin toolbar by its static name if self.alkisToolBar is None: # in case the toolbar is not yet loaded create the instance with its static name # create alkis toolbar in case it is not yet loaded self.alkisToolBar = self.iface.addToolBar(u"norGIS: ALKIS") self.alkisToolBar.setObjectName("norGIS_ALKIS_Toolbar") #create toolbar items self.hswapAction = QAction(QIcon("hunt:mark_transfer.svg"), "Flächenmarkierung übertragen", self.iface.mainWindow()) self.hswapAction.setWhatsThis( "Flächenmarkierung (gelb) nach Jagd-Flächenmarkierung (blau) übertragen" ) self.hswapAction.setStatusTip( "Flächenmarkierung (gelb) nach Jagd-Flächenmarkierung (blau) übertragen" ) self.hswapAction.triggered.connect(lambda: self.core.swapAlkisToHunt()) self.alkisToolBar.addAction(self.hswapAction) self.hAddMarkAction = QAction(QIcon("hunt:mark_add.svg"), u"Flurstück (de)selektieren", self.iface.mainWindow()) self.hAddMarkAction.setWhatsThis( "Flurstück in Jagd-Flächenmarkierung selektieren oder deselektieren" ) self.hAddMarkAction.setStatusTip( "Flurstück in Jagd-Flächenmarkierung selektieren oder deselektieren" ) self.hAddMarkAction.setCheckable(True) self.hAddMarkAction.triggered.connect( lambda: self.iface.mapCanvas().setMapTool(self.hAddMarkTool)) self.alkisToolBar.addAction(self.hAddMarkAction) self.hAddMarkTool = HAdd(self) self.hAddMarkTool.setAction(self.hAddMarkAction) self.hlistAction = QAction(QIcon("hunt:mark_list.svg"), "Selektieren nach Flurstückseigenschaft", self.iface.mainWindow()) self.hlistAction.setWhatsThis( "Selektierung der Flurstücke in Jagd-Flächenmarkierung anhand Flurstückseigenschaften" ) self.hlistAction.setStatusTip( "Selektierung der Flurstücke in Jagd-Flächenmarkierung anhand Flurstückseigenschaften" ) self.hlistAction.triggered.connect( lambda: self.core.showListSelection()) self.alkisToolBar.addAction(self.hlistAction) self.hclearAction = QAction(QIcon("hunt:mark_clear.svg"), "Alle deselektieren", self.iface.mainWindow()) self.hclearAction.setWhatsThis( "Alle Flurstücke in Jagd-Flächenmarkierung deselektieren") self.hclearAction.setStatusTip( "Alle Flurstücke in Jagd-Flächenmarkierung deselektieren") self.hclearAction.triggered.connect(lambda: self.core.clearHighlight()) self.alkisToolBar.addAction(self.hclearAction) self.hownerAction = QAction(QIcon("hunt:mark_own.svg"), "Flurstücksnachweise anzeigen", self.iface.mainWindow()) self.hownerAction.setWhatsThis( "Flurstücksnachweise für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen" ) self.hownerAction.setStatusTip( "Flurstücksnachweise für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen" ) self.hownerAction.triggered.connect( lambda: self.core.showParcelCerts()) self.alkisToolBar.addAction(self.hownerAction) self.hhuntAction = QAction(QIcon("hunt:mark_hunt.svg"), "Jagdkataster erstellen", self.iface.mainWindow()) self.hhuntAction.setWhatsThis( "Jagdkataster für selektierte Flurstücke in Jagd-Flächenmarkierung erstellen" ) self.hhuntAction.setStatusTip( "Jagdkataster für selektierte Flurstücke in Jagd-Flächenmarkierung erstellen" ) self.hhuntAction.triggered.connect(lambda: self.core.showHuntReg()) self.alkisToolBar.addAction(self.hhuntAction) self.hinfoAction = QAction(QIcon("hunt:mark_info.svg"), "Flurstückszusammenfassung anzeigen", self.iface.mainWindow()) self.hinfoAction.setWhatsThis( "Flurstückszusammenfassung für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen" ) self.hinfoAction.setStatusTip( "Flurstückszusammenfassung für selektierte Flurstücke in Jagd-Flächenmarkierung anzeigen" ) self.hinfoAction.triggered.connect( lambda: self.core.showSummaryDialog()) self.alkisToolBar.addAction(self.hinfoAction) self.helpAction = QAction(QIcon("hunt:logo.svg"), "Anleitungen", self.iface.mainWindow()) self.helpAction.setWhatsThis("JagdKataster-Anleitungen") self.helpAction.setStatusTip("JagdKataster-Anleitungen") self.helpAction.triggered.connect(lambda: self.helpview.show()) # self.testAction = QAction(QIcon("hunt:test.svg"), "Test", self.iface.mainWindow()) # self.testAction.setWhatsThis("Test action") # self.testAction.setStatusTip("Test action") # self.testAction.triggered.connect(lambda: self.core.test(self.huntSelectAreaLayer)) # self.alkisToolBar.addAction(self.testAction) self.iface.addPluginToDatabaseMenu("&ALKIS", self.helpAction) QgsProject.instance().layersAdded.connect( self.initTimer.start ) # react to changes in the layer tree. Maybe the alkis layers were added QgsProject.instance().layersWillBeRemoved.connect( self.layersRemoved ) # remove entries in case this plugin layers are to be removed def initLayers(self): """init self.huntSelectAreaLayer in case the alkis layers from alkisplugin are loaded""" self.initTimer.stop( ) # this methode may be called by a timer started when layers are added => stop the timer after first timeout event if self.alkisSelectAreaLayer is None: # are alkisplugin layers loaded ad readable from entry? (layerId, res) = QgsProject.instance().readEntry("alkis", "/areaMarkerLayer") if res and layerId: self.alkisSelectAreaLayer = QgsProject.instance().mapLayer( layerId) if self.huntSelectAreaLayer is None: # is the huntplugin layer already loaded? (layerId, res) = QgsProject.instance().readEntry("hunt", "/areaMarkerLayer") if res and layerId: self.huntSelectAreaLayer = QgsProject.instance().mapLayer( layerId) if self.huntSelectAreaLayer is None and self.alkisSelectAreaLayer is not None: # alkisplugin layers are loaded but huntplugin layer is not self.createLayer() # create huntplugin layer def layersRemoved(self, layersIds): """remove entries and references in case this plugin layers are to be removed""" if self.alkisSelectAreaLayer is not None and self.alkisSelectAreaLayer.id( ) in layersIds: self.alkisSelectAreaLayer = None if self.huntSelectAreaLayer is not None and self.huntSelectAreaLayer.id( ) in layersIds: QgsProject.instance().removeEntry("hunt", "/areaMarkerLayer") self.core.hlayer = None self.huntSelectAreaLayer = None def createLayer(self): """create and add huntplugin layer to the layer tree""" if (self.alkisSelectAreaLayer is not None): parent = QgsProject.instance().layerTreeRoot().findLayer( self.alkisSelectAreaLayer).parent() layeropts = QgsVectorLayer.LayerOptions(False, False) self.init( ) # reinit main instances because alkis instance conninfo might have changed (db, conninfo) = self.core.openDB() if db is None: return self.huntSelectAreaLayer = QgsVectorLayer( u"%s estimatedmetadata=true checkPrimaryKeyUnicity=0 key='ogc_fid' type=MULTIPOLYGON srid=%d table=%s.po_polygons (polygon) sql=false" % (conninfo, self.alkisplugin.epsg, self.alkisplugin.quotedschema()), u"Jagd-Flächenmarkierung", "postgres", layeropts) sym = QgsSymbol.defaultSymbol(QgsWkbTypes.PolygonGeometry) sym.setColor(Qt.blue) sym.setOpacity(0.3) self.huntSelectAreaLayer.setRenderer(QgsSingleSymbolRenderer(sym)) QgsProject.instance().addMapLayer(self.huntSelectAreaLayer, False) parent.insertLayer(0, self.huntSelectAreaLayer) self.core.hlayer = None QgsProject.instance().writeEntry("hunt", "/areaMarkerLayer", self.huntSelectAreaLayer.id()) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" if self.hswapAction: self.hswapAction.deleteLater() self.hswapAction = None if self.hAddMarkAction: self.hAddMarkAction.deleteLater() self.hAddMarkAction = None if self.hlistAction: self.hlistAction.deleteLater() self.hlistAction = None if self.hclearAction: self.hclearAction.deleteLater() self.hclearAction = None if self.hownerAction: self.hownerAction.deleteLater() self.hownerAction = None if self.hhuntAction: self.hhuntAction.deleteLater() self.hhuntAction = None if self.hinfoAction: self.hinfoAction.deleteLater() self.hinfoAction = None if self.helpAction: self.helpAction.deleteLater() self.helpAction = None # if self.testAction: # self.testAction.deleteLater() # self.testAction = None QgsProject.instance().layersAdded.disconnect(self.initTimer.start) QgsProject.instance().layersWillBeRemoved.disconnect( self.layersRemoved) def run(self): """Run method""" if self.first_start: self.first_start = False
class PointConnector(object): """QGIS Plugin Implementation.""" 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 locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'PointConnector_{}.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) # Create the dialog (after translation) and keep reference self.dlg = PointConnectorDialog() # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Point Connector') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'PointConnector') self.toolbar.setObjectName(u'PointConnector') self.addedLayers = 1 # noinspection PyMethodMayBeStatic def tr(self, message): """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('PointConnector', message) 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): """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.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def initGui(self): self.action = QAction(QIcon(":/plugins/PointConnector/icon.png"), "PointConnector", self.iface.mainWindow()) self.action.setWhatsThis("Connect points") self.action.setStatusTip("Connect points following a from-to list") self.action.triggered.connect(self.run) if hasattr(self.iface, "addPluginToVectorMenu"): self.iface.addVectorToolBarIcon(self.action) self.iface.addPluginToVectorMenu("&PointConnector", self.action) else: self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("&PointConnector", self.action) def unload(self): self.iface.removePluginVectorMenu("&PointConnector", self.action) self.iface.removeVectorToolBarIcon(self.action) self.iface.removeToolBarIcon(self.action) def run(self): self.dlg.populateComboBox() # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # See if OK was pressed if result == 1: # create layers dict #layers = QgsProject.instance().mapLayers() layers = {} for name, layer in QgsProject.instance().mapLayers().items(): layers[layer.name()] = layer #choose point-source chosenPoint = self.dlg.pointsComboBox.currentText() if chosenPoint != 'Choose layer...': point_layer = layers[chosenPoint] else: pointPath = self.dlg.pointPathLineEdit.text() point_layer = QgsVectorLayer( pointPath, 'points', 'ogr') #shp-file with attribute field name try: p = open(pointPath, 'r') p.close() except IOError: QMessageBox.information( None, "Error", "Shape-file not found. Check file path.") return point_name_index = 0 # choose csv-source lines_list = [] chosenCsv = self.dlg.csvComboBox.currentText() if chosenCsv != 'Choose layer...': csv_layer = layers[chosenCsv] csv_features = csv_layer.getFeatures() for line in csv_features: attrs = line.attributes() lines_list.append(((str(attrs[0])), str(attrs[1]))) else: csvPath = self.dlg.csvPathLineEdit.text() # test if csv is valid try: f = codecs.open(csvPath, 'r', 'utf-8-sig') for line in f: pass f = codecs.open(csvPath, 'r', 'utf-8-sig') except UnicodeDecodeError: try: f = open(csvPath, 'r') re.search('\\\\', f) == None except: QMessageBox.information( None, "Error", "PointConnector can not read csv-file. Try saving it with utf-8 encoding or import it as a layer." ) return except IOError: QMessageBox.information( None, "Error", "Csv-file not found. Check file path or select a csv-layer." ) return #creating lines list from file for line in f: line = line.splitlines() for s in line[:1]: s = tuple(s.split(',')) lines_list.append(s) f.close() point_layer_crs = point_layer.crs().authid() lines_layer = QgsVectorLayer( 'LineString?crs=' + point_layer_crs, 'PointConnector lines ' + str(self.addedLayers), 'memory') pr = lines_layer.dataProvider() lines_layer.startEditing() pr.addAttributes([ QgsField('id', QVariant.Int), QgsField('from', QVariant.String), QgsField('to', QVariant.String) ]) #creating point coordinate dict points = point_layer.getFeatures() points_dict = {} #Progress bar widget progressMessageBar = iface.messageBar().createMessage( "Building point database...") progress = QProgressBar() progress.setMaximum(point_layer.featureCount()) progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) progressMessageBar.layout().addWidget(progress) iface.messageBar().pushWidget(progressMessageBar, Qgis.Info) i = 0 for p in points: geom = p.geometry() attrs = p.attributes() p = geom.asPoint() key = attrs[point_name_index] points_dict[str( key)] = p #attrs[point_name_index] = name field i += 1 progress.setValue(i) iface.messageBar().clearWidgets() QgsProject.instance().addMapLayer(point_layer) #Progress bar widget progressMessageBar = iface.messageBar().createMessage( "Drawing lines...") progress = QProgressBar() progress.setMaximum(len(lines_list)) progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) progressMessageBar.layout().addWidget(progress) iface.messageBar().pushWidget(progressMessageBar, Qgis.Info) #Drawing the lines i = 1 not_processed_list = [] for line in lines_list: if (line[0] in list(points_dict.keys()) and line[1] in list(points_dict.keys())): frPoint = points_dict[line[0]] toPoint = points_dict[line[1]] attrs = [i, line[0], line[1]] new_line = QgsGeometry.fromPolyline( [QgsPoint(frPoint), QgsPoint(toPoint)]) feat = QgsFeature() feat.setGeometry(new_line) feat.setAttributes(attrs) (res, outFeats) = pr.addFeatures([feat]) lines_layer.commitChanges() if res != True: pass i += 1 progress.setValue(i) else: not_processed_list.append(line) progress.setValue(i) iface.messageBar().clearWidgets() # add lines layer to canvas QgsProject.instance().addMapLayer(lines_layer) self.addedLayers += 1 if not not_processed_list: QMessageBox.information(None, 'Success', 'All lines drawn without error') else: QMessageBox.information( None, 'Error', str(len(not_processed_list)) + ' out of ' + str(len(lines_list)) + ' line(s) not drawn.')
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): """Add a toolbar icon to the 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.png") 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.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action
class GdalTools: def __init__(self, iface): if not valid: return # Save reference to the QGIS interface self.iface = iface try: self.QgisVersion = unicode(QGis.QGIS_VERSION_INT) except: self.QgisVersion = unicode(QGis.qgisVersion)[0] if QGis.QGIS_VERSION[0:3] < "1.5": # For i18n support userPluginPath = qgis.utils.home_plugin_path + "/GdalTools" systemPluginPath = qgis.utils.sys_plugin_path + "/GdalTools" overrideLocale = QSettings().value("locale/overrideFlag", False, type=bool) if not overrideLocale: localeFullName = QLocale.system().name() else: localeFullName = QSettings().value("locale/userLocale", "", type=str) if QFileInfo(userPluginPath).exists(): translationPath = userPluginPath + "/i18n/GdalTools_" + localeFullName + ".qm" else: translationPath = systemPluginPath + "/i18n/GdalTools_" + localeFullName + ".qm" self.localePath = translationPath if QFileInfo(self.localePath).exists(): self.translator = QTranslator() self.translator.load(self.localePath) QCoreApplication.installTranslator(self.translator) # The list of actions added to menus, so we can remove them when unloading the plugin self._menuActions = [] def initGui(self): if not valid: return if int(self.QgisVersion) < 1: QMessageBox.warning( self.iface.getMainWindow(), "Gdal Tools", QCoreApplication.translate("GdalTools", "QGIS version detected: ") + unicode(self.QgisVersion) + ".xx\n" + QCoreApplication.translate("GdalTools", "This version of Gdal Tools requires at least QGIS version 1.0.0\nPlugin will not be enabled.")) return None from .tools.GdalTools_utils import GdalConfig, LayerRegistry self.GdalVersionNum = GdalConfig.versionNum() LayerRegistry.setIface(self.iface) # find the Raster menu rasterMenu = None menu_bar = self.iface.mainWindow().menuBar() actions = menu_bar.actions() rasterText = QCoreApplication.translate("QgisApp", "&Raster") for a in actions: if a.menu() is not None and a.menu().title() == rasterText: rasterMenu = a.menu() break if rasterMenu is None: # no Raster menu, create and insert it before the Help menu self.menu = QMenu(rasterText, self.iface.mainWindow()) lastAction = actions[len(actions) - 1] menu_bar.insertMenu(lastAction, self.menu) else: self.menu = rasterMenu self._menuActions.append(self.menu.addSeparator()) # projections menu (Warp (Reproject), Assign projection) self.projectionsMenu = QMenu(QCoreApplication.translate("GdalTools", "Projections"), self.iface.mainWindow()) self.projectionsMenu.setObjectName("projectionsMenu") self.warp = QAction(QIcon(":/icons/warp.png"), QCoreApplication.translate("GdalTools", "Warp (Reproject)..."), self.iface.mainWindow()) self.warp.setObjectName("warp") self.warp.setStatusTip(QCoreApplication.translate("GdalTools", "Warp an image into a new coordinate system")) self.warp.triggered.connect(self.doWarp) self.projection = QAction(QIcon(":icons/projection-add.png"), QCoreApplication.translate("GdalTools", "Assign Projection..."), self.iface.mainWindow()) self.projection.setObjectName("projection") self.projection.setStatusTip(QCoreApplication.translate("GdalTools", "Add projection info to the raster")) self.projection.triggered.connect(self.doProjection) self.extractProj = QAction(QIcon(":icons/projection-export.png"), QCoreApplication.translate("GdalTools", "Extract Projection..."), self.iface.mainWindow()) self.extractProj.setObjectName("extractProj") self.extractProj.setStatusTip(QCoreApplication.translate("GdalTools", "Extract projection information from raster(s)")) self.extractProj.triggered.connect(self.doExtractProj) self.projectionsMenu.addActions([self.warp, self.projection, self.extractProj]) # conversion menu (Rasterize (Vector to raster), Polygonize (Raster to vector), Translate, RGB to PCT, PCT to RGB) self.conversionMenu = QMenu(QCoreApplication.translate("GdalTools", "Conversion"), self.iface.mainWindow()) self.conversionMenu.setObjectName("conversionMenu") if self.GdalVersionNum >= 1300: self.rasterize = QAction(QIcon(":/icons/rasterize.png"), QCoreApplication.translate("GdalTools", "Rasterize (Vector to Raster)..."), self.iface.mainWindow()) self.rasterize.setObjectName("rasterize") self.rasterize.setStatusTip(QCoreApplication.translate("GdalTools", "Burns vector geometries into a raster")) self.rasterize.triggered.connect(self.doRasterize) self.conversionMenu.addAction(self.rasterize) if self.GdalVersionNum >= 1600: self.polygonize = QAction(QIcon(":/icons/polygonize.png"), QCoreApplication.translate("GdalTools", "Polygonize (Raster to Vector)..."), self.iface.mainWindow()) self.polygonize.setObjectName("polygonize") self.polygonize.setStatusTip(QCoreApplication.translate("GdalTools", "Produces a polygon feature layer from a raster")) self.polygonize.triggered.connect(self.doPolygonize) self.conversionMenu.addAction(self.polygonize) self.translate = QAction(QIcon(":/icons/translate.png"), QCoreApplication.translate("GdalTools", "Translate (Convert Format)..."), self.iface.mainWindow()) self.translate.setObjectName("translate") self.translate.setStatusTip(QCoreApplication.translate("GdalTools", "Converts raster data between different formats")) self.translate.triggered.connect(self.doTranslate) self.paletted = QAction(QIcon(":icons/24-to-8-bits.png"), QCoreApplication.translate("GdalTools", "RGB to PCT..."), self.iface.mainWindow()) self.paletted.setObjectName("paletted") self.paletted.setStatusTip(QCoreApplication.translate("GdalTools", "Convert a 24bit RGB image to 8bit paletted")) self.paletted.triggered.connect(self.doPaletted) self.rgb = QAction(QIcon(":icons/8-to-24-bits.png"), QCoreApplication.translate("GdalTools", "PCT to RGB..."), self.iface.mainWindow()) self.rgb.setObjectName("rgb") self.rgb.setStatusTip(QCoreApplication.translate("GdalTools", "Convert an 8bit paletted image to 24bit RGB")) self.rgb.triggered.connect(self.doRGB) self.conversionMenu.addActions([self.translate, self.paletted, self.rgb]) # extraction menu (Clipper, Contour) self.extractionMenu = QMenu(QCoreApplication.translate("GdalTools", "Extraction"), self.iface.mainWindow()) self.extractionMenu.setObjectName("extractionMenu") if self.GdalVersionNum >= 1600: self.contour = QAction(QIcon(":/icons/contour.png"), QCoreApplication.translate("GdalTools", "Contour..."), self.iface.mainWindow()) self.contour.setObjectName("contour") self.contour.setStatusTip(QCoreApplication.translate("GdalTools", "Builds vector contour lines from a DEM")) self.contour.triggered.connect(self.doContour) self.extractionMenu.addAction(self.contour) self.clipper = QAction(QIcon(":icons/raster-clip.png"), QCoreApplication.translate("GdalTools", "Clipper..."), self.iface.mainWindow()) self.clipper.setObjectName("clipper") #self.clipper.setStatusTip( QCoreApplication.translate( "GdalTools", "Converts raster data between different formats") ) self.clipper.triggered.connect(self.doClipper) self.extractionMenu.addActions([self.clipper]) # analysis menu (DEM (Terrain model), Grid (Interpolation), Near black, Proximity (Raster distance), Sieve) self.analysisMenu = QMenu(QCoreApplication.translate("GdalTools", "Analysis"), self.iface.mainWindow()) self.analysisMenu.setObjectName("analysisMenu") if self.GdalVersionNum >= 1600: self.sieve = QAction(QIcon(":/icons/sieve.png"), QCoreApplication.translate("GdalTools", "Sieve..."), self.iface.mainWindow()) self.sieve.setObjectName("sieve") self.sieve.setStatusTip(QCoreApplication.translate("GdalTools", "Removes small raster polygons")) self.sieve.triggered.connect(self.doSieve) self.analysisMenu.addAction(self.sieve) if self.GdalVersionNum >= 1500: self.nearBlack = QAction(QIcon(":/icons/nearblack.png"), QCoreApplication.translate("GdalTools", "Near Black..."), self.iface.mainWindow()) self.nearBlack.setObjectName("nearBlack") self.nearBlack.setStatusTip(QCoreApplication.translate("GdalTools", "Convert nearly black/white borders to exact value")) self.nearBlack.triggered.connect(self.doNearBlack) self.analysisMenu.addAction(self.nearBlack) if self.GdalVersionNum >= 1700: self.fillNodata = QAction(QIcon(":/icons/fillnodata.png"), QCoreApplication.translate("GdalTools", "Fill nodata..."), self.iface.mainWindow()) self.fillNodata.setObjectName("fillNodata") self.fillNodata.setStatusTip(QCoreApplication.translate("GdalTools", "Fill raster regions by interpolation from edges")) self.fillNodata.triggered.connect(self.doFillNodata) self.analysisMenu.addAction(self.fillNodata) if self.GdalVersionNum >= 1600: self.proximity = QAction(QIcon(":/icons/proximity.png"), QCoreApplication.translate("GdalTools", "Proximity (Raster Distance)..."), self.iface.mainWindow()) self.proximity.setObjectName("proximity") self.proximity.setStatusTip(QCoreApplication.translate("GdalTools", "Produces a raster proximity map")) self.proximity.triggered.connect(self.doProximity) self.analysisMenu.addAction(self.proximity) if self.GdalVersionNum >= 1500: self.grid = QAction(QIcon(":/icons/grid.png"), QCoreApplication.translate("GdalTools", "Grid (Interpolation)..."), self.iface.mainWindow()) self.grid.setObjectName("grid") self.grid.setStatusTip(QCoreApplication.translate("GdalTools", "Create raster from the scattered data")) self.grid.triggered.connect(self.doGrid) self.analysisMenu.addAction(self.grid) if self.GdalVersionNum >= 1700: self.dem = QAction(QIcon(":icons/dem.png"), QCoreApplication.translate("GdalTools", "DEM (Terrain Models)..."), self.iface.mainWindow()) self.dem.setObjectName("dem") self.dem.setStatusTip(QCoreApplication.translate("GdalTools", "Tool to analyze and visualize DEMs")) self.dem.triggered.connect(self.doDEM) self.analysisMenu.addAction(self.dem) #self.analysisMenu.addActions( [ ] ) # miscellaneous menu (Build overviews (Pyramids), Tile index, Information, Merge, Build Virtual Raster (Catalog)) self.miscellaneousMenu = QMenu(QCoreApplication.translate("GdalTools", "Miscellaneous"), self.iface.mainWindow()) self.miscellaneousMenu.setObjectName("miscellaneousMenu") if self.GdalVersionNum >= 1600: self.buildVRT = QAction(QIcon(":/icons/vrt.png"), QCoreApplication.translate("GdalTools", "Build Virtual Raster (Catalog)..."), self.iface.mainWindow()) self.buildVRT.setObjectName("buildVRT") self.buildVRT.setStatusTip(QCoreApplication.translate("GdalTools", "Builds a VRT from a list of datasets")) self.buildVRT.triggered.connect(self.doBuildVRT) self.miscellaneousMenu.addAction(self.buildVRT) self.merge = QAction(QIcon(":/icons/merge.png"), QCoreApplication.translate("GdalTools", "Merge..."), self.iface.mainWindow()) self.merge.setObjectName("merge") self.merge.setStatusTip(QCoreApplication.translate("GdalTools", "Build a quick mosaic from a set of images")) self.merge.triggered.connect(self.doMerge) self.info = QAction(QIcon(":/icons/raster-info.png"), QCoreApplication.translate("GdalTools", "Information..."), self.iface.mainWindow()) self.info.setObjectName("info") self.info.setStatusTip(QCoreApplication.translate("GdalTools", "Lists information about raster dataset")) self.info.triggered.connect(self.doInfo) self.overview = QAction(QIcon(":icons/raster-overview.png"), QCoreApplication.translate("GdalTools", "Build Overviews (Pyramids)..."), self.iface.mainWindow()) self.overview.setObjectName("overview") self.overview.setStatusTip(QCoreApplication.translate("GdalTools", "Builds or rebuilds overview images")) self.overview.triggered.connect(self.doOverview) self.tileindex = QAction(QIcon(":icons/tiles.png"), QCoreApplication.translate("GdalTools", "Tile Index..."), self.iface.mainWindow()) self.tileindex.setObjectName("tileindex") self.tileindex.setStatusTip(QCoreApplication.translate("GdalTools", "Build a shapefile as a raster tileindex")) self.tileindex.triggered.connect(self.doTileIndex) self.miscellaneousMenu.addActions([self.merge, self.info, self.overview, self.tileindex]) self._menuActions.append(self.menu.addMenu(self.projectionsMenu)) self._menuActions.append(self.menu.addMenu(self.conversionMenu)) self._menuActions.append(self.menu.addMenu(self.extractionMenu)) if not self.analysisMenu.isEmpty(): self._menuActions.append(self.menu.addMenu(self.analysisMenu)) self._menuActions.append(self.menu.addMenu(self.miscellaneousMenu)) self.settings = QAction(QCoreApplication.translate("GdalTools", "GdalTools Settings..."), self.iface.mainWindow()) self.settings.setObjectName("settings") self.settings.setStatusTip(QCoreApplication.translate("GdalTools", "Various settings for Gdal Tools")) self.settings.triggered.connect(self.doSettings) self.menu.addAction(self.settings) self._menuActions.append(self.settings) def unload(self): if not valid: return for a in self._menuActions: self.menu.removeAction(a) def doBuildVRT(self): from .tools.doBuildVRT import GdalToolsDialog as BuildVRT d = BuildVRT(self.iface) self.runToolDialog(d) def doContour(self): from .tools.doContour import GdalToolsDialog as Contour d = Contour(self.iface) self.runToolDialog(d) def doRasterize(self): from .tools.doRasterize import GdalToolsDialog as Rasterize d = Rasterize(self.iface) self.runToolDialog(d) def doPolygonize(self): from .tools.doPolygonize import GdalToolsDialog as Polygonize d = Polygonize(self.iface) self.runToolDialog(d) def doMerge(self): from .tools.doMerge import GdalToolsDialog as Merge d = Merge(self.iface) self.runToolDialog(d) def doSieve(self): from .tools.doSieve import GdalToolsDialog as Sieve d = Sieve(self.iface) self.runToolDialog(d) def doProximity(self): from .tools.doProximity import GdalToolsDialog as Proximity d = Proximity(self.iface) self.runToolDialog(d) def doNearBlack(self): from .tools.doNearBlack import GdalToolsDialog as NearBlack d = NearBlack(self.iface) self.runToolDialog(d) def doFillNodata(self): from .tools.doFillNodata import GdalToolsDialog as FillNodata d = FillNodata(self.iface) self.runToolDialog(d) def doWarp(self): from .tools.doWarp import GdalToolsDialog as Warp d = Warp(self.iface) self.runToolDialog(d) def doGrid(self): from .tools.doGrid import GdalToolsDialog as Grid d = Grid(self.iface) self.runToolDialog(d) def doTranslate(self): from .tools.doTranslate import GdalToolsDialog as Translate d = Translate(self.iface) self.runToolDialog(d) def doInfo(self): from .tools.doInfo import GdalToolsDialog as Info d = Info(self.iface) self.runToolDialog(d) def doProjection(self): from .tools.doProjection import GdalToolsDialog as Projection d = Projection(self.iface) self.runToolDialog(d) def doOverview(self): from .tools.doOverview import GdalToolsDialog as Overview d = Overview(self.iface) self.runToolDialog(d) def doClipper(self): from .tools.doClipper import GdalToolsDialog as Clipper d = Clipper(self.iface) self.runToolDialog(d) def doPaletted(self): from .tools.doRgbPct import GdalToolsDialog as RgbPct d = RgbPct(self.iface) self.runToolDialog(d) def doRGB(self): from .tools.doPctRgb import GdalToolsDialog as PctRgb d = PctRgb(self.iface) self.runToolDialog(d) def doTileIndex(self): from .tools.doTileIndex import GdalToolsDialog as TileIndex d = TileIndex(self.iface) self.runToolDialog(d) def doExtractProj(self): from .tools.doExtractProj import GdalToolsDialog as ExtractProj d = ExtractProj(self.iface) d.exec_() def doDEM(self): from .tools.doDEM import GdalToolsDialog as DEM d = DEM(self.iface) self.runToolDialog(d) def runToolDialog(self, dlg): dlg.show_() dlg.exec_() del dlg def doSettings(self): from .tools.doSettings import GdalToolsSettingsDialog as Settings d = Settings(self.iface) d.exec_()
class PostNAS_Search: def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir,'i18n','PostNAS_Search_{}.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) # Create the dialog (after translation) and keep reference self.dlg = PostNAS_SearchDialog(iface=self.iface) self.conf = PostNAS_ConfDialog(iface=self.iface) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&PostNAS_Search') self.searchDockWidget = None self.searchDockWidgetArea = Qt.LeftDockWidgetArea # noinspection PyMethodMayBeStatic def tr(self, message): # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('PostNAS_Search', message) def initGui(self): # Create Conf-Action and Menuentry self.confAction = QAction("Einstellungen", self.iface.mainWindow()) self.confAction.setWhatsThis("Konfiguration der PostNAS-Suche") self.confAction.setStatusTip("Konfiguration der PostNAS-Suche") self.confAction.triggered.connect(self.showConf) if hasattr(self.iface, "addPluginToDatabaseMenu"): self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.confAction) else: self.iface.addPluginToMenu("&PostNAS-Suche", self.confAction) self.toggleSearchAction = QAction(u"Flurstücksuche", self.iface.mainWindow()) self.toggleSearchAction.setWhatsThis(u"Starten/Schliessen der Flurstücksuche") self.toggleSearchAction.setStatusTip(u"Starten/Schliessen der Flurstücksuche") self.toggleSearchAction.triggered.connect(self.toggleWidget) if hasattr(self.iface, "addPluginToDatabaseMenu"): self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.toggleSearchAction) else: self.iface.addPluginToMenu("&PostNAS-Suche", self.toggleSearchAction) self.fulltextindex = QAction(u"Volltextindex erstellen", self.iface.mainWindow()) self.fulltextindex.setWhatsThis(u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen") self.fulltextindex.setStatusTip(u"Erzeugt einen Volltextindex in der Datenbank um die Suche zu beschleunigen") self.fulltextindex.triggered.connect(self.createFulltextindex) if hasattr(self.iface, "addPluginToDatabaseMenu"): self.iface.addPluginToDatabaseMenu("&PostNAS-Suche", self.fulltextindex) else: self.iface.addPluginToMenu("&PostNAS-Suche", self.fulltextindex) # Create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/PostNAS_Search/search_24x24.png"),u"Flurstücksuche", self.iface.mainWindow()) self.action.setCheckable(True) # connect the action to the run method self.action.triggered.connect(self.toggleWidget) # Add toolbar button and menu item self.iface.addToolBarIcon(self.action) def toggleWidget(self, event): if self.searchDockWidget == None: self.searchDockWidget = QDockWidget(self.iface.mainWindow()) self.searchDockWidget.setWindowTitle(self.tr(u'Suche')) self.searchDockWidget.setWidget(self.dlg) self.searchDockWidget.closeEvent = self.toggleWidget self.iface.addDockWidget(self.searchDockWidgetArea, self.searchDockWidget) self.action.setChecked(True) else: self.searchDockWidgetArea = self.iface.mainWindow().dockWidgetArea(self.searchDockWidget) self.iface.removeDockWidget(self.searchDockWidget) self.searchDockWidget = None self.action.setChecked(False) def showConf(self): dlg = PostNAS_ConfDialog(self) dlg.exec_() def createFulltextindex(self): dlg = PostNAS_CreateFulltextindex(self) dlg.exec_() def unload(self): # Remove the Toolbar Icon self.iface.removeToolBarIcon(self.action) # Remove DockWidget if self.searchDockWidget != None: self.iface.removeDockWidget(self.searchDockWidget) if hasattr(self.iface, "removePluginDatabaseMenu"): self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.confAction) self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.toggleSearchAction) self.iface.removePluginDatabaseMenu("&PostNAS-Suche", self.fulltextindex) else: self.iface.removePluginMenu("&PostNAS-Suche", self.confAction) self.iface.removePluginMenu("&PostNAS-Suche", self.toggleSearchAction) self.iface.removePluginMenu("&PostNAS-Suche", self.fulltextindex) if self.confAction: self.confAction.deleteLater() self.confAction = None if self.toggleSearchAction: self.toggleSearchAction.deleteLater() self.toggleSearchAction = None if self.fulltextindex: self.fulltextindex.deleteLater() self.fulltextindex = None
class QgisMapBiomasAPI: """Plugin implementation """ def __init__(self, iface): """ Constructor Args: iface (qgis.gui.QgisInterface): a reference to the QGIS GUI interface """ self.iface = iface self.plugin_dir = os.path.dirname(__file__) self.locale = QSettings().value('locale/userLocale')[0:2] self.dockwidget = None self.action = None self.name = 'MapBiomas API' self.about = 'MapBiomas API for QGIS' self.token = None self.biome = None self.state = None # initialize locale locale_path = os.path.join( self.plugin_dir, 'i18n', '{}_{}.qm'.format('mapbiomas-api', self.locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) def tr(self, msg): return QCoreApplication.translate("QgisMapBiomasAPI", msg) def initProcessing(self): self.provider = Provider() QgsApplication.processingRegistry().addProvider(self.provider) def initGui(self): """ This method is called by QGIS when the main GUI starts up or when the plugin is enabled in the Plugin Manager. Only want to register the menu items and toolbar buttons here, and connects action with run method. """ self.initProcessing() icon = QIcon(os.path.join(self.plugin_dir, 'icon.png')) self.action = QAction(icon, self.name, self.iface.mainWindow()) self.action.setWhatsThis(self.about) self.action.setStatusTip(self.about) self.action.setCheckable(True) self.action.triggered.connect(self.run) # for plugin menu/toolbar self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu(self.name, self.action) def unload(self): """ Will be executed when the plugin is disabled. Either in the Plugin Manager or when QGIS shuts down. It removes the previously defined QAction object from the menu and remove the plugin icon from the toolbar. """ # for plugin menu/toolbar self.iface.removeToolBarIcon(self.action) self.iface.removePluginMenu(self.name, self.action) if self.dockwidget is not None: # disconnect triggers here self.dockwidget.pushButton.clicked.disconnect(self.do_something) self.dockwidget.checkBoxStartDetected.toggled[bool].disconnect( self.dockwidget.startDetectedAt.setEnabled) self.dockwidget.checkBoxEndDetected.toggled[bool].disconnect( self.dockwidget.endDetectedAt.setEnabled) self.dockwidget.checkBoxStartPublished.toggled[bool].disconnect( self.dockwidget.startPublishedAt.setEnabled) self.dockwidget.checkBoxEndPublished.toggled[bool].disconnect( self.dockwidget.endPublishedAt.setEnabled) self.dockwidget.close() self.dockwidget.visibilityChanged.disconnect( self.visibility_changed) self.iface.removeDockWidget(self.dockwidget) del self.dockwidget # remove processing provider QgsApplication.processingRegistry().removeProvider(self.provider) def run(self): """ Executes the custom plugin functionality. This method is called by the previously defined QAction object (callback), which went into the toolbar icon and the menu entry. """ if self.dockwidget is None: self.dockwidget = DockMapBiomasApi() self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget) self.dockwidget.visibilityChanged.connect(self.visibility_changed) self.init() self.dockwidget.show() else: if self.dockwidget.isVisible(): self.dockwidget.hide() else: self.dockwidget.show() def visibility_changed(self, change): """ Change icon checked status with dockwidget visibility """ self.action.setChecked(change) def info(self, msg, level=Qgis.Info, duration=5): """ docstring """ self.iface.messageBar().pushMessage(msg, level, duration) def log(self, msg, level=Qgis.Info): """ docstring """ QgsMessageLog.logMessage(msg, self.name, level) def sign_in(self): """ Creation of an access token in the JWT standard to be used in the Authorization header and populate BIOME and STATE if empty """ err = None email = self.dockwidget.email.text() password = self.dockwidget.password.text() if password and email: try: self.token, err = MapbiomasApi.token({ "email": email, "password": password }) except Exception as e: err = str(e) if self.token is not None: if self.biome is None: self.biome, err = territories.get(self.token, {"category": "BIOME"}) if self.state is None: self.state, err = territories.get(self.token, {"category": "STATE"}) else: err = self.tr('Email and password are required.') return err def get_alerts(self): filters = {} territories = [] if self.dockwidget.BIOME.count: territories.extend( [self.biome[k] for k in self.dockwidget.BIOME.checkedItems()]) if self.dockwidget.STATE.count: territories.extend( [self.state[k] for k in self.dockwidget.STATE.checkedItems()]) if territories: filters["territoryIds"] = territories if self.dockwidget.checkBoxStartDetected.isChecked(): filters["startDetectedAt"] = self.dockwidget.startDetectedAt.date( ).toString('yyyy-MM-dd') if self.dockwidget.checkBoxEndDetected.isChecked(): filters["endDetectedAt"] = self.dockwidget.endDetectedAt.date( ).toString('yyyy-MM-dd') if self.dockwidget.checkBoxStartPublished.isChecked(): filters[ "startPublishedAt"] = self.dockwidget.startPublishedAt.date( ).toString('yyyy-MM-dd') if self.dockwidget.checkBoxEndPublished.isChecked(): filters["endPublishedAt"] = self.dockwidget.endPublishedAt.date( ).toString('yyyy-MM-dd') try: data, err = publishedAlerts.get(self.token, filters) except Exception as e: err = str(e) if err is None: with NamedTemporaryFile("w+t", prefix=self.tr("alerts_"), suffix=".geojson", delete=False) as outfile: json.dump(data, outfile) fn = outfile.name if not "territoryIds" in filters and (len(data["features"]) == publishedAlerts.LIMIT): self.info( self.tr('The number of alerts was limited to {}').format( publishedAlerts.LIMIT)) # add vector layer layer = QgsVectorLayer(fn, 'MapBiomasAPI', 'ogr') if layer.isValid(): locale_style = os.path.join( self.plugin_dir, 'i18n', 'mapbiomas-api_{}.qml'.format(self.locale)) if os.path.exists(locale_style): layer.loadNamedStyle(locale_style) else: layer.loadNamedStyle( os.path.join(self.plugin_dir, 'mapbiomas-api.qml')) QgsProject.instance().addMapLayer(layer) else: self.log("Invalid layer file: {}".format(fn)) self.info( self.tr("Unknown error. Invalid layer. Try it again."), level=Qgis.Critical) elif err == 'Você não tem permissão para realizar esta ação': self.dockwidget.pushButton.setText(self.tr('SIGN IN')) self.dockwidget.options.setDisabled(True) self.dockwidget.mGroupBox.setCollapsed(False) self.info(self.tr("The session has expired. Sign in again."), level=Qgis.Critical) else: self.info(err, level=Qgis.Critical) def do_something(self): """Sign in or get alerts """ if self.dockwidget.pushButton.text() == self.tr('SIGN IN'): err = self.sign_in() if err is None: self.dockwidget.BIOME.addItems(self.biome.keys()) self.dockwidget.STATE.addItems(self.state.keys()) self.dockwidget.pushButton.setText(self.tr('GET ALERTS')) self.dockwidget.options.setEnabled(True) self.dockwidget.mGroupBox.setCollapsed(True) else: self.info(err, level=Qgis.Critical) else: self.get_alerts() def init(self): """ Fill options, default values and connect triggers of the dockwidget """ # connect triggers self.dockwidget.pushButton.clicked.connect(self.do_something) self.dockwidget.checkBoxStartDetected.toggled[bool].connect( self.dockwidget.startDetectedAt.setEnabled) self.dockwidget.checkBoxEndDetected.toggled[bool].connect( self.dockwidget.endDetectedAt.setEnabled) self.dockwidget.checkBoxStartPublished.toggled[bool].connect( self.dockwidget.startPublishedAt.setEnabled) self.dockwidget.checkBoxEndPublished.toggled[bool].connect( self.dockwidget.endPublishedAt.setEnabled) # set defaults self.dockwidget.endDetectedAt.setDate(QDate.currentDate()) self.dockwidget.endPublishedAt.setDate(QDate.currentDate())
class MetaSearchPlugin(object): """base plugin""" def __init__(self, iface): """init""" self.iface = iface self.context = StaticContext() self.action_run = None self.action_help = None self.dialog = None self.web_menu = '&MetaSearch' def initGui(self): """startup""" # run run_icon = QIcon('%s/%s' % (self.context.ppath, 'images/MetaSearch.png')) self.action_run = QAction(run_icon, 'MetaSearch', self.iface.mainWindow()) self.action_run.setWhatsThis(QCoreApplication.translate('MetaSearch', 'MetaSearch plugin')) self.action_run.setStatusTip(QCoreApplication.translate('MetaSearch', 'Search Metadata Catalogs')) self.action_run.triggered.connect(self.run) self.iface.addWebToolBarIcon(self.action_run) self.iface.addPluginToWebMenu(self.web_menu, self.action_run) # help help_icon = QgsApplication.getThemeIcon('/mActionHelpContents.svg') self.action_help = QAction(help_icon, 'Help', self.iface.mainWindow()) self.action_help.setWhatsThis(QCoreApplication.translate('MetaSearch', 'MetaSearch plugin help')) self.action_help.setStatusTip(QCoreApplication.translate('MetaSearch', 'Get Help on MetaSearch')) self.action_help.triggered.connect(self.help) self.iface.addPluginToWebMenu(self.web_menu, self.action_help) # prefab the dialog but not open it yet self.dialog = MetaSearchDialog(self.iface) def unload(self): """teardown""" # remove the plugin menu item and icon self.iface.removePluginWebMenu(self.web_menu, self.action_run) self.iface.removePluginWebMenu(self.web_menu, self.action_help) self.iface.removeWebToolBarIcon(self.action_run) def run(self): """open MetaSearch""" self.dialog.exec_() def help(self): """open help in user's default web browser""" open_url(get_help_url())
class QRAVE: """QGIS Plugin Implementation.""" 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 self.tm = QgsApplication.taskManager() self.qproject = QgsProject.instance() self.pluginIsActive = False self.dockwidget = None self.metawidget = None # Populated on load from a URL self.acknowledgements = None # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'QRAVE_{}.qm'.format(locale)) self.settings = Settings(iface=self.iface) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) QCoreApplication.installTranslator(self.translator) # Declare instance attributes self.actions = [] self.menu = self.tr(u'&Riverscapes Plugin (QRAVE)') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'QRAVE') self.toolbar.setObjectName(u'QRAVE') def tr(self, message): """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('QRAVE', message) def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" self.qproject.readProject.connect(self.onProjectLoad) self.openAction = QAction( QIcon(':/plugins/qrave_toolbar/RaveAddIn_16px.png'), self.tr(u'Riverscapes Plugin (QRAVE)'), self.iface.mainWindow()) self.openAction.triggered.connect(self.toggle_widget) self.openAction.setStatusTip('Toggle the project viewer') self.openAction.setWhatsThis('Toggle the project viewer') self.openProjectAction = QAction( QIcon(':/plugins/qrave_toolbar/OpenProject.png'), self.tr(u'Open Riverscapes Project'), self.iface.mainWindow()) self.openProjectAction.triggered.connect(self.projectBrowserDlg) self.openProjectAction.setStatusTip('Open QRAVE project') self.openProjectAction.setWhatsThis('Open QRAVE project') self.helpButton = QToolButton() self.helpButton.setToolButtonStyle(Qt.ToolButtonTextOnly) self.helpButton.setMenu(QMenu()) self.helpButton.setPopupMode(QToolButton.MenuButtonPopup) m = self.helpButton.menu() # TODO: get the local help working # self.helpAction = QAction( # QIcon(':/plugins/qrave_toolbar/Help.png'), # self.tr('Help'), # self.iface.mainWindow() # ) # self.helpAction.triggered.connect(partial(showPluginHelp, None, filename=':/plugins/qrave_toolbar/help/build/html/index')) # self.websiteAction = QAction( # QIcon(':/plugins/qrave_toolbar/RaveAddIn_16px.png'), # self.tr('Website'), # self.iface.mainWindow() # ) # self.websiteAction.triggered.connect(lambda: QDesktopServices.openUrl(QUrl("http://rave.riverscapes.xyz"))) self.helpAction = QAction(QIcon(':/plugins/qrave_toolbar/Help.png'), self.tr('Help'), self.iface.mainWindow()) self.helpAction.triggered.connect(lambda: QDesktopServices.openUrl( QUrl("http://rave.riverscapes.xyz"))) self.raveOptionsAction = QAction( QIcon(':/plugins/qrave_toolbar/Options.png'), self.tr('Settings'), self.iface.mainWindow()) self.raveOptionsAction.triggered.connect(self.options_load) self.net_sync_action = QAction( QIcon(':/plugins/qrave_toolbar/refresh.png'), self.tr('Update resources'), self.iface.mainWindow()) self.net_sync_action.triggered.connect( lambda: self.net_sync_load(force=True)) self.find_resources_action = QAction( QIcon(':/plugins/qrave_toolbar/BrowseFolder.png'), self.tr('Find Resources folder'), self.iface.mainWindow()) self.find_resources_action.triggered.connect(self.locateResources) self.about_action = QAction( QIcon(':/plugins/qrave_toolbar/RaveAddIn_16px.png'), self.tr('About QRAVE'), self.iface.mainWindow()) self.about_action.triggered.connect(self.about_load) m.addAction(self.helpAction) # m.addAction(self.websiteAction) m.addAction(self.raveOptionsAction) m.addAction(self.net_sync_action) m.addSeparator() m.addAction(self.find_resources_action) m.addAction(self.about_action) self.helpButton.setDefaultAction(self.helpAction) self.toolbar.addAction(self.openAction) self.toolbar.addAction(self.openProjectAction) self.toolbar.addWidget(self.helpButton) # Do a check to see if the stored version is different than the current version lastVersion = self.settings.getValue('pluginVersion') # This does a lazy netsync (i.e. it will run it if it feels like it) versionChange = lastVersion != __version__ self.net_sync_load(force=versionChange) if versionChange: QgsMessageLog.logMessage( "Version change detected: {} ==> {}".format( lastVersion, __version__), 'QRAVE', level=Qgis.Info) self.settings.setValue('pluginVersion', __version__) def onProjectLoad(self, doc): # If the project has the plugin enabled then restore it. qrave_enabled, type_conversion_ok = self.qproject.readEntry( CONSTANTS['settingsCategory'], 'enabled') if type_conversion_ok and qrave_enabled == '1': self.toggle_widget(forceOn=True) if self.dockwidget is not None: self.dockwidget.reload_tree() def onClosePlugin(self): """Cleanup necessary items here when plugin dockwidget is closed""" if self.metawidget is not None: self.metawidget.hide() if self.dockwidget is not None: self.dockwidget.hide() # disconnects self.dockwidget.closingPlugin.disconnect(self.onClosePlugin) self.qproject.readProject.disconnect(self.onProjectLoad) # remove this statement if dockwidget is to remain # for reuse if plugin is reopened self.dockwidget = None self.pluginIsActive = False def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" if self.metawidget is not None: self.metawidget.hide() if self.dockwidget is not None: self.dockwidget.hide() for action in self.actions: self.iface.removePluginMenu( self.tr(u'&Riverscapes Plugin (QRAVE)'), action) self.iface.removeToolBarIcon(action) # remove the toolbar del self.toolbar def toggle_widget(self, forceOn=False): """Toggle the widget open and closed when clicking the toolbar""" if not self.pluginIsActive: self.pluginIsActive = True # dockwidget may not exist if: # first run of plugin # removed on close (see self.onClosePlugin method) if self.dockwidget is None: # Create the dockwidget (after translation) and keep reference self.dockwidget = QRAVEDockWidget() self.metawidget = QRAVEMetaWidget() # Hook metadata changes up to the metawidget self.dockwidget.metaChange.connect(self.metawidget.load) # Run a network sync operation to get the latest stuff. Don't force it. # This is just a quick check self.net_sync_load() # connect to provide cleanup on closing of dockwidget self.dockwidget.closingPlugin.connect(self.onClosePlugin) # show the dockwidget self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.dockwidget) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.metawidget) self.dockwidget.show() else: if self.dockwidget is not None: if self.dockwidget.isHidden(): self.dockwidget.show() elif forceOn is False: self.dockwidget.hide() # The metawidget always starts hidden if self.metawidget is not None: self.metawidget.hide() if self.dockwidget is not None and not self.dockwidget.isHidden(): self.qproject.writeEntry(CONSTANTS['settingsCategory'], 'enabled', True) else: self.qproject.removeEntry(CONSTANTS['settingsCategory'], 'enabled') def net_sync_load(self, force=False): """ Periodically check for new files """ lastDigestSync = self.settings.getValue('lastDigestSync') lastVersion = self.settings.getValue('pluginVersion') currTime = int(time()) # timestamp in seconds plugin_init = self.settings.getValue('initialized') autoUpdate = self.settings.getValue('autoUpdate') self.netsync = NetSync('Sync QRAVE resource files') perform_sync = False # setting the force flag overrides everything else if force: perform_sync = True # Otherwise you only get a sync if 'autoUpdate' is turned on elif autoUpdate: # If this is an old version or the plugin is uninitialized if not plugin_init or lastVersion != __version__ or self.netsync.need_sync: perform_sync = True # If we haven't checked for more than `digestSyncFreqHours` hours elif isinstance(lastDigestSync, int) \ and ((currTime - lastDigestSync) / 3600) > CONSTANTS['digestSyncFreqHours']: perform_sync = True if perform_sync is False: self.netsync = None return # Trigger the dockwidget to repaint after the netsync if self.dockwidget is not None: self.netsync.taskCompleted.connect(self.dockwidget.reload_tree) # FOR DEBUGGING ONLY. NEVER IN PRODUCTION # self.netsync.run() # COMMENT THIS OUT AND USE THE LINE ABOVE FOR SYNCHRONOUS DEBUGGING self.tm.addTask(self.netsync) def projectBrowserDlg(self): """ Browse for a project directory :return: """ last_browse_path = self.settings.getValue('lastBrowsePath') last_dir = os.path.dirname( last_browse_path) if last_browse_path is not None else None dialog_return = QFileDialog.getOpenFileName( self.dockwidget, "Open a Riverscapes project", last_dir, self.tr("Riverscapes Project files (project.rs.xml)")) if dialog_return is not None and dialog_return[ 0] != "" and os.path.isfile(dialog_return[0]): # We set the proect path in the project settings. This way it will be saved with the QgsProject file if self.dockwidget is None or self.dockwidget.isHidden() is True: self.toggle_widget(forceOn=True) self.dockwidget.add_project(dialog_return[0]) def locateResources(self): """This the OS-agnostic "show in Finder" or "show in explorer" equivalent It should open the folder of the item in question Args: fpath (str): [description] """ qurl = QUrl.fromLocalFile(RESOURCES_DIR) QDesktopServices.openUrl(qurl) def options_load(self): """ Open the options/settings dialog """ dialog = OptionsDialog() if self.dockwidget: dialog.dataChange.connect(self.dockwidget.dataChange) dialog.exec_() def about_load(self): """ Open the About dialog """ dialog = AboutDialog() if self.acknowledgements is None: self.acknowledgements = requests.get( 'http://rave.riverscapes.xyz/dotnetack.html').text dialog.acknowledgements.setText(self.acknowledgements) dialog.exec_()