from src.model.paragraph import Paragraph from src.model.block import Block INFINITE = 99999 class Container: def __init__(self, paragraphs: [Paragraph], title: Paragraph = None, level: int = 0, index: [int] = None, father=None, id_=0): if index is None: index = [] self.level = level self.title = title self.paragraphs = [] self.children = [] self.index = index self.father = father # if not father, then the container is at the top of the hierarchy self.id_ = int(str(1) + str(father.id_) + str(id_)) if paragraphs: self.paragraphs, self.children = self.create_children(paragraphs, level, index) self.blocks = self.get_blocks() self.normals, self.comments, self.tasks = self.sort_paragraphs() @property def text(self): text = "" if self.title: text = "Titre " + str(self.level) + " : " + self.title.text + '\n' for p in self.paragraphs: text += p.text + '\n' for child in self.children: text += child.text return text @property def text_chunks(self, chunk=500): text_chunks = [] text_chunk = "" for p in self.paragraphs: if chunk < len(text_chunk) + len(p.text): text_chunks.append(text_chunk) text_chunk = "" else: text_chunk += " " + p.text if text_chunk and not text_chunk.isspace(): text_chunks.append(text_chunk) for child in self.children: text_chunks += child.text_chunks return text_chunks def get_blocks(self): block = Block(level=self.level, index=self.index) if self.title: block.title = self.title.text for p in self.paragraphs: if not p.blank: if p.text.startswith('##### '): special_action = p.text.lstrip('##### ') block.specials.append(special_action) else: block.content += p.text blocks = [block] if block.content or block.specials else [] for child in self.children: blocks += child.blocks return blocks def create_children(self, paragraphs: Paragraph, level: int, index: [int]) -> ([Paragraph], []): """ creates children containers or directly attached content and returns the list of containers and contents of level+1 :return: [Content or Container] """ attached_paragraphs = [] container_paragraphs = [] container_title = None children = [] in_children = False child_id = 0 level = INFINITE while paragraphs: p = paragraphs.pop(0) if not in_children and not p.is_structure: attached_paragraphs.append(p) else: in_children = True if p.is_structure and p.level <= level: # if p is higher in hierarchy, then the child is completed if container_paragraphs or container_title: if level <= len(index): index = index[:level] index[-1] += 1 else: for i in range(level-len(index)): index.append(1) children.append(Container(container_paragraphs, container_title, level, index, self, child_id)) child_id += 1 container_paragraphs = [] container_title = p level = p.level else: # p is normal text or strictly lower in hierarchy, then the child continues to grow container_paragraphs.append(p) if container_paragraphs or container_title: if level <= len(index): index = index[:level] index[-1] += 1 else: for i in range(level - len(index)): index.append(1) children.append(Container(container_paragraphs, container_title, level, index, self, child_id)) child_id += 1 return attached_paragraphs, children @property def structure(self): self_structure = {str(self.id_): { 'index': str(self.id_), 'canMove': True, 'isFolder': True, 'children': [p.id_ for p in self.paragraphs] + [child.id_ for child in self.children], 'canRename': True, 'data': {}, 'level': self.level, 'rank': self.rank, 'title': self.title.text if self.title else 'root' }} paragraphs_structure = [p.structure for p in self.paragraphs] structure = [self_structure] + paragraphs_structure for child in self.children: structure += child.structure return structure def sort_paragraphs(self) -> ([Paragraph], [Paragraph], [Paragraph]): mapping = {'normal': [], 'comment': [], 'task': []} for p in self.paragraphs: mapping(p.type).append(p) return mapping['normal'], mapping['comment'], mapping['task']