Skip to content

Commit

Permalink
Handle list properties as *List with Slice method.
Browse files Browse the repository at this point in the history
This prepares the ground for the future support
of QML list manipulations without API breakage.
  • Loading branch information
niemeyer committed Nov 21, 2013
1 parent a9e1495 commit fe2a8f2
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 15 deletions.
1 change: 1 addition & 0 deletions all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,7 @@ var tests = []struct {
d.Assert(states[0].String("name"), Equals, "on")
d.Assert(states[1].String("name"), Equals, "off")
d.Assert(len(states), Equals, 2)
d.Assert(d.root.Property("states").(*qml.List).Len(), Equals, 2)
},
},
{
Expand Down
12 changes: 6 additions & 6 deletions bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ func hookGoValueWriteField(enginep, foldp unsafe.Pointer, reflectIndex, onChange
}
}

var ifaceSliceType = reflect.TypeOf([]interface{}(nil))
var listType = reflect.TypeOf(&List{})

func convertAndSet(to, from reflect.Value) {
defer func() {
Expand All @@ -364,12 +364,12 @@ func convertAndSet(to, from reflect.Value) {
fromType := from.Type()
if toType == fromType {
to.Set(from)
} else if fromType == ifaceSliceType && to.Kind() == reflect.Slice {
len := from.Len()
to.Set(reflect.MakeSlice(toType, len, len))
} else if fromType == listType && to.Kind() == reflect.Slice {
list := from.Interface().(*List)
to.Set(reflect.MakeSlice(toType, len(list.data), len(list.data)))
elemType := toType.Elem()
for i := 0; i < len; i++ {
to.Index(i).Set(from.Index(i).Elem().Convert(elemType))
for i, elem := range list.data {
to.Index(i).Set(reflect.ValueOf(elem).Convert(elemType))
}
} else {
to.Set(from.Convert(toType))
Expand Down
2 changes: 1 addition & 1 deletion datatype.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ func unpackDataValue(dvalue *C.DataValue, engine *Engine) interface{} {
result[i] = unpackDataValue(&dvlist[i], engine)
}
C.free(*(*unsafe.Pointer)(datap))
return result
return &List{result}
}
panic(fmt.Sprintf("unsupported data type: %d", dvalue.dataType))
}
Expand Down
38 changes: 30 additions & 8 deletions qml.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,31 @@ type Object interface {
On(signal string, function interface{})
}

// List holds a QML list.
type List struct {
// In the future this will be able to hold a reference to QML-owned
// lists, so they can be mutated.
data []interface{}
}

// Len returns the number of elements in the list.
func (list *List) Len() int {
return len(list.data)
}

// Slice allocates a new slice and copies the list content into it,
// performing type conversions as possible, and then assigns the result
// to the slice pointed to by sliceAddr.
// Slice panics if the list values are not compatible with the
// provided slice.
func (list *List) Slice(sliceAddr interface{}) {
toPtr := reflect.ValueOf(sliceAddr)
if toPtr.Kind() != reflect.Ptr || toPtr.Type().Elem().Kind() != reflect.Slice {
panic(fmt.Sprintf("Slice got a sliceAddr parameter that is not a slice address: %#v", sliceAddr))
}
convertAndSet(toPtr.Elem(), reflect.ValueOf(list))
}

// Common implements the common behavior of all QML objects.
// It implements the Object interface.
type Common struct {
Expand Down Expand Up @@ -524,15 +549,12 @@ func (obj *Common) Object(property string) Object {
// assigns the result to the slice pointed to by sliceAddr.
// Slice panics if the property value is not a list with proper values.
func (obj *Common) Slice(property string, sliceAddr interface{}) {
toPtr := reflect.ValueOf(sliceAddr)
if toPtr.Kind() != reflect.Ptr || toPtr.Type().Elem().Kind() != reflect.Slice {
panic(fmt.Sprintf("Slice got a sliceAddr parameter that is not a slice address: %#v", sliceAddr))
}
from := reflect.ValueOf(obj.Property(property))
if from.Kind() != reflect.Slice {
panic(fmt.Sprintf("value of property %q is not a slice: %#v", property, from.Interface()))
value := obj.Property(property)
list, ok := value.(*List)
if !ok {
panic(fmt.Sprintf("value of property %q is not a QML list: %#v", property, value))
}
convertAndSet(toPtr.Elem(), from)
list.Slice(sliceAddr)
}

// ObjectByName returns the Object value of the descendant object that
Expand Down

0 comments on commit fe2a8f2

Please sign in to comment.