Пример #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);
}
Пример #2
0
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
	}
}
Пример #3
0
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;
}
Пример #4
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");
}
Пример #5
0
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();
	}
}
Пример #6
0
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);
}
Пример #7
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;
}
Пример #8
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);
}
Пример #9
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");
}
Пример #10
0
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;
}
Пример #11
0
// 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;
}