1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * collection.cpp: different types of collections
5 * Copyright 2007 Novell, Inc. (http://www.novell.com)
7 * See the LICENSE file included with the distribution for details.
17 #include "collection.h"
19 #include "transform.h"
20 #include "frameworkelement.h"
21 #include "namescope.h"
22 #include "textblock.h"
25 #include "deployment.h"
26 #include "multiscalesubimage.h"
32 Collection::Collection ()
34 SetObjectType (Type::COLLECTION
);
35 array
= g_ptr_array_new ();
40 Collection::CloneCore (Types
* types
, DependencyObject
* fromObj
)
42 DependencyObject::CloneCore (types
, fromObj
);
44 Collection
*c
= (Collection
*)fromObj
;
46 for (guint i
= 0; i
< c
->array
->len
; i
++) {
47 Value
*value
= Value::Clone ((Value
*) c
->array
->pdata
[i
]);
53 Collection::~Collection ()
55 g_ptr_array_free (array
, true);
59 Collection::Dispose ()
63 for (guint i
= 0; i
< array
->len
; i
++) {
64 value
= (Value
*) array
->pdata
[i
];
65 RemovedFromCollection (value
);
68 g_ptr_array_set_size (array
, 0);
70 DependencyObject::Dispose ();
74 Collection::GetIterator ()
76 return new CollectionIterator (this);
80 Collection::Add (Value
*value
)
83 return AddWithError (value
, &error
);
87 Collection::Add (Value value
)
93 Collection::AddWithError (Value
*value
, MoonError
*error
)
95 bool rv
= InsertWithError (array
->len
, value
, error
);
96 return rv
? array
->len
- 1 : -1;
102 EmitChanged (CollectionChangedActionClearing
, NULL
, NULL
, -1);
104 guint len
= array
->len
;
105 Value
** vals
= new Value
*[len
];
106 memmove (vals
, array
->pdata
, len
* sizeof(Value
*));
108 g_ptr_array_set_size (array
, 0);
113 for (guint i
= 0; i
< len
; i
++) {
114 RemovedFromCollection (vals
[i
]);
119 EmitChanged (CollectionChangedActionCleared
, NULL
, NULL
, -1);
125 Collection::Contains (Value
*value
)
127 return IndexOf (value
) != -1;
131 Collection::IndexOf (Value
*value
)
135 for (guint i
= 0; i
< array
->len
; i
++) {
136 v
= (Value
*) array
->pdata
[i
];
145 Collection::Insert (int index
, Value value
)
147 return Insert (index
, &value
);
151 Collection::InsertWithError (int index
, Value
*value
, MoonError
*error
)
155 // Check that the item can be added to our collection
163 int count
= GetCount ();
167 added
= new Value (*value
);
169 if (AddedToCollection (added
, error
)) {
170 g_ptr_array_insert (array
, index
, added
);
172 SetCount ((int) array
->len
);
174 Value
*added_copy
= new Value (*added
);
176 EmitChanged (CollectionChangedActionAdd
, added_copy
, NULL
, index
);
189 Collection::Insert (int index
, Value
*value
)
192 return InsertWithError (index
, value
, &error
);
196 Collection::Remove (Value value
)
198 return Remove (&value
);
202 Collection::Remove (Value
*value
)
206 if ((index
= IndexOf (value
)) == -1)
209 return RemoveAt (index
);
213 Collection::RemoveAt (int index
)
218 if (index
< 0 || (guint
) index
>= array
->len
)
221 value
= (Value
*) array
->pdata
[index
];
223 g_ptr_array_remove_index (array
, index
);
224 SetCount ((int) array
->len
);
227 RemovedFromCollection (value
);
229 EmitChanged (CollectionChangedActionRemove
, NULL
, value
, index
);
237 Collection::RemoveAtWithError (int index
, MoonError
*error
)
240 if (index
< 0 || (guint
) index
>= array
->len
) {
241 MoonError::FillIn (error
, MoonError::ARGUMENT_OUT_OF_RANGE
, "");
245 return RemoveAt (index
);
249 Collection::GetValueAt (int index
)
251 if (index
< 0 || (guint
) index
>= array
->len
)
254 return (Value
*) array
->pdata
[index
];
258 Collection::GetValueAtWithError (int index
, MoonError
*error
)
260 // check array bounds
261 if (index
< 0 || (guint
) index
>= array
->len
) {
262 MoonError::FillIn (error
, MoonError::ARGUMENT_OUT_OF_RANGE
, "");
266 return GetValueAt (index
);
270 Collection::SetValueAt (int index
, Value
*value
)
273 return SetValueAtWithError (index
, value
, &error
);
277 Collection::SetValueAtWithError (int index
, Value
*value
, MoonError
*error
)
279 Value
*added
, *removed
;
281 // Check that the value can be added to our collection
282 if (!CanAdd (value
)) {
283 MoonError::FillIn (error
, MoonError::ARGUMENT
, "");
287 // check array bounds
288 if (index
< 0 || (guint
) index
>= array
->len
) {
289 MoonError::FillIn (error
, MoonError::ARGUMENT_OUT_OF_RANGE
, "");
293 removed
= (Value
*) array
->pdata
[index
];
294 added
= new Value (*value
);
296 if (AddedToCollection (added
, error
)) {
297 array
->pdata
[index
] = added
;
299 RemovedFromCollection (removed
);
301 EmitChanged (CollectionChangedActionReplace
, added
, removed
, index
);
312 Collection::EmitChanged (CollectionChangedAction action
, Value
*new_value
, Value
*old_value
, int index
)
314 Emit (Collection::ChangedEvent
, new CollectionChangedEventArgs (action
, new_value
, old_value
, index
));
318 Collection::EmitItemChanged (DependencyObject
*object
, DependencyProperty
*property
, Value
*newValue
, Value
*oldValue
)
320 Emit (Collection::ItemChangedEvent
, new CollectionItemChangedEventArgs (object
, property
, oldValue
, newValue
));
324 Collection::CanAdd (Value
*value
)
326 return value
->Is (GetElementType ());
331 // DependencyObjectCollection
334 DependencyObjectCollection::DependencyObjectCollection ()
336 SetObjectType (Type::DEPENDENCY_OBJECT_COLLECTION
);
339 DependencyObjectCollection::~DependencyObjectCollection ()
344 DependencyObjectCollection::AddedToCollection (Value
*value
, MoonError
*error
)
346 DependencyObject
*obj
= value
->AsDependencyObject ();
348 DependencyObject
*parent
= obj
->GetParent();
350 // Call SetSurface() /before/ setting the logical parent
351 // because Storyboard::SetSurface() needs to be able to
352 // distinguish between the two cases.
353 obj
->SetSurface (GetSurface ());
356 if (parent
->Is(Type::COLLECTION
) && !obj
->PermitsMultipleParents ()) {
357 MoonError::FillIn (error
, MoonError::INVALID_OPERATION
, "Element is already a child of another element.");
362 obj
->SetParent (this, error
);
367 obj
->AddPropertyChangeListener (this);
369 return Collection::AddedToCollection (value
, error
);
373 DependencyObjectCollection::RemovedFromCollection (Value
*value
)
375 DependencyObject
*obj
= value
->AsDependencyObject ();
377 obj
->RemovePropertyChangeListener (this);
378 obj
->SetParent (NULL
, NULL
);
379 obj
->SetSurface (NULL
);
381 Collection::RemovedFromCollection (value
);
385 DependencyObjectCollection::SetSurface (Surface
*surface
)
387 if (GetSurface() == surface
)
390 DependencyObject
*obj
;
393 for (guint i
= 0; i
< array
->len
; i
++) {
394 value
= (Value
*) array
->pdata
[i
];
395 obj
= value
->AsDependencyObject ();
396 obj
->SetSurface (surface
);
399 Collection::SetSurface (surface
);
403 DependencyObjectCollection::OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
)
405 EmitItemChanged (obj
, subobj_args
->GetProperty(), subobj_args
->GetNewValue(), subobj_args
->GetOldValue());
409 DependencyObjectCollection::UnregisterAllNamesRootedAt (NameScope
*from_ns
)
411 DependencyObject
*obj
;
414 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
415 for (guint i
= 0; i
< array
->len
; i
++) {
416 value
= (Value
*) array
->pdata
[i
];
417 obj
= value
->AsDependencyObject (types
);
418 obj
->UnregisterAllNamesRootedAt (from_ns
);
421 Collection::UnregisterAllNamesRootedAt (from_ns
);
425 DependencyObjectCollection::RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
)
427 DependencyObject
*obj
;
430 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
431 for (guint i
= 0; i
< array
->len
; i
++) {
435 value
= (Value
*) array
->pdata
[i
];
436 obj
= value
->AsDependencyObject (types
);
437 obj
->RegisterAllNamesRootedAt (to_ns
, error
);
440 Collection::RegisterAllNamesRootedAt (to_ns
, error
);
447 InlineCollection::InlineCollection ()
449 SetObjectType (Type::INLINE_COLLECTION
);
452 InlineCollection::~InlineCollection ()
457 InlineCollection::Equals (InlineCollection
*inlines
)
461 if (inlines
->array
->len
!= array
->len
)
464 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
465 for (guint i
= 0; i
< array
->len
; i
++) {
466 run1
= ((Value
*) inlines
->array
->pdata
[i
])->AsInline (types
);
467 run0
= ((Value
*) array
->pdata
[i
])->AsInline (types
);
469 if (!run0
->Equals (run1
))
478 // UIElementCollection
481 UIElementCollection::UIElementCollection ()
483 SetObjectType (Type::UIELEMENT_COLLECTION
);
484 z_sorted
= g_ptr_array_new ();
487 UIElementCollection::~UIElementCollection ()
489 g_ptr_array_free (z_sorted
, true);
493 UIElementZIndexComparer (gconstpointer ui1
, gconstpointer ui2
)
495 int z1
= Canvas::GetZIndex (*((UIElement
**) ui1
));
496 int z2
= Canvas::GetZIndex (*((UIElement
**) ui2
));
502 UIElementCollection::ResortByZIndex ()
504 g_ptr_array_set_size (z_sorted
, array
->len
);
509 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
510 for (guint i
= 0; i
< array
->len
; i
++)
511 z_sorted
->pdata
[i
] = ((Value
*) array
->pdata
[i
])->AsUIElement (types
);
514 g_ptr_array_sort (z_sorted
, UIElementZIndexComparer
);
518 UIElementCollection::Clear ()
520 g_ptr_array_set_size (z_sorted
, 0);
521 return DependencyObjectCollection::Clear ();
528 HitTestCollection::HitTestCollection ()
536 DoubleCollection::DoubleCollection ()
538 SetObjectType (Type::DOUBLE_COLLECTION
);
541 DoubleCollection::~DoubleCollection ()
546 DoubleCollection::FromStr (const char *s
)
548 GArray
*values
= double_garray_from_str (s
, 0);
550 if (values
->len
== 0) {
551 g_array_free (values
, true);
555 DoubleCollection
*doubles
= new DoubleCollection ();
556 for (guint i
= 0; i
< values
->len
; i
++)
557 doubles
->Add (Value (g_array_index (values
, double, i
)));
558 g_array_free (values
, true);
567 PointCollection::PointCollection ()
569 SetObjectType (Type::POINT_COLLECTION
);
572 PointCollection::~PointCollection ()
577 PointCollection::FromStr (const char *s
)
580 GArray
*values
= double_garray_from_str (s
, 0);
583 if (n
== 0 || n
% 1 == 1) {
584 g_array_free (values
, true);
588 PointCollection
*points
= new PointCollection();
589 for (i
= 0, j
= 0; j
< n
; j
++) {
590 double x
= g_array_index (values
, double, i
++);
591 double y
= g_array_index (values
, double, i
++);
593 points
->Add (Point (x
, y
));
596 g_array_free (values
, true);
604 ItemCollection::ItemCollection ()
606 SetObjectType (Type::ITEM_COLLECTION
);
609 ItemCollection::~ItemCollection ()
614 // Trigger Collection
617 TriggerCollection::TriggerCollection ()
619 SetObjectType (Type::TRIGGER_COLLECTION
);
622 TriggerCollection::~TriggerCollection ()
627 // TriggerAction Collection
630 TriggerActionCollection::TriggerActionCollection ()
632 SetObjectType (Type::TRIGGERACTION_COLLECTION
);
635 TriggerActionCollection::~TriggerActionCollection ()
640 // MultiScaleSubImage Collection
642 MultiScaleSubImageCollection::MultiScaleSubImageCollection ()
644 SetObjectType (Type::MULTISCALESUBIMAGE_COLLECTION
);
645 z_sorted
= g_ptr_array_new ();
648 MultiScaleSubImageCollection::~MultiScaleSubImageCollection ()
650 g_ptr_array_free (z_sorted
, true);
654 MultiScaleSubImageZIndexComparer (gconstpointer msisi1
, gconstpointer msisi2
)
656 int z1
= (*((MultiScaleSubImage
**)msisi1
))->GetZIndex ();
657 int z2
= (*((MultiScaleSubImage
**)msisi2
))->GetZIndex ();
663 MultiScaleSubImageCollection::ResortByZIndex ()
665 g_ptr_array_set_size (z_sorted
, array
->len
);
670 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
671 for (guint i
= 0; i
< array
->len
; i
++)
672 z_sorted
->pdata
[i
] = ((Value
*) array
->pdata
[i
])->AsMultiScaleSubImage (types
);
675 g_ptr_array_sort (z_sorted
, MultiScaleSubImageZIndexComparer
);
679 MultiScaleSubImageCollection::Clear ()
681 g_ptr_array_set_size (z_sorted
, 0);
682 return DependencyObjectCollection::Clear ();
686 // ResourceDictionaryCollection
689 ResourceDictionaryCollection::ResourceDictionaryCollection ()
691 SetObjectType (Type::RESOURCE_DICTIONARY_COLLECTION
);
694 ResourceDictionaryCollection::~ResourceDictionaryCollection ()
699 // CollectionIterator
702 CollectionIterator::CollectionIterator (Collection
*c
)
704 generation
= c
->Generation ();
710 CollectionIterator::~CollectionIterator ()
712 collection
->unref ();
716 CollectionIterator::Next ()
718 if (generation
!= collection
->Generation ())
723 if (index
>= collection
->GetCount ())
730 CollectionIterator::Reset()
732 if (generation
!= collection
->Generation ())
741 CollectionIterator::GetCurrent (int *error
)
743 if (generation
!= collection
->Generation ()) {
755 return collection
->GetValueAt (index
);
759 CollectionIterator::Destroy (CollectionIterator
*iterator
)
769 VisualTreeWalker::VisualTreeWalker (UIElement
*obj
, VisualTreeWalkerDirection dir
, Types
*cached
)
773 content
= obj
->GetSubtreeObject ();
775 types
= (cached
== NULL
) ? Deployment::GetCurrent ()->GetTypes () : cached
;
777 if (content
!= NULL
) {
778 if (types
->IsSubclassOf (content
->GetObjectType (), Type::COLLECTION
)) {
779 collection
= (Collection
*)content
;
781 if (!types
->IsSubclassOf (content
->GetObjectType (), Type::UIELEMENT_COLLECTION
))
790 VisualTreeWalker::Step ()
792 UIElement
*result
= NULL
;
795 UIElementCollection
*uiecollection
= NULL
;
798 if (direction
!= Logical
) {
799 uiecollection
= (UIElementCollection
*)collection
;
801 if (count
< 0 || index
>= count
)
804 if (count
== 1 && index
== 0) {
806 return collection
->GetValueAt (0)->AsUIElement(types
);
809 if ((int)uiecollection
->z_sorted
->len
!= count
) {
810 g_warning ("VisualTreeWalker: unexpectedly got an unsorted UIElementCollection");
811 uiecollection
->ResortByZIndex ();
817 result
= (UIElement
*)uiecollection
->z_sorted
->pdata
[index
];
820 result
= (UIElement
*)uiecollection
->z_sorted
->pdata
[count
- (index
+ 1)];
823 Value
*v
= collection
->GetValueAt (index
);
824 result
= v
== NULL
? NULL
: v
->AsUIElement (types
);
831 result
= (UIElement
*)content
;
841 VisualTreeWalker::GetCount ()
849 return collection
->GetCount ();
852 VisualTreeWalker::~VisualTreeWalker()
859 class UnsafeUIElementNode
: public List::Node
{
861 UIElement
*uielement
;
863 UnsafeUIElementNode (UIElement
*el
) { uielement
= el
; }
866 DeepTreeWalker::DeepTreeWalker (UIElement
*top
, Types
*types
)
868 walk_list
= new List ();
869 walk_list
->Append (new UnsafeUIElementNode (top
));
871 this->types
= types
? types
: Deployment::GetCurrent ()->GetTypes ();
875 DeepTreeWalker::Step ()
878 VisualTreeWalker
walker (last
, Logical
, types
);
879 //VisualTreeWalker walker (last, ZForward, types);
880 UnsafeUIElementNode
*prepend
= (UnsafeUIElementNode
*) walk_list
->First ();
881 while (UIElement
*child
= walker
.Step ())
882 walk_list
->InsertBefore (new UnsafeUIElementNode (child
), prepend
);
885 UnsafeUIElementNode
*next
= (UnsafeUIElementNode
*)walk_list
->First ();
892 UIElement
*current
= next
->uielement
;
893 walk_list
->Unlink (next
);
901 DeepTreeWalker::SkipBranch ()
906 DeepTreeWalker::~DeepTreeWalker ()
915 collection_new (Type::Kind kind
)
917 Type
*t
= Type::Find (kind
);
919 if (!t
->IsSubclassOf (Type::COLLECTION
)) {
920 g_warning ("create_collection passed non-collection type");
924 return (Collection
*) t
->CreateInstance();