mirror of
https://github.com/unidoc/unioffice.git
synced 2025-05-02 22:17:07 +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
|
- [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
|
- [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
|
- [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 ##
|
## 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)
|
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) {
|
func (c Cell) GetValue() (string, error) {
|
||||||
switch c.x.TAttr {
|
switch c.x.TAttr {
|
||||||
case sml.ST_CellTypeInlineStr:
|
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")
|
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