aboutsummaryrefslogtreecommitdiff
path: root/liblogdiag/ld-diagram.c
diff options
context:
space:
mode:
authorPřemysl Janouch <p.janouch@gmail.com>2011-01-10 16:49:13 +0100
committerPřemysl Janouch <p.janouch@gmail.com>2011-01-10 17:07:02 +0100
commit616c49a5053830a5e0a31c71fd6114926e43235f (patch)
tree8a21f60862a86d5fb2faf5ed7fd70aa7a2ce69d5 /liblogdiag/ld-diagram.c
parent63b36a2b5b8e04f5d96fa9aa8d212a01c73aad49 (diff)
downloadlogdiag-616c49a5053830a5e0a31c71fd6114926e43235f.tar.gz
logdiag-616c49a5053830a5e0a31c71fd6114926e43235f.tar.xz
logdiag-616c49a5053830a5e0a31c71fd6114926e43235f.zip
Make a separate library.
This is required for gtkdoc-scangobj. So far it's much like it's been before, the main differences are that source files are in two directories from now on and the build process has two stages.
Diffstat (limited to 'liblogdiag/ld-diagram.c')
-rw-r--r--liblogdiag/ld-diagram.c550
1 files changed, 550 insertions, 0 deletions
diff --git a/liblogdiag/ld-diagram.c b/liblogdiag/ld-diagram.c
new file mode 100644
index 0000000..0129e2b
--- /dev/null
+++ b/liblogdiag/ld-diagram.c
@@ -0,0 +1,550 @@
+/*
+ * ld-diagram.c
+ *
+ * This file is a part of logdiag.
+ * Copyright Přemysl Janouch 2010 - 2011. All rights reserved.
+ *
+ * See the file LICENSE for licensing information.
+ *
+ */
+
+#include "liblogdiag.h"
+#include "config.h"
+
+
+/**
+ * SECTION:ld-diagram
+ * @short_description: A diagram object.
+ * @see_also: #LdCanvas
+ *
+ * #LdDiagram is a model used for storing diagrams.
+ */
+
+/*
+ * LdDiagramPrivate:
+ * @modified: Whether the diagram has been modified.
+ * @objects: All objects in the diagram.
+ * @selection: All currently selected objects.
+ * @connections: Connections between objects.
+ */
+struct _LdDiagramPrivate
+{
+ gboolean modified;
+
+ GList *objects;
+ GList *selection;
+ GList *connections;
+};
+
+enum
+{
+ PROP_0,
+ PROP_MODIFIED
+};
+
+static void ld_diagram_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec);
+static void ld_diagram_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec);
+static void ld_diagram_dispose (GObject *gobject);
+static void ld_diagram_finalize (GObject *gobject);
+
+static gboolean write_signature (GOutputStream *stream, GError **error);
+
+static void ld_diagram_real_changed (LdDiagram *self);
+static void ld_diagram_clear_internal (LdDiagram *self);
+static void ld_diagram_unselect_all_internal (LdDiagram *self);
+
+
+G_DEFINE_TYPE (LdDiagram, ld_diagram, G_TYPE_OBJECT);
+
+static void
+ld_diagram_class_init (LdDiagramClass *klass)
+{
+ GObjectClass *object_class;
+ GParamSpec *pspec;
+
+ object_class = G_OBJECT_CLASS (klass);
+ object_class->get_property = ld_diagram_get_property;
+ object_class->set_property = ld_diagram_set_property;
+ object_class->dispose = ld_diagram_dispose;
+ object_class->finalize = ld_diagram_finalize;
+
+ klass->changed = ld_diagram_real_changed;
+
+/**
+ * LdDiagram:modified:
+ *
+ * Whether the diagram has been modified.
+ */
+ pspec = g_param_spec_boolean ("modified", "Modified",
+ "Whether the diagram has been modified.",
+ FALSE, G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_MODIFIED, pspec);
+
+/**
+ * LdDiagram::changed:
+ * @diagram: The diagram object.
+ *
+ * Contents of the diagram have changed.
+ */
+ klass->changed_signal = g_signal_new
+ ("changed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LdDiagramClass, changed), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+/**
+ * LdDiagram::selection-changed:
+ * @diagram: The diagram object.
+ *
+ * The current selection has changed.
+ */
+ klass->selection_changed_signal = g_signal_new
+ ("selection-changed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LdDiagramClass, selection_changed), NULL, NULL,
+ g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
+
+ g_type_class_add_private (klass, sizeof (LdDiagramPrivate));
+}
+
+static void
+ld_diagram_init (LdDiagram *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE
+ (self, LD_TYPE_DIAGRAM, LdDiagramPrivate);
+}
+
+static void
+ld_diagram_get_property (GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ LdDiagram *self;
+
+ self = LD_DIAGRAM (object);
+ switch (property_id)
+ {
+ case PROP_MODIFIED:
+ g_value_set_boolean (value, ld_diagram_get_modified (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+ld_diagram_set_property (GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ LdDiagram *self;
+
+ self = LD_DIAGRAM (object);
+ switch (property_id)
+ {
+ case PROP_MODIFIED:
+ ld_diagram_set_modified (self, g_value_get_boolean (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ }
+}
+
+static void
+ld_diagram_dispose (GObject *gobject)
+{
+ LdDiagram *self;
+
+ self = LD_DIAGRAM (gobject);
+ ld_diagram_clear_internal (self);
+
+ /* Chain up to the parent class. */
+ G_OBJECT_CLASS (ld_diagram_parent_class)->dispose (gobject);
+}
+
+static void
+ld_diagram_finalize (GObject *gobject)
+{
+ /* Chain up to the parent class. */
+ G_OBJECT_CLASS (ld_diagram_parent_class)->finalize (gobject);
+}
+
+static void
+ld_diagram_real_changed (LdDiagram *self)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+
+ ld_diagram_set_modified (self, TRUE);
+}
+
+
+/**
+ * ld_diagram_new:
+ *
+ * Create an instance.
+ */
+LdDiagram *
+ld_diagram_new (void)
+{
+ return g_object_new (LD_TYPE_DIAGRAM, NULL);
+}
+
+/**
+ * ld_diagram_clear:
+ * @self: An #LdDiagram object.
+ *
+ * Clear the whole diagram with it's objects and selection.
+ */
+void
+ld_diagram_clear (LdDiagram *self)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+
+ ld_diagram_clear_internal (self);
+
+ g_signal_emit (self,
+ LD_DIAGRAM_GET_CLASS (self)->changed_signal, 0);
+}
+
+/*
+ * ld_diagram_clear_internal:
+ * @self: An #LdDiagram object.
+ *
+ * Do the same as ld_diagram_clear() does but don't emit signals.
+ */
+static void
+ld_diagram_clear_internal (LdDiagram *self)
+{
+ ld_diagram_unselect_all (self);
+
+ g_list_free (self->priv->connections);
+ self->priv->connections = NULL;
+
+ g_list_foreach (self->priv->objects, (GFunc) g_object_unref, NULL);
+ g_list_free (self->priv->objects);
+ self->priv->objects = NULL;
+}
+
+/**
+ * ld_diagram_load_from_file:
+ * @self: An #LdDiagram object.
+ * @filename: A filename.
+ * @error: Return location for a GError, or NULL.
+ *
+ * Load a file into the diagram.
+ *
+ * Return value: TRUE if the file could be loaded, FALSE otherwise.
+ */
+gboolean
+ld_diagram_load_from_file (LdDiagram *self,
+ const gchar *filename, GError **error)
+{
+ JsonParser *parser;
+ GError *json_error;
+
+ g_return_val_if_fail (LD_IS_DIAGRAM (self), FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ /* TODO: Implement loading for real. This is just a stub. */
+ parser = json_parser_new ();
+
+ json_error = NULL;
+ json_parser_load_from_file (parser, filename, &json_error);
+ if (json_error)
+ {
+ g_propagate_error (error, json_error);
+ g_object_unref (parser);
+ return FALSE;
+ }
+
+ ld_diagram_clear (self);
+ g_object_unref (parser);
+ return TRUE;
+}
+
+/**
+ * ld_diagram_save_to_file:
+ * @self: An #LdDiagram object.
+ * @filename: A filename.
+ * @error: Return location for a GError, or NULL.
+ *
+ * Save the diagram into a file.
+ *
+ * Return value: TRUE if the diagram could be saved, FALSE otherwise.
+ */
+gboolean
+ld_diagram_save_to_file (LdDiagram *self,
+ const gchar *filename, GError **error)
+{
+ GFile *file;
+ GFileOutputStream *file_stream;
+ JsonGenerator *generator;
+ JsonNode *root;
+ GError *local_error;
+
+ g_return_val_if_fail (LD_IS_DIAGRAM (self), FALSE);
+ g_return_val_if_fail (filename != NULL, FALSE);
+
+ file = g_file_new_for_path (filename);
+
+ local_error = NULL;
+ file_stream = g_file_replace (file, NULL, FALSE,
+ G_FILE_CREATE_NONE, NULL, &local_error);
+ g_object_unref (file);
+
+ if (local_error)
+ {
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+
+ local_error = NULL;
+ write_signature (G_OUTPUT_STREAM (file_stream), &local_error);
+ if (local_error)
+ {
+ g_object_unref (file_stream);
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+
+ /* TODO: Implement saving for real. This is just a stub. */
+ generator = json_generator_new ();
+ g_object_set (generator, "pretty", TRUE, NULL);
+
+ /* XXX: json-glib dislikes empty objects. */
+ root = json_node_new (JSON_NODE_OBJECT);
+ json_generator_set_root (generator, root);
+ json_node_free (root);
+
+ local_error = NULL;
+ json_generator_to_stream (generator, G_OUTPUT_STREAM (file_stream),
+ NULL, &local_error);
+ g_object_unref (file_stream);
+ g_object_unref (generator);
+
+ if (local_error)
+ {
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+write_signature (GOutputStream *stream, GError **error)
+{
+ static const gchar signature[] = "/* logdiag diagram */\n";
+ GError *local_error = NULL;
+
+ g_output_stream_write (stream, signature, sizeof (signature) - 1,
+ NULL, &local_error);
+ if (local_error)
+ {
+ g_propagate_error (error, local_error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ * ld_diagram_get_modified:
+ * @self: An #LdDiagram object.
+ *
+ * Return value: The modification status of diagram.
+ */
+gboolean
+ld_diagram_get_modified (LdDiagram *self)
+{
+ g_return_val_if_fail (LD_IS_DIAGRAM (self), FALSE);
+ return self->priv->modified;
+}
+
+/**
+ * ld_diagram_set_modified:
+ * @self: An #LdDiagram object.
+ * @value: Whether the diagram has been modified.
+ *
+ * Set the modification status of diagram.
+ */
+void
+ld_diagram_set_modified (LdDiagram *self, gboolean value)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+ self->priv->modified = value;
+
+ g_object_notify (G_OBJECT (self), "modified");
+}
+
+/**
+ * ld_diagram_get_objects:
+ * @self: An #LdDiagram object.
+ *
+ * Get a list of objects in the diagram. Do not modify.
+ */
+GList *
+ld_diagram_get_objects (LdDiagram *self)
+{
+ g_return_val_if_fail (LD_IS_DIAGRAM (self), NULL);
+ return self->priv->objects;
+}
+
+/**
+ * ld_diagram_insert_object:
+ * @self: An #LdDiagram object.
+ * @object: The object to be inserted.
+ * @pos: The position at which the object is to be inserted.
+ * Negative values will append to the end.
+ *
+ * Insert an object into the diagram.
+ */
+void
+ld_diagram_insert_object (LdDiagram *self, LdDiagramObject *object, gint pos)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+ g_return_if_fail (LD_IS_DIAGRAM_OBJECT (object));
+
+ if (!g_list_find (self->priv->objects, object))
+ {
+ self->priv->objects =
+ g_list_insert (self->priv->objects, object, pos);
+ g_object_ref (object);
+
+ g_signal_emit (self,
+ LD_DIAGRAM_GET_CLASS (self)->changed_signal, 0);
+ }
+}
+
+/**
+ * ld_diagram_remove_object:
+ * @self: An #LdDiagram object.
+ * @object: The object to be removed.
+ *
+ * Remove an object from the diagram.
+ */
+void
+ld_diagram_remove_object (LdDiagram *self, LdDiagramObject *object)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+ g_return_if_fail (LD_IS_DIAGRAM_OBJECT (object));
+
+ if (g_list_find (self->priv->objects, object))
+ {
+ ld_diagram_selection_remove (self, object);
+
+ self->priv->objects = g_list_remove (self->priv->objects, object);
+ g_object_unref (object);
+
+ g_signal_emit (self,
+ LD_DIAGRAM_GET_CLASS (self)->changed_signal, 0);
+ }
+}
+
+/**
+ * ld_diagram_get_selection:
+ * @self: An #LdDiagram object.
+ *
+ * Get a list of objects that are currently selected in the diagram.
+ * Do not modify.
+ */
+GList *
+ld_diagram_get_selection (LdDiagram *self)
+{
+ g_return_val_if_fail (LD_IS_DIAGRAM (self), NULL);
+ return self->priv->selection;
+}
+
+/**
+ * ld_diagram_selection_add:
+ * @self: An #LdDiagram object.
+ * @object: The object to be added to the selection.
+ * @pos: The position at which the object is to be inserted.
+ * Negative values will append to the end.
+ *
+ * Add an object to selection.
+ */
+void
+ld_diagram_selection_add (LdDiagram *self, LdDiagramObject *object, gint pos)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+ g_return_if_fail (LD_IS_DIAGRAM_OBJECT (object));
+
+ g_return_if_fail (g_list_find (self->priv->objects, object) != NULL);
+
+ if (!g_list_find (self->priv->selection, object))
+ {
+ self->priv->selection =
+ g_list_insert (self->priv->selection, object, pos);
+ g_object_ref (object);
+
+ g_signal_emit (self,
+ LD_DIAGRAM_GET_CLASS (self)->selection_changed_signal, 0);
+ }
+}
+
+/**
+ * ld_diagram_selection_remove:
+ * @self: An #LdDiagram object.
+ * @object: The object to be removed from the selection.
+ *
+ * Remove an object from the selection.
+ */
+void
+ld_diagram_selection_remove (LdDiagram *self, LdDiagramObject *object)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+ g_return_if_fail (LD_IS_DIAGRAM_OBJECT (object));
+
+ if (g_list_find (self->priv->selection, object))
+ {
+ self->priv->selection = g_list_remove (self->priv->selection, object);
+ g_object_unref (object);
+
+ g_signal_emit (self,
+ LD_DIAGRAM_GET_CLASS (self)->selection_changed_signal, 0);
+ }
+}
+
+/**
+ * ld_diagram_select_all:
+ * @self: An #LdDiagram object.
+ *
+ * Include all objects in the document to the selection.
+ */
+void
+ld_diagram_select_all (LdDiagram *self)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+
+ ld_diagram_unselect_all_internal (self);
+
+ self->priv->selection = g_list_copy (self->priv->objects);
+ g_list_foreach (self->priv->selection, (GFunc) g_object_ref, NULL);
+
+ g_signal_emit (self,
+ LD_DIAGRAM_GET_CLASS (self)->selection_changed_signal, 0);
+}
+
+/**
+ * ld_diagram_unselect_all:
+ * @self: An #LdDiagram object.
+ *
+ * Remove all objects from the current selection.
+ */
+void
+ld_diagram_unselect_all (LdDiagram *self)
+{
+ g_return_if_fail (LD_IS_DIAGRAM (self));
+
+ ld_diagram_unselect_all_internal (self);
+
+ g_signal_emit (self,
+ LD_DIAGRAM_GET_CLASS (self)->selection_changed_signal, 0);
+}
+
+static void
+ld_diagram_unselect_all_internal (LdDiagram *self)
+{
+ g_list_foreach (self->priv->selection, (GFunc) g_object_unref, NULL);
+ g_list_free (self->priv->selection);
+ self->priv->selection = NULL;
+}