mirror of
https://github.com/unidoc/unioffice.git
synced 2025-04-25 13:48:53 +08:00
spreadsheet: add support for merged cells
This commit is contained in:
parent
8957cf73e3
commit
924140c87d
@ -41,6 +41,7 @@ and .pptx).
|
||||
- [Bar Chart](https://github.com/baliance/gooxml/tree/master/_examples/spreadsheet/bar-chart) Bar Charts
|
||||
- [Mutiple Charts](https://github.com/baliance/gooxml/tree/master/_examples/spreadsheet/multiple-charts) Multiple charts on a single sheet
|
||||
- [Named Cell Ranges](https://github.com/baliance/gooxml/tree/master/_examples/spreadsheet/named-ranges) Naming cell ranges
|
||||
- [Merged Cells](https://github.com/baliance/gooxml/tree/master/_examples/spreadsheet/merged) Merge and unmerge cells.
|
||||
|
||||
## Raw Types ##
|
||||
|
||||
|
35
_examples/spreadsheet/merged/main.go
Normal file
35
_examples/spreadsheet/merged/main.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright 2017 Baliance. All rights reserved.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"baliance.com/gooxml/spreadsheet"
|
||||
|
||||
sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ss := spreadsheet.New()
|
||||
sheet := ss.AddSheet()
|
||||
|
||||
sheet.Cell("A1").SetString("Hello World!")
|
||||
sheet.Cell("B1").SetString("will not be visible") // as it's not the first cell within a merged range Excel warns you when you do this through the UI
|
||||
sheet.AddMergedCells("A1", "C2")
|
||||
|
||||
centered := ss.StyleSheet.AddCellStyle()
|
||||
centered.SetHorizontalAlignment(sml.ST_HorizontalAlignmentCenter)
|
||||
centered.SetVerticalAlignment(sml.ST_VerticalAlignmentCenter)
|
||||
sheet.Cell("A1").SetStyle(centered)
|
||||
|
||||
for _, m := range sheet.MergedCells() {
|
||||
fmt.Println("merged region", m.Reference(), "has contents", m.Cell().GetString())
|
||||
}
|
||||
|
||||
if err := ss.Validate(); err != nil {
|
||||
log.Fatalf("error validating sheet: %s", err)
|
||||
}
|
||||
|
||||
ss.SaveToFile("merged.xlsx")
|
||||
}
|
BIN
_examples/spreadsheet/merged/merged.xlsx
Normal file
BIN
_examples/spreadsheet/merged/merged.xlsx
Normal file
Binary file not shown.
@ -245,6 +245,31 @@ func (c Cell) SetStyleIndex(idx uint32) {
|
||||
c.x.SAttr = gooxml.Uint32(idx)
|
||||
}
|
||||
|
||||
// GetString returns the string in a cell if it's an inline or string table
|
||||
// string. Otherwise it returns an empty string.
|
||||
func (c Cell) GetString() string {
|
||||
switch c.x.TAttr {
|
||||
case sml.ST_CellTypeInlineStr:
|
||||
if c.x.Is == nil || c.x.Is.T == nil {
|
||||
return ""
|
||||
}
|
||||
case sml.ST_CellTypeS:
|
||||
if c.x.V == nil {
|
||||
return ""
|
||||
}
|
||||
id, err := strconv.Atoi(*c.x.V)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
s, err := c.w.SharedStrings.GetString(id)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return s
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (c Cell) GetValue() (string, error) {
|
||||
switch c.x.TAttr {
|
||||
case sml.ST_CellTypeInlineStr:
|
||||
|
48
spreadsheet/mergedcell.go
Normal file
48
spreadsheet/mergedcell.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2017 Baliance. All rights reserved.
|
||||
//
|
||||
// Use of this source code is governed by the terms of the Affero GNU General
|
||||
// Public License version 3.0 as published by the Free Software Foundation and
|
||||
// appearing in the file LICENSE included in the packaging of this file. A
|
||||
// commercial license can be purchased by contacting sales@baliance.com.
|
||||
|
||||
package spreadsheet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sml "baliance.com/gooxml/schema/schemas.openxmlformats.org/spreadsheetml"
|
||||
)
|
||||
|
||||
type MergedCell struct {
|
||||
wb *Workbook
|
||||
ws *sml.Worksheet
|
||||
x *sml.CT_MergeCell
|
||||
}
|
||||
|
||||
// X returns the inner wrapped XML type.
|
||||
func (s MergedCell) X() *sml.CT_MergeCell {
|
||||
return s.x
|
||||
}
|
||||
|
||||
// SetReference sets the regin of cells that the merged cell applies to.
|
||||
func (s MergedCell) SetReference(ref string) {
|
||||
s.x.RefAttr = ref
|
||||
}
|
||||
|
||||
// Reference returns the region of cells that are merged.
|
||||
func (s MergedCell) Reference() string {
|
||||
return s.x.RefAttr
|
||||
}
|
||||
|
||||
// Cell returns the actual cell behind the merged region
|
||||
func (s MergedCell) Cell() Cell {
|
||||
ref := s.Reference()
|
||||
if idx := strings.Index(s.Reference(), ":"); idx != -1 {
|
||||
ref = ref[0:idx]
|
||||
return Sheet{w: s.wb, x: s.ws}.Cell(ref)
|
||||
}
|
||||
fmt.Println("DIE")
|
||||
// couldn't find it, log an error?
|
||||
return Cell{}
|
||||
}
|
@ -257,3 +257,46 @@ func (s Sheet) SetAutoFilter(rangeRef string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// AddMergedCells merges cells within a sheet.
|
||||
func (s Sheet) AddMergedCells(fromRef, toRef string) MergedCell {
|
||||
// TODO: we might need to actually create the merged cells if they don't
|
||||
// exist, but it appears to work fine on both Excel and LibreOffice just
|
||||
// creating the merged region
|
||||
|
||||
if s.x.MergeCells == nil {
|
||||
s.x.MergeCells = sml.NewCT_MergeCells()
|
||||
}
|
||||
|
||||
merge := sml.NewCT_MergeCell()
|
||||
merge.RefAttr = fmt.Sprintf("%s:%s", fromRef, toRef)
|
||||
|
||||
s.x.MergeCells.MergeCell = append(s.x.MergeCells.MergeCell, merge)
|
||||
s.x.MergeCells.CountAttr = gooxml.Uint32(uint32(len(s.x.MergeCells.MergeCell)))
|
||||
return MergedCell{s.w, s.x, merge}
|
||||
}
|
||||
|
||||
// MergedCells returns the merged cell regions within the sheet.
|
||||
func (s Sheet) MergedCells() []MergedCell {
|
||||
if s.x.MergeCells == nil {
|
||||
return nil
|
||||
}
|
||||
ret := []MergedCell{}
|
||||
for _, c := range s.x.MergeCells.MergeCell {
|
||||
ret = append(ret, MergedCell{s.w, s.x, c})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// RemoveMergedCell removes merging from a cell range within a sheet. The cells
|
||||
// that made up the merged cell remain, but are no lon merged.
|
||||
func (s Sheet) RemoveMergedCell(mc MergedCell) {
|
||||
for i, c := range s.x.MergeCells.MergeCell {
|
||||
if c == mc.X() {
|
||||
copy(s.x.MergeCells.MergeCell[i:], s.x.MergeCells.MergeCell[i+1:])
|
||||
s.x.MergeCells.MergeCell[len(s.x.MergeCells.MergeCell)-1] = nil
|
||||
s.x.MergeCells.MergeCell = s.x.MergeCells.MergeCell[:len(s.x.MergeCells.MergeCell)-1]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -132,3 +132,34 @@ func TestSheetNameLength(t *testing.T) {
|
||||
t.Errorf("expected validation error with sheet name too long")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergedCell(t *testing.T) {
|
||||
wb := spreadsheet.New()
|
||||
sheet := wb.AddSheet()
|
||||
|
||||
expContent := "testing 123"
|
||||
sheet.Cell("A1").SetString(expContent)
|
||||
sheet.Cell("B1").SetString("in range, but not visible")
|
||||
if len(sheet.MergedCells()) != 0 {
|
||||
t.Errorf("new sheet should have no merged cells")
|
||||
}
|
||||
sheet.AddMergedCells("A1", "C2")
|
||||
if len(sheet.MergedCells()) != 1 {
|
||||
t.Errorf("sheet should have a single merged cells")
|
||||
}
|
||||
|
||||
mc := sheet.MergedCells()[0]
|
||||
expRef := "A1:C2"
|
||||
if mc.Reference() != expRef {
|
||||
t.Errorf("expected merged cell reference %s, got %s", expRef, mc.Reference())
|
||||
}
|
||||
|
||||
if mc.Cell().GetString() != expContent {
|
||||
t.Errorf("expected merged cell content to be '%s', got '%s'", expContent, mc.Cell().GetString())
|
||||
}
|
||||
|
||||
sheet.RemoveMergedCell(mc)
|
||||
if len(sheet.MergedCells()) != 0 {
|
||||
t.Errorf("after removal, sheet should have no merged cells")
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user