/* Main menu callbacks for app main menubar for GTimeTracker * Copyright (C) 1997,98 Eckehard Berns * Copyright (C) 2001,2002,2003 Linas Vepstas * * 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 "app.h" #include "ctree.h" #include "ctree-gnome2.h" #include "cur-proj.h" #include "err-throw.h" #include "file-io.h" #include "gtt.h" #include "journal.h" #include "menucmd.h" #include "menus.h" #include "prefs.h" #include "proj.h" #include "props-proj.h" #include "timer.h" #include "toolbar.h" #include "xml-gtt.h" void about_box(GtkWidget *w, gpointer data) { static GtkWidget *about = NULL; const gchar *authors[] = { "Linas Vepstas ", "Eckehard Berns ", "George Lebl ", " ", _("Bug-fixes from:"), "Eric Anderson ", "Derek Atkins ", "Jonathan Blandford ", "Miguel de Icaza ", "John Fleck ", "Nat Friedman ", "Mark Galassi ", "Jeff Garzik ", "Sven M. Hallberg ", "Raja R Harinath ", "Peter Hawkins ", "Toshio Kuratomi ", "Egil Kvaleberg ", "Chris Lahey ", "Gregory McLean ", "Kjartan Maraas ", "Federico Mena Quintero ", "Tomas Ogren ", "Goedson Teixeira Paixao ", "Gediminas Paulauskas ", "Havoc Pennington ", "Ettore Perazzoli ", "Changwoo Ryu ", "Pablo Saratxaga ", "Carsten Schaar ", "Mark Stosberg ", "Tom Tromey ", "Sebastian Wilhelmi ", NULL }; const gchar *documentors[] = { "Eckehard Berns ", "Linas Vepstas ", NULL }; const gchar *translators = "Vasif Ismailoglu MD - az\n" "Borislav Aleksandrov - bg\n" "Ivan Vilata i Balaguer - ca\n" "Softcatala - ca\n" "David Sauer - cz\n" "George Lebl - cz\n" "Kenneth Christiansen - da\n" "Kim Schulz - da\n" "Birger Langkjer - da\n" "Keld Simonsen - da\n" "Ole Laursen - da\n" "Matthias Warkus - de\n" "Keld Simonsen - da\n" "Karl Eichwalder - de\n" "Benedikt Roth - de\n" "Christian Meyer - de\n" "Spiros Papadimitriou - el\n" "Simos Xenitellis - el\n" "Robert Brady - en_GB\n" "Pablo Saratxaga - es\n" "Manuel de Vega Barreiro - es\n" "Lauris Kaplinski - et\n" "Josu Wali*o - eu\n" "Antti Ahvensalmi - fi\n" "Tuomas Meril - fi\n" "Vincent Renardias - fr\n" "Thibaut Cousin - fr\n" "Christophe Merlet (RedFox) - fr\n" "Bretin Didier - fr\n" "Christophe Fergeau - fr\n" "Sean Ceallaigh - ga\n" "Jesus Bravo Alvarez - gl\n" "Ruben Lopez Gomez - gl\n" "Szabolcs BAN - hu\n" "Gergely Nagy - hu\n" "Andras Timar - hu\n" "Giovanni Bortolozzo - it\n" "Eiichiro ITANI - jp\n" "Yuusuke Tahara - jp\n" "Takayuki KUSANO - jp\n" "Changwoo Ryu - ko\n" "Young-Ho, Cha - ko\n" "Gediminas Paulauskas - lt\n" "Peteris Kriajlnis - lv\n" "Artis Trops - lv\n" "Mohamad Afifi Omar (App) - ms\n" "Hasbullah BIn Pit - ms\n" "Mendel mobach - nl\n" "Almer S. Tigelaar - nl\n" "Marc Maurer - nl\n" "Dennis Smit - nl\n" "Kjartan Maraas - nn\n" "Roy-Magne Mo - nn\n" "Kjartan Maraas - no\n" "Egil Kvaleberg - no\n" "GNOME PL Team - pl\n" "Nuno Ferreira - pt\n" "Francisco Petrecio Cavalcante Junior - pt\n" "Duarte Loreto - pt\n" "Alexandre Hautequest - pt_BR\n" "Ariel Bressan da Silva - pt_BR\n" "Goedson Teixeira Paixao - pt_BR\n" "Iustin Pop - ro\n" "Dan Damian - ro\n" "Valek Filppov - ru\n" "Sergey Panov - ru\n" "Stanislav Visnovsky - sk\n" "Andraz Tori - sl\n" "Martin Norbeck - sv\n" "Andreas Hyden - sv\n" "Christian Rose - sv\n" "Dinesh Nadarajah - ta\n" "Fatih Demir - tr\n" "Gorkem etin - tr\n" "Yuri Syrota - ua\n" "pclouds - vi\n" "Pablo Saratxaga - wa\n" "Wang Li - zh_CN\n" "Ming-Yen Hsu - zh_TW\n" "Abel Cheung - zh_TW.Big5\n" ; if (about != NULL) { gdk_window_show(about->window); gdk_window_raise(about->window); return; } about = gnome_about_new(GTT_APP_TITLE, VERSION, "Copyright (C) 1997,98 Eckehard Berns\n" "Copyright (C) 2001-2004 Linas Vepstas", #ifdef DEBUG __DATE__ ", " __TIME__, #else _("GnoTime is a combination stop-watch, diary, consultant billing " "system and todo-list manager. You can measure the amount of time you " "spend on a task, associate a memo with it, set a billing rate, print " "an invoice, as well as track the status of other projects."), #endif authors, documentors, translators, NULL); g_signal_connect(G_OBJECT(about), "destroy", G_CALLBACK(gtk_widget_destroyed), &about); gtk_widget_show(about); } /* =============================================================================== */ /* The below implements a new project popup dialog. * XXX It is HIG-deprecated and should be replaced by a * an editable c-tree entry line in the main window. * XXX FIXME remove this code ASAP ... */ static void project_name_desc(GtkDialog *w, gint response_id, GtkEntry **entries) { const char *name, *desc; GttProject *proj; GttProject *sib_prj; if (GTK_RESPONSE_OK != response_id) { gtk_widget_destroy (GTK_WIDGET (w)); return; } sib_prj = ctree_get_focus_project (global_ptw); if (!(name = gtk_entry_get_text(entries[0]))) return; if (!(desc = gtk_entry_get_text(entries[1]))) return; if (!name[0]) return; /* New project will have the same parent as the currently * running project. This seems like the sanest choice. */ proj = gtt_project_new_title_desc(name, desc); gtt_project_insert_after (proj, sib_prj); ctree_insert_after (global_ptw, proj, sib_prj); gtk_widget_destroy (GTK_WIDGET (w)); } static void free_data(GtkWidget *dlg, gpointer data) { g_free(data); } void new_project(GtkWidget *widget, gpointer data) { GtkWidget *w, *t, *title, *d, *desc; GtkDialog *dlg; GtkBox *vbox; GtkWidget **entries = g_new0(GtkWidget *, 2); GtkWidget *table; title = gnome_entry_new("project_title"); desc = gnome_entry_new("project_description"); entries[0] = gnome_entry_gtk_entry(GNOME_ENTRY(title)); entries[1] = gnome_entry_gtk_entry(GNOME_ENTRY(desc)); /* Create new dialog box */ w = gtk_dialog_new_with_buttons ( _("New Project..."), // GTK_WINDOW (widget), NULL, GTK_DIALOG_MODAL, NULL); g_signal_connect (G_OBJECT(w), "response", G_CALLBACK (project_name_desc), entries); dlg = GTK_DIALOG(w); gtk_dialog_add_button (dlg, GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_add_button (dlg, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); vbox = GTK_BOX(dlg->vbox); /* Put stuff into the dialog box */ t = gtk_label_new(_("Project Title")); d = gtk_label_new(_("Description")); table = gtk_table_new(2,2, FALSE); gtk_table_attach(GTK_TABLE(table), t, 0,1, 0,1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 2, 1); gtk_table_attach(GTK_TABLE(table), title, 1,2, 0,1, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 2, 1); gtk_table_attach(GTK_TABLE(table), d, 0,1, 1,2, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 2, 1); gtk_table_attach(GTK_TABLE(table), desc, 1,2, 1,2, GTK_FILL|GTK_EXPAND, GTK_FILL|GTK_EXPAND, 2, 1); gtk_box_pack_start(vbox, table, FALSE, FALSE, 2); gtk_widget_show(t); gtk_widget_show(title); gtk_widget_show(d); gtk_widget_show(desc); gtk_widget_show(table); gtk_widget_grab_focus(entries[0]); /* enter in first entry goes to next */ g_signal_connect_object (G_OBJECT (entries[0]), "activate", G_CALLBACK (gtk_widget_grab_focus), GTK_OBJECT (entries[1]), 0); // gnome_dialog_editable_enters(GNOME_DIALOG(dlg), // GTK_EDITABLE(entries[1])); g_signal_connect(G_OBJECT(dlg), "destroy", G_CALLBACK(free_data), entries); gtk_widget_show(GTK_WIDGET(dlg)); } /* ======================================================= */ /* Project cut-n-paste GUI interactions. Support infinite * undo by using glist to store list of cuts. */ /* XXX hack alert -- we should delete this list during shutdown. */ static GList *cutted_project_list = NULL; gboolean have_cutted_project (void) { return (NULL==cutted_project_list) ? FALSE : TRUE; } static inline void debug_print_cutted_proj_list (char * str) { #ifdef DEBUG GList *n; printf ("proj list --- \n"); if (NULL == cutted_project_list) { printf ("%s: project list is empty\n", str); } for (n=cutted_project_list; n; n=n->next) { GttProject *p = n->data; printf ("%s: n=%p prj=%p title=%s\n", str,n,p,gtt_project_get_title(p)); } printf ("\n"); #endif } void cut_project(GtkWidget *w, gpointer data) { GttProject *cut_prj; GttProject *prj; /* Do NOT cut unless the ctree window actually has focus. * Otherwise, it will lead to cutting mayhem. * (We might have gotten the ctrl-x cut event by accident) */ if (0 == ctree_has_focus (global_ptw)) return; cut_prj = ctree_get_focus_project (global_ptw); if (!cut_prj) return; cutted_project_list = g_list_prepend (cutted_project_list, cut_prj); debug_print_cutted_proj_list ("cut"); /* Clear out relevent GUI elements. */ prop_dialog_set_project(NULL); if (cut_prj == cur_proj) ctree_stop_timer (cur_proj); gtt_project_remove(cut_prj); ctree_remove(global_ptw, cut_prj); /* Update various subsystems */ /* Set the notes are to whatever the new focus project is. */ prj = ctree_get_focus_project (global_ptw); notes_area_set_project (global_na, prj); menu_set_states(); /* To enable paste menu item */ toolbar_set_states(); } void paste_project(GtkWidget *w, gpointer data) { GttProject *sib_prj; GttProject *p, *focus_prj; sib_prj = ctree_get_focus_project (global_ptw); debug_print_cutted_proj_list ("pre paste"); if (!cutted_project_list) return; p = cutted_project_list->data; if (NULL == cutted_project_list->next) { /* If we paste a second time, we better paste a copy ... */ cutted_project_list->data = gtt_project_dup(p); } else { /* Pop element off the top. */ cutted_project_list->data = NULL; cutted_project_list = g_list_delete_link(cutted_project_list, cutted_project_list); } debug_print_cutted_proj_list ("post paste"); /* Insert before the focus proj */ gtt_project_insert_before (p, sib_prj); if (!sib_prj) { /* top-level insert */ ctree_add(global_ptw, p); return; } ctree_insert_before(global_ptw, p, sib_prj); /* Set the notes are to whatever the new focus project is. * (which should be 'p', bbut we play it safe to avoid * weird inconsistent state.) */ focus_prj = ctree_get_focus_project (global_ptw); notes_area_set_project (global_na, focus_prj); } void copy_project(GtkWidget *w, gpointer data) { GttProject *prj; GList *n; prj = ctree_get_focus_project (global_ptw); if (!prj) return; prj = gtt_project_dup(prj); /* Hitting copy has effect of completely trashing * the list of earlier cut projects. We do this in order * to allow the most recently copied project to be pasted * multiple times. */ n = cutted_project_list; for (n=cutted_project_list; n; n=n->next) { GttProject *p = n->data; gtt_project_destroy (p); } g_list_free (cutted_project_list); cutted_project_list = g_list_prepend (NULL, prj); debug_print_cutted_proj_list ("copy"); /* Update various subsystems */ menu_set_states(); /* to enable paste menu item */ toolbar_set_states(); } /* ======================================================= */ /* Timer related menu functions */ void menu_start_timer(GtkWidget *w, gpointer data) { GttProject *prj; prj = ctree_get_focus_project (global_ptw); ctree_start_timer (prj); } void menu_stop_timer(GtkWidget *w, gpointer data) { ctree_stop_timer (cur_proj); } void menu_toggle_timer(GtkWidget *w, gpointer data) { GttProject *prj; prj = ctree_get_focus_project (global_ptw); if (timer_is_running()) { ctree_stop_timer (cur_proj); } else { ctree_start_timer (prj); } } void menu_options(GtkWidget *w, gpointer data) { prefs_dialog_show(); } void menu_properties(GtkWidget *w, gpointer data) { GttProject *prj; prj = ctree_get_focus_project (global_ptw); if (prj) { prop_dialog_show(prj); } } /* Cheesey usability hack to tell the user how to edit the timer * intervals. Replace with something intuitive at earliest convenience. * (Yes this generates compiler warnings ... thats the point !!! */ static void show_a (GtkWidget *w) { gtk_widget_destroy (w); show_report (NULL, ACTIVITY_REPORT); } void menu_howto_edit_times (GtkWidget *w,gpointer data) { char * msg; GtkWidget *mb; msg = _("To edit the timer interval for this project,\n" "open the Activity window and click on a link.\n" "This will bring up a menu of time editing options.\n"); mb = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_OK, msg); g_signal_connect (G_OBJECT(mb), "response", G_CALLBACK (show_a), mb); gtk_widget_show (mb); } /* ============================ END OF FILE ======================= */