Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Copyright (c) 2010-2020 openpyxl 

2 

3from openpyxl.descriptors.serialisable import Serialisable 

4from openpyxl.descriptors import ( 

5 Integer, 

6 Sequence, 

7) 

8 

9from openpyxl.cell.cell import MergedCell 

10from openpyxl.styles.borders import Border 

11 

12from .cell_range import CellRange 

13 

14 

15class MergeCell(CellRange): 

16 

17 tagname = "mergeCell" 

18 ref = CellRange.coord 

19 

20 __attrs__ = ("ref",) 

21 

22 

23 def __init__(self, 

24 ref=None, 

25 ): 

26 super(MergeCell, self).__init__(ref) 

27 

28 

29 def __copy__(self): 

30 return self.__class__(self.ref) 

31 

32 

33class MergeCells(Serialisable): 

34 

35 tagname = "mergeCells" 

36 

37 count = Integer(allow_none=True) 

38 mergeCell = Sequence(expected_type=MergeCell, ) 

39 

40 __elements__ = ('mergeCell',) 

41 __attrs__ = ('count',) 

42 

43 def __init__(self, 

44 count=None, 

45 mergeCell=(), 

46 ): 

47 self.mergeCell = mergeCell 

48 

49 

50 @property 

51 def count(self): 

52 return len(self.mergeCell) 

53 

54 

55class MergedCellRange(CellRange): 

56 

57 """ 

58 MergedCellRange stores the border information of a merged cell in the top 

59 left cell of the merged cell. 

60 The remaining cells in the merged cell are stored as MergedCell objects and 

61 get their border information from the upper left cell. 

62 """ 

63 

64 def __init__(self, worksheet, coord): 

65 self.ws = worksheet 

66 super(MergedCellRange, self).__init__(range_string=coord) 

67 self.start_cell = None 

68 self._get_borders() 

69 

70 

71 def _get_borders(self): 

72 """ 

73 If the upper left cell of the merged cell does not yet exist, it is 

74 created. 

75 The upper left cell gets the border information of the bottom and right 

76 border from the bottom right cell of the merged cell, if available. 

77 """ 

78 

79 # Top-left cell. 

80 self.start_cell = self.ws._cells.get((self.min_row, self.min_col)) 

81 if self.start_cell is None: 

82 self.start_cell = self.ws.cell(row=self.min_row, column=self.min_col) 

83 

84 # Bottom-right cell 

85 end_cell = self.ws._cells.get((self.max_row, self.max_col)) 

86 if end_cell is not None: 

87 self.start_cell.border += Border(right=end_cell.border.right, 

88 bottom=end_cell.border.bottom) 

89 

90 

91 def format(self): 

92 """ 

93 Each cell of the merged cell is created as MergedCell if it does not 

94 already exist. 

95 

96 The MergedCells at the edge of the merged cell gets its borders from 

97 the upper left cell. 

98 

99 - The top MergedCells get the top border from the top left cell. 

100 - The bottom MergedCells get the bottom border from the top left cell. 

101 - The left MergedCells get the left border from the top left cell. 

102 - The right MergedCells get the right border from the top left cell. 

103 """ 

104 

105 names = ['top', 'left', 'right', 'bottom'] 

106 

107 for name in names: 

108 side = getattr(self.start_cell.border, name) 

109 if side.style is None: 

110 continue # don't need to do anything if there is no border style 

111 border = Border(**{name:side}) 

112 for coord in getattr(self, name): 

113 cell = self.ws._cells.get(coord) 

114 if cell is None: 

115 row, col = coord 

116 cell = MergedCell(self.ws, row=row, column=col) 

117 self.ws._cells[(cell.row, cell.column)] = cell 

118 cell.border += border