summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: d892789)
raw | patch | inline | side by side (parent: d892789)
author | sasilver <sasilver@users.sourceforge.net> | |
Mon, 2 Jun 2008 08:23:40 +0000 (08:23 +0000) | ||
committer | sasilver <sasilver@users.sourceforge.net> | |
Mon, 2 Jun 2008 08:23:40 +0000 (08:23 +0000) |
make the Title and Description fields on the Object Properties dialog work (bug 171024)
src/dialogs/item-properties.cpp | patch | blob | history | |
src/sp-object.cpp | patch | blob | history | |
src/sp-object.h | patch | blob | history |
index 2f93179e109095abcf979e66b548542062e9e961..fb7753d0054f07f4798b6b47fea65b18a5c7232e 100644 (file)
gtk_table_attach ( GTK_TABLE (t), f, 0, 3, 3, 4,
(GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
(GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 0, 0 );
- gtk_object_set_data (GTK_OBJECT (spw), "desc_frame", l);
/* Create the text view box for the object description */
GtkWidget *textframe = gtk_frame_new(NULL);
gtk_widget_set_sensitive (GTK_WIDGET (textframe), FALSE);
gtk_container_add (GTK_CONTAINER (f), textframe);
gtk_frame_set_shadow_type (GTK_FRAME (textframe), GTK_SHADOW_IN);
+ gtk_object_set_data(GTK_OBJECT(spw), "desc_frame", textframe);
tf = gtk_text_view_new();
+ gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(tf), GTK_WRAP_WORD);
desc_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tf));
gtk_text_buffer_set_text(desc_buffer, "", -1);
gtk_container_add (GTK_CONTAINER (textframe), tf);
w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label"));
gtk_entry_set_text (GTK_ENTRY (w), obj->defaultLabel());
gtk_widget_set_sensitive (w, TRUE);
- w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label_label"));
+
+ /* Title */
+ w = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(spw), "title"));
+ gchar *title = obj->title();
+ if (title) {
+ gtk_entry_set_text(GTK_ENTRY(w), title);
+ g_free(title);
+ }
+ else gtk_entry_set_text(GTK_ENTRY(w), "");
+ gtk_widget_set_sensitive(w, TRUE);
+
+ /* Description */
+ gchar *desc = obj->desc();
+ if (desc) {
+ w = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(spw), "desc"));
+ GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(w));
+ gtk_text_buffer_set_text(buf, desc, -1);
+ g_free(desc);
+ }
+ w = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(spw), "desc_frame"));
+ gtk_widget_set_sensitive(w, TRUE);
}
gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
}
/* Retrieve the title */
- GtkWidget *w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "title"));
- gchar *title = (gchar *)gtk_entry_get_text (GTK_ENTRY (w));
- if (title != NULL) {
+ GtkWidget *w = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(spw), "title"));
+ gchar *title = (gchar *)gtk_entry_get_text(GTK_ENTRY (w));
+ g_assert(title != NULL);
+ gchar *old_title = obj->title();
+ if (old_title == NULL || strcmp(title, old_title)) {
obj->setTitle(title);
- sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
- _("Set object title"));
+ sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
+ _("Set object title"));
}
+ g_free(old_title);
/* Retrieve the description */
- gchar *desc = NULL; /* TODO: get text from text buffer */
- if (desc != NULL) {
+ GtkTextView *tv = GTK_TEXT_VIEW(gtk_object_get_data(GTK_OBJECT(spw), "desc"));
+ GtkTextBuffer *buf = gtk_text_view_get_buffer(tv);
+ GtkTextIter start, end;
+ gtk_text_buffer_get_bounds(buf, &start, &end);
+ gchar *desc = gtk_text_buffer_get_text(buf, &start, &end, TRUE);
+ g_assert(desc != NULL);
+ gchar *old_desc = obj->desc();
+ if (old_desc == NULL || strcmp(desc, old_desc)) {
obj->setDesc(desc);
- sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
- _("Set object description"));
+ sp_document_done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
+ _("Set object description"));
}
+ g_free(old_desc);
+ g_free(desc);
gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
diff --git a/src/sp-object.cpp b/src/sp-object.cpp
index f6ddf27dfa0aae1414a756e7ddf5c2c0ac260e63..d260792608a50e288064ab8f1a136baa04de8dbc 100644 (file)
--- a/src/sp-object.cpp
+++ b/src/sp-object.cpp
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* bulia byak <buliabyak@users.sf.net>
+ * Stephen Silver <sasilver@users.sourceforge.net>
*
- * Copyright (C) 1999-2005 authors
+ * Copyright (C) 1999-2008 authors
* Copyright (C) 2001-2002 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
g_object_unref(G_OBJECT(this));
}
-/*
- * Get and set descriptive parameters
- *
- * These are inefficent, so they are not intended to be used interactively
- */
-
-gchar const *
-sp_object_title_get(SPObject */*object*/)
-{
- return NULL;
-}
-
-gchar const *
-sp_object_description_get(SPObject */*object*/)
-{
- return NULL;
-}
-
-unsigned int
-sp_object_title_set(SPObject */*object*/, gchar const */*title*/)
-{
- return FALSE;
-}
-
-unsigned int
-sp_object_description_set(SPObject */*object*/, gchar const */*desc*/)
-{
- return FALSE;
-}
-
gchar const *
sp_object_tagName_get(SPObject const *object, SPException *ex)
{
return NULL;
}
+/* Titles and descriptions */
+
+/* Note:
+ Titles and descriptions are stored in 'title' and 'desc' child elements
+ (see section 5.4 of the SVG 1.0 and 1.1 specifications). The spec allows
+ an element to have more than one 'title' child element, but strongly
+ recommends against this and requires using the first one if a choice must
+ be made. The same applies to 'desc' elements. Therefore, these functions
+ ignore all but the first 'title' child element and first 'desc' child
+ element, except when deleting a title or description.
+*/
+
+/**
+ * Returns the title of this object, or NULL if there is none.
+ * The caller must free the returned string using g_free() - see comment
+ * for getTitleOrDesc() below.
+ */
+gchar *
+SPObject::title() const
+{
+ return getTitleOrDesc("svg:title");
+}
+
+/**
+ * Sets the title of this object
+ * A NULL or purely whitespace argument is interpreted as meaning that
+ * the existing title (if any) should be deleted.
+ */
+void
+SPObject::setTitle(gchar const *title)
+{
+ setTitleOrDesc(title, "svg:title");
+}
+
+/**
+ * Returns the description of this object, or NULL if there is none.
+ * The caller must free the returned string using g_free() - see comment
+ * for getTitleOrDesc() below.
+ */
+gchar *
+SPObject::desc() const
+{
+ return getTitleOrDesc("svg:desc");
+}
+
+/**
+ * Sets the description of this object.
+ * A NULL or purely whitespace argument is interpreted as meaning that
+ * the existing description (if any) should be deleted.
+ */
+void
+SPObject::setDesc(gchar const *desc)
+{
+ setTitleOrDesc(desc, "svg:desc");
+}
+
+/**
+ * Returns the title or description of this object, or NULL if there is none.
+ *
+ * The SVG spec allows 'title' and 'desc' elements to contain text marked up
+ * using elements from other namespaces. Therefore, this function cannot
+ * in general just return a pointer to an existing string - it must instead
+ * construct a string containing the title or description without the mark-up.
+ * Consequently, the return value is a newly allocated string (or NULL), and
+ * must be freed (using g_free()) by the caller.
+ */
+gchar *
+SPObject::getTitleOrDesc(gchar const *svg_tagname) const
+{
+ SPObject *elem = findFirstChild(svg_tagname);
+ if (elem == NULL) return NULL;
+ return g_string_free(elem->textualContent(), FALSE);
+}
+
+/**
+ * Sets or deletes the title or description of this object.
+ */
+void
+SPObject::setTitleOrDesc(gchar const *value, gchar const *svg_tagname)
+{
+ SPObject *elem = findFirstChild(svg_tagname);
+
+ // if the new title/description is NULL, or just whitespace,
+ // then delete any existing title/description
+ bool just_whitespace = true;
+ if (value)
+ for (const gchar *cp = value; *cp; ++cp) {
+ if (!std::strchr("\r\n \t", *cp)) {
+ just_whitespace = false;
+ break;
+ }
+ }
+ if (just_whitespace) {
+ // delete the title/description(s)
+ while (elem) {
+ elem->deleteObject();
+ elem = findFirstChild(svg_tagname);
+ }
+ return;
+ }
+
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
+
+ if (elem == NULL) {
+ // create a new 'title' or 'desc' element, putting it at the
+ // beginning (in accordance with the spec's recommendations)
+ Inkscape::XML::Node *xml_elem = xml_doc->createElement(svg_tagname);
+ repr->addChild(xml_elem, NULL);
+ elem = document->getObjectByRepr(xml_elem);
+ }
+ else {
+ // remove the current content of the 'text' or 'desc' element
+ SPObject *child;
+ while (NULL != (child = elem->firstChild())) child->deleteObject();
+ }
+
+ // add the new content
+ elem->appendChildRepr(xml_doc->createTextNode(value));
+}
+
+/**
+ * Find the first child of this object with a given tag name,
+ * and return it. Returns NULL if there is no matching child.
+ */
+SPObject *
+SPObject::findFirstChild(gchar const *tagname) const
+{
+ for (SPObject *child = children; child; child = child->next)
+ {
+ if (child->repr->type() == Inkscape::XML::ELEMENT_NODE &&
+ !strcmp(child->repr->name(), tagname)) return child;
+ }
+ return NULL;
+}
+
+/**
+ * Return the full textual content of an element (typically all the
+ * content except the tags).
+ * Must not be used on anything except elements.
+ */
+GString*
+SPObject::textualContent() const
+{
+ GString* text = g_string_new("");
+
+ for (const SPObject *child = firstChild(); child; child = child->next)
+ {
+ Inkscape::XML::NodeType child_type = child->repr->type();
+
+ if (child_type == Inkscape::XML::ELEMENT_NODE) {
+ GString * new_text = child->textualContent();
+ g_string_append(text, new_text->str);
+ g_string_free(new_text, TRUE);
+ }
+ else if (child_type == Inkscape::XML::TEXT_NODE) {
+ g_string_append(text, child->repr->content());
+ }
+ }
+ return text;
+}
/*
Local Variables:
diff --git a/src/sp-object.h b/src/sp-object.h
index f30654c12ebb214f862aa2f80f9baecf60ba17db..5d22e33e4290c41dbb38256c9121d1616c024ced 100644 (file)
--- a/src/sp-object.h
+++ b/src/sp-object.h
#define SP_OBJECT_PREV(o) (sp_object_prev((SPObject *) (o)))
#define SP_OBJECT_HREFCOUNT(o) (((SPObject *) (o))->hrefcount)
#define SP_OBJECT_STYLE(o) (((SPObject *) (o))->style)
-#define SP_OBJECT_TITLE(o) sp_object_title_get((SPObject *) (o))
-#define SP_OBJECT_DESCRIPTION(o) sp_object_description_get((SPObject *) (o))
#include <glib-object.h>
void setLabel(gchar const *label);
/** Retrieves the title of this object */
- gchar const *title() const { return NULL; /* TODO */ }
+ gchar *title() const;
/** Sets the title of this object */
- void setTitle(gchar const *title) { (void)title; /* TODO */ }
+ void setTitle(gchar const *title);
/** Retrieves the description of this object */
- gchar const *desc() const { return NULL; /* TODO */ }
+ gchar *desc() const;
/** Sets the description of this object */
- void setDesc(gchar const *desc) { (void)desc; /* TODO */ }
+ void setDesc(gchar const *desc);
/** @brief Set the policy under which this object will be
* orphan-collected.
CollectionPolicy _collection_policy;
gchar *_label;
mutable gchar *_default_label;
+
+private:
+ // Private member functions used in the definitions of setTitle(),
+ // setDesc(), title() and desc().
+ void setTitleOrDesc(gchar const *value, gchar const *svg_tagname);
+ gchar * getTitleOrDesc(gchar const *svg_tagname) const;
+ SPObject * findFirstChild(gchar const *tagname) const;
+ GString * textualContent() const;
};
/// The SPObject vtable.
void sp_object_read_attr(SPObject *object, gchar const *key);
-/*
- * Get and set descriptive parameters.
- *
- * These are inefficent, so they are not intended to be used interactively.
- */
-
-gchar const *sp_object_title_get(SPObject *object);
-gchar const *sp_object_description_get(SPObject *object);
-unsigned int sp_object_title_set(SPObject *object, gchar const *title);
-unsigned int sp_object_description_set(SPObject *object, gchar const *desc);
-
/* Public */
gchar const *sp_object_tagName_get(SPObject const *object, SPException *ex);