summaryrefslogtreecommitdiff
path: root/src/ui.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui.c')
-rw-r--r--src/ui.c1648
1 files changed, 1648 insertions, 0 deletions
diff --git a/src/ui.c b/src/ui.c
new file mode 100644
index 0000000..92e83c7
--- /dev/null
+++ b/src/ui.c
@@ -0,0 +1,1648 @@
+/*
+ * Copyright (C) 2009 Canonical Ltd.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This program is free software: you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License as published by the Free Software
+ * Foundation, either version 3 of the License, or (at your option) any later
+ * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
+ * license.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <math.h>
+#include <unistd.h> // TEMP: Needed for close() in get_temporary_filename()
+
+#include "ui.h"
+#include "book-view.h"
+
+
+#define DEFAULT_TEXT_DPI 150
+#define DEFAULT_PHOTO_DPI 300
+
+
+enum {
+ START_SCAN,
+ STOP_SCAN,
+ SAVE,
+ EMAIL,
+ QUIT,
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0, };
+
+
+struct SimpleScanPrivate
+{
+ GConfClient *client;
+
+ GtkBuilder *builder;
+
+ GtkWidget *window;
+ GtkWidget *preview_box, *preview_area, *preview_scroll;
+ GtkWidget *page_delete_menuitem, *crop_rotate_menuitem;
+ GtkWidget *stop_menuitem, *stop_toolbutton;
+
+ GtkWidget *text_toolbar_menuitem, *text_menu_menuitem;
+ GtkWidget *photo_toolbar_menuitem, *photo_menu_menuitem;
+
+ GtkWidget *authorize_dialog;
+ GtkWidget *authorize_label;
+ GtkWidget *username_entry, *password_entry;
+
+ GtkWidget *preferences_dialog;
+ GtkWidget *device_combo, *text_dpi_combo, *photo_dpi_combo, *page_side_combo, *paper_size_combo;
+ GtkTreeModel *device_model, *text_dpi_model, *photo_dpi_model, *page_side_model, *paper_size_model;
+ gboolean setting_devices, user_selected_device;
+
+ Book *book;
+ BookView *book_view;
+ gboolean updating_page_menu;
+ gint default_page_width, default_page_height, default_page_dpi;
+ Orientation default_page_orientation;
+
+ gboolean have_device_list;
+
+ gchar *document_hint;
+
+ gchar *default_file_name;
+ gboolean scanning;
+
+ gint window_width, window_height;
+ gboolean window_is_maximized;
+};
+
+G_DEFINE_TYPE (SimpleScan, ui, G_TYPE_OBJECT);
+
+static struct
+{
+ const gchar *key;
+ Orientation orientation;
+} orientation_keys[] =
+{
+ { "top-to-bottom", TOP_TO_BOTTOM },
+ { "bottom-to-top", BOTTOM_TO_TOP },
+ { "left-to-right", LEFT_TO_RIGHT },
+ { "right-to-left", RIGHT_TO_LEFT },
+ { NULL, 0 }
+};
+
+
+static gboolean
+find_scan_device (SimpleScan *ui, const char *device, GtkTreeIter *iter)
+{
+ gboolean have_iter = FALSE;
+
+ if (gtk_tree_model_get_iter_first (ui->priv->device_model, iter)) {
+ do {
+ gchar *d;
+ gtk_tree_model_get (ui->priv->device_model, iter, 0, &d, -1);
+ if (strcmp (d, device) == 0)
+ have_iter = TRUE;
+ g_free (d);
+ } while (!have_iter && gtk_tree_model_iter_next (ui->priv->device_model, iter));
+ }
+
+ return have_iter;
+}
+
+
+void
+ui_set_default_file_name (SimpleScan *ui, const gchar *default_file_name)
+{
+ g_free (ui->priv->default_file_name);
+ ui->priv->default_file_name = g_strdup (default_file_name);
+}
+
+
+void
+ui_authorize (SimpleScan *ui, const gchar *resource, gchar **username, gchar **password)
+{
+ GString *description;
+
+ description = g_string_new ("");
+ g_string_printf (description,
+ /* Label in authorization dialog. '%s' is replaced with the name of the resource requesting authorization */
+ _("Username and password required to access '%s'"),
+ resource);
+
+ gtk_entry_set_text (GTK_ENTRY (ui->priv->username_entry), *username ? *username : "");
+ gtk_entry_set_text (GTK_ENTRY (ui->priv->password_entry), "");
+ gtk_label_set_text (GTK_LABEL (ui->priv->authorize_label), description->str);
+ g_string_free (description, TRUE);
+
+ gtk_widget_show (ui->priv->authorize_dialog);
+ gtk_dialog_run (GTK_DIALOG (ui->priv->authorize_dialog));
+ gtk_widget_hide (ui->priv->authorize_dialog);
+
+ *username = g_strdup (gtk_entry_get_text (GTK_ENTRY (ui->priv->username_entry)));
+ *password = g_strdup (gtk_entry_get_text (GTK_ENTRY (ui->priv->password_entry)));
+}
+
+
+void device_combo_changed_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+device_combo_changed_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (ui->priv->setting_devices)
+ return;
+ ui->priv->user_selected_device = TRUE;
+}
+
+
+void
+ui_set_scan_devices (SimpleScan *ui, GList *devices)
+{
+ GList *d;
+ gboolean have_selection = FALSE;
+ gint index;
+ GtkTreeIter iter;
+
+ ui->priv->setting_devices = TRUE;
+
+ /* If the user hasn't chosen a scanner choose the best available one */
+ if (ui->priv->user_selected_device)
+ have_selection = gtk_combo_box_get_active (GTK_COMBO_BOX (ui->priv->device_combo)) >= 0;
+
+ /* Add new devices */
+ index = 0;
+ for (d = devices; d; d = d->next) {
+ ScanDevice *device = (ScanDevice *) d->data;
+ gint n_delete = -1;
+
+ /* Find if already exists */
+ if (gtk_tree_model_iter_nth_child (ui->priv->device_model, &iter, NULL, index)) {
+ gint i = 0;
+ do {
+ gchar *name;
+ gboolean matched;
+
+ gtk_tree_model_get (ui->priv->device_model, &iter, 0, &name, -1);
+ matched = strcmp (name, device->name) == 0;
+ g_free (name);
+
+ if (matched) {
+ n_delete = i;
+ break;
+ }
+ i++;
+ } while (gtk_tree_model_iter_next (ui->priv->device_model, &iter));
+ }
+
+ /* If exists, remove elements up to this one */
+ if (n_delete >= 0) {
+ gint i;
+
+ for (i = 0; i < n_delete; i++) {
+ gtk_tree_model_iter_nth_child (ui->priv->device_model, &iter, NULL, index);
+ gtk_list_store_remove (GTK_LIST_STORE (ui->priv->device_model), &iter);
+ }
+ }
+ else {
+ gtk_list_store_insert (GTK_LIST_STORE (ui->priv->device_model), &iter, index);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->device_model), &iter, 0, device->name, 1, device->label, -1);
+ }
+ index++;
+ }
+
+ /* Remove any remaining devices */
+ while (gtk_tree_model_iter_nth_child (ui->priv->device_model, &iter, NULL, index))
+ gtk_list_store_remove (GTK_LIST_STORE (ui->priv->device_model), &iter);
+
+ /* Select the first available device */
+ if (!have_selection && devices != NULL)
+ gtk_combo_box_set_active (GTK_COMBO_BOX (ui->priv->device_combo), 0);
+
+ ui->priv->setting_devices = FALSE;
+
+ if (!ui->priv->have_device_list) {
+ ui->priv->have_device_list = TRUE;
+
+ if (!devices) {
+ ui_show_error (ui,
+ /* Warning displayed when no scanners are detected */
+ _("No scanners detected"),
+ /* Hint to user on why there are no scanners detected */
+ _("Please check your scanner is connected and powered on"),
+ FALSE);
+ }
+ }
+}
+
+
+static gchar *
+get_selected_device (SimpleScan *ui)
+{
+ GtkTreeIter iter;
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter)) {
+ gchar *device;
+ gtk_tree_model_get (ui->priv->device_model, &iter, 0, &device, -1);
+ return device;
+ }
+
+ return NULL;
+}
+
+
+void
+ui_set_selected_device (SimpleScan *ui, const gchar *device)
+{
+ GtkTreeIter iter;
+
+ /* If doesn't exist add with label set to device name */
+ if (!find_scan_device (ui, device, &iter)) {
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->device_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->device_model), &iter, 0, device, 1, device, -1);
+ }
+
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter);
+}
+
+
+static void
+add_default_page (SimpleScan *ui)
+{
+ Page *page;
+
+ page = book_append_page (ui->priv->book,
+ ui->priv->default_page_width,
+ ui->priv->default_page_height,
+ ui->priv->default_page_dpi,
+ ui->priv->default_page_orientation);
+ book_view_select_page (ui->priv->book_view, page);
+}
+
+
+void new_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+new_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ book_clear (ui->priv->book);
+ add_default_page (ui);
+}
+
+
+static void
+set_document_hint (SimpleScan *ui, const gchar *document_hint)
+{
+ g_free (ui->priv->document_hint);
+ ui->priv->document_hint = g_strdup (document_hint);
+
+ if (strcmp (document_hint, "text") == 0) {
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->text_toolbar_menuitem), TRUE);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->text_menu_menuitem), TRUE);
+ }
+ else if (strcmp (document_hint, "photo") == 0) {
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->photo_toolbar_menuitem), TRUE);
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (ui->priv->photo_menu_menuitem), TRUE);
+ }
+}
+
+
+void text_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+text_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_document_hint (ui, "text");
+}
+
+
+void photo_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+photo_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_document_hint (ui, "photo");
+}
+
+
+static void
+set_page_side (SimpleScan *ui, const gchar *document_hint)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter_first (ui->priv->page_side_model, &iter)) {
+ do {
+ gchar *d;
+ gboolean have_match;
+
+ gtk_tree_model_get (ui->priv->page_side_model, &iter, 0, &d, -1);
+ have_match = strcmp (d, document_hint) == 0;
+ g_free (d);
+
+ if (have_match) {
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->page_side_combo), &iter);
+ return;
+ }
+ } while (gtk_tree_model_iter_next (ui->priv->page_side_model, &iter));
+ }
+}
+
+
+static void
+set_paper_size (SimpleScan *ui, gint width, gint height)
+{
+ GtkTreeIter iter;
+ gboolean have_iter;
+
+ for (have_iter = gtk_tree_model_get_iter_first (ui->priv->paper_size_model, &iter);
+ have_iter;
+ have_iter = gtk_tree_model_iter_next (ui->priv->paper_size_model, &iter)) {
+ gint w, h;
+
+ gtk_tree_model_get (ui->priv->paper_size_model, &iter, 0, &w, 1, &h, -1);
+ if (w == width && h == height)
+ break;
+ }
+
+ if (!have_iter)
+ have_iter = gtk_tree_model_get_iter_first (ui->priv->paper_size_model, &iter);
+ if (have_iter)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->paper_size_combo), &iter);
+}
+
+
+static gint
+get_text_dpi (SimpleScan *ui)
+{
+ GtkTreeIter iter;
+ gint dpi = DEFAULT_TEXT_DPI;
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->text_dpi_combo), &iter))
+ gtk_tree_model_get (ui->priv->text_dpi_model, &iter, 0, &dpi, -1);
+
+ return dpi;
+}
+
+
+static gint
+get_photo_dpi (SimpleScan *ui)
+{
+ GtkTreeIter iter;
+ gint dpi = DEFAULT_PHOTO_DPI;
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->photo_dpi_combo), &iter))
+ gtk_tree_model_get (ui->priv->photo_dpi_model, &iter, 0, &dpi, -1);
+
+ return dpi;
+}
+
+
+static gchar *
+get_page_side (SimpleScan *ui)
+{
+ GtkTreeIter iter;
+ gchar *mode = NULL;
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->page_side_combo), &iter))
+ gtk_tree_model_get (ui->priv->page_side_model, &iter, 0, &mode, -1);
+
+ return mode;
+}
+
+
+static gboolean
+get_paper_size (SimpleScan *ui, gint *width, gint *height)
+{
+ GtkTreeIter iter;
+
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (ui->priv->paper_size_combo), &iter)) {
+ gtk_tree_model_get (ui->priv->paper_size_model, &iter, 0, width, 1, height, -1);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static ScanOptions *
+get_scan_options (SimpleScan *ui)
+{
+ struct {
+ const gchar *name;
+ ScanMode mode;
+ } profiles[] =
+ {
+ { "text", SCAN_MODE_LINEART },
+ { "photo", SCAN_MODE_COLOR },
+ { NULL, SCAN_MODE_COLOR }
+ };
+ gint i;
+ ScanOptions *options;
+
+ /* Find this profile */
+ // FIXME: Move this into scan-profile.c
+ for (i = 0; profiles[i].name && strcmp (profiles[i].name, ui->priv->document_hint) != 0; i++);
+
+ options = g_malloc0 (sizeof (ScanOptions));
+ options->scan_mode = profiles[i].mode;
+ options->depth = 8;
+ if (options->scan_mode == SCAN_MODE_COLOR)
+ options->dpi = get_photo_dpi (ui);
+ else
+ options->dpi = get_text_dpi (ui);
+ get_paper_size (ui, &options->paper_width, &options->paper_height);
+
+ return options;
+}
+
+
+void scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ gchar *device;
+ ScanOptions *options;
+
+ device = get_selected_device (ui);
+
+ options = get_scan_options (ui);
+ options->type = SCAN_SINGLE;
+ g_signal_emit (G_OBJECT (ui), signals[START_SCAN], 0, device, options);
+ g_free (device);
+ g_free (options);
+}
+
+
+void stop_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+stop_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ g_signal_emit (G_OBJECT (ui), signals[STOP_SCAN], 0);
+}
+
+
+void continuous_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+continuous_scan_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (ui->priv->scanning) {
+ g_signal_emit (G_OBJECT (ui), signals[STOP_SCAN], 0);
+ } else {
+ gchar *device, *side;
+ ScanOptions *options;
+
+ device = get_selected_device (ui);
+ options = get_scan_options (ui);
+ side = get_page_side (ui);
+ if (strcmp (side, "front") == 0)
+ options->type = SCAN_ADF_FRONT;
+ else if (strcmp (side, "back") == 0)
+ options->type = SCAN_ADF_BACK;
+ else
+ options->type = SCAN_ADF_BOTH;
+
+ g_signal_emit (G_OBJECT (ui), signals[START_SCAN], 0, device, options);
+ g_free (device);
+ g_free (side);
+ g_free (options);
+ }
+}
+
+
+void preferences_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+preferences_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ gtk_window_present (GTK_WINDOW (ui->priv->preferences_dialog));
+}
+
+
+gboolean preferences_dialog_delete_event_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+gboolean
+preferences_dialog_delete_event_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ return TRUE;
+}
+
+
+void preferences_dialog_response_cb (GtkWidget *widget, gint response_id, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+preferences_dialog_response_cb (GtkWidget *widget, gint response_id, SimpleScan *ui)
+{
+ gtk_widget_hide (ui->priv->preferences_dialog);
+}
+
+
+static void
+page_selected_cb (BookView *view, Page *page, SimpleScan *ui)
+{
+ char *name = NULL;
+
+ if (page == NULL)
+ return;
+
+ ui->priv->updating_page_menu = TRUE;
+
+ if (page_has_crop (page)) {
+ char *crop_name;
+
+ // FIXME: Make more generic, move into page-size.c and reuse
+ crop_name = page_get_named_crop (page);
+ if (crop_name) {
+ if (strcmp (crop_name, "A4") == 0)
+ name = "a4_menuitem";
+ else if (strcmp (crop_name, "A5") == 0)
+ name = "a5_menuitem";
+ else if (strcmp (crop_name, "A6") == 0)
+ name = "a6_menuitem";
+ else if (strcmp (crop_name, "letter") == 0)
+ name = "letter_menuitem";
+ else if (strcmp (crop_name, "legal") == 0)
+ name = "legal_menuitem";
+ else if (strcmp (crop_name, "4x6") == 0)
+ name = "4x6_menuitem";
+ g_free (crop_name);
+ }
+ else
+ name = "custom_crop_menuitem";
+ }
+ else
+ name = "no_crop_menuitem";
+
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (ui->priv->builder, name)), TRUE);
+ gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (gtk_builder_get_object (ui->priv->builder, "crop_toolbutton")), page_has_crop (page));
+
+ ui->priv->updating_page_menu = FALSE;
+}
+
+
+// FIXME: Duplicated from simple-scan.c
+static gchar *
+get_temporary_filename (const gchar *prefix, const gchar *extension)
+{
+ gint fd;
+ gchar *filename, *path;
+ GError *error = NULL;
+
+ /* NOTE: I'm not sure if this is a 100% safe strategy to use g_file_open_tmp(), close and
+ * use the filename but it appears to work in practise */
+
+ filename = g_strdup_printf ("%s-XXXXXX.%s", prefix, extension);
+ fd = g_file_open_tmp (filename, &path, &error);
+ g_free (filename);
+ if (fd < 0) {
+ g_warning ("Error saving page for viewing: %s", error->message);
+ g_clear_error (&error);
+ return NULL;
+ }
+ close (fd);
+
+ return path;
+}
+
+
+static void
+show_page_cb (BookView *view, Page *page, SimpleScan *ui)
+{
+ gchar *path;
+ GFile *file;
+ GdkScreen *screen;
+ GError *error = NULL;
+
+ path = get_temporary_filename ("scanned-page", "tiff");
+ if (!path)
+ return;
+ file = g_file_new_for_path (path);
+ g_free (path);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (ui->priv->window));
+
+ if (page_save (page, "tiff", file, &error)) {
+ gchar *uri = g_file_get_uri (file);
+ gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error);
+ g_free (uri);
+ }
+
+ g_object_unref (file);
+
+ if (error) {
+ ui_show_error (ui,
+ /* Error message display when unable to preview image */
+ _("Unable to open image preview application"),
+ error->message,
+ FALSE);
+ g_clear_error (&error);
+ }
+}
+
+
+void rotate_left_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+rotate_left_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ Page *page;
+
+ if (ui->priv->updating_page_menu)
+ return;
+ page = book_view_get_selected (ui->priv->book_view);
+ page_rotate_left (page);
+}
+
+
+void rotate_right_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+rotate_right_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ Page *page;
+
+ if (ui->priv->updating_page_menu)
+ return;
+ page = book_view_get_selected (ui->priv->book_view);
+ page_rotate_right (page);
+}
+
+
+static void
+set_crop (SimpleScan *ui, const gchar *crop_name)
+{
+ Page *page;
+
+ gtk_widget_set_sensitive (ui->priv->crop_rotate_menuitem, crop_name != NULL);
+
+ if (ui->priv->updating_page_menu)
+ return;
+
+ page = book_view_get_selected (ui->priv->book_view);
+ if (!page)
+ return;
+
+ if (!crop_name) {
+ page_set_no_crop (page);
+ return;
+ }
+
+ if (strcmp (crop_name, "custom") == 0) {
+ gint width, height, crop_width, crop_height;
+
+ width = page_get_width (page);
+ height = page_get_height (page);
+
+ crop_width = (int) (width * 0.8 + 0.5);
+ crop_height = (int) (height * 0.8 + 0.5);
+ page_set_custom_crop (page, crop_width, crop_height);
+ page_move_crop (page, (width - crop_width) / 2, (height - crop_height) / 2);
+
+ return;
+ }
+
+ page_set_named_crop (page, crop_name);
+}
+
+
+void no_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+no_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, NULL);
+}
+
+
+void custom_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+custom_crop_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, "custom");
+}
+
+void crop_toolbutton_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+crop_toolbutton_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (ui->priv->updating_page_menu)
+ return;
+
+ if (gtk_toggle_tool_button_get_active (GTK_TOGGLE_TOOL_BUTTON (widget)))
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (ui->priv->builder, "custom_crop_menuitem")), TRUE);
+ else
+ gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (gtk_builder_get_object (ui->priv->builder, "no_crop_menuitem")), TRUE);
+}
+
+
+void four_by_six_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+four_by_six_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, "4x6");
+}
+
+
+void legal_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+legal_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, "legal");
+}
+
+
+void letter_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+letter_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, "letter");
+}
+
+
+void a6_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+a6_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, "A6");
+}
+
+
+void a5_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+a5_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, "A5");
+}
+
+
+void a4_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+a4_menuitem_toggled_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (widget)))
+ set_crop (ui, "A4");
+}
+
+
+void crop_rotate_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+crop_rotate_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ Page *page;
+
+ page = book_view_get_selected (ui->priv->book_view);
+ if (!page)
+ return;
+
+ page_rotate_crop (page);
+}
+
+
+void page_delete_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+page_delete_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ book_delete_page (book_view_get_book (ui->priv->book_view),
+ book_view_get_selected (ui->priv->book_view));
+}
+
+
+static void
+on_file_type_changed (GtkTreeSelection *selection, GtkWidget *dialog)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gchar *path, *filename, *extension, *new_filename;
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, 1, &extension, -1);
+ path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+ filename = g_path_get_basename (path);
+
+ /* Replace extension */
+ if (g_strrstr (filename, "."))
+ new_filename = g_strdup_printf ("%.*s%s", (int)(g_strrstr (filename, ".") - filename), filename, extension);
+ else
+ new_filename = g_strdup_printf ("%s%s", filename, extension);
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), new_filename);
+
+ g_free (path);
+ g_free (filename);
+ g_free (new_filename);
+ g_free (extension);
+}
+
+
+void save_file_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+save_file_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ GtkWidget *dialog;
+ gint response;
+ GtkFileFilter *filter;
+ GtkWidget *expander, *file_type_view;
+ GtkListStore *file_type_store;
+ GtkTreeIter iter;
+ GtkTreeViewColumn *column;
+ const gchar *extension;
+ gchar *directory;
+ gint i;
+
+ struct
+ {
+ gchar *label, *extension;
+ } file_types[] =
+ {
+ /* Save dialog: Label for saving in PDF format */
+ { _("PDF (multi-page document)"), ".pdf" },
+ /* Save dialog: Label for saving in JPEG format */
+ { _("JPEG (compressed)"), ".jpg" },
+ /* Save dialog: Label for saving in PNG format */
+ { _("PNG (lossless)"), ".png" },
+ { NULL, NULL }
+ };
+
+ /* Get directory to save to */
+ directory = gconf_client_get_string (ui->priv->client, GCONF_DIR "/save_directory", NULL);
+ if (!directory || directory[0] == '\0') {
+ g_free (directory);
+ directory = g_strdup (g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS));
+ }
+
+ dialog = gtk_file_chooser_dialog_new (/* Save dialog: Dialog title */
+ _("Save As..."),
+ GTK_WINDOW (ui->priv->window),
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), FALSE);
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), directory);
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), ui->priv->default_file_name);
+ g_free (directory);
+
+ /* Filter to only show images by default */
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter,
+ /* Save dialog: Filter name to show only image files */
+ _("Image Files"));
+ gtk_file_filter_add_pixbuf_formats (filter);
+ gtk_file_filter_add_mime_type (filter, "application/pdf");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter,
+ /* Save dialog: Filter name to show all files */
+ _("All Files"));
+ gtk_file_filter_add_pattern (filter, "*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
+
+ expander = gtk_expander_new_with_mnemonic (/* */
+ _("Select File _Type"));
+ gtk_expander_set_spacing (GTK_EXPANDER (expander), 5);
+ gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dialog), expander);
+
+ extension = strstr (ui->priv->default_file_name, ".");
+ if (!extension)
+ extension = "";
+
+ file_type_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_STRING);
+ for (i = 0; file_types[i].label; i++) {
+ gtk_list_store_append (file_type_store, &iter);
+ gtk_list_store_set (file_type_store, &iter, 0, file_types[i].label, 1, file_types[i].extension, -1);
+ }
+
+ file_type_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (file_type_store));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (file_type_view), FALSE);
+ gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (file_type_view), TRUE);
+ column = gtk_tree_view_column_new_with_attributes ("",
+ gtk_cell_renderer_text_new (),
+ "text", 0, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (file_type_view), column);
+ gtk_container_add (GTK_CONTAINER (expander), file_type_view);
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (file_type_store), &iter)) {
+ do {
+ gchar *e;
+ gtk_tree_model_get (GTK_TREE_MODEL (file_type_store), &iter, 1, &e, -1);
+ if (strcmp (extension, e) == 0)
+ gtk_tree_selection_select_iter (gtk_tree_view_get_selection (GTK_TREE_VIEW (file_type_view)), &iter);
+ g_free (e);
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (file_type_store), &iter));
+ }
+ g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (file_type_view)),
+ "changed",
+ G_CALLBACK (on_file_type_changed),
+ dialog);
+
+ gtk_widget_show_all (expander);
+
+ response = gtk_dialog_run (GTK_DIALOG (dialog));
+ if (response == GTK_RESPONSE_ACCEPT) {
+ gchar *uri;
+
+ uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog));
+ g_signal_emit (G_OBJECT (ui), signals[SAVE], 0, uri);
+
+ g_free (uri);
+ }
+
+ gconf_client_set_string (ui->priv->client, GCONF_DIR "/save_directory",
+ gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)),
+ NULL);
+
+ gtk_widget_destroy (dialog);
+}
+
+
+static void
+draw_page (GtkPrintOperation *operation,
+ GtkPrintContext *print_context,
+ gint page_number,
+ SimpleScan *ui)
+{
+ cairo_t *context;
+ Page *page;
+ GdkPixbuf *image;
+ gboolean is_landscape = FALSE;
+
+ context = gtk_print_context_get_cairo_context (print_context);
+
+ page = book_get_page (ui->priv->book, page_number);
+
+ /* Rotate to same aspect */
+ if (gtk_print_context_get_width (print_context) > gtk_print_context_get_height (print_context))
+ is_landscape = TRUE;
+ if (page_is_landscape (page) != is_landscape) {
+ cairo_translate (context, gtk_print_context_get_width (print_context), 0);
+ cairo_rotate (context, M_PI_2);
+ }
+
+ cairo_scale (context,
+ gtk_print_context_get_dpi_x (print_context) / page_get_dpi (page),
+ gtk_print_context_get_dpi_y (print_context) / page_get_dpi (page));
+
+ image = page_get_cropped_image (page);
+ gdk_cairo_set_source_pixbuf (context, image, 0, 0);
+ cairo_paint (context);
+
+ g_object_unref (image);
+}
+
+
+void email_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+email_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ g_signal_emit (G_OBJECT (ui), signals[EMAIL], 0, ui->priv->document_hint);
+}
+
+
+void print_button_clicked_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+print_button_clicked_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ GtkPrintOperation *print;
+ GtkPrintOperationResult result;
+ GError *error = NULL;
+
+ print = gtk_print_operation_new ();
+ gtk_print_operation_set_n_pages (print, book_get_n_pages (ui->priv->book));
+ g_signal_connect (print, "draw-page", G_CALLBACK (draw_page), ui);
+
+ result = gtk_print_operation_run (print, GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+ GTK_WINDOW (ui->priv->window), &error);
+
+ g_object_unref (print);
+}
+
+
+void help_contents_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+help_contents_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ GdkScreen *screen;
+ GError *error = NULL;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (ui->priv->window));
+ gtk_show_uri (screen, "ghelp:simple-scan", gtk_get_current_event_time (), &error);
+
+ if (error)
+ {
+ ui_show_error (ui,
+ /* Error message displayed when unable to launch help browser */
+ _("Unable to open help file"),
+ error->message,
+ FALSE);
+ g_clear_error (&error);
+ }
+}
+
+
+void about_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+about_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ const gchar *authors[] = { "Robert Ancell <robert.ancell@canonical.com>", NULL };
+
+ /* The license this software is under (GPL3+) */
+ const char *license = _("This program is free software: you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation, either version 3 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program. If not, see <http://www.gnu.org/licenses/>.");
+
+ /* Title of about dialog */
+ const char *title = _("About Simple Scan");
+
+ /* Description of program */
+ const char *description = _("Simple document scanning tool");
+
+ gtk_show_about_dialog (GTK_WINDOW (ui->priv->window),
+ "title", title,
+ "program-name", "Simple Scan",
+ "version", VERSION,
+ "comments", description,
+ "logo-icon-name", "scanner",
+ "authors", authors,
+ "translator-credits", _("translator-credits"),
+ "website", "https://launchpad.net/simple-scan",
+ "copyright", "Copyright © 2009 Canonical Ltd.",
+ "license", license,
+ "wrap-license", TRUE,
+ NULL);
+}
+
+
+static void
+quit (SimpleScan *ui)
+{
+ char *device;
+ gint paper_width = 0, paper_height = 0;
+ gint i;
+
+ // FIXME: Warn if document with unsaved changes
+
+ device = get_selected_device (ui);
+ if (device) {
+ gconf_client_set_string(ui->priv->client, GCONF_DIR "/selected_device", device, NULL);
+ g_free (device);
+ }
+
+ gconf_client_set_string (ui->priv->client, GCONF_DIR "/document_type", ui->priv->document_hint, NULL);
+ gconf_client_set_int (ui->priv->client, GCONF_DIR "/text_dpi", get_text_dpi (ui), NULL);
+ gconf_client_set_int (ui->priv->client, GCONF_DIR "/photo_dpi", get_photo_dpi (ui), NULL);
+ gconf_client_set_string (ui->priv->client, GCONF_DIR "/page_side", get_page_side (ui), NULL);
+ get_paper_size (ui, &paper_width, &paper_height);
+ gconf_client_set_int (ui->priv->client, GCONF_DIR "/paper_width", paper_width, NULL);
+ gconf_client_set_int (ui->priv->client, GCONF_DIR "/paper_height", paper_height, NULL);
+
+ gconf_client_set_int(ui->priv->client, GCONF_DIR "/window_width", ui->priv->window_width, NULL);
+ gconf_client_set_int(ui->priv->client, GCONF_DIR "/window_height", ui->priv->window_height, NULL);
+ gconf_client_set_bool(ui->priv->client, GCONF_DIR "/window_is_maximized", ui->priv->window_is_maximized, NULL);
+
+ for (i = 0; orientation_keys[i].key != NULL && orientation_keys[i].orientation != ui->priv->default_page_orientation; i++);
+ if (orientation_keys[i].key != NULL)
+ gconf_client_set_string(ui->priv->client, GCONF_DIR "/scan_direction", orientation_keys[i].key, NULL);
+ gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_width", ui->priv->default_page_width, NULL);
+ gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_height", ui->priv->default_page_height, NULL);
+ gconf_client_set_int (ui->priv->client, GCONF_DIR "/page_dpi", ui->priv->default_page_dpi, NULL);
+
+ g_signal_emit (G_OBJECT (ui), signals[QUIT], 0);
+}
+
+
+void quit_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui);
+G_MODULE_EXPORT
+void
+quit_menuitem_activate_cb (GtkWidget *widget, SimpleScan *ui)
+{
+ quit (ui);
+}
+
+
+gboolean simple_scan_window_configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, SimpleScan *ui);
+G_MODULE_EXPORT
+gboolean
+simple_scan_window_configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, SimpleScan *ui)
+{
+ if (!ui->priv->window_is_maximized) {
+ ui->priv->window_width = event->width;
+ ui->priv->window_height = event->height;
+ }
+
+ return FALSE;
+}
+
+
+gboolean simple_scan_window_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, SimpleScan *ui);
+G_MODULE_EXPORT
+gboolean
+simple_scan_window_window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event, SimpleScan *ui)
+{
+ if (event->changed_mask & GDK_WINDOW_STATE_MAXIMIZED)
+ ui->priv->window_is_maximized = (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) != 0;
+ return FALSE;
+}
+
+
+gboolean window_delete_event_cb (GtkWidget *widget, GdkEvent *event, SimpleScan *ui);
+G_MODULE_EXPORT
+gboolean
+window_delete_event_cb (GtkWidget *widget, GdkEvent *event, SimpleScan *ui)
+{
+ quit (ui);
+ return TRUE;
+}
+
+
+static void
+page_size_changed_cb (Page *page, SimpleScan *ui)
+{
+ ui->priv->default_page_width = page_get_width (page);
+ ui->priv->default_page_height = page_get_height (page);
+ ui->priv->default_page_dpi = page_get_dpi (page);
+}
+
+
+static void
+page_orientation_changed_cb (Page *page, SimpleScan *ui)
+{
+ ui->priv->default_page_orientation = page_get_orientation (page);
+}
+
+
+static void
+page_added_cb (Book *book, Page *page, SimpleScan *ui)
+{
+ ui->priv->default_page_width = page_get_width (page);
+ ui->priv->default_page_height = page_get_height (page);
+ ui->priv->default_page_dpi = page_get_dpi (page);
+ ui->priv->default_page_orientation = page_get_orientation (page);
+ g_signal_connect (page, "size-changed", G_CALLBACK (page_size_changed_cb), ui);
+ g_signal_connect (page, "orientation-changed", G_CALLBACK (page_orientation_changed_cb), ui);
+}
+
+
+static void
+page_removed_cb (Book *book, Page *page, SimpleScan *ui)
+{
+ /* If this is the last page add a new blank one */
+ if (book_get_n_pages (ui->priv->book) == 1)
+ add_default_page (ui);
+}
+
+
+static void
+set_dpi_combo (GtkWidget *combo, gint default_dpi, gint current_dpi)
+{
+ struct
+ {
+ gint dpi;
+ const gchar *label;
+ } scan_resolutions[] =
+ {
+ /* Preferences dialog: Label for minimum resolution in resolution list */
+ { 75, _("%d dpi (draft)") },
+ /* Preferences dialog: Label for resolution value in resolution list (dpi = dots per inch) */
+ { 150, _("%d dpi") },
+ { 300, _("%d dpi") },
+ { 600, _("%d dpi") },
+ /* Preferences dialog: Label for maximum resolution in resolution list */
+ { 1200, _("%d dpi (high resolution)") },
+ { 2400, _("%d dpi") },
+ { -1, NULL }
+ };
+ GtkCellRenderer *renderer;
+ GtkTreeModel *model;
+ gint i;
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (combo), renderer, "text", 1);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+ for (i = 0; scan_resolutions[i].dpi > 0; i++)
+ {
+ GtkTreeIter iter;
+ gchar *label;
+ gint dpi;
+
+ dpi = scan_resolutions[i].dpi;
+
+ if (dpi == default_dpi)
+ label = g_strdup_printf (/* Preferences dialog: Label for default resolution in resolution list */
+ _("%d dpi (default)"), dpi);
+ else
+ label = g_strdup_printf (scan_resolutions[i].label, dpi);
+
+ gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, 0, dpi, 1, label, -1);
+
+ if (dpi == current_dpi)
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
+
+ g_free (label);
+ }
+}
+
+
+static void
+ui_load (SimpleScan *ui)
+{
+ GtkBuilder *builder;
+ GError *error = NULL;
+ GtkCellRenderer *renderer;
+ gchar *device, *document_type, *scan_direction, *page_side;
+ gint dpi, paper_width, paper_height;
+
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), ICON_DIR);
+
+ gtk_window_set_default_icon_name ("scanner");
+
+ builder = ui->priv->builder = gtk_builder_new ();
+ gtk_builder_add_from_file (builder, UI_DIR "simple-scan.ui", &error);
+ if (error) {
+ g_critical ("Unable to load UI: %s\n", error->message);
+ ui_show_error (ui,
+ /* Title of dialog when cannot load required files */
+ _("Files missing"),
+ /* Description in dialog when cannot load required files */
+ _("Please check your installation"),
+ FALSE);
+ exit (1);
+ }
+ gtk_builder_connect_signals (builder, ui);
+
+ ui->priv->window = GTK_WIDGET (gtk_builder_get_object (builder, "simple_scan_window"));
+ ui->priv->preview_box = GTK_WIDGET (gtk_builder_get_object (builder, "preview_vbox"));
+ ui->priv->preview_area = GTK_WIDGET (gtk_builder_get_object (builder, "preview_area"));
+ ui->priv->preview_scroll = GTK_WIDGET (gtk_builder_get_object (builder, "preview_scrollbar"));
+ ui->priv->page_delete_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "page_delete_menuitem"));
+ ui->priv->crop_rotate_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "crop_rotate_menuitem"));
+ ui->priv->stop_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "stop_scan_menuitem"));
+ ui->priv->stop_toolbutton = GTK_WIDGET (gtk_builder_get_object (builder, "stop_toolbutton"));
+
+ ui->priv->text_toolbar_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "text_toolbutton_menuitem"));
+ ui->priv->text_menu_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "text_menuitem"));
+ ui->priv->photo_toolbar_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "photo_toolbutton_menuitem"));
+ ui->priv->photo_menu_menuitem = GTK_WIDGET (gtk_builder_get_object (builder, "photo_menuitem"));
+
+ ui->priv->authorize_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "authorize_dialog"));
+ ui->priv->authorize_label = GTK_WIDGET (gtk_builder_get_object (builder, "authorize_label"));
+ ui->priv->username_entry = GTK_WIDGET (gtk_builder_get_object (builder, "username_entry"));
+ ui->priv->password_entry = GTK_WIDGET (gtk_builder_get_object (builder, "password_entry"));
+
+ ui->priv->preferences_dialog = GTK_WIDGET (gtk_builder_get_object (builder, "preferences_dialog"));
+ ui->priv->device_combo = GTK_WIDGET (gtk_builder_get_object (builder, "device_combo"));
+ ui->priv->device_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->device_combo));
+ ui->priv->text_dpi_combo = GTK_WIDGET (gtk_builder_get_object (builder, "text_dpi_combo"));
+ ui->priv->text_dpi_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->text_dpi_combo));
+ ui->priv->photo_dpi_combo = GTK_WIDGET (gtk_builder_get_object (builder, "photo_dpi_combo"));
+ ui->priv->photo_dpi_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->photo_dpi_combo));
+ ui->priv->page_side_combo = GTK_WIDGET (gtk_builder_get_object (builder, "page_side_combo"));
+ ui->priv->page_side_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->page_side_combo));
+ ui->priv->paper_size_combo = GTK_WIDGET (gtk_builder_get_object (builder, "paper_size_combo"));
+ ui->priv->paper_size_model = gtk_combo_box_get_model (GTK_COMBO_BOX (ui->priv->paper_size_combo));
+
+ GtkTreeIter iter;
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 0, 1, 0, 2, "Automatic", -1);
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 2050, 1, 1480, 2, "A6", -1);
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 1480, 1, 2100, 2, "A5", -1);
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 2100, 1, 1970, 2, "A4", -1);
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 2159, 1, 2794, 2, "Letter", -1);
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 2159, 1, 3556, 2, "Legal", -1);
+ gtk_list_store_append (GTK_LIST_STORE (ui->priv->paper_size_model), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (ui->priv->paper_size_model), &iter, 0, 1016, 1, 1524, 2, "4×6", -1);
+
+ dpi = gconf_client_get_int (ui->priv->client, GCONF_DIR "/text_dpi", NULL);
+ if (dpi <= 0)
+ dpi = DEFAULT_TEXT_DPI;
+ set_dpi_combo (ui->priv->text_dpi_combo, DEFAULT_TEXT_DPI, dpi);
+ dpi = gconf_client_get_int (ui->priv->client, GCONF_DIR "/photo_dpi", NULL);
+ if (dpi <= 0)
+ dpi = DEFAULT_PHOTO_DPI;
+ set_dpi_combo (ui->priv->photo_dpi_combo, DEFAULT_PHOTO_DPI, dpi);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->device_combo), renderer, TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->device_combo), renderer, "text", 1);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->page_side_combo), renderer, TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->page_side_combo), renderer, "text", 1);
+ page_side = gconf_client_get_string (ui->priv->client, GCONF_DIR "/page_side", NULL);
+ if (page_side) {
+ set_page_side (ui, page_side);
+ g_free (page_side);
+ }
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (ui->priv->paper_size_combo), renderer, TRUE);
+ gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (ui->priv->paper_size_combo), renderer, "text", 2);
+ paper_width = gconf_client_get_int (ui->priv->client, GCONF_DIR "/paper_width", NULL);
+ paper_height = gconf_client_get_int (ui->priv->client, GCONF_DIR "/paper_height", NULL);
+ set_paper_size (ui, paper_width, paper_height);
+
+ device = gconf_client_get_string (ui->priv->client, GCONF_DIR "/selected_device", NULL);
+ if (device) {
+ GtkTreeIter iter;
+ if (find_scan_device (ui, device, &iter))
+ gtk_combo_box_set_active_iter (GTK_COMBO_BOX (ui->priv->device_combo), &iter);
+ g_free (device);
+ }
+
+ document_type = gconf_client_get_string (ui->priv->client, GCONF_DIR "/document_type", NULL);
+ if (document_type) {
+ set_document_hint (ui, document_type);
+ g_free (document_type);
+ }
+
+ ui->priv->book_view = book_view_new ();
+ g_signal_connect (ui->priv->book_view, "page-selected", G_CALLBACK (page_selected_cb), ui);
+ g_signal_connect (ui->priv->book_view, "show-page", G_CALLBACK (show_page_cb), ui);
+ book_view_set_widgets (ui->priv->book_view,
+ ui->priv->preview_box,
+ ui->priv->preview_area,
+ ui->priv->preview_scroll,
+ GTK_WIDGET (gtk_builder_get_object (builder, "page_menu")));
+
+ /* Find default page details */
+ scan_direction = gconf_client_get_string(ui->priv->client, GCONF_DIR "/scan_direction", NULL);
+ ui->priv->default_page_orientation = TOP_TO_BOTTOM;
+ if (scan_direction) {
+ gint i;
+ for (i = 0; orientation_keys[i].key != NULL && strcmp (orientation_keys[i].key, scan_direction) != 0; i++);
+ if (orientation_keys[i].key != NULL)
+ ui->priv->default_page_orientation = orientation_keys[i].orientation;
+ g_free (scan_direction);
+ }
+ ui->priv->default_page_width = gconf_client_get_int (ui->priv->client, GCONF_DIR "/page_width", NULL);
+ if (ui->priv->default_page_width <= 0)
+ ui->priv->default_page_width = 595;
+ ui->priv->default_page_height = gconf_client_get_int (ui->priv->client, GCONF_DIR "/page_height", NULL);
+ if (ui->priv->default_page_height <= 0)
+ ui->priv->default_page_height = 842;
+ ui->priv->default_page_dpi = gconf_client_get_int (ui->priv->client, GCONF_DIR "/page_dpi", NULL);
+ if (ui->priv->default_page_dpi <= 0)
+ ui->priv->default_page_dpi = 72;
+
+ /* Restore window size */
+ ui->priv->window_width = gconf_client_get_int (ui->priv->client, GCONF_DIR "/window_width", NULL);
+ if (ui->priv->window_width <= 0)
+ ui->priv->window_width = 600;
+ ui->priv->window_height = gconf_client_get_int (ui->priv->client, GCONF_DIR "/window_height", NULL);
+ if (ui->priv->window_height <= 0)
+ ui->priv->window_height = 400;
+ g_debug ("Restoring window to %dx%d pixels", ui->priv->window_width, ui->priv->window_height);
+ gtk_window_set_default_size (GTK_WINDOW (ui->priv->window), ui->priv->window_width, ui->priv->window_height);
+ ui->priv->window_is_maximized = gconf_client_get_bool (ui->priv->client, GCONF_DIR "/window_is_maximized", NULL);
+ if (ui->priv->window_is_maximized) {
+ g_debug ("Restoring window to maximized");
+ gtk_window_maximize (GTK_WINDOW (ui->priv->window));
+ }
+
+ if (book_get_n_pages (ui->priv->book) == 0)
+ add_default_page (ui);
+ book_view_set_book (ui->priv->book_view, ui->priv->book);
+}
+
+
+SimpleScan *
+ui_new ()
+{
+ return g_object_new (SIMPLE_SCAN_TYPE, NULL);
+}
+
+
+Book *
+ui_get_book (SimpleScan *ui)
+{
+ return g_object_ref (ui->priv->book);
+}
+
+
+void
+ui_set_selected_page (SimpleScan *ui, Page *page)
+{
+ book_view_select_page (ui->priv->book_view, page);
+}
+
+
+Page *
+ui_get_selected_page (SimpleScan *ui)
+{
+ return book_view_get_selected (ui->priv->book_view);
+}
+
+
+void
+ui_set_scanning (SimpleScan *ui, gboolean scanning)
+{
+ ui->priv->scanning = scanning;
+ gtk_widget_set_sensitive (ui->priv->page_delete_menuitem, !scanning);
+ gtk_widget_set_sensitive (ui->priv->stop_menuitem, scanning);
+ gtk_widget_set_sensitive (ui->priv->stop_toolbutton, scanning);
+}
+
+
+void
+ui_show_error (SimpleScan *ui, const gchar *error_title, const gchar *error_text, gboolean change_scanner_hint)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (ui->priv->window),
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ "%s", error_title);
+ if (change_scanner_hint)
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ /* Button in error dialog to open prefereces dialog and change scanner */
+ _("Change _Scanner"),
+ 1);
+ gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_CLOSE, 0);
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", error_text);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == 1) {
+ gtk_widget_grab_focus (ui->priv->device_combo);
+ gtk_window_present (GTK_WINDOW (ui->priv->preferences_dialog));
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+
+void
+ui_start (SimpleScan *ui)
+{
+ gtk_widget_show (ui->priv->window);
+}
+
+
+/* Generated with glib-genmarshal */
+static void
+g_cclosure_user_marshal_VOID__STRING_POINTER (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_POINTER) (gpointer data1,
+ gconstpointer arg_1,
+ gconstpointer arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_POINTER callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_POINTER) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ g_value_get_string (param_values + 1),
+ g_value_get_pointer (param_values + 2),
+ data2);
+}
+
+
+static void
+ui_finalize (GObject *object)
+{
+ SimpleScan *ui = SIMPLE_SCAN (object);
+
+ g_object_unref (ui->priv->client);
+ ui->priv->client = NULL;
+ g_object_unref (ui->priv->builder);
+ ui->priv->builder = NULL;
+ g_object_unref (ui->priv->book);
+ ui->priv->book = NULL;
+ g_object_unref (ui->priv->book_view);
+ ui->priv->book_view = NULL;
+
+ G_OBJECT_CLASS (ui_parent_class)->finalize (object);
+}
+
+
+static void
+ui_class_init (SimpleScanClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = ui_finalize;
+
+ signals[START_SCAN] =
+ g_signal_new ("start-scan",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SimpleScanClass, start_scan),
+ NULL, NULL,
+ g_cclosure_user_marshal_VOID__STRING_POINTER,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_POINTER);
+ signals[STOP_SCAN] =
+ g_signal_new ("stop-scan",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SimpleScanClass, stop_scan),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[SAVE] =
+ g_signal_new ("save",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SimpleScanClass, save),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE, 1, G_TYPE_POINTER);
+ signals[EMAIL] =
+ g_signal_new ("email",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SimpleScanClass, email),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+ signals[QUIT] =
+ g_signal_new ("quit",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (SimpleScanClass, quit),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (klass, sizeof (SimpleScanPrivate));
+}
+
+
+static void
+ui_init (SimpleScan *ui)
+{
+ ui->priv = G_TYPE_INSTANCE_GET_PRIVATE (ui, SIMPLE_SCAN_TYPE, SimpleScanPrivate);
+
+ ui->priv->book = book_new ();
+ g_signal_connect (ui->priv->book, "page-removed", G_CALLBACK (page_removed_cb), ui);
+ g_signal_connect (ui->priv->book, "page-added", G_CALLBACK (page_added_cb), ui);
+
+ ui->priv->client = gconf_client_get_default();
+ gconf_client_add_dir(ui->priv->client, GCONF_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);
+
+ ui->priv->document_hint = g_strdup ("photo");
+ ui->priv->default_file_name = g_strdup (_("Scanned Document.pdf"));
+ ui->priv->scanning = FALSE;
+ ui_load (ui);
+}