421 lines
8.7 KiB
Go
421 lines
8.7 KiB
Go
// Copyright 2013 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 (
|
|
"fmt"
|
|
"reflect"
|
|
"sort"
|
|
)
|
|
|
|
type reflectModel interface {
|
|
Items() interface{}
|
|
}
|
|
|
|
type bindingAndDisplayMemberSetter interface {
|
|
setBindingMember(member string)
|
|
setDisplayMember(member string)
|
|
}
|
|
|
|
type reflectListModel struct {
|
|
ListModelBase
|
|
bindingMember string
|
|
displayMember string
|
|
dataSource interface{}
|
|
items interface{}
|
|
value reflect.Value
|
|
}
|
|
|
|
func newReflectListModel(dataSource interface{}) (ListModel, error) {
|
|
items, err := itemsFromReflectModelDataSource(dataSource, "ReflectListModel")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m := &reflectListModel{
|
|
dataSource: dataSource,
|
|
items: items,
|
|
value: reflect.ValueOf(items),
|
|
}
|
|
|
|
if rlm, ok := dataSource.(ReflectListModel); ok {
|
|
rlm.setValueFunc(func(index int) interface{} {
|
|
return m.Value(index)
|
|
})
|
|
|
|
rlm.ItemChanged().Attach(func(index int) {
|
|
m.PublishItemChanged(index)
|
|
})
|
|
|
|
rlm.ItemsReset().Attach(func() {
|
|
m.items = rlm.Items()
|
|
m.value = reflect.ValueOf(m.items)
|
|
|
|
m.PublishItemsReset()
|
|
})
|
|
|
|
rlm.ItemsInserted().Attach(func(from, to int) {
|
|
m.items = rlm.Items()
|
|
m.value = reflect.ValueOf(m.items)
|
|
|
|
m.PublishItemsInserted(from, to)
|
|
})
|
|
|
|
rlm.ItemsRemoved().Attach(func(from, to int) {
|
|
m.items = rlm.Items()
|
|
m.value = reflect.ValueOf(m.items)
|
|
|
|
m.PublishItemsRemoved(from, to)
|
|
})
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func (m *reflectListModel) setBindingMember(member string) {
|
|
m.bindingMember = member
|
|
}
|
|
|
|
func (m *reflectListModel) setDisplayMember(member string) {
|
|
m.displayMember = member
|
|
}
|
|
|
|
func (m *reflectListModel) ItemCount() int {
|
|
return m.value.Len()
|
|
}
|
|
|
|
func (m *reflectListModel) BindingValue(index int) interface{} {
|
|
return valueFromSlice(m.dataSource, m.value, m.bindingMember, index)
|
|
}
|
|
|
|
func (m *reflectListModel) Value(index int) interface{} {
|
|
return valueFromSlice(m.dataSource, m.value, m.displayMember, index)
|
|
}
|
|
|
|
type lessFuncsSetter interface {
|
|
setLessFuncs(lessFuncs []func(i, j int) bool)
|
|
}
|
|
|
|
type dataMembersSetter interface {
|
|
setDataMembers(dataMembers []string)
|
|
}
|
|
|
|
type reflectTableModel struct {
|
|
TableModelBase
|
|
sorterBase *SorterBase
|
|
lessFuncs []func(i, j int) bool
|
|
dataMembers []string
|
|
dataSource interface{}
|
|
items interface{}
|
|
value reflect.Value
|
|
}
|
|
|
|
func newReflectTableModel(dataSource interface{}) (TableModel, error) {
|
|
items, err := itemsFromReflectModelDataSource(dataSource, "ReflectTableModel")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m := &reflectTableModel{
|
|
dataSource: dataSource,
|
|
items: items,
|
|
value: reflect.ValueOf(items),
|
|
}
|
|
|
|
if rtm, ok := dataSource.(ReflectTableModel); ok {
|
|
rtm.setValueFunc(func(row, col int) interface{} {
|
|
return m.Value(row, col)
|
|
})
|
|
|
|
rtm.RowChanged().Attach(func(index int) {
|
|
m.PublishRowChanged(index)
|
|
})
|
|
|
|
rtm.RowsReset().Attach(func() {
|
|
m.items = rtm.Items()
|
|
m.value = reflect.ValueOf(m.items)
|
|
|
|
m.PublishRowsReset()
|
|
|
|
if is, ok := dataSource.(interceptedSorter); ok {
|
|
sb := is.sorterBase()
|
|
m.sort(sb.SortedColumn(), sb.SortOrder())
|
|
}
|
|
})
|
|
|
|
rtm.RowsChanged().Attach(func(from, to int) {
|
|
m.PublishRowsChanged(from, to)
|
|
})
|
|
|
|
rtm.RowsInserted().Attach(func(from, to int) {
|
|
m.items = rtm.Items()
|
|
m.value = reflect.ValueOf(m.items)
|
|
|
|
m.PublishRowsInserted(from, to)
|
|
})
|
|
|
|
rtm.RowsRemoved().Attach(func(from, to int) {
|
|
m.items = rtm.Items()
|
|
m.value = reflect.ValueOf(m.items)
|
|
|
|
m.PublishRowsRemoved(from, to)
|
|
})
|
|
} else {
|
|
m.sorterBase = new(SorterBase)
|
|
}
|
|
|
|
if is, ok := dataSource.(interceptedSorter); ok {
|
|
m.sorterBase = is.sorterBase()
|
|
is.setSortFunc(func(col int, order SortOrder) error {
|
|
return m.sort(col, order)
|
|
})
|
|
}
|
|
|
|
_, isImageProvider := dataSource.(ImageProvider)
|
|
_, isSortable := dataSource.(Sorter)
|
|
if !isSortable {
|
|
isSortable = m.sorterBase != nil
|
|
}
|
|
if isImageProvider {
|
|
if isSortable {
|
|
return &sortedImageReflectTableModel{reflectTableModel: m}, nil
|
|
} else {
|
|
return &imageReflectTableModel{reflectTableModel: m}, nil
|
|
}
|
|
} else if isSortable {
|
|
return &sortedReflectTableModel{reflectTableModel: m}, nil
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
func (m *reflectTableModel) setLessFuncs(lessFuncs []func(i, j int) bool) {
|
|
m.lessFuncs = lessFuncs
|
|
}
|
|
|
|
func (m *reflectTableModel) setDataMembers(dataMembers []string) {
|
|
m.dataMembers = dataMembers
|
|
}
|
|
|
|
func (m *reflectTableModel) RowCount() int {
|
|
return m.value.Len()
|
|
}
|
|
|
|
func (m *reflectTableModel) Value(row, col int) interface{} {
|
|
return valueFromSlice(m.dataSource, m.value, m.dataMembers[col], row)
|
|
}
|
|
|
|
func (m *reflectTableModel) Checked(row int) bool {
|
|
if m.value.Index(row).IsNil() {
|
|
return false
|
|
}
|
|
|
|
if checker, ok := m.dataSource.(ItemChecker); ok {
|
|
return checker.Checked(row)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func (m *reflectTableModel) SetChecked(row int, checked bool) error {
|
|
if m.value.Index(row).IsNil() {
|
|
return nil
|
|
}
|
|
|
|
if checker, ok := m.dataSource.(ItemChecker); ok {
|
|
return checker.SetChecked(row, checked)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *reflectTableModel) ColumnSortable(col int) bool {
|
|
if sorter, ok := m.dataSource.(Sorter); ok {
|
|
return sorter.ColumnSortable(col)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (m *reflectTableModel) SortChanged() *Event {
|
|
if sorter, ok := m.dataSource.(Sorter); ok {
|
|
return sorter.SortChanged()
|
|
}
|
|
|
|
if m.sorterBase != nil {
|
|
return m.sorterBase.SortChanged()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *reflectTableModel) SortedColumn() int {
|
|
if sorter, ok := m.dataSource.(Sorter); ok {
|
|
return sorter.SortedColumn()
|
|
}
|
|
|
|
if m.sorterBase != nil {
|
|
return m.sorterBase.SortedColumn()
|
|
}
|
|
|
|
return -1
|
|
}
|
|
|
|
func (m *reflectTableModel) SortOrder() SortOrder {
|
|
if sorter, ok := m.dataSource.(Sorter); ok {
|
|
return sorter.SortOrder()
|
|
}
|
|
|
|
if m.sorterBase != nil {
|
|
return m.sorterBase.SortOrder()
|
|
}
|
|
|
|
return SortAscending
|
|
}
|
|
|
|
func (m *reflectTableModel) sort(col int, order SortOrder) error {
|
|
if sb := m.sorterBase; sb != nil {
|
|
sb.col, sb.order = col, order
|
|
|
|
sort.Stable(m)
|
|
|
|
sb.changedPublisher.Publish()
|
|
|
|
return nil
|
|
}
|
|
|
|
if sorter, ok := m.dataSource.(Sorter); ok {
|
|
return sorter.Sort(col, order)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (m *reflectTableModel) Len() int {
|
|
return m.RowCount()
|
|
}
|
|
|
|
func (m *reflectTableModel) Less(i, j int) bool {
|
|
col := m.SortedColumn()
|
|
|
|
if lt := m.lessFuncs[col]; lt != nil {
|
|
ls := lt(i, j)
|
|
|
|
if m.SortOrder() == SortAscending {
|
|
return ls
|
|
} else {
|
|
return !ls
|
|
}
|
|
}
|
|
|
|
return less(m.Value(i, col), m.Value(j, col), m.SortOrder())
|
|
}
|
|
|
|
func (m *reflectTableModel) Swap(i, j int) {
|
|
vi := m.value.Index(i)
|
|
vj := m.value.Index(j)
|
|
|
|
viv := vi.Interface()
|
|
vjv := vj.Interface()
|
|
|
|
vi.Set(reflect.ValueOf(vjv))
|
|
vj.Set(reflect.ValueOf(viv))
|
|
}
|
|
|
|
type imageReflectTableModel struct {
|
|
*reflectTableModel
|
|
}
|
|
|
|
func (m *imageReflectTableModel) Image(index int) interface{} {
|
|
if m.value.Index(index).IsNil() {
|
|
return nil
|
|
}
|
|
|
|
return m.dataSource.(ImageProvider).Image(index)
|
|
}
|
|
|
|
type sortedReflectTableModel struct {
|
|
*reflectTableModel
|
|
}
|
|
|
|
func (m *sortedReflectTableModel) Sort(col int, order SortOrder) error {
|
|
return m.reflectTableModel.sort(col, order)
|
|
}
|
|
|
|
type sortedImageReflectTableModel struct {
|
|
*reflectTableModel
|
|
}
|
|
|
|
func (m *sortedImageReflectTableModel) Sort(col int, order SortOrder) error {
|
|
return m.reflectTableModel.sort(col, order)
|
|
}
|
|
|
|
func (m *sortedImageReflectTableModel) Image(index int) interface{} {
|
|
if m.value.Index(index).IsNil() {
|
|
return nil
|
|
}
|
|
|
|
return m.dataSource.(ImageProvider).Image(index)
|
|
}
|
|
|
|
func itemsFromReflectModelDataSource(dataSource interface{}, requiredInterfaceName string) (interface{}, error) {
|
|
var items interface{}
|
|
if rm, ok := dataSource.(reflectModel); ok {
|
|
items = rm.Items()
|
|
} else {
|
|
items = dataSource
|
|
}
|
|
|
|
if requiredInterfaceName == "ReflectListModel" {
|
|
if _, ok := dataSource.([]string); ok {
|
|
return items, nil
|
|
}
|
|
}
|
|
|
|
if t := reflect.TypeOf(items); t != nil &&
|
|
t.Kind() == reflect.Slice &&
|
|
(t.Elem().Kind() == reflect.Struct ||
|
|
(t.Elem().Kind() == reflect.Interface || t.Elem().Kind() == reflect.Ptr) &&
|
|
t.Elem().Elem().Kind() == reflect.Struct) {
|
|
|
|
return items, nil
|
|
}
|
|
|
|
return nil, newError(fmt.Sprintf("dataSource must be a slice of struct or interface or pointer to struct or must implement %s.", requiredInterfaceName))
|
|
}
|
|
|
|
func valueFromSlice(dataSource interface{}, itemsValue reflect.Value, member string, index int) interface{} {
|
|
if member == "" {
|
|
if strs, ok := dataSource.([]string); ok {
|
|
return strs[index]
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
v := itemsValue.Index(index)
|
|
|
|
if v.Kind() == reflect.Ptr && v.IsNil() {
|
|
if populator, ok := dataSource.(Populator); ok {
|
|
if err := populator.Populate(index); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if v.IsNil() {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
_, vv, err := reflectValueFromPath(v, member)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return vv.Interface()
|
|
}
|