# region imports
from __future__ import annotations
import contextlib
from typing import Any, cast, TYPE_CHECKING
import unohelper
from com.sun.star.uno import XInterface
from com.sun.star.beans import XPropertySet
from com.sun.star.awt import PosSize
from ooodev.events.args.generic_args import GenericArgs
from ooodev.adapter.awt.focus_events import FocusEvents
from ooodev.adapter.awt.key_events import KeyEvents
from ooodev.adapter.awt.mouse_events import MouseEvents
from ooodev.adapter.awt.mouse_motion_events import MouseMotionEvents
from ooodev.adapter.awt.paint_events import PaintEvents
from ooodev.adapter.awt.window_events import WindowEvents
from ooodev.adapter.beans.properties_change_implement import PropertiesChangeImplement
from ooodev.adapter.beans.property_change_implement import PropertyChangeImplement
from ooodev.adapter.beans.vetoable_change_implement import VetoableChangeImplement
from ooodev.events.args.listener_event_args import ListenerEventArgs
from ooodev.loader import lo as mLo
from ooodev.utils.kind.dialog_control_kind import DialogControlKind
from ooodev.utils.kind.dialog_control_named_kind import DialogControlNamedKind
from ooodev.utils.partial.lo_inst_props_partial import LoInstPropsPartial
from ooodev.events.partial.events_partial import EventsPartial
from ooodev.utils.partial.model_prop_partial import ModelPropPartial
from ooodev.utils.partial.view_prop_partial import ViewPropPartial
from ooodev.adapter.awt.uno_control_dialog_element_partial import UnoControlDialogElementPartial
from ooodev.units.unit_px import UnitPX
from ooodev.units.unit_app_font_height import UnitAppFontHeight
from ooodev.units.unit_app_font_width import UnitAppFontWidth
from ooodev.units.unit_app_font_x import UnitAppFontX
from ooodev.units.unit_app_font_y import UnitAppFontY
from ooodev.utils.kind.point_size_kind import PointSizeKind
from ooodev.utils.builder.default_builder import DefaultBuilder
if TYPE_CHECKING:
from com.sun.star.awt import XControlModel
from com.sun.star.awt import XControl
from com.sun.star.awt import UnoControlDialogElement # service
from com.sun.star.beans import XMultiPropertySet
from com.sun.star.awt import XWindowPeer
from com.sun.star.awt import XWindow
from ooodev.proto.style_obj import StyleT
from ooodev.units.unit_obj import UnitT
# endregion imports
# pylint: disable=unused-argument
# Model Position and Size are in AppFont units. View Size and Position are in Pixel units.
[docs]class CtlBase(unohelper.Base, LoInstPropsPartial, ViewPropPartial, ModelPropPartial, EventsPartial):
"""Control Base Class"""
def __new__(cls, ctl: Any, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
# region Dunder Methods
[docs] def __init__(self, ctl: Any) -> None:
unohelper.Base.__init__(self)
LoInstPropsPartial.__init__(self, lo_inst=mLo.Lo.current_lo)
EventsPartial.__init__(self)
model = ctl.getModel()
ViewPropPartial.__init__(self, obj=ctl)
ModelPropPartial.__init__(self, obj=model)
self._set_control(ctl)
def _set_control(self, ctl: Any) -> None:
self._ctl_view = ctl
# endregion Dunder Methods
# region other methods
def _get_generic_args(self) -> GenericArgs:
try:
return self.__generic_args
except AttributeError:
self.__generic_args = GenericArgs(control_src=self)
return self.__generic_args
[docs] def get_view(self) -> XControl:
return self._ctl_view
get_view_ctl = get_view
[docs] def get_uno_srv_name(self) -> str:
"""Get Uno service name"""
raise NotImplementedError
[docs] def get_control_props(self) -> XPropertySet | None:
"""
Gets property set for a control model
Args:
control_model (Any): control model
Returns:
XPropertySet | None: Property set
"""
try:
return mLo.Lo.qi(XPropertySet, self.get_model())
except Exception:
return None
# endregion other methods
# region Other Methods
[docs] def get_model(self) -> XControlModel:
"""Gets the Model for the control"""
return self.get_view().getModel()
# endregion Other Methods
# region Properties
@property
def visible(self) -> bool:
"""Gets/Sets the visible state for the control"""
try:
model = cast(Any, self.get_view().getModel())
return model.EnableVisible
except Exception:
return True
@visible.setter
def visible(self, value: bool) -> None:
with contextlib.suppress(Exception):
model = cast(Any, self.get_model())
model.EnableVisible = value
# endregion Properties
# region Control Listener Base
class _UnoControlDialogElementOverrides:
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
def __init__(self, ctl: Any):
"""
Constructor
"""
self.__model = cast("UnoControlDialogElement", ctl.getModel())
# region UnoControlDialogElementPartial Overrides
@property
def width(self) -> UnitPX:
"""Gets the width of the control"""
model = self.__model
return UnitPX.from_app_font(model.Width, PointSizeKind.WIDTH)
# view = mLo.Lo.qi(XView, self.get_view(), True)
# return UnitPX(view.getSize().Width)
@width.setter
def width(self, value: int | UnitT) -> None:
"""
Gets/Sets the width of the control in Pixel units.
When setting can be an integer in ``Pixels`` Units or a ``UnitT``.
Returns:
UnitPX: Width of the control.
Note:
The Width is in Pixel units; however, the model is in AppFont units.
This property will convert the AppFont units to Pixel units.
When set using ``UnitAppFontWidth`` no conversion is done.
"""
model = self.__model
if isinstance(value, UnitAppFontWidth):
model.Width = int(value)
return
val = UnitPX.from_unit_val(value)
model.Width = round(val.get_value_app_font(PointSizeKind.WIDTH))
@property
def height(self) -> UnitPX:
"""
Gets/Sets the height of the control in Pixel units.
When setting can be an integer in ``Pixels`` Units or a ``UnitT``.
Returns:
UnitPX: Height of the control.
Note:
The Height is in Pixel units; however, the model is in AppFont units.
This property will convert the AppFont units to Pixel units.
When set using ``UnitAppFontHeight`` no conversion is done.
"""
model = self.__model
return UnitPX.from_app_font(model.Height, PointSizeKind.HEIGHT)
@height.setter
def height(self, value: int | UnitT) -> None:
model = self.__model
if isinstance(value, UnitAppFontHeight):
model.Height = int(value)
return
val = UnitPX.from_unit_val(value)
model.Height = round(val.get_value_app_font(PointSizeKind.HEIGHT))
# endregion UnoControlDialogElementPartial Overrides
[docs]class CtlListenerBase(
CtlBase,
# UnoControlDialogElementPartial,
# _UnoControlDialogElementOverrides,
FocusEvents,
KeyEvents,
MouseEvents,
MouseMotionEvents,
PaintEvents,
WindowEvents,
PropertyChangeImplement,
PropertiesChangeImplement,
VetoableChangeImplement,
):
"""
Class for managing table ConfigurationProvider Component.
Note:
This is a Dynamic class that is created at runtime.
This means that the class is created at runtime and not defined in the source code.
In addition, the class may be created with additional classes implemented.
The Type hints for this class at design time may not be accurate.
To check if a class implements a specific interface, use the ``isinstance`` function
or :py:meth:`~.InterfacePartial.is_supported_interface` methods which is always available in this class.
"""
# pylint: disable=unused-argument
def __new__(cls, *args, **kwargs):
# Because the Dialog class also inherits this class the extra check for ctl is needed.
ctl = kwargs.get("ctl", None)
if ctl is None:
try:
ctl = args[0]
except IndexError:
ctl = None
if ctl is None:
return super().__new__(cls, *args, **kwargs)
builder = _get_control_listener_builder(ctl)
clz = builder.get_class_type(
name="ooodev.dialog.dl_control.ctl_base.CtlListenerBase", base_class=cls, set_mod_name=False
)
return super().__new__(clz, *args, **kwargs)
# region Dunder Methods
[docs] def __init__(self, ctl: Any) -> None:
CtlBase.__init__(self, ctl)
if isinstance(self, UnoControlDialogElementPartial):
UnoControlDialogElementPartial.__init__(self, self.get_model()) # type: ignore
_UnoControlDialogElementOverrides.__init__(self, ctl) # type: ignore
generic_args = self._get_generic_args() # type: ignore
# The Events callback methods are invoked when any event is added or removed.
FocusEvents.__init__(self, trigger_args=generic_args, cb=self._on_focus_listener_add_remove)
KeyEvents.__init__(self, trigger_args=generic_args, cb=self._on_key_events_listener_add_remove)
MouseEvents.__init__(self, trigger_args=generic_args, cb=self._on_mouse_listener_add_remove)
MouseMotionEvents.__init__(self, trigger_args=generic_args, cb=self._on_mouse_motion_listener_add_remove)
PaintEvents.__init__(self, trigger_args=generic_args, cb=self._on_paint_listener_add_remove)
WindowEvents.__init__(self, trigger_args=generic_args, cb=self._on_window_event_listener_add_remove)
model = self.get_model() # type: ignore
PropertyChangeImplement.__init__(self, component=cast(XPropertySet, model), trigger_args=generic_args)
PropertiesChangeImplement.__init__(self, component=cast("XMultiPropertySet", model), trigger_args=generic_args)
VetoableChangeImplement.__init__(self, component=cast(XPropertySet, model), trigger_args=generic_args)
# endregion Dunder Methods
# region UnoControlDialogElementPartial properties
if TYPE_CHECKING:
# The properties from this point are optional. The builder will add them if needed.
# There are include here for type hinting only.
@property
def height(self) -> UnitPX:
"""
Gets/Sets the height of the control in Pixel units.
When setting can be an integer in ``Pixels`` Units or a ``UnitT``.
Returns:
UnitPX: Height of the control.
Note:
The Height is in Pixel units; however, the model is in AppFont units.
This property will convert the AppFont units to Pixel units.
When set using ``UnitAppFontHeight`` no conversion is done.
"""
...
@height.setter
def height(self, value: int | UnitT) -> None: ...
@property
def name(self) -> str:
"""
Gets/Sets the name of the control.
"""
...
@name.setter
def name(self, value: str) -> None: ...
@property
def x(self) -> UnitAppFontX:
"""
Gets/Sets the horizontal position of the control.
When setting can be an integer in ``AppFont`` Units or a ``UnitT``.
Returns:
UnitAppFontX: Horizontal position of the control.
"""
...
@x.setter
def x(self, value: int | UnitT) -> None: ...
@property
def y(self) -> UnitAppFontY:
"""
Gets/Sets the vertical position of the control.
When setting can be an integer in ``AppFont`` Units or a ``UnitT``.
Returns:
UnitAppFontY: Vertical position of the control.
"""
...
@y.setter
def y(self, value: int | UnitT) -> None: ...
@property
def step(self) -> int:
"""
Gets/Sets the step of the control.
"""
...
@step.setter
def step(self, value: int) -> None: ...
@property
def tab_index(self) -> int:
"""
Gets/Sets the tab index of the control.
"""
...
@tab_index.setter
def tab_index(self, value: int) -> None: ...
@property
def tag(self) -> str:
"""
Gets/Sets the tag of the control.
"""
...
@tag.setter
def tag(self, value: str) -> None: ...
@property
def width(self) -> UnitPX:
"""Gets the width of the control"""
...
@width.setter
def width(self, value: int | UnitT) -> None:
"""
Gets/Sets the width of the control in Pixel units.
When setting can be an integer in ``Pixels`` Units or a ``UnitT``.
Returns:
UnitPX: Width of the control.
Note:
The Width is in Pixel units; however, the model is in AppFont units.
This property will convert the AppFont units to Pixel units.
When set using ``UnitAppFontWidth`` no conversion is done.
"""
...
# endregion UnoControlDialogElementPartial properties
# region Overrides
[docs] def get_uno_srv_name(self) -> str:
"""Get Uno service name"""
raise NotImplementedError
# endregion Overrides
# region Lazy Listeners
# Listeners such as mouse, mouse motion, focus, key, paint, and window are added lazily.
# Some listeners such as mouse motion may be expensive.
# Each time the mouse moves, the listener is invoked.
# By lazy loading listeners are only added when needed.
# For example:
# ctl_button_ok.add_event_mouse_entered(on_mouse_entered)
# This would call _on_mouse_listener_add_remove() below, which would add the mouse listener to the class in a lazy manor.
def _on_mouse_listener_add_remove(self, source: Any, event: ListenerEventArgs) -> None:
# will only ever fire once
view = cast(Any, self.get_view_ctl())
view.addMouseListener(self.events_listener_mouse)
event.remove_callback = True
def _on_mouse_motion_listener_add_remove(self, source: Any, event: ListenerEventArgs) -> None:
# will only ever fire once
view = cast(Any, self.get_view_ctl())
view.addMouseMotionListener(self.events_listener_mouse_motion)
event.remove_callback = True
def _on_focus_listener_add_remove(self, source: Any, event: ListenerEventArgs) -> None:
# will only ever fire once
view = cast(Any, self.get_view_ctl())
view.addFocusListener(self.events_listener_focus)
event.remove_callback = True
def _on_key_events_listener_add_remove(self, source: Any, event: ListenerEventArgs) -> None:
# will only ever fire once
view = cast(Any, self.get_view_ctl())
view.addKeyListener(self.events_listener_key)
event.remove_callback = True
def _on_paint_listener_add_remove(self, source: Any, event: ListenerEventArgs) -> None:
# will only ever fire once
view = cast(Any, self.get_view_ctl())
view.addPaintListener(self.events_listener_paint)
event.remove_callback = True
def _on_window_event_listener_add_remove(self, source: Any, event: ListenerEventArgs) -> None:
# will only ever fire once
view = cast(Any, self.get_view_ctl())
view.addWindowListener(self.events_listener_window)
event.remove_callback = True
# endregion Lazy Listeners
# region other methods
[docs] def get_property_set(self) -> XPropertySet:
"""Gets the property set for this control"""
return mLo.Lo.qi(XPropertySet, self.get_model(), True)
# endregion other methods
def _get_control_listener_builder(ctl: Any) -> DefaultBuilder:
"""
Get the builder for the component.
Args:
component (Any): The component.
Returns:
DefaultBuilder: Builder instance.
"""
model = ctl.getModel()
builder = DefaultBuilder(ctl)
if hasattr(model, "Name"):
builder.add_import(
"ooodev.adapter.awt.uno_control_dialog_element_partial.UnoControlDialogElementPartial",
optional=False,
init_kind=1,
check_kind=0,
)
builder.add_import(
"ooodev.dialog.dl_control.ctl_base._UnoControlDialogElementOverrides",
optional=False,
init_kind=1,
check_kind=0,
)
return builder
# endregion Control Listener Base
# region DialogControlBase
[docs]class DialogControlBase(CtlListenerBase):
"""Dialog Control Base Class. Only for Controls that have a model that can be added to a dialog"""
def __new__(cls, *args, **kwargs):
ctl = kwargs.get("ctl", None)
if ctl is None:
ctl = args[0]
builder = _get_dialog_control_base_builder(ctl)
clz = builder.get_class_type(
name="ooodev.dialog.dl_control.ctl_base.DialogControlBase", base_class=cls, set_mod_name=False
)
return super().__new__(clz, *args, **kwargs)
[docs] def __init__(self, ctl: Any) -> None:
CtlListenerBase.__init__(self, ctl)
if isinstance(self, _DialogControlBaseUnoControlElements):
_DialogControlBaseUnoControlElements.__init__(self, ctl)
# region Overrides
[docs] def get_uno_srv_name(self) -> str:
"""Get Uno service name"""
raise NotImplementedError
# endregion Overrides
# region other methods
[docs] def get_control_kind(self) -> DialogControlKind:
"""Gets the control kind"""
return DialogControlKind.from_value(self.get_uno_srv_name())
[docs] def get_control_named_kind(self) -> DialogControlNamedKind:
"""Gets the control named kind"""
with contextlib.suppress(Exception):
kind = self.get_control_kind()
return DialogControlNamedKind.from_str(kind.name)
return DialogControlNamedKind.UNKNOWN
[docs] def apply_styles(self, *styles: StyleT) -> None:
"""
Applies styles to control
Args:
*styles: Styles to apply
"""
model = self.get_model()
for style in styles:
style.apply(model)
# endregion other methods
# region Properties
@property
def tip_text(self) -> str:
"""Gets/Sets the tip text"""
with contextlib.suppress(Exception):
model = cast(Any, self.get_model())
return model.HelpText
return ""
@tip_text.setter
def tip_text(self, value: str) -> None:
with contextlib.suppress(Exception):
model = cast(Any, self.get_model())
model.HelpText = value
# useful alias
help_text = tip_text
if TYPE_CHECKING:
# The properties from this point are optional. The builder will add them if needed.
# There are include here for type hinting only.
@property
def tab_index(self) -> int:
"""Gets/Sets the tab index"""
...
@tab_index.setter
def tab_index(self, value: int) -> None: ...
@property
def step(self) -> int:
"""Gets/Sets the step"""
...
@step.setter
def step(self, value: int) -> None: ...
@property
def tag(self) -> str:
"""Gets/Sets the tag"""
...
@tag.setter
def tag(self, value: str) -> None: ...
# endregion Properties
class _DialogControlBaseUnoControlElements:
def __new__(cls, *args, **kwargs):
return super().__new__(cls, *args, **kwargs)
def __init__(self, ctl: Any):
"""
Constructor
"""
self.__model = cast("UnoControlDialogElement", ctl.getModel())
# region UnoControlDialogElementPartial Overrides
@property
def tab_index(self) -> int:
"""Gets/Sets the tab index"""
with contextlib.suppress(Exception):
return self.__model.TabIndex
return -1
@tab_index.setter
def tab_index(self, value: int) -> None:
with contextlib.suppress(Exception):
self.__model.TabIndex = value
@property
def step(self) -> int:
"""Gets/Sets the step"""
with contextlib.suppress(Exception):
return self.__model.Step
return 0
@step.setter
def step(self, value: int) -> None:
with contextlib.suppress(Exception):
self.__model.Step = value
@property
def tag(self) -> str:
"""Gets/Sets the tag"""
with contextlib.suppress(Exception):
return self.__model.Tag
return ""
@tag.setter
def tag(self, value: str) -> None:
with contextlib.suppress(Exception):
self.__model.Tag = value
def _get_dialog_control_base_builder(ctl: Any) -> DefaultBuilder:
"""
Get the builder for the component.
Args:
component (Any): The component.
Returns:
DefaultBuilder: Builder instance.
"""
model = ctl.getModel()
builder = DefaultBuilder(ctl)
if hasattr(model, "Name"):
builder.add_import(
"ooodev.dialog.dl_control.ctl_base._DialogControlBaseUnoControlElements",
optional=False,
init_kind=1,
check_kind=0,
)
return builder
# endregion DialogControlBase
def _create_control(model_name: str, win: XWindowPeer, **kwargs) -> Any:
"""
Creates a new instance of the control.
Returns:
CtlFixedText: New instance of the control
"""
def set_size_pos(
ctl: XWindow, x: int | UnitT = -1, y: int | UnitT = -1, width: int | UnitT = -1, height: int | UnitT = -1
) -> None:
"""
Set Position and size for a control.
Args:
ctl (XWindow): Control that implements XWindow
x (int, UnitT, optional): X Position. Defaults to -1.
y (int, UnitT, optional): Y Position. Defaults to -1.
width (int, UnitT, optional): Width. Defaults to -1.
height (int, UnitT, optional): Height. Defaults to -1.
"""
px_x = int(UnitPX.from_unit_val(x))
px_y = int(UnitPX.from_unit_val(y))
px_width = int(UnitPX.from_unit_val(width))
px_height = int(UnitPX.from_unit_val(height))
if px_x < 0 and px_y < 0 and px_width < 0 and px_height < 0:
return
pos_size = None
if px_x > -1 and px_y > -1 and px_width > -1 and px_height > -1:
pos_size = PosSize.POSSIZE
elif px_x > -1 and px_y > -1:
pos_size = PosSize.POS
elif px_width > -1 and px_height > -1:
pos_size = PosSize.SIZE
if pos_size is not None:
ctl.setPosSize(px_x, px_y, px_width, px_height, pos_size)
x = kwargs.pop("x", -1)
y = kwargs.pop("y", -1)
width = kwargs.pop("width", -1)
height = kwargs.pop("height", -1)
lo_inst = kwargs.pop("lo_inst", mLo.Lo.current_lo)
model = cast(Any, lo_inst.create_instance_mcf(XInterface, model_name))
ctrl = cast(Any, lo_inst.create_instance_mcf(XInterface, model.DefaultControl))
props = cast(XPropertySet, lo_inst.qi(XPropertySet, model))
if props is not None:
prop_info = props.getPropertySetInfo()
for k, v in kwargs.items():
if prop_info.hasPropertyByName(k):
props.setPropertyValue(k, v)
ctrl.setModel(model)
set_size_pos(ctrl, x, y, width, height)
ctrl.createPeer(win.Toolkit, win) # type: ignore
return ctrl