Skip to content

Commit

Permalink
fix(project read): must check if layer is available in qgs project be…
Browse files Browse the repository at this point in the history
…fore use

- check if layer is available in qgs
- if no layer available, don't add layer to project
- add some checks on returned object to avoid failure
  • Loading branch information
jmkerloch committed Nov 28, 2024
1 parent 9dc3b68 commit 797ef44
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 84 deletions.
6 changes: 4 additions & 2 deletions menu_from_project/logic/layer_load.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ def addLayer(
node = getFirstChildByTagNameValue(
doc.documentElement(), "maplayer", "id", layerId
)
node = node.cloneNode()
if node:
node = node.cloneNode()
idNode = node.namedItem("id")
layerType = node.toElement().attribute("type", "vector")
# give it a new id (for multiple import)
Expand Down Expand Up @@ -173,7 +173,7 @@ def addLayer(
return newLayer, relationsToBuild

else:
self.log("{} not found".format(layerId), indent=loop)
self.log("Layer {} not found. Can't add layer to QGIS.".format(layerId), indent=loop)

return None, None

Expand Down Expand Up @@ -285,6 +285,8 @@ def fixForm(
layerNode = getFirstChildByTagNameValue(
doc.documentElement(), "maplayer", "id", oldLayerId
)
if not layerNode:
self.log("{} not found for form relation fix".format(oldLayerId))

nodes = layerNode.toElement().elementsByTagName("attributeEditorForm")
if nodes.count() == 0:
Expand Down
161 changes: 85 additions & 76 deletions menu_from_project/logic/project_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from pathlib import Path
from typing import Dict, Optional, Tuple

from qgis.core import QgsMapLayerType, QgsMessageLog, QgsWkbTypes

# PyQGIS
from qgis.core import QgsMapLayerType, QgsMessageLog, QgsWkbTypes
from qgis.PyQt import QtXml
from qgis.PyQt.QtCore import QFileInfo

Expand Down Expand Up @@ -148,7 +148,7 @@ def get_layer_menu_config(
qgs_dom_manager: QgsDomManager,
init_filename: str,
absolute_project: bool,
) -> MenuLayerConfig:
) -> Optional[MenuLayerConfig]:
"""Get layer menu configuration from a xml node
:param node: xml node
Expand All @@ -163,7 +163,7 @@ def get_layer_menu_config(
:param absolute_project: True if project is absolute, False otherwise
:type absolute_project: bool
:return: layer menu configuration
:rtype: MenuLayerConfig
:rtype: Optional[MenuLayerConfig]
"""

embedded, filename = read_embedded_properties(
Expand All @@ -175,40 +175,43 @@ def get_layer_menu_config(

if embedded:
ml = qgs_dom_manager.getMapLayerDomFromQgs(filename, layer_id)
else:
elif layer_id in maplayer_dict:
ml = maplayer_dict[layer_id]
else:
ml = None

if ml:
# Metadata infos
md = ml.namedItem("resourceMetadata")
metadata_title = md.namedItem("title").firstChild().toText().data()
metadata_abstract = md.namedItem("abstract").firstChild().toText().data()

# Layer info
title = ml.namedItem("title").firstChild().toText().data()
abstract = ml.namedItem("abstract").firstChild().toText().data()

# Layer notes
layer_notes = ""
elt_note = ml.namedItem("userNotes")
if elt_note.toElement().hasAttribute("value"):
layer_notes = elt_note.toElement().attribute("value")

# Geometry and layer type
ml_elem = ml.toElement()
geometry_type_str = ml_elem.attribute("geometry")
if geometry_type_str == "":
# A TMS has not a geometry attribute.
# Let's read the "type"
geometry_type_str = ml_elem.attribute("type")
layer_type, geometry_type, is_spatial = get_layer_type_from_geometry_str(
geometry_type_str
if not ml:
QgsMessageLog.logMessage(
f"Menu from layer: Can't find layer {layer_id} in qgs project. Layer won't be added to project.",
__title__,
notifyUser=True,
)
else:
metadata_abstract, metadata_title, title, abstract, layer_notes = ""
layer_type = None
geometry_type = None
is_spatial = False
return None
# Metadata infos
md = ml.namedItem("resourceMetadata")
metadata_title = md.namedItem("title").firstChild().toText().data()
metadata_abstract = md.namedItem("abstract").firstChild().toText().data()

# Layer info
title = ml.namedItem("title").firstChild().toText().data()
abstract = ml.namedItem("abstract").firstChild().toText().data()

# Layer notes
layer_notes = ""
elt_note = ml.namedItem("userNotes")
if elt_note.toElement().hasAttribute("value"):
layer_notes = elt_note.toElement().attribute("value")

# Geometry and layer type
ml_elem = ml.toElement()
geometry_type_str = ml_elem.attribute("geometry")
if geometry_type_str == "":
# A TMS has not a geometry attribute.
# Let's read the "type"
geometry_type_str = ml_elem.attribute("type")
layer_type, geometry_type, is_spatial = get_layer_type_from_geometry_str(
geometry_type_str
)

return MenuLayerConfig(
name=element.attribute("name"),
Expand Down Expand Up @@ -324,15 +327,15 @@ def get_group_menu_config(
)
)
elif child.nodeName() == "layer-tree-layer":
childs.append(
get_layer_menu_config(
node=child,
maplayer_dict=maplayer_dict,
qgs_dom_manager=qgs_dom_manager,
init_filename=init_filename,
absolute_project=absolute_project,
)
layer_config = get_layer_menu_config(
node=child,
maplayer_dict=maplayer_dict,
qgs_dom_manager=qgs_dom_manager,
init_filename=init_filename,
absolute_project=absolute_project,
)
if layer_config:
childs.append(layer_config)

return MenuGroupConfig(
name=name, embedded=embedded, filename=filename, childs=childs
Expand All @@ -352,39 +355,45 @@ def get_project_menu_config(
:return: Optional menu project configuration
:rtype: Optional[MenuProjectConfig]
"""
try:
# Get path to QgsProject file, local / downloaded / from postgres database
uri = project.file
qgs_dom_manager.set_project(project)
doc, filename = qgs_dom_manager.getQgsDoc(uri)

# Define project name
name = project.name
if name == "":
name = get_project_title(doc)
if name == "":
name = Path(filename).stem

# Get layer tree root
layer_tree_roots = doc.elementsByTagName("layer-tree-group")
if layer_tree_roots.length() > 0:
if node := layer_tree_roots.item(0):
# Create dict of maplayer nodes
maplayer_dict = create_map_layer_dict(doc)
# Parse node for group and layers
menu_project_config = MenuProjectConfig(
project_name=name,
filename=filename,
uri=uri,
root_group=get_group_menu_config(
node=node,
maplayer_dict=maplayer_dict,
qgs_dom_manager=qgs_dom_manager,
init_filename=filename,
absolute_project=is_absolute(doc),
),
)

# Get path to QgsProject file, local / downloaded / from postgres database
uri = project.file
qgs_dom_manager.set_project(project)
doc, filename = qgs_dom_manager.getQgsDoc(uri)

# Define project name
name = project.name
if name == "":
name = get_project_title(doc)
if name == "":
name = Path(filename).stem

# Get layer tree root
layer_tree_roots = doc.elementsByTagName("layer-tree-group")
if layer_tree_roots.length() > 0:
if node := layer_tree_roots.item(0):
# Create dict of maplayer nodes
maplayer_dict = create_map_layer_dict(doc)
# Parse node for group and layers
menu_project_config = MenuProjectConfig(
project_name=name,
filename=filename,
uri=uri,
root_group=get_group_menu_config(
node=node,
maplayer_dict=maplayer_dict,
qgs_dom_manager=qgs_dom_manager,
init_filename=filename,
absolute_project=is_absolute(doc),
),
)

qgs_dom_manager.set_project(None)
return menu_project_config
qgs_dom_manager.set_project(None)
return menu_project_config
except Exception as e:
QgsMessageLog.logMessage(
f"Menu from layer: Can't parse qgs project for {project.name} : {e}",
__title__,
notifyUser=True,
)
return None
2 changes: 1 addition & 1 deletion menu_from_project/logic/qgs_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,7 @@ def getQgsDoc(self, uri: str) -> Tuple[QtXml.QDomDocument, str]:

return doc, project_path

def getMapLayerDomFromQgs(self, fileName: str, layerId: str) -> QtXml.QDomNode:
def getMapLayerDomFromQgs(self, fileName: str, layerId: str) -> Optional[QtXml.QDomNode]:
"""Return the maplayer node in a project filepath given a maplayer ID.
:param fileName: The project filepath on the filesystem.
Expand Down
5 changes: 4 additions & 1 deletion menu_from_project/logic/xml_utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@

from typing import Optional

# PyQGIS
from qgis.PyQt.QtXml import QDomNode

Expand All @@ -17,7 +20,7 @@ def getFirstChildByAttrValue(elt, tagName, key, value):
return None


def getFirstChildByTagNameValue(elt, tagName, key, value):
def getFirstChildByTagNameValue(elt, tagName, key, value) -> Optional[QDomNode]:
nodes = elt.elementsByTagName(tagName)
for node in (nodes.at(i) for i in range(nodes.size())):
nd = node.namedItem(key)
Expand Down
15 changes: 11 additions & 4 deletions menu_from_project/menu_from_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,17 @@ def load_all_project_config(
if not project_config:
# Create project menu configuration from QgsProject
project_config = get_project_menu_config(project, self.qgs_dom_manager)
# Save in cache
cache_manager.save_project_menu_config(project, project_config)

result.append((project, project_config))
if project_config:
# Save in cache
cache_manager.save_project_menu_config(project, project_config)
if project_config:
result.append((project, project_config))
else:
self.log(
self.tr(
f"Can't define project configuration for project {project.name}"
)
)
return result

def project_config_loaded(
Expand Down

0 comments on commit 797ef44

Please sign in to comment.