744 lines
19 KiB
Python
744 lines
19 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from typing import Any
|
|
|
|
from com.sun.star.view.SelectionType import SINGLE, MULTI, RANGE
|
|
|
|
from .easyevents import *
|
|
from .easydocs import LODocuments
|
|
from .easymain import (log, TITLE,
|
|
BaseObject, Color,
|
|
create_instance, set_properties)
|
|
from .easytools import _, LOInspect, Paths, Services
|
|
|
|
|
|
__all__ = [
|
|
'LODialog',
|
|
'inputbox',
|
|
]
|
|
|
|
|
|
COLOR_ON_FOCUS = Color()('LightYellow')
|
|
SEPARATION = 5
|
|
MODELS = {
|
|
'label': 'com.sun.star.awt.UnoControlFixedTextModel',
|
|
'text': 'com.sun.star.awt.UnoControlEditModel',
|
|
'button': 'com.sun.star.awt.UnoControlButtonModel',
|
|
'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
|
|
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
|
|
'checkbox': 'com.sun.star.awt.UnoControlCheckBoxModel',
|
|
'image': 'com.sun.star.awt.UnoControlImageControlModel',
|
|
'listbox': 'com.sun.star.awt.UnoControlListBoxModel',
|
|
'roadmap': 'com.sun.star.awt.UnoControlRoadmapModel',
|
|
'tree': 'com.sun.star.awt.tree.TreeControlModel',
|
|
'grid': 'com.sun.star.awt.grid.UnoControlGridModel',
|
|
'pages': 'com.sun.star.awt.UnoMultiPageModel',
|
|
'groupbox': 'com.sun.star.awt.UnoControlGroupBoxModel',
|
|
'combobox': 'com.sun.star.awt.UnoControlComboBoxModel',
|
|
'spinbutton': 'com.sun.star.awt.UnoControlSpinButtonModel',
|
|
'numeric': 'com.sun.star.awt.UnoControlNumericFieldModel',
|
|
}
|
|
|
|
TYPE_CONTROL = {
|
|
'stardiv.Toolkit.UnoFixedTextControl': 'label',
|
|
'stardiv.Toolkit.UnoEditControl': 'text',
|
|
'stardiv.Toolkit.UnoButtonControl': 'button',
|
|
}
|
|
|
|
IMPLEMENTATIONS = {
|
|
'grid': 'stardiv.Toolkit.GridControl',
|
|
'link': 'stardiv.Toolkit.UnoFixedHyperlinkControl',
|
|
'roadmap': 'stardiv.Toolkit.UnoRoadmapControl',
|
|
'pages': 'stardiv.Toolkit.UnoMultiPageControl',
|
|
}
|
|
|
|
|
|
def add_listeners(events, control):
|
|
name = control.Model.Name
|
|
listeners = {
|
|
'addActionListener': EventsButton,
|
|
# ~ 'addMouseListener': EventsMouse,
|
|
# ~ 'addFocusListener': EventsFocus,
|
|
# ~ 'addItemListener': EventsItem,
|
|
# ~ 'addKeyListener': EventsKey,
|
|
# ~ 'addTabListener': EventsTab,
|
|
# ~ 'addSpinListener': EventsSpin,
|
|
}
|
|
if hasattr(control, 'obj'):
|
|
control = control.obj
|
|
# ~ log.debug(control.ImplementationName)
|
|
is_grid = control.ImplementationName == IMPLEMENTATIONS['grid']
|
|
is_link = control.ImplementationName == IMPLEMENTATIONS['link']
|
|
is_roadmap = control.ImplementationName == IMPLEMENTATIONS['roadmap']
|
|
is_pages = control.ImplementationName == IMPLEMENTATIONS['pages']
|
|
|
|
for key, value in listeners.items():
|
|
if hasattr(control, key):
|
|
if is_grid and key == 'addMouseListener':
|
|
control.addMouseListener(EventsMouseGrid(events, name))
|
|
continue
|
|
if is_link and key == 'addMouseListener':
|
|
control.addMouseListener(EventsMouseLink(events, name))
|
|
continue
|
|
if is_roadmap and key == 'addItemListener':
|
|
control.addItemListener(EventsItemRoadmap(events, name))
|
|
continue
|
|
|
|
getattr(control, key)(listeners[key](events, name))
|
|
|
|
if is_grid:
|
|
controllers = EventsGrid(events, name)
|
|
control.addSelectionListener(controllers)
|
|
control.Model.GridDataModel.addGridDataListener(controllers)
|
|
return
|
|
|
|
|
|
class UnoBaseObject(object):
|
|
|
|
def __init__(self, obj: Any):
|
|
self._obj = obj
|
|
self._model = obj.Model
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def model(self):
|
|
return self._model
|
|
@property
|
|
def m(self):
|
|
return self._model
|
|
|
|
@property
|
|
def properties(self):
|
|
data = LOInspect(self.obj).properties
|
|
return data
|
|
@properties.setter
|
|
def properties(self, properties: dict):
|
|
set_properties(self.model, properties)
|
|
|
|
@property
|
|
def name(self):
|
|
return self.model.Name
|
|
|
|
@property
|
|
def parent(self):
|
|
return self.obj.Context
|
|
|
|
@property
|
|
def tag(self):
|
|
return self.model.Tag
|
|
@tag.setter
|
|
def tag(self, value):
|
|
self.model.Tag = value
|
|
|
|
@property
|
|
def visible(self):
|
|
return self.obj.Visible
|
|
@visible.setter
|
|
def visible(self, value):
|
|
self.obj.setVisible(value)
|
|
|
|
@property
|
|
def enabled(self):
|
|
return self.model.Enabled
|
|
@enabled.setter
|
|
def enabled(self, value):
|
|
self.model.Enabled = value
|
|
|
|
@property
|
|
def step(self):
|
|
return self.model.Step
|
|
@step.setter
|
|
def step(self, value):
|
|
self.model.Step = value
|
|
|
|
@property
|
|
def align(self):
|
|
return self.model.Align
|
|
@align.setter
|
|
def align(self, value):
|
|
self.model.Align = value
|
|
|
|
@property
|
|
def valign(self):
|
|
return self.model.VerticalAlign
|
|
@valign.setter
|
|
def valign(self, value):
|
|
self.model.VerticalAlign = value
|
|
|
|
@property
|
|
def font_weight(self):
|
|
return self.model.FontWeight
|
|
@font_weight.setter
|
|
def font_weight(self, value):
|
|
self.model.FontWeight = value
|
|
|
|
@property
|
|
def font_height(self):
|
|
return self.model.FontHeight
|
|
@font_height.setter
|
|
def font_height(self, value):
|
|
self.model.FontHeight = value
|
|
|
|
@property
|
|
def font_name(self):
|
|
return self.model.FontName
|
|
@font_name.setter
|
|
def font_name(self, value):
|
|
self.model.FontName = value
|
|
|
|
@property
|
|
def font_underline(self):
|
|
return self.model.FontUnderline
|
|
@font_underline.setter
|
|
def font_underline(self, value):
|
|
self.model.FontUnderline = value
|
|
|
|
@property
|
|
def text_color(self):
|
|
return self.model.TextColor
|
|
@text_color.setter
|
|
def text_color(self, value):
|
|
self.model.TextColor = value
|
|
|
|
@property
|
|
def back_color(self):
|
|
return self.model.BackgroundColor
|
|
@back_color.setter
|
|
def back_color(self, value):
|
|
self.model.BackgroundColor = value
|
|
|
|
@property
|
|
def multi_line(self):
|
|
return self.model.MultiLine
|
|
@multi_line.setter
|
|
def multi_line(self, value):
|
|
self.model.MultiLine = value
|
|
|
|
@property
|
|
def help_text(self):
|
|
return self.model.HelpText
|
|
@help_text.setter
|
|
def help_text(self, value):
|
|
self.model.HelpText = value
|
|
|
|
@property
|
|
def border(self):
|
|
return self.model.Border
|
|
@border.setter
|
|
def border(self, value):
|
|
# ~ Bug for report
|
|
self.model.Border = value
|
|
|
|
@property
|
|
def width(self):
|
|
return self._model.Width
|
|
@width.setter
|
|
def width(self, value):
|
|
self.model.Width = value
|
|
|
|
@property
|
|
def height(self):
|
|
return self.model.Height
|
|
@height.setter
|
|
def height(self, value):
|
|
self.model.Height = value
|
|
|
|
def _get_possize(self, name):
|
|
ps = self.obj.getPosSize()
|
|
return getattr(ps, name)
|
|
|
|
def _set_possize(self, name, value):
|
|
ps = self.obj.getPosSize()
|
|
setattr(ps, name, value)
|
|
self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, POSSIZE)
|
|
return
|
|
|
|
@property
|
|
def x(self):
|
|
if hasattr(self.model, 'PositionX'):
|
|
return self.model.PositionX
|
|
return self._get_possize('X')
|
|
@x.setter
|
|
def x(self, value):
|
|
if hasattr(self.model, 'PositionX'):
|
|
self.model.PositionX = value
|
|
else:
|
|
self._set_possize('X', value)
|
|
|
|
@property
|
|
def y(self):
|
|
if hasattr(self.model, 'PositionY'):
|
|
return self.model.PositionY
|
|
return self._get_possize('Y')
|
|
@y.setter
|
|
def y(self, value):
|
|
if hasattr(self.model, 'PositionY'):
|
|
self.model.PositionY = value
|
|
else:
|
|
self._set_possize('Y', value)
|
|
|
|
@property
|
|
def tab_index(self):
|
|
return self._model.TabIndex
|
|
@tab_index.setter
|
|
def tab_index(self, value):
|
|
self.model.TabIndex = value
|
|
|
|
@property
|
|
def tab_stop(self):
|
|
return self._model.Tabstop
|
|
@tab_stop.setter
|
|
def tab_stop(self, value):
|
|
self.model.Tabstop = value
|
|
|
|
@property
|
|
def ps(self):
|
|
ps = self.obj.getPosSize()
|
|
return ps
|
|
@ps.setter
|
|
def ps(self, ps):
|
|
self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, POSSIZE)
|
|
|
|
def set_focus(self):
|
|
self.obj.setFocus()
|
|
return
|
|
|
|
def ps_from(self, source):
|
|
self.ps = source.ps
|
|
return
|
|
|
|
def center(self, horizontal=True, vertical=False):
|
|
p = self.parent.Model
|
|
w = p.Width
|
|
h = p.Height
|
|
if horizontal:
|
|
x = w / 2 - self.width / 2
|
|
self.x = x
|
|
if vertical:
|
|
y = h / 2 - self.height / 2
|
|
self.y = y
|
|
return
|
|
|
|
def move(self, origin, x=0, y=5, center=False):
|
|
if x:
|
|
self.x = origin.x + origin.width + x
|
|
else:
|
|
self.x = origin.x
|
|
if y:
|
|
h = origin.height
|
|
if y < 0:
|
|
h = 0
|
|
self.y = origin.y + h + y
|
|
else:
|
|
self.y = origin.y
|
|
|
|
if center:
|
|
self.center()
|
|
return
|
|
|
|
|
|
class UnoLabel(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'label'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.model.Label
|
|
@value.setter
|
|
def value(self, value):
|
|
self.model.Label = value
|
|
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1awt_1_1UnoControlEditModel.html
|
|
class UnoText(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'text'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.model.Text
|
|
@value.setter
|
|
def value(self, value):
|
|
self.model.Text = value
|
|
|
|
@property
|
|
def echochar(self):
|
|
return chr(self.model.EchoChar)
|
|
@echochar.setter
|
|
def echochar(self, value):
|
|
if value:
|
|
self.model.EchoChar = ord(value[0])
|
|
else:
|
|
self.model.EchoChar = 0
|
|
|
|
def validate(self):
|
|
return
|
|
|
|
|
|
class UnoButton(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'button'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.model.Label
|
|
@value.setter
|
|
def value(self, value):
|
|
self.model.Label = value
|
|
|
|
@property
|
|
def image(self):
|
|
return self.model.ImageURL
|
|
@image.setter
|
|
def image(self, value):
|
|
self.model.ImageURL = Paths.to_url(value)
|
|
|
|
|
|
UNO_CLASSES = {
|
|
'label': UnoLabel,
|
|
'text': UnoText,
|
|
'button': UnoButton,
|
|
# ~ 'link': UnoLabelLink,
|
|
# ~ 'radio': UnoRadio,
|
|
# ~ 'checkbox': UnoCheckBox,
|
|
# ~ 'image': UnoImage,
|
|
# ~ 'listbox': UnoListBox,
|
|
# ~ 'roadmap': UnoRoadmap,
|
|
# ~ 'tree': UnoTree,
|
|
# ~ 'grid': UnoGrid,
|
|
# ~ 'pages': UnoPages,
|
|
# ~ 'spinbutton': UnoSpinButton,
|
|
# ~ 'numeric': UnoNumericField,
|
|
}
|
|
|
|
|
|
class DialogBox(BaseObject):
|
|
SERVICE = 'com.sun.star.awt.DialogProvider'
|
|
SERVICE_DIALOG = 'com.sun.star.awt.UnoControlDialog'
|
|
|
|
def __init__(self, properties: dict={}):
|
|
self._controls = {}
|
|
obj = self._create(properties)
|
|
super().__init__(obj)
|
|
self._init_controls()
|
|
|
|
def _create_from_path(self, path: str):
|
|
dp = create_instance(self.SERVICE, True)
|
|
dialog = dp.createDialog(Paths.to_url(path))
|
|
return dialog
|
|
|
|
def _create_from_location(self, properties: dict):
|
|
# ~ uid = docs.active.uid
|
|
# ~ url = f'vnd.sun.star.tdoc:/{uid}/Dialogs/{library}/{name}.xml'
|
|
|
|
name = properties['Name']
|
|
library = properties.get('Library', 'Standard')
|
|
location = properties.get('Location', 'application').lower()
|
|
if location == 'user':
|
|
location = 'application'
|
|
|
|
url = f'vnd.sun.star.script:{library}.{name}?location={location}'
|
|
|
|
if location == 'document':
|
|
doc = LODocuments().active.obj
|
|
dp = create_instance(self.SERVICE, arguments=doc)
|
|
else:
|
|
dp = create_instance(self.SERVICE, True)
|
|
|
|
dialog = dp.createDialog(url)
|
|
return dialog
|
|
|
|
def _create_from_properties(self, properties: dict):
|
|
dialog = create_instance(self.SERVICE_DIALOG, True)
|
|
model = create_instance(f'{self.SERVICE_DIALOG}Model', True)
|
|
|
|
properties['Width'] = properties.get('Width', 200)
|
|
properties['Height'] = properties.get('Height', 150)
|
|
|
|
set_properties(model, properties)
|
|
dialog.setModel(model)
|
|
dialog.setVisible(False)
|
|
dialog.createPeer(Services.toolkit, None)
|
|
return dialog
|
|
|
|
def _create(self, properties: dict):
|
|
path = properties.pop('Path', '')
|
|
if path:
|
|
dialog = self._create_from_path(path)
|
|
elif 'Location' in properties:
|
|
dialog = self._create_from_location(properties)
|
|
else:
|
|
dialog = self._create_from_properties(properties)
|
|
return dialog
|
|
|
|
def _init_controls(self):
|
|
for control in self.obj.Controls:
|
|
tipo = control.ImplementationName
|
|
name = control.Model.Name
|
|
if not tipo in TYPE_CONTROL:
|
|
log.debug(f'Type control: {tipo}')
|
|
raise AttributeError(f"Has no class '{tipo}'")
|
|
control = UNO_CLASSES[TYPE_CONTROL[tipo]](control)
|
|
setattr(self, name, control)
|
|
self._controls[name] = control
|
|
return
|
|
|
|
def execute(self):
|
|
return self.obj.execute()
|
|
|
|
def open(self):
|
|
return self.execute()
|
|
|
|
def close(self, value=0):
|
|
value = self.obj.endDialog(value)
|
|
return value
|
|
|
|
# ~ def close(self, value=0):
|
|
# ~ if self._modal:
|
|
# ~ value = self.obj.endDialog(value)
|
|
# ~ else:
|
|
# ~ self.visible = False
|
|
# ~ self.obj.dispose()
|
|
# ~ return value
|
|
|
|
# ~ def show(self, modal=True):
|
|
# ~ self._modal = modal
|
|
# ~ if modal:
|
|
# ~ return self.obj.execute()
|
|
# ~ else:
|
|
# ~ self.visible = True
|
|
# ~ return
|
|
|
|
@property
|
|
def model(self):
|
|
return self.obj.Model
|
|
|
|
@property
|
|
def name(self):
|
|
return self.model.Name
|
|
|
|
@property
|
|
def height(self):
|
|
return self.model.Height
|
|
@height.setter
|
|
def height(self, value):
|
|
self.model.Height = value
|
|
|
|
@property
|
|
def width(self):
|
|
return self.model.Width
|
|
@width.setter
|
|
def width(self, value):
|
|
self.model.Width = value
|
|
|
|
@property
|
|
def visible(self):
|
|
return self.obj.Visible
|
|
@visible.setter
|
|
def visible(self, value):
|
|
self.obj.Visible = value
|
|
|
|
@property
|
|
def step(self):
|
|
return self.model.Step
|
|
@step.setter
|
|
def step(self, value):
|
|
self.model.Step = value
|
|
|
|
@property
|
|
def color_on_focus(self):
|
|
return self._color_on_focus
|
|
@color_on_focus.setter
|
|
def color_on_focus(self, value):
|
|
self._color_on_focus = get_color(value)
|
|
|
|
@property
|
|
def events(self):
|
|
return self._events
|
|
@events.setter
|
|
def events(self, controllers):
|
|
self._events = controllers(self)
|
|
self._connect_listeners()
|
|
|
|
def _connect_listeners(self):
|
|
for control in self.obj.Controls:
|
|
add_listeners(self.events, control)
|
|
return
|
|
|
|
def _set_image_url(self, image: str):
|
|
if Paths.exists(image):
|
|
return Paths.to_url(image)
|
|
|
|
path = Paths.join(self._path, DIR['images'], image)
|
|
return Paths.to_url(path)
|
|
|
|
def _special_properties(self, tipo, properties):
|
|
if tipo == 'link' and not 'Label' in properties:
|
|
properties['Label'] = properties['URL']
|
|
return properties
|
|
|
|
if tipo == 'button':
|
|
if 'ImageURL' in properties:
|
|
properties['ImageURL'] = self._set_image_url(properties['ImageURL'])
|
|
properties['FocusOnClick'] = properties.get('FocusOnClick', False)
|
|
return properties
|
|
|
|
if tipo == 'roadmap':
|
|
properties['Height'] = properties.get('Height', self.height)
|
|
if 'Title' in properties:
|
|
properties['Text'] = properties.pop('Title')
|
|
return properties
|
|
|
|
if tipo == 'tree':
|
|
properties['SelectionType'] = properties.get('SelectionType', SINGLE)
|
|
return properties
|
|
|
|
if tipo == 'grid':
|
|
properties['X'] = properties.get('X', SEPARATION)
|
|
properties['Y'] = properties.get('Y', SEPARATION)
|
|
properties['Width'] = properties.get('Width', self.width - SEPARATION * 2)
|
|
properties['Height'] = properties.get('Height', self.height - SEPARATION * 2)
|
|
properties['ShowRowHeader'] = properties.get('ShowRowHeader', True)
|
|
return properties
|
|
|
|
if tipo == 'pages':
|
|
properties['Width'] = properties.get('Width', self.width)
|
|
properties['Height'] = properties.get('Height', self.height)
|
|
|
|
return properties
|
|
|
|
def add_control(self, properties):
|
|
tipo = properties.pop('Type').lower()
|
|
root = properties.pop('Root', '')
|
|
sheets = properties.pop('Sheets', ())
|
|
columns = properties.pop('Columns', ())
|
|
|
|
properties = self._special_properties(tipo, properties)
|
|
model = self.model.createInstance(MODELS[tipo])
|
|
|
|
set_properties(model, properties)
|
|
name = properties['Name']
|
|
self.model.insertByName(name, model)
|
|
control = self.obj.getControl(name)
|
|
add_listeners(self.events, control)
|
|
control = UNO_CLASSES[tipo](control)
|
|
|
|
if tipo in ('listbox',):
|
|
control.path = self.path
|
|
|
|
if tipo == 'tree' and root:
|
|
control.root = root
|
|
elif tipo == 'grid' and columns:
|
|
control.columns = columns
|
|
elif tipo == 'pages' and sheets:
|
|
control.sheets = sheets
|
|
control.events = self.events
|
|
|
|
setattr(self, name, control)
|
|
self._controls[name] = control
|
|
return control
|
|
|
|
|
|
class LODialog():
|
|
@classmethod
|
|
def create(cls, properties: dict={}):
|
|
return DialogBox(properties)
|
|
|
|
|
|
def inputbox(message, default='', title=TITLE, echochar=''):
|
|
|
|
class ControllersInput(object):
|
|
|
|
def __init__(self, dialog):
|
|
self.d = dialog
|
|
|
|
def cmd_ok_action(self, event):
|
|
self.d.close(1)
|
|
return
|
|
|
|
properties = {
|
|
'Title': title,
|
|
'Width': 200,
|
|
'Height': 80,
|
|
}
|
|
dlg = DialogBox(properties)
|
|
dlg.events = ControllersInput
|
|
|
|
properties = {
|
|
'Type': 'Label',
|
|
'Name': 'lbl_msg',
|
|
'Label': message,
|
|
'Width': 140,
|
|
'Height': 50,
|
|
'X': 5,
|
|
'Y': 5,
|
|
'MultiLine': True,
|
|
'Border': 1,
|
|
}
|
|
dlg.add_control(properties)
|
|
|
|
properties = {
|
|
'Type': 'Text',
|
|
'Name': 'txt_value',
|
|
'Text': default,
|
|
'Width': 190,
|
|
'Height': 15,
|
|
}
|
|
if echochar:
|
|
properties['EchoChar'] = ord(echochar[0])
|
|
dlg.add_control(properties)
|
|
dlg.txt_value.move(dlg.lbl_msg)
|
|
|
|
properties = {
|
|
'Type': 'button',
|
|
'Name': 'cmd_ok',
|
|
'Label': _('OK'),
|
|
'Width': 40,
|
|
'Height': 15,
|
|
'DefaultButton': True,
|
|
'PushButtonType': 1,
|
|
}
|
|
dlg.add_control(properties)
|
|
dlg.cmd_ok.move(dlg.lbl_msg, 10, 0)
|
|
|
|
properties = {
|
|
'Type': 'button',
|
|
'Name': 'cmd_cancel',
|
|
'Label': _('Cancel'),
|
|
'Width': 40,
|
|
'Height': 15,
|
|
'PushButtonType': 2,
|
|
}
|
|
dlg.add_control(properties)
|
|
dlg.cmd_cancel.move(dlg.cmd_ok)
|
|
|
|
value = ''
|
|
if dlg.open():
|
|
value = dlg.txt_value.value
|
|
|
|
return value
|