4672 lines
123 KiB
Python
4672 lines
123 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# == Rapid Develop Macros in LibreOffice ==
|
|
|
|
import base64
|
|
import ctypes
|
|
import gettext
|
|
import zipfile
|
|
|
|
from collections import OrderedDict
|
|
from collections.abc import MutableMapping
|
|
from decimal import Decimal
|
|
from enum import IntEnum
|
|
|
|
import imaplib
|
|
|
|
from com.sun.star.awt.PosSize import POSSIZE, SIZE
|
|
|
|
from com.sun.star.sheet import TableFilterField
|
|
from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
|
|
from com.sun.star.util import Time, Date, DateTime
|
|
|
|
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
|
|
|
|
from com.sun.star.lang import Locale
|
|
from com.sun.star.awt import XActionListener
|
|
from com.sun.star.awt import XMenuListener
|
|
from com.sun.star.awt import XMouseListener
|
|
from com.sun.star.awt import XMouseMotionListener
|
|
from com.sun.star.awt import XFocusListener
|
|
from com.sun.star.awt import XKeyListener
|
|
from com.sun.star.awt import XItemListener
|
|
from com.sun.star.awt import XTabListener
|
|
from com.sun.star.awt import XSpinListener
|
|
from com.sun.star.awt import XWindowListener
|
|
from com.sun.star.awt import XTopWindowListener
|
|
from com.sun.star.awt.grid import XGridDataListener
|
|
from com.sun.star.awt.grid import XGridSelectionListener
|
|
from com.sun.star.script import ScriptEventDescriptor
|
|
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1FontUnderline.html
|
|
from com.sun.star.awt import FontUnderline
|
|
from com.sun.star.style.VerticalAlignment import TOP, MIDDLE, BOTTOM
|
|
|
|
from com.sun.star.view.SelectionType import SINGLE, MULTI, RANGE
|
|
|
|
from com.sun.star.sdb.CommandType import TABLE, QUERY, COMMAND
|
|
|
|
try:
|
|
from peewee import Database, DateTimeField, DateField, TimeField, \
|
|
__exception_wrapper__
|
|
except ImportError as e:
|
|
Database = DateField = TimeField = DateTimeField = object
|
|
print('You need install peewee, only if you will develop with Base')
|
|
|
|
|
|
LOG_FORMAT = '%(asctime)s - %(levelname)s - %(message)s'
|
|
LOG_DATE = '%d/%m/%Y %H:%M:%S'
|
|
logging.addLevelName(logging.ERROR, '\033[1;41mERROR\033[1;0m')
|
|
logging.addLevelName(logging.DEBUG, '\x1b[33mDEBUG\033[1;0m')
|
|
logging.addLevelName(logging.INFO, '\x1b[32mINFO\033[1;0m')
|
|
logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT, datefmt=LOG_DATE)
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
# ~ You can get custom salt
|
|
# ~ codecs.encode(os.urandom(16), 'hex')
|
|
# ~ but, not modify this file, modify in import file
|
|
SALT = b'c9548699d4e432dfd2b46adddafbb06d'
|
|
|
|
LOG_NAME = 'ZAZ'
|
|
|
|
LEFT = 0
|
|
CENTER = 1
|
|
RIGHT = 2
|
|
|
|
CALC = 'calc'
|
|
WRITER = 'writer'
|
|
DRAW = 'draw'
|
|
IMPRESS = 'impress'
|
|
BASE = 'base'
|
|
MATH = 'math'
|
|
BASIC = 'basic'
|
|
MAIN = 'main'
|
|
TYPE_DOC = {
|
|
CALC: 'com.sun.star.sheet.SpreadsheetDocument',
|
|
WRITER: 'com.sun.star.text.TextDocument',
|
|
DRAW: 'com.sun.star.drawing.DrawingDocument',
|
|
IMPRESS: 'com.sun.star.presentation.PresentationDocument',
|
|
MATH: 'com.sun.star.formula.FormulaProperties',
|
|
BASE: 'com.sun.star.sdb.DocumentDataSource',
|
|
BASIC: 'com.sun.star.script.BasicIDE',
|
|
MAIN: 'com.sun.star.frame.StartModule',
|
|
}
|
|
|
|
OBJ_SHAPE = 'com.sun.star.comp.sc.ScShapeObj'
|
|
OBJ_GRAPHIC = 'SwXTextGraphicObject'
|
|
|
|
OBJ_TEXTS = 'SwXTextRanges'
|
|
OBJ_TEXT = 'SwXTextRange'
|
|
|
|
CLSID = {
|
|
'FORMULA': '078B7ABA-54FC-457F-8551-6147e776a997',
|
|
}
|
|
|
|
SERVICES = {
|
|
'TEXT_EMBEDDED': 'com.sun.star.text.TextEmbeddedObject',
|
|
'TEXT_TABLE': 'com.sun.star.text.TextTable',
|
|
'GRAPHIC': 'com.sun.star.text.GraphicObject',
|
|
}
|
|
|
|
|
|
# ~ from com.sun.star.sheet.FilterOperator import EMPTY, NO_EMPTY, EQUAL, NOT_EQUAL
|
|
class FilterOperator(IntEnum):
|
|
EMPTY = 0
|
|
NO_EMPTY = 1
|
|
EQUAL = 2
|
|
NOT_EQUAL = 3
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1awt_1_1UnoControlEditModel.html#a54d3ff280d892218d71e667f81ce99d4
|
|
class Border(IntEnum):
|
|
NO_BORDER = 0
|
|
BORDER = 1
|
|
SIMPLE = 2
|
|
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet.html#aa5aa6dbecaeb5e18a476b0a58279c57a
|
|
class ValidationType():
|
|
from com.sun.star.sheet.ValidationType \
|
|
import ANY, WHOLE, DECIMAL, DATE, TIME, TEXT_LEN, LIST, CUSTOM
|
|
VT = ValidationType
|
|
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet.html#aecf58149730f4c8c5c18c70f3c7c5db7
|
|
class ValidationAlertStyle():
|
|
from com.sun.star.sheet.ValidationAlertStyle \
|
|
import STOP, WARNING, INFO, MACRO
|
|
VAS = ValidationAlertStyle
|
|
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1ConditionOperator2.html
|
|
class ConditionOperator():
|
|
from com.sun.star.sheet.ConditionOperator2 \
|
|
import NONE, EQUAL, NOT_EQUAL, GREATER, GREATER_EQUAL, LESS, \
|
|
LESS_EQUAL, BETWEEN, NOT_BETWEEN, FORMULA, DUPLICATE, NOT_DUPLICATE
|
|
CO = ConditionOperator
|
|
|
|
|
|
class DataPilotFieldOrientation():
|
|
from com.sun.star.sheet.DataPilotFieldOrientation \
|
|
import HIDDEN, COLUMN, ROW, PAGE, DATA
|
|
DPFO = DataPilotFieldOrientation
|
|
|
|
|
|
class CellInsertMode():
|
|
from com.sun.star.sheet.CellInsertMode import DOWN, RIGHT, ROWS, COLUMNS
|
|
CIM = CellInsertMode
|
|
|
|
|
|
class CellDeleteMode():
|
|
from com.sun.star.sheet.CellDeleteMode import UP, LEFT, ROWS, COLUMNS
|
|
CDM = CellDeleteMode
|
|
|
|
|
|
class FormButtonType():
|
|
from com.sun.star.form.FormButtonType import PUSH, SUBMIT, RESET, URL
|
|
FBT = FormButtonType
|
|
|
|
|
|
class TextContentAnchorType():
|
|
from com.sun.star.text.TextContentAnchorType \
|
|
import AT_PARAGRAPH, AS_CHARACTER, AT_PAGE, AT_FRAME, AT_CHARACTER
|
|
TCAT = TextContentAnchorType
|
|
|
|
|
|
SECONDS_DAY = 60 * 60 * 24
|
|
DIR = {
|
|
'images': 'images',
|
|
'locales': 'locales',
|
|
}
|
|
|
|
KEY = {
|
|
'enter': 1280,
|
|
}
|
|
|
|
DEFAULT_MIME_TYPE = 'png'
|
|
MIME_TYPE = {
|
|
'png': 'image/png',
|
|
'jpg': 'image/jpeg',
|
|
}
|
|
|
|
|
|
try:
|
|
COUNTRY = LANGUAGE.split('-')[1]
|
|
except:
|
|
COUNTRY = ''
|
|
LOCALE = Locale(LANG, COUNTRY, '')
|
|
|
|
|
|
def inspect(obj: Any, to_sheet: bool=True) -> None:
|
|
if hasattr(obj, 'obj'):
|
|
obj = obj.obj
|
|
|
|
if to_sheet:
|
|
_inspect_to_sheet(obj)
|
|
else:
|
|
zaz = create_instance('net.elmau.zaz.inspect')
|
|
zaz.inspect(obj)
|
|
return
|
|
|
|
|
|
def get_type_doc(obj: Any) -> str:
|
|
for k, v in TYPE_DOC.items():
|
|
if obj.supportsService(v):
|
|
return k
|
|
return ''
|
|
|
|
|
|
def _get_class_doc(obj: Any) -> Any:
|
|
classes = {
|
|
CALC: LOCalc,
|
|
WRITER: LOWriter,
|
|
DRAW: LODraw,
|
|
IMPRESS: LOImpress,
|
|
BASE: LOBase,
|
|
MATH: LOMath,
|
|
BASIC: LOBasic,
|
|
}
|
|
type_doc = get_type_doc(obj)
|
|
return classes[type_doc](obj)
|
|
|
|
|
|
def _date_to_struct(value):
|
|
if isinstance(value, datetime.datetime):
|
|
d = DateTime()
|
|
d.Year = value.year
|
|
d.Month = value.month
|
|
d.Day = value.day
|
|
d.Hours = value.hour
|
|
d.Minutes = value.minute
|
|
d.Seconds = value.second
|
|
elif isinstance(value, datetime.date):
|
|
d = Date()
|
|
d.Day = value.day
|
|
d.Month = value.month
|
|
d.Year = value.year
|
|
elif isinstance(value, datetime.time):
|
|
d = Time()
|
|
d.Hours = value.hour
|
|
d.Minutes = value.minute
|
|
d.Seconds = value.second
|
|
return d
|
|
|
|
|
|
def _struct_to_date(value):
|
|
d = None
|
|
if isinstance(value, Time):
|
|
d = datetime.time(value.Hours, value.Minutes, value.Seconds)
|
|
elif isinstance(value, Date):
|
|
if value != Date():
|
|
d = datetime.date(value.Year, value.Month, value.Day)
|
|
elif isinstance(value, DateTime):
|
|
if value.Year > 0:
|
|
d = datetime.datetime(
|
|
value.Year, value.Month, value.Day,
|
|
value.Hours, value.Minutes, value.Seconds)
|
|
return d
|
|
|
|
|
|
def install_locales(path: str, domain: str='base', dir_locales=DIR['locales']):
|
|
path_locales = _P.join(_P(path).path, dir_locales)
|
|
try:
|
|
lang = gettext.translation(domain, path_locales, languages=[LANG])
|
|
lang.install()
|
|
_ = lang.gettext
|
|
except Exception as e:
|
|
from gettext import gettext as _
|
|
error(e)
|
|
return _
|
|
|
|
|
|
def _export_image(obj, args):
|
|
name = 'com.sun.star.drawing.GraphicExportFilter'
|
|
exporter = create_instance(name)
|
|
path = _P.to_system(args['URL'])
|
|
args = dict_to_property(args)
|
|
exporter.setSourceDocument(obj)
|
|
exporter.filter(args)
|
|
return _P.exists(path)
|
|
|
|
|
|
def get_size_screen():
|
|
res = ''
|
|
if IS_WIN:
|
|
user32 = ctypes.windll.user32
|
|
res = f'{user32.GetSystemMetrics(0)}x{user32.GetSystemMetrics(1)}'
|
|
else:
|
|
try:
|
|
args = 'xrandr | grep "*" | cut -d " " -f4'
|
|
res = run(args, split=False)
|
|
except Exception as e:
|
|
error(e)
|
|
return res.strip()
|
|
|
|
|
|
def _get_key(password):
|
|
from cryptography.hazmat.primitives import hashes
|
|
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
|
|
|
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=SALT,
|
|
iterations=100000)
|
|
key = base64.urlsafe_b64encode(kdf.derive(password.encode()))
|
|
return key
|
|
|
|
|
|
def encrypt(data, password):
|
|
from cryptography.fernet import Fernet
|
|
|
|
f = Fernet(_get_key(password))
|
|
if isinstance(data, str):
|
|
data = data.encode()
|
|
token = f.encrypt(data).decode()
|
|
return token
|
|
|
|
|
|
def decrypt(token, password):
|
|
from cryptography.fernet import Fernet, InvalidToken
|
|
|
|
data = ''
|
|
f = Fernet(_get_key(password))
|
|
try:
|
|
data = f.decrypt(token.encode()).decode()
|
|
except InvalidToken as e:
|
|
error('Invalid Token')
|
|
return data
|
|
|
|
|
|
def switch_design_mode(doc):
|
|
call_dispatch(doc.frame, '.uno:SwitchControlDesignMode')
|
|
return
|
|
|
|
|
|
class ImapServer(object):
|
|
|
|
def __init__(self, config):
|
|
self._server = None
|
|
self._error = ''
|
|
self._is_connect = self._login(config)
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
self.close()
|
|
|
|
@property
|
|
def is_connect(self):
|
|
return self._is_connect
|
|
|
|
@property
|
|
def error(self):
|
|
return self._error
|
|
|
|
def _login(self, config):
|
|
try:
|
|
# ~ hosts = 'gmail' in config['server']
|
|
if config['ssl']:
|
|
self._server = imaplib.IMAP4_SSL(config['server'], config['port'])
|
|
else:
|
|
self._server = imaplib.IMAP4(config['server'], config['port'])
|
|
self._server.login(config['user'], config['password'])
|
|
self._server.select()
|
|
return True
|
|
except imaplib.IMAP4.error as e:
|
|
self._error = str(e)
|
|
return False
|
|
except Exception as e:
|
|
self._error = str(e)
|
|
return False
|
|
return False
|
|
|
|
def get_folders(self, exclude=()):
|
|
folders = {}
|
|
result, subdir = self._server.list()
|
|
for s in subdir:
|
|
print(s.decode('utf-8'))
|
|
return folders
|
|
|
|
def close(self):
|
|
try:
|
|
self._server.close()
|
|
self._server.logout()
|
|
msg = 'Close connection...'
|
|
debug(msg)
|
|
except:
|
|
pass
|
|
return
|
|
|
|
|
|
# ~ Classes
|
|
|
|
class LOBaseObject(object):
|
|
|
|
def __init__(self, obj):
|
|
self._obj = obj
|
|
|
|
def __setattr__(self, name, value):
|
|
exists = hasattr(self, name)
|
|
if not exists and not name in ('_obj', '_index', '_view'):
|
|
setattr(self._obj, name, value)
|
|
else:
|
|
super().__setattr__(name, value)
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
|
|
class LOCalc(LODocument):
|
|
|
|
@property
|
|
def db_ranges(self):
|
|
# ~ return LOCalcDataBaseRanges(self.obj.DataBaseRanges)
|
|
return self.obj.DatabaseRanges
|
|
|
|
def render(self, data, sheet=None, clean=True):
|
|
if sheet is None:
|
|
sheet = self.active
|
|
return sheet.render(data, clean=clean)
|
|
|
|
|
|
class LOChart(object):
|
|
|
|
def __init__(self, name, obj, draw_page):
|
|
self._name = name
|
|
self._obj = obj
|
|
self._eobj = self._obj.EmbeddedObject
|
|
self._type = 'Column'
|
|
self._cell = None
|
|
self._shape = self._get_shape(draw_page)
|
|
self._pos = self._shape.Position
|
|
|
|
def __getitem__(self, index):
|
|
return LOBaseObject(self.diagram.getDataRowProperties(index))
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def name(self):
|
|
return self._name
|
|
|
|
@property
|
|
def diagram(self):
|
|
return self._eobj.Diagram
|
|
|
|
@property
|
|
def type(self):
|
|
return self._type
|
|
@type.setter
|
|
def type(self, value):
|
|
self._type = value
|
|
if value == 'Bar':
|
|
self.diagram.Vertical = True
|
|
return
|
|
type_chart = f'com.sun.star.chart.{value}Diagram'
|
|
self._eobj.setDiagram(self._eobj.createInstance(type_chart))
|
|
|
|
@property
|
|
def cell(self):
|
|
return self._cell
|
|
@cell.setter
|
|
def cell(self, value):
|
|
self._cell = value
|
|
self._shape.Anchor = value.obj
|
|
|
|
@property
|
|
def position(self):
|
|
return self._pos
|
|
@position.setter
|
|
def position(self, value):
|
|
self._pos = value
|
|
self._shape.Position = value
|
|
|
|
def _get_shape(self, draw_page):
|
|
for shape in draw_page:
|
|
if shape.PersistName == self.name:
|
|
break
|
|
return shape
|
|
|
|
|
|
class LOSheetCharts(object):
|
|
|
|
def __init__(self, obj, sheet):
|
|
self._obj = obj
|
|
self._sheet = sheet
|
|
|
|
def __getitem__(self, index):
|
|
return LOChart(index, self.obj[index], self._sheet.draw_page)
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
def __contains__(self, item):
|
|
return item in self.obj
|
|
|
|
def __len__(self):
|
|
return len(self.obj)
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
def new(self, name, pos_size, data):
|
|
self.obj.addNewByName(name, pos_size, data, True, True)
|
|
return LOChart(name, self.obj[name], self._sheet.draw_page)
|
|
|
|
|
|
class LOSheetTableField(object):
|
|
|
|
def __init__(self, obj):
|
|
self._obj = obj
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def name(self):
|
|
return self.obj.Name
|
|
|
|
@property
|
|
def orientation(self):
|
|
return self.obj.Orientation
|
|
@orientation.setter
|
|
def orientation(self, value):
|
|
self.obj.Orientation = value
|
|
|
|
|
|
# ~ com.sun.star.sheet.DataPilotFieldOrientation.ROW
|
|
class LOSheetTable(object):
|
|
|
|
def __init__(self, obj):
|
|
self._obj = obj
|
|
self._source = None
|
|
|
|
def __getitem__(self, index):
|
|
field = self.obj.DataPilotFields[index]
|
|
return LOSheetTableField(field)
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def filter(self):
|
|
return self.obj.ShowFilterButton
|
|
@filter.setter
|
|
def filter(self, value):
|
|
self.obj.ShowFilterButton = value
|
|
|
|
@property
|
|
def source(self):
|
|
return self._source
|
|
@source.setter
|
|
def source(self, value):
|
|
self._source = value
|
|
self.obj.SourceRange = value.range_address
|
|
|
|
@property
|
|
def rows(self):
|
|
return self.obj.RowFields
|
|
@rows.setter
|
|
def rows(self, values):
|
|
if not isinstance(values, tuple):
|
|
values = (values,)
|
|
for v in values:
|
|
with self[v] as f:
|
|
f.orientation = DPFO.ROW
|
|
@property
|
|
def columns(self):
|
|
return self.obj.ColumnFields
|
|
@columns.setter
|
|
def columns(self, values):
|
|
if not isinstance(values, tuple):
|
|
values = (values,)
|
|
for v in values:
|
|
with self[v] as f:
|
|
f.orientation = DPFO.COLUMN
|
|
|
|
@property
|
|
def data(self):
|
|
return self.obj.DataFields
|
|
@data.setter
|
|
def data(self, values):
|
|
if not isinstance(values, tuple):
|
|
values = (values,)
|
|
for v in values:
|
|
with self[v] as f:
|
|
f.orientation = DPFO.DATA
|
|
|
|
|
|
class LOSheetTables(object):
|
|
|
|
def __init__(self, obj, sheet):
|
|
self._obj = obj
|
|
self._sheet = sheet
|
|
|
|
def __getitem__(self, index):
|
|
return LOSheetTable(self.obj[index])
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
def __contains__(self, item):
|
|
return item in self.obj
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def count(self):
|
|
return self.obj.Count
|
|
|
|
@property
|
|
def names(self):
|
|
return self.obj.ElementNames
|
|
|
|
def new(self, name, target):
|
|
table = self.obj.createDataPilotDescriptor()
|
|
self.obj.insertNewByName(name, target.address, table)
|
|
return LOSheetTable(self.obj[name])
|
|
|
|
def remove(self, name):
|
|
self.obj.removeByName(name)
|
|
return
|
|
|
|
|
|
# ~ class LOFormControl(LOBaseObject):
|
|
class LOFormControl():
|
|
EVENTS = {
|
|
'action': 'actionPerformed',
|
|
'click': 'mousePressed',
|
|
}
|
|
TYPES = {
|
|
'actionPerformed': 'XActionListener',
|
|
'mousePressed': 'XMouseListener',
|
|
}
|
|
|
|
def __init__(self, obj, view, form):
|
|
self._obj = obj
|
|
self._view = view
|
|
self._form = form
|
|
self._m = view.Model
|
|
self._index = -1
|
|
|
|
# ~ def __setattr__(self, name, value):
|
|
# ~ if name in ('_form', '_view', '_m', '_index'):
|
|
# ~ self.__dict__[name] = value
|
|
# ~ else:
|
|
# ~ super().__setattr__(name, value)
|
|
|
|
def __str__(self):
|
|
return f'{self.name} ({self.type}) {[self.index]}'
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def form(self):
|
|
return self._form
|
|
|
|
@property
|
|
def doc(self):
|
|
return self.obj.Parent.Forms.Parent
|
|
|
|
@property
|
|
def name(self):
|
|
return self._m.Name
|
|
@name.setter
|
|
def name(self, value):
|
|
self._m.Name = value
|
|
|
|
@property
|
|
def tag(self):
|
|
return self._m.Tag
|
|
@tag.setter
|
|
def tag(self, value):
|
|
self._m.Tag = value
|
|
|
|
@property
|
|
def index(self):
|
|
return self._index
|
|
@index.setter
|
|
def index(self, value):
|
|
self._index = value
|
|
|
|
@property
|
|
def enabled(self):
|
|
return self._m.Enabled
|
|
@enabled.setter
|
|
def enabled(self, value):
|
|
self._m.Enabled = value
|
|
|
|
@property
|
|
def anchor(self):
|
|
return self.obj.Anchor
|
|
@anchor.setter
|
|
def anchor(self, value):
|
|
size = None
|
|
if hasattr(value, 'obj'):
|
|
size = getattr(value, 'size', None)
|
|
value = value.obj
|
|
self.obj.Anchor = value
|
|
if not size is None:
|
|
self.size = size
|
|
try:
|
|
self.obj.ResizeWithCell = True
|
|
except:
|
|
pass
|
|
|
|
@property
|
|
def size(self):
|
|
return self.obj.Size
|
|
@size.setter
|
|
def size(self, value):
|
|
self.obj.Size = value
|
|
|
|
@property
|
|
def events(self):
|
|
return self.form.getScriptEvents(self.index)
|
|
def add_event(self, name, macro):
|
|
if not 'name' in macro:
|
|
macro['name'] = '{}_{}'.format(self.name, name)
|
|
|
|
event = ScriptEventDescriptor()
|
|
event.AddListenerParam = ''
|
|
event.EventMethod = self.EVENTS[name]
|
|
event.ListenerType = self.TYPES[event.EventMethod]
|
|
event.ScriptCode = _get_url_script(macro)
|
|
event.ScriptType = 'Script'
|
|
|
|
for ev in self.events:
|
|
if ev.EventMethod == event.EventMethod and \
|
|
ev.ListenerType == event.ListenerType:
|
|
self.form.revokeScriptEvent(self.index,
|
|
event.ListenerType, event.EventMethod, event.AddListenerParam)
|
|
break
|
|
|
|
self.form.registerScriptEvent(self.index, event)
|
|
return
|
|
|
|
def set_focus(self):
|
|
self._view.setFocus()
|
|
return
|
|
|
|
|
|
class LOFormControlLabel(LOFormControl):
|
|
|
|
def __init__(self, obj, view, form):
|
|
super().__init__(obj, view, form)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'label'
|
|
|
|
@property
|
|
def value(self):
|
|
return self._m.Label
|
|
@value.setter
|
|
def value(self, value):
|
|
self._m.Label = value
|
|
|
|
|
|
class LOFormControlText(LOFormControl):
|
|
|
|
def __init__(self, obj, view, form):
|
|
super().__init__(obj, view, form)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'text'
|
|
|
|
@property
|
|
def value(self):
|
|
return self._m.Text
|
|
@value.setter
|
|
def value(self, value):
|
|
self._m.Text = value
|
|
|
|
|
|
class LOFormControlButton(LOFormControl):
|
|
|
|
def __init__(self, obj, view, form):
|
|
super().__init__(obj, view, form)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'button'
|
|
|
|
@property
|
|
def value(self):
|
|
return self._m.Label
|
|
@value.setter
|
|
def value(self, value):
|
|
self._m.Text = Label
|
|
|
|
@property
|
|
def url(self):
|
|
return self._m.TargetURL
|
|
@url.setter
|
|
def url(self, value):
|
|
self._m.TargetURL = value
|
|
self._m.ButtonType = FormButtonType.URL
|
|
|
|
|
|
FORM_CONTROL_CLASS = {
|
|
'label': LOFormControlLabel,
|
|
'text': LOFormControlText,
|
|
'button': LOFormControlButton,
|
|
}
|
|
|
|
|
|
class LOForm(object):
|
|
MODELS = {
|
|
'label': 'com.sun.star.form.component.FixedText',
|
|
'text': 'com.sun.star.form.component.TextField',
|
|
'button': 'com.sun.star.form.component.CommandButton',
|
|
}
|
|
|
|
def __init__(self, obj, draw_page):
|
|
self._obj = obj
|
|
self._dp = draw_page
|
|
self._controls = {}
|
|
self._init_controls()
|
|
|
|
def __getitem__(self, index):
|
|
control = self.obj[index]
|
|
return self._controls[control.Name]
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
def __contains__(self, item):
|
|
return item in self.obj
|
|
|
|
def __len__(self):
|
|
return len(self.obj)
|
|
|
|
def __str__(self):
|
|
return f'Form: {self.name}'
|
|
|
|
def _init_controls(self):
|
|
types = {
|
|
'com.sun.star.form.OFixedTextModel': 'label',
|
|
'com.sun.star.form.OEditModel': 'text',
|
|
'com.sun.star.form.OButtonModel': 'button',
|
|
}
|
|
for i, control in enumerate(self.obj):
|
|
name = control.Name
|
|
tipo = types[control.ImplementationName]
|
|
view = self.doc.CurrentController.getControl(control)
|
|
control = FORM_CONTROL_CLASS[tipo](control, view, self._obj)
|
|
control.index = i
|
|
setattr(self, name, control)
|
|
self._controls[name] = control
|
|
return
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def name(self):
|
|
return self.obj.Name
|
|
@name.setter
|
|
def name(self, value):
|
|
self.obj.Name = value
|
|
|
|
@property
|
|
def source(self):
|
|
return self.obj.DataSourceName
|
|
@source.setter
|
|
def source(self, value):
|
|
self.obj.DataSourceName = value
|
|
|
|
@property
|
|
def type(self):
|
|
return self.obj.CommandType
|
|
@type.setter
|
|
def type(self, value):
|
|
self.obj.CommandType = value
|
|
|
|
@property
|
|
def command(self):
|
|
return self.obj.Command
|
|
@command.setter
|
|
def command(self, value):
|
|
self.obj.Command = value
|
|
|
|
@property
|
|
def doc(self):
|
|
return self.obj.Parent.Parent
|
|
|
|
def _special_properties(self, tipo, args):
|
|
if tipo == 'button':
|
|
# ~ if 'ImageURL' in args:
|
|
# ~ args['ImageURL'] = self._set_image_url(args['ImageURL'])
|
|
args['FocusOnClick'] = args.get('FocusOnClick', False)
|
|
return args
|
|
return args
|
|
|
|
def add(self, args):
|
|
name = args['Name']
|
|
tipo = args.pop('Type').lower()
|
|
w = args.pop('Width', 1000)
|
|
h = args.pop('Height', 200)
|
|
x = args.pop('X', 0)
|
|
y = args.pop('Y', 0)
|
|
control = self.doc.createInstance('com.sun.star.drawing.ControlShape')
|
|
control.setSize(Size(w, h))
|
|
control.setPosition(Point(x, y))
|
|
model = self.doc.createInstance(self.MODELS[tipo])
|
|
args = self._special_properties(tipo, args)
|
|
_set_properties(model, args)
|
|
control.Control = model
|
|
index = len(self)
|
|
self.obj.insertByIndex(index, model)
|
|
self._dp.add(control)
|
|
view = self.doc.CurrentController.getControl(self.obj.getByName(name))
|
|
control = FORM_CONTROL_CLASS[tipo](control, view, self.obj)
|
|
control.index = index
|
|
setattr(self, name, control)
|
|
self._controls[name] = control
|
|
return control
|
|
|
|
|
|
class LOSheetForms(object):
|
|
|
|
def __init__(self, draw_page):
|
|
self._dp = draw_page
|
|
self._obj = draw_page.Forms
|
|
|
|
def __getitem__(self, index):
|
|
return LOForm(self.obj[index], self._dp)
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
pass
|
|
|
|
def __contains__(self, item):
|
|
return item in self.obj
|
|
|
|
def __len__(self):
|
|
return len(self.obj)
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def doc(self):
|
|
return self.obj.Parent
|
|
|
|
@property
|
|
def count(self):
|
|
return len(self)
|
|
|
|
@property
|
|
def names(self):
|
|
return self.obj.ElementNames
|
|
|
|
def insert(self, name=''):
|
|
if not name:
|
|
name = f'form{self.count + 1}'
|
|
form = self.doc.createInstance('com.sun.star.form.component.Form')
|
|
self.obj.insertByName(name, form)
|
|
return LOForm(form, self._dp)
|
|
|
|
def remove(self, index):
|
|
if isinstance(index, int):
|
|
self.obj.removeByIndex(index)
|
|
else:
|
|
self.obj.removeByName(index)
|
|
return
|
|
|
|
|
|
# ~ IsFiltered,
|
|
# ~ IsManualPageBreak,
|
|
# ~ IsStartOfNewPage
|
|
class LOSheetRows(object):
|
|
|
|
def __init__(self, sheet, obj):
|
|
self._sheet = sheet
|
|
self._obj = obj
|
|
|
|
def __getitem__(self, index):
|
|
if isinstance(index, int):
|
|
rows = LOSheetRows(self._sheet, self.obj[index])
|
|
else:
|
|
rango = self._sheet[index.start:index.stop,0:]
|
|
rows = LOSheetRows(self._sheet, rango.obj.Rows)
|
|
return rows
|
|
|
|
def __len__(self):
|
|
return self.obj.Count
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def visible(self):
|
|
return self._obj.IsVisible
|
|
@visible.setter
|
|
def visible(self, value):
|
|
self._obj.IsVisible = value
|
|
|
|
@property
|
|
def color(self):
|
|
return self.obj.CellBackColor
|
|
@color.setter
|
|
def color(self, value):
|
|
self.obj.CellBackColor = value
|
|
|
|
@property
|
|
def is_transparent(self):
|
|
return self.obj.IsCellBackgroundTransparent
|
|
@is_transparent.setter
|
|
def is_transparent(self, value):
|
|
self.obj.IsCellBackgroundTransparent = value
|
|
|
|
@property
|
|
def height(self):
|
|
return self.obj.Height
|
|
@height.setter
|
|
def height(self, value):
|
|
self.obj.Height = value
|
|
|
|
def optimal(self):
|
|
self.obj.OptimalHeight = True
|
|
return
|
|
|
|
def insert(self, index, count):
|
|
self.obj.insertByIndex(index, count)
|
|
return
|
|
|
|
def remove(self, index, count):
|
|
self.obj.removeByIndex(index, count)
|
|
return
|
|
|
|
|
|
# ~ IsManualPageBreak,
|
|
# ~ IsStartOfNewPage
|
|
class LOSheetColumns(object):
|
|
|
|
def __init__(self, sheet, obj):
|
|
self._sheet = sheet
|
|
self._obj = obj
|
|
|
|
def __getitem__(self, index):
|
|
if isinstance(index, (int, str)):
|
|
rows = LOSheetColumns(self._sheet, self.obj[index])
|
|
else:
|
|
rango = self._sheet[0,index.start:index.stop]
|
|
rows = LOSheetColumns(self._sheet, rango.obj.Columns)
|
|
return rows
|
|
|
|
def __len__(self):
|
|
return self.obj.Count
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def visible(self):
|
|
return self._obj.IsVisible
|
|
@visible.setter
|
|
def visible(self, value):
|
|
self._obj.IsVisible = value
|
|
|
|
@property
|
|
def width(self):
|
|
return self.obj.Width
|
|
@width.setter
|
|
def width(self, value):
|
|
self.obj.Width = value
|
|
|
|
def optimal(self):
|
|
self.obj.OptimalWidth = True
|
|
return
|
|
|
|
def insert(self, index, count):
|
|
self.obj.insertByIndex(index, count)
|
|
return
|
|
|
|
def remove(self, index, count):
|
|
self.obj.removeByIndex(index, count)
|
|
return
|
|
|
|
|
|
class LOCalcSheet(object):
|
|
|
|
@property
|
|
def draw_page(self):
|
|
return LODrawPage(self.obj.DrawPage)
|
|
@property
|
|
def dp(self):
|
|
return self.draw_page
|
|
|
|
@property
|
|
def shapes(self):
|
|
return self.draw_page
|
|
|
|
@property
|
|
def charts(self):
|
|
return LOSheetCharts(self.obj.Charts, self)
|
|
|
|
@property
|
|
def tables(self):
|
|
return LOSheetTables(self.obj.DataPilotTables, self)
|
|
|
|
@property
|
|
def rows(self):
|
|
return LOSheetRows(self, self.obj.Rows)
|
|
|
|
@property
|
|
def columns(self):
|
|
return LOSheetColumns(self, self.obj.Columns)
|
|
|
|
@property
|
|
def forms(self):
|
|
return LOSheetForms(self.obj.DrawPage)
|
|
|
|
@property
|
|
def search_descriptor(self):
|
|
return self.obj.createSearchDescriptor()
|
|
|
|
@property
|
|
def replace_descriptor(self):
|
|
return self.obj.createReplaceDescriptor()
|
|
|
|
def render(self, data, rango=None, clean=True):
|
|
if rango is None:
|
|
rango = self.used_area
|
|
return rango.render(data, clean)
|
|
|
|
def find(self, search_string, rango=None):
|
|
if rango is None:
|
|
rango = self.used_area
|
|
return rango.find(search_string)
|
|
|
|
|
|
class LOCalcRange(object):
|
|
|
|
def __contains__(self, item):
|
|
return item.in_range(self)
|
|
|
|
@property
|
|
def back_color(self):
|
|
return self._obj.CellBackColor
|
|
@back_color.setter
|
|
def back_color(self, value):
|
|
self._obj.CellBackColor = get_color(value)
|
|
|
|
@property
|
|
def columns(self):
|
|
return self.obj.Columns.Count
|
|
|
|
@property
|
|
def column(self):
|
|
c1 = self.address.Column
|
|
c2 = c1 + 1
|
|
ra = self.current_region.range_address
|
|
r1 = ra.StartRow
|
|
r2 = ra.EndRow + 1
|
|
return LOCalcRange(self.sheet[r1:r2, c1:c2].obj)
|
|
|
|
@property
|
|
def rows(self):
|
|
return LOSheetRows(self.sheet, self.obj.Rows)
|
|
|
|
@property
|
|
def row(self):
|
|
r1 = self.address.Row
|
|
r2 = r1 + 1
|
|
ra = self.current_region.range_address
|
|
c1 = ra.StartColumn
|
|
c2 = ra.EndColumn + 1
|
|
return LOCalcRange(self.sheet[r1:r2, c1:c2].obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return self.obj.Type
|
|
|
|
@property
|
|
def error(self):
|
|
return self.obj.getError()
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1CellFlags.html
|
|
@property
|
|
def value(self):
|
|
v = None
|
|
if self.type == VALUE:
|
|
v = self.obj.getValue()
|
|
elif self.type == TEXT:
|
|
v = self.obj.getString()
|
|
elif self.type == FORMULA:
|
|
v = self.obj.getFormula()
|
|
return v
|
|
@value.setter
|
|
def value(self, data):
|
|
if isinstance(data, str):
|
|
if data[0] in '=':
|
|
self.obj.setFormula(data)
|
|
else:
|
|
self.obj.setString(data)
|
|
elif isinstance(data, Decimal):
|
|
self.obj.setValue(float(data))
|
|
elif isinstance(data, (int, float, bool)):
|
|
self.obj.setValue(data)
|
|
elif isinstance(data, datetime.datetime):
|
|
d = data.toordinal()
|
|
t = (data - datetime.datetime.fromordinal(d)).seconds / SECONDS_DAY
|
|
self.obj.setValue(d - DATE_OFFSET + t)
|
|
elif isinstance(data, datetime.date):
|
|
d = data.toordinal()
|
|
self.obj.setValue(d - DATE_OFFSET)
|
|
elif isinstance(data, datetime.time):
|
|
d = (data.hour * 3600 + data.minute * 60 + data.second) / SECONDS_DAY
|
|
self.obj.setValue(d)
|
|
|
|
@property
|
|
def date(self):
|
|
value = int(self.obj.Value)
|
|
date = datetime.date.fromordinal(value + DATE_OFFSET)
|
|
return date
|
|
|
|
@property
|
|
def time(self):
|
|
seconds = self.obj.Value * SECONDS_DAY
|
|
time_delta = datetime.timedelta(seconds=seconds)
|
|
time = (datetime.datetime.min + time_delta).time()
|
|
return time
|
|
|
|
@property
|
|
def datetime(self):
|
|
return datetime.datetime.combine(self.date, self.time)
|
|
|
|
@property
|
|
def dict(self):
|
|
rows = self.data
|
|
k = rows[0]
|
|
data = [dict(zip(k, r)) for r in rows[1:]]
|
|
return data
|
|
@dict.setter
|
|
def dict(self, values):
|
|
data = [tuple(values[0].keys())]
|
|
data += [tuple(d.values()) for d in values]
|
|
self.data = data
|
|
|
|
@property
|
|
def formula(self):
|
|
return self.obj.getFormulaArray()
|
|
@formula.setter
|
|
def formula(self, values):
|
|
self.obj.setFormulaArray(values)
|
|
|
|
@property
|
|
def array_formula(self):
|
|
return self.obj.ArrayFormula
|
|
@array_formula.setter
|
|
def array_formula(self, value):
|
|
self.obj.ArrayFormula = value
|
|
|
|
@property
|
|
def next_cell(self):
|
|
a = self.current_region.range_address
|
|
col = a.StartColumn
|
|
row = a.EndRow + 1
|
|
return LOCalcRange(self.sheet[row, col].obj)
|
|
|
|
@property
|
|
def position(self):
|
|
return self.obj.Position
|
|
|
|
@property
|
|
def size(self):
|
|
return self.obj.Size
|
|
|
|
@property
|
|
def possize(self):
|
|
data = {
|
|
'Width': self.size.Width,
|
|
'Height': self.size.Height,
|
|
'X': self.position.X,
|
|
'Y': self.position.Y,
|
|
}
|
|
return data
|
|
|
|
@property
|
|
def visible(self):
|
|
cursor = self.cursor
|
|
rangos = cursor.queryVisibleCells()
|
|
rangos = LOCalcRanges(rangos)
|
|
return rangos
|
|
|
|
@property
|
|
def merged_area(self):
|
|
cursor = self.cursor
|
|
cursor.collapseToMergedArea()
|
|
rango = LOCalcRange(self.sheet[cursor.AbsoluteName].obj)
|
|
return rango
|
|
|
|
@property
|
|
def empty(self):
|
|
cursor = self.cursor
|
|
rangos = cursor.queryEmptyCells()
|
|
rangos = [LOCalcRange(self.sheet[r.AbsoluteName].obj) for r in rangos]
|
|
return tuple(rangos)
|
|
|
|
def query_content(self, type_content=1023):
|
|
cursor = self.cursor
|
|
rangos = cursor.queryContentCells(type_content)
|
|
rangos = [LOCalcRange(self.sheet[r.AbsoluteName].obj) for r in rangos]
|
|
return tuple(rangos)
|
|
|
|
@property
|
|
def merge(self):
|
|
return self.obj.IsMerged
|
|
@merge.setter
|
|
def merge(self, value):
|
|
self.obj.merge(value)
|
|
|
|
@property
|
|
def auto_format(self):
|
|
return ''
|
|
@auto_format.setter
|
|
def auto_format(self, value):
|
|
self.obj.autoFormat(value)
|
|
|
|
@property
|
|
def validation(self):
|
|
return self.obj.Validation
|
|
@validation.setter
|
|
def validation(self, values):
|
|
current = self.validation
|
|
if not values:
|
|
current.Type = ValidationType.ANY
|
|
current.ShowInputMessage = False
|
|
else:
|
|
is_list = False
|
|
for k, v in values.items():
|
|
if k == 'Type' and v == VT.LIST:
|
|
is_list = True
|
|
if k == 'Formula1' and is_list:
|
|
if isinstance(v, (tuple, list)):
|
|
v = ';'.join(['"{}"'.format(i) for i in v])
|
|
setattr(current, k, v)
|
|
self.obj.Validation = current
|
|
|
|
def select(self):
|
|
self.doc._cc.select(self.obj)
|
|
return
|
|
|
|
def search(self, options, find_all=True):
|
|
rangos = None
|
|
|
|
descriptor = self.sheet.search_descriptor
|
|
descriptor.setSearchString(options['Search'])
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
descriptor.SearchType = options['Type']
|
|
|
|
if find_all:
|
|
found = self.obj.findAll(descriptor)
|
|
else:
|
|
found = self.obj.findFirst(descriptor)
|
|
|
|
if found:
|
|
if found.ImplementationName == OBJ_CELL:
|
|
rangos = LOCalcRange(found)
|
|
else:
|
|
rangos = [LOCalcRange(f) for f in found]
|
|
|
|
return rangos
|
|
|
|
def replace(self, options):
|
|
descriptor = self.sheet.replace_descriptor
|
|
descriptor.setSearchString(options['Search'])
|
|
descriptor.setReplaceString(options['Replace'])
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
descriptor.SearchType = options['Type']
|
|
count = self.obj.replaceAll(descriptor)
|
|
return count
|
|
|
|
def in_range(self, rango):
|
|
if isinstance(rango, LOCalcRange):
|
|
address = rango.range_address
|
|
else:
|
|
address = rango.RangeAddress
|
|
result = self.cursor.queryIntersection(address)
|
|
return bool(result.Count)
|
|
|
|
def move(self, target):
|
|
sheet = self.sheet.obj
|
|
sheet.moveRange(target.address, self.range_address)
|
|
return
|
|
|
|
def insert(self, insert_mode=CIM.DOWN):
|
|
sheet = self.sheet.obj
|
|
sheet.insertCells(self.range_address, insert_mode)
|
|
return
|
|
|
|
def delete(self, delete_mode=CDM.UP):
|
|
sheet = self.sheet.obj
|
|
sheet.removeRange(self.range_address, delete_mode)
|
|
return
|
|
|
|
def copy_from(self, source):
|
|
self.sheet.obj.copyRange(self.address, source.range_address)
|
|
return
|
|
|
|
def copy_to(self, target):
|
|
self.sheet.obj.copyRange(target.address, self.range_address)
|
|
return
|
|
|
|
# ~ def copy_to(self, cell, formula=False):
|
|
# ~ rango = cell.to_size(self.rows, self.columns)
|
|
# ~ if formula:
|
|
# ~ rango.formula = self.formula
|
|
# ~ else:
|
|
# ~ rango.data = self.data
|
|
# ~ return
|
|
|
|
# ~ def copy_from(self, rango, formula=False):
|
|
# ~ data = rango
|
|
# ~ if isinstance(rango, LOCalcRange):
|
|
# ~ if formula:
|
|
# ~ data = rango.formula
|
|
# ~ else:
|
|
# ~ data = rango.data
|
|
# ~ rows = len(data)
|
|
# ~ cols = len(data[0])
|
|
# ~ if formula:
|
|
# ~ self.to_size(rows, cols).formula = data
|
|
# ~ else:
|
|
# ~ self.to_size(rows, cols).data = data
|
|
# ~ return
|
|
|
|
def optimal_width(self):
|
|
self.obj.Columns.OptimalWidth = True
|
|
return
|
|
|
|
def clean_render(self, template='\{(\w.+)\}'):
|
|
self._sd.SearchRegularExpression = True
|
|
self._sd.setSearchString(template)
|
|
self.obj.replaceAll(self._sd)
|
|
return
|
|
|
|
def render(self, data, clean=True):
|
|
self._sd = self.sheet.obj.createSearchDescriptor()
|
|
self._sd.SearchCaseSensitive = False
|
|
for k, v in data.items():
|
|
cell = self._render_value(k, v)
|
|
return cell
|
|
|
|
def _render_value(self, key, value, parent=''):
|
|
cell = None
|
|
if isinstance(value, dict):
|
|
for k, v in value.items():
|
|
# ~ print(1, 'RENDER', k, v)
|
|
cell = self._render_value(k, v, key)
|
|
return cell
|
|
elif isinstance(value, (list, tuple)):
|
|
self._render_list(key, value)
|
|
return
|
|
|
|
search = f'{{{key}}}'
|
|
if parent:
|
|
search = f'{{{parent}.{key}}}'
|
|
ranges = self.find_all(search)
|
|
|
|
if ranges is None:
|
|
return
|
|
|
|
# ~ for cell in ranges or range(0):
|
|
for cell in ranges:
|
|
self._set_new_value(cell, search, value)
|
|
return LOCalcRange(cell)
|
|
|
|
def _set_new_value(self, cell, search, value):
|
|
if not cell.ImplementationName == 'ScCellObj':
|
|
return
|
|
|
|
if isinstance(value, str):
|
|
pattern = re.compile(search, re.IGNORECASE)
|
|
new_value = pattern.sub(value, cell.String)
|
|
cell.String = new_value
|
|
else:
|
|
LOCalcRange(cell).value = value
|
|
return
|
|
|
|
def _render_list(self, key, rows):
|
|
for row in rows:
|
|
for k, v in row.items():
|
|
self._render_value(k, v)
|
|
return
|
|
|
|
def find(self, search_string):
|
|
if self._sd is None:
|
|
self._sd = self.sheet.obj.createSearchDescriptor()
|
|
self._sd.SearchCaseSensitive = False
|
|
|
|
self._sd.setSearchString(search_string)
|
|
cell = self.obj.findFirst(self._sd)
|
|
if cell:
|
|
cell = LOCalcRange(cell)
|
|
return cell
|
|
|
|
def find_all(self, search_string):
|
|
if self._sd is None:
|
|
self._sd = self.sheet.obj.createSearchDescriptor()
|
|
self._sd.SearchCaseSensitive = False
|
|
|
|
self._sd.setSearchString(search_string)
|
|
ranges = self.obj.findAll(self._sd)
|
|
return ranges
|
|
|
|
def filter(self, args, with_headers=True):
|
|
ff = TableFilterField()
|
|
ff.Field = args['Field']
|
|
ff.Operator = args['Operator']
|
|
if isinstance(args['Value'], str):
|
|
ff.IsNumeric = False
|
|
ff.StringValue = args['Value']
|
|
else:
|
|
ff.IsNumeric = True
|
|
ff.NumericValue = args['Value']
|
|
|
|
fd = self.obj.createFilterDescriptor(True)
|
|
fd.ContainsHeader = with_headers
|
|
fd.FilterFields = ((ff,))
|
|
# ~ self.obj.AutoFilter = True
|
|
self.obj.filter(fd)
|
|
return
|
|
|
|
def copy_format_from(self, rango):
|
|
rango.select()
|
|
self.doc.copy()
|
|
self.select()
|
|
args = {
|
|
'Flags': 'T',
|
|
'MoveMode': 4,
|
|
}
|
|
url = '.uno:InsertContents'
|
|
call_dispatch(self.doc.frame, url, args)
|
|
return
|
|
|
|
def to_image(self):
|
|
self.select()
|
|
self.doc.copy()
|
|
args = {'SelectedFormat': 141}
|
|
url = '.uno:ClipboardFormatItems'
|
|
call_dispatch(self.doc.frame, url, args)
|
|
return self.sheet.shapes[-1]
|
|
|
|
def insert_image(self, path, options={}):
|
|
args = options.copy()
|
|
ps = self.possize
|
|
args['Width'] = args.get('Width', ps['Width'])
|
|
args['Height'] = args.get('Height', ps['Height'])
|
|
args['X'] = args.get('X', ps['X'])
|
|
args['Y'] = args.get('Y', ps['Y'])
|
|
# ~ img.ResizeWithCell = True
|
|
img = self.sheet.dp.insert_image(path, args)
|
|
img.anchor = self.obj
|
|
args.clear()
|
|
return img
|
|
|
|
def insert_shape(self, tipo, args={}):
|
|
ps = self.possize
|
|
args['Width'] = args.get('Width', ps['Width'])
|
|
args['Height'] = args.get('Height', ps['Height'])
|
|
args['X'] = args.get('X', ps['X'])
|
|
args['Y'] = args.get('Y', ps['Y'])
|
|
|
|
shape = self.sheet.dp.add(tipo, args)
|
|
shape.anchor = self.obj
|
|
args.clear()
|
|
return
|
|
|
|
def filter_by_color(self, cell):
|
|
rangos = cell.column[1:,:].visible
|
|
for r in rangos:
|
|
for c in r:
|
|
if c.back_color != cell.back_color:
|
|
c.rows.visible = False
|
|
return
|
|
|
|
def clear(self, what=1023):
|
|
# ~ http://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1sheet_1_1CellFlags.html
|
|
self.obj.clearContents(what)
|
|
return
|
|
|
|
def transpose(self):
|
|
# ~ 'Flags': 'A',
|
|
# ~ 'FormulaCommand': 0,
|
|
# ~ 'SkipEmptyCells': False,
|
|
# ~ 'AsLink': False,
|
|
# ~ 'MoveMode': 4,
|
|
self.select()
|
|
self.doc.copy()
|
|
self.clear(1023)
|
|
self[0,0].select()
|
|
self.doc.insert_contents({'Transpose': True})
|
|
_CB.set('')
|
|
return
|
|
|
|
def transpose_data(self, formula=False):
|
|
data = self.data
|
|
if formula:
|
|
data = self.formula
|
|
data = tuple(zip(*data))
|
|
self.clear(1023)
|
|
self[0,0].copy_from(data, formula=formula)
|
|
return
|
|
|
|
def merge_by_row(self):
|
|
for r in range(len(self.rows)):
|
|
self[r].merge = True
|
|
return
|
|
|
|
def fill(self, source=1):
|
|
self.obj.fillAuto(0, source)
|
|
return
|
|
|
|
def _cast(self, t, v):
|
|
if not t:
|
|
return v
|
|
|
|
if t == datetime.date:
|
|
nv = datetime.date.fromordinal(int(v) + DATE_OFFSET)
|
|
else:
|
|
nv = t(v)
|
|
return nv
|
|
|
|
def get_data(self, types):
|
|
values = [
|
|
[self._cast(types[i], v) for i, v in enumerate(row)]
|
|
for row in self.data
|
|
]
|
|
return values
|
|
|
|
|
|
class LOWriterStyles(object):
|
|
|
|
def __init__(self, styles):
|
|
self._styles = styles
|
|
|
|
@property
|
|
def names(self):
|
|
return {s.DisplayName: s.Name for s in self._styles}
|
|
|
|
def __str__(self):
|
|
return '\n'.join(tuple(self.names.values()))
|
|
|
|
|
|
class LOWriterStylesFamilies(object):
|
|
|
|
def __init__(self, styles):
|
|
self._styles = styles
|
|
|
|
def __getitem__(self, index):
|
|
styles = {
|
|
'Character': 'CharacterStyles',
|
|
'Paragraph': 'ParagraphStyles',
|
|
'Page': 'PageStyles',
|
|
'Frame': 'FrameStyles',
|
|
'Numbering': 'NumberingStyles',
|
|
'Table': 'TableStyles',
|
|
'Cell': 'CellStyles',
|
|
}
|
|
name = styles.get(index, index)
|
|
return LOWriterStyles(self._styles[name])
|
|
|
|
def __iter__(self):
|
|
self._index = 0
|
|
return self
|
|
|
|
def __next__(self):
|
|
obj = LOWriterStyles(self._styles[self._index])
|
|
self._index += 1
|
|
return obj
|
|
# ~ raise StopIteration
|
|
|
|
@property
|
|
def names(self):
|
|
return self._styles.ElementNames
|
|
|
|
def __str__(self):
|
|
return '\n'.join(self.names)
|
|
|
|
|
|
class LOWriterPageStyle(LOBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
def __str__(self):
|
|
return f'Page Style: {self.name}'
|
|
|
|
@property
|
|
def name(self):
|
|
return self._obj.Name
|
|
|
|
|
|
class LOWriterPageStyles(object):
|
|
|
|
def __init__(self, styles):
|
|
self._styles = styles
|
|
|
|
def __getitem__(self, index):
|
|
return LOWriterPageStyle(self._styles[index])
|
|
|
|
@property
|
|
def names(self):
|
|
return self._styles.ElementNames
|
|
|
|
def __str__(self):
|
|
return '\n'.join(self.names)
|
|
|
|
|
|
class LOWriterTextRange(object):
|
|
|
|
def __init__(self, obj, doc):
|
|
self._obj = obj
|
|
self._doc = doc
|
|
self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph'
|
|
self._is_table = self.obj.ImplementationName == 'SwXTextTable'
|
|
self._is_text = self.obj.ImplementationName == 'SwXTextPortion'
|
|
self._is_section = not self.obj.TextSection is None
|
|
self._parts = []
|
|
if self._is_paragraph:
|
|
self._parts = [LOWriterTextRange(p, doc) for p in obj]
|
|
|
|
def __iter__(self):
|
|
self._index = 0
|
|
return self
|
|
|
|
def __next__(self):
|
|
try:
|
|
obj = self._parts[self._index]
|
|
except IndexError:
|
|
raise StopIteration
|
|
|
|
self._index += 1
|
|
return obj
|
|
|
|
@property
|
|
def string(self):
|
|
s = ''
|
|
if not self._is_table:
|
|
s = self.obj.String
|
|
return s
|
|
@string.setter
|
|
def string(self, value):
|
|
self.obj.String = value
|
|
|
|
@property
|
|
def value(self):
|
|
return self.string
|
|
@value.setter
|
|
def value(self, value):
|
|
self.string = value
|
|
|
|
@property
|
|
def style(self):
|
|
s = ''
|
|
if self.is_paragraph:
|
|
s = self.obj.ParaStyleName
|
|
elif self.is_text:
|
|
s = self.obj.CharStyleName
|
|
return s
|
|
@style.setter
|
|
def style(self, value):
|
|
if self.is_paragraph:
|
|
self.obj.ParaStyleName = value
|
|
elif self.is_text:
|
|
self.obj.CharStyleName = value
|
|
|
|
@property
|
|
def is_paragraph(self):
|
|
return self._is_paragraph
|
|
|
|
@property
|
|
def is_table(self):
|
|
return self._is_table
|
|
|
|
@property
|
|
def is_text(self):
|
|
return self._is_text
|
|
|
|
@property
|
|
def is_section(self):
|
|
return self._is_section
|
|
|
|
@property
|
|
def text_cursor(self):
|
|
return self.text.createTextCursor()
|
|
|
|
@property
|
|
def dp(self):
|
|
return self._doc.dp
|
|
|
|
@property
|
|
def paragraph(self):
|
|
cursor = self.cursor
|
|
cursor.gotoStartOfParagraph(False)
|
|
cursor.gotoNextParagraph(True)
|
|
return LOWriterTextRange(cursor, self._doc)
|
|
|
|
def goto_start(self):
|
|
if self.is_section:
|
|
rango = self.obj.TextSection.Anchor.Start
|
|
else:
|
|
rango = self.obj.Start
|
|
return LOWriterTextRange(rango, self._doc)
|
|
|
|
def goto_end(self):
|
|
if self.is_section:
|
|
rango = self.obj.TextSection.Anchor.End
|
|
else:
|
|
rango = self.obj.End
|
|
return LOWriterTextRange(rango, self._doc)
|
|
|
|
def goto_previous(self, expand=True):
|
|
cursor = self.cursor
|
|
cursor.gotoPreviousParagraph(expand)
|
|
return LOWriterTextRange(cursor, self._doc)
|
|
|
|
def goto_next(self, expand=True):
|
|
cursor = self.cursor
|
|
cursor.gotoNextParagraph(expand)
|
|
return LOWriterTextRange(cursor, self._doc)
|
|
|
|
def go_left(self, from_self=True, count=1, expand=False):
|
|
cursor = self.cursor
|
|
if not from_self:
|
|
cursor = self.text_cursor
|
|
cursor.gotoRange(self.obj, False)
|
|
cursor.goLeft(count, expand)
|
|
return LOWriterTextRange(cursor, self._doc)
|
|
|
|
def go_right(self, from_self=True, count=1, expand=False):
|
|
cursor = self.cursor
|
|
if not from_self:
|
|
cursor = self.text_cursor
|
|
cursor.gotoRange(self.obj, False)
|
|
cursor.goRight(count, expand)
|
|
return LOWriterTextRange(cursor, self._doc)
|
|
|
|
def delete(self):
|
|
self.value = ''
|
|
return
|
|
|
|
def offset(self):
|
|
cursor = self.cursor.getEnd()
|
|
return LOWriterTextRange(cursor, self._doc)
|
|
|
|
def insert_content(self, data, cursor=None, replace=False):
|
|
if cursor is None:
|
|
cursor = self.cursor
|
|
self.text.insertTextContent(cursor, data, replace)
|
|
return
|
|
|
|
def insert_math(self, formula,
|
|
anchor_type=TextContentAnchorType.AS_CHARACTER,
|
|
cursor=None, replace=False):
|
|
|
|
math = self._doc.create_instance(SERVICES['TEXT_EMBEDDED'])
|
|
math.CLSID = CLSID['FORMULA']
|
|
math.AnchorType = anchor_type
|
|
self.insert_content(math, cursor, replace)
|
|
math.EmbeddedObject.Component.Formula = formula
|
|
return math
|
|
|
|
def new_line(self, count=1):
|
|
cursor = self.cursor
|
|
for i in range(count):
|
|
self.text.insertControlCharacter(cursor, PARAGRAPH_BREAK, False)
|
|
return LOWriterTextRange(cursor, self._doc)
|
|
|
|
def insert_table(self, data):
|
|
table = self._doc.create_instance(SERVICES['TEXT_TABLE'])
|
|
rows = len(data)
|
|
cols = len(data[0])
|
|
table.initialize(rows, cols)
|
|
self.insert_content(table)
|
|
table.DataArray = data
|
|
name = table.Name
|
|
table = LOWriterTextTable(self._doc.tables[name], self._doc)
|
|
return table
|
|
|
|
def insert_shape(self, tipo, args={}):
|
|
# ~ args['Width'] = args.get('Width', 1000)
|
|
# ~ args['Height'] = args.get('Height', 1000)
|
|
# ~ args['X'] = args.get('X', 0)
|
|
# ~ args['Y'] = args.get('Y', 0)
|
|
shape = self._doc.dp.add(tipo, args)
|
|
# ~ shape.anchor = self.obj
|
|
return shape
|
|
|
|
def insert_image(self, path, args={}):
|
|
w = args.get('Width', 1000)
|
|
h = args.get('Height', 1000)
|
|
|
|
image = self._doc.create_instance(SERVICES['GRAPHIC'])
|
|
image.GraphicURL = _P.to_url(path)
|
|
image.AnchorType = TextContentAnchorType.AS_CHARACTER
|
|
image.Width = w
|
|
image.Height = h
|
|
self.insert_content(image)
|
|
return self._doc.dp.last
|
|
|
|
|
|
class LOWriterTextRanges(object):
|
|
|
|
def __init__(self, obj, doc):
|
|
self._obj = obj
|
|
self._doc = doc
|
|
self._paragraphs = [LOWriterTextRange(p, doc) for p in obj]
|
|
|
|
def __len__(self):
|
|
return len(self._paragraphs)
|
|
|
|
def __getitem__(self, index):
|
|
return self._paragraphs[index]
|
|
|
|
def __iter__(self):
|
|
self._index = 0
|
|
return self
|
|
|
|
def __next__(self):
|
|
try:
|
|
obj = self._paragraphs[self._index]
|
|
except IndexError:
|
|
raise StopIteration
|
|
|
|
self._index += 1
|
|
return obj
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
|
|
class LOWriterTextTable(object):
|
|
|
|
def __init__(self, obj, doc):
|
|
self._obj = obj
|
|
self._doc = doc
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def name(self):
|
|
return self._obj.Name
|
|
|
|
@property
|
|
def data(self):
|
|
return self.obj.DataArray
|
|
@data.setter
|
|
def data(self, values):
|
|
self.obj.DataArray = values
|
|
|
|
@property
|
|
def style(self):
|
|
return self.obj.TableTemplateName
|
|
@style.setter
|
|
def style(self, value):
|
|
self.obj.autoFormat(value)
|
|
|
|
|
|
class LOWriterTextTables(object):
|
|
|
|
def __init__(self, doc):
|
|
self._doc = doc
|
|
self._obj = doc.obj.TextTables
|
|
|
|
def __getitem__(self, key):
|
|
return LOWriterTextTable(self._obj[key], self._doc)
|
|
|
|
def __len__(self):
|
|
return self._obj.Count
|
|
|
|
def insert(self, data, text_range=None):
|
|
if text_range is None:
|
|
text_range = self._doc.selection
|
|
text_range.insert_table(data)
|
|
return
|
|
|
|
|
|
class LOWriter(LODocument):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
self._type = WRITER
|
|
self._settings = self._cc.ViewSettings
|
|
|
|
@property
|
|
def text(self):
|
|
return self.paragraphs
|
|
|
|
@property
|
|
def paragraphs(self):
|
|
return LOWriterTextRanges(self.obj.Text, self)
|
|
|
|
@property
|
|
def tables(self):
|
|
return LOWriterTextTables(self)
|
|
|
|
@property
|
|
def selection(self):
|
|
sel = self.obj.CurrentSelection
|
|
if sel.ImplementationName == OBJ_TEXTS:
|
|
if len(sel) == 1:
|
|
sel = LOWriterTextRanges(sel, self)[0]
|
|
else:
|
|
sel = LOWriterTextRanges(sel, self)
|
|
return sel
|
|
|
|
if sel.ImplementationName == OBJ_SHAPES:
|
|
if len(sel) == 1:
|
|
sel = sel[0]
|
|
sel = LODrawPage(sel.Parent)[sel.Name]
|
|
return sel
|
|
|
|
if sel.ImplementationName == OBJ_GRAPHIC:
|
|
sel = self.dp[sel.Name]
|
|
else:
|
|
debug(sel.ImplementationName)
|
|
|
|
return sel
|
|
|
|
@property
|
|
def dp(self):
|
|
return self.draw_page
|
|
@property
|
|
def shapes(self):
|
|
return self.draw_page
|
|
@property
|
|
def draw_page(self):
|
|
return LODrawPage(self.obj.DrawPage)
|
|
|
|
@property
|
|
def cursor(self):
|
|
return self.obj.Text.createTextCursor()
|
|
|
|
@property
|
|
def view_cursor(self):
|
|
return self._cc.ViewCursor
|
|
|
|
@property
|
|
def page_styles(self):
|
|
ps = self.obj.StyleFamilies['PageStyles']
|
|
return LOWriterPageStyles(ps)
|
|
|
|
@property
|
|
def styles(self):
|
|
return LOWriterStylesFamilies(self.obj.StyleFamilies)
|
|
|
|
@property
|
|
def search_descriptor(self):
|
|
return self.obj.createSearchDescriptor()
|
|
|
|
@property
|
|
def replace_descriptor(self):
|
|
return self.obj.createReplaceDescriptor()
|
|
|
|
@property
|
|
def view_web(self):
|
|
return self._settings.ShowOnlineLayout
|
|
@view_web.setter
|
|
def view_web(self, value):
|
|
self._settings.ShowOnlineLayout = value
|
|
|
|
def goto_start(self):
|
|
self.view_cursor.gotoStart(False)
|
|
return self.selection
|
|
|
|
def goto_end(self):
|
|
self.view_cursor.gotoEnd(False)
|
|
return self.selection
|
|
|
|
def search(self, options, find_all=True):
|
|
descriptor = self.search_descriptor
|
|
descriptor.setSearchString(options.get('Search', ''))
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
if 'Attributes' in options:
|
|
attr = dict_to_property(options['Attributes'])
|
|
descriptor.setSearchAttributes(attr)
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
descriptor.SearchType = options['Type']
|
|
|
|
result = False
|
|
if find_all:
|
|
found = self.obj.findAll(descriptor)
|
|
if len(found):
|
|
result = [LOWriterTextRange(f, self) for f in found]
|
|
else:
|
|
found = self.obj.findFirst(descriptor)
|
|
if found:
|
|
result = LOWriterTextRange(found, self)
|
|
|
|
return result
|
|
|
|
def replace(self, options):
|
|
descriptor = self.replace_descriptor
|
|
descriptor.setSearchString(options['Search'])
|
|
descriptor.setReplaceString(options['Replace'])
|
|
descriptor.SearchCaseSensitive = options.get('CaseSensitive', False)
|
|
descriptor.SearchWords = options.get('Words', False)
|
|
if 'Attributes' in options:
|
|
attr = dict_to_property(options['Attributes'])
|
|
descriptor.setSearchAttributes(attr)
|
|
if hasattr(descriptor, 'SearchRegularExpression'):
|
|
descriptor.SearchRegularExpression = options.get('RegularExpression', False)
|
|
if hasattr(descriptor, 'SearchType') and 'Type' in options:
|
|
descriptor.SearchType = options['Type']
|
|
found = self.obj.replaceAll(descriptor)
|
|
return found
|
|
|
|
def select(self, text):
|
|
if hasattr(text, 'obj'):
|
|
text = text.obj
|
|
self._cc.select(text)
|
|
return
|
|
|
|
|
|
class LOShape(LOBaseObject):
|
|
|
|
@property
|
|
def cell(self):
|
|
return self.anchor
|
|
|
|
@property
|
|
def anchor(self):
|
|
obj = self.obj.Anchor
|
|
if obj.ImplementationName == OBJ_CELL:
|
|
obj = LOCalcRange(obj)
|
|
elif obj.ImplementationName == OBJ_TEXT:
|
|
obj = LOWriterTextRange(obj, LODocs().active)
|
|
else:
|
|
debug('Anchor', obj.ImplementationName)
|
|
return obj
|
|
@anchor.setter
|
|
def anchor(self, value):
|
|
if hasattr(value, 'obj'):
|
|
value = value.obj
|
|
try:
|
|
self.obj.Anchor = value
|
|
except Exception as e:
|
|
self.obj.AnchorType = value
|
|
|
|
@property
|
|
def visible(self):
|
|
return self.obj.Visible
|
|
@visible.setter
|
|
def visible(self, value):
|
|
self.obj.Visible = value
|
|
|
|
@property
|
|
def path(self):
|
|
return self.url
|
|
@property
|
|
def url(self):
|
|
url = ''
|
|
if self.is_image:
|
|
url = _P.to_system(self.obj.GraphicURL.OriginURL)
|
|
return url
|
|
|
|
@property
|
|
def mimetype(self):
|
|
mt = ''
|
|
if self.is_image:
|
|
mt = self.obj.GraphicURL.MimeType
|
|
return mt
|
|
|
|
@property
|
|
def linked(self):
|
|
l = False
|
|
if self.is_image:
|
|
l = self.obj.GraphicURL.Linked
|
|
return l
|
|
|
|
def delete(self):
|
|
self.remove()
|
|
return
|
|
def remove(self):
|
|
self.obj.Parent.remove(self.obj)
|
|
return
|
|
|
|
def save(self, path: str, mimetype=DEFAULT_MIME_TYPE):
|
|
if _P.is_dir(path):
|
|
name = self.name
|
|
ext = mimetype.lower()
|
|
else:
|
|
p = _P(path)
|
|
path = p.path
|
|
name = p.name
|
|
ext = p.ext.lower()
|
|
|
|
path = _P.join(path, f'{name}.{ext}')
|
|
args = dict(
|
|
URL = _P.to_url(path),
|
|
MimeType = MIME_TYPE[ext],
|
|
)
|
|
if not _export_image(self.obj, args):
|
|
path = ''
|
|
return path
|
|
|
|
# ~ def save2(self, path: str):
|
|
# ~ size = len(self.obj.Bitmap.DIB)
|
|
# ~ data = self.obj.GraphicStream.readBytes((), size)
|
|
# ~ data = data[-1].value
|
|
# ~ path = _P.join(path, f'{self.name}.png')
|
|
# ~ _P.save_bin(path, b'')
|
|
# ~ return
|
|
|
|
|
|
class LODrawPage(LOBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
def __getitem__(self, index):
|
|
if isinstance(index, int):
|
|
shape = LOShape(self.obj[index], index)
|
|
else:
|
|
for i, o in enumerate(self.obj):
|
|
shape = self.obj[i]
|
|
name = shape.Name or f'shape{i}'
|
|
if name == index:
|
|
shape = LOShape(shape, i)
|
|
break
|
|
return shape
|
|
|
|
def __iter__(self):
|
|
self._index = 0
|
|
return self
|
|
|
|
def __next__(self):
|
|
if self._index == self.count:
|
|
raise StopIteration
|
|
shape = self[self._index]
|
|
self._index += 1
|
|
return shape
|
|
|
|
|
|
@property
|
|
def name(self):
|
|
return self.obj.Name
|
|
|
|
@property
|
|
def doc(self):
|
|
return self.obj.Forms.Parent
|
|
|
|
@property
|
|
def width(self):
|
|
return self.obj.Width
|
|
|
|
@property
|
|
def height(self):
|
|
return self.obj.Height
|
|
|
|
@property
|
|
def count(self):
|
|
return self.obj.Count
|
|
|
|
@property
|
|
def last(self):
|
|
return self[self.count - 1]
|
|
|
|
def create_instance(self, name):
|
|
return self.doc.createInstance(name)
|
|
|
|
def add(self, type_shape, options={}):
|
|
args = options.copy()
|
|
"""Insert a shape in page, type shapes:
|
|
Line
|
|
Rectangle
|
|
Ellipse
|
|
Text
|
|
Connector
|
|
"""
|
|
index = self.count
|
|
default_height = 3000
|
|
if type_shape == 'Line':
|
|
default_height = 0
|
|
w = args.pop('Width', 3000)
|
|
h = args.pop('Height', default_height)
|
|
x = args.pop('X', 1000)
|
|
y = args.pop('Y', 1000)
|
|
name = args.pop('Name', f'{type_shape.lower()}{index}')
|
|
|
|
service = f'com.sun.star.drawing.{type_shape}Shape'
|
|
shape = self.create_instance(service)
|
|
shape.Size = Size(w, h)
|
|
shape.Position = Point(x, y)
|
|
shape.Name = name
|
|
self.obj.add(shape)
|
|
|
|
if args:
|
|
_set_properties(shape, args)
|
|
|
|
return LOShape(self.obj[index], index)
|
|
|
|
def remove(self, shape):
|
|
if hasattr(shape, 'obj'):
|
|
shape = shape.obj
|
|
return self.obj.remove(shape)
|
|
|
|
def remove_all(self):
|
|
while self.count:
|
|
self.obj.remove(self.obj[0])
|
|
return
|
|
|
|
def insert_image(self, path, options={}):
|
|
args = options.copy()
|
|
index = self.count
|
|
w = args.get('Width', 3000)
|
|
h = args.get('Height', 3000)
|
|
x = args.get('X', 1000)
|
|
y = args.get('Y', 1000)
|
|
name = args.get('Name', f'image{index}')
|
|
|
|
image = self.create_instance('com.sun.star.drawing.GraphicObjectShape')
|
|
if isinstance(path, str):
|
|
image.GraphicURL = _P.to_url(path)
|
|
else:
|
|
gp = create_instance('com.sun.star.graphic.GraphicProvider')
|
|
properties = dict_to_property({'InputStream': path})
|
|
image.Graphic = gp.queryGraphic(properties)
|
|
|
|
self.obj.add(image)
|
|
image.Size = Size(w, h)
|
|
image.Position = Point(x, y)
|
|
image.Name = name
|
|
return LOShape(self.obj[index], index)
|
|
|
|
|
|
class LODrawImpress(LODocument):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
def __getitem__(self, index):
|
|
if isinstance(index, int):
|
|
page = self.obj.DrawPages[index]
|
|
else:
|
|
page = self.obj.DrawPages.getByName(index)
|
|
return LODrawPage(page)
|
|
|
|
@property
|
|
def selection(self):
|
|
sel = self.obj.CurrentSelection[0]
|
|
# ~ return _get_class_uno(sel)
|
|
return sel
|
|
|
|
@property
|
|
def current_page(self):
|
|
return LODrawPage(self._cc.getCurrentPage())
|
|
|
|
def paste(self):
|
|
call_dispatch(self.frame, '.uno:Paste')
|
|
return self.current_page[-1]
|
|
|
|
def add(self, type_shape, args={}):
|
|
return self.current_page.add(type_shape, args)
|
|
|
|
def insert_image(self, path, args={}):
|
|
self.current_page.insert_image(path, args)
|
|
return
|
|
|
|
# ~ def export(self, path, mimetype='png'):
|
|
# ~ args = dict(
|
|
# ~ URL = _P.to_url(path),
|
|
# ~ MimeType = MIME_TYPE[mimetype],
|
|
# ~ )
|
|
# ~ result = _export_image(self.obj, args)
|
|
# ~ return result
|
|
|
|
|
|
class BaseRow:
|
|
pass
|
|
|
|
|
|
class BaseQuery(object):
|
|
PY_TYPES = {
|
|
'VARCHAR': 'getString',
|
|
'INTEGER': 'getLong',
|
|
'DATE': 'getDate',
|
|
# ~ 'SQL_LONG': 'getLong',
|
|
# ~ 'SQL_VARYING': 'getString',
|
|
# ~ 'SQL_FLOAT': 'getFloat',
|
|
# ~ 'SQL_BOOLEAN': 'getBoolean',
|
|
# ~ 'SQL_TYPE_DATE': 'getDate',
|
|
# ~ 'SQL_TYPE_TIME': 'getTime',
|
|
# ~ 'SQL_TIMESTAMP': 'getTimestamp',
|
|
}
|
|
# ~ TYPES_DATE = ('SQL_TYPE_DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
|
TYPES_DATE = ('DATE', 'SQL_TYPE_TIME', 'SQL_TIMESTAMP')
|
|
|
|
def __init__(self, query):
|
|
self._query = query
|
|
self._meta = query.MetaData
|
|
self._cols = self._meta.ColumnCount
|
|
self._names = query.Columns.ElementNames
|
|
self._data = self._get_data()
|
|
|
|
def __getitem__(self, index):
|
|
return self._data[index]
|
|
|
|
def __iter__(self):
|
|
self._index = 0
|
|
return self
|
|
|
|
def __next__(self):
|
|
try:
|
|
row = self._data[self._index]
|
|
except IndexError:
|
|
raise StopIteration
|
|
self._index += 1
|
|
return row
|
|
|
|
def _to_python(self, index):
|
|
type_field = self._meta.getColumnTypeName(index)
|
|
# ~ print('TF', type_field)
|
|
value = getattr(self._query, self.PY_TYPES[type_field])(index)
|
|
if type_field in self.TYPES_DATE:
|
|
value = _struct_to_date(value)
|
|
return value
|
|
|
|
def _get_row(self):
|
|
row = BaseRow()
|
|
for i in range(1, self._cols + 1):
|
|
column_name = self._meta.getColumnName(i)
|
|
value = self._to_python(i)
|
|
setattr(row, column_name, value)
|
|
return row
|
|
|
|
def _get_data(self):
|
|
data = []
|
|
while self._query.next():
|
|
row = self._get_row()
|
|
data.append(row)
|
|
return data
|
|
|
|
@property
|
|
def tuples(self):
|
|
data = [tuple(r.__dict__.values()) for r in self._data]
|
|
return tuple(data)
|
|
|
|
@property
|
|
def dicts(self):
|
|
data = [r.__dict__ for r in self._data]
|
|
return tuple(data)
|
|
|
|
|
|
def _add_listeners(events, control, name=''):
|
|
listeners = {
|
|
'addActionListener': EventsButton,
|
|
'addMouseListener': EventsMouse,
|
|
'addFocusListener': EventsFocus,
|
|
'addItemListener': EventsItem,
|
|
'addKeyListener': EventsKey,
|
|
'addTabListener': EventsTab,
|
|
'addSpinListener': EventsSpin,
|
|
}
|
|
if hasattr(control, 'obj'):
|
|
control = control.obj
|
|
# ~ debug(control.ImplementationName)
|
|
is_grid = control.ImplementationName == 'stardiv.Toolkit.GridControl'
|
|
is_link = control.ImplementationName == 'stardiv.Toolkit.UnoFixedHyperlinkControl'
|
|
is_roadmap = control.ImplementationName == 'stardiv.Toolkit.UnoRoadmapControl'
|
|
is_pages = control.ImplementationName == 'stardiv.Toolkit.UnoMultiPageControl'
|
|
|
|
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 EventsSpin(EventsListenerBase, XSpinListener):
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def up(self, event):
|
|
event_name = f'{self.name}_up'
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def down(self, event):
|
|
event_name = f'{self.name}_up'
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def first(self, event):
|
|
event_name = f'{self.name}_first'
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def last(self, event):
|
|
event_name = f'{self.name}_last'
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
|
|
class EventsMouse(EventsListenerBase, XMouseListener, XMouseMotionListener):
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def mousePressed(self, event):
|
|
event_name = '{}_click'.format(self._name)
|
|
if event.ClickCount == 2:
|
|
event_name = '{}_double_click'.format(self._name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def mouseReleased(self, event):
|
|
event_name = '{}_after_click'.format(self._name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def mouseEntered(self, event):
|
|
pass
|
|
|
|
def mouseExited(self, event):
|
|
pass
|
|
|
|
# ~ XMouseMotionListener
|
|
def mouseMoved(self, event):
|
|
pass
|
|
|
|
def mouseDragged(self, event):
|
|
pass
|
|
|
|
|
|
class EventsMouseLink(EventsMouse):
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
self._text_color = 0
|
|
|
|
def mouseEntered(self, event):
|
|
model = event.Source.Model
|
|
self._text_color = model.TextColor or 0
|
|
model.TextColor = get_color('blue')
|
|
return
|
|
|
|
def mouseExited(self, event):
|
|
model = event.Source.Model
|
|
model.TextColor = self._text_color
|
|
return
|
|
|
|
|
|
class EventsButton(EventsListenerBase, XActionListener):
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def actionPerformed(self, event):
|
|
event_name = f'{self.name}_action'
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
|
|
class EventsFocus(EventsListenerBase, XFocusListener):
|
|
CONTROLS = (
|
|
'stardiv.Toolkit.UnoControlEditModel',
|
|
)
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def focusGained(self, event):
|
|
service = event.Source.Model.ImplementationName
|
|
# ~ print('Focus enter', service)
|
|
if service in self.CONTROLS:
|
|
obj = event.Source.Model
|
|
obj.BackgroundColor = COLOR_ON_FOCUS
|
|
return
|
|
|
|
def focusLost(self, event):
|
|
service = event.Source.Model.ImplementationName
|
|
if service in self.CONTROLS:
|
|
obj = event.Source.Model
|
|
obj.BackgroundColor = -1
|
|
return
|
|
|
|
|
|
class EventsKey(EventsListenerBase, XKeyListener):
|
|
"""
|
|
event.KeyChar
|
|
event.KeyCode
|
|
event.KeyFunc
|
|
event.Modifiers
|
|
"""
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def keyPressed(self, event):
|
|
pass
|
|
|
|
def keyReleased(self, event):
|
|
event_name = '{}_key_released'.format(self._name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
# ~ else:
|
|
# ~ if event.KeyFunc == QUIT and hasattr(self._cls, 'close'):
|
|
# ~ self._cls.close()
|
|
return
|
|
|
|
|
|
class EventsItem(EventsListenerBase, XItemListener):
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def disposing(self, event):
|
|
pass
|
|
|
|
def itemStateChanged(self, event):
|
|
event_name = '{}_item_changed'.format(self.name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
|
|
class EventsItemRoadmap(EventsItem):
|
|
|
|
def itemStateChanged(self, event):
|
|
dialog = event.Source.Context.Model
|
|
dialog.Step = event.ItemId + 1
|
|
return
|
|
|
|
|
|
class EventsGrid(EventsListenerBase, XGridDataListener, XGridSelectionListener):
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def dataChanged(self, event):
|
|
event_name = '{}_data_changed'.format(self.name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def rowHeadingChanged(self, event):
|
|
pass
|
|
|
|
def rowsInserted(self, event):
|
|
pass
|
|
|
|
def rowsRemoved(self, evemt):
|
|
pass
|
|
|
|
def selectionChanged(self, event):
|
|
event_name = '{}_selection_changed'.format(self.name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
|
|
class EventsMouseGrid(EventsMouse):
|
|
selected = False
|
|
|
|
def mousePressed(self, event):
|
|
super().mousePressed(event)
|
|
# ~ obj = event.Source
|
|
# ~ col = obj.getColumnAtPoint(event.X, event.Y)
|
|
# ~ row = obj.getRowAtPoint(event.X, event.Y)
|
|
# ~ print(col, row)
|
|
# ~ if col == -1 and row == -1:
|
|
# ~ if self.selected:
|
|
# ~ obj.deselectAllRows()
|
|
# ~ else:
|
|
# ~ obj.selectAllRows()
|
|
# ~ self.selected = not self.selected
|
|
return
|
|
|
|
def mouseReleased(self, event):
|
|
# ~ obj = event.Source
|
|
# ~ col = obj.getColumnAtPoint(event.X, event.Y)
|
|
# ~ row = obj.getRowAtPoint(event.X, event.Y)
|
|
# ~ if row == -1 and col > -1:
|
|
# ~ gdm = obj.Model.GridDataModel
|
|
# ~ for i in range(gdm.RowCount):
|
|
# ~ gdm.updateRowHeading(i, i + 1)
|
|
return
|
|
|
|
|
|
class EventsTab(EventsListenerBase, XTabListener):
|
|
|
|
def __init__(self, controller, name):
|
|
super().__init__(controller, name)
|
|
|
|
def activated(self, id):
|
|
event_name = '{}_activated'.format(self.name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(id)
|
|
return
|
|
|
|
|
|
class EventsMenu(EventsListenerBase, XMenuListener):
|
|
|
|
def __init__(self, controller):
|
|
super().__init__(controller, '')
|
|
|
|
def itemHighlighted(self, event):
|
|
pass
|
|
|
|
def itemSelected(self, event):
|
|
name = event.Source.getCommand(event.MenuId)
|
|
if name.startswith('menu'):
|
|
event_name = '{}_selected'.format(name)
|
|
else:
|
|
event_name = 'menu_{}_selected'.format(name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def itemActivated(self, event):
|
|
return
|
|
|
|
def itemDeactivated(self, event):
|
|
return
|
|
|
|
|
|
class EventsWindow(EventsListenerBase, XTopWindowListener, XWindowListener):
|
|
|
|
def __init__(self, cls):
|
|
self._cls = cls
|
|
super().__init__(cls.events, cls.name, cls._window)
|
|
|
|
def windowOpened(self, event):
|
|
event_name = '{}_opened'.format(self._name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def windowActivated(self, event):
|
|
control_name = '{}_activated'.format(event.Source.Model.Name)
|
|
if hasattr(self._controller, control_name):
|
|
getattr(self._controller, control_name)(event)
|
|
return
|
|
|
|
def windowDeactivated(self, event):
|
|
control_name = '{}_deactivated'.format(event.Source.Model.Name)
|
|
if hasattr(self._controller, control_name):
|
|
getattr(self._controller, control_name)(event)
|
|
return
|
|
|
|
def windowMinimized(self, event):
|
|
pass
|
|
|
|
def windowNormalized(self, event):
|
|
pass
|
|
|
|
def windowClosing(self, event):
|
|
if self._window:
|
|
control_name = 'window_closing'
|
|
else:
|
|
control_name = '{}_closing'.format(event.Source.Model.Name)
|
|
|
|
if hasattr(self._controller, control_name):
|
|
getattr(self._controller, control_name)(event)
|
|
# ~ else:
|
|
# ~ if not self._modal and not self._block:
|
|
# ~ event.Source.Visible = False
|
|
return
|
|
|
|
def windowClosed(self, event):
|
|
control_name = '{}_closed'.format(event.Source.Model.Name)
|
|
if hasattr(self._controller, control_name):
|
|
getattr(self._controller, control_name)(event)
|
|
return
|
|
|
|
# ~ XWindowListener
|
|
def windowResized(self, event):
|
|
sb = self._cls._subcont
|
|
sb.setPosSize(0, 0, event.Width, event.Height, SIZE)
|
|
event_name = '{}_resized'.format(self._name)
|
|
if hasattr(self._controller, event_name):
|
|
getattr(self._controller, event_name)(event)
|
|
return
|
|
|
|
def windowMoved(self, event):
|
|
pass
|
|
|
|
def windowShown(self, event):
|
|
pass
|
|
|
|
def windowHidden(self, event):
|
|
pass
|
|
|
|
|
|
# ~ BorderColor = ?
|
|
# ~ FontStyleName = ?
|
|
# ~ HelpURL = ?
|
|
class UnoBaseObject(object):
|
|
|
|
def __init__(self, obj, path=''):
|
|
self._obj = obj
|
|
self._model = obj.Model
|
|
|
|
def __setattr__(self, name, value):
|
|
exists = hasattr(self, name)
|
|
if not exists and not name in ('_obj', '_model'):
|
|
setattr(self._model, name, value)
|
|
else:
|
|
super().__setattr__(name, value)
|
|
|
|
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):
|
|
return {}
|
|
@properties.setter
|
|
def properties(self, values):
|
|
_set_properties(self.model, values)
|
|
|
|
@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
|
|
|
|
|
|
class UnoLabelLink(UnoLabel):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'link'
|
|
|
|
|
|
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 = _P.to_url(value)
|
|
|
|
|
|
class UnoRadio(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'radio'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.model.Label
|
|
@value.setter
|
|
def value(self, value):
|
|
self.model.Label = value
|
|
|
|
|
|
class UnoCheckBox(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'checkbox'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.model.State
|
|
@value.setter
|
|
def value(self, value):
|
|
self.model.State = value
|
|
|
|
@property
|
|
def label(self):
|
|
return self.model.Label
|
|
@label.setter
|
|
def label(self, value):
|
|
self.model.Label = value
|
|
|
|
@property
|
|
def tri_state(self):
|
|
return self.model.TriState
|
|
@tri_state.setter
|
|
def tri_state(self, value):
|
|
self.model.TriState = 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 UnoImage(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'image'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.url
|
|
@value.setter
|
|
def value(self, value):
|
|
self.url = value
|
|
|
|
@property
|
|
def url(self):
|
|
return self.m.ImageURL
|
|
@url.setter
|
|
def url(self, value):
|
|
self.m.ImageURL = None
|
|
self.m.ImageURL = _P.to_url(value)
|
|
|
|
|
|
class UnoListBox(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
self._path = ''
|
|
|
|
def __setattr__(self, name, value):
|
|
if name in ('_path',):
|
|
self.__dict__[name] = value
|
|
else:
|
|
super().__setattr__(name, value)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'listbox'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.obj.getSelectedItem()
|
|
|
|
@property
|
|
def count(self):
|
|
return len(self.data)
|
|
|
|
@property
|
|
def data(self):
|
|
return self.model.StringItemList
|
|
@data.setter
|
|
def data(self, values):
|
|
self.model.StringItemList = list(sorted(values))
|
|
|
|
@property
|
|
def path(self):
|
|
return self._path
|
|
@path.setter
|
|
def path(self, value):
|
|
self._path = value
|
|
|
|
def unselect(self):
|
|
self.obj.selectItem(self.value, False)
|
|
return
|
|
|
|
def select(self, pos=0):
|
|
if isinstance(pos, str):
|
|
self.obj.selectItem(pos, True)
|
|
else:
|
|
self.obj.selectItemPos(pos, True)
|
|
return
|
|
|
|
def clear(self):
|
|
self.model.removeAllItems()
|
|
return
|
|
|
|
def _set_image_url(self, image):
|
|
if _P.exists(image):
|
|
return _P.to_url(image)
|
|
|
|
path = _P.join(self._path, DIR['images'], image)
|
|
return _P.to_url(path)
|
|
|
|
def insert(self, value, path='', pos=-1, show=True):
|
|
if pos < 0:
|
|
pos = self.count
|
|
if path:
|
|
self.model.insertItem(pos, value, self._set_image_url(path))
|
|
else:
|
|
self.model.insertItemText(pos, value)
|
|
if show:
|
|
self.select(pos)
|
|
return
|
|
|
|
|
|
class UnoRoadmap(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
self._options = ()
|
|
|
|
def __setattr__(self, name, value):
|
|
if name in ('_options',):
|
|
self.__dict__[name] = value
|
|
else:
|
|
super().__setattr__(name, value)
|
|
|
|
@property
|
|
def options(self):
|
|
return self._options
|
|
@options.setter
|
|
def options(self, values):
|
|
self._options = values
|
|
for i, v in enumerate(values):
|
|
opt = self.model.createInstance()
|
|
opt.ID = i
|
|
opt.Label = v
|
|
self.model.insertByIndex(i, opt)
|
|
return
|
|
|
|
@property
|
|
def enabled(self):
|
|
return True
|
|
@enabled.setter
|
|
def enabled(self, value):
|
|
for m in self.model:
|
|
m.Enabled = value
|
|
return
|
|
|
|
def set_enabled(self, index, value):
|
|
self.model.getByIndex(index).Enabled = value
|
|
return
|
|
|
|
|
|
class UnoTree(UnoBaseObject):
|
|
|
|
def __init__(self, obj, ):
|
|
super().__init__(obj)
|
|
self._tdm = None
|
|
self._data = []
|
|
|
|
def __setattr__(self, name, value):
|
|
if name in ('_tdm', '_data'):
|
|
self.__dict__[name] = value
|
|
else:
|
|
super().__setattr__(name, value)
|
|
|
|
@property
|
|
def selection(self):
|
|
sel = self.obj.Selection
|
|
return sel.DataValue, sel.DisplayValue
|
|
|
|
@property
|
|
def parent(self):
|
|
parent = self.obj.Selection.Parent
|
|
if parent is None:
|
|
return ()
|
|
return parent.DataValue, parent.DisplayValue
|
|
|
|
def _get_parents(self, node):
|
|
value = (node.DisplayValue,)
|
|
parent = node.Parent
|
|
if parent is None:
|
|
return value
|
|
return self._get_parents(parent) + value
|
|
|
|
@property
|
|
def parents(self):
|
|
values = self._get_parents(self.obj.Selection)
|
|
return values
|
|
|
|
@property
|
|
def root(self):
|
|
if self._tdm is None:
|
|
return ''
|
|
return self._tdm.Root.DisplayValue
|
|
@root.setter
|
|
def root(self, value):
|
|
self._add_data_model(value)
|
|
|
|
def _add_data_model(self, name):
|
|
tdm = create_instance('com.sun.star.awt.tree.MutableTreeDataModel')
|
|
root = tdm.createNode(name, True)
|
|
root.DataValue = 0
|
|
tdm.setRoot(root)
|
|
self.model.DataModel = tdm
|
|
self._tdm = self.model.DataModel
|
|
return
|
|
|
|
@property
|
|
def path(self):
|
|
return self.root
|
|
@path.setter
|
|
def path(self, value):
|
|
self.data = _P.walk_dir(value, True)
|
|
|
|
@property
|
|
def data(self):
|
|
return self._data
|
|
@data.setter
|
|
def data(self, values):
|
|
self._data = list(values)
|
|
self._add_data()
|
|
|
|
def _add_data(self):
|
|
if not self.data:
|
|
return
|
|
|
|
parents = {}
|
|
for node in self.data:
|
|
parent = parents.get(node[1], self._tdm.Root)
|
|
child = self._tdm.createNode(node[2], False)
|
|
child.DataValue = node[0]
|
|
parent.appendChild(child)
|
|
parents[node[0]] = child
|
|
self.obj.expandNode(self._tdm.Root)
|
|
return
|
|
|
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1grid.html
|
|
class UnoGrid(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
self._gdm = self.model.GridDataModel
|
|
self._data = []
|
|
self._formats = ()
|
|
|
|
def __setattr__(self, name, value):
|
|
if name in ('_gdm', '_data', '_formats'):
|
|
self.__dict__[name] = value
|
|
else:
|
|
super().__setattr__(name, value)
|
|
|
|
def __getitem__(self, key):
|
|
value = self._gdm.getCellData(key[0], key[1])
|
|
return value
|
|
|
|
def __setitem__(self, key, value):
|
|
self._gdm.updateCellData(key[0], key[1], value)
|
|
return
|
|
|
|
@property
|
|
def type(self):
|
|
return 'grid'
|
|
|
|
@property
|
|
def columns(self):
|
|
return {}
|
|
@columns.setter
|
|
def columns(self, values):
|
|
# ~ self._columns = values
|
|
#~ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1grid_1_1XGridColumn.html
|
|
model = create_instance('com.sun.star.awt.grid.DefaultGridColumnModel', True)
|
|
for properties in values:
|
|
column = create_instance('com.sun.star.awt.grid.GridColumn', True)
|
|
for k, v in properties.items():
|
|
setattr(column, k, v)
|
|
model.addColumn(column)
|
|
self.model.ColumnModel = model
|
|
return
|
|
|
|
@property
|
|
def data(self):
|
|
return self._data
|
|
@data.setter
|
|
def data(self, values):
|
|
self._data = values
|
|
self.clear()
|
|
headings = tuple(range(1, len(values) + 1))
|
|
self._gdm.addRows(headings, values)
|
|
# ~ rows = range(grid_dm.RowCount)
|
|
# ~ colors = [COLORS['GRAY'] if r % 2 else COLORS['WHITE'] for r in rows]
|
|
# ~ grid.Model.RowBackgroundColors = tuple(colors)
|
|
return
|
|
|
|
@property
|
|
def value(self):
|
|
if self.column == -1 or self.row == -1:
|
|
return ''
|
|
return self[self.column, self.row]
|
|
@value.setter
|
|
def value(self, value):
|
|
if self.column > -1 and self.row > -1:
|
|
self[self.column, self.row] = value
|
|
|
|
@property
|
|
def row(self):
|
|
return self.obj.CurrentRow
|
|
|
|
@property
|
|
def row_count(self):
|
|
return self._gdm.RowCount
|
|
|
|
@property
|
|
def column(self):
|
|
return self.obj.CurrentColumn
|
|
|
|
@property
|
|
def is_valid(self):
|
|
return not (self.row == -1 or self.column == -1)
|
|
|
|
@property
|
|
def selected_rows(self):
|
|
value = self.obj.SelectedRows
|
|
return value
|
|
|
|
@property
|
|
def row_background_colors(self):
|
|
value = self.m.RowBackgroundColors
|
|
return value
|
|
@row_background_colors.setter
|
|
def row_background_colors(self, colors):
|
|
c = Color()
|
|
self.m.RowBackgroundColors = (c(colors[0]), c(colors[1]))
|
|
|
|
@property
|
|
def formats(self):
|
|
return self._formats
|
|
@formats.setter
|
|
def formats(self, values):
|
|
self._formats = values
|
|
|
|
def clear(self):
|
|
self._gdm.removeAllRows()
|
|
return
|
|
|
|
def _format_columns(self, data):
|
|
row = data
|
|
if self.formats:
|
|
for i, f in enumerate(formats):
|
|
if f:
|
|
row[i] = f.format(data[i])
|
|
return row
|
|
|
|
def add_row(self, data):
|
|
self._data.append(data)
|
|
row = self._format_columns(data)
|
|
self._gdm.addRow(self.row_count + 1, row)
|
|
return
|
|
|
|
def set_cell_tooltip(self, col, row, value):
|
|
self._gdm.updateCellToolTip(col, row, value)
|
|
return
|
|
|
|
def get_cell_tooltip(self, col, row):
|
|
value = self._gdm.getCellToolTip(col, row)
|
|
return value
|
|
|
|
def sort(self, column, asc=True):
|
|
self._gdm.sortByColumn(column, asc)
|
|
self.update_row_heading()
|
|
return
|
|
|
|
def update_row_heading(self):
|
|
for i in range(self.row_count):
|
|
self._gdm.updateRowHeading(i, i + 1)
|
|
return
|
|
|
|
def remove_row(self, row):
|
|
self._gdm.removeRow(row)
|
|
del self._data[row]
|
|
self.update_row_heading()
|
|
return
|
|
|
|
|
|
class UnoPage(object):
|
|
|
|
def __init__(self, obj):
|
|
self._obj = obj
|
|
self._events = None
|
|
|
|
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._obj.Model
|
|
|
|
# ~ @property
|
|
# ~ def id(self):
|
|
# ~ return self.m.TabPageID
|
|
|
|
@property
|
|
def parent(self):
|
|
return self.obj.Context
|
|
|
|
def _set_image_url(self, image):
|
|
if _P.exists(image):
|
|
return _P.to_url(image)
|
|
|
|
path = _P.join(self._path, DIR['images'], image)
|
|
return _P.to_url(path)
|
|
|
|
def _special_properties(self, tipo, args):
|
|
if tipo == 'link' and not 'Label' in args:
|
|
args['Label'] = args['URL']
|
|
return args
|
|
|
|
if tipo == 'button':
|
|
if 'ImageURL' in args:
|
|
args['ImageURL'] = self._set_image_url(args['ImageURL'])
|
|
args['FocusOnClick'] = args.get('FocusOnClick', False)
|
|
return args
|
|
|
|
if tipo == 'roadmap':
|
|
args['Height'] = args.get('Height', self.height)
|
|
if 'Title' in args:
|
|
args['Text'] = args.pop('Title')
|
|
return args
|
|
|
|
if tipo == 'tree':
|
|
args['SelectionType'] = args.get('SelectionType', SINGLE)
|
|
return args
|
|
|
|
if tipo == 'grid':
|
|
args['ShowRowHeader'] = args.get('ShowRowHeader', True)
|
|
return args
|
|
|
|
if tipo == 'pages':
|
|
args['Width'] = args.get('Width', self.width)
|
|
args['Height'] = args.get('Height', self.height)
|
|
|
|
return args
|
|
|
|
def add_control(self, args):
|
|
tipo = args.pop('Type').lower()
|
|
root = args.pop('Root', '')
|
|
sheets = args.pop('Sheets', ())
|
|
columns = args.pop('Columns', ())
|
|
|
|
args = self._special_properties(tipo, args)
|
|
model = self.model.createInstance(UNO_MODELS[tipo])
|
|
_set_properties(model, args)
|
|
name = args['Name']
|
|
self.model.insertByName(name, model)
|
|
control = self.obj.getControl(name)
|
|
_add_listeners(self._events, control, name)
|
|
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)
|
|
return control
|
|
|
|
|
|
class UnoPages(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
self._sheets = []
|
|
self._events = None
|
|
|
|
def __setattr__(self, name, value):
|
|
if name in ('_sheets', '_events'):
|
|
self.__dict__[name] = value
|
|
else:
|
|
super().__setattr__(name, value)
|
|
|
|
def __getitem__(self, index):
|
|
name = index
|
|
if isinstance(index, int):
|
|
name = f'sheet{index}'
|
|
sheet = self.obj.getControl(name)
|
|
page = UnoPage(sheet)
|
|
page._events = self._events
|
|
return page
|
|
|
|
@property
|
|
def type(self):
|
|
return 'pages'
|
|
|
|
@property
|
|
def current(self):
|
|
return self.obj.ActiveTabID
|
|
@property
|
|
def active(self):
|
|
return self.current
|
|
|
|
@property
|
|
def sheets(self):
|
|
return self._sheets
|
|
@sheets.setter
|
|
def sheets(self, values):
|
|
self._sheets = values
|
|
for i, title in enumerate(values):
|
|
sheet = self.m.createInstance('com.sun.star.awt.UnoPageModel')
|
|
sheet.Title = title
|
|
self.m.insertByName(f'sheet{i + 1}', sheet)
|
|
return
|
|
|
|
@property
|
|
def events(self):
|
|
return self._events
|
|
@events.setter
|
|
def events(self, controllers):
|
|
self._events = controllers
|
|
|
|
@property
|
|
def visible(self):
|
|
return self.obj.Visible
|
|
@visible.setter
|
|
def visible(self, value):
|
|
self.obj.Visible = value
|
|
|
|
def insert(self, title):
|
|
self._sheets.append(title)
|
|
id = len(self._sheets)
|
|
sheet = self.m.createInstance('com.sun.star.awt.UnoPageModel')
|
|
sheet.Title = title
|
|
self.m.insertByName(f'sheet{id}', sheet)
|
|
return self[id]
|
|
|
|
def remove(self, id):
|
|
self.obj.removeTab(id)
|
|
return
|
|
|
|
def activate(self, id):
|
|
self.obj.activateTab(id)
|
|
return
|
|
|
|
|
|
class UnoSpinButton(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'spinbutton'
|
|
|
|
@property
|
|
def value(self):
|
|
return self.model.Label
|
|
@value.setter
|
|
def value(self, value):
|
|
self.model.Label = value
|
|
|
|
|
|
class UnoNumericField(UnoBaseObject):
|
|
|
|
def __init__(self, obj):
|
|
super().__init__(obj)
|
|
|
|
@property
|
|
def type(self):
|
|
return 'numeric'
|
|
|
|
@property
|
|
def int(self):
|
|
return int(self.value)
|
|
|
|
@property
|
|
def value(self):
|
|
return self.model.Value
|
|
@value.setter
|
|
def value(self, value):
|
|
self.model.Value = value
|
|
|
|
|
|
UNO_CLASSES = {
|
|
'label': UnoLabel,
|
|
'link': UnoLabelLink,
|
|
'button': UnoButton,
|
|
'radio': UnoRadio,
|
|
'checkbox': UnoCheckBox,
|
|
'text': UnoText,
|
|
'image': UnoImage,
|
|
'listbox': UnoListBox,
|
|
'roadmap': UnoRoadmap,
|
|
'tree': UnoTree,
|
|
'grid': UnoGrid,
|
|
'pages': UnoPages,
|
|
'spinbutton': UnoSpinButton,
|
|
'numeric': UnoNumericField,
|
|
}
|
|
|
|
UNO_MODELS = {
|
|
'label': 'com.sun.star.awt.UnoControlFixedTextModel',
|
|
'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
|
|
'button': 'com.sun.star.awt.UnoControlButtonModel',
|
|
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
|
|
'checkbox': 'com.sun.star.awt.UnoControlCheckBoxModel',
|
|
'text': 'com.sun.star.awt.UnoControlEditModel',
|
|
'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',
|
|
}
|
|
# ~ 'CurrencyField': 'com.sun.star.awt.UnoControlCurrencyFieldModel',
|
|
# ~ 'DateField': 'com.sun.star.awt.UnoControlDateFieldModel',
|
|
# ~ 'FileControl': 'com.sun.star.awt.UnoControlFileControlModel',
|
|
# ~ 'FormattedField': 'com.sun.star.awt.UnoControlFormattedFieldModel',
|
|
# ~ 'PatternField': 'com.sun.star.awt.UnoControlPatternFieldModel',
|
|
# ~ 'ProgressBar': 'com.sun.star.awt.UnoControlProgressBarModel',
|
|
# ~ 'ScrollBar': 'com.sun.star.awt.UnoControlScrollBarModel',
|
|
# ~ 'SimpleAnimation': 'com.sun.star.awt.UnoControlSimpleAnimationModel',
|
|
# ~ 'Throbber': 'com.sun.star.awt.UnoControlThrobberModel',
|
|
# ~ 'TimeField': 'com.sun.star.awt.UnoControlTimeFieldModel',
|
|
|
|
|
|
class LODialog(object):
|
|
SEPARATION = 5
|
|
MODELS = {
|
|
'label': 'com.sun.star.awt.UnoControlFixedTextModel',
|
|
'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
|
|
'button': 'com.sun.star.awt.UnoControlButtonModel',
|
|
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
|
|
'checkbox': 'com.sun.star.awt.UnoControlCheckBoxModel',
|
|
'text': 'com.sun.star.awt.UnoControlEditModel',
|
|
'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',
|
|
}
|
|
|
|
def __init__(self, args={}):
|
|
self._obj = self._create(args)
|
|
self._model = self.obj.Model
|
|
self._events = None
|
|
self._modal = True
|
|
self._controls = {}
|
|
self._color_on_focus = COLOR_ON_FOCUS
|
|
self._id = ''
|
|
self._path = ''
|
|
self._init_controls()
|
|
|
|
def _create(self, args):
|
|
service = 'com.sun.star.awt.DialogProvider'
|
|
path = args.pop('Path', '')
|
|
if path:
|
|
dp = create_instance(service, True)
|
|
dlg = dp.createDialog(_P.to_url(path))
|
|
return dlg
|
|
|
|
if 'Location' in args:
|
|
name = args['Name']
|
|
library = args.get('Library', 'Standard')
|
|
location = args.get('Location', 'application').lower()
|
|
if location == 'user':
|
|
location = 'application'
|
|
url = f'vnd.sun.star.script:{library}.{name}?location={location}'
|
|
if location == 'document':
|
|
dp = create_instance(service, args=docs.active.obj)
|
|
else:
|
|
dp = create_instance(service, True)
|
|
# ~ uid = docs.active.uid
|
|
# ~ url = f'vnd.sun.star.tdoc:/{uid}/Dialogs/{library}/{name}.xml'
|
|
dlg = dp.createDialog(url)
|
|
return dlg
|
|
|
|
dlg = create_instance('com.sun.star.awt.UnoControlDialog', True)
|
|
model = create_instance('com.sun.star.awt.UnoControlDialogModel', True)
|
|
toolkit = create_instance('com.sun.star.awt.Toolkit', True)
|
|
|
|
args['Title'] = args.get('Title', TITLE)
|
|
args['Width'] = args.get('Width', 200)
|
|
args['Height'] = args.get('Height', 150)
|
|
|
|
_set_properties(model, args)
|
|
dlg.setModel(model)
|
|
dlg.setVisible(False)
|
|
dlg.createPeer(toolkit, None)
|
|
return dlg
|
|
|
|
def _get_type_control(self, name):
|
|
name = name.split('.')[2]
|
|
types = {
|
|
'UnoFixedTextControl': 'label',
|
|
'UnoEditControl': 'text',
|
|
'UnoButtonControl': 'button',
|
|
}
|
|
return types[name]
|
|
|
|
def _init_controls(self):
|
|
for control in self.obj.getControls():
|
|
tipo = self._get_type_control(control.ImplementationName)
|
|
name = control.Model.Name
|
|
control = UNO_CLASSES[tipo](control)
|
|
setattr(self, name, control)
|
|
return
|
|
|
|
@property
|
|
def obj(self):
|
|
return self._obj
|
|
|
|
@property
|
|
def model(self):
|
|
return self._model
|
|
|
|
@property
|
|
def controls(self):
|
|
return self._controls
|
|
|
|
@property
|
|
def path(self):
|
|
return self._path
|
|
@property
|
|
def path_images(self):
|
|
return _P.join(self.path, DIR['images'])
|
|
@property
|
|
def id(self):
|
|
return self._id
|
|
@id.setter
|
|
def id(self, value):
|
|
self._id = value
|
|
self._path = _P.from_id(value)
|
|
|
|
@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 events(self):
|
|
return self._events
|
|
@events.setter
|
|
def events(self, controllers):
|
|
self._events = controllers(self)
|
|
self._connect_listeners()
|
|
|
|
@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)
|
|
|
|
def _connect_listeners(self):
|
|
for control in self.obj.Controls:
|
|
_add_listeners(self.events, control, control.Model.Name)
|
|
return
|
|
|
|
def _set_image_url(self, image):
|
|
if _P.exists(image):
|
|
return _P.to_url(image)
|
|
|
|
path = _P.join(self._path, DIR['images'], image)
|
|
return _P.to_url(path)
|
|
|
|
def _special_properties(self, tipo, args):
|
|
if tipo == 'link' and not 'Label' in args:
|
|
args['Label'] = args['URL']
|
|
return args
|
|
|
|
if tipo == 'button':
|
|
if 'ImageURL' in args:
|
|
args['ImageURL'] = self._set_image_url(args['ImageURL'])
|
|
args['FocusOnClick'] = args.get('FocusOnClick', False)
|
|
return args
|
|
|
|
if tipo == 'roadmap':
|
|
args['Height'] = args.get('Height', self.height)
|
|
if 'Title' in args:
|
|
args['Text'] = args.pop('Title')
|
|
return args
|
|
|
|
if tipo == 'tree':
|
|
args['SelectionType'] = args.get('SelectionType', SINGLE)
|
|
return args
|
|
|
|
if tipo == 'grid':
|
|
args['X'] = args.get('X', self.SEPARATION)
|
|
args['Y'] = args.get('Y', self.SEPARATION)
|
|
args['Width'] = args.get('Width', self.width - self.SEPARATION * 2)
|
|
args['Height'] = args.get('Height', self.height - self.SEPARATION * 2)
|
|
args['ShowRowHeader'] = args.get('ShowRowHeader', True)
|
|
return args
|
|
|
|
if tipo == 'pages':
|
|
args['Width'] = args.get('Width', self.width)
|
|
args['Height'] = args.get('Height', self.height)
|
|
|
|
return args
|
|
|
|
def add_control(self, args):
|
|
tipo = args.pop('Type').lower()
|
|
root = args.pop('Root', '')
|
|
sheets = args.pop('Sheets', ())
|
|
columns = args.pop('Columns', ())
|
|
|
|
args = self._special_properties(tipo, args)
|
|
model = self.model.createInstance(self.MODELS[tipo])
|
|
|
|
_set_properties(model, args)
|
|
name = args['Name']
|
|
self.model.insertByName(name, model)
|
|
control = self.obj.getControl(name)
|
|
_add_listeners(self.events, control, name)
|
|
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
|
|
|
|
def center(self, control, x=0, y=0):
|
|
w = self.width
|
|
h = self.height
|
|
|
|
if isinstance(control, tuple):
|
|
wt = self.SEPARATION * -1
|
|
for c in control:
|
|
wt += c.width + self.SEPARATION
|
|
x = w / 2 - wt / 2
|
|
for c in control:
|
|
c.x = x
|
|
x = c.x + c.width + self.SEPARATION
|
|
return
|
|
|
|
if x < 0:
|
|
x = w + x - control.width
|
|
elif x == 0:
|
|
x = w / 2 - control.width / 2
|
|
if y < 0:
|
|
y = h + y - control.height
|
|
elif y == 0:
|
|
y = h / 2 - control.height / 2
|
|
control.x = x
|
|
control.y = y
|
|
return
|
|
|
|
def open(self, modal=True):
|
|
self._modal = modal
|
|
if modal:
|
|
return self.obj.execute()
|
|
else:
|
|
self.visible = True
|
|
return
|
|
|
|
def close(self, value=0):
|
|
if self._modal:
|
|
value = self.obj.endDialog(value)
|
|
else:
|
|
self.visible = False
|
|
self.obj.dispose()
|
|
return value
|
|
|
|
def set_values(self, data):
|
|
for k, v in data.items():
|
|
self._controls[k].value = v
|
|
return
|
|
|
|
|
|
class LOCells(object):
|
|
|
|
def __getitem__(self, index):
|
|
return LODocs().active.active[index]
|
|
|
|
|
|
class LOWindow(object):
|
|
EMPTY = """<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE dlg:window PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "dialog.dtd">
|
|
<dlg:window xmlns:dlg="http://openoffice.org/2000/dialog" xmlns:script="http://openoffice.org/2000/script" dlg:id="empty" dlg:left="0" dlg:top="0" dlg:width="0" dlg:height="0" dlg:closeable="true" dlg:moveable="true" dlg:withtitlebar="false"/>"""
|
|
MODELS = {
|
|
'label': 'com.sun.star.awt.UnoControlFixedTextModel',
|
|
'link': 'com.sun.star.awt.UnoControlFixedHyperlinkModel',
|
|
'button': 'com.sun.star.awt.UnoControlButtonModel',
|
|
'radio': 'com.sun.star.awt.UnoControlRadioButtonModel',
|
|
'checkbox': 'com.sun.star.awt.UnoControlCheckBoxModel',
|
|
'text': 'com.sun.star.awt.UnoControlEditModel',
|
|
'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',
|
|
}
|
|
|
|
def __init__(self, args):
|
|
self._events = None
|
|
self._menu = None
|
|
self._container = None
|
|
self._model = None
|
|
self._id = ''
|
|
self._path = ''
|
|
self._obj = self._create(args)
|
|
|
|
def _create(self, properties):
|
|
ps = (
|
|
properties.get('X', 0),
|
|
properties.get('Y', 0),
|
|
properties.get('Width', 500),
|
|
properties.get('Height', 500),
|
|
)
|
|
self._title = properties.get('Title', TITLE)
|
|
self._create_frame(ps)
|
|
self._create_container(ps)
|
|
self._create_subcontainer(ps)
|
|
# ~ self._create_splitter(ps)
|
|
return
|
|
|
|
def _create_frame(self, ps):
|
|
service = 'com.sun.star.frame.TaskCreator'
|
|
tc = create_instance(service, True)
|
|
self._frame = tc.createInstanceWithArguments((
|
|
NamedValue('FrameName', 'EasyMacroWin'),
|
|
NamedValue('PosSize', Rectangle(*ps)),
|
|
))
|
|
self._window = self._frame.getContainerWindow()
|
|
self._toolkit = self._window.getToolkit()
|
|
desktop = get_desktop()
|
|
self._frame.setCreator(desktop)
|
|
desktop.getFrames().append(self._frame)
|
|
self._frame.Title = self._title
|
|
return
|
|
|
|
def _create_container(self, ps):
|
|
service = 'com.sun.star.awt.UnoControlContainer'
|
|
self._container = create_instance(service, True)
|
|
service = 'com.sun.star.awt.UnoControlContainerModel'
|
|
model = create_instance(service, True)
|
|
model.BackgroundColor = get_color((225, 225, 225))
|
|
self._container.setModel(model)
|
|
self._container.createPeer(self._toolkit, self._window)
|
|
self._container.setPosSize(*ps, POSSIZE)
|
|
self._frame.setComponent(self._container, None)
|
|
return
|
|
|
|
def _create_subcontainer(self, ps):
|
|
service = 'com.sun.star.awt.ContainerWindowProvider'
|
|
cwp = create_instance(service, True)
|
|
|
|
path_tmp = _P.save_tmp(self.EMPTY)
|
|
subcont = cwp.createContainerWindow(
|
|
_P.to_url(path_tmp), '', self._container.getPeer(), None)
|
|
_P.kill(path_tmp)
|
|
|
|
subcont.setPosSize(0, 0, 500, 500, POSSIZE)
|
|
subcont.setVisible(True)
|
|
self._container.addControl('subcont', subcont)
|
|
self._subcont = subcont
|
|
self._model = subcont.Model
|
|
return
|
|
|
|
def _create_popupmenu(self, menus):
|
|
menu = create_instance('com.sun.star.awt.PopupMenu', True)
|
|
for i, m in enumerate(menus):
|
|
label = m['label']
|
|
cmd = m.get('event', '')
|
|
if not cmd:
|
|
cmd = label.lower().replace(' ', '_')
|
|
if label == '-':
|
|
menu.insertSeparator(i)
|
|
else:
|
|
menu.insertItem(i, label, m.get('style', 0), i)
|
|
menu.setCommand(i, cmd)
|
|
# ~ menu.setItemImage(i, path?, True)
|
|
menu.addMenuListener(EventsMenu(self.events))
|
|
return menu
|
|
|
|
def _create_menu(self, menus):
|
|
#~ https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1XMenu.html
|
|
#~ nItemId specifies the ID of the menu item to be inserted.
|
|
#~ aText specifies the label of the menu item.
|
|
#~ nItemStyle 0 = Standard, CHECKABLE = 1, RADIOCHECK = 2, AUTOCHECK = 4
|
|
#~ nItemPos specifies the position where the menu item will be inserted.
|
|
self._menu = create_instance('com.sun.star.awt.MenuBar', True)
|
|
for i, m in enumerate(menus):
|
|
self._menu.insertItem(i, m['label'], m.get('style', 0), i)
|
|
cmd = m['label'].lower().replace(' ', '_')
|
|
self._menu.setCommand(i, cmd)
|
|
submenu = self._create_popupmenu(m['submenu'])
|
|
self._menu.setPopupMenu(i, submenu)
|
|
|
|
self._window.setMenuBar(self._menu)
|
|
return
|
|
|
|
def _add_listeners(self, control=None):
|
|
if self.events is None:
|
|
return
|
|
controller = EventsWindow(self)
|
|
self._window.addTopWindowListener(controller)
|
|
self._window.addWindowListener(controller)
|
|
# ~ self._container.addKeyListener(EventsKeyWindow(self))
|
|
return
|
|
|
|
def _set_image_url(self, image):
|
|
if _P.exists(image):
|
|
return _P.to_url(image)
|
|
|
|
path = _P.join(self._path, DIR['images'], image)
|
|
return _P.to_url(path)
|
|
|
|
def _special_properties(self, tipo, args):
|
|
if tipo == 'link' and not 'Label' in args:
|
|
args['Label'] = args['URL']
|
|
return args
|
|
|
|
if tipo == 'button':
|
|
if 'ImageURL' in args:
|
|
args['ImageURL'] = self._set_image_url(args['ImageURL'])
|
|
args['FocusOnClick'] = args.get('FocusOnClick', False)
|
|
return args
|
|
|
|
if tipo == 'roadmap':
|
|
args['Height'] = args.get('Height', self.height)
|
|
if 'Title' in args:
|
|
args['Text'] = args.pop('Title')
|
|
return args
|
|
|
|
if tipo == 'tree':
|
|
args['SelectionType'] = args.get('SelectionType', SINGLE)
|
|
return args
|
|
|
|
if tipo == 'grid':
|
|
args['ShowRowHeader'] = args.get('ShowRowHeader', True)
|
|
return args
|
|
|
|
if tipo == 'pages':
|
|
args['Width'] = args.get('Width', self.width)
|
|
args['Height'] = args.get('Height', self.height)
|
|
|
|
return args
|
|
|
|
def add_control(self, args):
|
|
tipo = args.pop('Type').lower()
|
|
root = args.pop('Root', '')
|
|
sheets = args.pop('Sheets', ())
|
|
columns = args.pop('Columns', ())
|
|
|
|
args = self._special_properties(tipo, args)
|
|
model = self.model.createInstance(self.MODELS[tipo])
|
|
_set_properties(model, args)
|
|
name = args['Name']
|
|
self.model.insertByName(name, model)
|
|
control = self._subcont.getControl(name)
|
|
_add_listeners(self.events, control, name)
|
|
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)
|
|
return control
|
|
|
|
@property
|
|
def events(self):
|
|
return self._events
|
|
@events.setter
|
|
def events(self, controllers):
|
|
self._events = controllers(self)
|
|
self._add_listeners()
|
|
|
|
@property
|
|
def model(self):
|
|
return self._model
|
|
|
|
@property
|
|
def width(self):
|
|
return self._container.Size.Width
|
|
|
|
@property
|
|
def height(self):
|
|
return self._container.Size.Height
|
|
|
|
@property
|
|
def name(self):
|
|
return self._title.lower().replace(' ', '_')
|
|
|
|
def add_menu(self, menus):
|
|
self._create_menu(menus)
|
|
return
|
|
|
|
def open(self):
|
|
self._window.setVisible(True)
|
|
return
|
|
|
|
def close(self):
|
|
self._window.setMenuBar(None)
|
|
self._window.dispose()
|
|
self._frame.close(True)
|
|
return
|
|
|
|
|
|
class LODBServer(object):
|
|
DRIVERS = {
|
|
'mysql': 'mysqlc',
|
|
'mariadb': 'mysqlc',
|
|
'postgres': 'postgresql:postgresql',
|
|
}
|
|
PORTS = {
|
|
'mysql': 3306,
|
|
'mariadb': 3306,
|
|
'postgres': 5432,
|
|
}
|
|
|
|
def __init__(self):
|
|
self._conn = None
|
|
self._error = 'Not connected'
|
|
self._type = ''
|
|
self._drivers = []
|
|
|
|
def __str__(self):
|
|
return f'DB type {self._type}'
|
|
|
|
def __enter__(self):
|
|
return self
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
self.disconnet()
|
|
|
|
@property
|
|
def is_connected(self):
|
|
return not self._conn is None
|
|
|
|
@property
|
|
def error(self):
|
|
return self._error
|
|
|
|
@property
|
|
def drivers(self):
|
|
return self._drivers
|
|
|
|
def disconnet(self):
|
|
if not self._conn is None:
|
|
if not self._conn.isClosed():
|
|
self._conn.close()
|
|
self._conn.dispose()
|
|
return
|
|
|
|
def connect(self, options={}):
|
|
args = options.copy()
|
|
self._error = ''
|
|
self._type = args.get('type', 'postgres')
|
|
driver = self.DRIVERS[self._type]
|
|
server = args.get('server', 'localhost')
|
|
port = args.get('port', self.PORTS[self._type])
|
|
dbname = args.get('dbname', '')
|
|
user = args['user']
|
|
password = args['password']
|
|
|
|
data = {'user': user, 'password': password}
|
|
url = f'sdbc:{driver}:{server}:{port}/{dbname}'
|
|
|
|
# ~ https://downloads.mariadb.com/Connectors/java/
|
|
# ~ data['JavaDriverClass'] = 'org.mariadb.jdbc.Driver'
|
|
# ~ url = f'jdbc:mysql://{server}:{port}/{dbname}'
|
|
|
|
args = dict_to_property(data)
|
|
manager = create_instance('com.sun.star.sdbc.DriverManager')
|
|
self._drivers = [d.ImplementationName for d in manager]
|
|
|
|
try:
|
|
self._conn = manager.getConnectionWithInfo(url, args)
|
|
except Exception as e:
|
|
error(e)
|
|
self._error = str(e)
|
|
|
|
return self
|
|
|
|
def execute(self, sql):
|
|
query = self._conn.createStatement()
|
|
try:
|
|
query.execute(sql)
|
|
result = True
|
|
except Exception as e:
|
|
error(e)
|
|
self._error = str(e)
|
|
result = False
|
|
|
|
return result
|
|
|
|
|
|
def create_window(args):
|
|
return LOWindow(args)
|
|
|
|
|
|
class Paths(object):
|
|
|
|
@classmethod
|
|
def image(cls, path):
|
|
# ~ sfa = create_instance('com.sun.star.ucb.SimpleFileAccess')
|
|
# ~ stream = sfa.openFileRead(cls.to_url(path))
|
|
gp = create_instance('com.sun.star.graphic.GraphicProvider')
|
|
if isinstance(path, str):
|
|
properties = (PropertyValue(Name='URL', Value=cls.to_url(path)),)
|
|
else:
|
|
properties = (PropertyValue(Name='InputStream', Value=path),)
|
|
image = gp.queryGraphic(properties)
|
|
return image
|
|
|
|
|
|
class IOStream(object):
|
|
|
|
@classmethod
|
|
def qr(cls, data, **kwargs):
|
|
import segno
|
|
|
|
kwargs['kind'] = kwargs.get('kind', 'svg')
|
|
kwargs['scale'] = kwargs.get('scale', 8)
|
|
kwargs['border'] = kwargs.get('border', 2)
|
|
buffer = cls.buffer()
|
|
segno.make(data).save(buffer, **kwargs)
|
|
stream = cls.input(buffer)
|
|
return stream
|
|
|
|
|
|
class SpellChecker(object):
|
|
|
|
def __init__(self):
|
|
service = 'com.sun.star.linguistic2.SpellChecker'
|
|
self._spellchecker = create_instance(service, True)
|
|
self._locale = LOCALE
|
|
|
|
@property
|
|
def locale(self):
|
|
slocal = f'{self._locale.Language}-{self._locale.Country}'
|
|
return slocale
|
|
@locale.setter
|
|
def locale(self, value):
|
|
lang = value.split('-')
|
|
self._locale = Locale(lang[0], lang[1], '')
|
|
|
|
def is_valid(self, word):
|
|
result = self._spellchecker.isValid(word, self._locale, ())
|
|
return result
|
|
|
|
def spell(self, word):
|
|
result = self._spellchecker.spell(word, self._locale, ())
|
|
if result:
|
|
result = result.getAlternatives()
|
|
if not isinstance(result, tuple):
|
|
result = ()
|
|
return result
|
|
|
|
|
|
def spell(word, locale=''):
|
|
sc = SpellChecker()
|
|
if locale:
|
|
sc.locale = locale
|
|
return sc.spell(word)
|
|
|
|
|
|
def __getattr__(name):
|
|
if name == 'current_region':
|
|
return LODocs().active.selection.current_region
|
|
if name in ('rectangle', 'pos_size'):
|
|
return Rectangle()
|
|
if name == 'db':
|
|
return LODBServer()
|
|
if name == 'cells':
|
|
return LOCells()
|
|
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
|
|
|
|
def create_dialog(args={}):
|
|
return LODialog(args)
|
|
|
|
|
|
def inputbox(message, default='', title=TITLE, echochar=''):
|
|
|
|
class ControllersInput(object):
|
|
|
|
def __init__(self, dlg):
|
|
self.d = dlg
|
|
|
|
def cmd_ok_action(self, event):
|
|
self.d.close(1)
|
|
return
|
|
|
|
args = {
|
|
'Title': title,
|
|
'Width': 200,
|
|
'Height': 80,
|
|
}
|
|
dlg = LODialog(args)
|
|
dlg.events = ControllersInput
|
|
|
|
args = {
|
|
'Type': 'Label',
|
|
'Name': 'lbl_msg',
|
|
'Label': message,
|
|
'Width': 140,
|
|
'Height': 50,
|
|
'X': 5,
|
|
'Y': 5,
|
|
'MultiLine': True,
|
|
'Border': 1,
|
|
}
|
|
dlg.add_control(args)
|
|
|
|
args = {
|
|
'Type': 'Text',
|
|
'Name': 'txt_value',
|
|
'Text': default,
|
|
'Width': 190,
|
|
'Height': 15,
|
|
}
|
|
if echochar:
|
|
args['EchoChar'] = ord(echochar[0])
|
|
dlg.add_control(args)
|
|
dlg.txt_value.move(dlg.lbl_msg)
|
|
|
|
args = {
|
|
'Type': 'button',
|
|
'Name': 'cmd_ok',
|
|
'Label': _('OK'),
|
|
'Width': 40,
|
|
'Height': 15,
|
|
'DefaultButton': True,
|
|
'PushButtonType': 1,
|
|
}
|
|
dlg.add_control(args)
|
|
dlg.cmd_ok.move(dlg.lbl_msg, 10, 0)
|
|
|
|
args = {
|
|
'Type': 'button',
|
|
'Name': 'cmd_cancel',
|
|
'Label': _('Cancel'),
|
|
'Width': 40,
|
|
'Height': 15,
|
|
'PushButtonType': 2,
|
|
}
|
|
dlg.add_control(args)
|
|
dlg.cmd_cancel.move(dlg.cmd_ok)
|
|
|
|
if dlg.open():
|
|
return dlg.txt_value.value
|
|
|
|
return ''
|