2009-10-09 Chris Toshok <toshok@ximian.com>
[moon.git] / src / collection.cpp
blob4736fb222fee4918879ef19cf88ee9f9cad41321
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
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.
8 *
9 */
11 #include <config.h>
13 #include <glib.h>
15 #include "cbinding.h"
16 #include "canvas.h"
17 #include "collection.h"
18 #include "geometry.h"
19 #include "transform.h"
20 #include "frameworkelement.h"
21 #include "namescope.h"
22 #include "textblock.h"
23 #include "utils.h"
24 #include "error.h"
25 #include "deployment.h"
26 #include "multiscalesubimage.h"
29 // Collection
32 Collection::Collection ()
34 SetObjectType (Type::COLLECTION);
35 array = g_ptr_array_new ();
36 generation = 0;
39 void
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]);
48 Add (value);
49 delete value;
53 Collection::~Collection ()
55 g_ptr_array_free (array, true);
58 void
59 Collection::Dispose ()
61 Value *value;
63 for (guint i = 0; i < array->len; i++) {
64 value = (Value *) array->pdata[i];
65 RemovedFromCollection (value);
66 delete value;
68 g_ptr_array_set_size (array, 0);
70 DependencyObject::Dispose ();
73 CollectionIterator *
74 Collection::GetIterator ()
76 return new CollectionIterator (this);
79 int
80 Collection::Add (Value *value)
82 MoonError error;
83 return AddWithError (value, &error);
86 int
87 Collection::Add (Value value)
89 return Add (&value);
92 int
93 Collection::AddWithError (Value *value, MoonError *error)
95 bool rv = InsertWithError (array->len, value, error);
96 return rv ? array->len - 1 : -1;
99 bool
100 Collection::Clear ()
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);
109 generation++;
111 SetCount (0);
113 for (guint i = 0; i < len; i++) {
114 RemovedFromCollection (vals[i]);
115 delete vals[i];
117 delete[] vals;
119 EmitChanged (CollectionChangedActionCleared, NULL, NULL, -1);
121 return true;
124 bool
125 Collection::Contains (Value *value)
127 return IndexOf (value) != -1;
131 Collection::IndexOf (Value *value)
133 Value *v;
135 for (guint i = 0; i < array->len; i++) {
136 v = (Value *) array->pdata[i];
137 if (*v == *value)
138 return i;
141 return -1;
144 bool
145 Collection::Insert (int index, Value value)
147 return Insert (index, &value);
150 bool
151 Collection::InsertWithError (int index, Value *value, MoonError *error)
153 Value *added;
155 // Check that the item can be added to our collection
156 if (!CanAdd (value))
157 return false;
159 // bounds check
160 if (index < 0)
161 return false;
163 int count = GetCount ();
164 if (index > count)
165 index = count;
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);
178 delete added_copy;
180 return true;
182 else {
183 delete added;
184 return false;
188 bool
189 Collection::Insert (int index, Value *value)
191 MoonError error;
192 return InsertWithError (index, value, &error);
195 bool
196 Collection::Remove (Value value)
198 return Remove (&value);
201 bool
202 Collection::Remove (Value *value)
204 int index;
206 if ((index = IndexOf (value)) == -1)
207 return false;
209 return RemoveAt (index);
212 bool
213 Collection::RemoveAt (int index)
215 Value *value;
217 // check bounds
218 if (index < 0 || (guint) index >= array->len)
219 return false;
221 value = (Value *) array->pdata[index];
223 g_ptr_array_remove_index (array, index);
224 SetCount ((int) array->len);
225 generation++;
227 RemovedFromCollection (value);
229 EmitChanged (CollectionChangedActionRemove, NULL, value, index);
231 delete value;
233 return true;
236 bool
237 Collection::RemoveAtWithError (int index, MoonError *error)
239 // check bounds
240 if (index < 0 || (guint) index >= array->len) {
241 MoonError::FillIn (error, MoonError::ARGUMENT_OUT_OF_RANGE, "");
242 return false;
245 return RemoveAt (index);
248 Value *
249 Collection::GetValueAt (int index)
251 if (index < 0 || (guint) index >= array->len)
252 return NULL;
254 return (Value *) array->pdata[index];
257 Value *
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, "");
263 return NULL;
266 return GetValueAt (index);
269 bool
270 Collection::SetValueAt (int index, Value *value)
272 MoonError error;
273 return SetValueAtWithError (index, value, &error);
276 bool
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, "");
284 return false;
287 // check array bounds
288 if (index < 0 || (guint) index >= array->len) {
289 MoonError::FillIn (error, MoonError::ARGUMENT_OUT_OF_RANGE, "");
290 return false;
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);
303 delete removed;
305 return true;
307 else
308 return false;
311 void
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));
317 void
318 Collection::EmitItemChanged (DependencyObject *object, DependencyProperty *property, Value *newValue, Value *oldValue)
320 Emit (Collection::ItemChangedEvent, new CollectionItemChangedEventArgs (object, property, oldValue, newValue));
323 bool
324 Collection::CanAdd (Value *value)
326 return value->Is (GetElementType ());
331 // DependencyObjectCollection
334 DependencyObjectCollection::DependencyObjectCollection ()
336 SetObjectType (Type::DEPENDENCY_OBJECT_COLLECTION);
339 DependencyObjectCollection::~DependencyObjectCollection ()
343 bool
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 ());
355 if (parent) {
356 if (parent->Is(Type::COLLECTION) && !obj->PermitsMultipleParents ()) {
357 MoonError::FillIn (error, MoonError::INVALID_OPERATION, "Element is already a child of another element.");
358 return false;
361 else {
362 obj->SetParent (this, error);
363 if (error->number)
364 return false;
367 obj->AddPropertyChangeListener (this);
369 return Collection::AddedToCollection (value, error);
372 void
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);
384 void
385 DependencyObjectCollection::SetSurface (Surface *surface)
387 if (GetSurface() == surface)
388 return;
390 DependencyObject *obj;
391 Value *value;
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);
402 void
403 DependencyObjectCollection::OnSubPropertyChanged (DependencyProperty *prop, DependencyObject *obj, PropertyChangedEventArgs *subobj_args)
405 EmitItemChanged (obj, subobj_args->GetProperty(), subobj_args->GetNewValue(), subobj_args->GetOldValue());
408 void
409 DependencyObjectCollection::UnregisterAllNamesRootedAt (NameScope *from_ns)
411 DependencyObject *obj;
412 Value *value;
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);
424 void
425 DependencyObjectCollection::RegisterAllNamesRootedAt (NameScope *to_ns, MoonError *error)
427 DependencyObject *obj;
428 Value *value;
430 Types *types = Deployment::GetCurrent ()->GetTypes ();
431 for (guint i = 0; i < array->len; i++) {
432 if (error->number)
433 break;
435 value = (Value *) array->pdata[i];
436 obj = value->AsDependencyObject (types);
437 obj->RegisterAllNamesRootedAt (to_ns, error);
440 Collection::RegisterAllNamesRootedAt (to_ns, error);
444 // InlineCollection
447 InlineCollection::InlineCollection ()
449 SetObjectType (Type::INLINE_COLLECTION);
452 InlineCollection::~InlineCollection ()
456 bool
457 InlineCollection::Equals (InlineCollection *inlines)
459 Inline *run0, *run1;
461 if (inlines->array->len != array->len)
462 return false;
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))
470 return false;
473 return true;
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);
492 static int
493 UIElementZIndexComparer (gconstpointer ui1, gconstpointer ui2)
495 int z1 = Canvas::GetZIndex (*((UIElement **) ui1));
496 int z2 = Canvas::GetZIndex (*((UIElement **) ui2));
498 return z1 - z2;
501 void
502 UIElementCollection::ResortByZIndex ()
504 g_ptr_array_set_size (z_sorted, array->len);
506 if (array->len == 0)
507 return;
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);
513 if (array->len > 1)
514 g_ptr_array_sort (z_sorted, UIElementZIndexComparer);
517 bool
518 UIElementCollection::Clear ()
520 g_ptr_array_set_size (z_sorted, 0);
521 return DependencyObjectCollection::Clear ();
525 // HitTestCollection
528 HitTestCollection::HitTestCollection ()
533 // DoubleCollection
536 DoubleCollection::DoubleCollection ()
538 SetObjectType (Type::DOUBLE_COLLECTION);
541 DoubleCollection::~DoubleCollection ()
545 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);
552 return NULL;
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);
560 return doubles;
564 // Point Collection
567 PointCollection::PointCollection ()
569 SetObjectType (Type::POINT_COLLECTION);
572 PointCollection::~PointCollection ()
576 PointCollection *
577 PointCollection::FromStr (const char *s)
579 int i, j, n = 0;
580 GArray *values = double_garray_from_str (s, 0);
582 n = values->len / 2;
583 if (n == 0 || n % 1 == 1) {
584 g_array_free (values, true);
585 return NULL;
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);
597 return points;
601 // Item Collection
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);
653 static int
654 MultiScaleSubImageZIndexComparer (gconstpointer msisi1, gconstpointer msisi2)
656 int z1 = (*((MultiScaleSubImage**)msisi1))->GetZIndex ();
657 int z2 = (*((MultiScaleSubImage**)msisi2))->GetZIndex ();
659 return z1 - z2;
662 void
663 MultiScaleSubImageCollection::ResortByZIndex ()
665 g_ptr_array_set_size (z_sorted, array->len);
667 if (array->len == 0)
668 return;
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);
674 if (array->len > 1)
675 g_ptr_array_sort (z_sorted, MultiScaleSubImageZIndexComparer);
678 bool
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 ();
705 collection = c;
706 collection->ref ();
707 index = -1;
710 CollectionIterator::~CollectionIterator ()
712 collection->unref ();
716 CollectionIterator::Next ()
718 if (generation != collection->Generation ())
719 return -1;
721 index++;
723 if (index >= collection->GetCount ())
724 return 0;
726 return 1;
729 bool
730 CollectionIterator::Reset()
732 if (generation != collection->Generation ())
733 return false;
735 index = -1;
737 return true;
740 Value *
741 CollectionIterator::GetCurrent (int *error)
743 if (generation != collection->Generation ()) {
744 *error = 1;
745 return NULL;
748 if (index < 0) {
749 *error = 1;
750 return NULL;
753 *error = 0;
755 return collection->GetValueAt (index);
758 void
759 CollectionIterator::Destroy (CollectionIterator *iterator)
761 delete iterator;
766 // VisualTreeWalker
769 VisualTreeWalker::VisualTreeWalker (UIElement *obj, VisualTreeWalkerDirection dir, Types *cached)
771 index = 0;
772 collection = NULL;
773 content = obj->GetSubtreeObject ();
774 direction = dir;
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))
782 direction = Logical;
785 content->ref ();
789 UIElement *
790 VisualTreeWalker::Step ()
792 UIElement *result = NULL;
794 if (collection) {
795 UIElementCollection *uiecollection = NULL;
796 int count = -1;
798 if (direction != Logical) {
799 uiecollection = (UIElementCollection *)collection;
800 count = GetCount ();
801 if (count < 0 || index >= count)
802 return NULL;
804 if (count == 1 && index == 0) {
805 index ++;
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 ();
815 switch (direction) {
816 case ZForward:
817 result = (UIElement*)uiecollection->z_sorted->pdata[index];
818 break;
819 case ZReverse:
820 result = (UIElement *)uiecollection->z_sorted->pdata[count - (index + 1)];
821 break;
822 default:
823 Value *v = collection->GetValueAt (index);
824 result = v == NULL ? NULL : v->AsUIElement (types);
827 index++;
828 } else {
829 if (index == 0) {
830 index++;
831 result = (UIElement *)content;
832 } else {
833 result = NULL;
837 return result;
841 VisualTreeWalker::GetCount ()
843 if (!content)
844 return 0;
846 if (!collection)
847 return 1;
849 return collection->GetCount ();
852 VisualTreeWalker::~VisualTreeWalker()
854 if (content)
855 content->unref ();
859 class UnsafeUIElementNode : public List::Node {
860 public:
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));
870 last = NULL;
871 this->types = types ? types : Deployment::GetCurrent ()->GetTypes ();
874 UIElement *
875 DeepTreeWalker::Step ()
877 if (last) {
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 ();
887 if (!next) {
888 last = NULL;
889 return NULL;
892 UIElement *current = next->uielement;
893 walk_list->Unlink (next);
894 delete next;
895 last = current;
897 return current;
900 void
901 DeepTreeWalker::SkipBranch ()
903 last = NULL;
906 DeepTreeWalker::~DeepTreeWalker ()
908 delete walk_list;
912 // Manual C-Bindings
914 Collection *
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");
921 return NULL;
924 return (Collection *) t->CreateInstance();