tables.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. # Purpose: tables section
  2. # Created: 12.03.2011
  3. # Copyright (c) 2011-2018, Manfred Moitzi
  4. # License: MIT License
  5. from typing import TYPE_CHECKING, Iterable, Sequence, Iterator
  6. from ezdxf.lldxf.tags import DXFTag
  7. from ezdxf.lldxf.extendedtags import ExtendedTags
  8. from ezdxf.lldxf.const import DXFAttributeError, DXFStructureError
  9. from .table import Table, ViewportTable, StyleTable
  10. if TYPE_CHECKING:
  11. from ezdxf.eztypes import Drawing, TagWriter, Tags
  12. class TablesSection:
  13. name = 'TABLES'
  14. def __init__(self, entities: Iterable[Sequence[DXFTag]], drawing: 'Drawing'):
  15. self._drawing = drawing
  16. self._tables = {}
  17. if entities is None:
  18. section_head = [DXFTag(0, 'SECTION'), DXFTag(2, 'TABLES')]
  19. entities = [section_head]
  20. self._setup_tables(iter(entities))
  21. def __iter__(self) -> Iterable[Table]:
  22. return iter(self._tables.values())
  23. @staticmethod
  24. def key(name: str) -> str:
  25. return name.upper()
  26. def _setup_tables(self, entities: Iterator[Sequence[DXFTag]]) -> None:
  27. section_head = next(entities)
  28. if section_head[0] != (0, 'SECTION') or section_head[1] != (2, 'TABLES'):
  29. raise DXFStructureError("Critical structure error in TABLES section.")
  30. table_entities = []
  31. table_name = None
  32. for entity in entities:
  33. if isinstance(entity, ExtendedTags):
  34. entity = entity.noclass
  35. if entity[0] == (0, 'TABLE'):
  36. table_entities = [entity] # collect table head!
  37. if len(entity) < 2 or entity[1].code != 2:
  38. raise DXFStructureError(
  39. 'DXFStructureError: missing required table name tag (2, name) at start of table.')
  40. table_name = entity[1].value
  41. elif entity[0] == (0, 'ENDTAB'): # do not collect (0, 'ENDTAB')
  42. self._new_table(table_name, table_entities)
  43. table_entities = [] # collect entities outside of tables, but ignore it
  44. table_name = None
  45. else: # collect table entries
  46. table_entities.append(entity)
  47. self._create_missing_tables()
  48. def _new_table(self, name: str, table_entities: Iterable['Tags']) -> None:
  49. table_class = TABLESMAP[name]
  50. new_table = table_class(table_entities, self._drawing)
  51. self._tables[self.key(new_table.name)] = new_table
  52. def _setup_table(self, name):
  53. """
  54. Setup new empty table.
  55. Args:
  56. name: real table name like 'VPORT' for viewports
  57. """
  58. name = self.key(name)
  59. if self._drawing is not None:
  60. dxfversion = self._drawing.dxfversion
  61. handle = self._drawing.entitydb.get_unique_handle()
  62. else: # test environment without Drawing() object
  63. dxfversion = 'AC1009' # DXF R12
  64. handle = '0'
  65. if dxfversion <= 'AC1009':
  66. table_entities = [[
  67. DXFTag(0, 'TABLE'),
  68. DXFTag(2, name),
  69. DXFTag(70, 0)
  70. ]]
  71. else:
  72. table_entities = [[
  73. DXFTag(0, 'TABLE'),
  74. DXFTag(2, name),
  75. DXFTag(5, handle),
  76. DXFTag(330, '0'),
  77. DXFTag(100, 'AcDbSymbolTable'),
  78. DXFTag(70, 0)
  79. ]]
  80. self._new_table(name, table_entities)
  81. def _create_missing_tables(self) -> None:
  82. if 'LAYERS' not in self:
  83. self._setup_table('LAYER')
  84. if 'LINETYPES' not in self:
  85. self._setup_table('LTYPE')
  86. if 'STYLES' not in self:
  87. self._setup_table('STYLE')
  88. if 'DIMSTYLES' not in self:
  89. self._setup_table('DIMSTYLE')
  90. if 'VIEWPORTS' not in self:
  91. self._setup_table('VPORT')
  92. if 'APPIDS' not in self:
  93. self._setup_table('APPID')
  94. if 'UCS' not in self:
  95. self._setup_table('UCS')
  96. def __contains__(self, item: str) -> bool:
  97. return self.key(item) in self._tables
  98. def __getattr__(self, key: str) -> Table:
  99. key = self.key(key)
  100. try:
  101. return self._tables[key]
  102. except KeyError: # internal exception
  103. raise DXFAttributeError(key)
  104. def __getitem__(self, key: str) -> Table:
  105. return self._tables[self.key(key)]
  106. def __delitem__(self, key: str) -> None:
  107. del self._tables[self.key(key)]
  108. def write(self, tagwriter: 'TagWriter') -> None:
  109. tagwriter.write_str(' 0\nSECTION\n 2\nTABLES\n')
  110. for table_name in TABLE_ORDER:
  111. table = self._tables.get(table_name)
  112. if table is not None:
  113. table.write(tagwriter)
  114. tagwriter.write_tag2(0, 'ENDSEC')
  115. TABLESMAP = {
  116. 'LAYER': Table,
  117. 'LTYPE': Table,
  118. 'STYLE': StyleTable,
  119. 'DIMSTYLE': Table,
  120. 'VPORT': ViewportTable,
  121. 'VIEW': Table,
  122. 'UCS': Table,
  123. 'APPID': Table,
  124. 'BLOCK_RECORD': Table,
  125. }
  126. # The order of the tables may change, but the LTYPE table always precedes the LAYER table.
  127. TABLE_ORDER = ('VIEWPORTS', 'LINETYPES', 'LAYERS', 'STYLES', 'VIEWS', 'UCS', 'APPIDS', 'DIMSTYLES', 'BLOCK_RECORDS')