1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
4
* Copyright (C) Philip Withnall 2011 <philip@tecnocode.co.uk>
6
* Almanah is free software: you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation, either version 3 of the License, or
9
* (at your option) any later version.
11
* Almanah is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with Almanah. If not, see <http://www.gnu.org/licenses/>.
22
#include <glib/gi18n.h>
26
#include "application.h"
27
#include "event-manager.h"
28
#include "import-export-dialog.h"
29
#include "main-window.h"
30
#include "preferences-dialog.h"
32
#include "search-dialog.h"
33
#include "storage-manager.h"
35
static void constructed (GObject *object);
36
static void dispose (GObject *object);
37
static void get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
38
static void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
40
static void startup (GApplication *application);
41
static void activate (GApplication *application);
42
static gint handle_command_line (GApplication *application, GApplicationCommandLine *command_line);
43
static void quit_main_loop (GApplication *application);
45
static void almanah_application_init_actions (AlmanahApplication *self);
47
/* GMenu application actions */
48
static void action_search_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
49
static void action_preferences_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
50
static void action_import_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
51
static void action_export_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
52
static void action_print_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
53
static void action_about_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
54
static void action_quit_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data);
56
struct _AlmanahApplicationPrivate {
60
AlmanahStorageManager *storage_manager;
61
AlmanahEventManager *event_manager;
63
AlmanahMainWindow *main_window;
65
GtkPrintSettings *print_settings;
66
GtkPageSetup *page_setup;
73
static GActionEntry app_entries[] = {
74
{"search", action_search_cb, NULL, NULL, NULL},
75
{"preferences", action_preferences_cb, NULL, NULL, NULL },
76
{"import", action_import_cb, NULL, NULL, NULL },
77
{"export", action_export_cb, NULL, NULL, NULL },
78
{"print", action_print_cb, NULL, NULL, NULL },
79
{"about", action_about_cb, NULL, NULL, NULL },
80
{"quit", action_quit_cb, NULL, NULL, NULL },
83
G_DEFINE_TYPE (AlmanahApplication, almanah_application, GTK_TYPE_APPLICATION)
86
almanah_application_class_init (AlmanahApplicationClass *klass)
88
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
89
GApplicationClass *gapplication_class = G_APPLICATION_CLASS (klass);
91
g_type_class_add_private (klass, sizeof (AlmanahApplicationPrivate));
93
gobject_class->constructed = constructed;
94
gobject_class->dispose = dispose;
95
gobject_class->get_property = get_property;
96
gobject_class->set_property = set_property;
98
gapplication_class->startup = startup;
99
gapplication_class->activate = activate;
100
gapplication_class->command_line = handle_command_line;
101
gapplication_class->quit_mainloop = quit_main_loop;
103
g_object_class_install_property (gobject_class, PROP_DEBUG,
104
g_param_spec_boolean ("debug",
105
"Debugging Mode", "Whether debugging mode is active.",
107
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
111
almanah_application_init (AlmanahApplication *self)
113
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ALMANAH_TYPE_APPLICATION, AlmanahApplicationPrivate);
114
self->priv->debug = FALSE;
118
constructed (GObject *object)
120
/* Set various properties up */
121
g_application_set_application_id (G_APPLICATION (object), "org.gnome.Almanah");
122
g_application_set_flags (G_APPLICATION (object), G_APPLICATION_HANDLES_COMMAND_LINE);
125
bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
126
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
127
textdomain (GETTEXT_PACKAGE);
129
g_set_application_name (_("Almanah Diary"));
130
gtk_window_set_default_icon_name ("almanah");
132
/* Chain up to the parent class */
133
G_OBJECT_CLASS (almanah_application_parent_class)->constructed (object);
137
dispose (GObject *object)
139
AlmanahApplicationPrivate *priv = ALMANAH_APPLICATION (object)->priv;
141
if (priv->main_window != NULL)
142
gtk_widget_destroy (GTK_WIDGET (priv->main_window));
143
priv->main_window = NULL;
145
if (priv->event_manager != NULL)
146
g_object_unref (priv->event_manager);
147
priv->event_manager = NULL;
149
if (priv->storage_manager != NULL)
150
g_object_unref (priv->storage_manager);
151
priv->storage_manager = NULL;
153
if (priv->settings != NULL)
154
g_object_unref (priv->settings);
155
priv->settings = NULL;
157
if (priv->page_setup != NULL)
158
g_object_unref (priv->page_setup);
159
priv->page_setup = NULL;
161
if (priv->print_settings != NULL)
162
g_object_unref (priv->print_settings);
163
priv->print_settings = NULL;
165
/* Chain up to the parent class */
166
G_OBJECT_CLASS (almanah_application_parent_class)->dispose (object);
170
get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
172
AlmanahApplicationPrivate *priv = ALMANAH_APPLICATION (object)->priv;
174
switch (property_id) {
176
g_value_set_boolean (value, priv->debug);
179
/* We don't have any other property... */
180
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
186
set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
188
AlmanahApplicationPrivate *priv = ALMANAH_APPLICATION (object)->priv;
190
switch (property_id) {
192
priv->debug = g_value_get_boolean (value);
195
/* We don't have any other property... */
196
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
202
debug_handler (const char *log_domain, GLogLevelFlags log_level, const char *message, AlmanahApplication *self)
204
/* Only display debug messages if we've been run with --debug */
205
if (self->priv->debug == TRUE) {
206
g_log_default_handler (log_domain, log_level, message, NULL);
211
startup (GApplication *application)
213
AlmanahApplicationPrivate *priv = ALMANAH_APPLICATION (application)->priv;
215
GError *error = NULL;
216
GtkCssProvider *style_provider;
220
G_APPLICATION_CLASS (almanah_application_parent_class)->startup (application);
222
/* Debug log handling */
223
g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, (GLogFunc) debug_handler, application);
226
priv->settings = g_settings_new ("org.gnome.almanah");
228
/* Ensure the DB directory exists */
229
if (g_file_test (g_get_user_data_dir (), G_FILE_TEST_IS_DIR) == FALSE) {
230
g_mkdir_with_parents (g_get_user_data_dir (), 0700);
234
db_filename = g_build_filename (g_get_user_data_dir (), "diary.db", NULL);
235
priv->storage_manager = almanah_storage_manager_new (db_filename, NULL);
236
g_free (db_filename);
238
g_settings_bind (priv->settings, "encryption-key", priv->storage_manager, "encryption-key",
239
G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_NO_SENSITIVITY);
241
if (almanah_storage_manager_connect (priv->storage_manager, &error) == FALSE) {
242
GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
243
_("Error opening database"));
244
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
245
gtk_dialog_run (GTK_DIALOG (dialog));
246
gtk_widget_destroy (dialog);
252
/* Create the event manager */
253
priv->event_manager = almanah_event_manager_new ();
255
/* Set up printing objects */
256
priv->print_settings = gtk_print_settings_new ();
258
#ifdef GTK_PRINT_SETTINGS_OUTPUT_BASENAME
259
/* Translators: This is the default name of the PDF/PS/SVG file the diary is printed to if "Print to File" is chosen. */
260
gtk_print_settings_set (priv->print_settings, GTK_PRINT_SETTINGS_OUTPUT_BASENAME, _("Diary"));
263
priv->page_setup = gtk_page_setup_new ();
265
/* Load GMenu application actions */
266
almanah_application_init_actions (ALMANAH_APPLICATION (application));
268
css_path = g_build_filename (almanah_get_css_path (), "almanah.css", NULL);
269
style_provider = gtk_css_provider_new ();
270
if (!gtk_css_provider_load_from_path (style_provider, css_path, NULL)) {
271
/* Error loading the CSS */
272
g_warning (_("Couldn't load the CSS file '%s'. The interface might not be styled correctly"), css_path);
273
g_error_free (error);
275
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (style_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
278
g_object_unref (style_provider);
281
/* Nullify our pointer to the main window when it gets destroyed (e.g. when we quit) so that we don't then try
282
* to destroy it again in dispose(). */
284
main_window_destroy_cb (AlmanahMainWindow *main_window, AlmanahApplication *self)
286
self->priv->main_window = NULL;
290
activate (GApplication *application)
292
AlmanahApplication *self = ALMANAH_APPLICATION (application);
293
AlmanahApplicationPrivate *priv = self->priv;
295
/* Create the interface */
296
if (priv->main_window == NULL) {
297
priv->main_window = almanah_main_window_new (self);
298
gtk_widget_show_all (GTK_WIDGET (priv->main_window));
299
g_signal_connect (priv->main_window, "destroy", (GCallback) main_window_destroy_cb, application);
302
/* Bring it to the foreground */
303
gtk_window_present (GTK_WINDOW (priv->main_window));
307
handle_command_line (GApplication *application, GApplicationCommandLine *command_line)
309
AlmanahApplicationPrivate *priv = ALMANAH_APPLICATION (application)->priv;
310
GOptionContext *context;
311
GError *error = NULL;
312
gchar **args, **argv;
313
gint argc, i, status = 0;
315
const GOptionEntry options[] = {
316
{ "debug", 0, 0, G_OPTION_ARG_NONE, &(priv->debug), N_("Enable debug mode"), NULL },
320
args = g_application_command_line_get_arguments (command_line, &argc);
322
/* We have to make an extra copy of the array, since g_option_context_parse() assumes that it can remove strings from the array without
324
argv = g_new (gchar*, argc + 1);
325
for (i = 0; i <= argc; i++) {
330
context = g_option_context_new (NULL);
331
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
333
g_option_context_set_summary (context, _("Manage your diary. Only one instance of the program may be open at any time."));
335
g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE);
336
g_option_context_add_group (context, gtk_get_option_group (TRUE));
338
if (g_option_context_parse (context, &argc, &argv, &error) == TRUE) {
339
/* Activate the remote instance */
340
g_application_activate (application);
344
g_application_command_line_printerr (command_line, _("Command line options could not be parsed: %s\n"), error->message);
345
g_error_free (error);
350
g_option_context_free (context);
359
storage_manager_disconnected_cb (AlmanahStorageManager *self, const gchar *gpgme_error_message, const gchar *warning_message, GApplication *application)
361
if (gpgme_error_message != NULL || warning_message != NULL) {
362
GtkWidget *dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
363
_("Error encrypting database"));
365
if (gpgme_error_message != NULL && warning_message != NULL)
366
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s %s", warning_message, gpgme_error_message);
367
else if (gpgme_error_message != NULL)
368
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", gpgme_error_message);
370
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", warning_message);
372
gtk_dialog_run (GTK_DIALOG (dialog));
373
gtk_widget_destroy (dialog);
376
/* Chain up to the parent class */
377
G_APPLICATION_CLASS (almanah_application_parent_class)->quit_mainloop (application);
381
quit_main_loop (GApplication *application)
383
AlmanahApplicationPrivate *priv = ALMANAH_APPLICATION (application)->priv;
385
/* This would normally result in gtk_main_quit() being called, but we need to close the database connection first. */
386
g_signal_connect (priv->storage_manager, "disconnected", (GCallback) storage_manager_disconnected_cb, application);
387
almanah_storage_manager_disconnect (priv->storage_manager, NULL);
389
/* Quitting is actually done in storage_manager_disconnected_cb, which is called once
390
* the storage manager has encrypted the DB and disconnected from it. */
394
almanah_application_init_actions (AlmanahApplication *self)
397
GError *error = NULL;
398
const gchar *interface_filename = almanah_get_interface_app_menu_filename ();
400
g_action_map_add_action_entries (G_ACTION_MAP (self), app_entries, G_N_ELEMENTS (app_entries), self);
402
builder = gtk_builder_new ();
403
if (gtk_builder_add_from_file (builder, interface_filename, &error) == FALSE) {
405
GtkWidget *dialog = gtk_message_dialog_new (NULL,
409
_("UI file \"%s\" could not be loaded"), interface_filename);
410
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
411
gtk_dialog_run (GTK_DIALOG (dialog));
412
gtk_widget_destroy (dialog);
414
g_error_free (error);
415
g_object_unref (builder);
420
gtk_builder_set_translation_domain (builder, GETTEXT_PACKAGE);
421
gtk_application_set_app_menu (GTK_APPLICATION (self), G_MENU_MODEL (gtk_builder_get_object (builder, "almanah_app_menu")));
423
#ifndef ENABLE_ENCRYPTION
424
#ifndef ENABLE_SPELL_CHECKING
425
/* Remove the "Preferences" entry from the menu */
426
g_action_map_remove_action (G_ACTION_MAP (self), "preferences");
427
#endif /* !ENABLE_SPELL_CHECKING */
428
#endif /* !ENABLE_ENCRYPTION */
430
g_object_unref (builder);
434
action_search_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
436
AlmanahApplication *application;
437
AlmanahSearchDialog *dialog = almanah_search_dialog_new ();
439
application = ALMANAH_APPLICATION (user_data);
440
gtk_window_set_application (GTK_WINDOW (dialog), GTK_APPLICATION (application));
441
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (application->priv->main_window));
442
gtk_widget_show (GTK_WIDGET (dialog));
443
gtk_dialog_run (GTK_DIALOG (dialog));
445
gtk_widget_destroy (GTK_WIDGET (dialog));
449
action_preferences_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
451
#if defined(ENABLE_ENCRYPTION) || defined(ENABLE_SPELL_CHECKING)
452
AlmanahApplication *application;
454
AlmanahPreferencesDialog *dialog;
456
application = ALMANAH_APPLICATION (user_data);
457
settings = almanah_application_dup_settings (application);
458
dialog = almanah_preferences_dialog_new (settings);
459
g_object_unref (settings);
461
gtk_widget_show_all (GTK_WIDGET (dialog));
462
gtk_dialog_run (GTK_DIALOG (dialog));
464
gtk_widget_destroy (GTK_WIDGET (dialog));
465
#endif /* ENABLE_ENCRYPTION || ENABLE_SPELL_CHECKING */
469
action_import_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
471
AlmanahApplication *application;
472
AlmanahStorageManager *storage_manager;
475
application = ALMANAH_APPLICATION (user_data);
476
storage_manager = almanah_application_dup_storage_manager (application);
477
dialog = GTK_WIDGET (almanah_import_export_dialog_new (storage_manager, TRUE));
478
g_object_unref (storage_manager);
480
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (application->priv->main_window));
481
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
483
/* The dialog destroys itself once done */
484
gtk_widget_show_all (dialog);
488
action_export_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
490
AlmanahApplication *application;
491
AlmanahStorageManager *storage_manager;
494
application = ALMANAH_APPLICATION (user_data);
495
storage_manager = almanah_application_dup_storage_manager (application);
496
dialog = GTK_WIDGET (almanah_import_export_dialog_new (storage_manager, FALSE));
497
g_object_unref (storage_manager);
499
gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (application->priv->main_window));
500
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
502
/* The dialog destroys itself once done */
503
gtk_widget_show_all (dialog);
507
action_print_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
509
AlmanahApplication *application;
510
AlmanahStorageManager *storage_manager;
512
application = ALMANAH_APPLICATION (user_data);
513
storage_manager = almanah_application_dup_storage_manager (application);
514
almanah_print_entries (FALSE, GTK_WINDOW (application->priv->main_window), &(application->priv->page_setup), &(application->priv->print_settings), storage_manager);
515
g_object_unref (storage_manager);
519
action_about_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
521
AlmanahApplication *application;
522
AlmanahStorageManager *storage_manager;
523
gchar *license, *description;
526
const gchar *authors[] =
528
"Philip Withnall <philip@tecnocode.co.uk>",
531
const gchar *license_parts[] = {
532
N_("Almanah is free software: you can redistribute it and/or modify "
533
"it under the terms of the GNU General Public License as published by "
534
"the Free Software Foundation, either version 3 of the License, or "
535
"(at your option) any later version."),
536
N_("Almanah is distributed in the hope that it will be useful, "
537
"but WITHOUT ANY WARRANTY; without even the implied warranty of "
538
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
539
"GNU General Public License for more details."),
540
N_("You should have received a copy of the GNU General Public License "
541
"along with Almanah. If not, see <http://www.gnu.org/licenses/>."),
544
license = g_strjoin ("\n\n",
550
application = ALMANAH_APPLICATION (user_data);
551
storage_manager = almanah_application_dup_storage_manager (application);
552
almanah_storage_manager_get_statistics (storage_manager, &entry_count);
553
g_object_unref (storage_manager);
555
description = g_strdup_printf (_("A helpful diary keeper, storing %u entries."), entry_count);
557
gtk_show_about_dialog (GTK_WINDOW (application->priv->main_window),
559
"copyright", _("Copyright \xc2\xa9 2008-2009 Philip Withnall"),
560
"comments", description,
562
/* Translators: please include your names here to be credited for your hard work!
564
* "Translator name 1 <translator@email.address>\n"
565
* "Translator name 2 <translator2@email.address>"
567
"translator-credits", _("translator-credits"),
568
"logo-icon-name", "almanah",
570
"wrap-license", TRUE,
571
"website-label", _("Almanah Website"),
572
"website", "http://live.gnome.org/Almanah_Diary",
576
g_free (description);
580
action_quit_cb (GSimpleAction *action, GVariant *parameter, gpointer user_data)
582
AlmanahMainWindow *main_window;
584
main_window = ALMANAH_APPLICATION (user_data)->priv->main_window;
586
/* Hide the window to make things look faster */
587
gtk_widget_hide (GTK_WIDGET (main_window));
589
almanah_main_window_save_current_entry (main_window, TRUE);
590
gtk_widget_destroy (GTK_WIDGET (main_window));
594
almanah_application_new (void)
596
return ALMANAH_APPLICATION (g_object_new (ALMANAH_TYPE_APPLICATION, NULL));
600
almanah_application_get_debug (AlmanahApplication *self)
602
g_return_val_if_fail (ALMANAH_IS_APPLICATION (self), FALSE);
603
return self->priv->debug;
606
AlmanahEventManager *
607
almanah_application_dup_event_manager (AlmanahApplication *self)
609
g_return_val_if_fail (ALMANAH_IS_APPLICATION (self), NULL);
610
return g_object_ref (self->priv->event_manager);
613
AlmanahStorageManager *
614
almanah_application_dup_storage_manager (AlmanahApplication *self)
616
g_return_val_if_fail (ALMANAH_IS_APPLICATION (self), NULL);
617
return g_object_ref (self->priv->storage_manager);
621
almanah_application_dup_settings (AlmanahApplication *self)
623
g_return_val_if_fail (ALMANAH_IS_APPLICATION (self), NULL);
624
return g_object_ref (self->priv->settings);