diff --git a/qtribu/__about__.py b/qtribu/__about__.py index cdfceae7..1cc8ab48 100644 --- a/qtribu/__about__.py +++ b/qtribu/__about__.py @@ -16,7 +16,7 @@ # ############################################################################ # ########## Globals ############### # ################################## -__all__ = [ +__all__: list = [ "__author__", "__copyright__", "__email__", @@ -28,8 +28,8 @@ ] -DIR_PLUGIN_ROOT = Path(__file__).parent -PLG_METADATA_FILE = DIR_PLUGIN_ROOT.resolve() / "metadata.txt" +DIR_PLUGIN_ROOT: Path = Path(__file__).parent +PLG_METADATA_FILE: Path = DIR_PLUGIN_ROOT.resolve() / "metadata.txt" # ############################################################################ @@ -57,31 +57,33 @@ def plugin_metadata_as_dict() -> dict: # ################################## # store full metadata.txt as dict into a var -__plugin_md__ = plugin_metadata_as_dict() +__plugin_md__: dict = plugin_metadata_as_dict() -__author__ = __plugin_md__.get("general").get("author") -__copyright__ = "2021 - {0}, {1}".format(date.today().year, __author__) -__email__ = __plugin_md__.get("general").get("email") -__icon_path__ = DIR_PLUGIN_ROOT.resolve() / __plugin_md__.get("general").get("icon") -__keywords__ = [ +__author__: str = __plugin_md__.get("general").get("author") +__copyright__: str = "2021 - {0}, {1}".format(date.today().year, __author__) +__email__: str = __plugin_md__.get("general").get("email") +__icon_path__: Path = DIR_PLUGIN_ROOT.resolve() / __plugin_md__.get("general").get( + "icon" +) +__keywords__: list = [ t.strip() for t in __plugin_md__.get("general").get("repository").split("tags") ] -__license__ = "MIT" -__summary__ = "{}\n{}".format( +__license__: str = "MIT" +__summary__: str = "{}\n{}".format( __plugin_md__.get("general").get("description"), __plugin_md__.get("general").get("about"), ) -__title__ = __plugin_md__.get("general").get("name") -__title_clean__ = "".join(e for e in __title__ if e.isalnum()) +__title__: str = __plugin_md__.get("general").get("name") +__title_clean__: str = "".join(e for e in __title__ if e.isalnum()) -__uri_homepage__ = __plugin_md__.get("general").get("homepage") -__uri_repository__ = __plugin_md__.get("general").get("repository") -__uri_tracker__ = __plugin_md__.get("general").get("tracker") -__uri__ = __uri_repository__ +__uri_homepage__: str = __plugin_md__.get("general").get("homepage") +__uri_repository__: str = __plugin_md__.get("general").get("repository") +__uri_tracker__: str = __plugin_md__.get("general").get("tracker") +__uri__: str = __uri_repository__ -__version__ = __plugin_md__.get("general").get("version") -__version_info__ = tuple( +__version__: str = __plugin_md__.get("general").get("version") +__version_info__: tuple = tuple( [ int(num) if num.isdigit() else num for num in __version__.replace("-", ".", 1).split(".") diff --git a/qtribu/logic/__init__.py b/qtribu/logic/__init__.py index 51ea86e4..a7d4d40a 100644 --- a/qtribu/logic/__init__.py +++ b/qtribu/logic/__init__.py @@ -1,5 +1,6 @@ #! python3 # noqa: E265 from .custom_datatypes import RssItem # noqa: F401 +from .eastereggs_manager import PlgEasterEggs # noqa: F401 from .rss_reader import RssMiniReader # noqa: F401 from .splash_changer import SplashChanger # noqa: F401 from .web_viewer import WebViewer # noqa: F401 diff --git a/qtribu/logic/eastereggs/__init__.py b/qtribu/logic/eastereggs/__init__.py new file mode 100644 index 00000000..17899934 --- /dev/null +++ b/qtribu/logic/eastereggs/__init__.py @@ -0,0 +1,2 @@ +#! python3 # noqa: E265 +from .egg_tribu import EggGeotribu # noqa: F401 diff --git a/qtribu/logic/eastereggs/egg_tribu.py b/qtribu/logic/eastereggs/egg_tribu.py new file mode 100644 index 00000000..818f4b1e --- /dev/null +++ b/qtribu/logic/eastereggs/egg_tribu.py @@ -0,0 +1,101 @@ +#! python3 # noqa: E265 + +""" + Easter egg on widget Coordinates. +""" + +# ############################################################################ +# ########## Imports ############### +# ################################## + +# Standard library +import logging + +# PyQGIS +from qgis.core import QgsProject, QgsProjectMetadata +from qgis.PyQt.QtCore import QCoreApplication +from qgis.PyQt.QtGui import QIcon +from qgis.utils import iface + +# project +from qtribu.__about__ import __icon_path__ +from qtribu.toolbelt import PlgLogger + +# ############################################################################ +# ########## Globals ############### +# ################################## + +logger = logging.getLogger(__name__) + + +# ############################################################################ +# ########## Classes ############### +# ################################## + + +class EggGeotribu(object): + + APPLIED: bool = False + KEYWORDS: tuple = ("geotribu",) + NAME: str = "Geotribu" + PRIORITY: int = 1 + + def __init__(self): + """Instancitation logic.""" + self.log = PlgLogger().log + + def apply(self) -> bool: + self.log( + message=self.tr(f"Easter egg found: {self.NAME}"), + log_level=4, + ) + + # QGIS main window + self.bkp_title = iface.mainWindow().windowTitle() + # new_title = self.bkp_title.replace("QGIS", "GIStribu") + iface.mainWindow().setWindowTitle("GISTribu") + iface.mainWindow().setWindowIcon(QIcon(str(__icon_path__.resolve()))) + iface.pluginToolBar().setVisible(False) + + # modify menus + iface.editMenu().setTitle("Créer") + iface.helpMenu().setTitle("Débrouille toi !") + iface.helpMenu().setEnabled(False) + + # Project + current_project = QgsProject.instance() + self.bkp_project = {"title": current_project.title()} + current_project.setTitle(f"Easter Egg {self.NAME}") + try: + self.bkp_project["metadata"] = current_project.Metadata() + except AttributeError as err: + self.log( + message="Project doesn't exist yet. Trace: {}".format(err), + log_level=4, + ) + self.bkp_project["metadata"] = None + gt_md = QgsProjectMetadata() + gt_md.setAuthor("Geotribu") + gt_md.setLanguage("FRE") + current_project.setMetadata(gt_md) + + self.APPLIED = True + return True + + def revert(self) -> bool: + iface.mainWindow().setWindowTitle(self.bkp_title) + iface.pluginToolBar().setVisible(True) + + self.APPLIED = False + return False + + def tr(self, message: str) -> str: + """Translation method. + + :param message: text to be translated + :type message: str + + :return: translated text + :rtype: str + """ + return QCoreApplication.translate(self.__class__.__name__, message) diff --git a/qtribu/logic/eastereggs_manager.py b/qtribu/logic/eastereggs_manager.py new file mode 100644 index 00000000..1eed12ce --- /dev/null +++ b/qtribu/logic/eastereggs_manager.py @@ -0,0 +1,127 @@ +#! python3 # noqa: E265 + +""" + Easter egg on widget Coordinates. +""" + +# ############################################################################ +# ########## Imports ############### +# ################################## + +# Standard library +import logging + +# PyQGIS +from qgis.core import QgsApplication, QgsProject, QgsProjectMetadata +from qgis.PyQt.QtCore import QCoreApplication +from qgis.PyQt.QtGui import QIcon +from qgis.PyQt.QtWidgets import QApplication, QLineEdit, QMessageBox +from qgis.utils import iface + +# project +from qtribu.logic.eastereggs.egg_tribu import EggGeotribu +from qtribu.toolbelt import PlgLogger +from qtribu.toolbelt.preferences import PlgOptionsManager + +# ############################################################################ +# ########## Globals ############### +# ################################## + +logger = logging.getLogger(__name__) + + +# ############################################################################ +# ########## Classes ############### +# ################################## + + +class PlgEasterEggs: + + CONNECTION_ENABLED: bool = False + EGG_TROLL_APPLIED: bool = False + + def __init__(self, parent): + """Instancitation logic.""" + self.log = PlgLogger().log + self.parent = parent + + # -- Easter eggs --------------------------------------------------------------- + self.eggs: tuple = (EggGeotribu(),) + + # on attrape la barre de statut de QGIS + qgis_st = iface.mainWindow().statusBar() + + # on filtre la barre de statut pour ne garder le widget des coordonnées + for wdgt in qgis_st.children()[1].children(): + if wdgt.objectName() == "mCoordsEdit": + break + + # dans le widget, on ne garde que la ligne de saisie + self.le_coords = wdgt.findChild(QLineEdit) + + def switch(self): + if self.CONNECTION_ENABLED: + self.parent.action_eastereggs.setIcon( + QIcon(QgsApplication.iconPath("repositoryConnected.svg")), + ) + self.le_coords.editingFinished.disconnect(self.on_coords_changed) + self.CONNECTION_ENABLED = False + PlgOptionsManager.set_value_from_key(key="easter_eggs_enabled", value=False) + self.log(message="Easter eggs connection has been disabled.") + else: + self.parent.action_eastereggs.setIcon( + QIcon(QgsApplication.iconPath("repositoryUnavailable.svg")), + ) + self.le_coords.editingFinished.connect(self.on_coords_changed) + self.CONNECTION_ENABLED = True + PlgOptionsManager.set_value_from_key(key="easter_eggs_enabled", value=True) + self.log(message="Easter eggs connection has been enabled.") + + for egg in self.eggs: + if egg.APPLIED: + egg.revert() + + def on_coords_changed(self): + for egg in self.eggs: + if not egg.APPLIED and self.le_coords.text() in egg.KEYWORDS: + self.le_coords.setEchoMode(QLineEdit.EchoMode.PasswordEchoOnEdit) + egg.apply() + break + + # -- Easter eggs ------------------------------------------------------------------- + def egg_coords_arcgis(self): + """Easter egg to mimic the behavior of ArcGIS Pro license subscription.""" + if not self.EGG_TROLL_APPLIED: + app = QApplication.instance() + app.setStyleSheet(".QWidget {color: green; background-color: blue;}") + self.log( + message="Easter egg found! Let's ask end-user for his QGIS license subscription." + ) + + # message box + msg = QMessageBox() + msg.setIcon(QMessageBox.Critical) + msg.setWindowTitle("QGIS Pro") + msg.setInformativeText( + "Your account is not licensed for QGIS Pro. " + "Please ask your organization administrator to assign you a user type " + "that is compatible with QGIS Pro (e.g. Creator) along with an add-on " + "QGIS Pro license, or a user type that includes QGIS Pro " + "(e.g. GIS Professional)." + ) + msg.exec_() + + self.EGG_TROLL_APPLIED = True + else: + self.EGG_TROLL_APPLIED = False + + def tr(self, message: str) -> str: + """Translation method. + + :param message: text to be translated + :type message: str + + :return: translated text + :rtype: str + """ + return QCoreApplication.translate(self.__class__.__name__, message) diff --git a/qtribu/plugin_main.py b/qtribu/plugin_main.py index 5cb74ec0..b41c1df8 100644 --- a/qtribu/plugin_main.py +++ b/qtribu/plugin_main.py @@ -18,7 +18,7 @@ # project from qtribu.__about__ import DIR_PLUGIN_ROOT, __icon_path__, __title__ from qtribu.gui.dlg_settings import PlgOptionsFactory -from qtribu.logic import RssMiniReader, SplashChanger, WebViewer +from qtribu.logic import PlgEasterEggs, RssMiniReader, SplashChanger, WebViewer from qtribu.toolbelt import ( NetworkRequestsManager, PlgLogger, @@ -50,6 +50,7 @@ def __init__(self, iface: QgisInterface): self.tr = plg_translation_mngr.tr # sub-modules + self.easter_eggs = PlgEasterEggs(self) self.rss_rdr = RssMiniReader() self.splash_chgr = SplashChanger(self) self.web_viewer = WebViewer() @@ -72,6 +73,13 @@ def initGui(self): ) self.action_run.triggered.connect(self.run) + self.action_eastereggs = QAction( + QIcon(QgsApplication.iconPath("repositoryConnected.svg")), + self.tr("Enable/disable easter eggs"), + self.iface.mainWindow(), + ) + self.action_eastereggs.triggered.connect(self.easter_eggs.switch) + self.action_help = QAction( QIcon(QgsApplication.iconPath("mActionHelpContents.svg")), self.tr("Help", context="GeotribuPlugin"), @@ -82,7 +90,7 @@ def initGui(self): ) self.action_settings = QAction( - QgsApplication.getThemeIcon("console/iconSettingsConsole.svg"), + QIcon(QgsApplication.iconPath("console/iconSettingsConsole.svg")), self.tr("Settings"), self.iface.mainWindow(), ) @@ -97,6 +105,7 @@ def initGui(self): # -- Menu self.iface.addPluginToWebMenu(__title__, self.action_run) + self.iface.addPluginToWebMenu(__title__, self.action_eastereggs) self.iface.addPluginToWebMenu(__title__, self.action_splash) self.iface.addPluginToWebMenu(__title__, self.action_settings) self.iface.addPluginToWebMenu(__title__, self.action_help) @@ -148,7 +157,12 @@ def initGui(self): def unload(self): """Cleans up when plugin is disabled/uninstalled.""" + # -- Specific clean up + if self.easter_eggs.CONNECTION_ENABLED: + self.easter_eggs.switch() + # -- Clean up menu + self.iface.removePluginWebMenu(__title__, self.action_eastereggs) self.iface.removePluginWebMenu(__title__, self.action_help) self.iface.removePluginWebMenu(__title__, self.action_run) self.iface.removePluginWebMenu(__title__, self.action_settings) diff --git a/qtribu/toolbelt/preferences.py b/qtribu/toolbelt/preferences.py index c6ea010e..2a8dab57 100644 --- a/qtribu/toolbelt/preferences.py +++ b/qtribu/toolbelt/preferences.py @@ -35,6 +35,7 @@ class PlgSettingsStructure(NamedTuple): notify_push_duration: int = 10 latest_content_guid: str = None splash_screen_enabled: bool = False + easter_eggs_enabled: bool = False # network network_http_user_agent: str = f"{__title__}/{__version__}" @@ -97,6 +98,11 @@ def get_plg_settings() -> PlgSettingsStructure: defaultValue=False, type=bool, ), + easter_eggs_enabled=settings.value( + key="easter_eggs_enabled", + defaultValue=False, + type=bool, + ), # network network_http_user_agent=settings.value( key="network_http_user_agent",