1 Star 0 Fork 1

wmdng/walk

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
data
declarative
examples
l10n
tools/ui2walk
AUTHORS
LICENSE
README.mdown
accessibility.go
action.go
actionlist.go
application.go
bitmap.go
boxlayout.go
brush.go
button.go
cancelevent.go
canvas.go
checkbox.go
clipboard.go
closeevent.go
color.go
combobox.go
commondialogs.go
composite.go
condition.go
container.go
cursor.go
customwidget.go
databinding.go
dateedit.go
datelabel.go
dialog.go
dropfilesevent.go
error.go
errorevent.go
event.go
expression.go
flowlayout.go
font.go
fontresource.go
form.go
gradientcomposite.go
graphicseffects.go
gridlayout.go
groupbox.go
icon.go
iconcache.go
image.go
imagelist.go
imageview.go
inifilesettings.go
intevent.go
intrangeevent.go
keyboard.go
keyevent.go
label.go
layout.go
lineedit.go
linklabel.go
listbox.go
mainloop_cgo.go
mainloop_default.go
mainwindow.go
maptablemodel.go
menu.go
messagebox.go
metafile.go
models.go
mouseevent.go
notifyicon.go
numberedit.go
numberlabel.go
path.go
pen.go
point.go
progressbar.go
progressindicator.go
property.go
pushbutton.go
radiobutton.go
rectangle.go
reflectmodels.go
registry.go
resourcemanager.go
scrollview.go
separator.go
simpletypes.go
size.go
slider.go
spacer.go
splitbutton.go
splitter.go
splitterhandle.go
splitterlayout.go
static.go
statusbar.go
stopwatch.go
stringevent.go
tableview.go
tableviewcolumn.go
tableviewcolumnlist.go
tabpage.go
tabpagelist.go
tabwidget.go
textedit.go
textlabel.go
toolbar.go
toolbutton.go
tooltip.go
tooltiperrorpresenter.go
treeitemevent.go
treeview.go
util.go
validators.go
walk.go
webview.go
webview_dwebbrowserevents2.go
webview_events.go
webview_idochostuihandler.go
webview_ioleclientsite.go
webview_ioleinplaceframe.go
webview_ioleinplacesite.go
widget.go
widgetlist.go
window.go
windowgroup.go
克隆/下载
databinding.go 12.24 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611
// Copyright 2012 The Walk Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build windows
package walk
import (
"errors"
"fmt"
"reflect"
"strings"
"time"
)
var (
errValidationFailed = errors.New("validation failed")
)
type ErrorPresenter interface {
PresentError(err error, widget Widget)
}
type DataBinder struct {
dataSource interface{}
boundWidgets []Widget
properties []Property
property2Widget map[Property]Widget
property2ChangedHandle map[Property]int
rootExpression Expression
path2Expression map[string]Expression
errorPresenter ErrorPresenter
dataSourceChangedPublisher EventPublisher
canSubmitChangedPublisher EventPublisher
submittedPublisher EventPublisher
resetPublisher EventPublisher
autoSubmitDelay time.Duration
autoSubmitTimer *time.Timer
autoSubmit bool
autoSubmitSuspended bool
canSubmit bool
inReset bool
dirty bool
}
func NewDataBinder() *DataBinder {
db := new(DataBinder)
db.rootExpression = &dataBinderRootExpression{db}
return db
}
func (db *DataBinder) AutoSubmit() bool {
return db.autoSubmit
}
func (db *DataBinder) SetAutoSubmit(autoSubmit bool) {
db.autoSubmit = autoSubmit
if autoSubmit {
db.canSubmit = true
}
}
func (db *DataBinder) AutoSubmitDelay() time.Duration {
return db.autoSubmitDelay
}
func (db *DataBinder) SetAutoSubmitDelay(delay time.Duration) {
db.autoSubmitDelay = delay
}
func (db *DataBinder) AutoSubmitSuspended() bool {
return db.autoSubmitSuspended
}
func (db *DataBinder) SetAutoSubmitSuspended(suspended bool) {
if suspended == db.autoSubmitSuspended {
return
}
db.autoSubmitSuspended = suspended
if suspended {
if db.autoSubmitTimer != nil {
db.autoSubmitTimer.Stop()
}
} else {
db.Submit()
}
}
func (db *DataBinder) Submitted() *Event {
return db.submittedPublisher.Event()
}
func (db *DataBinder) DataSource() interface{} {
return db.dataSource
}
func (db *DataBinder) SetDataSource(dataSource interface{}) error {
if kind := reflect.ValueOf(dataSource).Kind(); kind != reflect.Func && kind != reflect.Map && kind != reflect.Slice &&
kind == reflect.ValueOf(db.dataSource).Kind() && dataSource == db.dataSource {
return nil
}
if dataSource != nil {
if t := reflect.TypeOf(dataSource); t.Kind() != reflect.Map && (t.Kind() != reflect.Ptr || t.Elem().Kind() != reflect.Struct) {
return newError("dataSource must be pointer to struct or map[string]interface{}")
}
}
db.dataSource = dataSource
db.dataSourceChangedPublisher.Publish()
return nil
}
type dataBinderRootExpression struct {
db *DataBinder
}
func (dbre *dataBinderRootExpression) Value() interface{} {
return dbre.db.dataSource
}
func (dbre *dataBinderRootExpression) Changed() *Event {
return dbre.db.resetPublisher.Event()
}
func (db *DataBinder) DataSourceChanged() *Event {
return db.dataSourceChangedPublisher.Event()
}
func (db *DataBinder) BoundWidgets() []Widget {
return db.boundWidgets
}
func (db *DataBinder) SetBoundWidgets(boundWidgets []Widget) {
for prop, handle := range db.property2ChangedHandle {
prop.Changed().Detach(handle)
}
db.boundWidgets = boundWidgets
db.property2Widget = make(map[Property]Widget)
db.property2ChangedHandle = make(map[Property]int)
for _, widget := range boundWidgets {
widget := widget
for _, prop := range widget.AsWindowBase().name2Property {
prop := prop
if _, ok := prop.Source().(string); !ok {
continue
}
db.properties = append(db.properties, prop)
db.property2Widget[prop] = widget
db.property2ChangedHandle[prop] = prop.Changed().Attach(func() {
db.dirty = true
if db.autoSubmit && !db.autoSubmitSuspended {
if db.autoSubmitDelay > 0 {
if db.autoSubmitTimer == nil {
db.autoSubmitTimer = time.AfterFunc(db.autoSubmitDelay, func() {
widget.Synchronize(func() {
db.Submit()
})
})
} else {
db.autoSubmitTimer.Reset(db.autoSubmitDelay)
}
} else {
v := reflect.ValueOf(db.dataSource)
field := db.fieldBoundToProperty(v, prop)
if field == nil {
return
}
if err := db.submitProperty(prop, field); err != nil {
return
}
db.submittedPublisher.Publish()
}
} else {
if !db.inReset {
db.validateProperties()
}
}
})
}
}
}
func (db *DataBinder) Expression(path string) Expression {
if db.path2Expression == nil {
db.path2Expression = make(map[string]Expression)
}
if prop, ok := db.path2Expression[path]; ok {
return prop
}
expr := NewReflectExpression(db.rootExpression, path)
db.path2Expression[path] = expr
return expr
}
func (db *DataBinder) validateProperties() {
var hasError bool
for _, prop := range db.properties {
validator := prop.Validator()
if validator == nil {
continue
}
err := validator.Validate(prop.Get())
if err != nil {
hasError = true
}
if db.errorPresenter != nil {
widget := db.property2Widget[prop]
db.errorPresenter.PresentError(err, widget)
}
}
if hasError == db.canSubmit {
db.canSubmit = !hasError
db.canSubmitChangedPublisher.Publish()
}
}
func (db *DataBinder) ErrorPresenter() ErrorPresenter {
return db.errorPresenter
}
func (db *DataBinder) SetErrorPresenter(ep ErrorPresenter) {
db.errorPresenter = ep
}
func (db *DataBinder) CanSubmit() bool {
return db.canSubmit
}
func (db *DataBinder) CanSubmitChanged() *Event {
return db.canSubmitChangedPublisher.Event()
}
func (db *DataBinder) Reset() error {
db.inReset = true
defer func() {
db.inReset = false
}()
if err := db.forEach(func(prop Property, field DataField) error {
if f64, ok := prop.Get().(float64); ok {
switch v := field.Get().(type) {
case float32:
f64 = float64(v)
case float64:
f64 = v
case int:
f64 = float64(v)
case int8:
f64 = float64(v)
case int16:
f64 = float64(v)
case int32:
f64 = float64(v)
case int64:
f64 = float64(v)
case uint:
f64 = float64(v)
case uint8:
f64 = float64(v)
case uint16:
f64 = float64(v)
case uint32:
f64 = float64(v)
case uint64:
f64 = float64(v)
case uintptr:
f64 = float64(v)
default:
return newError(fmt.Sprintf("Field '%s': Can't convert %T to float64.", prop.Source().(string), field.Get()))
}
if err := prop.Set(f64); err != nil {
return err
}
} else {
if err := prop.Set(field.Get()); err != nil {
return err
}
}
return nil
}); err != nil {
return err
}
db.validateProperties()
db.dirty = false
db.resetPublisher.Publish()
return nil
}
func (db *DataBinder) ResetFinished() *Event {
return db.resetPublisher.Event()
}
func (db *DataBinder) Submit() error {
if !db.CanSubmit() {
return errValidationFailed
}
if err := db.forEach(func(prop Property, field DataField) error {
return db.submitProperty(prop, field)
}); err != nil {
return err
}
db.dirty = false
db.submittedPublisher.Publish()
return nil
}
func (db *DataBinder) Dirty() bool {
return db.dirty
}
func (db *DataBinder) submitProperty(prop Property, field DataField) error {
if !field.CanSet() {
// FIXME: handle properly
return nil
}
value := prop.Get()
if value == nil {
if _, ok := db.property2Widget[prop].(*RadioButton); ok {
return nil
}
return field.Set(field.Zero())
}
if err, ok := value.(error); ok {
return err
}
return field.Set(value)
}
func (db *DataBinder) forEach(f func(prop Property, field DataField) error) error {
dsv := reflect.ValueOf(db.dataSource)
if dsv.Kind() == reflect.Ptr && dsv.IsNil() {
return nil
}
for _, prop := range db.properties {
// if widget := db.property2Widget[prop]; !widget.Visible() {
// continue
// }
field := db.fieldBoundToProperty(dsv, prop)
if field == nil {
continue
}
if err := f(prop, field); err != nil {
return err
}
}
return nil
}
func (db *DataBinder) fieldBoundToProperty(v reflect.Value, prop Property) DataField {
if db.dataSource == nil {
return nilField{prop: prop}
}
source, ok := prop.Source().(string)
if !ok || source == "" {
return nil
}
f, err := dataFieldFromPath(v, source)
if err != nil {
panic(fmt.Sprintf("invalid source '%s'", source))
}
return f
}
func validateBindingMemberSyntax(member string) error {
// FIXME
return nil
}
type DataField interface {
CanSet() bool
Get() interface{}
Set(interface{}) error
Zero() interface{}
}
func dataFieldFromPath(root reflect.Value, path string) (DataField, error) {
parent, value, err := reflectValueFromPath(root, path)
if err != nil {
return nil, err
}
// convert to DataField
if i, ok := value.Interface().(DataField); ok {
return i, nil
}
return &reflectField{parent: parent, value: value, key: path[strings.LastIndexByte(path, '.')+1:]}, nil
}
func reflectValueFromPath(root reflect.Value, path string) (parent, value reflect.Value, err error) {
fullPath := path
value = root
for path != "" {
var name string
name, path = nextPathPart(path)
var p reflect.Value
for value.Kind() == reflect.Interface || value.Kind() == reflect.Ptr {
p = value
value = value.Elem()
}
switch value.Kind() {
case reflect.Map:
parent = value
value = value.MapIndex(reflect.ValueOf(name))
case reflect.Struct:
parent = value
var fun reflect.Value
// Try as field first.
if f := value.FieldByName(name); f.IsValid() {
switch f.Kind() {
case reflect.Func:
fun = f
case reflect.Interface:
if fn := f.Elem(); fn.Kind() == reflect.Func {
fun = fn
} else {
value = f
}
default:
value = f
}
} else {
// No field, so let's see if we got a method.
if p.IsValid() {
// Try pointer receiver first.
fun = p.MethodByName(name)
}
if !fun.IsValid() {
// No pointer, try directly.
fun = value.MethodByName(name)
}
if !fun.IsValid() {
return parent, value, fmt.Errorf("bad member: '%s', path: '%s'", path, fullPath)
}
}
if fun.IsValid() {
// We assume it takes no args and returns one mandatory value plus
// maybe an error.
rvs := fun.Call(nil)
switch len(rvs) {
case 1:
value = rvs[0]
case 2:
rv2 := rvs[1].Interface()
if err, ok := rv2.(error); ok {
return parent, value, err
} else if rv2 != nil {
return parent, value, fmt.Errorf("Second method return value must implement error.")
}
value = rvs[0]
default:
return parent, value, fmt.Errorf("Method must return a value plus optionally an error: %s", name)
}
}
}
}
return parent, value, nil
}
func nextPathPart(p string) (next, remaining string) {
for i, r := range p {
if r == '.' {
return p[:i], p[i+1:]
}
}
return p, ""
}
type nilField struct {
prop Property
}
func (nilField) CanSet() bool {
return false
}
func (f nilField) Get() interface{} {
return f.Zero()
}
func (nilField) Set(interface{}) error {
return nil
}
func (f nilField) Zero() interface{} {
return reflect.Zero(reflect.TypeOf(f.prop.Get())).Interface()
}
type reflectField struct {
parent reflect.Value
value reflect.Value
key string
}
func (f *reflectField) CanSet() bool {
if f.parent.IsValid() && f.parent.Kind() == reflect.Map {
return true
}
return f.value.CanSet()
}
func (f *reflectField) Get() interface{} {
return f.value.Interface()
}
func (f *reflectField) Set(value interface{}) error {
if f.parent.IsValid() && f.parent.Kind() == reflect.Map {
f.parent.SetMapIndex(reflect.ValueOf(f.key), reflect.ValueOf(value))
return nil
}
if f64, ok := value.(float64); ok {
switch f.value.Kind() {
case reflect.Float32, reflect.Float64:
f.value.SetFloat(f64)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
f.value.SetInt(int64(f64))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
f.value.SetUint(uint64(f64))
default:
return newError(fmt.Sprintf("Can't convert float64 to %s.", f.value.Type().Name()))
}
return nil
}
f.value.Set(reflect.ValueOf(value))
return nil
}
func (f *reflectField) Zero() interface{} {
return reflect.Zero(f.value.Type()).Interface()
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/wmdng/walk.git
git@gitee.com:wmdng/walk.git
wmdng
walk
walk
9fd96a6317b5

搜索帮助