1# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-
2#
3# This file is part of the LibreOffice project.
4#
5# This Source Code Form is subject to the terms of the Mozilla Public
6# License, v. 2.0. If a copy of the MPL was not distributed with this
7# file, You can obtain one at http://mozilla.org/MPL/2.0/.
8#
9# This file incorporates work covered by the following license notice:
10#
11#   Licensed to the Apache Software Foundation (ASF) under one or more
12#   contributor license agreements. See the NOTICE file distributed
13#   with this work for additional information regarding copyright
14#   ownership. The ASF licenses this file to you under the Apache
15#   License, Version 2.0 (the "License"); you may not use this file
16#   except in compliance with the License. You may obtain a copy of
17#   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18#
19import pyuno
20import sys
21import traceback
22import warnings
23
24# since on Windows sal3.dll no longer calls WSAStartup
25import socket
26
27# All functions and variables starting with a underscore (_) must be
28# considered private and can be changed at any time. Don't use them.
29_component_context = pyuno.getComponentContext()
30
31
32def getComponentContext():
33    """Returns the UNO component context used to initialize the Python runtime."""
34
35    return _component_context
36
37
38def getCurrentContext():
39    """Returns the current context.
40
41    See http://udk.openoffice.org/common/man/concept/uno_contexts.html#current_context
42    for an explanation on the current context concept.
43    """
44
45    return pyuno.getCurrentContext()
46
47
48def setCurrentContext(newContext):
49    """Sets newContext as new UNO context.
50
51    The newContext must implement the XCurrentContext interface. The
52    implementation should handle the desired properties and delegate
53    unknown properties to the old context. Ensure that the old one
54    is reset when you leave your stack, see
55    http://udk.openoffice.org/common/man/concept/uno_contexts.html#current_context
56    """
57
58    return pyuno.setCurrentContext(newContext)
59
60
61def getConstantByName(constant):
62    """Looks up the value of an IDL constant by giving its explicit name."""
63
64    return pyuno.getConstantByName(constant)
65
66
67def getTypeByName(typeName):
68    """Returns a `uno.Type` instance of the type given by typeName.
69
70    If the type does not exist, a `com.sun.star.uno.RuntimeException` is raised.
71    """
72
73    return pyuno.getTypeByName(typeName)
74
75
76def createUnoStruct(typeName, *args, **kwargs):
77    """Creates a UNO struct or exception given by typeName.
78
79    Can be called with:
80
81    1) No additional argument.
82       In this case, you get a default constructed UNO structure.
83       (e.g. `createUnoStruct("com.sun.star.uno.Exception")`)
84    2) Exactly one additional argument that is an instance of typeName.
85       In this case, a copy constructed instance of typeName is returned
86       (e.g. `createUnoStruct("com.sun.star.uno.Exception" , e)`)
87    3) As many additional arguments as the number of elements within typeName
88       (e.g. `createUnoStruct("com.sun.star.uno.Exception", "foo error" , self)`).
89    4) Keyword arguments to give values for each element of the struct by name.
90    5) A mix of 3) and 4), such that each struct element is given a value exactly once,
91       either by a positional argument or by a keyword argument.
92
93    The additional and/or keyword arguments must match the type of each struct element,
94    otherwise an exception is thrown.
95    """
96
97    return getClass(typeName)(*args, **kwargs)
98
99
100def getClass(typeName):
101    """Returns the class of a concrete UNO exception, struct, or interface."""
102
103    return pyuno.getClass(typeName)
104
105
106def isInterface(obj):
107    """Returns True, when obj is a class of a UNO interface."""
108
109    return pyuno.isInterface(obj)
110
111
112def generateUuid():
113    """Returns a 16 byte sequence containing a newly generated uuid or guid.
114
115    For more information, see rtl/uuid.h.
116    """
117
118    return pyuno.generateUuid()
119
120
121def systemPathToFileUrl(systemPath):
122    """Returns a file URL for the given system path."""
123
124    return pyuno.systemPathToFileUrl(systemPath)
125
126
127def fileUrlToSystemPath(url):
128    """Returns a system path.
129
130    This path is determined by the system that the Python interpreter is running on.
131    """
132
133    return pyuno.fileUrlToSystemPath(url)
134
135
136def absolutize(path, relativeUrl):
137    """Returns an absolute file url from the given urls."""
138
139    return pyuno.absolutize(path, relativeUrl)
140
141
142class Enum:
143    """Represents a UNO enum.
144
145    Use an instance of this class to explicitly pass an enum to UNO.
146
147    :param typeName: The name of the enum as a string.
148    :param value: The actual value of this enum as a string.
149    """
150
151    def __init__(self, typeName, value):
152        self.typeName = typeName
153        self.value = value
154        pyuno.checkEnum(self)
155
156    def __repr__(self):
157        return "<Enum instance %s (%r)>" % (self.typeName, self.value)
158
159    def __eq__(self, that):
160        if not isinstance(that, Enum):
161            return False
162
163        return (self.typeName == that.typeName) and (self.value == that.value)
164
165    def __ne__(self,other):
166        return not self.__eq__(other)
167
168
169class Type:
170    """Represents a UNO type.
171
172    Use an instance of this class to explicitly pass a type to UNO.
173
174    :param typeName: Name of the UNO type
175    :param typeClass: Python Enum of TypeClass, see com/sun/star/uno/TypeClass.idl
176    """
177
178    def __init__(self, typeName, typeClass):
179        self.typeName = typeName
180        self.typeClass = typeClass
181        pyuno.checkType(self)
182
183    def __repr__(self):
184        return "<Type instance %s (%r)>" % (self.typeName, self.typeClass)
185
186    def __eq__(self, that):
187        if not isinstance(that, Type):
188            return False
189
190        return self.typeClass == that.typeClass and self.typeName == that.typeName
191
192    def __ne__(self,other):
193        return not self.__eq__(other)
194
195    def __hash__(self):
196        return self.typeName.__hash__()
197
198
199class Bool(object):
200    """Represents a UNO boolean.
201
202    Use an instance of this class to explicitly pass a boolean to UNO.
203
204    Note: This class is deprecated. Use Python's True and False directly instead.
205    """
206
207    def __new__(cls, value):
208        message = "The Bool class is deprecated. Use Python's True and False directly instead."
209        warnings.warn(message, DeprecationWarning)
210
211        if isinstance(value, str) and value == "true":
212            return True
213
214        if isinstance(value, str) and value == "false":
215            return False
216
217        if value:
218            return True
219
220        return False
221
222
223class Char:
224    """Represents a UNO char.
225
226    Use an instance of this class to explicitly pass a char to UNO.
227
228    For Python 3, this class only works with unicode (str) objects. Creating
229    a Char instance with a bytes object or comparing a Char instance
230    to a bytes object will raise an AssertionError.
231
232    :param value: A Unicode string with length 1
233    """
234
235    def __init__(self, value):
236        assert isinstance(value, str), "Expected str object, got %s instead." % type(value)
237
238        assert len(value) == 1, "Char value must have length of 1."
239        assert ord(value[0]) <= 0xFFFF, "Char value must be UTF-16 code unit"
240
241        self.value = value
242
243    def __repr__(self):
244        return "<Char instance %s>" % (self.value,)
245
246    def __eq__(self, that):
247        if isinstance(that, str):
248            if len(that) > 1:
249                return False
250
251            return self.value == that[0]
252
253        if isinstance(that, Char):
254            return self.value == that.value
255
256        return False
257
258    def __ne__(self,other):
259        return not self.__eq__(other)
260
261
262class ByteSequence:
263    """Represents a UNO ByteSequence value.
264
265    Use an instance of this class to explicitly pass a byte sequence to UNO.
266
267    :param value: A string or bytesequence
268    """
269
270    def __init__(self, value):
271        if isinstance(value, bytes):
272            self.value = value
273
274        elif isinstance(value, ByteSequence):
275            self.value = value.value
276
277        else:
278            raise TypeError("Expected bytes object or ByteSequence, got %s instead." % type(value))
279
280    def __repr__(self):
281        return "<ByteSequence instance '%s'>" % (self.value,)
282
283    def __eq__(self, that):
284        if isinstance(that, bytes):
285            return self.value == that
286
287        if isinstance(that, ByteSequence):
288            return self.value == that.value
289
290        return False
291
292    def __len__(self):
293        return len(self.value)
294
295    def __getitem__(self, index):
296        return self.value[index]
297
298    def __iter__(self):
299        return self.value.__iter__()
300
301    def __add__(self, b):
302        if isinstance(b, bytes):
303            return ByteSequence(self.value + b)
304
305        elif isinstance(b, ByteSequence):
306            return ByteSequence(self.value + b.value)
307
308        else:
309            raise TypeError("Can't add ByteString and %s." % type(b))
310
311    def __hash__(self):
312        return self.value.hash()
313
314
315class Any:
316    """Represents a UNO Any value.
317
318    Use only in connection with uno.invoke() to pass an explicit typed Any.
319    """
320
321    def __init__(self, type, value):
322        if isinstance(type, Type):
323            self.type = type
324        else:
325            self.type = getTypeByName(type)
326
327        self.value = value
328
329
330def invoke(object, methodname, argTuple):
331    """Use this function to pass exactly typed Anys to the callee (using uno.Any)."""
332
333    return pyuno.invoke(object, methodname, argTuple)
334
335
336# -----------------------------------------------------------------------------
337# Don't use any functions beyond this point; private section, likely to change.
338# -----------------------------------------------------------------------------
339_builtin_import = __import__
340
341
342def _uno_import(name, *optargs, **kwargs):
343    """Overrides built-in import to allow directly importing LibreOffice classes."""
344
345    try:
346        return _builtin_import(name, *optargs, **kwargs)
347    except ImportError as e:
348        # process optargs
349        globals, locals, fromlist = list(optargs)[:3] + [kwargs.get('globals', {}), kwargs.get('locals', {}),
350                                                         kwargs.get('fromlist', [])][len(optargs):]
351
352        # from import form only, but skip if a uno lookup has already failed
353        if not fromlist or hasattr(e, '_uno_import_failed'):
354            raise
355
356        # hang onto exception for possible use on subsequent uno lookup failure
357        py_import_exc = e
358
359    mod = None
360    d = sys.modules
361
362    for module in name.split("."):
363        if module in d:
364            mod = d[module]
365        else:
366            # How to create a module ??
367            mod = pyuno.__class__(module)
368
369        d = mod.__dict__
370
371    RuntimeException = pyuno.getClass("com.sun.star.uno.RuntimeException")
372
373    for class_name in fromlist:
374        if class_name not in d:
375            failed = False
376
377            try:
378                # check for structs, exceptions or interfaces
379                d[class_name] = pyuno.getClass(name + "." + class_name)
380            except RuntimeException:
381                # check for enums
382                try:
383                    d[class_name] = Enum(name, class_name)
384                except RuntimeException:
385                    # check for constants
386                    try:
387                        d[class_name] = getConstantByName(name + "." + class_name)
388                    except RuntimeException:
389                        # check for constant group
390                        try:
391                            d[class_name] = _impl_getConstantGroupByName(name, class_name)
392                        except ValueError:
393                            failed = True
394
395            if failed:
396                # We have an import failure, but cannot distinguish between
397                # uno and non-uno errors as uno lookups are attempted for all
398                # "from xxx import yyy" imports following a python failure.
399                #
400                # In Python 3, the original python exception traceback is reused
401                # to help pinpoint the actual failing location.  Its original
402                # message, unlike Python 2, is unlikely to be helpful for uno
403                # failures, as it most commonly is just a top level module like
404                # 'com'.  So our exception appends the uno lookup failure.
405                # This is more ambiguous, but it plus the traceback should be
406                # sufficient to identify a root cause for python or uno issues.
407                #
408                # Our exception is raised outside of the nested exception
409                # handlers above, to avoid Python 3 nested exception
410                # information for the RuntimeExceptions during lookups.
411                #
412                # Finally, a private attribute is used to prevent further
413                # processing if this failure was in a nested import.  That
414                # keeps the exception relevant to the primary failure point,
415                # preventing us from re-processing our own import errors.
416
417                uno_import_exc = ImportError("%s (or '%s.%s' is unknown)" %
418                                             (py_import_exc, name, class_name))
419
420                uno_import_exc = uno_import_exc.with_traceback(py_import_exc.__traceback__)
421
422                uno_import_exc._uno_import_failed = True
423                raise uno_import_exc
424
425    return mod
426
427
428try:
429    import __builtin__
430except ImportError:
431    import builtins as __builtin__
432
433# hook into the __import__ chain
434__builtin__.__dict__['__import__'] = _uno_import
435
436
437class _ConstantGroup(object):
438    """Represents a group of UNOIDL constants."""
439
440    __slots__ = ['_constants']
441
442    def __init__(self, constants):
443        self._constants = constants
444
445    def __dir__(self):
446        return self._constants.keys()
447
448    def __getattr__(self, name):
449        if name in self._constants:
450            return self._constants[name]
451
452        raise AttributeError("The constant '%s' could not be found." % name)
453
454
455def _impl_getConstantGroupByName(module, group):
456    """Gets UNOIDL constant group by name."""
457
458    constants = Enum('com.sun.star.uno.TypeClass', 'CONSTANTS')
459    one = Enum('com.sun.star.reflection.TypeDescriptionSearchDepth', 'ONE')
460    type_desc_mgr = _component_context.getValueByName('/singletons/com.sun.star.reflection.theTypeDescriptionManager')
461    type_descs = type_desc_mgr.createTypeDescriptionEnumeration(module, (constants,), one)
462    qualified_name = module + '.' + group
463
464    for type_desc in type_descs:
465        if type_desc.Name == qualified_name:
466            return _ConstantGroup(dict(
467                (c.Name.split('.')[-1], c.ConstantValue)
468                for c in type_desc.Constants))
469
470    raise ValueError("The constant group '%s' could not be found." % qualified_name)
471
472
473def _uno_struct__init__(self, *args, **kwargs):
474    """Initializes a UNO struct.
475
476    Referenced from the pyuno shared library.
477
478    This function can be called with either an already constructed UNO struct, which it
479    will then just reference without copying, or with arguments to create a new UNO struct.
480    """
481
482    # Check to see if this function was passed an existing UNO struct
483    if len(kwargs) == 0 and len(args) == 1 and getattr(args[0], "__class__", None) == self.__class__:
484        self.__dict__['value'] = args[0]
485    else:
486        struct, used = pyuno._createUnoStructHelper(self.__class__.__pyunostruct__, args, **kwargs)
487
488        for kwarg in kwargs.keys():
489            if not used.get(kwarg):
490                RuntimeException = pyuno.getClass("com.sun.star.uno.RuntimeException")
491                raise RuntimeException("_uno_struct__init__: unused keyword argument '%s'." % kwarg, None)
492
493        self.__dict__["value"] = struct
494
495
496def _uno_struct__getattr__(self, name):
497    """Gets attribute from UNO struct.
498
499    Referenced from the pyuno shared library.
500    """
501
502    return getattr(self.__dict__["value"], name)
503
504
505def _uno_struct__setattr__(self, name, value):
506    """Sets attribute on UNO struct.
507
508    Referenced from the pyuno shared library.
509    """
510
511    return setattr(self.__dict__["value"], name, value)
512
513
514def _uno_struct__repr__(self):
515    """Converts a UNO struct to a printable string.
516
517    Referenced from the pyuno shared library.
518    """
519
520    return repr(self.__dict__["value"])
521
522
523def _uno_struct__str__(self):
524    """Converts a UNO struct to a string."""
525
526    return str(self.__dict__["value"])
527
528def _uno_struct__ne__(self, other):
529    return not self.__eq__(other)
530
531def _uno_struct__eq__(self, that):
532    """Compares two UNO structs.
533
534    Referenced from the pyuno shared library.
535    """
536
537    if hasattr(that, "value"):
538        return self.__dict__["value"] == that.__dict__["value"]
539
540    return False
541
542
543def _uno_extract_printable_stacktrace(trace):
544    """Extracts a printable stacktrace.
545
546    Referenced from pyuno shared lib and pythonscript.py.
547    """
548
549    return ''.join(traceback.format_tb(trace))
550
551# vim: set shiftwidth=4 softtabstop=4 expandtab:
552