// 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() }