1from __future__ import absolute_import
2# Copyright (c) 2010-2019 openpyxl
3
4"""
5Excel specific descriptors
6"""
7
8from openpyxl.xml.constants import REL_NS
9from openpyxl.compat import safe_string, unicode
10from openpyxl.xml.functions import Element
11
12from . import (
13    MatchPattern,
14    MinMax,
15    Integer,
16    String,
17    Typed,
18    Sequence,
19)
20from .serialisable import Serialisable
21from openpyxl.utils.cell import RANGE_EXPR
22
23class HexBinary(MatchPattern):
24
25    pattern = "[0-9a-fA-F]+$"
26
27
28class UniversalMeasure(MatchPattern):
29
30    pattern = r"[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)"
31
32
33class TextPoint(MinMax):
34    """
35    Size in hundredths of points.
36    In theory other units of measurement can be used but these are unbounded
37    """
38    expected_type = int
39
40    min = -400000
41    max = 400000
42
43
44Coordinate = Integer
45
46
47class Percentage(MinMax):
48
49    pattern = r"((100)|([0-9][0-9]?))(\.[0-9][0-9]?)?%" # strict
50    min = -1000000
51    max = 1000000
52
53    def __set__(self, instance, value):
54        if isinstance(value, unicode) and "%" in value:
55            value = value.replace("%", "")
56            value = int(float(value) * 1000)
57        super(Percentage, self).__set__(instance, value)
58
59
60class Extension(Serialisable):
61
62    uri = String()
63
64    def __init__(self,
65                 uri=None,
66                ):
67        self.uri = uri
68
69
70class ExtensionList(Serialisable):
71
72    ext = Sequence(expected_type=Extension)
73
74    def __init__(self,
75                 ext=(),
76                ):
77        self.ext = ext
78
79
80class Relation(String):
81
82    namespace = REL_NS
83    allow_none = True
84
85
86class Base64Binary(MatchPattern):
87    # http://www.w3.org/TR/xmlschema11-2/#nt-Base64Binary
88    pattern = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{4})$"
89
90
91class Guid(MatchPattern):
92    # https://msdn.microsoft.com/en-us/library/dd946381(v=office.12).aspx
93    pattern = r"{[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}\}"
94
95
96class CellRange(MatchPattern):
97
98    pattern = r"^[$]?([A-Za-z]{1,3})[$]?(\d+)(:[$]?([A-Za-z]{1,3})[$]?(\d+)?)?$|^[A-Za-z]{1,3}:[A-Za-z]{1,3}$"
99    allow_none = True
100
101    def __set__(self, instance, value):
102
103        if value is not None:
104            value = value.upper()
105        super(CellRange, self).__set__(instance, value)
106
107
108def _explicit_none(tagname, value, namespace=None):
109    """
110    Override serialisation because explicit none required
111    """
112    if namespace is not None:
113        tagname = "{%s}%s" % (namespace, tagname)
114    return Element(tagname, val=safe_string(value))
115