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 (GetDeployment (), 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 // Attach /before/ setting the logical parent
351 // because Storyboard::SetIsAttached () needs to be able to
352 // distinguish between the two cases.
353 obj
->SetIsAttached (IsAttached ());
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 bool rv
= Collection::AddedToCollection (value
, error
);
371 if (!rv
&& parent
== NULL
) {
372 /* If we set the parent, but the object wasn't added to the collection, make sure we clear the parent */
373 obj
->SetParent (NULL
, error
);
380 DependencyObjectCollection::RemovedFromCollection (Value
*value
)
382 DependencyObject
*obj
= value
->AsDependencyObject ();
384 obj
->RemovePropertyChangeListener (this);
385 obj
->SetParent (NULL
, NULL
);
386 obj
->SetIsAttached (false);
388 Collection::RemovedFromCollection (value
);
392 DependencyObjectCollection::SetIsAttached (bool attached
)
394 if (IsAttached () == attached
)
397 DependencyObject
*obj
;
400 for (guint i
= 0; i
< array
->len
; i
++) {
401 value
= (Value
*) array
->pdata
[i
];
402 obj
= value
->AsDependencyObject ();
403 obj
->SetIsAttached (attached
);
406 Collection::SetIsAttached (attached
);
410 DependencyObjectCollection::OnSubPropertyChanged (DependencyProperty
*prop
, DependencyObject
*obj
, PropertyChangedEventArgs
*subobj_args
)
412 EmitItemChanged (obj
, subobj_args
->GetProperty(), subobj_args
->GetNewValue(), subobj_args
->GetOldValue());
416 DependencyObjectCollection::UnregisterAllNamesRootedAt (NameScope
*from_ns
)
418 DependencyObject
*obj
;
421 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
422 for (guint i
= 0; i
< array
->len
; i
++) {
423 value
= (Value
*) array
->pdata
[i
];
424 obj
= value
->AsDependencyObject (types
);
425 obj
->UnregisterAllNamesRootedAt (from_ns
);
428 Collection::UnregisterAllNamesRootedAt (from_ns
);
432 DependencyObjectCollection::RegisterAllNamesRootedAt (NameScope
*to_ns
, MoonError
*error
)
434 DependencyObject
*obj
;
437 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
438 for (guint i
= 0; i
< array
->len
; i
++) {
442 value
= (Value
*) array
->pdata
[i
];
443 obj
= value
->AsDependencyObject (types
);
444 obj
->RegisterAllNamesRootedAt (to_ns
, error
);
447 Collection::RegisterAllNamesRootedAt (to_ns
, error
);
454 InlineCollection::InlineCollection ()
456 SetObjectType (Type::INLINE_COLLECTION
);
459 InlineCollection::~InlineCollection ()
464 InlineCollection::Equals (InlineCollection
*inlines
)
468 if (inlines
->array
->len
!= array
->len
)
471 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
472 for (guint i
= 0; i
< array
->len
; i
++) {
473 run1
= ((Value
*) inlines
->array
->pdata
[i
])->AsInline (types
);
474 run0
= ((Value
*) array
->pdata
[i
])->AsInline (types
);
476 if (!run0
->Equals (run1
))
485 // UIElementCollection
488 UIElementCollection::UIElementCollection ()
490 SetObjectType (Type::UIELEMENT_COLLECTION
);
491 z_sorted
= g_ptr_array_new ();
494 UIElementCollection::~UIElementCollection ()
496 g_ptr_array_free (z_sorted
, true);
500 UIElementZIndexComparer (gconstpointer ui1
, gconstpointer ui2
)
502 int z1
= Canvas::GetZIndex (*((UIElement
**) ui1
));
503 int z2
= Canvas::GetZIndex (*((UIElement
**) ui2
));
509 UIElementCollection::ResortByZIndex ()
511 g_ptr_array_set_size (z_sorted
, array
->len
);
516 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
517 for (guint i
= 0; i
< array
->len
; i
++)
518 z_sorted
->pdata
[i
] = ((Value
*) array
->pdata
[i
])->AsUIElement (types
);
521 g_ptr_array_sort (z_sorted
, UIElementZIndexComparer
);
525 UIElementCollection::Clear ()
527 g_ptr_array_set_size (z_sorted
, 0);
528 return DependencyObjectCollection::Clear ();
535 HitTestCollection::HitTestCollection ()
543 DoubleCollection::DoubleCollection ()
545 SetObjectType (Type::DOUBLE_COLLECTION
);
548 DoubleCollection::~DoubleCollection ()
553 DoubleCollection::FromStr (const char *s
)
555 GArray
*values
= double_garray_from_str (s
, 0);
557 if (values
->len
== 0) {
558 g_array_free (values
, true);
562 DoubleCollection
*doubles
= new DoubleCollection ();
563 for (guint i
= 0; i
< values
->len
; i
++)
564 doubles
->Add (Value (g_array_index (values
, double, i
)));
565 g_array_free (values
, true);
574 PointCollection::PointCollection ()
576 SetObjectType (Type::POINT_COLLECTION
);
579 PointCollection::~PointCollection ()
584 PointCollection::FromStr (const char *s
)
587 GArray
*values
= double_garray_from_str (s
, 0);
590 if (n
== 0 || n
% 1 == 1) {
591 g_array_free (values
, true);
595 PointCollection
*points
= new PointCollection();
596 for (i
= 0, j
= 0; j
< n
; j
++) {
597 double x
= g_array_index (values
, double, i
++);
598 double y
= g_array_index (values
, double, i
++);
600 points
->Add (Point (x
, y
));
603 g_array_free (values
, true);
611 ItemCollection::ItemCollection ()
613 SetObjectType (Type::ITEM_COLLECTION
);
616 ItemCollection::~ItemCollection ()
621 // Trigger Collection
624 TriggerCollection::TriggerCollection ()
626 SetObjectType (Type::TRIGGER_COLLECTION
);
629 TriggerCollection::~TriggerCollection ()
634 // TriggerAction Collection
637 TriggerActionCollection::TriggerActionCollection ()
639 SetObjectType (Type::TRIGGERACTION_COLLECTION
);
642 TriggerActionCollection::~TriggerActionCollection ()
647 // MultiScaleSubImage Collection
649 MultiScaleSubImageCollection::MultiScaleSubImageCollection ()
651 SetObjectType (Type::MULTISCALESUBIMAGE_COLLECTION
);
652 z_sorted
= g_ptr_array_new ();
655 MultiScaleSubImageCollection::~MultiScaleSubImageCollection ()
657 g_ptr_array_free (z_sorted
, true);
661 MultiScaleSubImageZIndexComparer (gconstpointer msisi1
, gconstpointer msisi2
)
663 int z1
= (*((MultiScaleSubImage
**)msisi1
))->GetZIndex ();
664 int z2
= (*((MultiScaleSubImage
**)msisi2
))->GetZIndex ();
670 MultiScaleSubImageCollection::ResortByZIndex ()
672 g_ptr_array_set_size (z_sorted
, array
->len
);
677 Types
*types
= Deployment::GetCurrent ()->GetTypes ();
678 for (guint i
= 0; i
< array
->len
; i
++)
679 z_sorted
->pdata
[i
] = ((Value
*) array
->pdata
[i
])->AsMultiScaleSubImage (types
);
682 g_ptr_array_sort (z_sorted
, MultiScaleSubImageZIndexComparer
);
686 MultiScaleSubImageCollection::Clear ()
688 g_ptr_array_set_size (z_sorted
, 0);
689 return DependencyObjectCollection::Clear ();
693 // ResourceDictionaryCollection
696 ResourceDictionaryCollection::ResourceDictionaryCollection ()
698 SetObjectType (Type::RESOURCE_DICTIONARY_COLLECTION
);
701 ResourceDictionaryCollection::~ResourceDictionaryCollection ()
706 // CollectionIterator
709 CollectionIterator::CollectionIterator (Collection
*c
)
711 generation
= c
->Generation ();
717 CollectionIterator::~CollectionIterator ()
719 collection
->unref ();
723 CollectionIterator::Next (MoonError
*err
)
725 if (generation
!= collection
->Generation ()) {
726 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "The underlying collection has mutated");
732 return index
< collection
->GetCount ();
736 CollectionIterator::Reset ()
738 if (generation
!= collection
->Generation ())
747 CollectionIterator::GetCurrent (MoonError
*err
)
749 if (generation
!= collection
->Generation ()) {
750 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "The underlying collection has mutated");
754 if (index
< 0 || index
>= collection
->GetCount ()) {
755 MoonError::FillIn (err
, MoonError::INVALID_OPERATION
, "Index out of bounds");
759 return collection
->GetValueAt (index
);
763 CollectionIterator::Destroy (CollectionIterator
*iterator
)
773 VisualTreeWalker::VisualTreeWalker (UIElement
*obj
, VisualTreeWalkerDirection dir
, Types
*cached
)
777 content
= obj
->GetSubtreeObject ();
779 types
= (cached
== NULL
) ? obj
->GetDeployment ()->GetTypes () : cached
;
781 if (content
!= NULL
) {
782 if (types
->IsSubclassOf (content
->GetObjectType (), Type::COLLECTION
)) {
783 collection
= (Collection
*)content
;
785 if (!types
->IsSubclassOf (content
->GetObjectType (), Type::UIELEMENT_COLLECTION
))
794 VisualTreeWalker::Step ()
796 UIElement
*result
= NULL
;
799 UIElementCollection
*uiecollection
= NULL
;
800 int count
= GetCount ();
802 if (count
< 0 || index
>= count
)
805 if (count
== 1 && index
== 0) {
807 return collection
->GetValueAt (0)->AsUIElement(types
);
810 if (direction
== ZForward
|| direction
== ZReverse
) {
811 uiecollection
= (UIElementCollection
*)collection
;
813 if ((int)uiecollection
->z_sorted
->len
!= count
) {
814 g_warning ("VisualTreeWalker: unexpectedly got an unsorted UIElementCollection");
815 uiecollection
->ResortByZIndex ();
821 result
= (UIElement
*)uiecollection
->z_sorted
->pdata
[index
];
824 result
= (UIElement
*)uiecollection
->z_sorted
->pdata
[count
- (index
+ 1)];
827 Value
*v
= collection
->GetValueAt (index
);
828 result
= v
== NULL
? NULL
: v
->AsUIElement (types
);
831 case LogicalReverse
: {
832 Value
*v
= collection
->GetValueAt (count
- (index
+ 1));
833 result
= v
== NULL
? NULL
: v
->AsUIElement (types
);
842 result
= (UIElement
*)content
;
852 VisualTreeWalker::GetCount ()
860 return collection
->GetCount ();
863 VisualTreeWalker::~VisualTreeWalker()
870 class UnsafeUIElementNode
: public List::Node
{
872 UIElement
*uielement
;
874 UnsafeUIElementNode (UIElement
*el
) { uielement
= el
; }
877 DeepTreeWalker::DeepTreeWalker (UIElement
*top
, VisualTreeWalkerDirection direction
, Types
*types
)
879 walk_list
= new List ();
880 walk_list
->Append (new UnsafeUIElementNode (top
));
882 this->types
= types
? types
: top
->GetDeployment ()->GetTypes ();
883 this->direction
= direction
;
887 DeepTreeWalker::Step ()
890 VisualTreeWalker
walker (last
, direction
, types
);
891 //VisualTreeWalker walker (last, ZForward, types);
892 UnsafeUIElementNode
*prepend
= (UnsafeUIElementNode
*) walk_list
->First ();
893 while (UIElement
*child
= walker
.Step ())
894 walk_list
->InsertBefore (new UnsafeUIElementNode (child
), prepend
);
897 UnsafeUIElementNode
*next
= (UnsafeUIElementNode
*)walk_list
->First ();
904 UIElement
*current
= next
->uielement
;
905 walk_list
->Unlink (next
);
913 DeepTreeWalker::SkipBranch ()
918 DeepTreeWalker::~DeepTreeWalker ()
927 collection_new (Type::Kind kind
)
929 Type
*t
= Type::Find (Deployment::GetCurrent (), kind
);
931 if (!t
->IsSubclassOf (Type::COLLECTION
)) {
932 g_warning ("create_collection passed non-collection type");
936 return (Collection
*) t
->CreateInstance();