2019-09-07 00:02:59 -05:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
# == Rapid Develop Macros in LibreOffice ==
|
|
|
|
|
|
|
|
# ~ This file is part of ZAZ.
|
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
# ~ https://git.cuates.net/elmau/zaz
|
2020-12-16 21:50:11 -06:00
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
# ~ ZAZ is free software: you can redistribute it and/or modify
|
|
|
|
# ~ it under the terms of the GNU General Public License as published by
|
|
|
|
# ~ the Free Software Foundation, either version 3 of the License, or
|
|
|
|
# ~ (at your option) any later version.
|
|
|
|
|
|
|
|
# ~ ZAZ is distributed in the hope that it will be useful,
|
|
|
|
# ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# ~ GNU General Public License for more details.
|
|
|
|
|
|
|
|
# ~ You should have received a copy of the GNU General Public License
|
|
|
|
# ~ along with ZAZ. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
2019-09-27 12:17:21 -05:00
|
|
|
import base64
|
2019-10-12 20:16:00 -05:00
|
|
|
import csv
|
2019-09-14 17:40:07 -05:00
|
|
|
import datetime
|
2019-09-07 00:02:59 -05:00
|
|
|
import getpass
|
2020-12-16 21:50:11 -06:00
|
|
|
import gettext
|
2019-09-27 12:17:21 -05:00
|
|
|
import hashlib
|
2019-09-18 21:41:47 -05:00
|
|
|
import json
|
2019-09-07 00:02:59 -05:00
|
|
|
import logging
|
2019-09-09 22:13:01 -05:00
|
|
|
import os
|
2019-09-07 00:02:59 -05:00
|
|
|
import platform
|
2019-09-18 21:41:47 -05:00
|
|
|
import re
|
2019-09-11 23:53:29 -05:00
|
|
|
import shlex
|
2019-09-18 21:41:47 -05:00
|
|
|
import shutil
|
2019-10-05 11:14:19 -05:00
|
|
|
import socket
|
2019-11-26 23:32:39 -06:00
|
|
|
import ssl
|
2020-12-16 21:50:11 -06:00
|
|
|
import subprocess
|
2019-09-07 00:02:59 -05:00
|
|
|
import sys
|
2019-09-08 00:25:30 -05:00
|
|
|
import tempfile
|
2019-09-07 00:02:59 -05:00
|
|
|
import threading
|
|
|
|
import time
|
2019-09-27 12:17:21 -05:00
|
|
|
import traceback
|
2019-09-11 23:53:29 -05:00
|
|
|
import zipfile
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
from collections import OrderedDict
|
|
|
|
from collections.abc import MutableMapping
|
|
|
|
from decimal import Decimal
|
|
|
|
from enum import IntEnum
|
2019-09-07 00:02:59 -05:00
|
|
|
from functools import wraps
|
2020-12-16 21:50:11 -06:00
|
|
|
from pathlib import Path
|
2019-09-11 23:53:29 -05:00
|
|
|
from pprint import pprint
|
2020-12-16 21:50:11 -06:00
|
|
|
from string import Template
|
|
|
|
from typing import Any, Union
|
2019-10-19 20:01:04 -05:00
|
|
|
from urllib.request import Request, urlopen
|
|
|
|
from urllib.error import URLError, HTTPError
|
2019-09-07 00:02:59 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
import imaplib
|
2019-09-27 12:17:21 -05:00
|
|
|
import smtplib
|
|
|
|
from smtplib import SMTPException, SMTPAuthenticationError
|
|
|
|
from email.mime.multipart import MIMEMultipart
|
|
|
|
from email.mime.base import MIMEBase
|
|
|
|
from email.mime.text import MIMEText
|
|
|
|
from email.utils import formatdate
|
|
|
|
from email import encoders
|
|
|
|
import mailbox
|
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
import uno
|
2019-09-09 22:13:01 -05:00
|
|
|
import unohelper
|
2019-09-07 00:02:59 -05:00
|
|
|
from com.sun.star.awt import MessageBoxButtons as MSG_BUTTONS
|
|
|
|
from com.sun.star.awt.MessageBoxResults import YES
|
2020-12-16 21:50:11 -06:00
|
|
|
from com.sun.star.awt import Rectangle, Size, Point
|
2019-09-08 00:25:30 -05:00
|
|
|
from com.sun.star.awt.PosSize import POSSIZE, SIZE
|
2020-12-16 21:50:11 -06:00
|
|
|
from com.sun.star.awt import Key, KeyModifier, KeyEvent
|
|
|
|
from com.sun.star.container import NoSuchElementException
|
2019-09-14 17:40:07 -05:00
|
|
|
from com.sun.star.datatransfer import XTransferable, DataFlavor
|
2020-12-16 21:50:11 -06:00
|
|
|
|
|
|
|
from com.sun.star.beans import PropertyValue, NamedValue
|
|
|
|
from com.sun.star.sheet import TableFilterField
|
2019-09-08 00:25:30 -05:00
|
|
|
from com.sun.star.table.CellContentType import EMPTY, VALUE, TEXT, FORMULA
|
2020-12-16 21:50:11 -06:00
|
|
|
from com.sun.star.util import Time, Date, DateTime
|
2019-09-07 00:02:59 -05:00
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
|
2019-09-09 22:13:01 -05:00
|
|
|
from com.sun.star.text.TextContentAnchorType import AS_CHARACTER
|
|
|
|
|
|
|
|
from com.sun.star.awt import XActionListener
|
2020-12-16 21:50:11 -06:00
|
|
|
from com.sun.star.lang import XEventListener
|
|
|
|
from com.sun.star.awt import XMenuListener
|
2019-09-09 22:13:01 -05:00
|
|
|
from com.sun.star.awt import XMouseListener
|
2019-10-10 00:07:45 -05:00
|
|
|
from com.sun.star.awt import XMouseMotionListener
|
2020-12-16 21:50:11 -06:00
|
|
|
from com.sun.star.awt import XFocusListener
|
2019-10-10 00:07:45 -05:00
|
|
|
from com.sun.star.awt import XKeyListener
|
2019-10-14 19:48:13 -05:00
|
|
|
from com.sun.star.awt import XItemListener
|
2019-10-29 11:23:24 -06:00
|
|
|
from com.sun.star.awt import XTabListener
|
2020-12-16 21:50:11 -06:00
|
|
|
from com.sun.star.awt import XWindowListener
|
|
|
|
from com.sun.star.awt import XTopWindowListener
|
2019-10-29 11:23:24 -06:00
|
|
|
from com.sun.star.awt.grid import XGridDataListener
|
|
|
|
from com.sun.star.awt.grid import XGridSelectionListener
|
2020-12-16 21:50:11 -06:00
|
|
|
from com.sun.star.script import ScriptEventDescriptor
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ 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
|
2019-10-14 19:48:13 -05:00
|
|
|
|
2019-09-27 12:17:21 -05:00
|
|
|
try:
|
2020-12-16 21:50:11 -06:00
|
|
|
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__)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ You can get custom salt
|
|
|
|
# ~ codecs.encode(os.urandom(16), 'hex')
|
2020-12-16 22:13:40 -06:00
|
|
|
# ~ but, not modify this file, modify in import file
|
2020-12-16 21:50:11 -06:00
|
|
|
SALT = b'c9548699d4e432dfd2b46adddafbb06d'
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
TIMEOUT = 10
|
|
|
|
LOG_NAME = 'ZAZ'
|
|
|
|
FILE_NAME_CONFIG = 'zaz-{}.json'
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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',
|
|
|
|
BASE: 'com.sun.star.sdb.DocumentDataSource',
|
|
|
|
MATH: 'com.sun.star.formula.FormulaProperties',
|
|
|
|
BASIC: 'com.sun.star.script.BasicIDE',
|
|
|
|
MAIN: 'com.sun.star.frame.StartModule',
|
2019-10-19 20:01:04 -05:00
|
|
|
}
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
OBJ_CELL = 'ScCellObj'
|
|
|
|
OBJ_RANGE = 'ScCellRangeObj'
|
|
|
|
OBJ_RANGES = 'ScCellRangesObj'
|
|
|
|
TYPE_RANGES = (OBJ_CELL, OBJ_RANGE, OBJ_RANGES)
|
|
|
|
|
|
|
|
OBJ_SHAPES = 'com.sun.star.drawing.SvxShapeCollection'
|
|
|
|
OBJ_SHAPE = 'com.sun.star.comp.sc.ScShapeObj'
|
|
|
|
OBJ_GRAPHIC = 'SwXTextGraphicObject'
|
|
|
|
|
|
|
|
OBJ_TEXTS = 'SwXTextRanges'
|
|
|
|
OBJ_TEXT = 'SwXTextRange'
|
|
|
|
|
|
|
|
|
|
|
|
# ~ 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
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
|
2019-09-11 23:53:29 -05:00
|
|
|
OS = platform.system()
|
2020-12-16 21:50:11 -06:00
|
|
|
IS_WIN = OS == 'Windows'
|
|
|
|
IS_MAC = OS == 'Darwin'
|
2019-09-10 22:20:31 -05:00
|
|
|
USER = getpass.getuser()
|
|
|
|
PC = platform.node()
|
2019-09-14 17:40:07 -05:00
|
|
|
DESKTOP = os.environ.get('DESKTOP_SESSION', '')
|
2020-12-16 21:50:11 -06:00
|
|
|
INFO_DEBUG = f"{sys.version}\n\n{platform.platform()}\n\n" + '\n'.join(sys.path)
|
2019-09-11 23:53:29 -05:00
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
PYTHON = 'python'
|
|
|
|
if IS_WIN:
|
|
|
|
PYTHON = 'python.exe'
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
_MACROS = {}
|
|
|
|
_start = 0
|
2019-11-26 23:32:39 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
SECONDS_DAY = 60 * 60 * 24
|
|
|
|
DIR = {
|
|
|
|
'images': 'images',
|
|
|
|
'locales': 'locales',
|
|
|
|
}
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
KEY = {
|
|
|
|
'enter': 1280,
|
|
|
|
}
|
2019-11-26 23:32:39 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
MODIFIERS = {
|
|
|
|
'shift': KeyModifier.SHIFT,
|
|
|
|
'ctrl': KeyModifier.MOD1,
|
|
|
|
'alt': KeyModifier.MOD2,
|
|
|
|
'ctrlmac': KeyModifier.MOD3,
|
2019-09-18 21:41:47 -05:00
|
|
|
}
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ Menus
|
2019-09-18 21:41:47 -05:00
|
|
|
NODE_MENUBAR = 'private:resource/menubar/menubar'
|
2020-12-16 21:50:11 -06:00
|
|
|
MENUS = {
|
2019-10-19 20:01:04 -05:00
|
|
|
'file': '.uno:PickList',
|
|
|
|
'tools': '.uno:ToolsMenu',
|
|
|
|
'help': '.uno:HelpMenu',
|
2020-12-16 21:50:11 -06:00
|
|
|
'windows': '.uno:WindowList',
|
2019-09-18 21:41:47 -05:00
|
|
|
'edit': '.uno:EditMenu',
|
|
|
|
'view': '.uno:ViewMenu',
|
|
|
|
'insert': '.uno:InsertMenu',
|
|
|
|
'format': '.uno:FormatMenu',
|
|
|
|
'styles': '.uno:FormatStylesMenu',
|
|
|
|
'sheet': '.uno:SheetMenu',
|
|
|
|
'data': '.uno:DataMenu',
|
2020-12-16 21:50:11 -06:00
|
|
|
'table': '.uno:TableMenu',
|
|
|
|
'form': '.uno:FormatFormMenu',
|
|
|
|
'page': '.uno:PageMenu',
|
|
|
|
'shape': '.uno:ShapeMenu',
|
|
|
|
'slide': '.uno:SlideMenu',
|
|
|
|
'show': '.uno:SlideShowMenu',
|
2019-09-18 21:41:47 -05:00
|
|
|
}
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
DEFAULT_MIME_TYPE = 'png'
|
|
|
|
MIME_TYPE = {
|
|
|
|
'png': 'image/png',
|
|
|
|
'jpg': 'image/jpeg',
|
2019-09-27 12:17:21 -05:00
|
|
|
}
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
MESSAGES = {
|
|
|
|
'es': {
|
|
|
|
'OK': 'Aceptar',
|
|
|
|
'Cancel': 'Cancelar',
|
|
|
|
'Select path': 'Seleccionar ruta',
|
|
|
|
'Select directory': 'Seleccionar directorio',
|
|
|
|
'Select file': 'Seleccionar archivo',
|
|
|
|
'Incorrect user or password': 'Nombre de usuario o contraseƱa invƔlidos',
|
|
|
|
'Allow less secure apps in GMail': 'Activa: Permitir aplicaciones menos segura en GMail',
|
|
|
|
}
|
|
|
|
}
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
CTX = uno.getComponentContext()
|
|
|
|
SM = CTX.getServiceManager()
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def create_instance(name: str, with_context: bool=False, args: Any=None) -> Any:
|
2019-09-07 00:02:59 -05:00
|
|
|
if with_context:
|
|
|
|
instance = SM.createInstanceWithContext(name, CTX)
|
2020-12-16 21:50:11 -06:00
|
|
|
elif args:
|
|
|
|
instance = SM.createInstanceWithArguments(name, (args,))
|
2019-09-07 00:02:59 -05:00
|
|
|
else:
|
|
|
|
instance = SM.createInstance(name)
|
|
|
|
return instance
|
|
|
|
|
|
|
|
|
2021-01-03 20:57:19 -06:00
|
|
|
def get_app_config(node_name: str, key: str=''):
|
2019-09-07 00:02:59 -05:00
|
|
|
name = 'com.sun.star.configuration.ConfigurationProvider'
|
|
|
|
service = 'com.sun.star.configuration.ConfigurationAccess'
|
|
|
|
cp = create_instance(name, True)
|
|
|
|
node = PropertyValue(Name='nodepath', Value=node_name)
|
|
|
|
try:
|
|
|
|
ca = cp.createInstanceWithArguments(service, (node,))
|
2019-10-05 11:14:19 -05:00
|
|
|
if ca and not key:
|
|
|
|
return ca
|
|
|
|
if ca and ca.hasByName(key):
|
|
|
|
return ca.getPropertyValue(key)
|
2019-09-07 00:02:59 -05:00
|
|
|
except Exception as e:
|
2019-10-05 11:14:19 -05:00
|
|
|
error(e)
|
2019-09-07 00:02:59 -05:00
|
|
|
return ''
|
|
|
|
|
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
LANGUAGE = get_app_config('org.openoffice.Setup/L10N/', 'ooLocale')
|
2019-09-14 17:40:07 -05:00
|
|
|
LANG = LANGUAGE.split('-')[0]
|
2019-10-12 20:16:00 -05:00
|
|
|
NAME = TITLE = get_app_config('org.openoffice.Setup/Product', 'ooName')
|
|
|
|
VERSION = get_app_config('org.openoffice.Setup/Product','ooSetupVersion')
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
INFO_DEBUG = f"{NAME} v{VERSION} {LANGUAGE}\n\n{INFO_DEBUG}"
|
|
|
|
|
|
|
|
node = '/org.openoffice.Office.Calc/Calculate/Other/Date'
|
|
|
|
y = get_app_config(node, 'YY')
|
|
|
|
m = get_app_config(node, 'MM')
|
|
|
|
d = get_app_config(node, 'DD')
|
2019-10-12 20:16:00 -05:00
|
|
|
DATE_OFFSET = datetime.date(y, m, d).toordinal()
|
2019-09-07 00:02:59 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def error(info):
|
|
|
|
log.error(info)
|
|
|
|
return
|
2019-09-07 00:02:59 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
|
|
|
|
def debug(*args):
|
|
|
|
data = [str(a) for a in args]
|
|
|
|
log.debug('\t'.join(data))
|
2019-09-07 00:02:59 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def info(*args):
|
|
|
|
data = [str(a) for a in args]
|
|
|
|
log.info('\t'.join(data))
|
|
|
|
return
|
|
|
|
|
|
|
|
|
2021-01-03 20:57:19 -06:00
|
|
|
def save_log(path: str, data):
|
2020-12-16 21:50:11 -06:00
|
|
|
with open(path, 'a') as f:
|
|
|
|
f.write(f'{str(now())[:19]} -{LOG_NAME}- ')
|
|
|
|
pprint(data, stream=f)
|
2019-11-26 23:32:39 -06:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
def catch_exception(f):
|
|
|
|
@wraps(f)
|
|
|
|
def func(*args, **kwargs):
|
|
|
|
try:
|
|
|
|
return f(*args, **kwargs)
|
|
|
|
except Exception as e:
|
2019-09-27 12:17:21 -05:00
|
|
|
name = f.__name__
|
|
|
|
if IS_WIN:
|
2020-12-16 21:50:11 -06:00
|
|
|
msgbox(traceback.format_exc())
|
2019-09-27 12:17:21 -05:00
|
|
|
log.error(name, exc_info=True)
|
2019-09-07 00:02:59 -05:00
|
|
|
return func
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def inspect(obj: Any) -> None:
|
|
|
|
zaz = create_instance('net.elmau.zaz.inspect')
|
|
|
|
if hasattr(obj, 'obj'):
|
|
|
|
obj = obj.obj
|
|
|
|
zaz.inspect(obj)
|
2019-09-11 23:53:29 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2021-01-03 20:57:19 -06:00
|
|
|
def mri(obj: Any) -> None:
|
2020-12-16 21:50:11 -06:00
|
|
|
m = create_instance('mytools.Mri')
|
|
|
|
if m is None:
|
|
|
|
msg = 'Extension MRI not found'
|
|
|
|
error(msg)
|
2019-09-11 23:53:29 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
m.inspect(obj)
|
2019-09-11 23:53:29 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
def run_in_thread(fn):
|
|
|
|
def run(*k, **kw):
|
|
|
|
t = threading.Thread(target=fn, args=k, kwargs=kw)
|
|
|
|
t.start()
|
|
|
|
return t
|
|
|
|
return run
|
|
|
|
|
|
|
|
|
2021-01-03 20:57:19 -06:00
|
|
|
def now(only_time: bool=False):
|
2019-10-23 23:09:23 -05:00
|
|
|
now = datetime.datetime.now()
|
|
|
|
if only_time:
|
2020-12-16 21:50:11 -06:00
|
|
|
now = now.time()
|
2019-10-23 23:09:23 -05:00
|
|
|
return now
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
def today():
|
|
|
|
return datetime.date.today()
|
|
|
|
|
|
|
|
|
2019-09-07 00:02:59 -05:00
|
|
|
def _(msg):
|
2020-12-16 21:50:11 -06:00
|
|
|
if LANG == 'en':
|
2019-09-07 00:02:59 -05:00
|
|
|
return msg
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if not LANG in MESSAGES:
|
2019-09-07 00:02:59 -05:00
|
|
|
return msg
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return MESSAGES[LANG][msg]
|
2019-09-07 00:02:59 -05:00
|
|
|
|
|
|
|
|
|
|
|
def msgbox(message, title=TITLE, buttons=MSG_BUTTONS.BUTTONS_OK, type_msg='infobox'):
|
|
|
|
""" Create message box
|
|
|
|
type_msg: infobox, warningbox, errorbox, querybox, messbox
|
|
|
|
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1awt_1_1XMessageBoxFactory.html
|
|
|
|
"""
|
|
|
|
toolkit = create_instance('com.sun.star.awt.Toolkit')
|
|
|
|
parent = toolkit.getDesktopWindow()
|
2020-12-16 21:50:11 -06:00
|
|
|
box = toolkit.createMessageBox(parent, type_msg, buttons, title, str(message))
|
|
|
|
return box.execute()
|
2019-09-07 00:02:59 -05:00
|
|
|
|
|
|
|
|
|
|
|
def question(message, title=TITLE):
|
2020-12-16 21:50:11 -06:00
|
|
|
result = msgbox(message, title, MSG_BUTTONS.BUTTONS_YES_NO, 'querybox')
|
|
|
|
return result == YES
|
2019-09-07 00:02:59 -05:00
|
|
|
|
|
|
|
|
|
|
|
def warning(message, title=TITLE):
|
|
|
|
return msgbox(message, title, type_msg='warningbox')
|
|
|
|
|
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
def errorbox(message, title=TITLE):
|
2019-09-07 00:02:59 -05:00
|
|
|
return msgbox(message, title, type_msg='errorbox')
|
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_type_doc(obj: Any) -> str:
|
2019-09-18 21:41:47 -05:00
|
|
|
for k, v in TYPE_DOC.items():
|
2019-09-09 22:13:01 -05:00
|
|
|
if obj.supportsService(v):
|
|
|
|
return k
|
|
|
|
return ''
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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 dict_to_property(values: dict, uno_any: bool=False):
|
2019-09-18 21:41:47 -05:00
|
|
|
ps = tuple([PropertyValue(Name=n, Value=v) for n, v in values.items()])
|
|
|
|
if uno_any:
|
|
|
|
ps = uno.Any('[]com.sun.star.beans.PropertyValue', ps)
|
|
|
|
return ps
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _array_to_dict(values):
|
|
|
|
d = {v[0]: v[1] for v in values}
|
|
|
|
return d
|
2019-11-26 23:32:39 -06:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _property_to_dict(values):
|
|
|
|
d = {v.Name: v.Value for v in values}
|
2019-09-18 21:41:47 -05:00
|
|
|
return d
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def json_dumps(data):
|
|
|
|
return json.dumps(data, indent=4, sort_keys=True)
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def json_loads(data):
|
|
|
|
return json.loads(data)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def data_to_dict(data):
|
|
|
|
if isinstance(data, tuple) and isinstance(data[0], tuple):
|
|
|
|
return _array_to_dict(data)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if isinstance(data, tuple) and isinstance(data[0], (PropertyValue, NamedValue)):
|
|
|
|
return _property_to_dict(data)
|
|
|
|
return {}
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _get_dispatch() -> Any:
|
|
|
|
return create_instance('com.sun.star.frame.DispatchHelper')
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ https://wiki.documentfoundation.org/Development/DispatchCommands
|
|
|
|
# ~ Used only if not exists in API
|
|
|
|
def call_dispatch(frame: Any, url: str, args: dict={}) -> None:
|
|
|
|
dispatch = _get_dispatch()
|
|
|
|
opt = dict_to_property(args)
|
|
|
|
dispatch.executeDispatch(frame, url, '', 0, opt)
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_desktop():
|
|
|
|
return create_instance('com.sun.star.frame.Desktop', True)
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
|
2021-01-03 20:57:19 -06:00
|
|
|
def _get_url_script(args: dict):
|
2020-12-16 21:50:11 -06:00
|
|
|
library = args['library']
|
|
|
|
module = '.'
|
|
|
|
name = args['name']
|
|
|
|
language = args.get('language', 'Python')
|
|
|
|
location = args.get('location', 'user')
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if language == 'Python':
|
|
|
|
module = '.py$'
|
|
|
|
elif language == 'Basic':
|
|
|
|
module = f".{module}."
|
|
|
|
if location == 'user':
|
|
|
|
location = 'application'
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
url = 'vnd.sun.star.script'
|
|
|
|
url = f'{url}:{library}{module}{name}?language={language}&location={location}'
|
|
|
|
return url
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
|
2021-01-03 20:57:19 -06:00
|
|
|
def _call_macro(args: dict):
|
2020-12-16 21:50:11 -06:00
|
|
|
#~ https://wiki.openoffice.org/wiki/Documentation/DevGuide/Scripting/Scripting_Framework_URI_Specification
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
url = _get_url_script(args)
|
|
|
|
args = args.get('args', ())
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
service = 'com.sun.star.script.provider.MasterScriptProviderFactory'
|
|
|
|
factory = create_instance(service)
|
|
|
|
script = factory.createScriptProvider('').getScript(url)
|
|
|
|
result = script.invoke(args, None, None)[0]
|
2019-10-13 23:44:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return result
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-09-14 17:40:07 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def call_macro(args, in_thread=False):
|
|
|
|
result = None
|
|
|
|
if in_thread:
|
|
|
|
t = threading.Thread(target=_call_macro, args=(args,))
|
|
|
|
t.start()
|
|
|
|
else:
|
|
|
|
result = _call_macro(args)
|
|
|
|
return result
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def run(command, capture=False, split=True):
|
|
|
|
if not split:
|
|
|
|
return subprocess.check_output(command, shell=True).decode()
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
cmd = shlex.split(command)
|
|
|
|
result = subprocess.run(cmd, capture_output=capture, text=True, shell=IS_WIN)
|
|
|
|
if capture:
|
|
|
|
result = result.stdout
|
|
|
|
else:
|
|
|
|
result = result.returncode
|
|
|
|
return result
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def popen(command):
|
|
|
|
try:
|
|
|
|
proc = subprocess.Popen(shlex.split(command), shell=IS_WIN,
|
|
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
|
|
|
for line in proc.stdout:
|
|
|
|
yield line.decode().rstrip()
|
|
|
|
except Exception as e:
|
|
|
|
error(e)
|
|
|
|
yield (e.errno, e.strerror)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def sleep(seconds):
|
|
|
|
time.sleep(seconds)
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class TimerThread(threading.Thread):
|
2019-09-11 23:53:29 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, event, seconds, macro):
|
|
|
|
threading.Thread.__init__(self)
|
|
|
|
self.stopped = event
|
|
|
|
self.seconds = seconds
|
|
|
|
self.macro = macro
|
2019-09-10 22:20:31 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def run(self):
|
|
|
|
info('Timer started... {}'.format(self.macro['name']))
|
|
|
|
while not self.stopped.wait(self.seconds):
|
|
|
|
_call_macro(self.macro)
|
|
|
|
info('Timer stopped... {}'.format(self.macro['name']))
|
2019-09-11 23:53:29 -05:00
|
|
|
return
|
|
|
|
|
2019-09-14 17:40:07 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def start_timer(name, seconds, macro):
|
|
|
|
global _MACROS
|
|
|
|
_MACROS[name] = threading.Event()
|
|
|
|
thread = TimerThread(_MACROS[name], seconds, macro)
|
|
|
|
thread.start()
|
|
|
|
return
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def stop_timer(name):
|
|
|
|
global _MACROS
|
|
|
|
_MACROS[name].set()
|
|
|
|
del _MACROS[name]
|
|
|
|
return
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2021-01-03 20:59:46 -06:00
|
|
|
def install_locales(path: str, domain: str='base', dir_locales=DIR['locales']):
|
2020-12-16 21:50:11 -06:00
|
|
|
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 _
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def sha256(data):
|
|
|
|
result = hashlib.sha256(data.encode()).hexdigest()
|
|
|
|
return result
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def sha512(data):
|
|
|
|
result = hashlib.sha512(data.encode()).hexdigest()
|
|
|
|
return result
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_config(key='', default={}, prefix='conf'):
|
|
|
|
name_file = FILE_NAME_CONFIG.format(prefix)
|
|
|
|
values = None
|
|
|
|
path = _P.join(_P.config('UserConfig'), name_file)
|
|
|
|
if not _P.exists(path):
|
|
|
|
return default
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
values = _P.from_json(path)
|
|
|
|
if key:
|
|
|
|
values = values.get(key, default)
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return values
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def set_config(key, value, prefix='conf'):
|
|
|
|
name_file = FILE_NAME_CONFIG.format(prefix)
|
|
|
|
path = _P.join(_P.config('UserConfig'), name_file)
|
|
|
|
values = get_config(default={}, prefix=prefix)
|
|
|
|
values[key] = value
|
|
|
|
result = _P.to_json(path, values)
|
|
|
|
return result
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def start():
|
|
|
|
global _start
|
|
|
|
_start = now()
|
|
|
|
info(_start)
|
|
|
|
return
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
|
2021-01-03 20:59:46 -06:00
|
|
|
def end(get_seconds: bool=False):
|
2020-12-16 21:50:11 -06:00
|
|
|
global _start
|
|
|
|
e = now()
|
|
|
|
td = e - _start
|
|
|
|
result = str(td)
|
|
|
|
if get_seconds:
|
|
|
|
result = td.total_seconds()
|
|
|
|
return result
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_epoch():
|
|
|
|
n = now()
|
|
|
|
return int(time.mktime(n.timetuple()))
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def render(template, data):
|
|
|
|
s = Template(template)
|
|
|
|
return s.safe_substitute(**data)
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_size_screen():
|
|
|
|
if IS_WIN:
|
|
|
|
user32 = ctypes.windll.user32
|
|
|
|
res = f'{user32.GetSystemMetrics(0)}x{user32.GetSystemMetrics(1)}'
|
|
|
|
else:
|
|
|
|
args = 'xrandr | grep "*" | cut -d " " -f4'
|
|
|
|
res = run(args, split=False)
|
|
|
|
return res.strip()
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def url_open(url, data=None, headers={}, verify=True, get_json=False):
|
|
|
|
err = ''
|
|
|
|
req = Request(url)
|
|
|
|
for k, v in headers.items():
|
|
|
|
req.add_header(k, v)
|
|
|
|
try:
|
|
|
|
# ~ debug(url)
|
|
|
|
if verify:
|
|
|
|
if not data is None and isinstance(data, str):
|
|
|
|
data = data.encode()
|
|
|
|
response = urlopen(req, data=data)
|
|
|
|
else:
|
|
|
|
context = ssl._create_unverified_context()
|
|
|
|
response = urlopen(req, context=context)
|
|
|
|
except HTTPError as e:
|
|
|
|
error(e)
|
|
|
|
err = str(e)
|
|
|
|
except URLError as e:
|
|
|
|
error(e.reason)
|
|
|
|
err = str(e.reason)
|
|
|
|
else:
|
|
|
|
headers = dict(response.info())
|
|
|
|
result = response.read()
|
|
|
|
if get_json:
|
|
|
|
result = json.loads(result)
|
|
|
|
|
|
|
|
return result, headers, err
|
|
|
|
|
|
|
|
|
|
|
|
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 SmtpServer(object):
|
|
|
|
|
|
|
|
def __init__(self, config):
|
|
|
|
self._server = None
|
|
|
|
self._error = ''
|
|
|
|
self._sender = ''
|
|
|
|
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):
|
|
|
|
name = config['server']
|
|
|
|
port = config['port']
|
|
|
|
is_ssl = config['ssl']
|
|
|
|
self._sender = config['user']
|
|
|
|
hosts = ('gmail' in name or 'outlook' in name)
|
|
|
|
try:
|
|
|
|
if is_ssl and hosts:
|
|
|
|
self._server = smtplib.SMTP(name, port, timeout=TIMEOUT)
|
|
|
|
self._server.ehlo()
|
|
|
|
self._server.starttls()
|
|
|
|
self._server.ehlo()
|
|
|
|
elif is_ssl:
|
|
|
|
self._server = smtplib.SMTP_SSL(name, port, timeout=TIMEOUT)
|
|
|
|
self._server.ehlo()
|
|
|
|
else:
|
|
|
|
self._server = smtplib.SMTP(name, port, timeout=TIMEOUT)
|
|
|
|
|
|
|
|
self._server.login(self._sender, config['password'])
|
|
|
|
msg = 'Connect to: {}'.format(name)
|
|
|
|
debug(msg)
|
|
|
|
return True
|
|
|
|
except smtplib.SMTPAuthenticationError as e:
|
|
|
|
if '535' in str(e):
|
|
|
|
self._error = _('Incorrect user or password')
|
|
|
|
return False
|
|
|
|
if '534' in str(e) and 'gmail' in name:
|
|
|
|
self._error = _('Allow less secure apps in GMail')
|
|
|
|
return False
|
|
|
|
except smtplib.SMTPException as e:
|
|
|
|
self._error = str(e)
|
|
|
|
return False
|
|
|
|
except Exception as e:
|
|
|
|
self._error = str(e)
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _body(self, msg):
|
|
|
|
body = msg.replace('\\n', '<BR>')
|
|
|
|
return body
|
|
|
|
|
|
|
|
def send(self, message):
|
|
|
|
file_name = 'attachment; filename={}'
|
|
|
|
email = MIMEMultipart()
|
|
|
|
email['From'] = self._sender
|
|
|
|
email['To'] = message['to']
|
|
|
|
email['Cc'] = message.get('cc', '')
|
|
|
|
email['Subject'] = message['subject']
|
|
|
|
email['Date'] = formatdate(localtime=True)
|
|
|
|
if message.get('confirm', False):
|
|
|
|
email['Disposition-Notification-To'] = email['From']
|
|
|
|
email.attach(MIMEText(self._body(message['body']), 'html'))
|
|
|
|
|
|
|
|
for path in message.get('files', ()):
|
|
|
|
fn = _P(path).file_name
|
|
|
|
part = MIMEBase('application', 'octet-stream')
|
|
|
|
part.set_payload(_P.read_bin(path))
|
|
|
|
encoders.encode_base64(part)
|
|
|
|
part.add_header('Content-Disposition', f'attachment; filename={fn}')
|
|
|
|
email.attach(part)
|
|
|
|
|
|
|
|
receivers = (
|
|
|
|
email['To'].split(',') +
|
|
|
|
email['CC'].split(',') +
|
|
|
|
message.get('bcc', '').split(','))
|
|
|
|
try:
|
|
|
|
self._server.sendmail(self._sender, receivers, email.as_string())
|
|
|
|
msg = 'Email sent...'
|
|
|
|
debug(msg)
|
|
|
|
if message.get('path', ''):
|
|
|
|
self.save_message(email, message['path'])
|
|
|
|
return True
|
|
|
|
except Exception as e:
|
|
|
|
self._error = str(e)
|
|
|
|
return False
|
|
|
|
return False
|
|
|
|
|
|
|
|
def save_message(self, email, path):
|
|
|
|
mbox = mailbox.mbox(path, create=True)
|
|
|
|
mbox.lock()
|
|
|
|
try:
|
|
|
|
msg = mailbox.mboxMessage(email)
|
|
|
|
mbox.add(msg)
|
|
|
|
mbox.flush()
|
|
|
|
finally:
|
|
|
|
mbox.unlock()
|
|
|
|
return
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
try:
|
|
|
|
self._server.quit()
|
|
|
|
msg = 'Close connection...'
|
|
|
|
debug(msg)
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
def _send_email(server, messages):
|
|
|
|
with SmtpServer(server) as server:
|
|
|
|
if server.is_connect:
|
|
|
|
for msg in messages:
|
|
|
|
server.send(msg)
|
|
|
|
else:
|
|
|
|
error(server.error)
|
|
|
|
return server.error
|
|
|
|
|
|
|
|
|
|
|
|
def send_email(server, message):
|
|
|
|
messages = message
|
|
|
|
if isinstance(message, dict):
|
|
|
|
messages = (message,)
|
|
|
|
t = threading.Thread(target=_send_email, args=(server, messages))
|
|
|
|
t.start()
|
|
|
|
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 LODocument(object):
|
|
|
|
FILTERS = {
|
|
|
|
'doc': 'MS Word 97',
|
|
|
|
'docx': 'MS Word 2007 XML',
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
self._obj = obj
|
|
|
|
self._cc = self.obj.getCurrentController()
|
|
|
|
self._undo = True
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
|
|
self.close()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def title(self):
|
|
|
|
return self.obj.getTitle()
|
|
|
|
@title.setter
|
|
|
|
def title(self, value):
|
|
|
|
self.obj.setTitle(value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
return self._type
|
|
|
|
|
|
|
|
@property
|
|
|
|
def uid(self):
|
|
|
|
return self.obj.RuntimeUID
|
|
|
|
|
|
|
|
@property
|
|
|
|
def frame(self):
|
|
|
|
return self._cc.getFrame()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_saved(self):
|
|
|
|
return self.obj.hasLocation()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_modified(self):
|
|
|
|
return self.obj.isModified()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_read_only(self):
|
|
|
|
return self.obj.isReadOnly()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def path(self):
|
|
|
|
return _P.to_system(self.obj.URL)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def dir(self):
|
|
|
|
return _P(self.path).path
|
|
|
|
|
|
|
|
@property
|
|
|
|
def file_name(self):
|
|
|
|
return _P(self.path).file_name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return _P(self.path).name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def status_bar(self):
|
|
|
|
return self._cc.getStatusIndicator()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def visible(self):
|
|
|
|
w = self.frame.ContainerWindow
|
|
|
|
return w.isVisible()
|
|
|
|
@visible.setter
|
|
|
|
def visible(self, value):
|
|
|
|
w = self.frame.ContainerWindow
|
|
|
|
w.setVisible(value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def zoom(self):
|
|
|
|
return self._cc.ZoomValue
|
|
|
|
@zoom.setter
|
|
|
|
def zoom(self, value):
|
|
|
|
self._cc.ZoomValue = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def undo(self):
|
|
|
|
return self._undo
|
|
|
|
@undo.setter
|
|
|
|
def undo(self, value):
|
|
|
|
self._undo = value
|
|
|
|
um = self.obj.UndoManager
|
|
|
|
if value:
|
|
|
|
try:
|
|
|
|
um.leaveUndoContext()
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
um.enterHiddenUndoContext()
|
|
|
|
|
|
|
|
def clear_undo(self):
|
|
|
|
self.obj.getUndoManager().clear()
|
|
|
|
return
|
|
|
|
|
|
|
|
@property
|
|
|
|
def selection(self):
|
|
|
|
sel = self.obj.CurrentSelection
|
|
|
|
# ~ return _get_class_uno(sel)
|
|
|
|
return sel
|
|
|
|
|
|
|
|
@property
|
|
|
|
def table_auto_formats(self):
|
|
|
|
taf = create_instance('com.sun.star.sheet.TableAutoFormats')
|
|
|
|
return taf.ElementNames
|
|
|
|
|
|
|
|
def create_instance(self, name):
|
|
|
|
obj = self.obj.createInstance(name)
|
|
|
|
return obj
|
|
|
|
|
|
|
|
def set_focus(self):
|
|
|
|
w = self.frame.ComponentWindow
|
|
|
|
w.setFocus()
|
|
|
|
return
|
|
|
|
|
|
|
|
def copy(self):
|
|
|
|
call_dispatch(self.frame, '.uno:Copy')
|
|
|
|
return
|
|
|
|
|
|
|
|
def insert_contents(self, args={}):
|
|
|
|
call_dispatch(self.frame, '.uno:InsertContents', args)
|
|
|
|
return
|
|
|
|
|
|
|
|
def paste(self):
|
|
|
|
sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
|
|
|
|
transferable = sc.getContents()
|
|
|
|
self._cc.insertTransferable(transferable)
|
|
|
|
# ~ return self.obj.getCurrentSelection()
|
|
|
|
return
|
|
|
|
|
|
|
|
def select(self, obj):
|
|
|
|
self._cc.select(obj)
|
|
|
|
return
|
|
|
|
|
|
|
|
def to_pdf(self, path: str='', args: dict={}):
|
2021-02-01 23:00:51 -06:00
|
|
|
"""
|
|
|
|
https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data
|
|
|
|
"""
|
2020-12-16 21:50:11 -06:00
|
|
|
path_pdf = path
|
|
|
|
filter_name = '{}_pdf_Export'.format(self.type)
|
|
|
|
filter_data = dict_to_property(args, True)
|
|
|
|
args = {
|
|
|
|
'FilterName': filter_name,
|
|
|
|
'FilterData': filter_data,
|
|
|
|
}
|
|
|
|
opt = dict_to_property(args)
|
|
|
|
try:
|
|
|
|
self.obj.storeToURL(_P.to_url(path), opt)
|
|
|
|
except Exception as e:
|
|
|
|
error(e)
|
|
|
|
path_pdf = ''
|
|
|
|
|
|
|
|
return _P.exists(path_pdf)
|
|
|
|
|
|
|
|
def export(self, path: str, ext: str='', args: dict={}):
|
|
|
|
if not ext:
|
|
|
|
ext = _P(path).ext
|
|
|
|
filter_name = self.FILTERS[ext]
|
|
|
|
filter_data = dict_to_property(args, True)
|
|
|
|
args = {
|
|
|
|
'FilterName': filter_name,
|
|
|
|
'FilterData': filter_data,
|
|
|
|
}
|
|
|
|
opt = dict_to_property(args)
|
|
|
|
try:
|
|
|
|
self.obj.storeToURL(_P.to_url(path), opt)
|
|
|
|
except Exception as e:
|
|
|
|
error(e)
|
|
|
|
path = ''
|
|
|
|
return _P.exists(path)
|
|
|
|
|
|
|
|
def save(self, path: str='', args: dict={}) -> bool:
|
|
|
|
result = True
|
|
|
|
opt = dict_to_property(args)
|
|
|
|
if path:
|
|
|
|
try:
|
|
|
|
self.obj.storeAsURL(_P.to_url(path), opt)
|
|
|
|
except Exception as e:
|
|
|
|
error(e)
|
|
|
|
result = False
|
|
|
|
else:
|
|
|
|
self.obj.store()
|
|
|
|
return result
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self.obj.close(True)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class LOCellStyle(LOBaseObject):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self.obj.Name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def properties(self):
|
|
|
|
properties = self.obj.PropertySetInfo.Properties
|
|
|
|
data = {p.Name: getattr(self.obj, p.Name) for p in properties}
|
|
|
|
return data
|
|
|
|
@properties.setter
|
|
|
|
def properties(self, values):
|
|
|
|
_set_properties(self.obj, values)
|
|
|
|
|
|
|
|
|
|
|
|
class LOCellStyles(object):
|
|
|
|
|
|
|
|
def __init__(self, obj, doc):
|
|
|
|
self._obj = obj
|
|
|
|
self._doc = doc
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
return len(self.obj)
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return LOCellStyle(self.obj[index])
|
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
self.obj[key] = value
|
|
|
|
|
|
|
|
def __delitem__(self, key):
|
|
|
|
if not isinstance(key, str):
|
|
|
|
key = key.Name
|
|
|
|
del self.obj[key]
|
|
|
|
|
|
|
|
def __contains__(self, item):
|
|
|
|
return item in self.obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def names(self):
|
|
|
|
return self.obj.ElementNames
|
|
|
|
|
|
|
|
def new(self, name: str=''):
|
|
|
|
obj = self._doc.create_instance('com.sun.star.style.CellStyle')
|
|
|
|
if name:
|
|
|
|
self.obj[name] = obj
|
|
|
|
obj = LOCellStyle(obj)
|
|
|
|
return obj
|
|
|
|
|
|
|
|
|
|
|
|
class LOCalc(LODocument):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._type = CALC
|
|
|
|
self._sheets = obj.Sheets
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return LOCalcSheet(self._sheets[index])
|
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
self._sheets[key] = value
|
|
|
|
|
|
|
|
def __len__(self):
|
|
|
|
return self._sheets.Count
|
|
|
|
|
|
|
|
def __contains__(self, item):
|
|
|
|
return item in self._sheets
|
|
|
|
|
|
|
|
@property
|
|
|
|
def names(self):
|
|
|
|
names = self.obj.Sheets.ElementNames
|
|
|
|
return names
|
|
|
|
|
|
|
|
@property
|
|
|
|
def selection(self):
|
|
|
|
sel = self.obj.CurrentSelection
|
|
|
|
if sel.ImplementationName in TYPE_RANGES:
|
|
|
|
sel = LOCalcRange(sel)
|
|
|
|
elif sel.ImplementationName == OBJ_SHAPES:
|
|
|
|
if len(sel) == 1:
|
|
|
|
sel = sel[0]
|
|
|
|
sel = LODrawPage(sel.Parent)[sel.Name]
|
|
|
|
else:
|
|
|
|
debug(sel.ImplementationName)
|
|
|
|
return sel
|
|
|
|
|
|
|
|
@property
|
|
|
|
def active(self):
|
|
|
|
return LOCalcSheet(self._cc.ActiveSheet)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def headers(self):
|
|
|
|
return self._cc.ColumnRowHeaders
|
|
|
|
@headers.setter
|
|
|
|
def headers(self, value):
|
|
|
|
self._cc.ColumnRowHeaders = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def tabs(self):
|
|
|
|
return self._cc.SheetTabs
|
|
|
|
@tabs.setter
|
|
|
|
def tabs(self, value):
|
|
|
|
self._cc.SheetTabs = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def cs(self):
|
|
|
|
return self.cell_styles
|
|
|
|
@property
|
|
|
|
def cell_styles(self):
|
|
|
|
obj = self.obj.StyleFamilies['CellStyles']
|
|
|
|
return LOCellStyles(obj, self)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def db_ranges(self):
|
|
|
|
# ~ return LOCalcDataBaseRanges(self.obj.DataBaseRanges)
|
|
|
|
return self.obj.DatabaseRanges
|
|
|
|
|
|
|
|
def activate(self, sheet):
|
|
|
|
obj = sheet
|
|
|
|
if isinstance(sheet, LOCalcSheet):
|
|
|
|
obj = sheet.obj
|
|
|
|
elif isinstance(sheet, str):
|
|
|
|
obj = self._sheets[sheet]
|
|
|
|
self._cc.setActiveSheet(obj)
|
|
|
|
return
|
|
|
|
|
|
|
|
def new_sheet(self):
|
|
|
|
s = self.create_instance('com.sun.star.sheet.Spreadsheet')
|
|
|
|
return s
|
|
|
|
|
|
|
|
def insert(self, name):
|
|
|
|
names = name
|
|
|
|
if isinstance(name, str):
|
|
|
|
names = (name,)
|
|
|
|
for n in names:
|
|
|
|
self._sheets[n] = self.new_sheet()
|
|
|
|
return LOCalcSheet(self._sheets[n])
|
|
|
|
|
|
|
|
def move(self, name, pos=-1):
|
|
|
|
index = pos
|
|
|
|
if pos < 0:
|
|
|
|
index = len(self)
|
|
|
|
if isinstance(name, LOCalcSheet):
|
|
|
|
name = name.name
|
|
|
|
self._sheets.moveByName(name, index)
|
|
|
|
return
|
|
|
|
|
|
|
|
def remove(self, name):
|
|
|
|
if isinstance(name, LOCalcSheet):
|
|
|
|
name = name.name
|
|
|
|
self._sheets.removeByName(name)
|
|
|
|
return
|
|
|
|
|
|
|
|
def copy(self, name, new_name='', pos=-1):
|
|
|
|
if isinstance(name, LOCalcSheet):
|
|
|
|
name = name.name
|
|
|
|
index = pos
|
|
|
|
if pos < 0:
|
|
|
|
index = len(self)
|
|
|
|
self._sheets.copyByName(name, new_name, index)
|
|
|
|
return LOCalcSheet(self._sheets[new_name])
|
|
|
|
|
|
|
|
def copy_from(self, doc, source='', target='', pos=-1):
|
|
|
|
index = pos
|
|
|
|
if pos < 0:
|
|
|
|
index = len(self)
|
|
|
|
|
|
|
|
names = source
|
|
|
|
if not source:
|
|
|
|
names = doc.names
|
|
|
|
elif isinstance(source, str):
|
|
|
|
names = (source,)
|
|
|
|
|
|
|
|
new_names = target
|
|
|
|
if not target:
|
|
|
|
new_names = names
|
|
|
|
elif isinstance(target, str):
|
|
|
|
new_names = (target,)
|
|
|
|
|
|
|
|
for i, name in enumerate(names):
|
|
|
|
self._sheets.importSheet(doc.obj, name, index + i)
|
|
|
|
self[index + i].name = new_names[i]
|
|
|
|
|
|
|
|
return LOCalcSheet(self._sheets[index])
|
|
|
|
|
|
|
|
def sort(self, reverse=False):
|
|
|
|
names = sorted(self.names, reverse=reverse)
|
|
|
|
for i, n in enumerate(names):
|
|
|
|
self.move(n, i)
|
|
|
|
return
|
|
|
|
|
|
|
|
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 LOFormControl(LOBaseObject):
|
|
|
|
EVENTS = {
|
|
|
|
'action': 'actionPerformed',
|
|
|
|
'click': 'mousePressed',
|
|
|
|
}
|
|
|
|
TYPES = {
|
|
|
|
'actionPerformed': 'XActionListener',
|
|
|
|
'mousePressed': 'XMouseListener',
|
|
|
|
}
|
|
|
|
|
|
|
|
def __init__(self, obj, view, form):
|
|
|
|
super().__init__(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 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 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
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
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')
|
|
|
|
h = args.pop('Height')
|
|
|
|
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):
|
|
|
|
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):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
self._obj = obj
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return LOCalcRange(self.obj[index])
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return f'easymacro.LOCalcSheet: {self.name}'
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._obj.Name
|
2019-10-14 17:23:15 -05:00
|
|
|
@name.setter
|
|
|
|
def name(self, value):
|
2020-12-16 21:50:11 -06:00
|
|
|
self._obj.Name = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def code_name(self):
|
|
|
|
return self._obj.CodeName
|
|
|
|
@code_name.setter
|
|
|
|
def code_name(self, value):
|
|
|
|
self._obj.CodeName = value
|
|
|
|
|
|
|
|
@property
|
|
|
|
def visible(self):
|
|
|
|
return self._obj.IsVisible
|
|
|
|
@visible.setter
|
|
|
|
def visible(self, value):
|
|
|
|
self._obj.IsVisible = value
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def is_protected(self):
|
|
|
|
return self._obj.isProtected()
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def password(self):
|
|
|
|
return ''
|
|
|
|
@visible.setter
|
|
|
|
def password(self, value):
|
|
|
|
self.obj.protect(value)
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def unprotect(self, value):
|
|
|
|
try:
|
|
|
|
self.obj.unprotect(value)
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
return False
|
|
|
|
|
|
|
|
@property
|
|
|
|
def color(self):
|
|
|
|
return self._obj.TabColor
|
|
|
|
@color.setter
|
|
|
|
def color(self, value):
|
|
|
|
self._obj.TabColor = get_color(value)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def used_area(self):
|
|
|
|
cursor = self.get_cursor()
|
|
|
|
cursor.gotoEndOfUsedArea(True)
|
|
|
|
return LOCalcRange(self[cursor.AbsoluteName].obj)
|
|
|
|
|
|
|
|
@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 doc(self):
|
|
|
|
return LOCalc(self.obj.DrawPage.Forms.Parent)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def charts(self):
|
|
|
|
return LOSheetCharts(self.obj.Charts, 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 events(self):
|
|
|
|
names = ('OnFocus', 'OnUnfocus', 'OnSelect', 'OnDoubleClick',
|
|
|
|
'OnRightClick', 'OnChange', 'OnCalculate')
|
|
|
|
evs = self.obj.Events
|
|
|
|
events = {n: _property_to_dict(evs.getByName(n)) for n in names
|
|
|
|
if evs.getByName(n)}
|
|
|
|
return events
|
|
|
|
@events.setter
|
|
|
|
def events(self, values):
|
|
|
|
pv = '[]com.sun.star.beans.PropertyValue'
|
|
|
|
ev = self.obj.Events
|
|
|
|
for name, v in values.items():
|
|
|
|
url = _get_url_script(v)
|
|
|
|
args = dict_to_property(dict(EventType='Script', Script=url))
|
|
|
|
# ~ e.replaceByName(k, args)
|
|
|
|
uno.invoke(ev, 'replaceByName', (name, uno.Any(pv, args)))
|
|
|
|
|
|
|
|
@property
|
|
|
|
def search_descriptor(self):
|
|
|
|
return self.obj.createSearchDescriptor()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def replace_descriptor(self):
|
|
|
|
return self.obj.createReplaceDescriptor()
|
|
|
|
|
|
|
|
def activate(self):
|
|
|
|
self.doc.activate(self.obj)
|
|
|
|
return
|
|
|
|
|
|
|
|
def clean(self):
|
|
|
|
doc = self.doc
|
|
|
|
sheet = doc.create_instance('com.sun.star.sheet.Spreadsheet')
|
|
|
|
doc._sheets.replaceByName(self.name, sheet)
|
|
|
|
return
|
|
|
|
|
|
|
|
def move(self, pos=-1):
|
|
|
|
index = pos
|
|
|
|
if pos < 0:
|
|
|
|
index = len(self.doc)
|
|
|
|
self.doc._sheets.moveByName(self.name, index)
|
|
|
|
return
|
|
|
|
|
|
|
|
def remove(self):
|
|
|
|
self.doc._sheets.removeByName(self.name)
|
|
|
|
return
|
|
|
|
|
|
|
|
def copy(self, new_name='', pos=-1):
|
|
|
|
index = pos
|
|
|
|
if pos < 0:
|
|
|
|
index = len(self.doc)
|
|
|
|
self.doc._sheets.copyByName(self.name, new_name, index)
|
|
|
|
return LOCalcSheet(self.doc._sheets[new_name])
|
|
|
|
|
|
|
|
def copy_to(self, doc, target='', pos=-1):
|
|
|
|
index = pos
|
|
|
|
if pos < 0:
|
|
|
|
index = len(doc)
|
|
|
|
name = self.name
|
|
|
|
if not target:
|
|
|
|
new_name = name
|
|
|
|
|
|
|
|
doc._sheets.importSheet(self.doc.obj, name, index)
|
|
|
|
sheet = doc[name]
|
|
|
|
sheet.name = new_name
|
|
|
|
return sheet
|
|
|
|
|
|
|
|
def get_cursor(self, cell=None):
|
|
|
|
if cell is None:
|
|
|
|
cursor = self.obj.createCursor()
|
|
|
|
else:
|
|
|
|
cursor = self.obj.createCursorByRange(cell)
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
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 __init__(self, obj):
|
|
|
|
self._obj = obj
|
|
|
|
self._sd = None
|
|
|
|
self._is_cell = obj.ImplementationName == OBJ_CELL
|
2019-10-14 17:23:15 -05:00
|
|
|
|
|
|
|
def __getitem__(self, index):
|
2020-12-16 21:50:11 -06:00
|
|
|
return LOCalcRange(self.obj[index])
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
self._r = 0
|
|
|
|
self._c = 0
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __next__(self):
|
|
|
|
try:
|
|
|
|
rango = self[self._r, self._c]
|
|
|
|
except Exception as e:
|
|
|
|
raise StopIteration
|
|
|
|
self._c += 1
|
|
|
|
if self._c == self.columns:
|
|
|
|
self._c = 0
|
|
|
|
self._r +=1
|
|
|
|
return rango
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def __contains__(self, item):
|
|
|
|
return item.in_range(self)
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
if self.is_none:
|
|
|
|
s = 'Range: None'
|
|
|
|
else:
|
|
|
|
s = f'Range: {self.name}'
|
|
|
|
return s
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_none(self):
|
|
|
|
return self.obj is None
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_cell(self):
|
|
|
|
return self._is_cell
|
|
|
|
|
|
|
|
@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 dp(self):
|
|
|
|
return self.sheet.dp
|
|
|
|
|
|
|
|
@property
|
|
|
|
def sheet(self):
|
|
|
|
return LOCalcSheet(self.obj.Spreadsheet)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def doc(self):
|
|
|
|
doc = self.obj.Spreadsheet.DrawPage.Forms.Parent
|
|
|
|
return LODocument(doc)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self.obj.AbsoluteName
|
|
|
|
|
|
|
|
@property
|
|
|
|
def code_name(self):
|
|
|
|
name = self.name.replace('$', '').replace('.', '_').replace(':', '')
|
|
|
|
return name
|
|
|
|
|
|
|
|
@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 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):
|
|
|
|
# ~ print(isinstance(data, str), data[0])
|
|
|
|
if data[0] in '=':
|
|
|
|
self.obj.setFormula(data)
|
|
|
|
# ~ print('Set Formula')
|
|
|
|
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)
|
2019-10-14 17:23:15 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def date(self):
|
|
|
|
value = int(self.obj.Value)
|
|
|
|
date = datetime.date.fromordinal(value + DATE_OFFSET)
|
|
|
|
return date
|
2019-10-14 17:23:15 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def time(self):
|
|
|
|
seconds = self.obj.Value * SECONDS_DAY
|
|
|
|
time_delta = datetime.timedelta(seconds=seconds)
|
|
|
|
time = (datetime.datetime.min + time_delta).time()
|
|
|
|
return time
|
2019-10-14 17:23:15 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def datetime(self):
|
|
|
|
return datetime.datetime.combine(self.date, self.time)
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
return self.obj.getDataArray()
|
|
|
|
@data.setter
|
|
|
|
def data(self, values):
|
|
|
|
if self._is_cell:
|
|
|
|
self.to_size(len(values), len(values[0])).data = values
|
2019-10-14 17:23:15 -05:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
self.obj.setDataArray(values)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def formula(self):
|
|
|
|
return self.obj.getFormulaArray()
|
|
|
|
@formula.setter
|
|
|
|
def formula(self, values):
|
|
|
|
self.obj.setFormulaArray(values)
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def array_formula(self):
|
|
|
|
return self.obj.ArrayFormula
|
|
|
|
@array_formula.setter
|
|
|
|
def array_formula(self, value):
|
|
|
|
self.obj.ArrayFormula = value
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def address(self):
|
|
|
|
return self.obj.CellAddress
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def range_address(self):
|
|
|
|
return self.obj.RangeAddress
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def cursor(self):
|
|
|
|
cursor = self.obj.Spreadsheet.createCursorByRange(self.obj)
|
|
|
|
return cursor
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def current_region(self):
|
|
|
|
cursor = self.cursor
|
|
|
|
cursor.collapseToCurrentRegion()
|
|
|
|
return LOCalcRange(self.sheet[cursor.AbsoluteName].obj)
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def next_cell(self):
|
|
|
|
a = self.current_region.range_address
|
|
|
|
col = a.StartColumn
|
|
|
|
row = a.EndRow + 1
|
|
|
|
return LOCalcRange(self.sheet[row, col].obj)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def position(self):
|
|
|
|
return self.obj.Position
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def size(self):
|
|
|
|
return self.obj.Size
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def possize(self):
|
|
|
|
data = {
|
|
|
|
'Width': self.size.Width,
|
|
|
|
'Height': self.size.Height,
|
|
|
|
'X': self.position.X,
|
|
|
|
'Y': self.position.Y,
|
|
|
|
}
|
|
|
|
return data
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def visible(self):
|
|
|
|
cursor = self.cursor
|
|
|
|
rangos = cursor.queryVisibleCells()
|
|
|
|
rangos = [LOCalcRange(self.sheet[r.AbsoluteName].obj) for r in rangos]
|
|
|
|
return tuple(rangos)
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def merged_area(self):
|
|
|
|
cursor = self.cursor
|
|
|
|
cursor.collapseToMergedArea()
|
|
|
|
rango = LOCalcRange(self.sheet[cursor.AbsoluteName].obj)
|
|
|
|
return rango
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def empty(self):
|
|
|
|
cursor = self.sheet.get_cursor(self.obj)
|
|
|
|
cursor = self.cursor
|
|
|
|
rangos = cursor.queryEmptyCells()
|
|
|
|
rangos = [LOCalcRange(self.sheet[r.AbsoluteName].obj) for r in rangos]
|
|
|
|
return tuple(rangos)
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def merge(self):
|
|
|
|
return self.obj.IsMerged
|
|
|
|
@merge.setter
|
|
|
|
def merge(self, value):
|
|
|
|
self.obj.merge(value)
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def style(self):
|
|
|
|
return self.obj.CellStyle
|
|
|
|
@style.setter
|
|
|
|
def style(self, value):
|
|
|
|
self.obj.CellStyle = value
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def auto_format(self):
|
|
|
|
return ''
|
|
|
|
@auto_format.setter
|
|
|
|
def auto_format(self, value):
|
|
|
|
self.obj.autoFormat(value)
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@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
|
2019-10-29 11:23:24 -06:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def select(self):
|
|
|
|
self.doc.select(self.obj)
|
|
|
|
return
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def search(self, options, find_all=True):
|
|
|
|
rangos = None
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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']
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if find_all:
|
|
|
|
found = self.obj.findAll(descriptor)
|
|
|
|
else:
|
|
|
|
found = self.obj.findFirst(descriptor)
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if found:
|
|
|
|
if found.ImplementationName == OBJ_CELL:
|
|
|
|
rangos = LOCalcRange(found)
|
|
|
|
else:
|
|
|
|
rangos = [LOCalcRange(f) for f in found]
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return rangos
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def offset(self, rows=0, cols=1):
|
|
|
|
ra = self.range_address
|
|
|
|
col = ra.EndColumn + cols
|
|
|
|
row = ra.EndRow + rows
|
|
|
|
return LOCalcRange(self.sheet[row, col].obj)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def to_size(self, rows, cols):
|
|
|
|
cursor = self.cursor
|
|
|
|
cursor.collapseToSize(cols, rows)
|
|
|
|
return LOCalcRange(self.sheet[cursor.AbsoluteName].obj)
|
|
|
|
|
|
|
|
def copy(self, source):
|
|
|
|
self.sheet.obj.copyRange(self.address, source.range_address)
|
2019-10-05 11:14:19 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def copy_to(self, cell, formula=False):
|
|
|
|
rango = cell.to_size(self.rows, self.columns)
|
|
|
|
if formula:
|
|
|
|
rango.formula = self.data
|
|
|
|
else:
|
|
|
|
rango.data = self.data
|
|
|
|
return
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def optimal_width(self):
|
|
|
|
self.obj.Columns.OptimalWidth = True
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def clean_render(self, template='\{(\w.+)\}'):
|
|
|
|
self._sd.SearchRegularExpression = True
|
|
|
|
self._sd.setSearchString(template)
|
|
|
|
self.obj.replaceAll(self._sd)
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _render_value(self, key, value, parent=''):
|
|
|
|
cell = None
|
|
|
|
if isinstance(value, dict):
|
|
|
|
for k, v in value.items():
|
2021-02-01 23:00:51 -06:00
|
|
|
# ~ print(1, 'RENDER', k, v)
|
2020-12-16 21:50:11 -06:00
|
|
|
cell = self._render_value(k, v, key)
|
|
|
|
return cell
|
|
|
|
elif isinstance(value, (list, tuple)):
|
|
|
|
self._render_list(key, value)
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
search = f'{{{key}}}'
|
|
|
|
if parent:
|
|
|
|
search = f'{{{parent}.{key}}}'
|
|
|
|
ranges = self.find_all(search)
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2021-02-01 23:00:51 -06:00
|
|
|
if ranges is None:
|
|
|
|
return
|
|
|
|
|
|
|
|
# ~ for cell in ranges or range(0):
|
|
|
|
for cell in ranges:
|
2020-12-16 21:50:11 -06:00
|
|
|
self._set_new_value(cell, search, value)
|
|
|
|
return LOCalcRange(cell)
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _set_new_value(self, cell, search, value):
|
|
|
|
if not cell.ImplementationName == 'ScCellObj':
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _render_list(self, key, rows):
|
|
|
|
for row in rows:
|
|
|
|
for k, v in row.items():
|
|
|
|
self._render_value(k, v)
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def find(self, search_string):
|
|
|
|
if self._sd is None:
|
|
|
|
self._sd = self.sheet.obj.createSearchDescriptor()
|
|
|
|
self._sd.SearchCaseSensitive = False
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
self._sd.setSearchString(search_string)
|
|
|
|
cell = self.obj.findFirst(self._sd)
|
|
|
|
if cell:
|
|
|
|
cell = LOCalcRange(cell)
|
|
|
|
return cell
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def find_all(self, search_string):
|
|
|
|
if self._sd is None:
|
|
|
|
self._sd = self.sheet.obj.createSearchDescriptor()
|
|
|
|
self._sd.SearchCaseSensitive = False
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
self._sd.setSearchString(search_string)
|
|
|
|
ranges = self.obj.findAll(self._sd)
|
|
|
|
return ranges
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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']
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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, 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'])
|
|
|
|
# ~ img.ResizeWithCell = True
|
|
|
|
img = self.sheet.dp.insert_image(path, args)
|
|
|
|
img.anchor = self.obj
|
|
|
|
args.clear()
|
|
|
|
return img
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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'])
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
shape = self.sheet.dp.add(tipo, args)
|
|
|
|
shape.anchor = self.obj
|
|
|
|
args.clear()
|
2019-10-05 11:14:19 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-09-14 17:40:07 -05:00
|
|
|
return
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-10-12 20:16:00 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def merge_by_row(self):
|
|
|
|
for r in range(len(self.rows)):
|
|
|
|
self[r].merge = True
|
|
|
|
return
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def fill(self, source=1):
|
|
|
|
self.obj.fillAuto(0, source)
|
2020-08-16 22:04:40 -05:00
|
|
|
return
|
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOWriterPageStyle(LOBaseObject):
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __str__(self):
|
|
|
|
return f'Page Style: {self.name}'
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def name(self):
|
|
|
|
return self._obj.Name
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOWriterPageStyles(object):
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, styles):
|
|
|
|
self._styles = styles
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __getitem__(self, index):
|
|
|
|
return LOWriterPageStyle(self._styles[index])
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def names(self):
|
|
|
|
return self._styles.ElementNames
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __str__(self):
|
|
|
|
return '\n'.join(self.names)
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOWriterTextRange(object):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
def __init__(self, obj, doc):
|
2019-09-08 00:25:30 -05:00
|
|
|
self._obj = obj
|
2019-09-09 22:13:01 -05:00
|
|
|
self._doc = doc
|
2020-12-16 21:50:11 -06:00
|
|
|
self._is_paragraph = self.obj.ImplementationName == 'SwXParagraph'
|
|
|
|
self._is_table = self.obj.ImplementationName == 'SwXTextTable'
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __iter__(self):
|
|
|
|
self._index = 0
|
2019-10-10 00:07:45 -05:00
|
|
|
return self
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __next__(self):
|
|
|
|
for i, p in enumerate(self.obj):
|
|
|
|
if i == self._index:
|
|
|
|
obj = LOWriterTextRange(p, self._doc)
|
|
|
|
self._index += 1
|
|
|
|
return obj
|
|
|
|
raise StopIteration
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def string(self):
|
|
|
|
s = ''
|
2020-12-23 22:24:00 -06:00
|
|
|
if not self._is_table:
|
2020-12-16 21:50:11 -06:00
|
|
|
s = self.obj.String
|
|
|
|
return s
|
|
|
|
@string.setter
|
|
|
|
def string(self, value):
|
|
|
|
self.obj.String = value
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-29 11:23:24 -06:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def value(self):
|
|
|
|
return self.string
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def is_table(self):
|
|
|
|
return self._is_table
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def text(self):
|
|
|
|
return self.obj.Text
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def cursor(self):
|
|
|
|
return self.text.createTextCursorByRange(self.obj)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def dp(self):
|
|
|
|
return self._doc.dp
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-10-05 11:14:19 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def new_line(self, count=1):
|
|
|
|
cursor = self.cursor
|
|
|
|
for i in range(count):
|
|
|
|
self.text.insertControlCharacter(cursor, PARAGRAPH_BREAK, False)
|
|
|
|
return self._doc.selection
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def insert_table(self, data):
|
|
|
|
table = self._doc.create_instance('com.sun.star.text.TextTable')
|
|
|
|
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_image(self, path, args={}):
|
|
|
|
w = args.get('Width', 1000)
|
|
|
|
h = args.get('Height', 1000)
|
|
|
|
image = self._doc.create_instance('com.sun.star.text.GraphicObject')
|
|
|
|
image.GraphicURL = _P.to_url(path)
|
|
|
|
image.AnchorType = AS_CHARACTER
|
|
|
|
image.Width = w
|
|
|
|
image.Height = h
|
|
|
|
self.insert_content(image)
|
|
|
|
return self._doc.dp.last
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOWriterTextRanges(object):
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj, doc):
|
|
|
|
self._obj = obj
|
|
|
|
self._doc = doc
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
for i, p in enumerate(self.obj):
|
|
|
|
if i == index:
|
|
|
|
obj = LOWriterTextRange(p, self._doc)
|
|
|
|
break
|
|
|
|
return obj
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
self._index = 0
|
|
|
|
return self
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __next__(self):
|
|
|
|
for i, p in enumerate(self.obj):
|
|
|
|
if i == self._index:
|
|
|
|
obj = LOWriterTextRange(p, self._doc)
|
|
|
|
self._index += 1
|
|
|
|
return obj
|
|
|
|
raise StopIteration
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2019-10-14 17:23:15 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
|
|
|
|
class LOWriterTextTable(object):
|
|
|
|
|
|
|
|
def __init__(self, obj, doc):
|
|
|
|
self._obj = obj
|
|
|
|
self._doc = doc
|
2019-10-14 17:23:15 -05:00
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._obj.Name
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
return self._obj.DataArray
|
|
|
|
@data.setter
|
|
|
|
def data(self, values):
|
|
|
|
self._obj.DataArray = values
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOWriterTextTables(object):
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, doc):
|
|
|
|
self._doc = doc
|
|
|
|
self._obj = doc.obj.TextTables
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __getitem__(self, key):
|
|
|
|
return LOWriterTextTable(self._obj[key], self._doc)
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __len__(self):
|
|
|
|
return self._obj.Count
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def insert(self, data, text_range=None):
|
|
|
|
if text_range is None:
|
|
|
|
text_range = self._doc.selection
|
|
|
|
text_range.insert_table(data)
|
|
|
|
return
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
class LOWriter(LODocument):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
2020-12-16 21:50:11 -06:00
|
|
|
self._type = WRITER
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def text(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
return LOWriterTextRange(self.obj.Text, self)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def paragraphs(self):
|
|
|
|
return LOWriterTextRanges(self.obj.Text, self)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-14 23:43:42 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def tables(self):
|
|
|
|
return LOWriterTextTables(self)
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
|
|
|
def selection(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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]
|
2019-10-12 20:16:00 -05:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
debug(sel.ImplementationName)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return sel
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def dp(self):
|
|
|
|
return self.draw_page
|
|
|
|
@property
|
|
|
|
def draw_page(self):
|
|
|
|
return LODrawPage(self.obj.DrawPage)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def view_cursor(self):
|
|
|
|
return self._cc.ViewCursor
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def cursor(self):
|
|
|
|
return self.obj.Text.createTextCursor()
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def page_styles(self):
|
|
|
|
ps = self.obj.StyleFamilies['PageStyles']
|
|
|
|
return LOWriterPageStyles(ps)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def search_descriptor(self):
|
|
|
|
return self.obj.createSearchDescriptor()
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def replace_descriptor(self):
|
|
|
|
return self.obj.createReplaceDescriptor()
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def goto_start(self):
|
|
|
|
self.view_cursor.gotoStart(False)
|
|
|
|
return self.selection
|
|
|
|
|
|
|
|
def goto_end(self):
|
|
|
|
self.view_cursor.gotoEnd(False)
|
|
|
|
return self.selection
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def search(self, options, find_all=True):
|
|
|
|
descriptor = self.search_descriptor
|
2019-10-23 23:09:23 -05:00
|
|
|
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']
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
result = False
|
|
|
|
if find_all:
|
2019-10-23 23:09:23 -05:00
|
|
|
found = self.obj.findAll(descriptor)
|
2020-12-16 21:50:11 -06:00
|
|
|
if len(found):
|
|
|
|
result = [LOWriterTextRange(f, self) for f in found]
|
|
|
|
else:
|
|
|
|
found = self.obj.findFirst(descriptor)
|
|
|
|
if found:
|
|
|
|
result = LOWriterTextRange(found, self)
|
2019-10-23 23:09:23 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return result
|
2019-10-23 23:09:23 -05:00
|
|
|
|
|
|
|
def replace(self, options):
|
2020-12-16 21:50:11 -06:00
|
|
|
descriptor = self.replace_descriptor
|
2019-10-23 23:09:23 -05:00
|
|
|
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
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def select(self, text):
|
|
|
|
if hasattr(text, 'obj'):
|
|
|
|
text = text.obj
|
|
|
|
self._cc.select(text)
|
|
|
|
return
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOShape(LOBaseObject):
|
|
|
|
IMAGE = 'com.sun.star.drawing.GraphicObjectShape'
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj, index):
|
|
|
|
self._index = index
|
|
|
|
super().__init__(obj)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-14 23:43:42 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def type(self):
|
|
|
|
t = self.shape_type[21:]
|
|
|
|
if self.is_image:
|
|
|
|
t = 'image'
|
|
|
|
return t
|
2019-10-14 23:43:42 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def shape_type(self):
|
|
|
|
return self.obj.ShapeType
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def is_image(self):
|
|
|
|
return self.shape_type == self.IMAGE
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def name(self):
|
|
|
|
return self.obj.Name or f'{self.type}{self.index}'
|
|
|
|
@name.setter
|
|
|
|
def name(self, value):
|
|
|
|
self.obj.Name = value
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def index(self):
|
|
|
|
return self._index
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def size(self):
|
|
|
|
s = self.obj.Size
|
|
|
|
a = dict(Width=s.Width, Height=s.Height)
|
|
|
|
return a
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def string(self):
|
|
|
|
return self.obj.String
|
|
|
|
@string.setter
|
|
|
|
def string(self, value):
|
|
|
|
self.obj.String = value
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def description(self):
|
|
|
|
return self.obj.Description
|
|
|
|
@description.setter
|
|
|
|
def description(self, value):
|
|
|
|
self.obj.Description = value
|
2019-10-14 23:43:42 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def cell(self):
|
|
|
|
return self.anchor
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
|
|
|
self.obj.Anchor = value
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def visible(self):
|
|
|
|
return self.obj.Visible
|
|
|
|
@visible.setter
|
|
|
|
def visible(self, value):
|
|
|
|
self.obj.Visible = value
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def path(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
return self.url
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def url(self):
|
|
|
|
url = ''
|
|
|
|
if self.is_image:
|
|
|
|
url = _P.to_system(self.obj.GraphicURL.OriginURL)
|
|
|
|
return url
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def mimetype(self):
|
|
|
|
mt = ''
|
|
|
|
if self.is_image:
|
|
|
|
mt = self.obj.GraphicURL.MimeType
|
|
|
|
return mt
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def linked(self):
|
|
|
|
l = False
|
|
|
|
if self.is_image:
|
|
|
|
l = self.obj.GraphicURL.Linked
|
|
|
|
return l
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def delete(self):
|
|
|
|
self.remove()
|
2019-10-05 11:14:19 -05:00
|
|
|
return
|
2020-12-16 21:50:11 -06:00
|
|
|
def remove(self):
|
|
|
|
self.obj.Parent.remove(self.obj)
|
2019-10-05 11:14:19 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ 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
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LODrawPage(LOBaseObject):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
if isinstance(index, int):
|
|
|
|
shape = LOShape(self.obj[index], index)
|
2019-10-05 11:14:19 -05:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __next__(self):
|
|
|
|
if self._index == self.count:
|
|
|
|
raise StopIteration
|
|
|
|
shape = self[self._index]
|
|
|
|
self._index += 1
|
|
|
|
return shape
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self.obj.Name
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def doc(self):
|
|
|
|
return self.obj.Forms.Parent
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@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, args={}):
|
|
|
|
"""Insert a shape in page, type shapes:
|
|
|
|
Line
|
|
|
|
Rectangle
|
|
|
|
Ellipse
|
|
|
|
Text
|
|
|
|
"""
|
|
|
|
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'{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)
|
|
|
|
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, args={}):
|
|
|
|
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}')
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
image = self.create_instance('com.sun.star.drawing.GraphicObjectShape')
|
2020-12-16 21:50:11 -06:00
|
|
|
image.GraphicURL = _P.to_url(path)
|
2019-09-09 22:13:01 -05:00
|
|
|
image.Size = Size(w, h)
|
|
|
|
image.Position = Point(x, y)
|
2020-12-16 21:50:11 -06:00
|
|
|
image.Name = name
|
|
|
|
self.obj.add(image)
|
|
|
|
return LOShape(self.obj[index], index)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LODrawImpress(LODocument):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __getitem__(self, index):
|
|
|
|
if isinstance(index, int):
|
|
|
|
page = self.obj.DrawPages[index]
|
|
|
|
else:
|
|
|
|
page = self.obj.DrawPages.getByName(index)
|
|
|
|
return LODrawPage(page)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-08-16 22:04:40 -05:00
|
|
|
@property
|
|
|
|
def selection(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
sel = self.obj.CurrentSelection[0]
|
|
|
|
# ~ return _get_class_uno(sel)
|
2020-08-16 22:04:40 -05:00
|
|
|
return sel
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def current_page(self):
|
|
|
|
return LODrawPage(self._cc.getCurrentPage())
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def paste(self):
|
|
|
|
call_dispatch(self.frame, '.uno:Paste')
|
|
|
|
return self.current_page[-1]
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ 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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
|
|
|
|
class LODraw(LODrawImpress):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
2020-12-16 21:50:11 -06:00
|
|
|
self._type = DRAW
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-09-14 17:40:07 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOImpress(LODrawImpress):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._type = IMPRESS
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class BaseDateField(DateField):
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def db_value(self, value):
|
|
|
|
return _date_to_struct(value)
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def python_value(self, value):
|
|
|
|
return _struct_to_date(value)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-11-26 23:32:39 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class BaseTimeField(TimeField):
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def db_value(self, value):
|
|
|
|
return _date_to_struct(value)
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def python_value(self, value):
|
|
|
|
return _struct_to_date(value)
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class BaseDateTimeField(DateTimeField):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def db_value(self, value):
|
|
|
|
return _date_to_struct(value)
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def python_value(self, value):
|
|
|
|
return _struct_to_date(value)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class FirebirdDatabase(Database):
|
|
|
|
field_types = {'BOOL': 'BOOLEAN', 'DATETIME': 'TIMESTAMP'}
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, database, **kwargs):
|
|
|
|
super().__init__(database, **kwargs)
|
|
|
|
self._db = database
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _connect(self):
|
|
|
|
return self._db
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def create_tables(self, models, **options):
|
|
|
|
options['safe'] = False
|
|
|
|
tables = self._db.tables
|
|
|
|
models = [m for m in models if not m.__name__.lower() in tables]
|
|
|
|
super().create_tables(models, **options)
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def execute_sql(self, sql, params=None, commit=True):
|
|
|
|
with __exception_wrapper__:
|
|
|
|
cursor = self._db.execute(sql, params)
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
def last_insert_id(self, cursor, query_type=None):
|
|
|
|
# ~ debug('LAST_ID', cursor)
|
|
|
|
return 0
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def rows_affected(self, cursor):
|
|
|
|
return self._db.rows_affected
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def path(self):
|
|
|
|
return self._db.path
|
2019-10-10 00:07:45 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class BaseRow:
|
|
|
|
pass
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class BaseQuery(object):
|
|
|
|
PY_TYPES = {
|
|
|
|
'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')
|
2019-11-26 23:32:39 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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()
|
2019-11-26 23:32:39 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __getitem__(self, index):
|
|
|
|
return self._data[index]
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __iter__(self):
|
|
|
|
self._index = 0
|
|
|
|
return self
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
|
|
|
value = getattr(self._query, self.PY_TYPES[type_field])(index)
|
|
|
|
if type_field in self.TYPES_DATE:
|
|
|
|
value = _struct_to_date(value)
|
|
|
|
return value
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def tuples(self):
|
|
|
|
data = [tuple(r.__dict__.values()) for r in self._data]
|
|
|
|
return tuple(data)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def dicts(self):
|
|
|
|
data = [r.__dict__ for r in self._data]
|
|
|
|
return tuple(data)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOBase(object):
|
|
|
|
DB_TYPES = {
|
|
|
|
str: 'setString',
|
|
|
|
int: 'setInt',
|
|
|
|
float: 'setFloat',
|
|
|
|
bool: 'setBoolean',
|
|
|
|
Date: 'setDate',
|
|
|
|
Time: 'setTime',
|
|
|
|
DateTime: 'setTimestamp',
|
|
|
|
}
|
|
|
|
# ~ setArray
|
|
|
|
# ~ setBinaryStream
|
|
|
|
# ~ setBlob
|
|
|
|
# ~ setByte
|
|
|
|
# ~ setBytes
|
|
|
|
# ~ setCharacterStream
|
|
|
|
# ~ setClob
|
|
|
|
# ~ setNull
|
|
|
|
# ~ setObject
|
|
|
|
# ~ setObjectNull
|
|
|
|
# ~ setObjectWithInfo
|
|
|
|
# ~ setPropertyValue
|
|
|
|
# ~ setRef
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj, args={}):
|
|
|
|
self._obj = obj
|
|
|
|
self._type = BASE
|
|
|
|
self._dbc = create_instance('com.sun.star.sdb.DatabaseContext')
|
|
|
|
self._rows_affected = 0
|
|
|
|
path = args.get('path', '')
|
|
|
|
self._path = _P(path)
|
|
|
|
self._name = self._path.name
|
|
|
|
if _P.exists(path):
|
|
|
|
if not self.is_registered:
|
|
|
|
self.register()
|
|
|
|
db = self._dbc.getByName(self.name)
|
2019-09-08 00:25:30 -05:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
db = self._dbc.createInstance()
|
|
|
|
db.URL = 'sdbc:embedded:firebird'
|
|
|
|
db.DatabaseDocument.storeAsURL(self._path.url, ())
|
|
|
|
self.register()
|
|
|
|
self._obj = db
|
|
|
|
self._con = db.getConnection('', '')
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __contains__(self, item):
|
|
|
|
return item in self.tables
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-08-16 22:04:40 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def name(self):
|
|
|
|
return self._name
|
2019-10-10 00:07:45 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def path(self):
|
|
|
|
return str(self._path)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def is_registered(self):
|
|
|
|
return self._dbc.hasRegisteredDatabase(self.name)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def tables(self):
|
|
|
|
tables = [t.Name.lower() for t in self._con.getTables()]
|
|
|
|
return tables
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def rows_affected(self):
|
|
|
|
return self._rows_affected
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def register(self):
|
|
|
|
if not self.is_registered:
|
|
|
|
self._dbc.registerDatabaseLocation(self.name, self._path.url)
|
2019-11-26 23:32:39 -06:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def revoke(self, name):
|
|
|
|
self._dbc.revokeDatabaseLocation(name)
|
|
|
|
return True
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def save(self):
|
|
|
|
self.obj.DatabaseDocument.store()
|
|
|
|
self.refresh()
|
2019-10-14 23:43:42 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def close(self):
|
|
|
|
self._con.close()
|
2019-09-14 17:40:07 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def refresh(self):
|
|
|
|
self._con.getTables().refresh()
|
2019-10-05 11:14:19 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def initialize(self, database_proxy, tables):
|
|
|
|
db = FirebirdDatabase(self)
|
|
|
|
database_proxy.initialize(db)
|
|
|
|
db.create_tables(tables)
|
2019-10-10 00:07:45 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _validate_sql(self, sql, params):
|
|
|
|
limit = ' LIMIT '
|
|
|
|
for p in params:
|
|
|
|
sql = sql.replace('?', f"'{p}'", 1)
|
|
|
|
if limit in sql:
|
|
|
|
sql = sql.split(limit)[0]
|
|
|
|
sql = sql.replace('SELECT', f'SELECT FIRST {params[-1]}')
|
|
|
|
return sql
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def cursor(self, sql, params):
|
|
|
|
if sql.startswith('SELECT'):
|
|
|
|
sql = self._validate_sql(sql, params)
|
|
|
|
cursor = self._con.prepareStatement(sql)
|
|
|
|
return cursor
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if not params:
|
|
|
|
cursor = self._con.createStatement()
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
cursor = self._con.prepareStatement(sql)
|
|
|
|
for i, v in enumerate(params, 1):
|
|
|
|
t = type(v)
|
|
|
|
if not t in self.DB_TYPES:
|
|
|
|
error('Type not support')
|
|
|
|
debug((i, t, v, self.DB_TYPES[t]))
|
|
|
|
getattr(cursor, self.DB_TYPES[t])(i, v)
|
|
|
|
return cursor
|
|
|
|
|
|
|
|
def execute(self, sql, params):
|
|
|
|
debug(sql, params)
|
|
|
|
cursor = self.cursor(sql, params)
|
|
|
|
|
|
|
|
if sql.startswith('SELECT'):
|
|
|
|
result = cursor.executeQuery()
|
|
|
|
elif params:
|
|
|
|
result = cursor.executeUpdate()
|
|
|
|
self._rows_affected = result
|
|
|
|
self.save()
|
2019-10-12 20:16:00 -05:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
result = cursor.execute(sql)
|
|
|
|
self.save()
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return result
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def select(self, sql):
|
|
|
|
debug('SELECT', sql)
|
|
|
|
if not sql.startswith('SELECT'):
|
|
|
|
return ()
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
cursor = self._con.prepareStatement(sql)
|
|
|
|
query = cursor.executeQuery()
|
|
|
|
return BaseQuery(query)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_query(self, query):
|
|
|
|
sql, args = query.sql()
|
|
|
|
sql = self._validate_sql(sql, args)
|
|
|
|
return self.select(sql)
|
2019-10-23 23:09:23 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOMath(LODocument):
|
2019-10-23 23:09:23 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._type = MATH
|
2019-10-23 23:09:23 -05:00
|
|
|
|
2019-11-26 23:32:39 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOBasic(LODocument):
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._type = BASIC
|
2020-08-16 22:04:40 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LODocs(object):
|
|
|
|
_desktop = None
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self):
|
|
|
|
self._desktop = get_desktop()
|
|
|
|
LODocs._desktop = self._desktop
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __getitem__(self, index):
|
|
|
|
document = None
|
|
|
|
for i, doc in enumerate(self._desktop.Components):
|
|
|
|
if isinstance(index, int) and i == index:
|
|
|
|
document = _get_class_doc(doc)
|
|
|
|
break
|
|
|
|
elif isinstance(index, str) and doc.Title == index:
|
|
|
|
document = _get_class_doc(doc)
|
|
|
|
break
|
|
|
|
return document
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __contains__(self, item):
|
|
|
|
doc = self[item]
|
|
|
|
return not doc is None
|
|
|
|
|
|
|
|
def __iter__(self):
|
|
|
|
self._i = -1
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __next__(self):
|
|
|
|
self._i += 1
|
|
|
|
doc = self[self._i]
|
|
|
|
if doc is None:
|
|
|
|
raise StopIteration
|
2020-08-16 22:04:40 -05:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
return doc
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __len__(self):
|
|
|
|
for i, _ in enumerate(self._desktop.Components):
|
|
|
|
pass
|
|
|
|
return i + 1
|
|
|
|
|
|
|
|
@property
|
|
|
|
def active(self):
|
|
|
|
return _get_class_doc(self._desktop.getCurrentComponent())
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def new(cls, type_doc=CALC, args={}):
|
|
|
|
if type_doc == BASE:
|
|
|
|
return LOBase(None, args)
|
|
|
|
|
|
|
|
path = f'private:factory/s{type_doc}'
|
|
|
|
opt = dict_to_property(args)
|
|
|
|
doc = cls._desktop.loadComponentFromURL(path, '_default', 0, opt)
|
|
|
|
return _get_class_doc(doc)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def open(cls, path, args={}):
|
|
|
|
""" Open document in path
|
|
|
|
Usually options:
|
|
|
|
Hidden: True or False
|
|
|
|
AsTemplate: True or False
|
|
|
|
ReadOnly: True or False
|
|
|
|
Password: super_secret
|
|
|
|
MacroExecutionMode: 4 = Activate macros
|
|
|
|
Preview: True or False
|
|
|
|
|
|
|
|
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1frame_1_1XComponentLoader.html
|
|
|
|
http://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html
|
|
|
|
"""
|
|
|
|
path = _P.to_url(path)
|
|
|
|
opt = dict_to_property(args)
|
|
|
|
doc = cls._desktop.loadComponentFromURL(path, '_default', 0, opt)
|
|
|
|
if doc is None:
|
2020-08-16 22:04:40 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return _get_class_doc(doc)
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def connect(self, path):
|
|
|
|
return LOBase(None, {'path': path})
|
2020-08-16 22:04:40 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _add_listeners(events, control, name=''):
|
|
|
|
listeners = {
|
|
|
|
'addActionListener': EventsButton,
|
|
|
|
'addMouseListener': EventsMouse,
|
|
|
|
'addFocusListener': EventsFocus,
|
|
|
|
'addItemListener': EventsItem,
|
|
|
|
'addKeyListener': EventsKey,
|
|
|
|
'addTabListener': EventsTab,
|
|
|
|
}
|
|
|
|
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'
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
getattr(control, key)(listeners[key](events, name))
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if is_grid:
|
|
|
|
controllers = EventsGrid(events, name)
|
|
|
|
control.addSelectionListener(controllers)
|
|
|
|
control.Model.GridDataModel.addGridDataListener(controllers)
|
|
|
|
return
|
2020-08-16 22:04:40 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _set_properties(model, properties):
|
|
|
|
if 'X' in properties:
|
|
|
|
properties['PositionX'] = properties.pop('X')
|
|
|
|
if 'Y' in properties:
|
|
|
|
properties['PositionY'] = properties.pop('Y')
|
|
|
|
keys = tuple(properties.keys())
|
|
|
|
values = tuple(properties.values())
|
|
|
|
model.setPropertyValues(keys, values)
|
|
|
|
return
|
2020-08-16 22:04:40 -05:00
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
class EventsListenerBase(unohelper.Base, XEventListener):
|
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
def __init__(self, controller, name, window=None):
|
2019-09-09 22:13:01 -05:00
|
|
|
self._controller = controller
|
2019-10-10 00:07:45 -05:00
|
|
|
self._name = name
|
2019-09-09 22:13:01 -05:00
|
|
|
self._window = window
|
|
|
|
|
2019-10-29 11:23:24 -06:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._name
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
def disposing(self, event):
|
|
|
|
self._controller = None
|
|
|
|
if not self._window is None:
|
|
|
|
self._window.setMenuBar(None)
|
|
|
|
|
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
class EventsMouse(EventsListenerBase, XMouseListener, XMouseMotionListener):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
def __init__(self, controller, name):
|
|
|
|
super().__init__(controller, name)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
def mousePressed(self, event):
|
2019-10-10 00:07:45 -05:00
|
|
|
event_name = '{}_click'.format(self._name)
|
2019-09-09 22:13:01 -05:00
|
|
|
if event.ClickCount == 2:
|
2019-10-19 20:01:04 -05:00
|
|
|
event_name = '{}_double_click'.format(self._name)
|
2019-09-09 22:13:01 -05:00
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
def mouseReleased(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def mouseEntered(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def mouseExited(self, event):
|
|
|
|
pass
|
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
# ~ XMouseMotionListener
|
|
|
|
def mouseMoved(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def mouseDragged(self, event):
|
|
|
|
pass
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-14 17:23:15 -05:00
|
|
|
class EventsMouseLink(EventsMouse):
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, controller, name):
|
|
|
|
super().__init__(controller, name)
|
|
|
|
self._text_color = 0
|
|
|
|
|
2019-10-14 17:23:15 -05:00
|
|
|
def mouseEntered(self, event):
|
2020-12-16 21:50:11 -06:00
|
|
|
model = event.Source.Model
|
|
|
|
self._text_color = model.TextColor or 0
|
|
|
|
model.TextColor = get_color('blue')
|
2019-10-14 17:23:15 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
def mouseExited(self, event):
|
2020-12-16 21:50:11 -06:00
|
|
|
model = event.Source.Model
|
|
|
|
model.TextColor = self._text_color
|
2019-10-05 11:14:19 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class EventsButton(EventsListenerBase, XActionListener):
|
2019-10-14 19:48:13 -05:00
|
|
|
|
|
|
|
def __init__(self, controller, name):
|
|
|
|
super().__init__(controller, name)
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def actionPerformed(self, event):
|
|
|
|
event_name = f'{self.name}_action'
|
2019-11-26 23:32:39 -06:00
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
2019-10-14 19:48:13 -05:00
|
|
|
|
|
|
|
|
2019-10-14 23:43:42 -05:00
|
|
|
class EventsFocus(EventsListenerBase, XFocusListener):
|
2020-12-16 21:50:11 -06:00
|
|
|
CONTROLS = (
|
|
|
|
'stardiv.Toolkit.UnoControlEditModel',
|
|
|
|
)
|
2019-10-14 23:43:42 -05:00
|
|
|
|
|
|
|
def __init__(self, controller, name):
|
|
|
|
super().__init__(controller, name)
|
|
|
|
|
|
|
|
def focusGained(self, event):
|
2019-10-19 20:01:04 -05:00
|
|
|
service = event.Source.Model.ImplementationName
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ print('Focus enter', service)
|
|
|
|
if service in self.CONTROLS:
|
|
|
|
obj = event.Source.Model
|
|
|
|
obj.BackgroundColor = COLOR_ON_FOCUS
|
|
|
|
return
|
2019-10-14 23:43:42 -05:00
|
|
|
|
|
|
|
def focusLost(self, event):
|
2020-12-16 21:50:11 -06:00
|
|
|
service = event.Source.Model.ImplementationName
|
|
|
|
if service in self.CONTROLS:
|
|
|
|
obj = event.Source.Model
|
|
|
|
obj.BackgroundColor = -1
|
|
|
|
return
|
2019-10-14 23:43:42 -05:00
|
|
|
|
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
class EventsKey(EventsListenerBase, XKeyListener):
|
|
|
|
"""
|
|
|
|
event.KeyChar
|
|
|
|
event.KeyCode
|
|
|
|
event.KeyFunc
|
|
|
|
event.Modifiers
|
|
|
|
"""
|
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
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)
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ else:
|
|
|
|
# ~ if event.KeyFunc == QUIT and hasattr(self._cls, 'close'):
|
|
|
|
# ~ self._cls.close()
|
2019-10-19 20:01:04 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class EventsItem(EventsListenerBase, XItemListener):
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
def __init__(self, controller, name):
|
|
|
|
super().__init__(controller, name)
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def disposing(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def itemStateChanged(self, event):
|
|
|
|
event_name = '{}_item_changed'.format(self.name)
|
2019-10-29 11:23:24 -06:00
|
|
|
if hasattr(self._controller, event_name):
|
2020-12-16 21:50:11 -06:00
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class EventsItemRoadmap(EventsItem):
|
|
|
|
|
|
|
|
def itemStateChanged(self, event):
|
|
|
|
dialog = event.Source.Context.Model
|
|
|
|
dialog.Step = event.ItemId + 1
|
2019-10-29 11:23:24 -06:00
|
|
|
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
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class EventsMouseGrid(EventsMouse):
|
|
|
|
selected = False
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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):
|
2019-10-10 00:07:45 -05:00
|
|
|
pass
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-10-10 00:07:45 -05:00
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
2020-12-16 21:50:11 -06:00
|
|
|
return
|
|
|
|
|
|
|
|
def itemActivated(self, event):
|
|
|
|
return
|
|
|
|
|
|
|
|
def itemDeactivated(self, event):
|
2019-10-10 00:07:45 -05:00
|
|
|
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):
|
2019-10-29 11:23:24 -06:00
|
|
|
sb = self._cls._subcont
|
2020-12-16 21:50:11 -06:00
|
|
|
sb.setPosSize(0, 0, event.Width, event.Height, SIZE)
|
|
|
|
event_name = '{}_resized'.format(self._name)
|
2019-10-10 00:07:45 -05:00
|
|
|
if hasattr(self._controller, event_name):
|
|
|
|
getattr(self._controller, event_name)(event)
|
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def windowMoved(self, event):
|
|
|
|
pass
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def windowShown(self, event):
|
|
|
|
pass
|
|
|
|
|
|
|
|
def windowHidden(self, event):
|
|
|
|
pass
|
2019-10-10 00:07:45 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ BorderColor = ?
|
|
|
|
# ~ FontStyleName = ?
|
|
|
|
# ~ HelpURL = ?
|
2019-09-09 22:13:01 -05:00
|
|
|
class UnoBaseObject(object):
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj, path=''):
|
2019-09-09 22:13:01 -05:00
|
|
|
self._obj = obj
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def model(self):
|
|
|
|
return self._model
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def m(self):
|
|
|
|
return self._model
|
|
|
|
|
|
|
|
@property
|
|
|
|
def properties(self):
|
|
|
|
return {}
|
|
|
|
@properties.setter
|
|
|
|
def properties(self, values):
|
|
|
|
_set_properties(self.model, values)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self.model.Name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def parent(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
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
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
|
|
|
def x(self):
|
2019-10-10 00:07:45 -05:00
|
|
|
if hasattr(self.model, 'PositionX'):
|
|
|
|
return self.model.PositionX
|
|
|
|
return self._get_possize('X')
|
2019-09-09 22:13:01 -05:00
|
|
|
@x.setter
|
|
|
|
def x(self, value):
|
2019-10-10 00:07:45 -05:00
|
|
|
if hasattr(self.model, 'PositionX'):
|
|
|
|
self.model.PositionX = value
|
|
|
|
else:
|
|
|
|
self._set_possize('X', value)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def y(self):
|
2019-10-10 00:07:45 -05:00
|
|
|
if hasattr(self.model, 'PositionY'):
|
|
|
|
return self.model.PositionY
|
|
|
|
return self._get_possize('Y')
|
2019-09-09 22:13:01 -05:00
|
|
|
@y.setter
|
|
|
|
def y(self, value):
|
2019-10-10 00:07:45 -05:00
|
|
|
if hasattr(self.model, 'PositionY'):
|
|
|
|
self.model.PositionY = value
|
|
|
|
else:
|
|
|
|
self._set_possize('Y', value)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def tab_index(self):
|
|
|
|
return self._model.TabIndex
|
|
|
|
@tab_index.setter
|
|
|
|
def tab_index(self, value):
|
|
|
|
self.model.TabIndex = value
|
2019-11-26 23:32:39 -06:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def tab_stop(self):
|
|
|
|
return self._model.Tabstop
|
|
|
|
@tab_stop.setter
|
|
|
|
def tab_stop(self, value):
|
|
|
|
self.model.Tabstop = value
|
2019-11-26 23:32:39 -06:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def ps(self):
|
2019-11-26 23:32:39 -06:00
|
|
|
ps = self.obj.getPosSize()
|
2020-12-16 21:50:11 -06:00
|
|
|
return ps
|
|
|
|
@ps.setter
|
|
|
|
def ps(self, ps):
|
|
|
|
self.obj.setPosSize(ps.X, ps.Y, ps.Width, ps.Height, POSSIZE)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
def set_focus(self):
|
|
|
|
self.obj.setFocus()
|
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def ps_from(self, source):
|
|
|
|
self.ps = source.ps
|
|
|
|
return
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
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
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def move(self, origin, x=0, y=5, center=False):
|
2019-09-09 22:13:01 -05:00
|
|
|
if x:
|
2019-10-19 20:01:04 -05:00
|
|
|
self.x = origin.x + origin.width + x
|
2019-11-26 23:32:39 -06:00
|
|
|
else:
|
|
|
|
self.x = origin.x
|
2019-09-09 22:13:01 -05:00
|
|
|
if y:
|
2019-10-19 20:01:04 -05:00
|
|
|
self.y = origin.y + origin.height + y
|
2019-11-26 23:32:39 -06:00
|
|
|
else:
|
|
|
|
self.y = origin.y
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if center:
|
|
|
|
self.center()
|
2019-09-09 22:13:01 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class UnoLabel(UnoBaseObject):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
2019-09-27 12:17:21 -05:00
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
return 'label'
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
|
|
|
def value(self):
|
|
|
|
return self.model.Label
|
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
|
|
|
self.model.Label = value
|
|
|
|
|
|
|
|
|
2019-10-14 17:23:15 -05:00
|
|
|
class UnoLabelLink(UnoLabel):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
return 'link'
|
|
|
|
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
class UnoButton(UnoBaseObject):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
return 'button'
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def value(self):
|
|
|
|
return self.model.Label
|
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
|
|
|
self.model.Label = value
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class UnoRadio(UnoBaseObject):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
2019-09-27 12:17:21 -05:00
|
|
|
@property
|
|
|
|
def type(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
return 'radio'
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
|
|
|
def value(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
return self.model.Label
|
2019-09-09 22:13:01 -05:00
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
2020-12-16 21:50:11 -06:00
|
|
|
self.model.Label = value
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class UnoCheckBox(UnoBaseObject):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
2019-10-05 11:14:19 -05:00
|
|
|
@property
|
|
|
|
def type(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
return 'checkbox'
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
|
|
|
def value(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
return self.model.State
|
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
|
|
|
self.model.State = value
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def label(self):
|
|
|
|
return self.model.Label
|
|
|
|
@label.setter
|
|
|
|
def label(self, value):
|
|
|
|
self.model.Label = value
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def tri_state(self):
|
|
|
|
return self.model.TriState
|
|
|
|
@tri_state.setter
|
|
|
|
def tri_state(self, value):
|
|
|
|
self.model.TriState = value
|
2019-10-21 00:28:00 -05:00
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1awt_1_1UnoControlEditModel.html
|
|
|
|
class UnoText(UnoBaseObject):
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def type(self):
|
|
|
|
return 'text'
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def value(self):
|
|
|
|
return self.model.Text
|
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
|
|
|
self.model.Text = value
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def validate(self):
|
2019-09-09 22:13:01 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class UnoImage(UnoBaseObject):
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def type(self):
|
|
|
|
return 'image'
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def value(self):
|
|
|
|
return self.url
|
|
|
|
@value.setter
|
|
|
|
def value(self, value):
|
|
|
|
self.url = value
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def type(self):
|
|
|
|
return 'listbox'
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def value(self):
|
|
|
|
return self.obj.getSelectedItem()
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def count(self):
|
|
|
|
return len(self.data)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
return self.model.StringItemList
|
|
|
|
@data.setter
|
|
|
|
def data(self, values):
|
|
|
|
self.model.StringItemList = list(sorted(values))
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def path(self):
|
|
|
|
return self._path
|
|
|
|
@path.setter
|
|
|
|
def path(self, value):
|
|
|
|
self._path = value
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def unselect(self):
|
|
|
|
self.obj.selectItem(self.value, False)
|
2019-10-29 11:23:24 -06:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def select(self, pos=0):
|
|
|
|
if isinstance(pos, str):
|
|
|
|
self.obj.selectItem(pos, True)
|
|
|
|
else:
|
|
|
|
self.obj.selectItemPos(pos, True)
|
2019-09-27 12:17:21 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def clear(self):
|
|
|
|
self.model.removeAllItems()
|
2019-09-27 12:17:21 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _set_image_url(self, image):
|
|
|
|
if _P.exists(image):
|
|
|
|
return _P.to_url(image)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
path = _P.join(self._path, DIR['images'], image)
|
|
|
|
return _P.to_url(path)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-09-27 12:17:21 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2019-10-14 19:48:13 -05:00
|
|
|
class UnoRoadmap(UnoBaseObject):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._options = ()
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __setattr__(self, name, value):
|
|
|
|
if name in ('_options',):
|
|
|
|
self.__dict__[name] = value
|
|
|
|
else:
|
|
|
|
super().__setattr__(name, value)
|
|
|
|
|
2019-10-14 19:48:13 -05:00
|
|
|
@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
|
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
@property
|
|
|
|
def enabled(self):
|
|
|
|
return True
|
|
|
|
@enabled.setter
|
|
|
|
def enabled(self, value):
|
|
|
|
for m in self.model:
|
|
|
|
m.Enabled = value
|
|
|
|
return
|
|
|
|
|
2019-10-14 23:43:42 -05:00
|
|
|
def set_enabled(self, index, value):
|
|
|
|
self.model.getByIndex(index).Enabled = value
|
|
|
|
return
|
|
|
|
|
2019-10-14 19:48:13 -05:00
|
|
|
|
2019-10-21 00:28:00 -05:00
|
|
|
class UnoTree(UnoBaseObject):
|
|
|
|
|
|
|
|
def __init__(self, obj, ):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._tdm = None
|
|
|
|
self._data = []
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __setattr__(self, name, value):
|
|
|
|
if name in ('_tdm', '_data'):
|
|
|
|
self.__dict__[name] = value
|
|
|
|
else:
|
|
|
|
super().__setattr__(name, value)
|
|
|
|
|
2019-10-21 00:28:00 -05:00
|
|
|
@property
|
|
|
|
def selection(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-21 00:28:00 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def root(self):
|
|
|
|
if self._tdm is None:
|
|
|
|
return ''
|
|
|
|
return self._tdm.Root.DisplayValue
|
|
|
|
@root.setter
|
|
|
|
def root(self, value):
|
2020-12-16 21:50:11 -06:00
|
|
|
self._add_data_model(value)
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def path(self):
|
|
|
|
return self.root
|
|
|
|
@path.setter
|
|
|
|
def path(self, value):
|
|
|
|
self.data = _P.walk_dir(value, True)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def data(self):
|
|
|
|
return self._data
|
|
|
|
@data.setter
|
|
|
|
def data(self, values):
|
|
|
|
self._data = list(values)
|
|
|
|
self._add_data()
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _add_data(self):
|
|
|
|
if not self.data:
|
|
|
|
return
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ https://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1awt_1_1grid.html
|
|
|
|
class UnoGrid(UnoBaseObject):
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj):
|
2019-10-12 20:16:00 -05:00
|
|
|
super().__init__(obj)
|
2020-12-16 21:50:11 -06:00
|
|
|
self._gdm = self.model.GridDataModel
|
|
|
|
self._data = []
|
2020-12-26 21:59:52 -06:00
|
|
|
self._formats = ()
|
2020-12-16 21:50:11 -06:00
|
|
|
|
|
|
|
def __setattr__(self, name, value):
|
2020-12-26 21:59:52 -06:00
|
|
|
if name in ('_gdm', '_data', '_formats'):
|
2020-12-16 21:50:11 -06:00
|
|
|
self.__dict__[name] = value
|
|
|
|
else:
|
|
|
|
super().__setattr__(name, value)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
def __getitem__(self, key):
|
2020-12-16 21:50:11 -06:00
|
|
|
value = self._gdm.getCellData(key[0], key[1])
|
|
|
|
return value
|
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
self._gdm.updateCellData(key[0], key[1], value)
|
|
|
|
return
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def type(self):
|
|
|
|
return 'grid'
|
|
|
|
|
|
|
|
@property
|
|
|
|
def columns(self):
|
2020-12-26 21:59:52 -06:00
|
|
|
return {}
|
2020-12-16 21:50:11 -06:00
|
|
|
@columns.setter
|
|
|
|
def columns(self, values):
|
2020-12-26 21:59:52 -06:00
|
|
|
# ~ self._columns = values
|
2020-12-16 21:50:11 -06:00
|
|
|
#~ 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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def data(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
return self._data
|
2019-10-12 20:16:00 -05:00
|
|
|
@data.setter
|
|
|
|
def data(self, values):
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def row(self):
|
|
|
|
return self.obj.CurrentRow
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
@property
|
|
|
|
def row_count(self):
|
|
|
|
return self._gdm.RowCount
|
|
|
|
|
|
|
|
@property
|
|
|
|
def column(self):
|
|
|
|
return self.obj.CurrentColumn
|
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def column(self):
|
|
|
|
return self.obj.CurrentColumn
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
@property
|
|
|
|
def is_valid(self):
|
|
|
|
return not (self.row == -1 or self.column == -1)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def formats(self):
|
|
|
|
return self._formats
|
|
|
|
@formats.setter
|
|
|
|
def formats(self, values):
|
|
|
|
self._formats = values
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def clear(self):
|
|
|
|
self._gdm.removeAllRows()
|
|
|
|
return
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
def add_row(self, data):
|
|
|
|
self._data.append(data)
|
|
|
|
row = self._format_columns(data)
|
|
|
|
self._gdm.addRow(self.row_count + 1, row)
|
|
|
|
return
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def set_cell_tooltip(self, col, row, value):
|
|
|
|
self._gdm.updateCellToolTip(col, row, value)
|
|
|
|
return
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_cell_tooltip(self, col, row):
|
|
|
|
value = self._gdm.getCellToolTip(col, row)
|
|
|
|
return value
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
def sort(self, column, asc=True):
|
|
|
|
self._gdm.sortByColumn(column, asc)
|
2020-12-16 21:50:11 -06:00
|
|
|
self.update_row_heading()
|
|
|
|
return
|
|
|
|
|
|
|
|
def update_row_heading(self):
|
2020-12-26 21:59:52 -06:00
|
|
|
for i in range(self.row_count):
|
2020-12-16 21:50:11 -06:00
|
|
|
self._gdm.updateRowHeading(i, i + 1)
|
|
|
|
return
|
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
def remove_row(self, row):
|
|
|
|
self._gdm.removeRow(row)
|
|
|
|
del self._data[row]
|
2020-12-16 21:50:11 -06:00
|
|
|
self.update_row_heading()
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class UnoPage(object):
|
|
|
|
|
|
|
|
def __init__(self, obj):
|
|
|
|
self._obj = obj
|
|
|
|
self._events = None
|
|
|
|
|
2019-10-12 20:16:00 -05:00
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
2020-12-16 21:50:11 -06:00
|
|
|
pass
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def model(self):
|
|
|
|
return self._obj.Model
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ @property
|
|
|
|
# ~ def id(self):
|
|
|
|
# ~ return self.m.TabPageID
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def parent(self):
|
|
|
|
return self.obj.Context
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _set_image_url(self, image):
|
|
|
|
if _P.exists(image):
|
|
|
|
return _P.to_url(image)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
path = _P.join(self._path, DIR['images'], image)
|
|
|
|
return _P.to_url(path)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _special_properties(self, tipo, args):
|
|
|
|
if tipo == 'link' and not 'Label' in args:
|
|
|
|
args['Label'] = args['URL']
|
|
|
|
return args
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'button':
|
|
|
|
if 'ImageURL' in args:
|
|
|
|
args['ImageURL'] = self._set_image_url(args['ImageURL'])
|
|
|
|
args['FocusOnClick'] = args.get('FocusOnClick', False)
|
|
|
|
return args
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'roadmap':
|
|
|
|
args['Height'] = args.get('Height', self.height)
|
|
|
|
if 'Title' in args:
|
|
|
|
args['Text'] = args.pop('Title')
|
|
|
|
return args
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'tree':
|
|
|
|
args['SelectionType'] = args.get('SelectionType', SINGLE)
|
|
|
|
return args
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'grid':
|
|
|
|
args['ShowRowHeader'] = args.get('ShowRowHeader', True)
|
|
|
|
return args
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'pages':
|
|
|
|
args['Width'] = args.get('Width', self.width)
|
|
|
|
args['Height'] = args.get('Height', self.height)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return args
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def add_control(self, args):
|
|
|
|
tipo = args.pop('Type').lower()
|
|
|
|
root = args.pop('Root', '')
|
|
|
|
sheets = args.pop('Sheets', ())
|
|
|
|
columns = args.pop('Columns', ())
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo in ('listbox',):
|
|
|
|
control.path = self.path
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
setattr(self, name, control)
|
|
|
|
return control
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class UnoPages(UnoBaseObject):
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, obj):
|
|
|
|
super().__init__(obj)
|
|
|
|
self._sheets = []
|
|
|
|
self._events = None
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __setattr__(self, name, value):
|
|
|
|
if name in ('_sheets', '_events'):
|
|
|
|
self.__dict__[name] = value
|
|
|
|
else:
|
|
|
|
super().__setattr__(name, value)
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def type(self):
|
|
|
|
return 'pages'
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def current(self):
|
|
|
|
return self.obj.ActiveTabID
|
2019-10-12 20:16:00 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def active(self):
|
|
|
|
return self.current
|
2019-10-12 20:16:00 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
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)
|
2019-10-12 20:16:00 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def events(self):
|
|
|
|
return self._events
|
|
|
|
@events.setter
|
|
|
|
def events(self, controllers):
|
|
|
|
self._events = controllers
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def visible(self):
|
|
|
|
return self.obj.Visible
|
|
|
|
@visible.setter
|
|
|
|
def visible(self, value):
|
|
|
|
self.obj.Visible = value
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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]
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def remove(self, id):
|
|
|
|
self.obj.removeTab(id)
|
|
|
|
return
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def activate(self, id):
|
|
|
|
self.obj.activateTab(id)
|
|
|
|
return
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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,
|
|
|
|
}
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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',
|
|
|
|
}
|
|
|
|
# ~ 'CurrencyField': 'com.sun.star.awt.UnoControlCurrencyFieldModel',
|
|
|
|
# ~ 'DateField': 'com.sun.star.awt.UnoControlDateFieldModel',
|
|
|
|
# ~ 'FileControl': 'com.sun.star.awt.UnoControlFileControlModel',
|
|
|
|
# ~ 'FormattedField': 'com.sun.star.awt.UnoControlFormattedFieldModel',
|
|
|
|
# ~ 'NumericField': 'com.sun.star.awt.UnoControlNumericFieldModel',
|
|
|
|
# ~ 'PatternField': 'com.sun.star.awt.UnoControlPatternFieldModel',
|
|
|
|
# ~ 'ProgressBar': 'com.sun.star.awt.UnoControlProgressBarModel',
|
|
|
|
# ~ 'ScrollBar': 'com.sun.star.awt.UnoControlScrollBarModel',
|
|
|
|
# ~ 'SimpleAnimation': 'com.sun.star.awt.UnoControlSimpleAnimationModel',
|
|
|
|
# ~ 'SpinButton': 'com.sun.star.awt.UnoControlSpinButtonModel',
|
|
|
|
# ~ 'Throbber': 'com.sun.star.awt.UnoControlThrobberModel',
|
|
|
|
# ~ 'TimeField': 'com.sun.star.awt.UnoControlTimeFieldModel',
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
class LODialog(object):
|
2020-12-16 21:50:11 -06:00
|
|
|
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',
|
|
|
|
}
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, args):
|
|
|
|
self._obj = self._create(args)
|
|
|
|
self._model = self.obj.Model
|
2019-09-09 22:13:01 -05:00
|
|
|
self._events = None
|
2020-12-16 21:50:11 -06:00
|
|
|
self._modal = True
|
|
|
|
self._controls = {}
|
|
|
|
self._color_on_focus = COLOR_ON_FOCUS
|
|
|
|
self._id = ''
|
|
|
|
self._path = ''
|
|
|
|
self._init_controls()
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _create(self, args):
|
|
|
|
service = 'com.sun.star.awt.DialogProvider'
|
|
|
|
path = args.pop('Path', '')
|
2019-09-09 22:13:01 -05:00
|
|
|
if path:
|
2020-12-16 21:50:11 -06:00
|
|
|
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()
|
2019-09-09 22:13:01 -05:00
|
|
|
if location == 'user':
|
|
|
|
location = 'application'
|
2020-12-16 21:50:11 -06:00
|
|
|
url = f'vnd.sun.star.script:{library}.{name}?location={location}'
|
2019-10-13 23:44:45 -05:00
|
|
|
if location == 'document':
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-09-09 22:13:01 -05:00
|
|
|
|
|
|
|
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)
|
2020-12-16 21:50:11 -06:00
|
|
|
_set_properties(model, args)
|
2019-09-09 22:13:01 -05:00
|
|
|
dlg.setModel(model)
|
|
|
|
dlg.setVisible(False)
|
|
|
|
dlg.createPeer(toolkit, None)
|
|
|
|
return dlg
|
|
|
|
|
2019-10-13 23:44:45 -05:00
|
|
|
def _get_type_control(self, name):
|
2020-12-16 21:50:11 -06:00
|
|
|
name = name.split('.')[2]
|
2019-10-13 23:44:45 -05:00
|
|
|
types = {
|
2020-12-16 21:50:11 -06:00
|
|
|
'UnoFixedTextControl': 'label',
|
|
|
|
'UnoEditControl': 'text',
|
|
|
|
'UnoButtonControl': 'button',
|
2019-10-13 23:44:45 -05:00
|
|
|
}
|
|
|
|
return types[name]
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-13 23:44:45 -05:00
|
|
|
def _init_controls(self):
|
|
|
|
for control in self.obj.getControls():
|
|
|
|
tipo = self._get_type_control(control.ImplementationName)
|
|
|
|
name = control.Model.Name
|
2020-12-16 21:50:11 -06:00
|
|
|
control = UNO_CLASSES[tipo](control)
|
2019-10-13 23:44:45 -05:00
|
|
|
setattr(self, name, control)
|
2019-09-09 22:13:01 -05:00
|
|
|
return
|
|
|
|
|
|
|
|
@property
|
|
|
|
def obj(self):
|
|
|
|
return self._obj
|
|
|
|
|
|
|
|
@property
|
|
|
|
def model(self):
|
|
|
|
return self._model
|
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def controls(self):
|
|
|
|
return self._controls
|
2019-10-19 20:01:04 -05:00
|
|
|
|
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def path(self):
|
|
|
|
return self._path
|
|
|
|
@property
|
|
|
|
def id(self):
|
|
|
|
return self._id
|
|
|
|
@id.setter
|
|
|
|
def id(self, value):
|
|
|
|
self._id = value
|
|
|
|
self._path = _P.from_id(value)
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2019-10-14 19:48:13 -05:00
|
|
|
@property
|
|
|
|
def height(self):
|
|
|
|
return self.model.Height
|
|
|
|
@height.setter
|
|
|
|
def height(self, value):
|
|
|
|
self.model.Height = value
|
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
@property
|
|
|
|
def width(self):
|
|
|
|
return self.model.Width
|
|
|
|
@width.setter
|
|
|
|
def width(self, value):
|
|
|
|
self.model.Width = value
|
|
|
|
|
2019-10-14 23:43:42 -05:00
|
|
|
@property
|
2020-12-16 21:50:11 -06:00
|
|
|
def visible(self):
|
|
|
|
return self.obj.Visible
|
|
|
|
@visible.setter
|
|
|
|
def visible(self, value):
|
|
|
|
self.obj.Visible = value
|
2019-10-14 23:43:42 -05:00
|
|
|
|
2019-10-14 19:48:13 -05:00
|
|
|
@property
|
|
|
|
def step(self):
|
|
|
|
return self.model.Step
|
|
|
|
@step.setter
|
|
|
|
def step(self, value):
|
|
|
|
self.model.Step = value
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
@property
|
|
|
|
def events(self):
|
|
|
|
return self._events
|
|
|
|
@events.setter
|
|
|
|
def events(self, controllers):
|
2020-12-16 21:50:11 -06:00
|
|
|
self._events = controllers(self)
|
2019-09-09 22:13:01 -05:00
|
|
|
self._connect_listeners()
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@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)
|
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
def _connect_listeners(self):
|
2020-12-16 21:50:11 -06:00
|
|
|
for control in self.obj.Controls:
|
|
|
|
_add_listeners(self.events, control, control.Model.Name)
|
2019-09-09 22:13:01 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _set_image_url(self, image):
|
|
|
|
if _P.exists(image):
|
|
|
|
return _P.to_url(image)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
path = _P.join(self._path, DIR['images'], image)
|
|
|
|
return _P.to_url(path)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def _special_properties(self, tipo, args):
|
|
|
|
if tipo == 'link' and not 'Label' in args:
|
|
|
|
args['Label'] = args['URL']
|
|
|
|
return args
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'button':
|
|
|
|
if 'ImageURL' in args:
|
|
|
|
args['ImageURL'] = self._set_image_url(args['ImageURL'])
|
|
|
|
args['FocusOnClick'] = args.get('FocusOnClick', False)
|
|
|
|
return args
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'roadmap':
|
|
|
|
args['Height'] = args.get('Height', self.height)
|
|
|
|
if 'Title' in args:
|
|
|
|
args['Text'] = args.pop('Title')
|
|
|
|
return args
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if tipo == 'tree':
|
|
|
|
args['SelectionType'] = args.get('SelectionType', SINGLE)
|
|
|
|
return args
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
if tipo == 'grid':
|
2020-12-16 21:50:11 -06:00
|
|
|
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']
|
2019-09-09 22:13:01 -05:00
|
|
|
self.model.insertByName(name, model)
|
2019-10-10 00:07:45 -05:00
|
|
|
control = self.obj.getControl(name)
|
2020-12-16 21:50:11 -06:00
|
|
|
_add_listeners(self.events, control, name)
|
|
|
|
control = UNO_CLASSES[tipo](control)
|
|
|
|
|
|
|
|
if tipo in ('listbox',):
|
|
|
|
control.path = self.path
|
2019-10-21 00:28:00 -05:00
|
|
|
|
|
|
|
if tipo == 'tree' and root:
|
|
|
|
control.root = root
|
2020-12-16 21:50:11 -06:00
|
|
|
elif tipo == 'grid' and columns:
|
|
|
|
control.columns = columns
|
2019-10-29 11:23:24 -06:00
|
|
|
elif tipo == 'pages' and sheets:
|
|
|
|
control.sheets = sheets
|
|
|
|
control.events = self.events
|
2019-10-21 00:28:00 -05:00
|
|
|
|
2019-09-09 22:13:01 -05:00
|
|
|
setattr(self, name, control)
|
2020-12-16 21:50:11 -06:00
|
|
|
self._controls[name] = control
|
|
|
|
return control
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2019-10-19 20:01:04 -05:00
|
|
|
def center(self, control, x=0, y=0):
|
|
|
|
w = self.width
|
|
|
|
h = self.height
|
|
|
|
|
|
|
|
if isinstance(control, tuple):
|
2020-12-16 21:50:11 -06:00
|
|
|
wt = self.SEPARATION * -1
|
2019-10-19 20:01:04 -05:00
|
|
|
for c in control:
|
2020-12-16 21:50:11 -06:00
|
|
|
wt += c.width + self.SEPARATION
|
2019-10-19 20:01:04 -05:00
|
|
|
x = w / 2 - wt / 2
|
|
|
|
for c in control:
|
|
|
|
c.x = x
|
2020-12-16 21:50:11 -06:00
|
|
|
x = c.x + c.width + self.SEPARATION
|
2019-10-19 20:01:04 -05:00
|
|
|
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
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
class LOSheets(object):
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return LODocs().active[index]
|
|
|
|
|
|
|
|
def __enter__(self):
|
|
|
|
return self
|
|
|
|
|
|
|
|
def __exit__(self, exc_type, exc_value, traceback):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
class LOCells(object):
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return LODocs().active.active[index]
|
|
|
|
|
|
|
|
|
|
|
|
class LOShortCut(object):
|
|
|
|
# ~ getKeyEventsByCommand
|
|
|
|
|
|
|
|
def __init__(self, app):
|
|
|
|
self._app = app
|
|
|
|
self._scm = None
|
|
|
|
self._init_values()
|
|
|
|
|
|
|
|
def _init_values(self):
|
|
|
|
name = 'com.sun.star.ui.GlobalAcceleratorConfiguration'
|
|
|
|
instance = 'com.sun.star.ui.ModuleUIConfigurationManagerSupplier'
|
|
|
|
service = TYPE_DOC[self._app]
|
|
|
|
manager = create_instance(instance, True)
|
|
|
|
uicm = manager.getUIConfigurationManager(service)
|
|
|
|
self._scm = uicm.ShortCutManager
|
|
|
|
return
|
|
|
|
|
|
|
|
def __contains__(self, item):
|
|
|
|
cmd = self._get_command(item)
|
|
|
|
return bool(cmd)
|
|
|
|
|
|
|
|
def _get_key_event(self, command):
|
|
|
|
events = self._scm.AllKeyEvents
|
|
|
|
for event in events:
|
|
|
|
cmd = self._scm.getCommandByKeyEvent(event)
|
|
|
|
if cmd == command:
|
|
|
|
break
|
|
|
|
return event
|
|
|
|
|
|
|
|
def _to_key_event(self, shortcut):
|
|
|
|
key_event = KeyEvent()
|
|
|
|
keys = shortcut.split('+')
|
|
|
|
for v in keys[:-1]:
|
|
|
|
key_event.Modifiers += MODIFIERS[v.lower()]
|
|
|
|
key_event.KeyCode = getattr(Key, keys[-1].upper())
|
|
|
|
return key_event
|
|
|
|
|
|
|
|
def _get_command(self, shortcut):
|
|
|
|
command = ''
|
|
|
|
key_event = self._to_key_event(shortcut)
|
|
|
|
try:
|
|
|
|
command = self._scm.getCommandByKeyEvent(key_event)
|
|
|
|
except NoSuchElementException:
|
|
|
|
debug(f'No exists: {shortcut}')
|
|
|
|
return command
|
|
|
|
|
|
|
|
def add(self, shortcut, command):
|
|
|
|
if isinstance(command, dict):
|
|
|
|
command = _get_url_script(command)
|
|
|
|
key_event = self._to_key_event(shortcut)
|
|
|
|
self._scm.setKeyEvent(key_event, command)
|
|
|
|
self._scm.store()
|
|
|
|
return
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
self._scm.reset()
|
|
|
|
self._scm.store()
|
|
|
|
return
|
|
|
|
|
|
|
|
def remove(self, shortcut):
|
|
|
|
key_event = self._to_key_event(shortcut)
|
|
|
|
try:
|
|
|
|
self._scm.removeKeyEvent(key_event)
|
|
|
|
self._scm.store()
|
|
|
|
except NoSuchElementException:
|
|
|
|
debug(f'No exists: {shortcut}')
|
|
|
|
return
|
|
|
|
|
|
|
|
def remove_by_command(self, command):
|
|
|
|
if isinstance(command, dict):
|
|
|
|
command = _get_url_script(command)
|
|
|
|
try:
|
|
|
|
self._scm.removeCommandFromAllKeyEvents(command)
|
|
|
|
self._scm.store()
|
|
|
|
except NoSuchElementException:
|
|
|
|
debug(f'No exists: {command}')
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class LOShortCuts(object):
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return LOShortCut(index)
|
|
|
|
|
|
|
|
|
|
|
|
class LOMenu(object):
|
|
|
|
|
|
|
|
def __init__(self, app):
|
|
|
|
self._app = app
|
|
|
|
self._ui = None
|
|
|
|
self._pymenus = None
|
|
|
|
self._menu = None
|
|
|
|
self._menus = self._get_menus()
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
if isinstance(index, int):
|
|
|
|
self._menu = self._menus[index]
|
|
|
|
else:
|
|
|
|
for menu in self._menus:
|
|
|
|
cmd = menu.get('CommandURL', '')
|
|
|
|
if MENUS[index.lower()] == cmd:
|
|
|
|
self._menu = menu
|
|
|
|
break
|
2021-01-03 20:57:19 -06:00
|
|
|
# ~ line = self._menu.get('CommandURL', '')
|
|
|
|
# ~ line += self._get_submenus(self._menu['ItemDescriptorContainer'])
|
|
|
|
return self._menu
|
2020-12-16 21:50:11 -06:00
|
|
|
|
|
|
|
def _get_menus(self):
|
|
|
|
instance = 'com.sun.star.ui.ModuleUIConfigurationManagerSupplier'
|
|
|
|
service = TYPE_DOC[self._app]
|
|
|
|
manager = create_instance(instance, True)
|
|
|
|
self._ui = manager.getUIConfigurationManager(service)
|
|
|
|
self._pymenus = self._ui.getSettings(NODE_MENUBAR, True)
|
|
|
|
data = []
|
|
|
|
for menu in self._pymenus:
|
|
|
|
data.append(data_to_dict(menu))
|
|
|
|
return data
|
|
|
|
|
|
|
|
def _get_info(self, menu):
|
|
|
|
line = menu.get('CommandURL', '')
|
|
|
|
line += self._get_submenus(menu['ItemDescriptorContainer'])
|
|
|
|
return line
|
|
|
|
|
|
|
|
def _get_submenus(self, menu, level=1):
|
|
|
|
line = ''
|
|
|
|
for i, v in enumerate(menu):
|
|
|
|
data = data_to_dict(v)
|
|
|
|
cmd = data.get('CommandURL', '----------')
|
|
|
|
line += f'\n{" " * level}āā ({i}) {cmd}'
|
|
|
|
submenu = data.get('ItemDescriptorContainer', None)
|
|
|
|
if not submenu is None:
|
|
|
|
line += self._get_submenus(submenu, level + 1)
|
|
|
|
return line
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
info = '\n'.join([self._get_info(m) for m in self._menus])
|
|
|
|
return info
|
|
|
|
|
|
|
|
def _get_index_menu(self, menu, command):
|
|
|
|
index = -1
|
|
|
|
for i, v in enumerate(menu):
|
|
|
|
data = data_to_dict(v)
|
|
|
|
cmd = data.get('CommandURL', '')
|
|
|
|
if cmd == command:
|
|
|
|
index = i
|
|
|
|
break
|
|
|
|
return index
|
|
|
|
|
|
|
|
def insert(self, name, args):
|
|
|
|
idc = None
|
|
|
|
replace = False
|
|
|
|
command = args['CommandURL']
|
|
|
|
label = args['Label']
|
|
|
|
|
|
|
|
self[name]
|
|
|
|
menu = self._menu['ItemDescriptorContainer']
|
|
|
|
submenu = args.get('Submenu', False)
|
|
|
|
if submenu:
|
|
|
|
idc = self._ui.createSettings()
|
|
|
|
|
|
|
|
index = self._get_index_menu(menu, command)
|
|
|
|
if index == -1:
|
|
|
|
if 'Index' in args:
|
|
|
|
index = args['Index']
|
|
|
|
else:
|
|
|
|
index = self._get_index_menu(menu, args['After']) + 1
|
|
|
|
else:
|
|
|
|
replace = True
|
|
|
|
|
|
|
|
data = dict (
|
|
|
|
CommandURL = command,
|
|
|
|
Label = label,
|
|
|
|
Style = 0,
|
|
|
|
Type = 0,
|
|
|
|
ItemDescriptorContainer = idc,
|
|
|
|
)
|
|
|
|
self._save(menu, data, index, replace)
|
|
|
|
self._insert_submenu(idc, submenu)
|
|
|
|
return
|
|
|
|
|
|
|
|
def _get_command(self, args):
|
|
|
|
shortcut = args.get('ShortCut', '')
|
|
|
|
cmd = args['CommandURL']
|
|
|
|
if isinstance(cmd, dict):
|
|
|
|
cmd = _get_url_script(cmd)
|
|
|
|
if shortcut:
|
|
|
|
LOShortCut(self._app).add(shortcut, cmd)
|
|
|
|
return cmd
|
|
|
|
|
|
|
|
def _insert_submenu(self, parent, menus):
|
|
|
|
for i, v in enumerate(menus):
|
|
|
|
submenu = v.pop('Submenu', False)
|
|
|
|
if submenu:
|
|
|
|
idc = self._ui.createSettings()
|
|
|
|
v['ItemDescriptorContainer'] = idc
|
|
|
|
v['Type'] = 0
|
|
|
|
if v['Label'] == '-':
|
|
|
|
v['Type'] = 1
|
|
|
|
else:
|
|
|
|
v['CommandURL'] = self._get_command(v)
|
|
|
|
self._save(parent, v, i)
|
|
|
|
if submenu:
|
|
|
|
self._insert_submenu(idc, submenu)
|
|
|
|
return
|
|
|
|
|
|
|
|
def remove(self, name, command):
|
|
|
|
self[name]
|
|
|
|
menu = self._menu['ItemDescriptorContainer']
|
|
|
|
index = self._get_index_menu(menu, command)
|
|
|
|
if index > -1:
|
|
|
|
uno.invoke(menu, 'removeByIndex', (index,))
|
|
|
|
self._ui.replaceSettings(NODE_MENUBAR, self._pymenus)
|
|
|
|
self._ui.store()
|
|
|
|
return
|
|
|
|
|
|
|
|
def _save(self, menu, properties, index, replace=False):
|
|
|
|
properties = dict_to_property(properties, True)
|
|
|
|
if replace:
|
|
|
|
uno.invoke(menu, 'replaceByIndex', (index, properties))
|
|
|
|
else:
|
|
|
|
uno.invoke(menu, 'insertByIndex', (index, properties))
|
|
|
|
self._ui.replaceSettings(NODE_MENUBAR, self._pymenus)
|
|
|
|
self._ui.store()
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
class LOMenus(object):
|
|
|
|
|
|
|
|
def __getitem__(self, index):
|
|
|
|
return LOMenu(index)
|
|
|
|
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
class LOWindow(object):
|
2020-12-16 21:50:11 -06:00
|
|
|
EMPTY = """<?xml version="1.0" encoding="UTF-8"?>
|
2019-10-29 11:23:24 -06:00
|
|
|
<!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"/>"""
|
2020-12-16 21:50:11 -06:00
|
|
|
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',
|
|
|
|
}
|
2019-10-10 00:07:45 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, args):
|
2019-10-10 00:07:45 -05:00
|
|
|
self._events = None
|
|
|
|
self._menu = None
|
|
|
|
self._container = None
|
2020-12-16 21:50:11 -06:00
|
|
|
self._model = None
|
|
|
|
self._id = ''
|
|
|
|
self._path = ''
|
|
|
|
self._obj = self._create(args)
|
2019-10-29 11:23:24 -06:00
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
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)
|
2019-10-29 11:23:24 -06:00
|
|
|
self._create_subcontainer(ps)
|
2019-10-10 00:07:45 -05:00
|
|
|
# ~ 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)
|
2020-12-16 21:50:11 -06:00
|
|
|
model.BackgroundColor = get_color((225, 225, 225))
|
2019-10-10 00:07:45 -05:00
|
|
|
self._container.setModel(model)
|
|
|
|
self._container.createPeer(self._toolkit, self._window)
|
|
|
|
self._container.setPosSize(*ps, POSSIZE)
|
|
|
|
self._frame.setComponent(self._container, None)
|
|
|
|
return
|
|
|
|
|
2019-10-29 11:23:24 -06:00
|
|
|
def _create_subcontainer(self, ps):
|
|
|
|
service = 'com.sun.star.awt.ContainerWindowProvider'
|
|
|
|
cwp = create_instance(service, True)
|
2020-12-16 21:50:11 -06:00
|
|
|
|
|
|
|
path_tmp = _P.save_tmp(self.EMPTY)
|
|
|
|
subcont = cwp.createContainerWindow(
|
|
|
|
_P.to_url(path_tmp), '', self._container.getPeer(), None)
|
|
|
|
_P.kill(path_tmp)
|
2019-10-29 11:23:24 -06:00
|
|
|
|
|
|
|
subcont.setPosSize(0, 0, 500, 500, POSSIZE)
|
|
|
|
subcont.setVisible(True)
|
|
|
|
self._container.addControl('subcont', subcont)
|
|
|
|
self._subcont = subcont
|
2020-12-16 21:50:11 -06:00
|
|
|
self._model = subcont.Model
|
2019-10-10 00:07:45 -05:00
|
|
|
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)
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ self._container.addKeyListener(EventsKeyWindow(self))
|
2019-10-10 00:07:45 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
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
|
2019-10-10 00:07:45 -05:00
|
|
|
|
|
|
|
@property
|
|
|
|
def events(self):
|
|
|
|
return self._events
|
|
|
|
@events.setter
|
2020-12-16 21:50:11 -06:00
|
|
|
def events(self, controllers):
|
|
|
|
self._events = controllers(self)
|
2019-10-10 00:07:45 -05:00
|
|
|
self._add_listeners()
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def model(self):
|
|
|
|
return self._model
|
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
@property
|
|
|
|
def width(self):
|
|
|
|
return self._container.Size.Width
|
|
|
|
|
|
|
|
@property
|
|
|
|
def height(self):
|
|
|
|
return self._container.Size.Height
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._title.lower().replace(' ', '_')
|
|
|
|
|
|
|
|
def add_menu(self, menus):
|
|
|
|
self._create_menu(menus)
|
|
|
|
return
|
|
|
|
|
2019-10-10 00:07:45 -05:00
|
|
|
def open(self):
|
|
|
|
self._window.setVisible(True)
|
|
|
|
return
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
self._window.setMenuBar(None)
|
|
|
|
self._window.dispose()
|
|
|
|
self._frame.close(True)
|
|
|
|
return
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def create_window(args):
|
|
|
|
return LOWindow(args)
|
2019-09-08 00:25:30 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class classproperty:
|
|
|
|
def __init__(self, method=None):
|
|
|
|
self.fget = method
|
|
|
|
|
|
|
|
def __get__(self, instance, cls=None):
|
|
|
|
return self.fget(cls)
|
|
|
|
|
|
|
|
def getter(self, method):
|
|
|
|
self.fget = method
|
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
|
|
class ClipBoard(object):
|
|
|
|
SERVICE = 'com.sun.star.datatransfer.clipboard.SystemClipboard'
|
|
|
|
CLIPBOARD_FORMAT_TEXT = 'text/plain;charset=utf-16'
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class TextTransferable(unohelper.Base, XTransferable):
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, text):
|
|
|
|
df = DataFlavor()
|
|
|
|
df.MimeType = ClipBoard.CLIPBOARD_FORMAT_TEXT
|
|
|
|
df.HumanPresentableName = "encoded text utf-16"
|
|
|
|
self.flavors = (df,)
|
|
|
|
self._data = text
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def getTransferData(self, flavor):
|
|
|
|
return self._data
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def getTransferDataFlavors(self):
|
|
|
|
return self.flavors
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def set(cls, value):
|
|
|
|
ts = cls.TextTransferable(value)
|
|
|
|
sc = create_instance(cls.SERVICE)
|
|
|
|
sc.setContents(ts, None)
|
2019-09-27 12:17:21 -05:00
|
|
|
return
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classproperty
|
|
|
|
def contents(cls):
|
|
|
|
df = None
|
|
|
|
text = ''
|
|
|
|
sc = create_instance(cls.SERVICE)
|
|
|
|
transferable = sc.getContents()
|
|
|
|
data = transferable.getTransferDataFlavors()
|
|
|
|
for df in data:
|
|
|
|
if df.MimeType == cls.CLIPBOARD_FORMAT_TEXT:
|
|
|
|
break
|
|
|
|
if df:
|
|
|
|
text = transferable.getTransferData(df)
|
|
|
|
return text
|
|
|
|
_CB = ClipBoard
|
|
|
|
|
|
|
|
|
|
|
|
class Paths(object):
|
|
|
|
FILE_PICKER = 'com.sun.star.ui.dialogs.FilePicker'
|
|
|
|
|
|
|
|
def __init__(self, path=''):
|
|
|
|
if path.startswith('file://'):
|
|
|
|
path = str(Path(uno.fileUrlToSystemPath(path)).resolve())
|
|
|
|
self._path = Path(path)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def path(self):
|
|
|
|
return str(self._path.parent)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def file_name(self):
|
|
|
|
return self._path.name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
return self._path.stem
|
|
|
|
|
|
|
|
@property
|
|
|
|
def ext(self):
|
|
|
|
return self._path.suffix[1:]
|
|
|
|
|
|
|
|
@property
|
|
|
|
def info(self):
|
|
|
|
return self.path, self.file_name, self.name, self.ext
|
|
|
|
|
|
|
|
@property
|
|
|
|
def url(self):
|
|
|
|
return self._path.as_uri()
|
|
|
|
|
|
|
|
@property
|
|
|
|
def size(self):
|
|
|
|
return self._path.stat().st_size
|
|
|
|
|
|
|
|
@classproperty
|
|
|
|
def home(self):
|
|
|
|
return str(Path.home())
|
|
|
|
|
|
|
|
@classproperty
|
|
|
|
def documents(self):
|
|
|
|
return self.config()
|
|
|
|
|
|
|
|
@classproperty
|
|
|
|
def temp_dir(self):
|
|
|
|
return tempfile.gettempdir()
|
|
|
|
|
|
|
|
@classproperty
|
|
|
|
def python(self):
|
|
|
|
if IS_WIN:
|
|
|
|
path = self.join(self.config('Module'), PYTHON)
|
|
|
|
elif IS_MAC:
|
|
|
|
path = self.join(self.config('Module'), '..', 'Resources', PYTHON)
|
|
|
|
else:
|
|
|
|
path = sys.executable
|
|
|
|
return path
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def dir_tmp(self, only_name=False):
|
|
|
|
dt = tempfile.TemporaryDirectory()
|
|
|
|
if only_name:
|
|
|
|
dt = dt.name
|
|
|
|
return dt
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def tmp(cls, ext=''):
|
|
|
|
tmp = tempfile.NamedTemporaryFile(suffix=ext)
|
|
|
|
return tmp.name
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def save_tmp(cls, data):
|
|
|
|
path_tmp = cls.tmp()
|
|
|
|
cls.save(path_tmp, data)
|
|
|
|
return path_tmp
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def config(cls, name='Work'):
|
|
|
|
"""
|
|
|
|
Return de path name in config
|
|
|
|
http://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1util_1_1XPathSettings.html
|
|
|
|
"""
|
|
|
|
path = create_instance('com.sun.star.util.PathSettings')
|
|
|
|
return cls.to_system(getattr(path, name))
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def get(cls, init_dir='', filters: str=''):
|
|
|
|
"""
|
|
|
|
Options: http://api.libreoffice.org/docs/idl/ref/namespacecom_1_1sun_1_1star_1_1ui_1_1dialogs_1_1TemplateDescription.html
|
|
|
|
filters: 'xml' or 'txt,xml'
|
|
|
|
"""
|
|
|
|
if not init_dir:
|
|
|
|
init_dir = cls.documents
|
|
|
|
init_dir = cls.to_url(init_dir)
|
|
|
|
file_picker = create_instance(cls.FILE_PICKER)
|
|
|
|
file_picker.setTitle(_('Select path'))
|
|
|
|
file_picker.setDisplayDirectory(init_dir)
|
|
|
|
file_picker.initialize((2,))
|
|
|
|
if filters:
|
|
|
|
filters = [(f.upper(), f'*.{f.lower()}') for f in filters.split(',')]
|
|
|
|
file_picker.setCurrentFilter(filters[0][0])
|
|
|
|
for f in filters:
|
|
|
|
file_picker.appendFilter(f[0], f[1])
|
|
|
|
|
|
|
|
path = ''
|
|
|
|
if file_picker.execute():
|
|
|
|
path = cls.to_system(file_picker.getSelectedFiles()[0])
|
|
|
|
return path
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def get_dir(cls, init_dir=''):
|
|
|
|
folder_picker = create_instance(cls.FILE_PICKER)
|
|
|
|
if not init_dir:
|
|
|
|
init_dir = cls.documents
|
|
|
|
init_dir = cls.to_url(init_dir)
|
|
|
|
folder_picker.setTitle(_('Select directory'))
|
|
|
|
folder_picker.setDisplayDirectory(init_dir)
|
|
|
|
|
|
|
|
path = ''
|
|
|
|
if folder_picker.execute():
|
|
|
|
path = cls.to_system(folder_picker.getDisplayDirectory())
|
|
|
|
return path
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def get_file(cls, init_dir: str='', filters: str='', multiple: bool=False):
|
|
|
|
"""
|
|
|
|
init_folder: folder default open
|
|
|
|
multiple: True for multiple selected
|
|
|
|
filters: 'xml' or 'xml,txt'
|
|
|
|
"""
|
|
|
|
if not init_dir:
|
|
|
|
init_dir = cls.documents
|
|
|
|
init_dir = cls.to_url(init_dir)
|
2019-09-08 00:25:30 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
file_picker = create_instance(cls.FILE_PICKER)
|
|
|
|
file_picker.setTitle(_('Select file'))
|
|
|
|
file_picker.setDisplayDirectory(init_dir)
|
|
|
|
file_picker.setMultiSelectionMode(multiple)
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if filters:
|
|
|
|
filters = [(f.upper(), f'*.{f.lower()}') for f in filters.split(',')]
|
|
|
|
file_picker.setCurrentFilter(filters[0][0])
|
|
|
|
for f in filters:
|
|
|
|
file_picker.appendFilter(f[0], f[1])
|
|
|
|
|
|
|
|
path = ''
|
|
|
|
if file_picker.execute():
|
|
|
|
files = file_picker.getSelectedFiles()
|
|
|
|
path = [cls.to_system(f) for f in files]
|
|
|
|
if not multiple:
|
|
|
|
path = path[0]
|
|
|
|
return path
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def replace_ext(cls, path, new_ext):
|
|
|
|
p = Paths(path)
|
|
|
|
name = f'{p.name}.{new_ext}'
|
|
|
|
path = cls.join(p.path, name)
|
|
|
|
return path
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def exists(cls, path):
|
|
|
|
result = False
|
|
|
|
if path:
|
|
|
|
path = cls.to_system(path)
|
|
|
|
result = Path(path).exists()
|
|
|
|
return result
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def exists_app(cls, name_app):
|
|
|
|
return bool(shutil.which(name_app))
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def open(cls, path):
|
|
|
|
if IS_WIN:
|
|
|
|
os.startfile(path)
|
|
|
|
else:
|
|
|
|
pid = subprocess.Popen(['xdg-open', path]).pid
|
|
|
|
return
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def is_dir(cls, path):
|
|
|
|
return Path(path).is_dir()
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def is_file(cls, path):
|
|
|
|
return Path(path).is_file()
|
2019-09-09 22:13:01 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def join(cls, *paths):
|
|
|
|
return str(Path(paths[0]).joinpath(*paths[1:]))
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def save(cls, path, data, encoding='utf-8'):
|
|
|
|
result = bool(Path(path).write_text(data, encoding=encoding))
|
|
|
|
return result
|
2019-10-12 20:16:00 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def save_bin(cls, path, data):
|
|
|
|
result = bool(Path(path).write_bytes(data))
|
|
|
|
return result
|
2019-09-18 21:41:47 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def read(cls, path, encoding='utf-8'):
|
|
|
|
data = Path(path).read_text(encoding=encoding)
|
|
|
|
return data
|
2019-09-18 21:41:47 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def read_bin(cls, path):
|
|
|
|
data = Path(path).read_bytes()
|
|
|
|
return data
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def to_url(cls, path):
|
|
|
|
if not path.startswith('file://'):
|
|
|
|
path = Path(path).as_uri()
|
|
|
|
return path
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def to_system(cls, path):
|
|
|
|
if path.startswith('file://'):
|
|
|
|
path = str(Path(uno.fileUrlToSystemPath(path)).resolve())
|
|
|
|
return path
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def kill(cls, path):
|
|
|
|
result = True
|
|
|
|
p = Path(path)
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
try:
|
|
|
|
if p.is_file():
|
|
|
|
p.unlink()
|
|
|
|
elif p.is_dir():
|
|
|
|
shutil.rmtree(path)
|
|
|
|
except OSError as e:
|
|
|
|
log.error(e)
|
|
|
|
result = False
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return result
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def files(cls, path, pattern='*'):
|
|
|
|
files = [str(p) for p in Path(path).glob(pattern) if p.is_file()]
|
|
|
|
return files
|
2020-03-12 22:51:38 -06:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def dirs(cls, path):
|
|
|
|
dirs = [str(p) for p in Path(path).iterdir() if p.is_dir()]
|
|
|
|
return dirs
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def walk(cls, path, filters=''):
|
|
|
|
paths = []
|
|
|
|
if filters in ('*', '*.*'):
|
|
|
|
filters = ''
|
|
|
|
for folder, _, files in os.walk(path):
|
|
|
|
if filters:
|
|
|
|
pattern = re.compile(r'\.(?:{})$'.format(filters), re.IGNORECASE)
|
|
|
|
paths += [cls.join(folder, f) for f in files if pattern.search(f)]
|
|
|
|
else:
|
|
|
|
paths += [cls.join(folder, f) for f in files]
|
|
|
|
return paths
|
2019-10-19 20:01:04 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def walk_dir(cls, path, tree=False):
|
|
|
|
folders = []
|
|
|
|
if tree:
|
|
|
|
i = 0
|
|
|
|
p = 0
|
|
|
|
parents = {path: 0}
|
|
|
|
for root, dirs, _ in os.walk(path):
|
|
|
|
for name in dirs:
|
|
|
|
i += 1
|
|
|
|
rn = cls.join(root, name)
|
|
|
|
if not rn in parents:
|
|
|
|
parents[rn] = i
|
|
|
|
folders.append((i, parents[root], name))
|
2019-09-27 12:17:21 -05:00
|
|
|
else:
|
2020-12-16 21:50:11 -06:00
|
|
|
for root, dirs, _ in os.walk(path):
|
|
|
|
folders += [cls.join(root, name) for name in dirs]
|
|
|
|
return folders
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def from_id(cls, id_ext):
|
|
|
|
pip = CTX.getValueByName('/singletons/com.sun.star.deployment.PackageInformationProvider')
|
|
|
|
path = _P.to_system(pip.getPackageLocation(id_ext))
|
|
|
|
return path
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def from_json(cls, path):
|
|
|
|
data = json.loads(cls.read(path))
|
|
|
|
return data
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def to_json(cls, path, data):
|
|
|
|
data = json.dumps(data, indent=4, ensure_ascii=False, sort_keys=True)
|
|
|
|
return cls.save(path, data)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def from_csv(cls, path, args={}):
|
|
|
|
# ~ See https://docs.python.org/3.7/library/csv.html#csv.reader
|
|
|
|
with open(path) as f:
|
|
|
|
rows = tuple(csv.reader(f, **args))
|
|
|
|
return rows
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def to_csv(cls, path, data, args={}):
|
|
|
|
with open(path, 'w') as f:
|
|
|
|
writer = csv.writer(f, **args)
|
|
|
|
writer.writerows(data)
|
|
|
|
return
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def zip(cls, source, target='', pwd=''):
|
|
|
|
path_zip = target
|
|
|
|
if not isinstance(source, (tuple, list)):
|
|
|
|
path, _, name, _ = _P(source).info
|
|
|
|
start = len(path) + 1
|
|
|
|
if not target:
|
|
|
|
path_zip = f'{path}/{name}.zip'
|
|
|
|
|
|
|
|
if isinstance(source, (tuple, list)):
|
|
|
|
files = [(f, f[len(_P(f).path)+1:]) for f in source]
|
|
|
|
elif _P.is_file(source):
|
|
|
|
files = ((source, source[start:]),)
|
|
|
|
else:
|
|
|
|
files = [(f, f[start:]) for f in _P.walk(source)]
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
compression = zipfile.ZIP_DEFLATED
|
|
|
|
with zipfile.ZipFile(path_zip, 'w', compression=compression) as z:
|
|
|
|
for f in files:
|
|
|
|
z.write(f[0], f[1])
|
|
|
|
return
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def zip_content(cls, path):
|
|
|
|
with zipfile.ZipFile(path) as z:
|
|
|
|
names = z.namelist()
|
|
|
|
return names
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def unzip(cls, source, target='', members=None, pwd=None):
|
|
|
|
path = target
|
|
|
|
if not target:
|
|
|
|
path = _P(source).path
|
|
|
|
with zipfile.ZipFile(source) as z:
|
|
|
|
if not pwd is None:
|
|
|
|
pwd = pwd.encode()
|
|
|
|
if isinstance(members, str):
|
|
|
|
members = (members,)
|
|
|
|
z.extractall(path, members=members, pwd=pwd)
|
|
|
|
return True
|
2019-10-05 11:14:19 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def merge_zip(cls, target, zips):
|
|
|
|
try:
|
|
|
|
with zipfile.ZipFile(target, 'w', compression=zipfile.ZIP_DEFLATED) as t:
|
|
|
|
for path in zips:
|
|
|
|
with zipfile.ZipFile(path, compression=zipfile.ZIP_DEFLATED) as s:
|
|
|
|
for name in s.namelist():
|
|
|
|
t.writestr(name, s.open(name).read())
|
|
|
|
except Exception as e:
|
|
|
|
error(e)
|
|
|
|
return False
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
return True
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-26 21:59:52 -06:00
|
|
|
@classmethod
|
|
|
|
def image(cls, path):
|
|
|
|
gp = create_instance('com.sun.star.graphic.GraphicProvider')
|
|
|
|
image = gp.queryGraphic((
|
|
|
|
PropertyValue(Name='URL', Value=cls.to_url(path)),
|
|
|
|
))
|
|
|
|
return image
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
@classmethod
|
|
|
|
def copy(cls, source, target='', name=''):
|
|
|
|
p, f, n, e = _P(source).info
|
|
|
|
if target:
|
|
|
|
p = target
|
|
|
|
if name:
|
|
|
|
e = ''
|
|
|
|
n = name
|
|
|
|
path_new = cls.join(p, f'{n}{e}')
|
|
|
|
shutil.copy(source, path_new)
|
|
|
|
return path_new
|
|
|
|
_P = Paths
|
|
|
|
|
|
|
|
|
|
|
|
def __getattr__(name):
|
|
|
|
if name == 'active':
|
|
|
|
return LODocs().active
|
|
|
|
if name == 'active_sheet':
|
|
|
|
return LODocs().active.active
|
|
|
|
if name == 'selection':
|
|
|
|
return LODocs().active.selection
|
|
|
|
if name == 'current_region':
|
|
|
|
return LODocs().active.selection.current_region
|
|
|
|
if name in ('rectangle', 'pos_size'):
|
|
|
|
return Rectangle()
|
|
|
|
if name == 'paths':
|
|
|
|
return Paths
|
|
|
|
if name == 'docs':
|
|
|
|
return LODocs()
|
|
|
|
if name == 'sheets':
|
|
|
|
return LOSheets()
|
|
|
|
if name == 'cells':
|
|
|
|
return LOCells()
|
|
|
|
if name == 'menus':
|
|
|
|
return LOMenus()
|
|
|
|
if name == 'shortcuts':
|
|
|
|
return LOShortCuts()
|
|
|
|
if name == 'clipboard':
|
|
|
|
return ClipBoard
|
|
|
|
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
|
|
|
|
|
|
|
|
|
|
def create_dialog(args):
|
|
|
|
return LODialog(args)
|
2019-10-21 00:28:00 -05:00
|
|
|
|
|
|
|
|
2019-09-27 12:17:21 -05:00
|
|
|
def inputbox(message, default='', title=TITLE, echochar=''):
|
2019-09-10 22:20:31 -05:00
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
2020-12-16 21:50:11 -06:00
|
|
|
dlg = LODialog(args)
|
|
|
|
dlg.events = ControllersInput
|
2019-09-10 22:20:31 -05:00
|
|
|
|
|
|
|
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,
|
|
|
|
}
|
2019-09-27 12:17:21 -05:00
|
|
|
if echochar:
|
|
|
|
args['EchoChar'] = ord(echochar[0])
|
2019-09-10 22:20:31 -05:00
|
|
|
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 ''
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_fonts():
|
|
|
|
toolkit = create_instance('com.sun.star.awt.Toolkit')
|
|
|
|
device = toolkit.createScreenCompatibleDevice(0, 0)
|
|
|
|
return device.FontDescriptors
|
2019-09-18 21:41:47 -05:00
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# ~ From request
|
|
|
|
# ~ https://github.com/psf/requests/blob/master/requests/structures.py#L15
|
|
|
|
class CaseInsensitiveDict(MutableMapping):
|
2019-09-18 21:41:47 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __init__(self, data=None, **kwargs):
|
|
|
|
self._store = OrderedDict()
|
|
|
|
if data is None:
|
|
|
|
data = {}
|
|
|
|
self.update(data, **kwargs)
|
2019-09-18 21:41:47 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __setitem__(self, key, value):
|
|
|
|
# Use the lowercased key for lookups, but store the actual
|
|
|
|
# key alongside the value.
|
|
|
|
self._store[key.lower()] = (key, value)
|
2019-09-18 21:41:47 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __getitem__(self, key):
|
|
|
|
return self._store[key.lower()][1]
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __delitem__(self, key):
|
|
|
|
del self._store[key.lower()]
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __iter__(self):
|
|
|
|
return (casedkey for casedkey, mappedvalue in self._store.values())
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __len__(self):
|
|
|
|
return len(self._store)
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def lower_items(self):
|
|
|
|
"""Like iteritems(), but with all lowercase keys."""
|
|
|
|
values = (
|
|
|
|
(lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items()
|
|
|
|
)
|
|
|
|
return values
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
# Copy is required
|
|
|
|
def copy(self):
|
|
|
|
return CaseInsensitiveDict(self._store.values())
|
2019-09-27 12:17:21 -05:00
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
def __repr__(self):
|
|
|
|
return str(dict(self.items()))
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
|
|
|
|
# ~ https://en.wikipedia.org/wiki/Web_colors
|
2020-12-16 21:50:11 -06:00
|
|
|
def get_color(value):
|
2019-09-27 12:17:21 -05:00
|
|
|
COLORS = {
|
|
|
|
'aliceblue': 15792383,
|
|
|
|
'antiquewhite': 16444375,
|
|
|
|
'aqua': 65535,
|
|
|
|
'aquamarine': 8388564,
|
|
|
|
'azure': 15794175,
|
|
|
|
'beige': 16119260,
|
|
|
|
'bisque': 16770244,
|
|
|
|
'black': 0,
|
|
|
|
'blanchedalmond': 16772045,
|
|
|
|
'blue': 255,
|
|
|
|
'blueviolet': 9055202,
|
|
|
|
'brown': 10824234,
|
|
|
|
'burlywood': 14596231,
|
|
|
|
'cadetblue': 6266528,
|
|
|
|
'chartreuse': 8388352,
|
|
|
|
'chocolate': 13789470,
|
|
|
|
'coral': 16744272,
|
|
|
|
'cornflowerblue': 6591981,
|
|
|
|
'cornsilk': 16775388,
|
|
|
|
'crimson': 14423100,
|
|
|
|
'cyan': 65535,
|
|
|
|
'darkblue': 139,
|
|
|
|
'darkcyan': 35723,
|
|
|
|
'darkgoldenrod': 12092939,
|
|
|
|
'darkgray': 11119017,
|
|
|
|
'darkgreen': 25600,
|
|
|
|
'darkgrey': 11119017,
|
|
|
|
'darkkhaki': 12433259,
|
|
|
|
'darkmagenta': 9109643,
|
|
|
|
'darkolivegreen': 5597999,
|
|
|
|
'darkorange': 16747520,
|
|
|
|
'darkorchid': 10040012,
|
|
|
|
'darkred': 9109504,
|
|
|
|
'darksalmon': 15308410,
|
|
|
|
'darkseagreen': 9419919,
|
|
|
|
'darkslateblue': 4734347,
|
|
|
|
'darkslategray': 3100495,
|
|
|
|
'darkslategrey': 3100495,
|
|
|
|
'darkturquoise': 52945,
|
|
|
|
'darkviolet': 9699539,
|
|
|
|
'deeppink': 16716947,
|
|
|
|
'deepskyblue': 49151,
|
|
|
|
'dimgray': 6908265,
|
|
|
|
'dimgrey': 6908265,
|
|
|
|
'dodgerblue': 2003199,
|
|
|
|
'firebrick': 11674146,
|
|
|
|
'floralwhite': 16775920,
|
|
|
|
'forestgreen': 2263842,
|
|
|
|
'fuchsia': 16711935,
|
|
|
|
'gainsboro': 14474460,
|
|
|
|
'ghostwhite': 16316671,
|
|
|
|
'gold': 16766720,
|
|
|
|
'goldenrod': 14329120,
|
|
|
|
'gray': 8421504,
|
|
|
|
'grey': 8421504,
|
|
|
|
'green': 32768,
|
|
|
|
'greenyellow': 11403055,
|
|
|
|
'honeydew': 15794160,
|
|
|
|
'hotpink': 16738740,
|
|
|
|
'indianred': 13458524,
|
|
|
|
'indigo': 4915330,
|
|
|
|
'ivory': 16777200,
|
|
|
|
'khaki': 15787660,
|
|
|
|
'lavender': 15132410,
|
|
|
|
'lavenderblush': 16773365,
|
|
|
|
'lawngreen': 8190976,
|
|
|
|
'lemonchiffon': 16775885,
|
|
|
|
'lightblue': 11393254,
|
|
|
|
'lightcoral': 15761536,
|
|
|
|
'lightcyan': 14745599,
|
|
|
|
'lightgoldenrodyellow': 16448210,
|
|
|
|
'lightgray': 13882323,
|
|
|
|
'lightgreen': 9498256,
|
|
|
|
'lightgrey': 13882323,
|
|
|
|
'lightpink': 16758465,
|
|
|
|
'lightsalmon': 16752762,
|
|
|
|
'lightseagreen': 2142890,
|
|
|
|
'lightskyblue': 8900346,
|
|
|
|
'lightslategray': 7833753,
|
|
|
|
'lightslategrey': 7833753,
|
|
|
|
'lightsteelblue': 11584734,
|
|
|
|
'lightyellow': 16777184,
|
|
|
|
'lime': 65280,
|
|
|
|
'limegreen': 3329330,
|
|
|
|
'linen': 16445670,
|
|
|
|
'magenta': 16711935,
|
|
|
|
'maroon': 8388608,
|
|
|
|
'mediumaquamarine': 6737322,
|
|
|
|
'mediumblue': 205,
|
|
|
|
'mediumorchid': 12211667,
|
|
|
|
'mediumpurple': 9662683,
|
|
|
|
'mediumseagreen': 3978097,
|
|
|
|
'mediumslateblue': 8087790,
|
|
|
|
'mediumspringgreen': 64154,
|
|
|
|
'mediumturquoise': 4772300,
|
|
|
|
'mediumvioletred': 13047173,
|
|
|
|
'midnightblue': 1644912,
|
|
|
|
'mintcream': 16121850,
|
|
|
|
'mistyrose': 16770273,
|
|
|
|
'moccasin': 16770229,
|
|
|
|
'navajowhite': 16768685,
|
|
|
|
'navy': 128,
|
|
|
|
'oldlace': 16643558,
|
|
|
|
'olive': 8421376,
|
|
|
|
'olivedrab': 7048739,
|
|
|
|
'orange': 16753920,
|
|
|
|
'orangered': 16729344,
|
|
|
|
'orchid': 14315734,
|
|
|
|
'palegoldenrod': 15657130,
|
|
|
|
'palegreen': 10025880,
|
|
|
|
'paleturquoise': 11529966,
|
|
|
|
'palevioletred': 14381203,
|
|
|
|
'papayawhip': 16773077,
|
|
|
|
'peachpuff': 16767673,
|
|
|
|
'peru': 13468991,
|
|
|
|
'pink': 16761035,
|
|
|
|
'plum': 14524637,
|
|
|
|
'powderblue': 11591910,
|
|
|
|
'purple': 8388736,
|
|
|
|
'red': 16711680,
|
|
|
|
'rosybrown': 12357519,
|
|
|
|
'royalblue': 4286945,
|
|
|
|
'saddlebrown': 9127187,
|
|
|
|
'salmon': 16416882,
|
|
|
|
'sandybrown': 16032864,
|
|
|
|
'seagreen': 3050327,
|
|
|
|
'seashell': 16774638,
|
|
|
|
'sienna': 10506797,
|
|
|
|
'silver': 12632256,
|
|
|
|
'skyblue': 8900331,
|
|
|
|
'slateblue': 6970061,
|
|
|
|
'slategray': 7372944,
|
|
|
|
'slategrey': 7372944,
|
|
|
|
'snow': 16775930,
|
|
|
|
'springgreen': 65407,
|
|
|
|
'steelblue': 4620980,
|
|
|
|
'tan': 13808780,
|
|
|
|
'teal': 32896,
|
|
|
|
'thistle': 14204888,
|
|
|
|
'tomato': 16737095,
|
|
|
|
'turquoise': 4251856,
|
|
|
|
'violet': 15631086,
|
|
|
|
'wheat': 16113331,
|
|
|
|
'white': 16777215,
|
|
|
|
'whitesmoke': 16119285,
|
|
|
|
'yellow': 16776960,
|
|
|
|
'yellowgreen': 10145074,
|
|
|
|
}
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
if isinstance(value, tuple):
|
2019-10-05 11:14:19 -05:00
|
|
|
color = (value[0] << 16) + (value[1] << 8) + value[2]
|
|
|
|
else:
|
|
|
|
if value[0] == '#':
|
|
|
|
r, g, b = bytes.fromhex(value[1:])
|
|
|
|
color = (r << 16) + (g << 8) + b
|
|
|
|
else:
|
|
|
|
color = COLORS.get(value.lower(), -1)
|
|
|
|
return color
|
2019-09-27 12:17:21 -05:00
|
|
|
|
|
|
|
|
2019-10-14 23:43:42 -05:00
|
|
|
COLOR_ON_FOCUS = get_color('LightYellow')
|
|
|
|
|
|
|
|
|
2020-12-16 21:50:11 -06:00
|
|
|
class LOServer(object):
|
2019-10-05 11:14:19 -05:00
|
|
|
HOST = 'localhost'
|
|
|
|
PORT = '8100'
|
2020-12-16 21:50:11 -06:00
|
|
|
ARG = f'socket,host={HOST},port={PORT};urp;StarOffice.ComponentContext'
|
2019-10-05 11:14:19 -05:00
|
|
|
CMD = ['soffice',
|
|
|
|
'-env:SingleAppInstance=false',
|
2020-12-16 21:50:11 -06:00
|
|
|
'-env:UserInstallation=file:///tmp/LO_Process8100',
|
2019-10-05 11:14:19 -05:00
|
|
|
'--headless', '--norestore', '--invisible',
|
2020-12-16 21:50:11 -06:00
|
|
|
f'--accept={ARG}']
|
2019-10-05 11:14:19 -05:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self._server = None
|
|
|
|
self._ctx = None
|
|
|
|
self._sm = None
|
|
|
|
self._start_server()
|
|
|
|
self._init_values()
|
|
|
|
|
|
|
|
def _init_values(self):
|
|
|
|
global CTX
|
|
|
|
global SM
|
|
|
|
|
|
|
|
if not self.is_running:
|
|
|
|
return
|
|
|
|
|
|
|
|
ctx = uno.getComponentContext()
|
|
|
|
service = 'com.sun.star.bridge.UnoUrlResolver'
|
|
|
|
resolver = ctx.ServiceManager.createInstanceWithContext(service, ctx)
|
|
|
|
self._ctx = resolver.resolve('uno:{}'.format(self.ARG))
|
|
|
|
self._sm = self._ctx.getServiceManager()
|
|
|
|
CTX = self._ctx
|
|
|
|
SM = self._sm
|
|
|
|
return
|
|
|
|
|
|
|
|
@property
|
|
|
|
def is_running(self):
|
|
|
|
try:
|
|
|
|
s = socket.create_connection((self.HOST, self.PORT), 5.0)
|
|
|
|
s.close()
|
|
|
|
debug('LibreOffice is running...')
|
|
|
|
return True
|
|
|
|
except ConnectionRefusedError:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _start_server(self):
|
|
|
|
if self.is_running:
|
|
|
|
return
|
|
|
|
|
|
|
|
for i in range(3):
|
|
|
|
self._server = subprocess.Popen(self.CMD,
|
|
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
|
|
time.sleep(3)
|
|
|
|
if self.is_running:
|
|
|
|
break
|
|
|
|
return
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
if self._server is None:
|
|
|
|
print('Search pgrep soffice')
|
|
|
|
else:
|
|
|
|
self._server.terminate()
|
|
|
|
debug('LibreOffice is stop...')
|
|
|
|
return
|
|
|
|
|
|
|
|
def create_instance(self, name, with_context=True):
|
|
|
|
if with_context:
|
|
|
|
instance = self._sm.createInstanceWithContext(name, self._ctx)
|
|
|
|
else:
|
|
|
|
instance = self._sm.createInstance(name)
|
|
|
|
return instance
|