diary r91 - in trunk: . src
- From: pwithnall svn gnome org
- To: svn-commits-list gnome org
- Subject: diary r91 - in trunk: . src
- Date: Sun, 19 Oct 2008 11:08:00 +0000 (UTC)
Author: pwithnall
Date: Sun Oct 19 11:08:00 2008
New Revision: 91
URL: http://svn.gnome.org/viewvc/diary?rev=91&view=rev
Log:
2008-10-19 Philip Withnall <philip tecnocode co uk>
* src/entry.c (almanah_entry_class_init), (almanah_entry_init),
(almanah_entry_finalize), (almanah_entry_get_property),
(almanah_entry_set_property), (almanah_entry_get_data),
(almanah_entry_set_data), (almanah_entry_get_content),
(almanah_entry_set_content), (almanah_entry_is_empty):
* src/entry.h:
* src/main-window.c (save_current_entry),
(mw_about_activate_cb),
(mw_calendar_day_selected_cb):
* src/printing.c (get_iter_attrs), (is_empty_line),
(lay_out_entry), (print_entry), (custom_widget_apply_cb),
(diary_print_entries):
* src/storage-manager.c
(almanah_storage_manager_get_statistics),
(almanah_storage_manager_get_entry),
(almanah_storage_manager_set_entry),
(almanah_storage_manager_search_entries):
* src/storage-manager.h: Serialise and deserialise entries when
writing them to/from the database to enable persistence of
formatting
tags. Modify the printing code to also be able to deal with
formatting tags.
Modified:
trunk/ChangeLog
trunk/src/entry.c
trunk/src/entry.h
trunk/src/main-window.c
trunk/src/printing.c
trunk/src/storage-manager.c
trunk/src/storage-manager.h
Modified: trunk/src/entry.c
==============================================================================
--- trunk/src/entry.c (original)
+++ trunk/src/entry.c Sun Oct 19 11:08:00 2008
@@ -17,7 +17,9 @@
* along with Almanah. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <config.h>
#include <glib.h>
+#include <gtk/gtk.h>
#include "entry.h"
@@ -28,14 +30,15 @@
struct _AlmanahEntryPrivate {
GDate date;
- gchar *content;
+ guint8 *data;
+ gsize length;
+ gboolean is_empty;
};
enum {
PROP_DAY = 1,
PROP_MONTH,
- PROP_YEAR,
- PROP_CONTENT
+ PROP_YEAR
};
G_DEFINE_TYPE (AlmanahEntry, almanah_entry, G_TYPE_OBJECT)
@@ -67,17 +70,14 @@
"Year", "The year for which this is the entry.",
1, (1 << 16) - 1, 1,
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_CONTENT,
- g_param_spec_string ("content",
- "Content", "The textual content of the entry.",
- NULL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
almanah_entry_init (AlmanahEntry *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ALMANAH_TYPE_ENTRY, AlmanahEntryPrivate);
+ self->priv->data = NULL;
+ self->priv->length = 0;
g_date_clear (&(self->priv->date), 1);
}
@@ -86,8 +86,8 @@
{
AlmanahEntryPrivate *priv = ALMANAH_ENTRY (object)->priv;
- g_free (priv->content);
- priv->content = NULL;
+ g_free (priv->data);
+ priv->data = NULL;
/* Chain up to the parent class */
G_OBJECT_CLASS (almanah_entry_parent_class)->finalize (object);
@@ -108,9 +108,6 @@
case PROP_YEAR:
g_value_set_uint (value, g_date_get_year (&(priv->date)));
break;
- case PROP_CONTENT:
- g_value_set_string (value, priv->content);
- break;
default:
/* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -133,9 +130,6 @@
case PROP_YEAR:
g_date_set_year (&(priv->date), g_value_get_uint (value));
break;
- case PROP_CONTENT:
- almanah_entry_set_content (ALMANAH_ENTRY (object), g_value_get_string (value));
- break;
default:
/* We don't have any other property... */
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -153,18 +147,78 @@
NULL);
}
+/* NOTE: There's a difference between content and data, as recognised by AlmanahEntry.
+ * Content is deserialized, and handled in terms of GtkTextBuffers.
+ * Data is serialized, and handled in terms of a guint8 *data and gsize length. */
+const guint8 *
+almanah_entry_get_data (AlmanahEntry *self, gsize *length)
+{
+ if (length != NULL)
+ *length = self->priv->length;
+ return self->priv->data;
+}
+
void
-almanah_entry_set_content (AlmanahEntry *self, const gchar *content)
+almanah_entry_set_data (AlmanahEntry *self, const guint8 *data, gsize length)
+{
+ AlmanahEntryPrivate *priv = self->priv;
+
+ g_free (priv->data);
+
+ priv->data = g_memdup (data, length * sizeof (*data));
+ priv->length = length;
+ priv->is_empty = FALSE;
+}
+
+gboolean
+almanah_entry_get_content (AlmanahEntry *self, GtkTextBuffer *text_buffer, GError **error)
{
- g_free (self->priv->content);
- self->priv->content = g_strdup (content);
- g_object_notify (G_OBJECT (self), "content");
+ GdkAtom format_atom;
+ GtkTextIter start_iter;
+ AlmanahEntryPrivate *priv = self->priv;
+ GError *deserialise_error = NULL;
+
+ format_atom = gtk_text_buffer_register_deserialize_tagset (text_buffer, PACKAGE_NAME);
+ gtk_text_buffer_get_start_iter (text_buffer, &start_iter);
+
+ /* Try deserializing the (hopefully) serialized data first */
+ if (gtk_text_buffer_deserialize (text_buffer, text_buffer,
+ format_atom,
+ &start_iter,
+ priv->data, priv->length,
+ &deserialise_error) == FALSE) {
+ /* Since that failed, check the data's in the old format, and try to just load it as text */
+ if (g_strcmp0 (priv->data, "GTKTEXTBUFFERCONTENTS-0001") != 0) {
+ gtk_text_buffer_set_text (text_buffer, (gchar*) priv->data, priv->length);
+ g_error_free (deserialise_error);
+ return TRUE;
+ }
+
+ g_propagate_error (error, deserialise_error);
+ return FALSE;
+ }
+
+ return TRUE;
}
-gchar *
-almanah_entry_get_content (AlmanahEntry *self)
+void
+almanah_entry_set_content (AlmanahEntry *self, GtkTextBuffer *text_buffer)
{
- return g_strdup (self->priv->content);
+ GtkTextIter start, end;
+ GdkAtom format_atom;
+ AlmanahEntryPrivate *priv = self->priv;
+
+ /* Update our cached empty status */
+ self->priv->is_empty = (gtk_text_buffer_get_char_count (text_buffer) == 0) ? TRUE : FALSE;
+
+ g_free (priv->data);
+
+ gtk_text_buffer_get_bounds (text_buffer, &start, &end);
+ format_atom = gtk_text_buffer_register_serialize_tagset (text_buffer, PACKAGE_NAME);
+ priv->data = gtk_text_buffer_serialize (text_buffer, text_buffer,
+ format_atom,
+ &start, &end,
+ &(priv->length));
}
/* NOTE: Designed for use on the stack */
@@ -199,5 +253,8 @@
gboolean
almanah_entry_is_empty (AlmanahEntry *self)
{
- return (self->priv->content == NULL || self->priv->content[0] == '\0') ? TRUE : FALSE;
+ return (self->priv->is_empty == TRUE ||
+ self->priv->length == 0 ||
+ self->priv->data == NULL ||
+ self->priv->data[0] == '\0') ? TRUE : FALSE;
}
Modified: trunk/src/entry.h
==============================================================================
--- trunk/src/entry.h (original)
+++ trunk/src/entry.h Sun Oct 19 11:08:00 2008
@@ -54,8 +54,10 @@
GType almanah_entry_get_type (void);
AlmanahEntry *almanah_entry_new (GDate *date);
-void almanah_entry_set_content (AlmanahEntry *self, const gchar *content);
-gchar *almanah_entry_get_content (AlmanahEntry *self);
+const guint8 *almanah_entry_get_data (AlmanahEntry *self, gsize *length);
+void almanah_entry_set_data (AlmanahEntry *self, const guint8 *data, gsize length);
+gboolean almanah_entry_get_content (AlmanahEntry *self, GtkTextBuffer *text_buffer, GError **error);
+void almanah_entry_set_content (AlmanahEntry *self, GtkTextBuffer *text_buffer);
void almanah_entry_get_date (AlmanahEntry *self, GDate *date);
AlmanahEntryEditability almanah_entry_get_editability (AlmanahEntry *self);
gboolean almanah_entry_is_empty (AlmanahEntry *self);
Modified: trunk/src/main-window.c
==============================================================================
--- trunk/src/main-window.c (original)
+++ trunk/src/main-window.c Sun Oct 19 11:08:00 2008
@@ -215,8 +215,6 @@
static void
save_current_entry (AlmanahMainWindow *self)
{
- GtkTextIter start_iter, end_iter;
- gchar *entry_text;
gboolean entry_exists, entry_is_empty;
GDate date;
AlmanahMainWindowPrivate *priv = self->priv;
@@ -231,18 +229,9 @@
return;
/* Save the entry */
- gtk_text_buffer_get_bounds (priv->entry_buffer, &start_iter, &end_iter);
- entry_text = gtk_text_buffer_get_text (priv->entry_buffer, &start_iter, &end_iter, FALSE);
- almanah_entry_set_content (priv->current_entry, entry_text);
- g_free (entry_text);
-
+ almanah_entry_set_content (priv->current_entry, priv->entry_buffer);
gtk_text_buffer_set_modified (priv->entry_buffer, FALSE);
- /* TODO: Serialise the buffer contents instead of just grabbing the text, so we can
- * keep tags between saves. Could use gtk_text_buffer_register_serialize_tagset() et al
- * for this, but could also add a more general framework for serialisation, which would aid
- * output/export to other formats from the program. */
-
almanah_entry_get_date (priv->current_entry, &date);
editability = almanah_entry_get_editability (priv->current_entry);
entry_exists = almanah_storage_manager_entry_exists (diary->storage_manager, &date);
@@ -309,10 +298,12 @@
gtk_widget_destroy (dialog);
}
+ /* Store the entry! */
+ almanah_storage_manager_set_entry (diary->storage_manager, priv->current_entry);
+
/* Mark the day on the calendar if the entry was non-empty (and deleted)
* and update the state of the add link button. */
- if (almanah_storage_manager_set_entry (diary->storage_manager, priv->current_entry) == FALSE) {
- /* TODO: This sort of thing should be done by connecting to signals from the storage manager */
+ if (entry_is_empty == TRUE) {
gtk_calendar_unmark_day (priv->calendar, g_date_get_day (&date));
gtk_widget_set_sensitive (GTK_WIDGET (priv->add_button), FALSE);
@@ -569,7 +560,7 @@
mw_about_activate_cb (GtkAction *action, AlmanahMainWindow *main_window)
{
gchar *license, *description;
- guint entry_count, link_count, character_count;
+ guint entry_count, link_count;
const gchar *authors[] =
{
@@ -595,11 +586,10 @@
_(license_parts[2]),
NULL);
- almanah_storage_manager_get_statistics (diary->storage_manager, &entry_count, &link_count, &character_count);
- description = g_strdup_printf (_("A helpful diary keeper, storing %u entries with %u links and a total of %u characters."),
+ almanah_storage_manager_get_statistics (diary->storage_manager, &entry_count, &link_count);
+ description = g_strdup_printf (_("A helpful diary keeper, storing %u entries and %u links."),
entry_count,
- link_count,
- character_count);
+ link_count);
gtk_show_about_dialog (GTK_WINDOW (main_window),
"version", VERSION,
@@ -677,23 +667,37 @@
gtk_text_view_set_editable (priv->entry_view, almanah_entry_get_editability (priv->current_entry) != ALMANAH_ENTRY_FUTURE ? TRUE : FALSE);
gtk_text_buffer_set_modified (priv->entry_buffer, FALSE);
+ /* Prepare for the possibility of failure --- do as much of the general interface changes as possible first */
+ gtk_list_store_clear (priv->link_store);
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->remove_button), FALSE); /* Only sensitive if something's selected */
+ gtk_action_set_sensitive (priv->remove_action, FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->view_button), FALSE);
+ gtk_widget_set_sensitive (GTK_WIDGET (priv->add_button), FALSE);
+ gtk_action_set_sensitive (priv->add_action, FALSE);
+
if (almanah_entry_is_empty (priv->current_entry) == FALSE) {
- gchar *entry_content = almanah_entry_get_content (priv->current_entry);
- gtk_text_buffer_set_text (priv->entry_buffer, entry_content, -1);
- g_free (entry_content);
+ GError *error = NULL;
+
+ gtk_text_buffer_set_text (priv->entry_buffer, "", 0);
+ if (almanah_entry_get_content (priv->current_entry, priv->entry_buffer, &error) == FALSE) {
+ gchar *error_message = g_strdup_printf (_("The entry content could not be loaded: %s"), error->message);
+ diary_interface_error (error_message, NULL);
+ g_free (error_message);
+ g_error_free (error);
+
+ /* Make sure the interface is left in a decent state before we return */
+ gtk_text_view_set_editable (priv->entry_view, FALSE);
+
+ return;
+ }
gtk_widget_set_sensitive (GTK_WIDGET (priv->add_button), TRUE);
gtk_action_set_sensitive (priv->add_action, TRUE);
} else {
+ /* Set the buffer to be empty */
gtk_text_buffer_set_text (priv->entry_buffer, "", -1);
- gtk_widget_set_sensitive (GTK_WIDGET (priv->add_button), FALSE);
- gtk_action_set_sensitive (priv->add_action, FALSE);
}
- gtk_widget_set_sensitive (GTK_WIDGET (priv->remove_button), FALSE); /* Only sensitive if something's selected */
- gtk_action_set_sensitive (priv->remove_action, FALSE);
- gtk_widget_set_sensitive (GTK_WIDGET (priv->view_button), FALSE);
-
#ifdef ENABLE_SPELL_CHECKING
/* Ensure the spell-checking is updated */
gtkspell = gtkspell_get_from_text_view (priv->entry_view);
@@ -702,7 +706,6 @@
#endif /* ENABLE_SPELL_CHECKING */
/* List the entry's links */
- gtk_list_store_clear (priv->link_store);
links = almanah_storage_manager_get_entry_links (diary->storage_manager, &calendar_date);
i = 0;
Modified: trunk/src/printing.c
==============================================================================
--- trunk/src/printing.c (original)
+++ trunk/src/printing.c Sun Oct 19 11:08:00 2008
@@ -30,6 +30,7 @@
#define MAX_ORPHANS 3 /* maximum number of orphan lines to be forced to the next page */
typedef struct {
+ GtkTextBuffer *buffer;
GDate *start_date;
GDate *end_date;
GDate *current_date;
@@ -40,6 +41,197 @@
gdouble y;
} DiaryPrintOperation;
+/* Adapted from code in GtkSourceView's gtksourceprintcompositor.c, previously LGPL >= 2.1
+ * Copyright (C) 2000, 2001 Chema Celorio
+ * Copyright (C) 2003 Gustavo GirÃldez
+ * Copyright (C) 2004 Red Hat, Inc.
+ * Copyright (C) 2001-2007 Paolo Maggi
+ * Copyright (C) 2008 Paolo Maggi, Paolo Borelli and Yevgen Muntyan */
+static GSList *
+get_iter_attrs (GtkTextIter *iter, GtkTextIter *limit)
+{
+ GSList *attrs = NULL;
+ GSList *tags;
+ PangoAttribute *bg = NULL, *fg = NULL, *style = NULL, *ul = NULL;
+ PangoAttribute *weight = NULL, *st = NULL;
+
+ tags = gtk_text_iter_get_tags (iter);
+ gtk_text_iter_forward_to_tag_toggle (iter, NULL);
+
+ if (gtk_text_iter_compare (iter, limit) > 0)
+ *iter = *limit;
+
+ while (tags)
+ {
+ GtkTextTag *tag;
+ gboolean bg_set, fg_set, style_set, ul_set, weight_set, st_set;
+
+ tag = tags->data;
+ tags = g_slist_delete_link (tags, tags);
+
+ g_object_get (tag,
+ "background-set", &bg_set,
+ "foreground-set", &fg_set,
+ "style-set", &style_set,
+ "underline-set", &ul_set,
+ "weight-set", &weight_set,
+ "strikethrough-set", &st_set,
+ NULL);
+
+ if (bg_set)
+ {
+ GdkColor *color = NULL;
+ if (bg) pango_attribute_destroy (bg);
+ g_object_get (tag, "background-gdk", &color, NULL);
+ bg = pango_attr_background_new (color->red, color->green, color->blue);
+ gdk_color_free (color);
+ }
+
+ if (fg_set)
+ {
+ GdkColor *color = NULL;
+ if (fg) pango_attribute_destroy (fg);
+ g_object_get (tag, "foreground-gdk", &color, NULL);
+ fg = pango_attr_foreground_new (color->red, color->green, color->blue);
+ gdk_color_free (color);
+ }
+
+ if (style_set)
+ {
+ PangoStyle style_value;
+ if (style) pango_attribute_destroy (style);
+ g_object_get (tag, "style", &style_value, NULL);
+ style = pango_attr_style_new (style_value);
+ }
+
+ if (ul_set)
+ {
+ PangoUnderline underline;
+ if (ul) pango_attribute_destroy (ul);
+ g_object_get (tag, "underline", &underline, NULL);
+ ul = pango_attr_underline_new (underline);
+ }
+
+ if (weight_set)
+ {
+ PangoWeight weight_value;
+ if (weight) pango_attribute_destroy (weight);
+ g_object_get (tag, "weight", &weight_value, NULL);
+ weight = pango_attr_weight_new (weight_value);
+ }
+
+ if (st_set)
+ {
+ gboolean strikethrough;
+ if (st) pango_attribute_destroy (st);
+ g_object_get (tag, "strikethrough", &strikethrough, NULL);
+ st = pango_attr_strikethrough_new (strikethrough);
+ }
+ }
+
+ if (bg)
+ attrs = g_slist_prepend (attrs, bg);
+ if (fg)
+ attrs = g_slist_prepend (attrs, fg);
+ if (style)
+ attrs = g_slist_prepend (attrs, style);
+ if (ul)
+ attrs = g_slist_prepend (attrs, ul);
+ if (weight)
+ attrs = g_slist_prepend (attrs, weight);
+ if (st)
+ attrs = g_slist_prepend (attrs, st);
+
+ return attrs;
+}
+
+/* Adapted from code in GtkSourceView's gtksourceprintcompositor.c, previously LGPL >= 2.1
+ * Copyright (C) 2000, 2001 Chema Celorio
+ * Copyright (C) 2003 Gustavo GirÃldez
+ * Copyright (C) 2004 Red Hat, Inc.
+ * Copyright (C) 2001-2007 Paolo Maggi
+ * Copyright (C) 2008 Paolo Maggi, Paolo Borelli and Yevgen Muntyan */
+static gboolean
+is_empty_line (const gchar *text)
+{
+ if (*text != '\0') {
+ const gchar *p;
+
+ for (p = text; p != NULL; p = g_utf8_next_char (p)) {
+ if (!g_unichar_isspace (*p))
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Adapted from code in GtkSourceView's gtksourceprintcompositor.c, previously LGPL >= 2.1
+ * Copyright (C) 2000, 2001 Chema Celorio
+ * Copyright (C) 2003 Gustavo GirÃldez
+ * Copyright (C) 2004 Red Hat, Inc.
+ * Copyright (C) 2001-2007 Paolo Maggi
+ * Copyright (C) 2008 Paolo Maggi, Paolo Borelli and Yevgen Muntyan */
+static void
+lay_out_entry (PangoLayout *layout, GtkTextIter *start, GtkTextIter *end)
+{
+ gchar *text;
+ PangoAttrList *attr_list = NULL;
+ GtkTextIter segm_start, segm_end;
+ int start_index;
+
+ text = gtk_text_iter_get_slice (start, end);
+
+ /* If it is an empty line (or it just contains tabs) pango has problems:
+ * see for instance comment #22 and #23 on bug #143874 and bug #457990.
+ * We just hack around it by inserting a space... not elegant but
+ * works :-) */
+ if (gtk_text_iter_ends_line (start) || is_empty_line (text)) {
+ pango_layout_set_text (layout, " ", 1);
+ g_free (text);
+ return;
+ }
+
+ pango_layout_set_text (layout, text, -1);
+ g_free (text);
+
+ segm_start = *start;
+ start_index = gtk_text_iter_get_line_index (start);
+
+ while (gtk_text_iter_compare (&segm_start, end) < 0) {
+ GSList *attrs;
+ int si, ei;
+
+ segm_end = segm_start;
+ attrs = get_iter_attrs (&segm_end, end);
+ if (attrs) {
+ si = gtk_text_iter_get_line_index (&segm_start) - start_index;
+ ei = gtk_text_iter_get_line_index (&segm_end) - start_index;
+ }
+
+ while (attrs) {
+ PangoAttribute *a = attrs->data;
+
+ a->start_index = si;
+ a->end_index = ei;
+
+ if (!attr_list)
+ attr_list = pango_attr_list_new ();
+
+ pango_attr_list_insert (attr_list, a);
+
+ attrs = g_slist_delete_link (attrs, attrs);
+ }
+
+ segm_start = segm_end;
+ }
+
+ pango_layout_set_attributes (layout, attr_list);
+
+ if (attr_list)
+ pango_attr_list_unref (attr_list);
+}
+
/* TRUE if the entry was printed OK on the current page, FALSE if it needs to be moved to a new page/is split across pages */
static gboolean
print_entry (GtkPrintOperation *operation, GtkPrintContext *context, DiaryPrintOperation *diary_operation)
@@ -77,16 +269,21 @@
entry = almanah_storage_manager_get_entry (diary->storage_manager, diary_operation->current_date);
- if (almanah_entry_is_empty (entry)) {
+ if (entry == NULL || almanah_entry_is_empty (entry)) {
gchar *entry_text = g_strdup_printf ("<i>%s</i>", _("No entry for this date."));
pango_layout_set_markup (entry_layout, entry_text, -1);
} else {
- gchar *entry_text = almanah_entry_get_content (entry);
- pango_layout_set_text (entry_layout, entry_text, -1);
- g_free (entry_text);
+ GtkTextIter start, end;
+
+ gtk_text_buffer_set_text (diary_operation->buffer, "", 0);
+ if (almanah_entry_get_content (entry, diary_operation->buffer, NULL) == TRUE) {
+ gtk_text_buffer_get_bounds (diary_operation->buffer, &start, &end);
+ lay_out_entry (entry_layout, &start, &end);
+ }
}
- g_object_unref (entry);
+ if (entry != NULL)
+ g_object_unref (entry);
/* Check we're not orphaning things */
entry_line = pango_layout_get_line_readonly (entry_layout, MIN (pango_layout_get_line_count (entry_layout), diary_operation->current_line + MAX_ORPHANS) - 1);
@@ -244,11 +441,20 @@
/* Start date */
gtk_calendar_get_date (diary_operation->start_calendar, &year, &month, &day);
diary_operation->start_date = g_date_new_dmy (day, month + 1, year);
- diary_operation->current_date = g_memdup (diary_operation->start_date, sizeof (*diary_operation->start_date));
/* End date */
gtk_calendar_get_date (diary_operation->end_calendar, &year, &month, &day);
diary_operation->end_date = g_date_new_dmy (day, month + 1, year);
+
+ /* Ensure they're in order */
+ if (g_date_compare (diary_operation->start_date, diary_operation->end_date) > 0) {
+ GDate *temp;
+ temp = diary_operation->start_date;
+ diary_operation->start_date = diary_operation->end_date;
+ diary_operation->end_date = temp;
+ }
+
+ diary_operation->current_date = g_memdup (diary_operation->start_date, sizeof (*(diary_operation->start_date)));
}
void
@@ -265,6 +471,17 @@
diary_operation.y = 0;
diary_operation.current_line = 0;
+ diary_operation.buffer = gtk_text_buffer_new (NULL);
+ gtk_text_buffer_create_tag (diary_operation.buffer, "bold",
+ "weight", PANGO_WEIGHT_BOLD,
+ NULL);
+ gtk_text_buffer_create_tag (diary_operation.buffer, "italic",
+ "style", PANGO_STYLE_ITALIC,
+ NULL);
+ gtk_text_buffer_create_tag (diary_operation.buffer, "underline",
+ "underline", PANGO_UNDERLINE_SINGLE,
+ NULL);
+
if (settings != NULL)
gtk_print_operation_set_print_settings (operation, settings);
@@ -285,6 +502,7 @@
}
if (diary_operation.current_date != NULL) {
+ g_object_unref (diary_operation.buffer);
g_date_free (diary_operation.current_date);
g_date_free (diary_operation.start_date);
g_date_free (diary_operation.end_date);
Modified: trunk/src/storage-manager.c
==============================================================================
--- trunk/src/storage-manager.c (original)
+++ trunk/src/storage-manager.c Sun Oct 19 11:08:00 2008
@@ -596,16 +596,15 @@
}
gboolean
-almanah_storage_manager_get_statistics (AlmanahStorageManager *self, guint *entry_count, guint *link_count, guint *character_count)
+almanah_storage_manager_get_statistics (AlmanahStorageManager *self, guint *entry_count, guint *link_count)
{
AlmanahQueryResults *results;
*entry_count = 0;
- *character_count = 0;
*link_count = 0;
/* Get the number of entries and the number of letters */
- results = almanah_storage_manager_query (self, "SELECT COUNT (year), SUM (LENGTH (content)) FROM entries", NULL);
+ results = almanah_storage_manager_query (self, "SELECT COUNT (year) FROM entries", NULL);
if (results == NULL) {
return FALSE;
} else if (results->rows != 1) {
@@ -614,12 +613,9 @@
} else {
*entry_count = atoi (results->data[2]);
if (*entry_count == 0) {
- *character_count = 0;
*link_count = 0;
return TRUE;
}
-
- *character_count = atoi (results->data[3]);
}
almanah_storage_manager_free_results (results);
@@ -674,25 +670,37 @@
AlmanahEntry *
almanah_storage_manager_get_entry (AlmanahStorageManager *self, GDate *date)
{
- AlmanahQueryResults *results;
AlmanahEntry *entry;
+ sqlite3_stmt *statement;
- results = almanah_storage_manager_query (self, "SELECT content FROM entries WHERE year = %u AND month = %u AND day = %u", NULL,
- g_date_get_year (date),
- g_date_get_month (date),
- g_date_get_day (date));
-
- if (results == NULL)
+ /* It's necessary to avoid our nice SQLite interface and use the sqlite3 API directly here
+ * as we can't otherwise reliably bind the data blob to the query --- if we pass it in as
+ * a string, it gets cut off at the first nul character, which could occur anywhere in
+ * the blob. */
+
+ /* Prepare the statement */
+ if (sqlite3_prepare_v2 (self->priv->connection,
+ "SELECT content FROM entries WHERE year = ? AND month = ? AND day = ?", -1,
+ &statement, NULL) != SQLITE_OK) {
return NULL;
- if (results->rows != 1) {
- /* Invalid number of rows returned. */
- almanah_storage_manager_free_results (results);
+ }
+
+ /* Bind parameters */
+ sqlite3_bind_int (statement, 1, g_date_get_year (date));
+ sqlite3_bind_int (statement, 2, g_date_get_month (date));
+ sqlite3_bind_int (statement, 3, g_date_get_day (date));
+
+ /* Execute the statement */
+ if (sqlite3_step (statement) != SQLITE_ROW) {
+ sqlite3_finalize (statement);
return NULL;
}
+ /* Get the data */
entry = almanah_entry_new (date);
- almanah_entry_set_content (entry, results->data[1]);
- almanah_storage_manager_free_results (results);
+ almanah_entry_set_data (entry, sqlite3_column_blob (statement, 0), sqlite3_column_bytes (statement, 0));
+
+ sqlite3_finalize (statement);
return entry;
}
@@ -702,12 +710,11 @@
* @self: a #AlmanahStorageManager
* @entry: an #AlmanahEntry
*
- * Saves the specified @entry in the database. If the @entry
- * content is empty or %NULL, it will ask if the user wants to delete
- * the entry for that date. It will return %TRUE if the content is
- * non-empty, and %FALSE otherwise.
+ * Saves the specified @entry in the database synchronously.
+ * If the @entry's content is empty, it will delete @entry's rows
+ * in the database (as well as its links' rows).
*
- * Return value: %TRUE if the entry is non-empty
+ * Return value: %TRUE on success, %FALSE otherwise
**/
gboolean
almanah_storage_manager_set_entry (AlmanahStorageManager *self, AlmanahEntry *entry)
@@ -727,17 +734,40 @@
g_date_get_month (&date),
g_date_get_day (&date));
- return FALSE;
+ return TRUE;
} else {
- /* Update the entry */
- gchar *content = almanah_entry_get_content (entry);
+ const guint8 *data;
+ gsize length;
+ sqlite3_stmt *statement;
+
+ /* It's necessary to avoid our nice SQLite interface and use the sqlite3 API directly here
+ * as we can't otherwise reliably bind the data blob to the query --- if we pass it in as
+ * a string, it gets cut off at the first nul character, which could occur anywhere in
+ * the blob. */
+
+ /* Prepare the statement */
+ if (sqlite3_prepare_v2 (self->priv->connection,
+ "REPLACE INTO entries (year, month, day, content) VALUES (?, ?, ?, ?)", -1,
+ &statement, NULL) != SQLITE_OK) {
+ return FALSE;
+ }
+
+ /* Bind parameters */
+ sqlite3_bind_int (statement, 1, g_date_get_year (&date));
+ sqlite3_bind_int (statement, 2, g_date_get_month (&date));
+ sqlite3_bind_int (statement, 3, g_date_get_day (&date));
+
+ data = almanah_entry_get_data (entry, &length);
+ sqlite3_bind_blob (statement, 4, data, length, SQLITE_TRANSIENT);
+
+ /* Execute the statement */
+ if (sqlite3_step (statement) != SQLITE_DONE) {
+ sqlite3_finalize (statement);
+ return FALSE;
+ }
+
+ sqlite3_finalize (statement);
- almanah_storage_manager_query_async (self, "REPLACE INTO entries (year, month, day, content) VALUES (%u, %u, %u, '%q')", NULL, NULL, NULL,
- g_date_get_year (&date),
- g_date_get_month (&date),
- g_date_get_day (&date),
- content);
- g_free (content);
return TRUE;
}
}
@@ -763,6 +793,7 @@
AlmanahQueryResults *results;
guint i;
+ /* TODO: Won't really work with serialized data */
results = almanah_storage_manager_query (self, "SELECT day, month, year FROM entries WHERE content LIKE '%%%q%%'", NULL,
search_string);
Modified: trunk/src/storage-manager.h
==============================================================================
--- trunk/src/storage-manager.h (original)
+++ trunk/src/storage-manager.h Sun Oct 19 11:08:00 2008
@@ -76,7 +76,7 @@
void almanah_storage_manager_free_results (AlmanahQueryResults *results);
gboolean almanah_storage_manager_query_async (AlmanahStorageManager *self, const gchar *query, const AlmanahQueryCallback callback, gpointer user_data, GError **error, ...);
-gboolean almanah_storage_manager_get_statistics (AlmanahStorageManager *self, guint *entry_count, guint *link_count, guint *character_count);
+gboolean almanah_storage_manager_get_statistics (AlmanahStorageManager *self, guint *entry_count, guint *link_count);
gboolean almanah_storage_manager_entry_exists (AlmanahStorageManager *self, GDate *date);
AlmanahEntry *almanah_storage_manager_get_entry (AlmanahStorageManager *self, GDate *date);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]