Example #1
0
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);
}
Example #2
0
Value *
TextSelection::GetPropertyValue (DependencyProperty *formatting) const
{
	Value *value = start.GetParent()->GetValue (formatting);
	Value *current_value;

	DocumentWalker walker (start.GetParentNode(), DocumentWalker::Forward);

	walker.Step ();// skip the ::Leave for the start node

	while (true) {
		IDocumentNode *node;
		DocumentWalker::StepType step = walker.Step (&node);
		switch (step) {
		case DocumentWalker::Enter:
			current_value = node->AsDependencyObject()->GetValue (formatting);
			if (!Value::AreEqual (value, current_value))
				return NULL;

			if (node == end.GetParentNode())
				return value;

		case DocumentWalker::Leave:
			break;
		case DocumentWalker::Done:
			// this shouldn't happen, but do we care?
			g_warning ("TextSelecion::GetPropertyValue document walker found the end of the document before finding the selection end.");
			break;
			return NULL;
		}
	}
}
Example #3
0
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");
}
Example #4
0
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;
}
Example #5
0
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);
}
Example #6
0
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;
}
Example #7
0
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");
}
Example #8
0
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;
}
Example #9
0
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;
			}
		}
	}
}