-
Notifications
You must be signed in to change notification settings - Fork 6
/
data_binder.go
129 lines (108 loc) · 3.64 KB
/
data_binder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package control
import (
"context"
"github.com/goradd/goradd/pkg/log"
"github.com/goradd/goradd/pkg/page"
"reflect"
)
type DataBinder interface {
// A DataBinder must be a control so that we can serialize it
ID() string
// BindData is called by the data manager to get the data for the control during draw time
BindData(ctx context.Context, s DataManagerI)
}
// A DataManagerI is the interface for the owner (the embedder) of the DataManager
type DataManagerI interface {
page.ControlI
DataManagerEmbedder
}
// DataManagerEmbedder is the interface to include in embedded control interfaces
// Currently go does not allow interface conflicts, but that is scheduled to change
type DataManagerEmbedder interface {
SetDataProvider(b DataBinder)
HasDataProvider() bool
// SetData should be passed a slice of data items
SetData(interface{})
LoadData(ctx context.Context, owner DataManagerI)
ResetData()
}
// DataManager is an object designed to be embedded in a control that will help manage the data binding process.
type DataManager struct {
dataProviderID string
// data is a temporary copy of the drawing data that is intended to only be loaded during drawing, and then unloaded after drawing.
data interface{}
}
func (d *DataManager) SetDataProvider(b DataBinder) {
d.dataProviderID = b.ID()
}
func (d *DataManager) HasDataProvider() bool {
return d.dataProviderID != ""
}
// Call SetData to set the data of a control that uses a data binder. You MUST call it with a slice
// of some kind of data.
func (d *DataManager) SetData(data interface{}) {
kind := reflect.TypeOf(data).Kind()
if kind != reflect.Slice {
panic("you must call SetData with a slice")
}
d.data = data
}
// ResetData is called by controls that use a data binder to unload the data after it is used.
func (d *DataManager) ResetData() {
if d.HasDataProvider() {
d.data = nil
}
}
// LoadData tells the data binder to load data by calling SetData on the given object. The object should be
// the embedder of the DataManager
func (d *DataManager) LoadData(ctx context.Context, owner DataManagerI) {
if d.HasDataProvider() && // load data if we have a data provider
!d.HasData() { // We might have already been told to load the data so that another related control
// can access information in this control. For example, a paged control and a pager.
// This MANDATES that the control then unload the data after drawing
log.FrameworkDebug("Calling BindData")
dataProvider := owner.Page().GetControl(d.dataProviderID).(DataBinder)
dataProvider.BindData(ctx, owner) // tell the data binder to call SetData on the given object, or load data some other way
}
}
// RangeData will call the given function for each item in the data.
// The function should return true to continue, and false to end early.
func (d *DataManager) RangeData(f func(int, interface{}) bool) {
if d.data == nil {
return
}
listValue := reflect.ValueOf(d.data)
for i := 0; i < listValue.Len(); i++ {
itemI := listValue.Index(i).Interface()
result := f(i, itemI)
if !result {
break
}
}
}
func (d *DataManager) HasData() bool {
return d.data != nil
}
type encodedDataManager struct {
DataProviderID string
Data interface{}
}
func (d *DataManager) Serialize(e page.Encoder) (err error) {
enc := encodedDataManager{
DataProviderID: d.dataProviderID,
Data: d.data,
}
if err = e.Encode(enc); err != nil {
panic (err)
}
return
}
func (d *DataManager) Deserialize(dec page.Decoder) (err error) {
enc := encodedDataManager{}
if err = dec.Decode(&enc); err != nil {
panic(err)
}
d.dataProviderID = enc.DataProviderID
d.data = enc.Data
return
}