Skip to content

Commit

Permalink
Merge pull request #18 from Samweli/time_slider
Browse files Browse the repository at this point in the history
Time slider implementation
  • Loading branch information
Samweli committed Jul 16, 2024
2 parents e387449 + 5bc5a54 commit 7739d3a
Show file tree
Hide file tree
Showing 15 changed files with 661 additions and 82 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ jobs:
fail-fast: false
matrix:
qgis_version_tag:
- release-3_16
- release-3_26
- release-3_30
- release-3_34
- release-3_36
os: [ubuntu-22.04]
Expand Down
62 changes: 49 additions & 13 deletions admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

import os
import sys

import configparser
import datetime as dt
Expand Down Expand Up @@ -61,6 +62,20 @@ def main(context: typer.Context, verbose: bool = False, qgis_profile: str = "def
}


def _qgis_profile_path() -> str:
"""Returns the path segment to QGIS profiles folder based on the platform.
:returns: Correct path segment corresponding to the current platform.
:rtype: str
"""
if sys.platform == "win32":
app_data_dir = "AppData/Roaming"
else:
app_data_dir = ".local/share"

return f"{app_data_dir}/QGIS/QGIS3/profiles/"


@app.command()
def install(context: typer.Context, build_src: bool = True):
"""Deploys plugin to QGIS plugins directory
Expand All @@ -80,8 +95,7 @@ def install(context: typer.Context, build_src: bool = True):
)

root_directory = (
Path.home() / f".local/share/QGIS/QGIS3/profiles/"
f"{context.obj['qgis_profile']}"
Path.home() / f"{_qgis_profile_path()}{context.obj['qgis_profile']}"
)

base_target_directory = root_directory / "python/plugins" / SRC_NAME
Expand All @@ -104,8 +118,7 @@ def symlink(context: typer.Context):
build_path = LOCAL_ROOT_DIR / "build" / SRC_NAME

root_directory = (
Path.home() / f".local/share/QGIS/QGIS3/profiles/"
f"{context.obj['qgis_profile']}"
Path.home() / f"{_qgis_profile_path()}{context.obj['qgis_profile']}"
)

destination_path = root_directory / "python/plugins" / SRC_NAME
Expand All @@ -124,8 +137,7 @@ def uninstall(context: typer.Context):
:type context: typer.Context
"""
root_directory = (
Path.home() / f".local/share/QGIS/QGIS3/profiles/"
f"{context.obj['qgis_profile']}"
Path.home() / f"{_qgis_profile_path()}{context.obj['qgis_profile']}"
)
base_target_directory = root_directory / "python/plugins" / SRC_NAME
shutil.rmtree(str(base_target_directory), ignore_errors=True)
Expand All @@ -136,6 +148,7 @@ def uninstall(context: typer.Context):
def generate_zip(
context: typer.Context,
version: str = None,
file_name: str = None,
output_directory: typing.Optional[Path] = LOCAL_ROOT_DIR / "dist",
):
"""Generates plugin zip folder, that can be used to installed the
Expand All @@ -147,14 +160,20 @@ def generate_zip(
:param version: Plugin version
:type version: str
:param file_name: Plugin zip file name
:type file_name: str
:param output_directory: Directory where the zip folder will be saved.
:type context: Path
"""
build_dir = build(context)
metadata = _get_metadata()
plugin_version = metadata["version"] if version is None else version
output_directory.mkdir(parents=True, exist_ok=True)
zip_path = output_directory / f"{SRC_NAME}.{plugin_version}.zip"
zip_file_name = (
f"{SRC_NAME}.{plugin_version}.zip" if file_name is None else file_name
)
zip_path = output_directory / f"{zip_file_name}"
with zipfile.ZipFile(zip_path, "w") as fh:
_add_to_zip(build_dir, fh, arc_path_base=build_dir.parent)
typer.echo(
Expand Down Expand Up @@ -190,7 +209,7 @@ def build(
:returns: Build directory path.
:rtype: Path
"""
if clean:
if clean and output_directory.exists():
shutil.rmtree(str(output_directory), ignore_errors=True)
output_directory.mkdir(parents=True, exist_ok=True)
copy_source_files(output_directory, tests=tests)
Expand All @@ -201,7 +220,6 @@ def build(
generate_metadata(context, output_directory)
return output_directory


@app.command()
def copy_icon(
output_directory: typing.Optional[Path] = LOCAL_ROOT_DIR / "build/temp",
Expand Down Expand Up @@ -247,14 +265,26 @@ def copy_source_files(
for child in (LOCAL_ROOT_DIR / "src" / SRC_NAME).iterdir():
if child.name != "__pycache__":
target_path = output_directory / child.name
handler = shutil.copytree if child.is_dir() else shutil.copy
handler(str(child.resolve()), str(target_path))
if child.is_dir():
shutil.copytree(
str(child.resolve()),
str(target_path),
ignore=shutil.ignore_patterns("*.pyc", "__pycache*"),
)
else:
shutil.copy(str(child.resolve()), str(target_path))
if tests:
for child in LOCAL_ROOT_DIR.iterdir():
if child.name in TEST_FILES:
target_path = output_directory / child.name
handler = shutil.copytree if child.is_dir() else shutil.copy
handler(str(child.resolve()), str(target_path))
if child.is_dir():
shutil.copytree(
str(child.resolve()),
str(target_path),
ignore=shutil.ignore_patterns("*.pyc", "__pycache*"),
)
else:
shutil.copy(str(child.resolve()), str(target_path))


@app.command()
Expand All @@ -273,6 +303,12 @@ def compile_resources(
resources_path = LOCAL_ROOT_DIR / "resources" / "resources.qrc"
target_path = output_directory / "resources.py"
target_path.parent.mkdir(parents=True, exist_ok=True)

# Windows handling of paths for shlex.split function
if sys.platform == "win32":
target_path = target_path.as_posix()
resources_path = resources_path.as_posix()

_log(f"compile_resources target_path: {target_path}", context=context)
subprocess.run(shlex.split(f"pyrcc5 -o {target_path} {resources_path}"))

Expand Down
2 changes: 1 addition & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
"author": "Kartoza",
"email": "[email protected]",
"description": "View, browse and navigate through imagery.",
"version": "0.0.1",
"version": "0.0.11dev",
"changelog": ""
}
}
4 changes: 3 additions & 1 deletion run-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ QGIS_IMAGE=qgis/qgis
QGIS_IMAGE_latest=latest
QGIS_IMAGE_V_3_26=release-3_26

QGIS_VERSION_TAGS=($QGIS_IMAGE_latest $QGIS_IMAGE_V_3_26)
QGIS_VERSION_TAGS=($QGIS_IMAGE_V_3_26)

export IMAGE=$QGIS_IMAGE

python admin.py build --tests

for TAG in "${QGIS_VERSION_TAGS[@]}"
do
echo "Running tests for QGIS $TAG"
Expand Down
8 changes: 4 additions & 4 deletions scripts/docker/qgis-gea-plugin-test-pre-scripts.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

qgis_setup.sh

# FIX default installation because the sources must be in "qgis-gea-plugin" parent folder
rm -rf /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/qgis-gea-plugin
ln -sf /tests_directory /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/qgis-gea-plugin
ln -sf /tests_directory /usr/share/qgis/python/plugins/qgis-gea-plugin
# FIX default installation because the sources must be in "qgis_gea_plugin" parent folder
rm -rf /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/qgis_gea_plugin
ln -sf /tests_directory /root/.local/share/QGIS/QGIS3/profiles/default/python/plugins/qgis_gea_plugin
ln -sf /tests_directory /usr/share/qgis/python/plugins/qgis_gea_plugin
128 changes: 128 additions & 0 deletions src/qgis_gea_plugin/conf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# -*- coding: utf-8 -*-
"""
Handles storage and retrieval of the plugin QgsSettings.
"""

import contextlib
import dataclasses
import datetime
import enum
import json
import os.path
import uuid
from pathlib import Path

from qgis.PyQt import QtCore
from qgis.core import QgsSettings

from .utils import log


@contextlib.contextmanager
def qgis_settings(group_root: str, settings=None):
"""Context manager to help defining groups when creating QgsSettings.
:param group_root: Name of the root group for the settings
:type group_root: str
:param settings: QGIS settings to use
:type settings: QgsSettings
:yields: Instance of the created settings
:ytype: QgsSettings
"""
if settings is None:
settings = QgsSettings()
settings.beginGroup(group_root)
try:
yield settings
finally:
settings.endGroup()


class Settings(enum.Enum):
"""Plugin settings names"""

HISTORICAL_VIEW = "historical"
NICFI_VIEW = "nicfi"


class SettingsManager(QtCore.QObject):
"""Manages saving/loading settings for the plugin in QgsSettings."""

BASE_GROUP_NAME: str = "qgis_gea_plugin"

settings = QgsSettings()

scenarios_settings_updated = QtCore.pyqtSignal()
priority_layers_changed = QtCore.pyqtSignal()
settings_updated = QtCore.pyqtSignal([str, object], [Settings, object])

def set_value(self, name: str, value):
"""Adds a new setting key and value on the plugin specific settings.
:param name: Name of setting key
:type name: str
:param value: Value of the setting
:type value: Any
"""
self.settings.setValue(f"{self.BASE_GROUP_NAME}/{name}", value)
if isinstance(name, Settings):
name = name.value

self.settings_updated.emit(name, value)

def get_value(self, name: str, default=None, setting_type=None):
"""Gets value of the setting with the passed name.
:param name: Name of setting key
:type name: str
:param default: Default value returned when the setting key does not exist
:type default: Any
:param setting_type: Type of the store setting
:type setting_type: Any
:returns: Value of the setting
:rtype: Any
"""
if setting_type:
return self.settings.value(
f"{self.BASE_GROUP_NAME}/{name}", default, setting_type
)
return self.settings.value(f"{self.BASE_GROUP_NAME}/{name}", default)

def find_settings(self, name):
"""Returns the plugin setting keys from the
plugin root group that matches the passed name
:param name: Setting name to search for
:type name: str
:returns result: List of the matching settings names
:rtype result: list
"""

result = []
with qgis_settings(f"{self.BASE_GROUP_NAME}") as settings:
for settings_name in settings.childKeys():
if name in settings_name:
result.append(settings_name)
return result

def remove(self, name):
"""Remove the setting with the specified name.
:param name: Name of the setting key
:type name: str
"""
self.settings.remove(f"{self.BASE_GROUP_NAME}/{name}")

def delete_settings(self):
"""Deletes the all the plugin settings."""
self.settings.remove(f"{self.BASE_GROUP_NAME}")


settings_manager = SettingsManager()
9 changes: 9 additions & 0 deletions src/qgis_gea_plugin/definitions/defaults.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
"""
Definitions for all defaults settings
"""

PLUGIN_ICON = ":/plugins/qgis_gea_plugin/icon.png"

ANIMATION_PLAY_ICON = ":/images/themes/default/mActionPlay.svg"
ANIMATION_PAUSE_ICON = ":/images/themes/default/temporal_navigation/pause.svg"
Loading

0 comments on commit 7739d3a

Please sign in to comment.