This commit is contained in:
Jean-Marie Place 2023-05-17 08:07:35 +02:00
parent 342bff3b56
commit c536336017
5 changed files with 370 additions and 162 deletions

View File

@ -33,7 +33,6 @@ import time
from flask import flash, abort
from app.but.cursus_but import EtudCursusBUT
from app.but.prepajury_cells import Cell
from app.but.prepajury_desc import ParcoursDesc
from app.comp import res_sem
from app.comp.res_but import ResultatsSemestreBUT
@ -46,7 +45,7 @@ from app.models import (
ApcCompetence,
)
import app.scodoc.sco_utils as scu
from app.scodoc.sco_excel import ScoExcelBook, ScoExcelSheet
from app.but.prepajury_xl import ScoExcelBook
class _Bilan:
@ -220,8 +219,8 @@ def feuille_preparation_jury_but(formsemestre_id):
abort(404)
formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
# res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
breakpoint()
"""Feuille excel pour préparation des jurys adaptée pour le BUT."""
breakpoint()
compilation = _Compilation(formsemestre)
compilation.computes_decision()
filename = scu.sanitize_filename(

View File

@ -1,3 +1,6 @@
import openpyxl.cell
from openpyxl.cell import Cell
from app.but.prepajury_xl import (
ScoExcelSheet,
)
@ -11,14 +14,29 @@ from app.but.prepajury_xl_format import (
)
base_signature = (
FMT.FONT_NAME.write(SCO_FONTNAME.FONTNAME_CALIBRI)
+ FMT.FONT_SIZE.write(SCO_FONTSIZE.FONTSIZE_10)
+ FMT.ALIGNMENT_HALIGN.write(SCO_HALIGN.HALIGN_CENTER)
+ FMT.ALIGNEMENT_VALIGN.write(SCO_VALIGN.VALIGN_CENTER)
FMT.FONT_NAME.set(SCO_FONTNAME.FONTNAME_CALIBRI)
+ FMT.FONT_SIZE.set(SCO_FONTSIZE.FONTSIZE_13)
+ FMT.ALIGNMENT_HALIGN.set(SCO_HALIGN.HALIGN_CENTER)
+ FMT.ALIGNMENT_VALIGN.set(SCO_VALIGN.VALIGN_CENTER)
)
class Cell:
def set_cell(
ws: Cell,
row: int,
column: int,
text: str = "",
from_signature: int = 0,
composition: list = [],
):
cell = ws.cell(row, column)
cell.value = text
sign = FMT.compose(composition, from_signature)
style: Sco_Style = FMT.style(sign)
style.apply(cell)
class Sco_Cell:
def __init__(
self, text: str = None, signature: int = base_signature, comment: str = None
):
@ -26,11 +44,16 @@ class Cell:
self.signature = signature or base_signature
self.comment = comment
def format(self, FMT: FMT, value=None):
self.signature = FMT.composante.write(self.signature, value)
def format(self, value=None):
self.signature = FMT.ALL.composante.write(self.signature, value)
def copy(self, cell: openpyxl.cell.Cell):
cell.value = self.text
style: Sco_Style = FMT.style(self.signature)
style.apply(cell)
def make_cell(self, worksheet: ScoExcelSheet):
cell = worksheet.make_cell(self.text or "")
style: Sco_Style = FMT.ALL.get_style(self.signature)
style: Sco_Style = FMT.style(self.signature)
style.apply(cell)
return cell

View File

@ -1,10 +1,18 @@
from openpyxl.styles.colors import BLACK
import openpyxl
from openpyxl.worksheet.worksheet import Worksheet
from app.but.prepajury_cells import Cell, base_style
from app.but.prepajury_xl import Sco_Style
from app.but.prepajury_xl_format import SCO_COLORS
from app.but.prepajury_cells import Sco_Cell, base_signature, set_cell
from app.but.prepajury_xl_format import (
SCO_COLORS,
FMT,
SCO_FONTSIZE,
SCO_VALIGN,
SCO_HALIGN,
SCO_BORDERTHICKNESS,
Sco_Style,
)
from app.models import ApcCompetence, ApcParcours
from app.scodoc.sco_excel import ScoExcelBook, ScoExcelSheet
from app.but.prepajury_xl import ScoExcelBook, ScoExcelSheet
def parite(semestre_idx):
@ -33,16 +41,21 @@ header_colors = {
class _Header:
def __init__(self):
self.lines: list[list[Cell]] = []
self.lines: list[list[Sco_Cell]] = []
self.presets = [None, None, None, None]
self.styles = [None, None, None, None]
self.signatures = [
base_signature,
base_signature,
base_signature,
base_signature,
]
def setLabelOnce(self, rang: int, label: str):
self.presets[rang] = label
def setStyles(self, rangs: list[int], style: Sco_Style):
def setSignatures(self, rangs: list[int], signature: int):
for rang in rangs:
self.styles[rang] = style
self.signatures[rang] = signature
def add_column(
self,
@ -54,9 +67,9 @@ class _Header:
):
if labels is None:
labels = [label0, label1, label2, label3]
cells: list(Cell) = [
Cell(preset or label, style=style)
for label, preset, style in zip(labels, self.presets, self.styles)
cells: list(Sco_Cell) = [
Sco_Cell(preset or label, signature=signature)
for label, preset, signature in zip(labels, self.presets, self.signatures)
]
self.presets = [None, None, None, None]
self.lines.append(cells)
@ -65,19 +78,13 @@ class _Header:
self.lines.extend(header.lines)
def write(self, worksheet: ScoExcelSheet):
row1 = []
row2 = []
row3 = []
row4 = []
column = 1
for items in self.lines:
row1.append(items[0].make_cell(worksheet))
row2.append(items[1].make_cell(worksheet))
row3.append(items[2].make_cell(worksheet))
row4.append(items[3].make_cell(worksheet))
worksheet.append_row(row1)
worksheet.append_row(row2)
worksheet.append_row(row3)
worksheet.append_row(row4)
items[0].copy(worksheet.ws.cell(1, column))
items[1].copy(worksheet.ws.cell(2, column))
items[2].copy(worksheet.ws.cell(3, column))
items[3].copy(worksheet.ws.cell(4, column))
column += 1
class NiveauDesc:
@ -91,17 +98,17 @@ class NiveauDesc:
self.ue[parite(scodocUe.semestre_idx)] = scodocUe
def generate_header(self, header):
rcue_style = Sco_Style(
fromStyle=base_style,
bgcolor=header_colors[self.fromScodoc.annee]["RCUE"],
rcue_signature = FMT.FILL_BGCOLOR.write(
value=header_colors[self.fromScodoc.annee]["RCUE"].value,
signature=base_signature,
)
ue_style = Sco_Style(
fromStyle=base_style,
bgcolor=header_colors[self.fromScodoc.annee]["UE"],
ue_signature = FMT.FILL_BGCOLOR.write(
value=header_colors[self.fromScodoc.annee]["UE"].value,
signature=base_signature,
)
header.setLabelOnce(1, self.fromScodoc.competence.titre)
header.setStyles([1], rcue_style)
header.setStyles([2, 3], ue_style)
header.setSignatures([1], rcue_signature)
header.setSignatures([2, 3], ue_signature)
for ue in self.ue:
if ue is None:
header.setLabelOnce(2, "XXX")
@ -111,7 +118,7 @@ class NiveauDesc:
header.setLabelOnce(2, ue.acronyme)
header.add_column(label3="Note")
header.add_column(label3="Res.")
header.setStyles([1, 2, 3], rcue_style)
header.setSignatures([1, 2, 3], rcue_signature)
header.add_column(label2="RCUE", label3="Note")
header.add_column(label3="Res.")
return header
@ -160,24 +167,67 @@ class AnneeDesc:
for _ in range(3):
header.add_column()
def generate_header(self, header):
but_style = Sco_Style(
fromStyle=base_style, bgcolor=header_colors[self.codeAnnee]["BUT"]
def generate_header(self, ws: Worksheet, column: int, codeAnnee: str):
start = column
but_signature = FMT.FILL_BGCOLOR.write(
signature=base_signature, value=header_colors[self.codeAnnee]["BUT"].value
)
header.setStyles([0], but_style)
for niveau in self.niveaux.values():
niveau.generate_header(header)
for i in range(len(self.niveaux), 6):
self.generate_blank_niveau(header)
header.add_column(label1="Année", label2="Nb", label3="RCUE")
header.add_column(label3="Rés.")
but_style = FMT.style(but_signature)
set_cell(
ws,
1,
column,
text=codeAnnee,
from_signature=but_signature,
composition=[
(FMT.BORDER_LEFT_COLOR, SCO_COLORS.BLACK.value),
(FMT.BORDER_LEFT_STYLE, SCO_BORDERTHICKNESS.BORDER_MEDIUM.value),
],
)
ws.cell(1, column).value = codeAnnee
but_style.apply(ws.cell(1, column))
# for niveau in self.niveaux.values():
# column = niveau.generate_header(ws, column)
# for i in range(len(self.niveaux), 6):
# column = self.generate_blank_niveau(ws, column)
ws.cell(2, column).value = "Année"
# cell_format(ws.cell(2, column), but_signature, [(FMT.FONT_BOLD, True)])
ws.cell(3, column).value = "Nb"
ws.cell(4, column).value = "RCUE"
column += 1
ws.cell(2, column).value = "Année"
ws.cell(4, column).value = "Moy."
column += 1
if self.codeAnnee == "BUT2":
header.add_column(label1="DUT", label3="Rés.")
ws.cell(3, column).value = "DUT"
ws.cell(3, column).value = "Rés."
if self.codeAnnee == "BUT3":
header.add_column(label1="BUT", label3="Rés.")
ws.cell(3, column).value = "BUT"
ws.cell(3, column).value = "Rés."
# ws.merge_cells(start_column=start, end_column=column, start_row=1, end_row=1)
return column
class ParcoursDesc:
signature_header = FMT.compose(
[
(FMT.FILL_BGCOLOR, SCO_COLORS.LIGHT_YELLOW.value),
(FMT.FONT_BOLD, True),
(FMT.FONT_SIZE, SCO_FONTSIZE.FONTSIZE_13.value),
(FMT.ALIGNMENT_VALIGN, SCO_VALIGN.VALIGN_CENTER.value),
(FMT.ALIGNMENT_HALIGN, SCO_HALIGN.HALIGN_CENTER.value),
(FMT.BORDER_LEFT_STYLE, SCO_BORDERTHICKNESS.BORDER_THIN.value),
(FMT.BORDER_RIGHT_STYLE, SCO_BORDERTHICKNESS.BORDER_THIN.value),
(FMT.BORDER_TOP_STYLE, SCO_BORDERTHICKNESS.BORDER_THIN.value),
(FMT.BORDER_BOTTOM_STYLE, SCO_BORDERTHICKNESS.BORDER_THIN.value),
(FMT.BORDER_LEFT_COLOR, SCO_COLORS.BLACK.value),
(FMT.BORDER_RIGHT_COLOR, SCO_COLORS.BLACK.value),
(FMT.BORDER_TOP_COLOR, SCO_COLORS.BLACK.value),
(FMT.BORDER_RIGHT_COLOR, SCO_COLORS.BLACK.value),
],
base_signature,
)
def __init__(self, formation, scodocParcour: ApcParcours = None):
self.fromScodoc: ApcParcours = scodocParcour # None pour le tronc commun 'TC'
self.etudiants = []
@ -221,16 +271,60 @@ class ParcoursDesc:
cells3.append(worksheet.make_cell(val3))
cells4.append(worksheet.make_cell(val4))
def handle_description(self, header, description, level):
def handle_description(
self, ws: Worksheet, description: tuple, row: int, column: int
) -> int:
title, content_list = description
header.setLabelOnce(level, title)
style = FMT.style(self.signature_header)
ws.cell(row, column).value = title
style.apply(ws.cell(row, column))
if content_list is None:
header.add_column()
ws.merge_cells(
start_row=row, end_row=4, start_column=column, end_column=column
)
column += 1
else:
first = column
for content in content_list:
self.handle_description(header, content, level + 1)
column = self.handle_description(ws, content, row + 1, column)
if column - first > 1:
ws.merge_cells(
start_row=row,
end_row=row,
start_column=first,
end_column=column - 1,
)
# left_medium = FMT.compose(
# self.signature_header,
# [
# (FMT.BORDER_LEFT_STYLE, SCO_BORDERTHICKNESS.BORDER_MEDIUM.value),
# (FMT.BORDER_LEFT_COLOR, SCO_COLORS.BLACK.value),
# ],
# )
# right_medium = FMT.compose(
# self.signature_header,
# [
# (FMT.BORDER_RIGHT_STYLE, SCO_BORDERTHICKNESS.BORDER_MEDIUM.value),
# (FMT.BORDER_RIGHT_COLOR, SCO_COLORS.BLACK.value),
# ],
# )
# top_medium = FMT.compose(
# self.signature_header,
# [
# (FMT.BORDER_TOP_STYLE, SCO_BORDERTHICKNESS.BORDER_MEDIUM.value),
# (FMT.BORDER_TOP_COLOR, SCO_COLORS.BLACK.value),
# ],
# )
# FMT.get_style(FMT.ALL, left_medium).apply(ws.cell(1, 1))
# FMT.get_style(FMT.ALL, top_medium).apply(ws.cell(1, 1))
# FMT.get_style(FMT.ALL, right_medium).apply(ws.cell(1, 1))
# FMT.get_style(FMT.ALL, left_medium).apply(ws.cell(2, 1))
# FMT.get_style(FMT.ALL, right_medium).apply(ws.cell(2, column - 1))
# FMT.get_style(FMT.ALL, right_medium).apply(ws.cell(3, column - 1))
# FMT.get_style(FMT.ALL, right_medium).apply(ws.cell(4, column - 1))
return column
def generate_etudiant_header(self, header):
def generate_etudiant_header(self, ws: Worksheet) -> int:
titles = (
"ETUDIANT",
[
@ -250,14 +344,13 @@ class ParcoursDesc:
),
],
)
self.handle_description(header, titles, 0)
column = self.handle_description(ws, titles, 1, 1)
return column
def generate_header(self, header) -> _Header:
self.generate_etudiant_header(header)
def generate_header(self, ws: Worksheet):
column: int = self.generate_etudiant_header(ws)
for codeAnnee in listeAnnees:
header.setLabelOnce(0, codeAnnee)
self.annees[codeAnnee].generate_header(header)
return header
column = self.annees[codeAnnee].generate_header(ws, column, codeAnnee)
def generate(self, workbook: ScoExcelBook):
header = _Header()
@ -266,4 +359,4 @@ class ParcoursDesc:
else:
sheet_name = "TC"
worksheet: ScoExcelSheet = workbook.create_sheet(sheet_name)
self.generate_header(header).write(worksheet)
self.generate_header(worksheet.ws)

View File

@ -87,7 +87,7 @@ class ScoExcelBook:
def __init__(self):
self.sheets = [] # list of sheets
self.wb = Workbook(write_only=True)
self.wb = Workbook()
def create_sheet(self, sheet_name="feuille", default_style=None):
"""Crée une nouvelle feuille dans ce classeur
@ -208,21 +208,9 @@ class ScoExcelSheet:
# création de la cellule
cell = WriteOnlyCell(self.ws, value)
# recopie des styles
if style is None:
style = self.default_style
if "font" in style:
cell.font = style["font"]
if "alignment" in style:
cell.alignment = style["alignment"].get_openxl()
if "border" in style:
cell.border = style["border"].get_openxl()
if "number_format" in style:
cell.number_format = style["number_format"]
if "fill" in style:
cell.fill = style["fill"]
if "alignment" in style:
cell.alignment = style["alignment"].get_openxl()
if style is not None:
style.apply(cell)
if not comment is None:
cell.comment = Comment(comment, "scodoc")
lines = comment.splitlines()

View File

@ -2,9 +2,11 @@ import abc
from enum import Enum
import openpyxl.styles
from openpyxl.styles import Side, Border, Font, PatternFill
from openpyxl.styles import Side, Border, Font, PatternFill, Alignment
from openpyxl.styles.numbers import FORMAT_GENERAL, FORMAT_NUMBER_00
# Formatting Enums
class SCO_COLORS(Enum):
def __new__(cls, value, argb):
@ -13,6 +15,7 @@ class SCO_COLORS(Enum):
obj.argb = argb
return obj
NONE = (0, None)
BLACK = (1, "FF000000")
WHITE = (2, "FFFFFFFF")
RED = (3, "FFFF0000")
@ -39,11 +42,11 @@ class SCO_BORDERTHICKNESS(Enum):
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")
BORDER_NONE = (0, None)
BORDER_HAIR = (1, "hair")
BORDER_THIN = (2, "thin")
BORDER_MEDIUM = (3, "medium")
BORDER_THICK = (4, "thick")
class SCO_FONTNAME(Enum):
@ -53,10 +56,10 @@ class SCO_FONTNAME(Enum):
obj.fontname = fontname
return obj
FONTNAME_CALIBRI = (0, "Calibri")
FONTNAME_ARIAL = (1, "Arial")
FONTNAME_COURIER = (2, "Courier New")
FONTNAME_CALIBRI = (3, "Calibri")
FONTNAME_TIMES = (4, "Times New Roman")
FONTNAME_TIMES = (3, "Times New Roman")
class SCO_FONTSIZE(Enum):
@ -66,11 +69,11 @@ class SCO_FONTSIZE(Enum):
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)
FONTSIZE_10 = (0, 10.0)
FONTSIZE_9 = (1, 9.0)
FONTSIZE_11 = (2, 11.0)
FONTSIZE_13 = (3, 13.0)
FONTSIZE_16 = (4, 16.0)
class SCO_NUMBER_FORMAT(Enum):
@ -91,9 +94,9 @@ class SCO_HALIGN(Enum):
obj.position = position
return obj
HALIGN_LEFT = (0, "left")
HALIGN_CENTER = (1, "center")
HALIGN_RIGHT = (2, "right")
HALIGN_LEFT = (3, "left")
class SCO_VALIGN(Enum):
@ -103,18 +106,18 @@ class SCO_VALIGN(Enum):
obj.position = position
return obj
VALIGN_BOTTOM = (0, "bottom")
VALIGN_TOP = (1, "top")
VALIGN_BOTTOM = (2, "bottom")
VALIGN_CENTER = (3, "center")
VALIGN_CENTER = (2, "center")
# Composante (bitfield) atomique. Based on Enums
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
@ -131,13 +134,7 @@ class Composante:
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]
return self.clear(signature) + (index << self.base)
@abc.abstractmethod
def build(self, value: int):
@ -148,8 +145,12 @@ class Composante_boolean(Composante):
def __init__(self):
super().__init__(width=1)
def set(self, data: bool, signature=0) -> int:
return self.write(1 if data else 0, signature)
def build(self, signature):
value = self.read(signature)
assert value < (1 << self.width)
return value == 1
@ -157,44 +158,76 @@ class Composante_number_format(Composante):
def __init__(self):
super().__init__(width=2)
def set(self, data: SCO_NUMBER_FORMAT, signature=0) -> int:
return self.write(data.value, signature)
def build(self, signature: int):
value = self.read(signature)
return SCO_NUMBER_FORMAT(value) or None
assert value < (1 << self.width)
return SCO_NUMBER_FORMAT(value)
class Composante_Colors(Composante):
def __init__(self):
def __init__(self, default: SCO_COLORS = SCO_COLORS.BLACK):
super().__init__(width=5)
self.default: SCO_COLORS = default
def set(self, data: SCO_COLORS, signature=0) -> int:
return self.write(data.value, signature)
def build(self, signature: int):
value = self.read(signature)
return SCO_COLORS(value) or SCO_COLORS.BLACK
assert value < (1 << self.width)
if value == 0:
return None
try:
return SCO_COLORS(value)
except:
return self.default
class Composante_borderThickness(Composante):
def __init__(self):
super().__init__(width=2)
def set(self, data: SCO_BORDERTHICKNESS, signature=0) -> int:
return self.write(data.value, signature)
def build(self, signature: int):
value = self.read(signature)
return SCO_BORDERTHICKNESS(value) or None
assert value < (1 << self.width)
try:
return SCO_BORDERTHICKNESS(value)
except:
return None
class Composante_fontname(Composante):
def __init__(self):
super().__init__(width=3)
def set(self, data: SCO_FONTNAME, signature=0) -> int:
return self.write(data.value, signature)
def build(self, signature: int):
value = self.read(signature)
return SCO_FONTNAME(value) or None
assert value < (1 << self.width)
try:
return SCO_FONTNAME(value)
except:
return SCO_FONTNAME.FONTNAME_CALIBRI
class Composante_fontsize(Composante):
def __init__(self):
super().__init__(width=3)
def set(self, data: SCO_FONTSIZE, signature=0) -> int:
return self.write(data.value, signature)
def build(self, signature: int):
value = self.read(signature)
assert value < (1 << self.width)
return SCO_FONTSIZE(value) or None
@ -202,18 +235,46 @@ class Composante_halign(Composante):
def __init__(self):
super().__init__(width=2)
def set(self, data: SCO_HALIGN, signature=0) -> int:
return self.write(data.value, signature)
def build(self, signature: int):
value = self.read(signature)
return SCO_HALIGN(value) or None
assert value < (1 << self.width)
try:
return SCO_HALIGN(value)
except:
return SCO_HALIGN.HALIGN_LEFT
class Composante_valign(Composante):
def __init__(self):
super().__init__(width=2)
def set(self, data: SCO_VALIGN, signature=0) -> int:
return self.write(data.value, signature)
def build(self, signature: int):
value = self.read(signature)
return SCO_VALIGN(signature) or None
assert value < (1 << self.width)
try:
return SCO_VALIGN(value)
except:
return SCO_VALIGN.VALIGN_CENTER
# Formatting objects
class Sco_Fill:
def __init__(self, color: SCO_COLORS):
self.color = color
def to_openpyxl(self):
return PatternFill(
fill_type="solid",
fgColor=None if self.color is None else self.color.argb,
)
class Sco_BorderSide:
@ -225,9 +286,11 @@ class Sco_BorderSide:
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
def to_openpyxl(self):
return Side(
border_style=self.thickness.width,
color=None if self.color is None else self.color.argb,
)
class Sco_Borders:
@ -243,12 +306,12 @@ class Sco_Borders:
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(),
def to_openpyxl(self):
return Border(
left=self.left.to_openpyxl(),
right=self.right.to_openpyxl(),
top=self.top.to_openpyxl(),
bottom=self.bottom.to_openpyxl(),
)
@ -261,18 +324,18 @@ class Sco_Alignment:
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
def to_openpyxl(self):
return Alignment(
horizontal=self.halign.position,
vertical=self.valign.position,
)
class Sco_Font:
def __init__(
self,
name: str = None,
fontsize: int = None,
name: SCO_FONTNAME = SCO_FONTNAME(0),
fontsize: SCO_FONTSIZE = SCO_FONTSIZE(0),
bold: bool = None,
italic: bool = None,
outline: bool = None,
@ -285,40 +348,54 @@ class Sco_Font:
self.color = color
self.fontsize = fontsize
def to_openpyxl(self):
return Font(
name=self.name.fontname,
size=self.fontsize.fontsize,
bold=self.bold,
italic=self.italic,
outline=self.outline,
color=None if self.color is None else self.color.argb,
)
class Sco_Style:
from openpyxl.cell import WriteOnlyCell, Cell
from openpyxl.cell import Cell
def __init__(
self,
font: Sco_Font = None,
bgcolor: SCO_COLORS = None,
fill: Sco_Fill = None,
alignment: Sco_Alignment = None,
borders: Sco_Borders = None,
number_format: SCO_NUMBER_FORMAT = None,
):
self.font = font
self.bgcolor = bgcolor
self.fill = fill
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)
cell.font = self.font.to_openpyxl()
if self.fill and self.fill.color:
cell.fill = self.fill.to_openpyxl()
if self.alignment:
cell.alignment = self.alignment.get_openxl()
cell.alignment = self.alignment.to_openpyxl()
if self.borders:
cell.border = self.borders.get_openxl()
cell.border = self.borders.to_openpyxl()
if self.number_format:
cell.number_format = self.number_format.get_openxl()
cell.number_format = self.number_format.format
# Composantes groupant d'autres composantes et dotées d'un mécanisme de cache
class Composante_group(Composante):
def __init__(self, composantes: list[Composante]):
self.composantes = composantes
self.cache = {}
mini = min([comp.base for comp in composantes])
maxi = max([comp.end for comp in composantes])
width = sum([comp.width for comp in composantes])
@ -326,6 +403,22 @@ class Composante_group(Composante):
raise Exception("Composante group non complete ou non connexe")
super().__init__(base=mini, width=width)
def lookup_or_cache(self, signature: int):
value = self.read(signature)
assert value < (1 << self.width)
if not value in self.cache:
self.cache[value] = self.build(signature)
return self.cache[value]
class Composante_fill(Composante_group):
def __init__(self, color: Composante_Colors):
super().__init__([color])
self.color = color
def build(self, signature: int):
return Sco_Fill(color=self.color.build(signature))
class Composante_font(Composante_group):
def __init__(
@ -345,14 +438,14 @@ class Composante_font(Composante_group):
self.italic = italic
self.outline = outline
def build(self, signature):
def build(self, signature: int):
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),
name=self.name.build(signature),
fontsize=self.fontsize.build(signature),
color=self.color.build(signature),
bold=self.bold.build(signature),
italic=self.italic.build(signature),
outline=self.outline.build(signature),
)
@ -364,8 +457,8 @@ class Composante_border(Composante_group):
def build(self, signature: int):
return Sco_BorderSide(
thickness=self.thick.lookup_or_cache(signature),
color=self.color.lookup_or_cache(signature),
thickness=self.thick.build(signature),
color=self.color.build(signature),
)
@ -400,36 +493,34 @@ class Composante_alignment(Composante_group):
def build(self, signature: int):
return Sco_Alignment(
halign=self.halign.lookup_or_cache(signature),
valign=self.valign.lookup_or_cache(signature),
halign=self.halign.build(signature),
valign=self.valign.build(signature),
)
# ALL = Composante_all(FONT, BGCOLOR, BORDERS, ALIGNMENT, NUMBER_FORMAT)
class Composante_all(Composante_group):
def __init__(
self,
font: Composante_font,
bgcolor: Composante_Colors,
fill: Composante_fill,
borders: Composante_borders,
alignment: Composante_alignment,
number_format: Composante_number_format,
):
super().__init__([font, bgcolor, borders, alignment, number_format])
super().__init__([font, fill, borders, alignment, number_format])
self.font = font
self.bgcolor = bgcolor
self.fill = fill
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),
fill=self.fill.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),
number_format=self.number_format.build(signature),
)
def get_style(self, signature: int):
@ -443,9 +534,22 @@ class FMT(Enum):
def write(self, value, signature=0) -> int:
return self.composante.write(value, signature)
def set(self, data, signature: int = 0) -> int:
return self.composante.set(data, signature)
def get_style(self, signature: int):
return self.composante.lookup_or_cache(signature)
@classmethod
def compose(cls, composition: list, signature: int = 0) -> int:
for field, value in composition:
signature = field.write(value, signature)
return signature
@classmethod
def style(cls, signature: int):
return FMT.ALL.get_style(signature)
FONT_NAME = Composante_fontname()
FONT_SIZE = Composante_fontsize()
FONT_COLOR = Composante_Colors()
@ -460,17 +564,18 @@ class FMT(Enum):
BORDER_TOP_COLOR = Composante_Colors()
BORDER_BOTTOM_STYLE = Composante_borderThickness()
BORDER_BOTTOM_COLOR = Composante_Colors()
BGCOLOR = Composante_Colors()
FILL_BGCOLOR = Composante_Colors(None)
ALIGNMENT_HALIGN = Composante_halign()
ALIGNEMENT_VALIGN = Composante_valign()
ALIGNMENT_VALIGN = Composante_valign()
NUMBER_FORMAT = Composante_number_format()
FONT = Composante_font(
FONT_NAME, FONT_SIZE, FONT_COLOR, FONT_BOLD, FONT_ITALIC, FONT_OUTLINE
)
FILL = Composante_fill(FILL_BGCOLOR)
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)
ALIGNMENT = Composante_alignment(ALIGNMENT_HALIGN, ALIGNMENT_VALIGN)
ALL = Composante_all(FONT, FILL, BORDERS, ALIGNMENT, NUMBER_FORMAT)