col.go 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. package xlsx
  2. // Default column width in excel
  3. const ColWidth = 9.5
  4. const Excel2006MaxRowCount = 1048576
  5. const Excel2006MaxRowIndex = Excel2006MaxRowCount - 1
  6. type Col struct {
  7. Min int
  8. Max int
  9. Hidden bool
  10. Width float64
  11. Collapsed bool
  12. OutlineLevel uint8
  13. BestFit bool
  14. CustomWidth bool
  15. Phonetic bool
  16. numFmt string
  17. parsedNumFmt *parsedNumberFormat
  18. style *Style
  19. outXfID int
  20. }
  21. // NewColForRange return a pointer to a new Col, which will apply to
  22. // columns in the range min to max (inclusive). Note, in order for
  23. // this Col to do anything useful you must set some of its parameters
  24. // and then apply it to a Sheet by calling sheet.SetColParameters.
  25. func NewColForRange(min, max int) *Col {
  26. if max < min {
  27. // Nice try ;-)
  28. return &Col{Min: max, Max: min}
  29. }
  30. return &Col{Min: min, Max: max}
  31. }
  32. // SetWidth sets the width of columns that have this Col applied to
  33. // them. The width is expressed as the number of characters of the
  34. // maximum digit width of the numbers 0-9 as rendered in the normal
  35. // style's font.
  36. func (c *Col) SetWidth(width float64) {
  37. c.Width = width
  38. c.CustomWidth = true
  39. }
  40. // SetType will set the format string of a column based on the type that you want to set it to.
  41. // This function does not really make a lot of sense.
  42. func (c *Col) SetType(cellType CellType) {
  43. switch cellType {
  44. case CellTypeString:
  45. c.numFmt = builtInNumFmt[builtInNumFmtIndex_STRING]
  46. case CellTypeNumeric:
  47. c.numFmt = builtInNumFmt[builtInNumFmtIndex_INT]
  48. case CellTypeBool:
  49. c.numFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL] //TEMP
  50. case CellTypeInline:
  51. c.numFmt = builtInNumFmt[builtInNumFmtIndex_STRING]
  52. case CellTypeError:
  53. c.numFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL] //TEMP
  54. case CellTypeDate:
  55. // Cells that are stored as dates are not properly supported in this library.
  56. // They should instead be stored as a Numeric with a date format.
  57. c.numFmt = builtInNumFmt[builtInNumFmtIndex_GENERAL]
  58. case CellTypeStringFormula:
  59. c.numFmt = builtInNumFmt[builtInNumFmtIndex_STRING]
  60. }
  61. }
  62. // GetStyle returns the Style associated with a Col
  63. func (c *Col) GetStyle() *Style {
  64. return c.style
  65. }
  66. // SetStyle sets the style of a Col
  67. func (c *Col) SetStyle(style *Style) {
  68. c.style = style
  69. }
  70. // SetStreamStyle sets the style and number format id to the ones specified in the given StreamStyle
  71. func (c *Col) SetStreamStyle(style StreamStyle) {
  72. c.style = style.style
  73. // TODO: `style.xNumFmtId` could be out of the range of the builtin map
  74. // returning "" which may not be a valid formatCode
  75. c.numFmt = builtInNumFmt[style.xNumFmtId]
  76. }
  77. func (c *Col) GetStreamStyle() StreamStyle {
  78. // TODO: Like `SetStreamStyle`, `numFmt` could be out of the range of the builtin inv map
  79. // returning 0 which maps to formatCode "general"
  80. return StreamStyle{builtInNumFmtInv[c.numFmt], c.style}
  81. }
  82. func (c *Col) SetOutlineLevel(outlineLevel uint8) {
  83. c.OutlineLevel = outlineLevel
  84. }
  85. // copyToRange is an internal convenience function to make a copy of a
  86. // Col with a different Min and Max value, it is not intended as a
  87. // general purpose Col copying function as you must still insert the
  88. // resulting Col into the Col Store.
  89. func (c *Col) copyToRange(min, max int) *Col {
  90. return &Col{
  91. Min: min,
  92. Max: max,
  93. Hidden: c.Hidden,
  94. Width: c.Width,
  95. Collapsed: c.Collapsed,
  96. OutlineLevel: c.OutlineLevel,
  97. BestFit: c.BestFit,
  98. CustomWidth: c.CustomWidth,
  99. Phonetic: c.Phonetic,
  100. numFmt: c.numFmt,
  101. parsedNumFmt: c.parsedNumFmt,
  102. style: c.style,
  103. }
  104. }
  105. type ColStoreNode struct {
  106. Col *Col
  107. Prev *ColStoreNode
  108. Next *ColStoreNode
  109. }
  110. //
  111. func (csn *ColStoreNode) findNodeForColNum(num int) *ColStoreNode {
  112. switch {
  113. case num >= csn.Col.Min && num <= csn.Col.Max:
  114. return csn
  115. case num < csn.Col.Min:
  116. if csn.Prev == nil {
  117. return nil
  118. }
  119. if csn.Prev.Col.Max < num {
  120. return nil
  121. }
  122. return csn.Prev.findNodeForColNum(num)
  123. case num > csn.Col.Max:
  124. if csn.Next == nil {
  125. return nil
  126. }
  127. if csn.Next.Col.Min > num {
  128. return nil
  129. }
  130. return csn.Next.findNodeForColNum(num)
  131. }
  132. return nil
  133. }
  134. // ColStore is the working store of Col definitions, it will simplify all Cols added to it, to ensure there ar no overlapping definitions.
  135. type ColStore struct {
  136. Root *ColStoreNode
  137. Len int
  138. }
  139. // Add a Col to the ColStore. If it overwrites all, or part of some
  140. // existing Col's range of columns the that Col will be adjusted
  141. // and/or split to make room for the new Col.
  142. func (cs *ColStore) Add(col *Col) *ColStoreNode {
  143. newNode := &ColStoreNode{Col: col}
  144. if cs.Root == nil {
  145. cs.Root = newNode
  146. cs.Len = 1
  147. return newNode
  148. }
  149. cs.makeWay(cs.Root, newNode)
  150. return newNode
  151. }
  152. func (cs *ColStore) FindColByIndex(index int) *Col {
  153. csn := cs.findNodeForColNum(index)
  154. if csn != nil {
  155. return csn.Col
  156. }
  157. return nil
  158. }
  159. func (cs *ColStore) findNodeForColNum(num int) *ColStoreNode {
  160. if cs.Root == nil {
  161. return nil
  162. }
  163. return cs.Root.findNodeForColNum(num)
  164. }
  165. func (cs *ColStore) removeNode(node *ColStoreNode) {
  166. if node.Prev != nil {
  167. if node.Next != nil {
  168. node.Prev.Next = node.Next
  169. } else {
  170. node.Prev.Next = nil
  171. }
  172. }
  173. if node.Next != nil {
  174. if node.Prev != nil {
  175. node.Next.Prev = node.Prev
  176. } else {
  177. node.Next.Prev = nil
  178. }
  179. }
  180. if cs.Root == node {
  181. switch {
  182. case node.Prev != nil:
  183. cs.Root = node.Prev
  184. case node.Next != nil:
  185. cs.Root = node.Next
  186. default:
  187. cs.Root = nil
  188. }
  189. }
  190. node.Next = nil
  191. node.Prev = nil
  192. cs.Len -= 1
  193. }
  194. // makeWay will adjust the Min and Max of this ColStoreNode's Col to
  195. // make way for a new ColStoreNode's Col. If necessary it will
  196. // generate an additional ColStoreNode with a new Col covering the
  197. // "tail" portion of this ColStoreNode's Col should the new node lay
  198. // completely within the range of this one, but without reaching its
  199. // maximum extent.
  200. func (cs *ColStore) makeWay(node1, node2 *ColStoreNode) {
  201. switch {
  202. case node1.Col.Max < node2.Col.Min:
  203. // The node2 starts after node1 ends, there's no overlap
  204. //
  205. // Node1 |----|
  206. // Node2 |----|
  207. if node1.Next != nil {
  208. if node1.Next.Col.Min <= node2.Col.Max {
  209. cs.makeWay(node1.Next, node2)
  210. return
  211. }
  212. cs.addNode(node1, node2, node1.Next)
  213. return
  214. }
  215. cs.addNode(node1, node2, nil)
  216. return
  217. case node1.Col.Min > node2.Col.Max:
  218. // Node2 ends before node1 begins, there's no overlap
  219. //
  220. // Node1 |-----|
  221. // Node2 |----|
  222. if node1.Prev != nil {
  223. if node1.Prev.Col.Max >= node2.Col.Min {
  224. cs.makeWay(node1.Prev, node2)
  225. return
  226. }
  227. cs.addNode(node1.Prev, node2, node1)
  228. return
  229. }
  230. cs.addNode(nil, node2, node1)
  231. return
  232. case node1.Col.Min == node2.Col.Min && node1.Col.Max == node2.Col.Max:
  233. // Exact match
  234. //
  235. // Node1 |xxx|
  236. // Node2 |---|
  237. prev := node1.Prev
  238. next := node1.Next
  239. cs.removeNode(node1)
  240. cs.addNode(prev, node2, next)
  241. // Remove node may have set the root to nil
  242. if cs.Root == nil {
  243. cs.Root = node2
  244. }
  245. return
  246. case node1.Col.Min > node2.Col.Min && node1.Col.Max < node2.Col.Max:
  247. // Node2 envelopes node1
  248. //
  249. // Node1 |xx|
  250. // Node2 |----|
  251. prev := node1.Prev
  252. next := node1.Next
  253. cs.removeNode(node1)
  254. switch {
  255. case prev == node2:
  256. node2.Next = next
  257. case next == node2:
  258. node2.Prev = prev
  259. default:
  260. cs.addNode(prev, node2, next)
  261. }
  262. if node2.Prev != nil && node2.Prev.Col.Max >= node2.Col.Min {
  263. cs.makeWay(prev, node2)
  264. }
  265. if node2.Next != nil && node2.Next.Col.Min <= node2.Col.Max {
  266. cs.makeWay(next, node2)
  267. }
  268. if cs.Root == nil {
  269. cs.Root = node2
  270. }
  271. case node1.Col.Min < node2.Col.Min && node1.Col.Max > node2.Col.Max:
  272. // Node2 bisects node1:
  273. //
  274. // Node1 |---xx---|
  275. // Node2 |--|
  276. newCol := node1.Col.copyToRange(node2.Col.Max+1, node1.Col.Max)
  277. newNode := &ColStoreNode{Col: newCol}
  278. cs.addNode(node1, newNode, node1.Next)
  279. node1.Col.Max = node2.Col.Min - 1
  280. cs.addNode(node1, node2, newNode)
  281. return
  282. case node1.Col.Max >= node2.Col.Min && node1.Col.Min < node2.Col.Min:
  283. // Node2 overlaps node1 at some point above it's minimum:
  284. //
  285. // Node1 |----xx|
  286. // Node2 |-------|
  287. next := node1.Next
  288. node1.Col.Max = node2.Col.Min - 1
  289. if next == node2 {
  290. return
  291. }
  292. cs.addNode(node1, node2, next)
  293. if next != nil && next.Col.Min <= node2.Col.Max {
  294. cs.makeWay(next, node2)
  295. }
  296. return
  297. case node1.Col.Min <= node2.Col.Max && node1.Col.Min > node2.Col.Min:
  298. // Node2 overlaps node1 at some point below it's maximum:
  299. //
  300. // Node1: |------|
  301. // Node2: |----xx|
  302. prev := node1.Prev
  303. node1.Col.Min = node2.Col.Max + 1
  304. if prev == node2 {
  305. return
  306. }
  307. cs.addNode(prev, node2, node1)
  308. if prev != nil && prev.Col.Max >= node2.Col.Min {
  309. cs.makeWay(node1.Prev, node2)
  310. }
  311. return
  312. }
  313. return
  314. }
  315. func (cs *ColStore) addNode(prev, this, next *ColStoreNode) {
  316. if prev != nil {
  317. prev.Next = this
  318. }
  319. this.Prev = prev
  320. this.Next = next
  321. if next != nil {
  322. next.Prev = this
  323. }
  324. cs.Len += 1
  325. }
  326. func (cs *ColStore) getOrMakeColsForRange(start *ColStoreNode, min, max int) []*Col {
  327. cols := []*Col{}
  328. var csn *ColStoreNode
  329. var newCol *Col
  330. switch {
  331. case start == nil:
  332. newCol = NewColForRange(min, max)
  333. csn = cs.Add(newCol)
  334. case start.Col.Min <= min && start.Col.Max >= min:
  335. csn = start
  336. case start.Col.Min < min && start.Col.Max < min:
  337. if start.Next != nil {
  338. return cs.getOrMakeColsForRange(start.Next, min, max)
  339. }
  340. newCol = NewColForRange(min, max)
  341. csn = cs.Add(newCol)
  342. case start.Col.Min > min:
  343. if start.Col.Min > max {
  344. newCol = NewColForRange(min, max)
  345. } else {
  346. newCol = NewColForRange(min, start.Col.Min-1)
  347. }
  348. csn = cs.Add(newCol)
  349. }
  350. cols = append(cols, csn.Col)
  351. if csn.Col.Max >= max {
  352. return cols
  353. }
  354. cols = append(cols, cs.getOrMakeColsForRange(csn.Next, csn.Col.Max+1, max)...)
  355. return cols
  356. }
  357. func chainOp(csn *ColStoreNode, fn func(idx int, col *Col)) {
  358. for csn.Prev != nil {
  359. csn = csn.Prev
  360. }
  361. var i int
  362. for i = 0; csn.Next != nil; i++ {
  363. fn(i, csn.Col)
  364. csn = csn.Next
  365. }
  366. fn(i+1, csn.Col)
  367. }
  368. // ForEach calls the function fn for each Col defined in the ColStore.
  369. func (cs *ColStore) ForEach(fn func(idx int, col *Col)) {
  370. if cs.Root == nil {
  371. return
  372. }
  373. chainOp(cs.Root, fn)
  374. }