Browse Source

Добавил механизм формирования стилей и первый стиль, для текста,
улучшил модель

kpmy 10 years ago
parent
commit
ade7e039a0

+ 6 - 1
generators/gen.go

@@ -51,7 +51,8 @@ func docParts(m model.Model) (ret Parts) {
 			halt.As(100, l.Name())
 		}
 		enc := xml.NewEncoder(buf)
-		enc.Encode(l)
+		err := enc.Encode(l)
+		assert.For(err == nil, 60, err)
 	}
 	return
 }
@@ -61,6 +62,8 @@ func Generate(m model.Model, out io.Writer, mimetype xmlns.Mime) {
 	mime := &zip.FileHeader{Name: xmlns.Mimetype, Method: zip.Store} //файл mimetype не надо сжимать, режим Store
 	if w, err := z.CreateHeader(mime); err == nil {
 		bytes.NewBufferString(string(mimetype)).WriteTo(w)
+	} else {
+		halt.As(100, err)
 	}
 	manifest := &Manifest{}
 	manifest.init(mimetype)
@@ -68,6 +71,8 @@ func Generate(m model.Model, out io.Writer, mimetype xmlns.Mime) {
 		if w, err := z.Create(k); err == nil {
 			v.WriteTo(w)
 			manifest.Entries = append(manifest.Entries, Entry{MediaType: xmlns.MimeDefault, FullPath: k})
+		} else {
+			halt.As(100, err)
 		}
 	}
 	//place for attachements

+ 78 - 9
mappers/attr.go

@@ -1,18 +1,38 @@
 package mappers
 
 import (
+	"odf/mappers/attr"
 	"odf/model"
 	"odf/xmlns/office"
+	"odf/xmlns/style"
+	"odf/xmlns/svg"
+	"strconv"
+	"ypk/halt"
 )
 
 type Attr struct {
-	doc  model.Model
-	ds   model.Leaf //document styles
-	ffd  model.Leaf //font-face decls
-	as   model.Leaf //automatic styles
-	ms   model.Leaf //master styles
-	asc  model.Leaf //automatic styles
-	ffdc model.Leaf //font-face decls
+	doc     model.Model
+	ds      model.Leaf //document styles
+	ffd     model.Leaf //font-face decls
+	as      model.Leaf //automatic styles
+	ms      model.Leaf //master styles
+	asc     model.Leaf //automatic styles
+	ffdc    model.Leaf //font-face decls
+	current map[string]attr.Attributes
+	old     map[string]attr.Attributes
+	fonts   map[string]model.Leaf
+	stored  bool
+	count   int
+}
+
+func (a *Attr) nextName() string {
+	a.count++
+	return "auto" + strconv.Itoa(a.count)
+}
+
+func (a *Attr) reset() {
+	a.stored = true
+	a.current = make(map[string]attr.Attributes)
 }
 
 func (a *Attr) Init(m model.Model) {
@@ -22,8 +42,57 @@ func (a *Attr) Init(m model.Model) {
 	a.ds = wr.WritePos(New(office.DocumentStyles))
 	wr.Attr(office.Version, "1.0")
 	a.ffd = wr.WritePos(New(office.FontFaceDecls))
+	wr.Pos(a.ds)
 	a.as = wr.WritePos(New(office.AutomaticStyles))
+	wr.Pos(a.ds)
 	a.ms = wr.WritePos(New(office.MasterStyles))
-	a.asc = wr.WritePos(New(office.AutomaticStyles))
-	a.ffdc = wr.WritePos(New(office.FontFaceDecls))
+	wr.Pos(a.ds)
+	a.asc = New(office.AutomaticStyles)
+	a.ffdc = New(office.FontFaceDecls)
+	a.old = make(map[string]attr.Attributes)
+	a.fonts = make(map[string]model.Leaf)
+	a.reset()
+}
+
+func (a *Attr) Fit(n model.LeafName) (ret attr.Attributes) {
+	fit := make(map[model.LeafName]attr.Attributes)
+	for _, v := range a.current {
+		fit[v.Fit()] = v
+	}
+	ret = fit[n]
+	return
+}
+
+func (a *Attr) RegisterFont(name, fontface string) {
+	if a.fonts[name] == nil {
+		wr := a.doc.NewWriter()
+		wr.Pos(a.ffd)
+		wr.WritePos(New(style.FontFace))
+		wr.Attr(style.Name, name)
+		wr.Attr(svg.FontFamily, fontface)
+		//TODO deep copy fontface node
+		wr.Pos(a.ffdc)
+		a.fonts[name] = wr.WritePos(New(style.FontFace))
+		wr.Attr(style.Name, name)
+		wr.Attr(svg.FontFamily, name)
+	}
+}
+
+func (a *Attr) Flush() {
+	if !a.stored {
+		wr := a.doc.NewWriter()
+		for _, v := range a.current {
+			if n := v.Name(); n == "" && a.old[n] == nil {
+				v.Name(a.nextName())
+				wr.Pos(a.asc)
+				wr.WritePos(New(style.Style))
+				wr.Attr(style.Name, v.Name())
+				v.Write(a.doc.NewWriter(wr))
+				a.old[v.Name()] = v
+			} else {
+				halt.As(100, v.Name())
+			}
+		}
+		a.stored = true
+	}
 }

+ 65 - 0
mappers/attr/styles.go

@@ -0,0 +1,65 @@
+package attr
+
+import (
+	"odf/model"
+	"odf/xmlns/fo"
+	"odf/xmlns/style"
+	"odf/xmlns/text"
+	"ypk/assert"
+)
+
+var New func(name model.LeafName) model.Leaf
+
+type Attributes interface {
+	Name(...string) string
+	Equal(Attributes) bool
+	Fit() model.LeafName
+	Write(model.Writer)
+}
+
+type named struct {
+	name string
+}
+
+func (n *named) Name(s ...string) string {
+	if len(s) == 1 {
+		assert.For(s[0] != "", 20)
+		n.name = s[0]
+	}
+	return n.name
+}
+
+type TextAttributes struct {
+	fontFace string
+	size     int
+	named
+}
+
+func (t *TextAttributes) Equal(_a Attributes) (ok bool) {
+	a, ok := _a.(*TextAttributes)
+	ok = t.size == a.size && t.fontFace == a.fontFace
+	return
+}
+
+func (t *TextAttributes) Fit() model.LeafName { return text.Span }
+
+func (t *TextAttributes) Write(wr model.Writer) {
+	wr.Attr(style.Family, style.FamilyText)
+	wr.WritePos(New(style.TextProperties))
+	wr.Attr(style.FontName, t.fontFace)
+	wr.Attr(fo.FontSize, t.size)
+}
+
+func (t *TextAttributes) Size(s int) *TextAttributes {
+	t.size = s
+	return t
+}
+
+func (t *TextAttributes) FontFace(name string) *TextAttributes {
+	t.fontFace = name
+	return t
+}
+
+func init() {
+	New = model.LeafFactory
+}

+ 48 - 2
mappers/fmt.go

@@ -1,10 +1,12 @@
 package mappers
 
 import (
+	"odf/mappers/attr"
 	"odf/model"
 	"odf/xmlns"
 	"odf/xmlns/office"
 	"odf/xmlns/text"
+	"reflect"
 	"ypk/assert"
 )
 
@@ -44,7 +46,9 @@ func (f *Formatter) Init() {
 }
 
 func (f *Formatter) writeAttr() {
-
+	if !f.attr.stored {
+		f.attr.Flush()
+	}
 }
 
 func (f *Formatter) WritePara(s string) {
@@ -68,7 +72,7 @@ func (f *Formatter) WriteString(_s string) {
 		f.rider.Write(model.Text(string(buf)))
 		buf = make([]rune, 0)
 		if space && count > 1 {
-			w := f.m.NewWriter()
+			w := f.m.NewWriter(f.rider)
 			w.WritePos(New(text.S))
 			w.Attr(text.C, count)
 		}
@@ -90,12 +94,33 @@ func (f *Formatter) WriteString(_s string) {
 		f.WritePara(_s)
 	} else {
 		f.writeAttr()
+		if a := f.attr.Fit(text.Span); a != nil {
+			f.rider.WritePos(New(text.Span))
+			f.rider.Attr(text.StyleName, a.Name())
+		}
 		s := []rune(_s)
 		br := false
 		for pos := 0; pos < len(s) && s[pos] != 0; {
 			switch s[pos] {
 			case ' ':
 				count++
+			case '\n':
+				grow()
+				f.rider.Write(New(text.LineBreak))
+			case '\r':
+				grow()
+				if f.attr.Fit(text.Span) != nil {
+					f.rider.Pos(f.rider.Pos().Parent())
+				}
+				for pos = pos + 1; pos < len(s); pos++ {
+					buf = append(buf, s[pos])
+				}
+				f.WritePara(string(buf))
+				pos--
+				br = true
+			case '\t':
+				grow()
+				f.rider.Write(New(text.Tab))
 			default:
 				if count > 1 {
 					flush(true)
@@ -109,10 +134,31 @@ func (f *Formatter) WriteString(_s string) {
 		}
 		if !br {
 			grow()
+			if f.attr.Fit(text.Span) != nil {
+				f.rider.Pos(f.rider.Pos().Parent())
+			}
+		}
+	}
+}
+
+func (f *Formatter) SetAttr(a attr.Attributes) {
+	assert.For(f.ready, 20)
+	if a != nil {
+		n := reflect.TypeOf(a).String()
+		c := f.attr.current[n]
+		if (c == nil) || !c.Equal(a) {
+			f.attr.stored = false
+			f.attr.current[n] = a
 		}
+	} else {
+		f.attr.reset()
 	}
 }
 
+func (f *Formatter) RegisterFont(name, fontface string) {
+	f.attr.RegisterFont(name, fontface)
+}
+
 func init() {
 	New = model.LeafFactory
 }

+ 16 - 1
model/stub/simple_attrs.go

@@ -2,6 +2,7 @@ package stub
 
 import (
 	"encoding/xml"
+	"strconv"
 )
 
 type StringAttr struct {
@@ -14,6 +15,20 @@ func (a *StringAttr) String() string {
 
 func (a *StringAttr) MarshalXMLAttr(name xml.Name) (xa xml.Attr, err error) {
 	xa.Name = name
-	xa.Value = a.Value
+	xa.Value = a.String()
+	return
+}
+
+type IntAttr struct {
+	Value int
+}
+
+func (a *IntAttr) String() string {
+	return strconv.Itoa(a.Value)
+}
+
+func (a *IntAttr) MarshalXMLAttr(name xml.Name) (xa xml.Attr, err error) {
+	xa.Name = name
+	xa.Value = a.String()
 	return
 }

+ 12 - 1
model/stub/simple_nodes.go

@@ -33,14 +33,25 @@ func (r *root) NofChild() int {
 	return r.inner.NofChild()
 }
 
+func (r *root) Parent(...model.Node) model.Node { return nil }
+
 type text struct {
-	data string
+	data   string
+	parent model.Node
 }
 
 func (t *text) Name() model.LeafName { panic(100) }
 
 func (t *text) Attr(model.AttrName, ...model.Attribute) model.Attribute { panic(100) }
 
+func (t *text) Parent(p ...model.Node) model.Node {
+	if len(p) == 1 {
+		assert.For(t.parent == nil, 20)
+		t.parent = p[0]
+	}
+	return t.parent
+}
+
 func (r *root) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
 	start.Name.Local = string(r.inner.Name())
 

+ 21 - 1
model/stub/simple_riders.go

@@ -66,7 +66,9 @@ func (w *sw) Base() model.Model {
 }
 
 func (w *sw) InitFrom(old model.Writer) {
-	panic(126)
+	if old != nil {
+		w.Pos(old.Pos())
+	}
 }
 
 func (w *sw) Pos(p ...model.Leaf) model.Leaf {
@@ -83,8 +85,10 @@ func (w *sw) Write(l model.Leaf) {
 		switch n := _n.(type) {
 		case *sn:
 			n.children = append(n.children, l)
+			l.Parent(n)
 		case *root:
 			n.inner.children = append(n.inner.children, l)
+			l.Parent(n.inner)
 		default:
 			halt.As(100, reflect.TypeOf(n))
 		}
@@ -96,11 +100,27 @@ func (w *sw) WritePos(l model.Leaf) model.Leaf {
 	return w.Pos(l)
 }
 
+func validateAttr(n model.AttrName, val string) {
+	values := xmlns.Enums[n]
+	found := false
+	for _, v := range values {
+		if v == val {
+			found = true
+		}
+	}
+	assert.For(found, 60)
+}
+
 func castAttr(n model.AttrName, i interface{}) (ret model.Attribute) {
 	typ := xmlns.Typed[n]
 	switch typ {
 	case xmlns.NONE, xmlns.STRING:
 		ret = &StringAttr{Value: i.(string)}
+	case xmlns.INT:
+		ret = &IntAttr{Value: i.(int)}
+	case xmlns.ENUM:
+		validateAttr(n, i.(string))
+		ret = &StringAttr{Value: i.(string)}
 	default:
 		halt.As(100, typ, reflect.TypeOf(i))
 	}

+ 9 - 0
model/stub/simple_tree.go

@@ -14,6 +14,7 @@ type sn struct {
 	name     model.LeafName
 	attr     map[model.AttrName]model.Attribute
 	children []model.Leaf
+	parent   model.Node
 }
 
 func (n *sn) Attr(name model.AttrName, val ...model.Attribute) model.Attribute {
@@ -53,6 +54,14 @@ func (n *sn) init() {
 	n.children = make([]model.Leaf, 0)
 }
 
+func (n *sn) Parent(p ...model.Node) model.Node {
+	if len(p) == 1 {
+		assert.For(n.parent == nil, 20)
+		n.parent = p[0]
+	}
+	return n.parent
+}
+
 func (n *sn) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
 	start.Name.Local = string(n.name)
 	for k, v := range n.attr {

+ 1 - 0
model/tree.go

@@ -7,6 +7,7 @@ type Attribute interface {
 type Leaf interface {
 	Name() LeafName
 	Attr(AttrName, ...Attribute) Attribute
+	Parent(...Node) Node
 }
 
 type Node interface {

+ 20 - 3
odf_test.go

@@ -3,11 +3,13 @@ package odf
 import (
 	"odf/generators"
 	"odf/mappers"
+	"odf/mappers/attr"
 	"odf/model"
 	_ "odf/model/stub"
 	"odf/xmlns"
 	"os"
 	"testing"
+	"ypk/assert"
 )
 
 func TestModel(t *testing.T) {
@@ -37,17 +39,32 @@ func TestGenerators(t *testing.T) {
 	fm.MimeType = xmlns.MimeText
 	fm.Init()
 	generators.Generate(m, output, fm.MimeType)
-	output.Close()
+	assert.For(output.Close() == nil, 20)
 }
 
 func TestStructure(t *testing.T) {
-	output, _ := os.OpenFile("test0.odf", os.O_CREATE|os.O_WRONLY, 0666)
+	output, _ := os.OpenFile("test1.odf", os.O_CREATE|os.O_WRONLY, 0666)
+	m := model.ModelFactory()
+	fm := &mappers.Formatter{}
+	fm.ConnectTo(m)
+	fm.MimeType = xmlns.MimeText
+	fm.Init()
+	fm.WriteString("Hello, World!   \t   \n   \r	фыва 	фыва		\n фыва")
+	generators.Generate(m, output, fm.MimeType)
+	assert.For(output.Close() == nil, 20)
+}
+
+func TestStyles(t *testing.T) {
+	output, _ := os.OpenFile("test2.odf", os.O_CREATE|os.O_WRONLY, 0666)
 	m := model.ModelFactory()
 	fm := &mappers.Formatter{}
 	fm.ConnectTo(m)
 	fm.MimeType = xmlns.MimeText
 	fm.Init()
 	fm.WriteString(`Hello, World!`)
+	fm.RegisterFont("Arial", "Arial")
+	fm.SetAttr(new(attr.TextAttributes).Size(32).FontFace("Arial"))
+	fm.WriteString(`Hello, World!`)
 	generators.Generate(m, output, fm.MimeType)
-	output.Close()
+	assert.For(output.Close() == nil, 20)
 }

+ 14 - 0
xmlns/fo/f.go

@@ -0,0 +1,14 @@
+package fo
+
+import (
+	"odf/model"
+	"odf/xmlns"
+)
+
+const (
+	FontSize model.AttrName = "fo:font-size"
+)
+
+func init() {
+	xmlns.Typed[FontSize] = xmlns.INT
+}

+ 27 - 0
xmlns/style/s.go

@@ -0,0 +1,27 @@
+package style
+
+import (
+	"odf/model"
+	"odf/xmlns"
+)
+
+const (
+	Style          model.LeafName = "style:style"
+	TextProperties model.LeafName = "style:text-properties"
+	FontFace       model.LeafName = "style:font-face"
+)
+
+const (
+	Family   model.AttrName = "style:family"
+	Name     model.AttrName = "style:name"
+	FontName model.AttrName = "style:font-name"
+)
+
+const (
+	FamilyText = "text"
+)
+
+func init() {
+	xmlns.Typed[Family] = xmlns.ENUM
+	xmlns.Enums[Family] = []string{FamilyText}
+}

+ 9 - 0
xmlns/svg/s.go

@@ -0,0 +1,9 @@
+package svg
+
+import (
+	"odf/model"
+)
+
+const (
+	FontFamily model.AttrName = "svg:font-family"
+)

+ 10 - 1
xmlns/text/t.go

@@ -2,13 +2,22 @@ package text
 
 import (
 	"odf/model"
+	"odf/xmlns"
 )
 
 const (
 	Paragraph model.LeafName = "text:p"
 	S         model.LeafName = "text:s"
+	LineBreak model.LeafName = "text:line-break"
+	Tab       model.LeafName = "text:tab"
+	Span      model.LeafName = "text:span"
 )
 
 const (
-	C model.AttrName = "text:c"
+	C         model.AttrName = "text:c"
+	StyleName model.AttrName = "text:style-name"
 )
+
+func init() {
+	xmlns.Typed[C] = xmlns.INT
+}

+ 4 - 0
xmlns/x.go

@@ -42,6 +42,8 @@ type AttrType int
 const (
 	NONE AttrType = iota
 	STRING
+	INT
+	ENUM
 )
 
 type Mime string
@@ -52,7 +54,9 @@ const (
 )
 
 var Typed map[model.AttrName]AttrType
+var Enums map[model.AttrName][]string
 
 func init() {
 	Typed = make(map[model.AttrName]AttrType)
+	Enums = make(map[model.AttrName][]string)
 }