Source code for ooodev.calc.cell.custom_prop_clean

from __future__ import annotations
from typing import Any, Dict, List, cast, Set, TYPE_CHECKING
import contextlib

from com.sun.star.drawing import XControlShape
from com.sun.star.uno import RuntimeException

from ooodev.io.log import logging as logger
from ooodev.calc.cell.custom_prop_base import CustomPropBase

if TYPE_CHECKING:
    from ooodev.calc.calc_sheet import CalcSheet


[docs]class CustomPropClean(CustomPropBase):
[docs] def __init__(self, sheet: CalcSheet): CustomPropBase.__init__(self, sheet) self._sheet = sheet
def _get_shapes_artifact_dict(self) -> Dict[str, Dict[str, List[XControlShape]]]: comp = self.draw_page.component shapes = { "prop_shapes": {}, "artifacts": {}, } # find all shapes on the draw page that start with prefix and end with suffix for shape in comp: # type: ignore if not shape.supportsService("com.sun.star.drawing.ControlShape"): continue name = cast(str, shape.Name) if name.startswith(self._shape_prefix): if name.endswith(self._shape_suffix): if name in shapes["prop_shapes"]: shapes["prop_shapes"][name].append(shape) else: shapes["prop_shapes"][name] = [shape] else: if name in shapes["artifacts"]: shapes["artifacts"][name].append(shape) else: shapes["artifacts"][name] = [shape] return shapes def _is_cell_deleted(self, cell: Any) -> bool: try: _ = cell.AbsoluteName except RuntimeException: return True return False def _has_hidden_control(self, shape: XControlShape) -> bool: ctl = self._get_hidden_control_simple(self._get_hidden_control_name_from_shape(shape)) return ctl is not None def _clean_duplicate_shapes(self, shapes: List[XControlShape]) -> List[XControlShape]: # remove any duplicates named shapes if len(shapes) < 2: return shapes shapes.sort(key=lambda x: x.ZOrder) # type: ignore for shape in shapes[1:]: with contextlib.suppress(Exception): logger.debug(f"Removing duplicate shape {shape.Name}") # type: ignore self.draw_page.remove(shape) shapes = shapes[:1] return shapes def _get_all_hidden_controls(self) -> Set[str]: # get all hidden controls on the draw page hidden_controls = set() form = self._get_form() for control in form: # type: ignore if control.supportsService("com.sun.star.form.component.HiddenControl"): hidden_controls.add(control.Name) return hidden_controls def _remove_hidden_controls(self, hidden_controls: Set[str]) -> None: # remove any hidden controls that are not associated with a shape. form = self._get_form() for control_name in hidden_controls: if form.hasByName(control_name): logger.debug(f"Removing hidden control {control_name}") # type: ignore form.removeByName(control_name)
[docs] def clean(self): # clean up any artifacts such a name like '_cprop_idofhsvtcky1hgom_id 1' # remove any duplicates named shapes # remove any shapes that have a cell anchor that is deleted. all_shapes = self._get_shapes_artifact_dict() for shapes in all_shapes["artifacts"].values(): for shape in shapes: with contextlib.suppress(Exception): logger.debug(f"Removing artifact shape {shape.Name}") # type: ignore self.draw_page.remove(shape) prop_shapes = all_shapes["prop_shapes"] # each shape should have a corresponding anchor that is a cell. for shape_name, shapes in prop_shapes.items(): single_shapes = self._clean_duplicate_shapes(shapes) if not single_shapes: continue # should only have one shape at this point if len(single_shapes) > 1: logger.error( f"{self.__class__.__name__} - More than one shape found for {shape_name}. Unable to clean." ) continue # make sure the single_shape cell has not been deleted. shape = single_shapes[0] anchor = shape.Anchor # type: ignore if anchor is None: with contextlib.suppress(Exception): logger.debug(f"Removing shape {shape.Name} because anchor is None") # type: ignore self.draw_page.remove(shape) continue if self._is_cell_deleted(anchor): with contextlib.suppress(Exception): logger.debug(f"Removing shape {shape.Name} because cell is deleted") # type: ignore self.draw_page.remove(shape) current_hidden_controls = self._get_all_hidden_controls() keep_hidden_controls = set() all_shapes = self._get_shapes_artifact_dict() prop_shapes = all_shapes["prop_shapes"] for _, shape in prop_shapes.items(): keep_hidden_controls.add(self._get_hidden_control_name_from_shape(shape[0])) removed_ids = current_hidden_controls - keep_hidden_controls if removed_ids: self._remove_hidden_controls(removed_ids)