/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* * Copyright (C) 2003-2005 Imendio AB * Copyright (C) 2002-2003 CodeFactory AB * Copyright (C) 2002-2003 Richard Hult * Copyright (C) 2002-2003 Mikael Hallendal * * 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 2 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "planner-marshal.h" #include "planner-conf.h" #include "planner-sidebar.h" #include "planner-window.h" #include "planner-plugin-loader.h" #include "planner-project-properties.h" #include "planner-phase-dialog.h" #include "planner-calendar-dialog.h" #include "planner-day-type-dialog.h" #include "planner-print-dialog.h" #include "planner-view.h" #include "planner-gantt-view.h" #include "planner-task-view.h" #include "planner-resource-view.h" #include "planner-usage-view.h" #include "planner-util.h" #define d(x) struct _PlannerWindowPriv { PlannerApplication *application; GtkUIManager *ui_manager; GtkActionGroup *actions; GtkActionGroup *view_actions; PlannerCmdManager *cmd_manager; MrpProject *project; GtkWidget *statusbar; GtkWidget *ui_box; GtkWidget *sidebar; GtkWidget *notebook; GtkWidget *properties_dialog; GtkWidget *calendar_dialog; GtkWidget *day_type_dialog; GtkWidget *phase_dialog; PlannerView *current_view; GList *views; GList *plugins; GTimer *last_saved; EggRecentViewUIManager *recent_view; }; /* Drop targets. */ enum { TARGET_STRING, TARGET_URI_LIST }; static const GtkTargetEntry drop_target_types[] = { { "STRING", 0, TARGET_STRING }, { "text/plain", 0, TARGET_STRING }, { "text/uri-list", 0, TARGET_URI_LIST }, }; /* Signals */ enum { CLOSED, NEW_WINDOW, EXIT, LAST_SIGNAL }; /* Links type */ enum { LINK_TYPE_EMAIL, LINK_TYPE_URL }; static void window_class_init (PlannerWindowClass *klass); static void window_init (PlannerWindow *window); static void window_finalize (GObject *object); static void window_populate (PlannerWindow *window); static void window_view_selected (PlannerSidebar *sidebar, gint index, PlannerWindow *window); static void window_view_cb (GtkAction *action, GtkRadioAction *current, gpointer data); static void window_new_cb (GtkAction *action, gpointer data); static void window_open_cb (GtkAction *action, gpointer data); static void window_save_as_cb (GtkAction *action, gpointer data); static void window_save_cb (GtkAction *action, gpointer data); static void window_print_cb (GtkAction *action, gpointer data); static void window_print_preview_cb (GtkAction *action, gpointer data); static void window_close_cb (GtkAction *action, gpointer data); static void window_exit_cb (GtkAction *action, gpointer data); static void window_undo_cb (GtkAction *action, gpointer data); static void window_redo_cb (GtkAction *action, gpointer data); static void window_project_props_cb (GtkAction *action, gpointer data); static void window_manage_calendars_cb (GtkAction *action, gpointer data); static void window_edit_day_types_cb (GtkAction *action, gpointer data); static void window_edit_phases_cb (GtkAction *action, gpointer data); static void window_help_cb (GtkAction *action, gpointer data); static void window_about_cb (GtkAction *action, gpointer data); static gboolean window_delete_event_cb (PlannerWindow *window, gpointer user_data); static void window_undo_state_changed_cb (PlannerCmdManager *manager, gboolean state, const gchar *label, PlannerWindow *window); static void window_redo_state_changed_cb (PlannerCmdManager *manager, gboolean state, const gchar *label, PlannerWindow *window); static void window_drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *data, guint info, guint time, PlannerWindow *window); static void window_project_needs_saving_changed_cb (MrpProject *project, gboolean needs_saving, PlannerWindow *window); static void window_project_notify_name_cb (MrpProject *project, GParamSpec *pspec, PlannerWindow *window); static gboolean window_confirm_exit_run (PlannerWindow *window); static gboolean window_do_save (PlannerWindow *window, gboolean force); static gboolean window_do_save_as (PlannerWindow *window); static gchar * window_get_name (PlannerWindow *window); static void window_update_title (PlannerWindow *window); static GtkWidget *window_create_dialog_button (const gchar *icon_name, const gchar *text); static gchar * window_recent_tooltip_func (EggRecentItem *item, gpointer user_data); static void window_save_state (PlannerWindow *window); static void window_restore_state (PlannerWindow *window); static void window_disconnect_proxy_cb (GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, PlannerWindow *window); static void window_connect_proxy_cb (GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, PlannerWindow *window); static void handle_links (GtkAboutDialog *about G_GNUC_UNUSED, const gchar *link, gpointer data); #define CONF_WINDOW_DIR "/ui" #define CONF_WINDOW_MAXIMIZED "/ui/main_window_maximized" #define CONF_WINDOW_WIDTH "/ui/main_window_width" #define CONF_WINDOW_HEIGHT "/ui/main_window_height" #define CONF_WINDOW_POS_X "/ui/main_window_position_x" #define CONF_WINDOW_POS_Y "/ui/main_window_position_y" #define CONF_ACTIVE_VIEW "/ui/active_view" #define CONF_LAST_DIR "/general/last_dir" #define VIEW_PATH "/menu/View/Views placeholder" #define VIEW_GROUP "view group" static GtkWindowClass *parent_class = NULL; static guint signals[LAST_SIGNAL]; static GtkActionEntry entries[] = { { "File", NULL, N_("_File"), NULL, NULL, NULL }, { "FileNew", GTK_STOCK_NEW, N_("_New Project"), "n", N_("Create a new project"), G_CALLBACK (window_new_cb) }, { "FileOpen", GTK_STOCK_OPEN, N_("_Open..."), "F3", N_("Open a project"), G_CALLBACK (window_open_cb) }, { "Import", NULL, N_("_Import"), NULL, NULL, NULL }, { "FileSave", GTK_STOCK_SAVE, N_("_Save"), "s", N_("Save the current project"), G_CALLBACK (window_save_cb) }, { "Export", NULL, N_("_Export"), NULL, NULL, NULL }, { "FileSaveAs", GTK_STOCK_SAVE_AS, N_("Save _As..."), "s", N_("Save the current project with a different name"), G_CALLBACK (window_save_as_cb) }, { "FilePrint", GTK_STOCK_PRINT, N_("_Print..."), "p", N_("Print the current project"), G_CALLBACK (window_print_cb) }, { "FilePrintPreview", GTK_STOCK_PRINT_PREVIEW, N_("Print Pre_view"), "p", N_("Print preview of the current project"), G_CALLBACK (window_print_preview_cb) }, { "FileClose", GTK_STOCK_CLOSE, N_("_Close"), "w", N_("Close the current file"), G_CALLBACK (window_close_cb) }, { "FileExit", GTK_STOCK_QUIT, N_("_Quit"), "q", N_("Exit the program"), G_CALLBACK (window_exit_cb) }, { "Edit", NULL, N_("_Edit"), NULL, NULL, NULL }, { "EditUndo", GTK_STOCK_UNDO, N_("_Undo"), "z", N_("Undo the last action"), G_CALLBACK (window_undo_cb) }, { "EditRedo", GTK_STOCK_REDO, N_("_Redo"), "r", N_("Redo the undone action"), G_CALLBACK (window_redo_cb) }, { "View", NULL, N_("_View"), NULL, NULL, NULL }, { "Actions", NULL, N_("_Actions"), NULL, NULL, NULL }, { "Project", NULL, N_("_Project"), NULL, NULL, NULL }, { "ManageCalendars", NULL, N_("_Manage Calendars"), NULL, NULL, G_CALLBACK (window_manage_calendars_cb) }, { "EditDayTypes", NULL, N_("Edit Day _Types"), NULL, NULL, G_CALLBACK (window_edit_day_types_cb) }, { "EditPhases", NULL, N_("Edit Project _Phases"), NULL, NULL, G_CALLBACK (window_edit_phases_cb) }, { "EditProjectProps", GTK_STOCK_PROPERTIES, N_("_Edit Project Properties"), NULL, N_("Edit the project properties"), G_CALLBACK (window_project_props_cb) }, /* { "PreferencesEditPreferences", NULL, NULL, NULL, NULL, G_CALLBACK (window_preferences_cb) },*/ { "Help", NULL, N_("_Help"), NULL, NULL, NULL }, { "HelpHelp", GTK_STOCK_HELP, N_("_User Guide"), "F1", N_("Show the Planner User Guide"), G_CALLBACK (window_help_cb) }, { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("About this application"), G_CALLBACK (window_about_cb) }, }; static guint n_entries = G_N_ELEMENTS(entries); GType planner_window_get_type (void) { static GtkType type = 0; if (!type) { static const GTypeInfo info = { sizeof (PlannerWindowClass), NULL, /* base_init */ NULL, /* base_finalize */ (GClassInitFunc) window_class_init, NULL, /* class_finalize */ NULL, /* class_data */ sizeof (PlannerWindow), 0, /* n_preallocs */ (GInstanceInitFunc) window_init }; type = g_type_register_static (GTK_TYPE_WINDOW, "PlannerWindow", &info, 0); } return type; } static void window_class_init (PlannerWindowClass *klass) { GObjectClass *o_class; parent_class = g_type_class_peek_parent (klass); o_class = (GObjectClass *) klass; /* GObject functions */ o_class->finalize = window_finalize; /* Signals */ signals[CLOSED] = g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, /*G_STRUCT_OFFSET (PlannerWindowClass, method), */ NULL, NULL, planner_marshal_VOID__VOID, G_TYPE_NONE, 0); } static void window_init (PlannerWindow *window) { PlannerWindowPriv *priv; priv = g_new0 (PlannerWindowPriv, 1); window->priv = priv; /* Setup drag-n-drop. */ gtk_drag_dest_set (GTK_WIDGET (window), GTK_DEST_DEFAULT_ALL, drop_target_types, G_N_ELEMENTS (drop_target_types), GDK_ACTION_COPY); g_signal_connect (window, "drag_data_received", G_CALLBACK (window_drag_data_received_cb), window); priv->cmd_manager = planner_cmd_manager_new (); g_signal_connect (priv->cmd_manager, "undo_state_changed", G_CALLBACK (window_undo_state_changed_cb), window); g_signal_connect (priv->cmd_manager, "redo_state_changed", G_CALLBACK (window_redo_state_changed_cb), window); } static void window_finalize (GObject *object) { PlannerWindow *window = PLANNER_WINDOW (object); PlannerWindowPriv *priv = window->priv; if (priv->application) { g_object_unref (priv->application); } if (priv->last_saved) { g_timer_destroy (priv->last_saved); } if (priv->cmd_manager) { g_object_unref (priv->cmd_manager); } if (priv->recent_view) { g_object_unref (priv->recent_view); } if (priv->ui_manager) { g_object_unref (priv->ui_manager); } g_free (window->priv); if (G_OBJECT_CLASS (parent_class)->finalize) { (* G_OBJECT_CLASS (parent_class)->finalize) (object); } } static void planner_window_open_recent_cb (GtkAction *action, PlannerWindow *window) { const EggRecentItem *item; const gchar *uri; item = egg_recent_view_uimanager_get_item (window->priv->recent_view, action); uri = egg_recent_item_peek_uri (item); planner_window_open_in_existing_or_new (window, uri, FALSE); } static void window_add_widget (GtkUIManager *merge, GtkWidget *widget, PlannerWindow *window) { PlannerWindowPriv *priv; priv = window->priv; gtk_box_pack_start (GTK_BOX (priv->ui_box), widget, FALSE, FALSE, 0); } static void window_add_stock_icon (GtkIconFactory *icon_factory, const gchar *stock_id, const gchar *filename) { gchar *path; GdkPixbuf *pixbuf; GtkIconSet *icon_set; path = mrp_paths_get_image_dir (filename); pixbuf = gdk_pixbuf_new_from_file (path, NULL); icon_set = gtk_icon_set_new_from_pixbuf (pixbuf); g_object_unref (pixbuf); gtk_icon_factory_add (icon_factory, stock_id, icon_set); g_free (path); } static void window_add_stock_icons (void) { static GtkIconFactory *icon_factory = NULL; if (icon_factory) { return; } icon_factory = gtk_icon_factory_new (); gtk_icon_factory_add_default (icon_factory); /* Task/Gantt icons. */ window_add_stock_icon (icon_factory, "planner-stock-insert-task", "24_insert_task.png"); window_add_stock_icon (icon_factory, "planner-stock-remove-task", "24_remove_task.png"); window_add_stock_icon (icon_factory, "planner-stock-unlink-task", "24_unlink_task.png"); window_add_stock_icon (icon_factory, "planner-stock-link-task", "24_link_task.png"); window_add_stock_icon (icon_factory, "planner-stock-indent-task", "24_indent_task.png"); window_add_stock_icon (icon_factory, "planner-stock-unindent-task", "24_unindent_task.png"); window_add_stock_icon (icon_factory, "planner-stock-move-task-up", "24_task_up.png"); window_add_stock_icon (icon_factory, "planner-stock-move-task-down", "24_task_down.png"); /* Resource icons. */ window_add_stock_icon (icon_factory, "planner-stock-insert-resource", "/24_insert_resource.png"); window_add_stock_icon (icon_factory, "planner-stock-remove-resource", "24_remove_resource.png"); window_add_stock_icon (icon_factory, "planner-stock-edit-resource", "24_edit_resource.png"); window_add_stock_icon (icon_factory, "planner-stock-edit-groups", "24_groups.png"); } static void window_populate (PlannerWindow *window) { PlannerWindowPriv *priv; GtkWidget *hbox; GList *l; GtkWidget *view_widget; PlannerView *view; gint view_num; GtkRadioActionEntry *r_entries; gchar *xml_string_tmp, *xml_string; gchar *str; gchar *filename; const gchar *xml_string_full = "" "" "" "" "%s" "" "" "" ""; priv = window->priv; window_add_stock_icons (); priv->ui_box = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), priv->ui_box); priv->actions = gtk_action_group_new ("Planner"); gtk_action_group_set_translation_domain (priv->actions, GETTEXT_PACKAGE); gtk_action_group_add_actions (priv->actions, entries, n_entries, window); priv->ui_manager = gtk_ui_manager_new (); g_signal_connect (priv->ui_manager, "add_widget", G_CALLBACK (window_add_widget), window); g_signal_connect (priv->ui_manager, "connect_proxy", G_CALLBACK (window_connect_proxy_cb), window); g_signal_connect (priv->ui_manager, "disconnect_proxy", G_CALLBACK (window_disconnect_proxy_cb), window); gtk_ui_manager_insert_action_group (priv->ui_manager, priv->actions, 0); gtk_window_add_accel_group (GTK_WINDOW (window), gtk_ui_manager_get_accel_group (priv->ui_manager)); filename = mrp_paths_get_ui_dir ("main-window.ui"); gtk_ui_manager_add_ui_from_file (priv->ui_manager, filename , NULL); g_free (filename); g_object_set (gtk_action_group_get_action (priv->actions, "EditUndo"), "sensitive", FALSE, NULL); g_object_set (gtk_action_group_get_action (priv->actions, "EditRedo"), "sensitive", FALSE, NULL); g_object_set (gtk_action_group_get_action (priv->actions, "FileSave"), "sensitive", FALSE, NULL); /* Make the Actions menu always visible even when empty. */ g_object_set (gtk_action_group_get_action (priv->actions, "Actions"), "hide-if-empty", FALSE, NULL); /* Handle recent file stuff. */ priv->recent_view = egg_recent_view_uimanager_new (priv->ui_manager, "/MenuBar/File/OpenRecent", G_CALLBACK (planner_window_open_recent_cb), window); egg_recent_view_set_model (EGG_RECENT_VIEW (priv->recent_view), planner_application_get_recent_model (priv->application)); egg_recent_view_uimanager_set_tooltip_func (priv->recent_view, window_recent_tooltip_func, NULL); hbox = gtk_hbox_new (FALSE, 0); priv->sidebar = planner_sidebar_new (); gtk_box_pack_start (GTK_BOX (hbox), priv->sidebar, FALSE, TRUE, 0); g_signal_connect (priv->sidebar, "icon-selected", G_CALLBACK (window_view_selected), window); priv->notebook = gtk_notebook_new (); gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE); gtk_box_pack_start (GTK_BOX (hbox), priv->notebook, TRUE, TRUE, 0); priv->statusbar = gtk_statusbar_new (); gtk_box_pack_end (GTK_BOX (priv->ui_box), priv->statusbar, FALSE, TRUE, 0); gtk_widget_show (priv->statusbar); gtk_box_pack_end (GTK_BOX (priv->ui_box), hbox, TRUE, TRUE, 0); /* Create views. */ priv->view_actions = gtk_action_group_new ("View Actions"); gtk_ui_manager_insert_action_group (priv->ui_manager, priv->view_actions, 0); priv->views = NULL; priv->views = g_list_append (priv->views, planner_gantt_view_new ()); priv->views = g_list_append (priv->views, planner_task_view_new ()); priv->views = g_list_append (priv->views, planner_resource_view_new ()); priv->views = g_list_append (priv->views, planner_usage_view_new ()); view_num = 0; xml_string = g_strdup (""); r_entries = g_new0 (GtkRadioActionEntry, g_list_length (priv->views)); for (l = priv->views; l; l = l->next, view_num++ ) { view = l->data; planner_view_setup (view, window); view_widget = planner_view_get_widget (view); gtk_widget_show (view_widget); planner_sidebar_append (PLANNER_SIDEBAR (priv->sidebar), planner_view_get_icon (view), planner_view_get_label (view)); r_entries[view_num].name = planner_view_get_name (view); r_entries[view_num].label = planner_view_get_menu_label (view); r_entries[view_num].value = view_num; /* Note: these strings are leaked. */ r_entries[view_num].tooltip = g_strdup_printf (_("Switch to the view \"%s\""), planner_view_get_label (view)); xml_string_tmp = xml_string; xml_string = g_strdup_printf ("%s", xml_string, r_entries[view_num].name); g_free (xml_string_tmp); gtk_notebook_append_page ( GTK_NOTEBOOK (priv->notebook), view_widget, gtk_label_new (planner_view_get_label (view))); } gtk_action_group_add_radio_actions (priv->view_actions, r_entries, g_list_length (priv->views), 0, G_CALLBACK (window_view_cb), window); xml_string_tmp = g_strdup_printf (xml_string_full, xml_string); gtk_ui_manager_add_ui_from_string (priv->ui_manager, xml_string_tmp, -1, NULL); g_free (xml_string); g_free (xml_string_tmp); gtk_ui_manager_ensure_update (priv->ui_manager); /* Load plugins. */ priv->plugins = planner_plugin_loader_load (window); str = planner_conf_get_string (CONF_ACTIVE_VIEW, NULL); if (str) { gboolean found; found = FALSE; view_num = 0; for (l = priv->views; l; l = l->next, view_num++ ) { view = l->data; if (strcmp (str, planner_view_get_name (view)) == 0) { found = TRUE; break; } } if (!found) { view_num = 0; } window_view_selected (PLANNER_SIDEBAR (priv->sidebar), view_num, window); g_free (str); } else { window_view_selected (PLANNER_SIDEBAR (priv->sidebar), 0, window); } } static void window_view_selected (PlannerSidebar *sidebar, gint index, PlannerWindow *window) { PlannerWindowPriv *priv; GList *list; PlannerView *view; GtkAction *action; priv = window->priv; list = g_list_nth (priv->views, index); if (list != NULL) { view = list->data; } else { view = NULL; } if (view == priv->current_view) { return; } if (priv->current_view != NULL) { planner_view_deactivate (priv->current_view); } if (view != NULL) { planner_view_activate (view); } gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), index); g_signal_handlers_block_by_func (sidebar, window_view_selected, window); planner_sidebar_set_active (PLANNER_SIDEBAR (sidebar), index); g_signal_handlers_unblock_by_func (sidebar, window_view_selected, window); action = gtk_action_group_get_action (priv->view_actions, planner_view_get_name (view)); if (!gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) ) { gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE); } priv->current_view = view; planner_conf_set_string (CONF_ACTIVE_VIEW, planner_view_get_name (view), NULL); } static void window_view_cb (GtkAction *action, GtkRadioAction *current, gpointer data) { PlannerWindow *window; GtkWidget *sidebar; guint index; window = PLANNER_WINDOW (data); sidebar = window->priv->sidebar; index = gtk_radio_action_get_current_value(current); planner_sidebar_set_active (PLANNER_SIDEBAR (sidebar), index); } static void window_new_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; GtkWidget *new_window; window = PLANNER_WINDOW (data); priv = window->priv; new_window = planner_application_new_window (priv->application); gtk_widget_show_all (new_window); } static gchar * get_last_dir (PlannerWindow *window) { PlannerWindowPriv *priv; gchar *last_dir; priv = window->priv; last_dir = planner_conf_get_string (CONF_LAST_DIR, NULL); if (last_dir == NULL) { last_dir = g_strdup (g_get_home_dir ()); } return last_dir; } static void window_open_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; GtkWidget *file_chooser; GtkFileFilter *filter; gint response; gchar *last_dir; window = PLANNER_WINDOW (data); priv = window->priv; file_chooser = gtk_file_chooser_dialog_new (_("Open a File"), GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL); gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (file_chooser), TRUE); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("Planner Files")); gtk_file_filter_add_pattern (filter, "*.planner"); gtk_file_filter_add_pattern (filter, "*.mrproject"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_chooser), filter); filter = gtk_file_filter_new (); gtk_file_filter_set_name (filter, _("All Files")); gtk_file_filter_add_pattern (filter, "*"); gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_chooser), filter); last_dir = get_last_dir (window); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser), last_dir); g_free (last_dir); gtk_window_set_modal (GTK_WINDOW (file_chooser), TRUE); gtk_widget_show (file_chooser); response = gtk_dialog_run (GTK_DIALOG (file_chooser)); gtk_widget_hide (file_chooser); if (response == GTK_RESPONSE_OK) { GSList *uris, *l; uris = gtk_file_chooser_get_uris (GTK_FILE_CHOOSER (file_chooser)); if (uris) { gchar *filename; filename = g_filename_from_uri (uris->data, NULL, NULL); if (filename) { last_dir = g_path_get_dirname (filename); g_free (filename); planner_conf_set_string (CONF_LAST_DIR, last_dir, NULL); g_free (last_dir); } } for (l = uris; l; l = l->next) { planner_window_open_in_existing_or_new (window, l->data, FALSE); } g_slist_foreach (uris, (GFunc) g_free, NULL); g_slist_free (uris); } gtk_widget_destroy (file_chooser); } static void window_save_as_cb (GtkAction *action, gpointer data) { PlannerWindow *window; window = PLANNER_WINDOW (data); window_do_save_as (window); } static void window_save_cb (GtkAction *action, gpointer data) { PlannerWindow *window; window = PLANNER_WINDOW (data); window_do_save (window, FALSE); } static GList * window_get_print_selection (PlannerWindow *window) { PlannerWindowPriv *priv; GList *views = NULL, *l; PlannerView *view; gchar *str; priv = window->priv; for (l = priv->views; l; l = l->next) { view = l->data; str = g_strdup_printf ("/views/%s/print_enabled", planner_view_get_name (view)); if (planner_conf_get_bool (str, NULL)) { views = g_list_append (views, view); } g_free (str); } return views; } static void window_print_preview_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; GnomePrintConfig *config; GnomePrintJob *gpj; GtkWidget *dialog; GtkWidget *preview; GList *views, *l; PlannerView *view; PlannerPrintJob *job; gboolean summary; gint n_pages, n_views; gint response; window = PLANNER_WINDOW (data); priv = window->priv; /* Load printer settings */ config = planner_print_dialog_load_config (); gpj = gnome_print_job_new (config); gnome_print_config_unref (config); job = planner_print_job_new (gpj); views = window_get_print_selection (window); /* Check to be sure there are some views selected */ n_views = g_list_length (views); if (n_views == 0) { dialog = planner_print_views_dialog_new (window, priv->views); while (n_views == 0) { response = gtk_dialog_run (GTK_DIALOG (dialog)); if (response == GTK_RESPONSE_CANCEL) { gtk_widget_destroy (dialog); g_object_unref (gpj); return; } else if (response == GTK_RESPONSE_DELETE_EVENT) { gtk_widget_destroy (dialog); g_object_unref (gpj); return; } /* Save printer settings. */ planner_print_dialog_save_config (config); views = planner_print_dialog_get_print_selection (GTK_DIALOG (dialog), &summary); n_views = g_list_length (views); } gtk_widget_destroy (dialog); } n_pages = 0; for (l = views; l; l = l->next) { view = l->data; planner_view_print_init (view, job); n_pages += planner_view_print_get_n_pages (view); } planner_print_job_set_total_pages (job, n_pages); for (l = views; l; l = l->next) { view = l->data; planner_view_print (view); planner_view_print_cleanup (view); } gnome_print_job_close (job->pj); preview = gnome_print_job_preview_new (job->pj, "Planner"); gtk_widget_show (preview); g_list_free (views); g_object_unref (job); } static void window_print_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; GnomePrintJob *gpj; GnomePrintConfig *config; GtkWidget *dialog, *message; gint response; gboolean summary; GList *views, *l; PlannerView *view; PlannerPrintJob *job; gint n_pages, n_views; window = PLANNER_WINDOW (data); priv = window->priv; /* Load printer settings */ config = planner_print_dialog_load_config (); gpj = gnome_print_job_new (config); gnome_print_config_unref (config); dialog = planner_print_dialog_new (data, gpj, priv->views); /* n_views is the number of views selected. */ n_views = 0; while (n_views == 0) { response = gtk_dialog_run (GTK_DIALOG (dialog)); if (response == GTK_RESPONSE_CANCEL) { gtk_widget_destroy (dialog); g_object_unref (gpj); return; } else if (response == GTK_RESPONSE_DELETE_EVENT) { g_object_unref (gpj); return; } /* Save printer settings. */ planner_print_dialog_save_config (config); views = planner_print_dialog_get_print_selection (GTK_DIALOG (dialog), &summary); n_views = g_list_length (views); if (n_views == 0) { message = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", "Please choose one or more views to print."); gtk_dialog_run (GTK_DIALOG (message)); gtk_widget_destroy (message); } } if (summary) { /*g_print ("Print summary\n");*/ } job = planner_print_job_new (gpj); n_pages = 0; for (l = views; l; l = l->next) { view = l->data; planner_view_print_init (view, job); n_pages += planner_view_print_get_n_pages (view); } planner_print_job_set_total_pages (job, n_pages); for (l = views; l; l = l->next) { view = l->data; planner_view_print (view); planner_view_print_cleanup (view); } gtk_widget_destroy (dialog); gnome_print_job_close (job->pj); if (response == GNOME_PRINT_DIALOG_RESPONSE_PREVIEW) { GtkWidget *preview; preview = gnome_print_job_preview_new (job->pj, "Planner"); gtk_widget_show (preview); } else if (response == GNOME_PRINT_DIALOG_RESPONSE_PRINT) { gchar *tmp; /* This seems to be needed for now to stop older versions of * gnome-print from outputting locale dependent floats. Remove * this later. */ tmp = g_strdup (setlocale (LC_NUMERIC, NULL)); setlocale (LC_NUMERIC, "C"); gnome_print_job_print (job->pj); setlocale (LC_NUMERIC, tmp); g_free (tmp); } g_list_free (views); g_object_unref (job); g_object_unref (config); } static void window_close_cb (GtkAction *action, gpointer data) { planner_window_close (PLANNER_WINDOW (data)); } static void window_exit_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; window = PLANNER_WINDOW (data); priv = window->priv; planner_application_exit (priv->application); } static void window_redo_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; window = PLANNER_WINDOW (data); priv = window->priv; planner_cmd_manager_redo (priv->cmd_manager); } static void window_undo_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; window = PLANNER_WINDOW (data); priv = window->priv; planner_cmd_manager_undo (priv->cmd_manager); } static void window_project_props_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; window = PLANNER_WINDOW (data); priv = window->priv; if (priv->properties_dialog) { gtk_window_present (GTK_WINDOW (priv->properties_dialog)); } else { priv->properties_dialog = planner_project_properties_new (window); g_object_add_weak_pointer (G_OBJECT (priv->properties_dialog), (gpointer) &priv->properties_dialog); gtk_widget_show (priv->properties_dialog); } } static void window_manage_calendars_cb (GtkAction *action, gpointer data) { PlannerWindow *window; window = PLANNER_WINDOW (data); planner_window_show_calendar_dialog (window); } static void window_edit_day_types_cb (GtkAction *action, gpointer data) { PlannerWindow *window; window = PLANNER_WINDOW (data); planner_window_show_day_type_dialog (window); } static void window_edit_phases_cb (GtkAction *action, gpointer data) { PlannerWindow *window; PlannerWindowPriv *priv; window = PLANNER_WINDOW (data); priv = window->priv; if (priv->phase_dialog) { gtk_window_present (GTK_WINDOW (priv->phase_dialog)); } else { priv->phase_dialog = planner_phase_dialog_new (window); g_object_add_weak_pointer (G_OBJECT (priv->phase_dialog), (gpointer) &priv->phase_dialog); gtk_widget_show (priv->phase_dialog); } } static void window_help_cb (GtkAction *action, gpointer data) { GError *error = NULL; GtkWidget *dialog; if (!planner_util_show_help (&error)) { dialog = gtk_message_dialog_new (GTK_WINDOW (data), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", error->message); gtk_widget_show (dialog); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); g_error_free (error); } } static void handle_links (GtkAboutDialog *about, const gchar *link, gpointer data) { gchar *newlink; switch (GPOINTER_TO_INT (data)) { case LINK_TYPE_EMAIL: newlink = g_strdup_printf ("mailto:%s", link); break; case LINK_TYPE_URL: newlink = g_strdup (link); break; default: g_assert_not_reached (); } planner_util_show_url (newlink, NULL); g_free (newlink); } static void window_about_cb (GtkAction *action, gpointer data) { PlannerWindow *window; gchar *filename; GdkPixbuf *pixbuf; const gchar *authors[] = { "Kurt Maute ", "Richard Hult ", "Mikael Hallendal ", "Alvaro del Castillo ", NULL }; const gchar *documenters[] = { "Kurt Maute ", "Alvaro del Castillo ", "Pedro Soria-Rodriguez ", NULL }; /* I18n: Translators, list your names here, newline separated if there * are more than one, to appear in the about box. */ const gchar *translator_credits = N_("translator-credits"); window = PLANNER_WINDOW (data); filename = mrp_paths_get_image_dir ("gnome-planner.png"); pixbuf = gdk_pixbuf_new_from_file (filename, NULL); g_free (filename); gtk_about_dialog_set_email_hook ((GtkAboutDialogActivateLinkFunc) handle_links, GINT_TO_POINTER (LINK_TYPE_EMAIL), NULL); gtk_about_dialog_set_url_hook ((GtkAboutDialogActivateLinkFunc) handle_links, GINT_TO_POINTER (LINK_TYPE_URL), NULL); gtk_show_about_dialog (GTK_WINDOW (window), "name", "Planner", "version", VERSION, "comments", _("A Project Management application for the GNOME desktop"), "authors", authors, "documenters", documenters, "translator-credits", strcmp (translator_credits, _("translator-credits")) != 0 ? _(translator_credits) : NULL, "website", "http://live.gnome.org/Planner", "website-label", _("The Planner Homepage"), "logo", pixbuf, NULL); if (pixbuf != NULL) { gdk_pixbuf_unref (pixbuf); } } static gboolean window_delete_event_cb (PlannerWindow *window, gpointer user_data) { planner_window_close (window); return TRUE; } static void window_drag_data_received_cb (GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *data, guint info, guint time, PlannerWindow *window) { PlannerWindowPriv *priv; gchar **uris; gint i; priv = window->priv; if (data->length < 0 || data->format != 8) { g_message ("Don't know how to handle format %d", data->format); gtk_drag_finish (context, FALSE, FALSE, time); return; } uris = g_uri_list_extract_uris (data->data); i = 0; while (uris[i]) { planner_window_open_in_existing_or_new (window, uris[i], FALSE); i++; } g_strfreev (uris); gtk_drag_finish (context, TRUE, FALSE, time); } static void window_undo_state_changed_cb (PlannerCmdManager *manager, gboolean state, const gchar *str, PlannerWindow *window) { PlannerWindowPriv *priv; GtkWidget *widget; GtkWidget *label; priv = window->priv; g_object_set (gtk_action_group_get_action (priv->actions, "EditUndo"), "sensitive", state, NULL); g_object_set (gtk_action_group_get_action (priv->actions, "EditUndo"), "tooltip", str, NULL); widget = gtk_ui_manager_get_widget (priv->ui_manager, "/MenuBar/Edit/EditUndo"); label = gtk_bin_get_child (GTK_BIN (widget)); gtk_label_set_text (GTK_LABEL (label), str); } static void window_redo_state_changed_cb (PlannerCmdManager *manager, gboolean state, const gchar *str, PlannerWindow *window) { PlannerWindowPriv *priv; GtkWidget *widget; GtkWidget *label; priv = window->priv; g_object_set (gtk_action_group_get_action (priv->actions, "EditRedo"), "sensitive", state, NULL); g_object_set (gtk_action_group_get_action (priv->actions, "EditRedo"), "tooltip", str, NULL); widget = gtk_ui_manager_get_widget (priv->ui_manager, "/MenuBar/Edit/EditRedo"); label = gtk_bin_get_child (GTK_BIN (widget)); gtk_label_set_text (GTK_LABEL (label), str); } static void window_project_needs_saving_changed_cb (MrpProject *project, gboolean needs_saving, PlannerWindow *window) { PlannerWindowPriv *priv; priv = window->priv; if (needs_saving) { g_timer_reset (priv->last_saved); } g_object_set (gtk_action_group_get_action (priv->actions, "FileSave"), "sensitive", needs_saving, NULL); } static void window_project_notify_name_cb (MrpProject *project, GParamSpec *pspec, PlannerWindow *window) { window_update_title (window); } static gboolean window_confirm_exit_run (PlannerWindow *window) { PlannerWindowPriv *priv; gchar *time_str; GtkWidget *dialog; GtkWidget *quit_button, *cancel_button, *save_button; gint ret; gint minutes; gint hours; gchar *name; gchar *tmp; const gchar *uri; gboolean is_sql = FALSE; priv = window->priv; minutes = (gint) (g_timer_elapsed (priv->last_saved, NULL) / 60); minutes = MAX (1, minutes); hours = floor (minutes / 60.0 + 0.5); minutes -= 60 * hours; if (hours == 0 && minutes == 1) { time_str = g_strdup (_("If you don't save, changes made " "the last minute will be discarded.")); } else if (hours == 0) { time_str = g_strdup_printf (_("If you don't save, changes made " "the last %d minutes will be " "discarded."), minutes); } else if (hours == 1) { time_str = g_strdup (_("If you don't save, changes made " "the last hour will be " "discarded.")); } else { time_str = g_strdup_printf (_("If you don't save, changes made " "the last %d hours will be " "discarded."), hours); } name = window_get_name (window); tmp = g_strdup_printf (_("Save changes to document '%s' before closing?"), name); dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_NONE, "%s\n%s", tmp, time_str); g_free (name); g_free (time_str); g_free (tmp); g_object_set (GTK_MESSAGE_DIALOG (dialog)->label, "use-markup", TRUE, "wrap", FALSE, "selectable", FALSE, NULL); uri = mrp_project_get_uri (priv->project); if (uri && strncmp (uri, "sql://", 6) == 0) { /* Hack. */ is_sql = TRUE; } quit_button = window_create_dialog_button (GTK_STOCK_QUIT, _("C_lose without saving")); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), quit_button, GTK_RESPONSE_NO); cancel_button = window_create_dialog_button (GTK_STOCK_CANCEL, _("_Cancel")); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), cancel_button, GTK_RESPONSE_CANCEL); if (!is_sql) { save_button = window_create_dialog_button (GTK_STOCK_SAVE, _("_Save")); gtk_dialog_add_action_widget (GTK_DIALOG (dialog), save_button, GTK_RESPONSE_YES); gtk_widget_grab_focus (save_button); } gtk_widget_show_all (dialog); ret = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); switch (ret) { case GTK_RESPONSE_NO: /* Don't save */ return TRUE; break; case GTK_RESPONSE_DELETE_EVENT: case GTK_RESPONSE_CANCEL: /* Don't quit */ return FALSE; break; case GTK_RESPONSE_YES: /* Save and quit */ return window_do_save (window, FALSE); break; default: g_assert_not_reached (); }; return FALSE; } static gboolean window_do_save (PlannerWindow *window, gboolean force) { PlannerWindowPriv *priv; const gchar *uri = NULL; GError *error = NULL; gint response; priv = window->priv; uri = mrp_project_get_uri (priv->project); if (uri == NULL) { return window_do_save_as (window); } else { if (!mrp_project_save (priv->project, force, &error)) { GtkWidget *dialog; if (!force && error->code == MRP_ERROR_SAVE_FILE_CHANGED) { dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, error->message); response = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); if (response == GTK_RESPONSE_YES) { return window_do_save (window, TRUE); } return FALSE; } dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, error->message); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return FALSE; } } return TRUE; } static gboolean window_do_save_as (PlannerWindow *window) { PlannerWindowPriv *priv; GtkWidget *file_chooser; gint response; gchar *filename = NULL; gchar *last_dir; EggRecentItem *item; priv = window->priv; file_chooser = gtk_file_chooser_dialog_new (_("Save a File"), GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL); gtk_window_set_modal (GTK_WINDOW (file_chooser), TRUE); gtk_dialog_set_default_response (GTK_DIALOG (file_chooser), GTK_RESPONSE_OK); last_dir = get_last_dir (window); gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (file_chooser), last_dir); g_free (last_dir); response = gtk_dialog_run (GTK_DIALOG (file_chooser)); if (response == GTK_RESPONSE_OK) { filename = gtk_file_chooser_get_filename ( GTK_FILE_CHOOSER (file_chooser)); } gtk_widget_destroy (file_chooser); if (filename != NULL) { gboolean success; GError *error = NULL; /* Save the file. */ success = mrp_project_save_as (window->priv->project, filename, FALSE, &error); if (!success && error->code == MRP_ERROR_SAVE_FILE_EXIST) { GtkWidget *dialog; gint ret; dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("File \"%s\" exists, do you want to overwrite it?"), error->message); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES); ret = gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); switch (ret) { case GTK_RESPONSE_YES: success = mrp_project_save_as (priv->project, filename, TRUE, &error); break; case GTK_RESPONSE_NO: case GTK_RESPONSE_DELETE_EVENT: return window_do_save_as (window); break; default: g_assert_not_reached (); }; } if (success) { /* Add the file to the recent list */ item = egg_recent_item_new_from_uri (mrp_project_get_uri (priv->project)); egg_recent_item_set_mime_type (item, "application/x-planner"); egg_recent_model_add_full (planner_application_get_recent_model (priv->application), item); egg_recent_item_unref (item); } else { GtkWidget *dialog; dialog = gtk_message_dialog_new (GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, error->message); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return FALSE; } last_dir = g_path_get_dirname (filename); planner_conf_set_string (CONF_LAST_DIR, last_dir, NULL); g_free (last_dir); g_free (filename); return TRUE; } else { return FALSE; } } static GtkWidget * window_create_dialog_button (const gchar *icon_name, const gchar *text) { GtkWidget *button; GtkWidget *image; GtkWidget *label; GtkWidget *align; GtkWidget *hbox; button = gtk_button_new (); image = gtk_image_new_from_stock (icon_name, GTK_ICON_SIZE_BUTTON); label = gtk_label_new_with_mnemonic (text); gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button)); hbox = gtk_hbox_new (FALSE, 2); align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0); gtk_container_add (GTK_CONTAINER (button), align); gtk_container_add (GTK_CONTAINER (align), hbox); gtk_widget_show_all (align); return button; } GtkWidget * planner_window_new (PlannerApplication *application) { PlannerWindow *window; PlannerWindowPriv *priv; window = g_object_new (PLANNER_TYPE_WINDOW, NULL); priv = window->priv; priv->application = g_object_ref (application); priv->project = mrp_project_new (MRP_APPLICATION (application)); priv->last_saved = g_timer_new (); g_signal_connect (priv->project, "needs_saving_changed", G_CALLBACK (window_project_needs_saving_changed_cb), window); g_signal_connect (priv->project, "notify::name", G_CALLBACK (window_project_notify_name_cb), window); window_restore_state (window); g_signal_connect (window, "delete_event", G_CALLBACK (window_delete_event_cb), NULL); window_populate (window); window_update_title (window); return GTK_WIDGET (window); } gboolean planner_window_open (PlannerWindow *window, const gchar *uri, gboolean internal) { PlannerWindowPriv *priv; GError *error = NULL; GtkWidget *dialog; EggRecentItem *item; g_return_val_if_fail (PLANNER_IS_WINDOW (window), FALSE); g_return_val_if_fail (uri != NULL, FALSE); priv = window->priv; if (!mrp_project_load (priv->project, uri, &error)) { dialog = gtk_message_dialog_new ( GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, error->message); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); return FALSE; } planner_window_check_version (window); if (!internal) { /* Add the file to the recent list */ item = egg_recent_item_new_from_uri (uri); egg_recent_item_set_mime_type (item, "application/x-planner"); egg_recent_model_add_full (planner_application_get_recent_model (priv->application), item); egg_recent_item_unref (item); window_update_title (window); } return TRUE; } gboolean planner_window_open_in_existing_or_new (PlannerWindow *window, const gchar *uri, gboolean internal) { PlannerWindowPriv *priv; GtkWidget *new_window; gchar *filename; gboolean ret; priv = window->priv; filename = g_filename_from_uri (uri, NULL, NULL); if (!filename) { return FALSE; } if (mrp_project_is_empty (priv->project)) { ret = planner_window_open (window, filename, internal); g_free (filename); return ret; } else { new_window = planner_application_new_window (priv->application); if (planner_window_open (PLANNER_WINDOW (new_window), filename, internal)) { g_free (filename); gtk_widget_show_all (new_window); return TRUE; } else { g_free (filename); g_signal_emit (new_window, signals[CLOSED], 0, NULL); gtk_widget_destroy (new_window); return FALSE; } } g_free (filename); return FALSE; } GtkUIManager * planner_window_get_ui_manager (PlannerWindow *window) { g_return_val_if_fail (PLANNER_IS_WINDOW (window), NULL); return window->priv->ui_manager; } MrpProject * planner_window_get_project (PlannerWindow *window) { g_return_val_if_fail (PLANNER_IS_WINDOW (window), NULL); return window->priv->project; } PlannerApplication * planner_window_get_application (PlannerWindow *window) { g_return_val_if_fail (PLANNER_IS_WINDOW (window), NULL); return window->priv->application; } void planner_window_check_version (PlannerWindow *window) { PlannerWindowPriv *priv; GtkWidget *dialog; gint version; g_return_if_fail (PLANNER_IS_WINDOW (window)); priv = window->priv; version = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (priv->project), "version")); if (version == 1) { dialog = gtk_message_dialog_new ( GTK_WINDOW (window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, _("You have opened a file that was saved with an old " "version of Planner.\n" "\n" "When loading old files, all tasks will use the " "constraint 'Must Start On', since the old version " "did not fully support automatic rescheduling. To " "take advantage of this new feature, you should add " "predecessor relations between tasks that are " "dependant on each other.\n" "\n" "You can add a predecessor relation by clicking on " "the predecessor and dragging to the successor.\n" "\n" "After doing this, you can remove all constraints by " "selecting the menu item 'Remove all constraints' in " "the 'Edit' menu.")); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_destroy (dialog); } } /* Returns the project name, filename, or "Unnamed", in that order. */ static gchar * window_get_name (PlannerWindow *window) { PlannerWindowPriv *priv; gchar *name, *tmp; const gchar *uri; priv = window->priv; uri = mrp_project_get_uri (priv->project); if (uri && strncmp (uri, "sql://", 6) == 0) { /* Hack. */ uri = _("Unnamed database project"); } g_object_get (priv->project, "name", &name, NULL); if (name == NULL || name[0] == 0) { g_free (name); if (uri == NULL || uri[0] == 0) { name = g_strdup (_("Unnamed")); } else { tmp = g_path_get_basename (uri); name = g_markup_escape_text (tmp, -1); g_free (tmp); } } return name; } static void window_update_title (PlannerWindow *window) { PlannerWindowPriv *priv; gchar *name; gchar *title; priv = window->priv; name = window_get_name (window); title = g_strconcat (name, " - Planner", NULL); gtk_window_set_title (GTK_WINDOW (window), title); g_free (name); g_free (title); } void planner_window_close (PlannerWindow *window) { PlannerWindowPriv *priv; gboolean close = TRUE; g_return_if_fail (PLANNER_IS_WINDOW (window)); priv = window->priv; if (mrp_project_needs_saving (priv->project)) { close = window_confirm_exit_run (window); } if (close) { window_save_state (window); g_signal_emit (window, signals[CLOSED], 0, NULL); gtk_widget_destroy (GTK_WIDGET (window)); } } void planner_window_show_day_type_dialog (PlannerWindow *window) { PlannerWindowPriv *priv; g_return_if_fail (PLANNER_IS_WINDOW (window)); priv = window->priv; if (priv->day_type_dialog) { gtk_window_present (GTK_WINDOW (priv->day_type_dialog)); } else { priv->day_type_dialog = planner_day_type_dialog_new (window); g_object_add_weak_pointer (G_OBJECT (priv->day_type_dialog), (gpointer) &priv->day_type_dialog); gtk_widget_show (priv->day_type_dialog); } } void planner_window_show_calendar_dialog (PlannerWindow *window) { PlannerWindowPriv *priv; g_return_if_fail (PLANNER_IS_WINDOW (window)); priv = window->priv; if (priv->calendar_dialog) { gtk_window_present (GTK_WINDOW (priv->calendar_dialog)); } else { priv->calendar_dialog = planner_calendar_dialog_new (window); g_object_add_weak_pointer (G_OBJECT (priv->calendar_dialog), (gpointer) &priv->calendar_dialog); gtk_widget_show (priv->calendar_dialog); } } static gchar * window_recent_tooltip_func (EggRecentItem *item, gpointer user_data) { gchar *uri; gchar *escaped; gchar *tooltip; uri = egg_recent_item_get_uri_for_display (item); escaped = egg_recent_util_escape_underlines (uri); tooltip = g_strdup_printf (_("Open '%s'"), escaped); g_free (uri); g_free (escaped); return tooltip; } PlannerCmdManager * planner_window_get_cmd_manager (PlannerWindow *window) { g_return_val_if_fail (PLANNER_IS_WINDOW (window), NULL); return window->priv->cmd_manager; } static void window_save_state (PlannerWindow *window) { PlannerWindowPriv *priv; GdkWindowState state; gboolean maximized; priv = window->priv; state = gdk_window_get_state (GTK_WIDGET (window)->window); if (state & GDK_WINDOW_STATE_MAXIMIZED) { maximized = TRUE; } else { maximized = FALSE; } planner_conf_set_bool (CONF_WINDOW_MAXIMIZED, maximized, NULL); /* If maximized don't save the size and position */ if (!maximized) { int width, height; int x, y; gtk_window_get_size (GTK_WINDOW (window), &width, &height); planner_conf_set_int (CONF_WINDOW_WIDTH, width, NULL); planner_conf_set_int (CONF_WINDOW_HEIGHT, height, NULL); gtk_window_get_position (GTK_WINDOW (window), &x, &y); planner_conf_set_int (CONF_WINDOW_POS_X, x, NULL); planner_conf_set_int (CONF_WINDOW_POS_Y, y, NULL); } } static void window_restore_state (PlannerWindow *window) { PlannerWindowPriv *priv; gboolean exists; gboolean maximized; int width, height; int x, y; priv = window->priv; exists = planner_conf_dir_exists (CONF_WINDOW_DIR, NULL); if (exists) { maximized = planner_conf_get_bool (CONF_WINDOW_MAXIMIZED, NULL); if (maximized) { gtk_window_maximize (GTK_WINDOW (window)); } else { width = planner_conf_get_int (CONF_WINDOW_WIDTH, NULL); height = planner_conf_get_int (CONF_WINDOW_HEIGHT, NULL); gtk_window_set_default_size (GTK_WINDOW (window), width, height); x = planner_conf_get_int (CONF_WINDOW_POS_X, NULL); y = planner_conf_get_int (CONF_WINDOW_POS_Y, NULL); gtk_window_move (GTK_WINDOW (window), x, y); } } else { gtk_window_set_default_size (GTK_WINDOW (window), 800, 600); } } void planner_window_set_status (PlannerWindow *window, const gchar *message) { PlannerWindowPriv *priv; priv = window->priv; gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar), 0); gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar), 0, message ? message : ""); } static void window_menu_item_select_cb (GtkMenuItem *proxy, PlannerWindow *window) { PlannerWindowPriv *priv; GtkAction *action; gchar *message; priv = window->priv; action = g_object_get_data (G_OBJECT (proxy), "gtk-action"); g_return_if_fail (action != NULL); g_object_get (action, "tooltip", &message, NULL); if (message) { gtk_statusbar_push (GTK_STATUSBAR (priv->statusbar), 0, message); g_free (message); } } static void window_menu_item_deselect_cb (GtkMenuItem *proxy, PlannerWindow *window) { PlannerWindowPriv *priv; priv = window->priv; gtk_statusbar_pop (GTK_STATUSBAR (priv->statusbar), 0); } static void window_disconnect_proxy_cb (GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, PlannerWindow *window) { if (GTK_IS_MENU_ITEM (proxy)) { g_signal_handlers_disconnect_by_func ( proxy, G_CALLBACK (window_menu_item_select_cb), window); g_signal_handlers_disconnect_by_func (proxy, G_CALLBACK (window_menu_item_deselect_cb), window); } } static void window_connect_proxy_cb (GtkUIManager *manager, GtkAction *action, GtkWidget *proxy, PlannerWindow *window) { if (GTK_IS_MENU_ITEM (proxy)) { g_signal_connect (proxy, "select", G_CALLBACK (window_menu_item_select_cb), window); g_signal_connect (proxy, "deselect", G_CALLBACK (window_menu_item_deselect_cb), window); } }