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"); }
DocumentWalker::StepType DocumentWalker::Step (IDocumentNode **node_return) { DependencyObjectCollection *children = node->GetDocumentChildren(); if (direction == DocumentWalker::Forward) { if (children && children->GetCount() > child_index) { // 1) if node is a container, step into the child node = IDocumentNode::CastToIDocumentNode (children->GetValueAt (child_index)->AsTextElement()); child_index = 0; if (node_return) *node_return = node; return Enter; } else { // 2) if it's not a container, then we walk up a level, step out of this node IDocumentNode *parent_node = node->GetParentDocumentNode(); if (parent_node == NULL) return Done; DependencyObjectCollection *parent_children= parent_node->GetDocumentChildren(); int i = parent_children->IndexOf (node->AsDependencyObject()); if (node_return) *node_return = node; child_index = i + 1; node = parent_node; return Leave; } } else { if (children && children->GetCount() > child_index && child_index >= 0) { // 1) if node is a container, step into the child node = IDocumentNode::CastToIDocumentNode (children->GetValueAt (child_index)->AsTextElement()); children = node->GetDocumentChildren (); child_index = children ? children->GetCount() - 1 : 0; if (node_return) *node_return = node; return Enter; } else { // 2) if it's not a container, then we walk up a level, step out of this node IDocumentNode *parent_node = node->GetParentDocumentNode(); if (parent_node == NULL) return Done; DependencyObjectCollection *parent_children= parent_node->GetDocumentChildren(); int i = parent_children->IndexOf (node->AsDependencyObject()); if (node_return) *node_return = node; child_index = i - 1; node = parent_node; return Leave; } } }
void TextSelection::SetText (const char *text) { #define CONTENT_START (0) #define CONTENT_END ((guint32)-1) if (anchor.GetParent() == NULL || moving.GetParent() == NULL) // if either are null we're going nowhere fast... return; ClearSelection (); // at this point the selection is empty and anchor == moving if (text && *text) { if (anchor.GetParent()->Is (Type::RUN)) { const char *run_text = ((Run*)anchor.GetParent())->GetText(); if (run_text == NULL) run_text = "\0"; char *new_text = (char*)g_malloc0 (strlen (run_text) + strlen (text) + 1); if (strlen (text) < (size_t) anchor.ResolveLocation ()){ // #339RT enters here g_free (new_text); new_text = g_strdup ("BUGBUGBUG"); } else { strncpy (new_text, run_text, anchor.ResolveLocation()); strcpy (new_text + anchor.ResolveLocation(), text); strncpy (new_text + anchor.ResolveLocation() + strlen(text), run_text + anchor.ResolveLocation(), strlen (run_text) - anchor.ResolveLocation()); } ((Run*)anchor.GetParent())->SetText (new_text); if (moving.GetLocation() > strlen (new_text)) { anchor = TextPointer (anchor.GetParent(), CONTENT_END, anchor.GetLogicalDirection()); moving = TextPointer (anchor.GetParent(), CONTENT_END, anchor.GetLogicalDirection()); } else { TextPointer new_anchor (anchor.GetParent(), anchor.ResolveLocation () + strlen (text), anchor.GetLogicalDirection()); moving = TextPointer (anchor.GetParent(), anchor.ResolveLocation () + strlen (text), anchor.GetLogicalDirection()); anchor = new_anchor; } g_free (new_text); if (anchor.CompareTo_np (moving) < 0) { start = anchor; end = moving; } else { start = moving; end = anchor; } } else { IDocumentNode *node = anchor.GetParentNode(); DependencyObjectCollection *children = node->GetDocumentChildren(); if (!children) { // this can happen when anchor is in an InlineUIContainer. printf ("NIEX TextSelection.SetText for anchor == InlineUIContainer.\n"); return; } Run *r = MoonUnmanagedFactory::CreateRun (); r->SetText (text); if (children->Is(Type::BLOCK_COLLECTION)) { // the node takes Blocks as children, so we need to create a Paragraph first. Paragraph *p = MoonUnmanagedFactory::CreateParagraph(); children->Insert (anchor.GetLocation(), Value (p)); children = p->GetInlines(); children->Add (Value (r)); p->unref (); } else { children->Insert (anchor.GetLocation(), Value (r)); } anchor = TextPointer (r, CONTENT_END, anchor.GetLogicalDirection()); moving = TextPointer (r, CONTENT_END, anchor.GetLogicalDirection()); r->unref (); if (anchor.CompareTo_np (moving) < 0) { start = anchor; end = moving; } else { start = moving; end = anchor; } } } g_free (this->text); this->text = 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"); }
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; }