Page MenuHomec4science

style.py
No OneTemporary

File Metadata

Created
Sun, May 5, 23:05

style.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" This class can be used to represent the style of a word.
"""
# Copyright (C) University of Basel 2019 {{{1
#
# This program 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.
#
# This program 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 this program. If not, see <https://www.gnu.org/licenses/> 1}}}
__author__ = "Christian Steiner"
__maintainer__ = __author__
__copyright__ = 'University of Basel'
__email__ = "christian.steiner@unibas.ch"
__status__ = "Development"
__license__ = "GPL v3"
__version__ = "0.0.1"
import copy
from lxml import etree as ET
import re
import sys
from .color import Color
sys.path.append('py2ttl')
from class_spec import SemanticClass
class Style(SemanticClass):
"""
This class represents the style of a word.
Args:
manuscript: a ArchivalManuscriptUnity
"""
NIETSCHES_FONTS = { 'german': 'deutsche Schreibschrift', 'latin': 'lateinische Schreibschrift' }
COLOR_KEYS = [ 'black', 'red', 'blue', 'green', 'grey' ]
RELEVANT_STYLE_KEYS = [ 'font-family', 'fill', 'stroke' ]
ADDITIONAL_STYLE_KEYS = [ 'font-size' ]
PERCENTS = [ '80%', '70%' ]
WRITING_INSTRUMENTS = { (COLOR_KEYS[0], False): 'schwarze Tinte',\
(COLOR_KEYS[0], True): 'Bleistift',\
(COLOR_KEYS[4], True): 'Bleistift',\
(COLOR_KEYS[4], False): 'Bleistift',\
(COLOR_KEYS[1], False): 'braune Tinte',\
(COLOR_KEYS[1], True): 'Rotstift',\
(COLOR_KEYS[2], False): 'violette Tinte',\
(COLOR_KEYS[2], True): 'Blaustift',\
(COLOR_KEYS[3], False): '„Tinte der letzten Korrektur“',\
(COLOR_KEYS[3], True): '„Tinte der letzten Korrektur“'}
def __init__(self, manuscript=None, writing_process_id=-1, extended_styles=False, deletion_color=None, underline=False):
self.color = Color.create_cls(manuscript=manuscript)
self.css_styles = []
self.css_string = None
self.deletion_color = deletion_color
self.is_german = True
self.font = self.NIETSCHES_FONTS['german']
self.font_family = 'Weidemann-Book'
self.font_size = ''
self.manuscript = manuscript
self.relevant_key_map = {}
relevant_style_keys = self.RELEVANT_STYLE_KEYS + self.ADDITIONAL_STYLE_KEYS\
if extended_styles else self.RELEVANT_STYLE_KEYS
for key in relevant_style_keys:
if not key.startswith('font'):
self.relevant_key_map.update({key: self.set_color})
elif key == 'font-family':
self.relevant_key_map.update({key: self.set_font})
elif key == 'font-size':
self.relevant_key_map.update({key: self.set_size})
self.underline = underline
self.writing_instrument = self.WRITING_INSTRUMENTS[(self.color.name, False)]
self.writing_process_id = writing_process_id
def create_a_copy_wo_writing_process_id(self):
new_self = copy.deepcopy(self)
new_self.writing_process_id = -1
return new_self
def create_a_copy(self, reduce_writing_process_id=False):
writing_process_id = self.writing_process_id\
if not reduce_writing_process_id\
else self.writing_process_id-1
copy = Style(manuscript=self.manuscript, writing_process_id=writing_process_id)
copy.color = self.color
copy.font_family = self.font_family
copy.process_style_classes()
if copy.manuscript is not None:
copy.manuscript.update_styles(copy)
return copy
def create_css_styles(self):
"""Create css styles.
"""
if self.deletion_color is not None:
self.css_styles.append('text-decoration:line-through;')
self.css_styles.append(f'text-decoration-color:{self.deletion_color.hex_color};')
self.css_styles.append(f'-webkit-text-decoration-color:{self.deletion_color.hex_color};')
if self.underline:
self.css_styles.append('text-decoration:underline;')
if self.font_family.endswith('Bold'):
self.css_styles.append(f'font-weight:bold;')
#if self.font_size != '':
# self.css_styles.append(f'font-size:{self.font_size};')
if self.writing_process_id > 0:
self.css_styles.append(f'font-size:{self.PERCENTS[self.writing_process_id-1]};')
self.css_styles.append(f'color:{self.color.hex_color};')
self.css_string = ''.join(self.css_styles)
@classmethod
def create_cls(cls, page, style_string, manuscript=None, create_css=False, deletion_color=None, writing_process_id=-1):
"""Creates a Style from a style_string.
:return: (datatypes.style) Style
"""
style = cls(manuscript=manuscript, extended_styles=create_css, deletion_color=deletion_color, writing_process_id=writing_process_id)
style_dict = { key: key_dict for key, key_dict in page.style_dict.items()\
if any(relevant_key in key_dict.keys() for relevant_key in style.relevant_key_map.keys()) }
if style_string is not None:
for style_key in style_string.split(' '):
if style_key in style_dict.keys():
dictionary = style_dict[style_key]
for key, set_function in [ (key, func) for key, func in style.relevant_key_map.items() if key in dictionary.keys() ]:
if callable(set_function):
set_function(dictionary[key])
style.process_style_classes()
if create_css:
style.create_css_styles()
return style
@classmethod
def get_semantic_dictionary(cls):
""" Creates a semantic dictionary as specified by SemanticClass.
"""
properties = {}
properties.update(cls.create_semantic_property_dictionary('font', str, cardinality=1,\
name='styleHasFont', label='style has font', comment='Connects a style with the kind of font Nietzsche used in writing.'))
properties.update(cls.create_semantic_property_dictionary('writing_instrument', str, cardinality=1,\
name='styleHasWritingInstrument', label='style has writing instrument', comment='Connects a style with the description of a writing instrument.'))
properties.update(cls.create_semantic_property_dictionary('color', Color, cardinality=1,\
name='styleHasColor', label='style has color', comment='Connects a style with a color.'))
#properties.update(cls.create_semantic_property_dictionary('css_styles', str,\
properties.update(cls.create_semantic_property_dictionary('css_string', str,\
subPropertyOf=cls.STOFF_STYLE_HAS_CSS_URL_STRING,\
name='styleHasCSS', label='style has css', comment='Connects a style with CSS style.'))
dictionary = { cls.CLASS_KEY: cls.get_class_dictionary(), cls.PROPERTIES_KEY: properties }
return cls.return_dictionary_after_updating_super_classes(dictionary)
def process_style_classes(self):
"""Infere writing instrument from font-family and color.
"""
if self.font_family.startswith('NewsGothic'):
self.is_german = False
self.font = self.NIETSCHES_FONTS['latin']
if self.color.name in self.COLOR_KEYS:
self.writing_instrument = self.WRITING_INSTRUMENTS[(self.color.name, self.font_family.endswith('Bold'))]
def set_color(self, hex_color: str):
if hex_color != 'none':
self.color = Color.create_cls(hex_color=hex_color, manuscript=self.manuscript)
def set_font(self, font_family: str):
self.font_family = font_family
def set_size(self, font_size: str):
self.font_size = font_size
@classmethod
def remove_irrelevant_style_keys(cls, style_string, page, extended_styles=False) -> str:
"""Return a style_string without irrelevant style keys.
"""
relevant_style_keys = cls.RELEVANT_STYLE_KEYS + cls.ADDITIONAL_STYLE_KEYS\
if extended_styles else cls.RELEVANT_STYLE_KEYS
return ' '.join(sorted( style_key for style_key in style_string.split(' ')\
if len(\
[ key for key in page.style_dict[style_key].keys()\
if key in relevant_style_keys ]\
) > 0 ))
def __eq__(self, other):
"""Returns true if self is qualitatively identical to other.
Reason: For qualities, the idea of numerical identity is silly.
"""
if other is None:
return False
return self.color == other.color\
and self.font_family == other.font_family\
and self.writing_process_id == other.writing_process_id\
and self.css_styles == other.css_styles\
and self.font_size == other.font_size
def __hash__(self):
"""Return a hash value for self.
"""
return hash((self.color.__hash__, self.font_family, self.writing_process_id))

Event Timeline