void TextSelection::Insert (TextElement *element) { if (anchor.GetParent() == NULL || moving.GetParent() == NULL) // if either are null we're going nowhere fast... return; // refactor out the "clear out selection" from SetText ClearSelection (); // at this point both anchor and moving are the same location // depending on what the anchor's parent is, // and what @element is, we might need to // split the tree higher up DependencyObject *el = anchor.GetParent (); int loc = anchor.ResolveLocation(); while (el) { DependencyObject *el_parent = el->GetParent(); if (el_parent) el_parent = el_parent->GetParent(); IDocumentNode *node = IDocumentNode::CastToIDocumentNode (el); DependencyObjectCollection *children = node->GetDocumentChildren (); if (children && element->Is (children->GetElementType())) { // we can insert the element here, so let's do it and be done with things children->Insert (loc, element); return; } if (!el_parent) { g_warning ("new element cannot fit inside element, and we can't split it"); return; } // we need to split the current element at // @loc, add the new element to el's parent // after el, and walk back up to el's parent // with new_el's index as @loc. IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (el_parent); DependencyObjectCollection *parents_children = parent_node ? parent_node->GetDocumentChildren () : NULL; DependencyObject *new_el = node ? node->Split (loc) : NULL; if (!new_el) { g_warning ("split failed"); return; } int new_el_loc = parents_children->IndexOf (el) + 1; parents_children->Insert (new_el_loc, new_el); el = el_parent; loc = new_el_loc; new_el->unref (); } printf ("TextSelection::Insert\n"); }
void ResourceDictionary::SetInternalSourceWithError (const char* source, MoonError *error) { this->source = g_strdup (source); if (source == NULL) return; /* we need to walk up the tree checking for resource dictionaries with the same source, generate an error if it matches */ DependencyObject *p = GetParent(); while (p) { if (p->Is (Type::RESOURCE_DICTIONARY)) { ResourceDictionary* rd = (ResourceDictionary*)p; const char *rd_source = rd->GetInternalSource(); if (rd_source && !strcmp (rd_source, source)) { MoonError::FillIn (error, MoonError::INVALID_OPERATION, /* FIXME: verify exception type */ "cycle found in resource dictionaries"); return; } } p = p->GetParent(); } }
gboolean NameScope::remove_handler (gpointer key, gpointer value, gpointer data) { DependencyObject *depobj = (DependencyObject*)value; depobj->RemoveHandler (EventObject::DestroyedEvent, NameScope::ObjectDestroyedEvent, data); return TRUE; }
bool ResourceDictionary::Remove (const char *key) { if (!key) return false; /* check if the item exists first */ Value* orig_value; gpointer orig_key; if (!g_hash_table_lookup_extended (hash, key, &orig_key, (gpointer*)&orig_value)) return false; from_resource_dictionary_api = true; Collection::Remove (orig_value); from_resource_dictionary_api = false; DependencyObject *ob = orig_value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT) ? orig_value->AsDependencyObject () : NULL; if (ob) ob->SetMentor (NULL); // No need to strengthen orig_value before clearing // because we copy it first. Value orig_copy (*orig_value); g_hash_table_remove (hash, key); EmitChanged (CollectionChangedActionRemove, NULL, &orig_copy, key); return true; }
char* TextSelection::GetXaml () { if (anchor.GetLocation () == moving.GetLocation()) return g_strdup (""); // I'm guessing this should only include ancestors (up to the // root) that are required to serialize the actual selection, // but for now let's just serialize the entire contents of the // RTB. DependencyObject *el = anchor.GetParent(); while (el) { if (el->Is (Type::RICHTEXTBOX)) break; el = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!el) break; } if (el == NULL) { g_warning ("this shouldn't happen..."); return NULL; } // el should be the RichTextBox now. GString *str = g_string_new (""); IDocumentNode *node = IDocumentNode::CastToIDocumentNode (el); node->SerializeXaml(str); return g_string_free (str, FALSE); }
static gboolean remove_from_hash_by_value (gpointer key, gpointer value, gpointer user_data) { Value *v = (Value*)value; DependencyObject *obj = (DependencyObject *) user_data; // FIXME: clearManagedRef return (v->GetKind () == obj->GetObjectType () && v->AsDependencyObject() == obj); }
char* TextSelection::GetText () { GString *gstr; TextPointer tp; if (text) goto done; if (anchor.GetParent() == NULL || moving.GetParent() == NULL) { text = g_strdup (""); goto done; } if (anchor.GetParent() == moving.GetParent() && anchor.GetLocation () == moving.GetLocation()) { text = g_strdup (""); goto done; } gstr = g_string_new (""); tp = anchor; while (tp.CompareTo_np (moving) < 0) { DependencyObject *parent = tp.GetParent (); if (parent && parent->Is (Type::RUN)) { Run *run = (Run*)parent; if (parent == moving.GetParent()) { // tp and moving are in the same element, so we append the substring and set tp = moving. g_string_append_len (gstr, run->GetText() + tp.ResolveLocation(), moving.ResolveLocation() - tp.ResolveLocation()); tp = moving; } else { g_string_append (gstr, run->GetText()); tp = run->GetContentEnd_np(); tp = tp.GetPositionAtOffset_np (1, tp.GetLogicalDirection()); } } else { TextPointer new_tp = tp.GetPositionAtOffset_np (1, tp.GetLogicalDirection()); if (new_tp.CompareTo_np (tp) == 0) break; tp = new_tp; } } text = g_string_free (gstr, FALSE); done: return g_strdup (text); }
DependencyObject* PositionAtOffsetIterator::GetElementParent() { if (element->Is(Type::RICHTEXTBOX)) return NULL; else { // element is a TextElement DependencyObject *p = element->GetParent(); // this first GetParent returns the parent collection if (!p) return NULL; return p->GetParent(); // and this the actual parent } }
void NameScope::ObjectDestroyedEvent (EventObject *sender, EventArgs *args, gpointer closure) { NameScope *ns = (NameScope*)closure; // XXX this method worries me.. using GetName like this. DependencyObject *depobj = (DependencyObject*)sender; const char *name = depobj->GetName (); if (name != NULL) { g_hash_table_remove (ns->names, name); } else { g_hash_table_foreach_remove (ns->names, remove_object_from_namescope, depobj); } }
RichTextBox * TextPointer::GetRichTextBox () const { DependencyObject *el = GetParent(); while (el) { if (el->Is (Type::RICHTEXTBOX)) return (RichTextBox*)el; el = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!el) break; } return NULL; }
// XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection void ResourceDictionary::UnregisterAllNamesRootedAt (NameScope *from_ns) { Value *value; for (guint i = 0; i < array->len; i++) { value = (Value *) array->pdata[i]; if (value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) { DependencyObject *obj = value->AsDependencyObject (); if (obj) obj->UnregisterAllNamesRootedAt (from_ns); } } Collection::UnregisterAllNamesRootedAt (from_ns); }
// XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection void ResourceDictionary::OnIsAttachedChanged (bool attached) { Collection::OnIsAttachedChanged (attached); Value *value; for (guint i = 0; i < array->len; i++) { value = (Value *) array->pdata[i]; if (value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) { DependencyObject *obj = value->AsDependencyObject (); if (obj) obj->SetIsAttached (attached); } } }
void NameScope::UnregisterName (const char *name) { if (GetIsLocked ()) return; if (!names) return; DependencyObject *depobj = (DependencyObject*)g_hash_table_lookup (names, name); if (depobj) { depobj->RemoveHandler (EventObject::DestroyedEvent, ObjectDestroyedEvent, this); g_hash_table_remove (names, name); } }
// XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection void ResourceDictionary::RegisterAllNamesRootedAt (NameScope *to_ns, MoonError *error) { Value *value; for (guint i = 0; i < array->len; i++) { if (error->number) break; value = (Value *) array->pdata[i]; if (value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) { DependencyObject *obj = value->AsDependencyObject (); obj->RegisterAllNamesRootedAt (to_ns, error); } } Collection::RegisterAllNamesRootedAt (to_ns, error); }
void TextSelection::ApplyPropertyValue (DependencyProperty *formatting, Value *value) { DependencyObject *el = anchor.GetParent(); while (el) { if (el->Is (Type::RICHTEXTBOX)) break; el = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!el) break; } if (el == NULL) { g_warning ("this shouldn't happen..."); return; } RichTextBox *rtb = (RichTextBox*)el; rtb->ApplyFormattingToSelection (this, formatting, value); }
Variant GetDPByExpExpression::Evaluate(Expressive::EvalContext* context) { Object* obj = m_object->Evaluate(context); DependencyObject* depObj = dynamic_cast<DependencyObject*>(obj); if (depObj == NULL) { VERIFY(0); } Variant propertyRef = m_exp->Evaluate(context); PropertyValue* pProperty; if (propertyRef.IsString()) pProperty = depObj->GetProperty(depObj->GetClass()->GetLocalProperty(propertyRef.ToString())); else if (propertyRef.IsInt()) pProperty = depObj->GetProperty(depObj->GetClass()->GetLocalProperty((int)propertyRef)); else throw new Exception("property not found"); return pProperty->GetComputedValue(); }
bool GetDPByExpExpression::Set(Expressive::EvalContext* context, Variant value) { Object* obj = m_object->Evaluate(context); DependencyObject* depObj = dynamic_cast<DependencyObject*>(obj); if (depObj == NULL) { VERIFY(0); } Variant propertyRef = m_exp->Evaluate(context); PropertyValue* pProperty; if (propertyRef.IsString()) pProperty = depObj->GetProperty(depObj->GetClass()->GetLocalProperty(propertyRef.ToString())); else if (propertyRef.IsInt()) pProperty = depObj->GetProperty(depObj->GetClass()->GetLocalProperty(int(propertyRef))); else raise(Exception("property not found")); pProperty->UpdateValue(value); return true; }
bool Control::DoApplyTemplateWithError (MoonError *error) { ControlTemplate *t = GetTemplate (); if (!t) return FrameworkElement::DoApplyTemplateWithError (error); // If the template expands to an element which is *not* a UIElement // we don't apply the template. DependencyObject *root = t->GetVisualTreeWithError (this, error); if (root && !root->Is (Type::UIELEMENT)) { g_warning ("Control::DoApplyTemplate () Template root was not a UIElement"); root->unref (); root = NULL; } if (!root) return FrameworkElement::DoApplyTemplateWithError (error); // No need to ref template_root here as ElementAdded refs it // and it is cleared when ElementRemoved is called. if (template_root != root && template_root != NULL) { template_root->SetParent (NULL, NULL); template_root->SetMentor (NULL); template_root = NULL; } template_root = (UIElement *) root; ElementAdded (template_root); if (IsLoaded ()) GetDeployment ()->EmitLoadedAsync (); root->unref (); return true; }
// XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection void ResourceDictionary::RemovedFromCollection (Value *value, bool is_value_safe) { if (is_value_safe & value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) { DependencyObject *obj = value->AsDependencyObject (); if (obj) { obj->RemovePropertyChangeListener (this); obj->RemoveParent (this, NULL); obj->SetIsAttached (false); } } Collection::RemovedFromCollection (value, is_value_safe); if (is_value_safe && value->Is (GetDeployment (), Type::DEPENDENCY_OBJECT)) { if (!from_resource_dictionary_api && value->AsDependencyObject()) { g_hash_table_foreach_remove (hash, remove_from_hash_by_value, value->AsDependencyObject ()); // FIXME we need to EmitChanged something here so the managed RD can remain in sync } } }
// XXX this was (mostly, except for the type check) c&p from DependencyObjectCollection bool ResourceDictionary::AddedToCollection (Value *value, MoonError *error) { DependencyObject *obj = NULL; bool rv = false; if (value->Is(GetDeployment (), Type::DEPENDENCY_OBJECT)) { obj = value->AsDependencyObject (); // Call SetSurface() /before/ setting the logical parent // because Storyboard::SetSurface() needs to be able to // distinguish between the two cases. if (obj->GetParent () && !can_be_added_twice (GetDeployment (), value)) { MoonError::FillIn (error, MoonError::INVALID_OPERATION, g_strdup_printf ("Element is already a child of another element. %s", GetTypeName ())); return false; } obj->AddParent (this, error); if (error->number) return false; obj->SetIsAttached (IsAttached ()); obj->AddPropertyChangeListener (this); if (!from_resource_dictionary_api) { const char *key = obj->GetName(); if (!key) { MoonError::FillIn (error, MoonError::ARGUMENT_NULL, "key was null"); goto cleanup; } if (ContainsKey (key)) { MoonError::FillIn (error, MoonError::ARGUMENT, "An item with the same key has already been added"); goto cleanup; } } } rv = Collection::AddedToCollection (value, error); if (rv && !from_resource_dictionary_api && obj != NULL) { const char *key = obj->GetName(); Value *obj_value = new Value (obj); g_hash_table_insert (hash, g_strdup (key), obj_value); obj_value->Weaken (GetDeployment ()); EmitChanged (CollectionChangedActionAdd, obj_value, NULL, key); } cleanup: if (!rv) { if (obj) { /* If we set the parent, but the object wasn't added to the collection, make sure we clear the parent */ printf ("ResourceDictionary::AddedToCollection (): not added, clearing parent from %p\n", obj); obj->RemoveParent (this, NULL); } } return rv; }
void TextSelection::ClearSelection () { // clear out the selection if (anchor.GetParent() == moving.GetParent()) { bool remove_element = false; if (anchor.GetLocation () != moving.GetLocation()) { if (anchor.GetParent()->Is (Type::RUN)) { Run *run = (Run*)anchor.GetParent(); char *run_text = g_strdup (run->GetText()); if (run_text) { int length_to_remove = moving.ResolveLocation() - anchor.ResolveLocation(); memmove (run_text + anchor.ResolveLocation(), run_text + moving.ResolveLocation (), strlen (run_text + moving.ResolveLocation())); *(run_text + strlen(run_text) - length_to_remove) = 0; run->SetText (run_text); // we need to remove the run if we've cleared all the text in it remove_element = !*run_text; } else { remove_element = true; } g_free (run_text); } else { IDocumentNode *node = anchor.GetParentNode(); int length_to_remove = moving.ResolveLocation() - anchor.ResolveLocation(); for (int i = 0; i < length_to_remove; i ++) node->GetDocumentChildren()->RemoveAt (anchor.ResolveLocation()); // we need to remove the element if we've removed all the children remove_element = node->GetDocumentChildren()->GetCount() == 0; } } DependencyObject *el = anchor.GetParent(); while (remove_element) { if (el->Is (Type::RICHTEXTBOX)) break; DependencyObject* parent = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!parent) { g_warning ("shouldn't happen"); return; } IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); parent_node->GetDocumentChildren()->Remove (Value(el)); el = parent; remove_element = parent_node->GetDocumentChildren()->GetCount() == 0; } } else { // harder case, anchor/moving are in different elements printf ("NIEX hard case TextSelection::ClearSelection\n"); } g_free (text); text = NULL; g_free (xaml); xaml = NULL; }
char* TextSelection::GetXaml () { const char *header = "<Section xml:space=\"preserve\" HasTrailingParagraphBreakOnPaste=\"False\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">"; const char *trailer = "</Section>"; GString *str; ArrayList ancestors; DependencyObject *el; if (xaml) goto done; if (!anchor.GetParent() || !moving.GetParent()) { xaml = g_strdup (""); goto done; } if (anchor.GetParent() == moving.GetParent() && anchor.GetLocation () == moving.GetLocation()) { xaml = g_strdup (""); goto done; } str = g_string_new (header); // first we serialize the xaml start elements for all // TextElements that contain the selection start (but not the // most deeply nested element itself) el = anchor.GetParent(); if (el && !el->Is (Type::RICHTEXTBOX)) { // skip anchor.GetParent() here. el = el->GetParent() ? el->GetParent()->GetParent() : NULL; while (el) { if (el->Is (Type::RICHTEXTBOX)) break; ancestors.Add (el); el = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!el) break; } } for (int i = ancestors.GetCount() - 1; i >= 0; i --) { TextElement *te = (TextElement*)ancestors[i]; IDocumentNode *node = IDocumentNode::CastToIDocumentNode (te); node->SerializeXamlStartElement (str); } // now we output the start element (and deal with the case where start_element == end_element) el = anchor.GetParent (); if (el->Is (Type::RUN)) { if (el == moving.GetParent()) { // if both textpointers are in the same // element, we need to use start+length form ((Run*)el)->SerializeXaml (str, anchor.ResolveLocation (), moving.ResolveLocation () - anchor.ResolveLocation()); } else { // since the moving textpointer is outside // this run, we just use the start form. ((Run*)el)->SerializeXaml (str, anchor.ResolveLocation ()); } } else { ((TextElement*)el)->SerializeXaml (str); } if (anchor.GetParent() != moving.GetParent()) { // now walk the document from start element to end element, outputting everything manually along the way. DocumentWalker walker (anchor.GetParentNode(), DocumentWalker::Forward); IDocumentNode *node; DocumentWalker::StepType stepType; stepType = walker.Step (); // step out of the start element while (stepType != DocumentWalker::Done) { stepType = walker.Step (&node); if (node == moving.GetParentNode()) break; if (stepType == DocumentWalker::Enter) node->SerializeXamlStartElement(str); else node->SerializeXamlEndElement(str); } // now we output the end element el = moving.GetParent (); if (el->Is (Type::RUN)) { ((Run*)el)->SerializeXaml (str, 0, moving.ResolveLocation ()); } else { ((TextElement*)el)->SerializeXaml (str); } } // now serialize the xaml end elements for all TextElements // that contain the selection end (but not the most deeply // nested element itself) if (anchor.GetParent() == moving.GetParent ()) { // this case is trivial, we just output the same list // of end elements that we outputted the start // elements before for (int i = ancestors.GetCount() - 1; i >= 0; i --) { TextElement *te = (TextElement*)ancestors[i]; IDocumentNode *node = IDocumentNode::CastToIDocumentNode (te); node->SerializeXamlEndElement (str); } } else { ancestors.SetCount (0); DependencyObject *el = moving.GetParent(); if (el && !el->Is (Type::RICHTEXTBOX)) { // skip moving.GetParent() here. el = el->GetParent() ? el->GetParent()->GetParent() : NULL; while (el) { if (el->Is (Type::RICHTEXTBOX)) break; ancestors.Add (el); el = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!el) break; } } for (int i = ancestors.GetCount() - 1; i >= 0; i --) { TextElement *te = (TextElement*)ancestors[i]; IDocumentNode *node = IDocumentNode::CastToIDocumentNode (te); node->SerializeXamlEndElement (str); } } g_string_append (str, trailer); xaml = g_string_free (str, FALSE); done: return g_strdup (xaml); }
// // Everything inside of a ( ) resolves to a DependencyProperty, if there is a // '.' after the property, we get the object, and continue resolving from there // if there is a [n] after the property, we convert the property to a collection // and grab the nth item. // // Dependency properties can be specified as (PropertyName) of the current object // or they can be specified as (DependencyObject.PropertyName). // // Returns NULL on any error // DependencyProperty * resolve_property_path (DependencyObject **o, PropertyPath *propertypath, GHashTable *promoted_values) { g_return_val_if_fail (o != NULL, NULL); g_return_val_if_fail (propertypath != NULL, NULL); g_return_val_if_fail (propertypath->path != NULL || propertypath->property != NULL, NULL); if (propertypath->property) return propertypath->property; const char *path = propertypath->path; if (propertypath->expanded_path) path = propertypath->expanded_path; const char *inend = path + strlen (path); register const char *inptr = path; const char *start, *prop = path; bool expression_found = false; DependencyProperty *res = NULL; DependencyObject *lu = *o; Collection *collection; char *p, *name = NULL; Value *value = NULL; Type *type = NULL; int index; bool paren_open = false; bool tick_open = false; bool cloned = false; while (inptr < inend) { switch (*inptr++) { case '(': paren_open = true; break; case ')': paren_open = false; break; case '\'': // Ticks are only legal in expanded paths, so we should just fail here if (!propertypath->expanded_path) { g_warning ("The ' character is not legal in property paths."); break; } tick_open = !tick_open; break; case '.': if (tick_open) continue; // resolve the dependency property if (res) { DependencyObject *new_lu; // make sure that we are getting what we expect if (!(value = lu->GetValue (res))) goto error; if (!(new_lu = value->AsDependencyObject ())) goto error; if (!cloned && !g_hash_table_lookup (promoted_values, value) && !value->Is (lu->GetDeployment (), Type::UIELEMENT)) { // we need to clone the value here so that we deep copy any // DO subclasses (such as brushes, etc) that we're promoting // from a shared space (Styles, default values) Value *cloned_value = Value::Clone (value); DependencyObject *cloned_do = cloned_value->AsDependencyObject(); if (cloned_do != NULL) { new_lu = cloned_do; lu->SetValue (res, cloned_value); delete cloned_value; cloned_value = lu->GetValue (res); g_hash_table_insert (promoted_values, cloned_value, cloned_value); } } lu = new_lu; } expression_found = false; prop = inptr; break; case '[': // Need to be a little more loving if (*inptr == '\0') break; index = strtol (inptr, &p, 10); if (*p != ']' || *(p + 1) != '.') break; inptr = p + 2; prop = inptr; if (expression_found) { expression_found = false; if (!(value = lu->GetValue (res))) goto error; } if (value == NULL) goto error; if (!(collection = value->AsCollection ())) goto error; if (!(value = collection->GetValueAt (index))) goto error; if (!(lu = value->AsDependencyObject ())) goto error; break; default: bool explicit_type = false; expression_found = true; start = inptr - 1; while (inptr < inend && (*inptr != '.' || tick_open) && (!paren_open || *inptr != ')') && *inptr != '[') { if (*inptr == '\'') { tick_open = !tick_open; if (!tick_open) { inptr++; break; } } inptr++; } if (inptr == start) goto error; if (*inptr == '.') { // we found a type name, now we need to find the property name if ((inptr - start) == 11 && !g_ascii_strncasecmp (start, "TextElement", 11)) { // Some Beta versions of Blend had a bug where they would save the TextBlock // properties as TextElement instead. Since Silverlight 1.0 works around this // bug, we should too. Fixes http://silverlight.timovil.com and // http://election.msn.com/podium08.aspx. type = Type::Find (lu->GetDeployment (), "TextBlock"); explicit_type = true; } else { const char *s = inptr; if (*(inptr -1) == '\'' && !tick_open) { s = inptr - 1; } name = g_strndup (start, s - start); type = lookup_type (lu, name); explicit_type = true; if (!type) type = lu->GetType (); g_free (name); } inptr++; start = inptr; while (inptr < inend && (!paren_open || *inptr != ')') && (*inptr != '.' || tick_open)) { if (*inptr == '\'') { tick_open = !tick_open; if (!tick_open) { inptr++; break; } } inptr++; } if (inptr == start) goto error; } else { type = lu->GetType (); explicit_type = false; } if ((*inptr != ')' && paren_open) || !type) goto error; name = g_strndup (start, inptr - start); if (!(res = DependencyProperty::GetDependencyProperty (type, name)) && lu) res = DependencyProperty::GetDependencyProperty (lu->GetType (), name); if (!res) { g_free (name); goto error; } if (!res->IsAttached () && !lu->Is (type->GetKind ())) { // We try to be gracefull here and do something smart... if (!(res = DependencyProperty::GetDependencyProperty (lu->GetType (), name))) { g_free (name); goto error; } } if (res->IsAttached () && explicit_type && !paren_open) goto error; g_free (name); break; } } *o = lu; return res; error: *o = NULL; return NULL; }
void TextSelection::Insert (TextElement *element) { if (anchor.GetParent() == NULL || moving.GetParent() == NULL) // if either are null we're going nowhere fast... return; ClearSelection (); // at this point both anchor and moving are the same location // depending on what the anchor's parent is, // and what @element is, we might need to // split the tree higher up DependencyObject *el = anchor.GetParent (); int loc = anchor.ResolveLocation(); while (el) { DependencyObject *el_parent = el->GetParent(); if (el_parent) el_parent = el_parent->GetParent(); IDocumentNode *node = IDocumentNode::CastToIDocumentNode (el); DependencyObjectCollection *children = node->GetDocumentChildren (); if (children && element->Is (children->GetElementType())) { // we can insert the element here, so let's do it and be done with things children->Insert (loc, element); return; } if (!el_parent) { g_warning ("new element cannot fit inside element, and we can't split it"); return; } // we need to split the current element at // @loc, add the new element to el's parent // after el, and walk back up to el's parent // with new_el's index as @loc. IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (el_parent); DependencyObjectCollection *parents_children = parent_node ? parent_node->GetDocumentChildren () : NULL; if (parents_children == NULL) return; /* #rtx24 */ DependencyObject *new_el; if (element->Is (el->GetObjectType()) /* a more precise check perhaps? instead of subclass? */) { // we don't need to split the node. we just // need to reach in and reparent children // after @loc into element. new_el = node ? node->Split (loc, element) : NULL; } else { new_el = node ? node->Split (loc) : NULL; } int new_el_loc = parents_children->IndexOf (el) + 1; if (new_el) parents_children->Insert (new_el_loc, new_el); el = el_parent; loc = new_el_loc; if (new_el && new_el != element) new_el->unref (); if (new_el == element) { // we've already inserted the element as part of the split. return; } } printf ("NIEX TextSelection::Insert\n"); }
TextPointer TextPointer::GetPositionInsideRun (int offset) const { DependencyObject *parent = GetParent (); if (parent == NULL) return *this; if (offset > 0) { if (parent->Is(Type::RUN)) { int location = ResolveLocation (); const char *text = ((Run*)parent)->GetText(); if ((guint)location < strlen (text)) return GetPositionAtOffset_np (1, LogicalDirectionForward); } // we're at the end of the run (or not in a run at all). we need to walk the document until we hit another run. DocumentWalker walker (IDocumentNode::CastToIDocumentNode (parent), DocumentWalker::Forward); walker.Step (); while (true) { IDocumentNode *node; DocumentWalker::StepType type = walker.Step (&node); switch (type) { case DocumentWalker::Done: // there is no position beyond this return *this; case DocumentWalker::Enter: if (node->AsDependencyObject()->Is(Type::RUN)) return ((Run*)node->AsDependencyObject())->GetContentStart_np(); break; case DocumentWalker::Leave: // do nothing here break; } } } else { if (parent->Is(Type::RUN)) { int location = ResolveLocation (); if (location > 0) return GetPositionAtOffset_np (-1, LogicalDirectionForward); } // we're at the start of the run (or not in a run at all). we need to walk the document until we hit another run. DocumentWalker walker (IDocumentNode::CastToIDocumentNode (parent), DocumentWalker::Backward); walker.Step (); while (true) { IDocumentNode *node; DocumentWalker::StepType type = walker.Step (&node); switch (type) { case DocumentWalker::Done: // there is no position before this return *this; case DocumentWalker::Enter: if (node->AsDependencyObject()->Is(Type::RUN)) return ((Run*)node->AsDependencyObject())->GetContentEnd_np(); break; case DocumentWalker::Leave: // do nothing here break; } } } return *this; }
bool PositionAtOffsetIterator::Step (int *offset) { if (element == NULL) return false; if (*offset == 0) { // we're done stepping. element/location should be valid. return false; } if (*offset < 0) { // we're stepping backward if (location == CONTENT_START) { // we're stepping backward but we're currently // at element's ContentStart. we need to step // up into our parent DependencyObject *parent = GetElementParent(); if (!parent) { // we can't back up anymore. result is NULL. element = NULL; return true; } IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); (*offset) ++; location = parent_node->GetDocumentChildren()->IndexOf (Value (element)); element = parent; return true; } if (element->Is (Type::RUN)) { const char *text = ((Run*)element)->GetText(); guint32 textlen = strlen (text); if (location == CONTENT_END) location = textlen; if (location + *offset < CONTENT_START) { // bump up to the parent after adding the location to our offset *offset += location; location = CONTENT_START; return true; } else { // the operation can be satisfied completely inside this run location += *offset; *offset = 0; return false; } } else { IDocumentNode *node = IDocumentNode::CastToIDocumentNode (element); DependencyObjectCollection *doc_children = node->GetDocumentChildren(); int children_count = doc_children ? doc_children->GetCount() : 0; if (children_count) { if (location == CONTENT_END) location = children_count; element = node->GetDocumentChildren()->GetValueAt(location-1)->AsTextElement(); (*offset) ++; location = CONTENT_END; return true; } else { // not a Run, but also doesn't have children DependencyObject *parent = GetElementParent(); if (!parent) { // we can't back up anymore. result is NULL. element = NULL; return true; } IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); (*offset) ++; location = parent_node->GetDocumentChildren()->IndexOf (Value (element)); element = parent; return true; } } } else /* if offset > 0 */ { if (location == CONTENT_END) { // we're stepping forward but we're currently // at element's ContentEnd. we need to step // up into our parent DependencyObject *parent = GetElementParent(); if (!parent) { // we can't step forward anymore. result is NULL. element = NULL; return true; } IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); (*offset) --; location = parent_node->GetDocumentChildren()->IndexOf (Value (element)); if ((int)location == parent_node->GetDocumentChildren()->GetCount() - 1) location = CONTENT_END; else location ++; element = parent; return true; } if (element->Is (Type::RUN)) { const char *text = ((Run*)element)->GetText(); if (text == NULL) { (*offset) --; location = CONTENT_END; return true; } guint32 textlen = strlen (text); if (location + *offset >= textlen) { // bump up to the parent after subtracting the remaining length of the run from offset *offset = location + *offset - textlen; location = CONTENT_END; return true; } else { // the operation can be satisfied completely inside this run location += *offset; *offset = 0; return false; } } else { IDocumentNode *node = IDocumentNode::CastToIDocumentNode (element); DependencyObjectCollection *doc_children = node->GetDocumentChildren(); int children_count = doc_children ? doc_children->GetCount() : 0; if (children_count > 0) { if ((int)location > children_count - 1) { DependencyObject *parent = GetElementParent(); if (!parent) { // we can't step forward anymore. result is NULL. element = NULL; return true; } IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); (*offset) --; location = parent_node->GetDocumentChildren()->IndexOf (Value (element)) + 1; if ((int)location == children_count - 1) location = CONTENT_END; element = parent; return true; } else { element = node->GetDocumentChildren()->GetValueAt(location)->AsTextElement(); (*offset) --; location = CONTENT_START; return true; } } else { // not a Run, but also doesn't have children DependencyObject *parent = GetElementParent(); if (!parent) { // we can't step forward anymore. result is NULL. element = NULL; return true; } IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); (*offset) --; location = parent_node->GetDocumentChildren()->IndexOf (Value (element)) + 1; if ((int)location == children_count - 1) location = CONTENT_END; element = parent; return true; } } } }
int TextPointer::CompareToWithError (const TextPointer *pointer, MoonError *error) const { if (!verify_textpointer_in_document (this, error) || !verify_textpointer_in_document (pointer, error)) return -1; if (this->GetParent() == pointer->GetParent()) { DependencyObjectCollection *children = this->GetParentNode()->GetDocumentChildren(); if (children && children->GetCount() > 0) return compare_locations (this->GetLocation(), pointer->GetLocation()); else return this->ResolveLocation() - pointer->ResolveLocation(); } else { GPtrArray *this_array = g_ptr_array_new(); GPtrArray *pointer_array = g_ptr_array_new(); DependencyObject *el = GetParent(); while (el) { g_ptr_array_insert (this_array, 0, el); if (el->Is (Type::RICHTEXTBOX)) break; el = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!el) break; } el = pointer->GetParent(); while (el) { g_ptr_array_insert (pointer_array, 0, el); if (el->Is (Type::RICHTEXTBOX)) break; el = el->GetParent() ? el->GetParent()->GetParent() : NULL; if (!el) break; } guint32 count_to_compare = MIN (this_array->len, pointer_array->len); for (guint32 i = 0; i < count_to_compare; i ++) { DependencyObject *this_el = (DependencyObject*)g_ptr_array_index (this_array, i); DependencyObject *pointer_el = (DependencyObject*)g_ptr_array_index (pointer_array, i); if (this_el == pointer_el) continue; if (i == 0) { // this shouldn't happen... there shouldn't be a difference between two paths on the first element, since that should always be a RTB int rv = this_array->len < pointer_array->len ? -1 : 1; g_ptr_array_free (this_array, TRUE); g_ptr_array_free (pointer_array, TRUE); return rv; } /* at this point this_el and pointer_el are different. check index i-1's idea of their positions */ DependencyObject *common_parent = (DependencyObject*)g_ptr_array_index (this_array, i-1); IDocumentNode *common_parent_node = IDocumentNode::CastToIDocumentNode (common_parent); int this_index = common_parent_node->GetDocumentChildren()->IndexOf (Value (this_el)); int pointer_index = common_parent_node->GetDocumentChildren()->IndexOf (Value (pointer_el)); g_ptr_array_free (this_array, TRUE); g_ptr_array_free (pointer_array, TRUE); return this_index < pointer_index ? -1 : 1; } // if we make it here, it means we've run through // "count_to_compare" items that were identical, and // one of the paths is longer (so represents a child // of items[count_to_compare]. // so we need to figure out which array has more // elements, then compare that against the other // TextPointer's location if (count_to_compare < this_array->len) { // @this's parent is a child of pointer_array[count_to_compare-1] DependencyObject *parent = (DependencyObject*)g_ptr_array_index(pointer_array, count_to_compare - 1); IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); guint32 child_index = parent_node->GetDocumentChildren()->IndexOf (Value ((DependencyObject*)g_ptr_array_index(this_array, count_to_compare))); return pointer->GetLocation() > child_index ? -1 : 1; } else if (count_to_compare < pointer_array->len) { // @pointer's parent is a child of this_array[count_to_compare-1] DependencyObject *parent = (DependencyObject*)g_ptr_array_index(this_array, count_to_compare - 1); IDocumentNode *parent_node = IDocumentNode::CastToIDocumentNode (parent); guint32 child_index = parent_node->GetDocumentChildren()->IndexOf (Value ((DependencyObject*)g_ptr_array_index(pointer_array, count_to_compare))); return child_index >= this->GetLocation () ? -1 : 1; } } return -1; }
bool ResourceDictionary::AddWithError (const char* key, Value *value, MoonError *error) { if (!key) { MoonError::FillIn (error, MoonError::ARGUMENT_NULL, "key was null"); return false; } Value *v = NULL; gpointer orig_key; gboolean exists = g_hash_table_lookup_extended (hash, key, &orig_key, (gpointer*)&v); if (exists) { MoonError::FillIn (error, MoonError::ARGUMENT, "An item with the same key has already been added"); return false; } v = new Value (*value); from_resource_dictionary_api = true; bool result = Collection::AddWithError (v, error) != -1; from_resource_dictionary_api = false; if (result) { g_hash_table_insert (hash, g_strdup (key), v); v->Weaken (GetDeployment ()); EmitChanged (CollectionChangedActionAdd, v, NULL, key); if (!strncmp (key, INTERNAL_TYPE_KEY_MAGIC_COOKIE, sizeof (INTERNAL_TYPE_KEY_MAGIC_COOKIE) - 1) && v->Is (GetDeployment (), Type::STYLE)) { DependencyObject *p = GetParent(); if (!p) return result; Style *style = v->AsStyle(); if (p->Is (Type::APPLICATION)) { // we modified the application's resources, so we need to traverse all layers CollectionIterator *iterator = p->GetDeployment()->GetSurface()->GetLayers()->GetIterator(); while (iterator->Next (NULL)) { Value *v = iterator->GetCurrent(NULL); FrameworkElement *fwe = v->AsFrameworkElement(); fwe->StyleResourceChanged (key, style); } delete iterator; } else if (p->Is (Type::FRAMEWORKELEMENT)) { // just traverse down from this frameworkelement ((FrameworkElement*)p)->StyleResourceChanged (key, style); } } } else { delete v; } return result; }