ScoDoc-Lille/app/but/prepajury_xl_format.py

477 lines
13 KiB
Python
Raw Normal View History

2023-05-15 06:32:54 +02:00
import abc
from enum import Enum
import openpyxl.styles
from openpyxl.styles import Side, Border, Font, PatternFill
from openpyxl.styles.numbers import FORMAT_GENERAL, FORMAT_NUMBER_00
class SCO_COLORS(Enum):
def __new__(cls, value, argb):
obj = object.__new__(cls)
obj._value_ = value
obj.argb = argb
return obj
BLACK = (1, "FF000000")
WHITE = (2, "FFFFFFFF")
RED = (3, "FFFF0000")
BROWN = (4, "FF993300")
PURPLE = (5, "FF993366")
BLUE = (6, "FF0000FF")
ORANGE = (7, "FFFF3300")
LIGHT_YELLOW = (8, "FFFFFF99")
BUT1 = (9, "FF95B3D7")
RCUE1 = (10, "FFB8CCE4")
UE1 = (11, "FFDCE6F1")
BUT2 = (12, "FFC4D79B")
RCUE2 = (13, "FFD8E4BC")
UE2 = (14, "FFEBF1DE")
BUT3 = (15, "FFFABF8F")
RCUE3 = (16, "FFFCD5B4")
UE3 = (17, "FFFDE9D9")
class SCO_BORDERTHICKNESS(Enum):
def __new__(cls, value, width):
obj = object.__new__(cls)
obj._value_ = value
obj.width = width
return obj
BORDER_NONE = (1, None)
BORDER_HAIR = (2, "hair")
BORDER_THIN = (3, "thin")
BORDER_MEDIUM = (4, "medium")
BORDER_THICK = (5, "thick")
class SCO_FONTNAME(Enum):
def __new__(cls, value, fontname):
obj = object.__new__(cls)
obj._value_ = value
obj.fontname = fontname
return obj
FONTNAME_ARIAL = (1, "Arial")
FONTNAME_COURIER = (2, "Courier New")
FONTNAME_CALIBRI = (3, "Calibri")
FONTNAME_TIMES = (4, "Times New Roman")
class SCO_FONTSIZE(Enum):
def __new__(cls, value, fontsize):
obj = object.__new__(cls)
obj._value_ = value
obj.fontsize = fontsize
return obj
FONTSIZE_9 = (1, 9)
FONTSIZE_10 = (1, 10)
FONTSIZE_11 = (1, 11)
FONTSIZE_13 = (1, 13)
FONTSIZE_16 = (1, 16)
class SCO_NUMBER_FORMAT(Enum):
def __new__(cls, value, format):
obj = object.__new__(cls)
obj._value_ = value
obj.format = format
return obj
NUMBER_GENERAL = (0, FORMAT_GENERAL)
NUMBER_00 = (1, FORMAT_NUMBER_00)
class SCO_HALIGN(Enum):
def __new__(cls, value, position):
obj = object.__new__(cls)
obj._value_ = value
obj.position = position
return obj
HALIGN_CENTER = (1, "center")
HALIGN_RIGHT = (2, "right")
HALIGN_LEFT = (3, "left")
class SCO_VALIGN(Enum):
def __new__(cls, value, position):
obj = object.__new__(cls)
obj._value_ = value
obj.position = position
return obj
VALIGN_TOP = (1, "top")
VALIGN_BOTTOM = (2, "bottom")
VALIGN_CENTER = (3, "center")
free = 0
class Composante:
def __init__(self, base=None, width: int = 1):
global free
self.cache = {}
if base is None:
self.base = free
free += width
else:
self.base = base
self.width = width
self.end = self.base + self.width
self.mask = ((1 << width) - 1) << self.base
def read(self, signature: int) -> int:
return (signature & self.mask) >> self.base
def clear(self, signature: int) -> int:
return signature & ~self.mask
def write(self, index, signature=0) -> int:
return self.clear(signature) + index << self.base
def lookup_or_cache(self, signature: int):
value = self.read(signature)
if not value in self.cache:
self.cache[signature] = self.build(value)
return self.cache[value]
@abc.abstractmethod
def build(self, value: int):
pass
class Composante_boolean(Composante):
def __init__(self):
super().__init__(width=1)
def build(self, signature):
value = self.read(signature)
return value == 1
class Composante_number_format(Composante):
def __init__(self):
super().__init__(width=2)
def build(self, signature: int):
value = self.read(signature)
return SCO_NUMBER_FORMAT(value) or None
class Composante_Colors(Composante):
def __init__(self):
super().__init__(width=5)
def build(self, signature: int):
value = self.read(signature)
return SCO_COLORS(value) or SCO_COLORS.BLACK
class Composante_borderThickness(Composante):
def __init__(self):
super().__init__(width=2)
def build(self, signature: int):
value = self.read(signature)
return SCO_BORDERTHICKNESS(value) or None
class Composante_fontname(Composante):
def __init__(self):
super().__init__(width=3)
def build(self, signature: int):
value = self.read(signature)
return SCO_FONTNAME(value) or None
class Composante_fontsize(Composante):
def __init__(self):
super().__init__(width=3)
def build(self, signature: int):
value = self.read(signature)
return SCO_FONTSIZE(value) or None
class Composante_halign(Composante):
def __init__(self):
super().__init__(width=2)
def build(self, signature: int):
value = self.read(signature)
return SCO_HALIGN(value) or None
class Composante_valign(Composante):
def __init__(self):
super().__init__(width=2)
def build(self, signature: int):
value = self.read(signature)
return SCO_VALIGN(signature) or None
class Sco_BorderSide:
def __init__(
self,
thickness: SCO_BORDERTHICKNESS = None,
color: SCO_COLORS = SCO_COLORS.WHITE,
):
self.thickness = thickness
self.color: SCO_COLORS = color
def get_openxl(self):
side: Side = Side(border_style=self.thickness.width, color=self.color.argb)
return side
class Sco_Borders:
def __init__(
self,
left: Sco_BorderSide = None,
right: Sco_BorderSide = None,
top: Sco_BorderSide = None,
bottom: Sco_BorderSide = None,
):
self.left = left
self.right = right
self.top = top
self.bottom = bottom
def get_openxl(self):
border: Border = Border(
left=self.left.get_openxl(),
right=self.right.get_openxl(),
top=self.top.get_openxl(),
bottom=self.bottom.get_openxl(),
)
class Sco_Alignment:
def __init__(
self,
halign: SCO_HALIGN = None,
valign: SCO_VALIGN = None,
):
self.halign = halign
self.valign = valign
def get_openxl(self):
al = openpyxl.styles.Alignment()
al.horizontal = self.halign.position
al.vertical = self.valign.position
return al
class Sco_Font:
def __init__(
self,
name: str = None,
fontsize: int = None,
bold: bool = None,
italic: bool = None,
outline: bool = None,
color: "SCO_COLORS" = None,
):
self.name = name
self.bold = bold
self.italic = italic
self.outline = outline
self.color = color
self.fontsize = fontsize
class Sco_Style:
from openpyxl.cell import WriteOnlyCell, Cell
def __init__(
self,
font: Sco_Font = None,
bgcolor: SCO_COLORS = None,
alignment: Sco_Alignment = None,
borders: Sco_Borders = None,
number_format: SCO_NUMBER_FORMAT = None,
):
self.font = font
self.bgcolor = bgcolor
self.alignment = alignment
self.borders = borders
self.number_format = number_format
def apply(self, cell: Cell):
if self.font:
cell.font = self.font.get_openxl()
if self.bgcolor:
cell.fill = PatternFill(fill_type="solid", fgColor=self.bgcolor.argb)
if self.alignment:
cell.alignment = self.alignment.get_openxl()
if self.borders:
cell.border = self.borders.get_openxl()
if self.number_format:
cell.number_format = self.number_format.get_openxl()
class Composante_group(Composante):
def __init__(self, composantes: list[Composante]):
self.composantes = composantes
mini = min([comp.base for comp in composantes])
maxi = max([comp.end for comp in composantes])
width = sum([comp.width for comp in composantes])
if not width == (maxi - mini):
raise Exception("Composante group non complete ou non connexe")
super().__init__(base=mini, width=width)
class Composante_font(Composante_group):
def __init__(
self,
name: Composante_fontname,
fontsize: Composante_fontsize,
color: Composante_Colors,
bold: Composante_boolean,
italic: Composante_boolean,
outline: Composante_boolean,
):
super().__init__([name, fontsize, color, bold, italic, outline])
self.name = name
self.fontsize = fontsize
self.color = color
self.bold = bold
self.italic = italic
self.outline = outline
def build(self, signature):
return Sco_Font(
name=self.name.lookup_or_cache(signature),
fontsize=self.fontsize.lookup_or_cache(signature),
color=self.color.lookup_or_cache(signature),
bold=self.bold.lookup_or_cache(signature),
italic=self.italic.lookup_or_cache(signature),
outline=self.outline.lookup_or_cache(signature),
)
class Composante_border(Composante_group):
def __init__(self, thick: Composante_borderThickness, color: Composante_Colors):
super().__init__([thick, color])
self.thick = thick
self.color = color
def build(self, signature: int):
return Sco_BorderSide(
thickness=self.thick.lookup_or_cache(signature),
color=self.color.lookup_or_cache(signature),
)
class Composante_borders(Composante_group):
def __init__(
self,
left: Composante_border,
right: Composante_border,
top: Composante_border,
bottom: Composante_border,
):
super().__init__([left, right, top, bottom])
self.left = left
self.right = right
self.top = top
self.bottom = bottom
def build(self, signature: int):
return Sco_Borders(
left=self.left.lookup_or_cache(signature),
right=self.right.lookup_or_cache(signature),
top=self.top.lookup_or_cache(signature),
bottom=self.bottom.lookup_or_cache(signature),
)
class Composante_alignment(Composante_group):
def __init__(self, halign: Composante_halign, valign: Composante_valign):
super().__init__([halign, valign])
self.halign = halign
self.valign = valign
def build(self, signature: int):
return Sco_Alignment(
halign=self.halign.lookup_or_cache(signature),
valign=self.valign.lookup_or_cache(signature),
)
# ALL = Composante_all(FONT, BGCOLOR, BORDERS, ALIGNMENT, NUMBER_FORMAT)
class Composante_all(Composante_group):
def __init__(
self,
font: Composante_font,
bgcolor: Composante_Colors,
borders: Composante_borders,
alignment: Composante_alignment,
number_format: Composante_number_format,
):
super().__init__([font, bgcolor, borders, alignment, number_format])
self.font = font
self.bgcolor = bgcolor
self.borders = borders
self.alignment = alignment
self.number_format = number_format
def build(self, signature: int):
return Sco_Style(
bgcolor=self.bgcolor.lookup_or_cache(signature),
font=self.font.lookup_or_cache(signature),
borders=self.borders.lookup_or_cache(signature),
alignment=self.alignment.lookup_or_cache(signature),
number_format=self.number_format.lookup_or_cache(signature),
)
def get_style(self, signature: int):
return self.lookup_or_cache(signature)
class FMT(Enum):
def __init__(self, composante: Composante):
self.composante = composante
def write(self, value, signature=0) -> int:
return self.composante.write(value, signature)
def get_style(self, signature: int):
return self.composante.lookup_or_cache(signature)
FONT_NAME = Composante_fontname()
FONT_SIZE = Composante_fontsize()
FONT_COLOR = Composante_Colors()
FONT_BOLD = Composante_boolean()
FONT_ITALIC = Composante_boolean()
FONT_OUTLINE = Composante_boolean()
BORDER_LEFT_STYLE = Composante_borderThickness()
BORDER_LEFT_COLOR = Composante_Colors()
BORDER_RIGHT_STYLE = Composante_borderThickness()
BORDER_RIGHT_COLOR = Composante_Colors()
BORDER_TOP_STYLE = Composante_borderThickness()
BORDER_TOP_COLOR = Composante_Colors()
BORDER_BOTTOM_STYLE = Composante_borderThickness()
BORDER_BOTTOM_COLOR = Composante_Colors()
BGCOLOR = Composante_Colors()
ALIGNMENT_HALIGN = Composante_halign()
ALIGNEMENT_VALIGN = Composante_valign()
NUMBER_FORMAT = Composante_number_format()
FONT = Composante_font(
FONT_NAME, FONT_SIZE, FONT_COLOR, FONT_BOLD, FONT_ITALIC, FONT_OUTLINE
)
BORDER_LEFT = Composante_border(BORDER_LEFT_STYLE, BORDER_LEFT_COLOR)
BORDER_RIGHT = Composante_border(BORDER_RIGHT_STYLE, BORDER_RIGHT_COLOR)
BORDER_TOP = Composante_border(BORDER_TOP_STYLE, BORDER_TOP_COLOR)
BORDER_BOTTOM = Composante_border(BORDER_BOTTOM_STYLE, BORDER_BOTTOM_COLOR)
BORDERS = Composante_borders(BORDER_LEFT, BORDER_RIGHT, BORDER_TOP, BORDER_BOTTOM)
ALIGNMENT = Composante_alignment(ALIGNMENT_HALIGN, ALIGNMENT_HALIGN)
ALL = Composante_all(FONT, BGCOLOR, BORDERS, ALIGNMENT, NUMBER_FORMAT)