/* * workbook.c: Workbook management (toplevel windows) * * Author: * Miguel de Icaza (miguel@gnu.org). * */ #include #include #include #include "gnumeric.h" #include "eval.h" #include "gnumeric-util.h" #include "gnumeric-sheet.h" #include "sheet-object.h" #include "dialogs.h" #include "main.h" #include "file.h" #include "xml-io.h" #include "plugin.h" #include "pixmaps.h" #include "widget-editable-label.h" /* The locations within the main table in the workbook */ #define WB_EA_LINE 0 #define WB_EA_SHEETS 1 #define WB_EA_STATUS 2 #define WB_COLS 1 Workbook *current_workbook; static int workbook_count; static GList *workbook_list = NULL; static void new_cmd (void) { Workbook *wb; wb = workbook_new_with_sheets (1); gtk_widget_show (wb->toplevel); } static void open_cmd (GtkWidget *widget, Workbook *wb) { char *fname = dialog_query_load_file (wb); Workbook *new_wb; if (fname && (new_wb = workbook_read (fname))) gtk_widget_show (new_wb->toplevel); } static void save_cmd (GtkWidget *widget, Workbook *wb) { workbook_save (wb); } static void save_as_cmd (GtkWidget *widget, Workbook *wb) { workbook_save_as (wb); } static void plugins_cmd (GtkWidget *widget, Workbook *wb) { GtkWidget *pm = plugin_manager_new (wb); gtk_widget_show(pm); } static void set_selection_halign (Workbook *wb, StyleHAlignFlags align) { Sheet *sheet; GList *cells, *l; sheet = workbook_get_current_sheet (wb); cells = sheet_selection_to_list (sheet); for (l = cells; l; l = l->next){ Cell *cell = l->data; cell_set_halign (cell, align); } g_list_free (cells); } static void left_align_cmd (GtkWidget *widget, Workbook *wb) { set_selection_halign (wb, HALIGN_LEFT); } static void right_align_cmd (GtkWidget *widget, Workbook *wb) { set_selection_halign (wb, HALIGN_RIGHT); } static void center_cmd (GtkWidget *widget, Workbook *wb) { set_selection_halign (wb, HALIGN_CENTER); } /* * change_selection_font * @wb: The workbook to operate on * @idx: the index in the X Logical font description to try to replace with * @new: list of possible values we want to substitute with. * * Changes the font for the selection for the range: it does this by replacing * the idxth component (counting from zero) of the X logical font description * with the values listed (in order of preference) in the new array. */ static void change_selection_font (Workbook *wb, int idx, char *new[]) { Sheet *sheet; GList *cells, *l; sheet = workbook_get_current_sheet (wb); cells = sheet_selection_to_list (sheet); for (l = cells; l; l = l->next){ Cell *cell = l->data; char *old_name, *new_name; int i; StyleFont *f; for (i = 0; new [i]; i++){ old_name = cell->style->font->font_name; new_name = font_change_component (old_name, idx, new [i]); f = style_font_new_simple (new_name, cell->style->font->units); g_free (new_name); if (f){ cell_set_font_from_style (cell, f); break; } } } g_list_free (cells); } static void bold_cmd (GtkWidget *widget, Workbook *wb) { GtkToggleButton *t = GTK_TOGGLE_BUTTON (widget); char *bold_names [] = { "bold", NULL }; char *normal_names [] = { "regular", "medium", "light", NULL }; if (!t->active) change_selection_font (wb, 2, normal_names); else change_selection_font (wb, 2, bold_names); } static void italic_cmd (GtkWidget *widget, Workbook *wb) { GtkToggleButton *t = GTK_TOGGLE_BUTTON (widget); char *italic_names [] = { "i", "o", NULL }; char *normal_names [] = { "r", NULL }; if (!t->active) change_selection_font (wb, 3, normal_names); else change_selection_font (wb, 3, italic_names); } static void create_line_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_set_mode_type (sheet, SHEET_MODE_CREATE_LINE); } static void create_arrow_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_set_mode_type (sheet, SHEET_MODE_CREATE_ARROW); } static void create_rectangle_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_set_mode_type (sheet, SHEET_MODE_CREATE_BOX); } static void create_ellipse_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_set_mode_type (sheet, SHEET_MODE_CREATE_OVAL); } static void workbook_do_destroy (Workbook *wb) { if (wb->filename) g_free (wb->filename); g_list_free (wb->eval_queue); g_free (wb->toolbar); if (wb->auto_expr){ expr_tree_unref (wb->auto_expr); string_unref (wb->auto_expr_desc); } workbook_list = g_list_remove (workbook_list, wb); workbook_count--; symbol_table_destroy (wb->symbol_names); if (workbook_count == 0) gtk_main_quit (); } void workbook_destroy (Workbook *wb) { gtk_widget_destroy (wb->toplevel); } static void workbook_widget_destroy (GtkWidget *widget, Workbook *wb) { workbook_do_destroy (wb); } static void cb_sheet_mark_clean (gpointer key, gpointer value, gpointer user_data) { Sheet *sheet = value; sheet_mark_clean (sheet); } void workbook_mark_clean (Workbook *wb) { g_return_if_fail (wb != NULL); g_hash_table_foreach (wb->sheets, cb_sheet_mark_clean, NULL); } typedef enum { CLOSE_DENY, CLOSE_ALLOW, CLOSE_RECHECK } CloseAction; static void cb_sheet_check_dirty (gpointer key, gpointer value, gpointer user_data) { Sheet *sheet = value; GtkWidget *d, *l; int *allow_close = user_data; int button; char *f, *s; if (!sheet->modified) return; if (*allow_close != CLOSE_ALLOW) return; d = gnome_dialog_new ( _("Warning"), GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, GNOME_STOCK_BUTTON_CANCEL, NULL); if (sheet->workbook->filename) s = g_strdup_printf ( _("Workbook %s has unsaved changes, save them?"), g_basename (sheet->workbook->filename)); else s = g_strdup (_("Workbook has unsaved changes, save them?")); l = gtk_label_new (s); gtk_widget_show (l); g_free (s); gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(d)->vbox), l, TRUE, TRUE, 0); gtk_window_set_position (GTK_WINDOW (d), GTK_WIN_POS_MOUSE); button = gnome_dialog_run (GNOME_DIALOG (d)); switch (button){ /* YES */ case 0: workbook_save (sheet->workbook); *allow_close = CLOSE_RECHECK; break; /* NO */ case 1: workbook_mark_clean (sheet->workbook); break; /* CANCEL */ case -1: case 2: *allow_close = CLOSE_DENY; break; } gtk_widget_destroy (d); } static int workbook_can_close (Workbook *wb) { CloseAction allow_close; do { allow_close = CLOSE_ALLOW; g_hash_table_foreach ( wb->sheets, cb_sheet_check_dirty, &allow_close); } while (allow_close == CLOSE_RECHECK); g_assert (allow_close == CLOSE_ALLOW || allow_close == CLOSE_DENY); return allow_close == CLOSE_ALLOW; } static void close_cmd (GtkWidget *widget, Workbook *wb) { if (workbook_can_close (wb)) workbook_destroy (wb); } static int workbook_delete_event (GtkWidget *widget, GdkEvent *event, Workbook *wb) { if (workbook_can_close (wb)){ workbook_destroy (wb); return FALSE; } else return TRUE; } static void quit_cmd (void) { GList *l, *n = NULL; /* * Duplicate the list as the workbook_list is modified during * workbook destruction */ for (l = workbook_list; l; l = l->next) n = g_list_prepend (n, l->data); for (l = n; l; l = l->next){ Workbook *wb = l->data; if (workbook_can_close (wb)) workbook_destroy (wb); } g_list_free (n); } static void paste_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_selection_paste (sheet, sheet->cursor_col, sheet->cursor_row, PASTE_DEFAULT, GDK_CURRENT_TIME); } static void copy_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_selection_copy (sheet); } static void cut_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); if (sheet->mode == SHEET_MODE_SHEET) sheet_selection_cut (sheet); else { if (sheet->current_object){ sheet_object_destroy (sheet->current_object); sheet_set_mode_type (sheet, SHEET_MODE_SHEET); } else printf ("no object selected\n"); } } static void paste_special_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; int flags; sheet = workbook_get_current_sheet (wb); flags = dialog_paste_special (wb); sheet_selection_paste (sheet, sheet->cursor_col, sheet->cursor_row, flags, GDK_CURRENT_TIME); } static void select_all_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet = workbook_get_current_sheet (wb); sheet_select_all (sheet); sheet_redraw_all (sheet); } static void goto_cell_cmd (GtkWidget *unused, Workbook *wb) { dialog_goto_cell (wb); } static void define_cell_cmd (GtkWidget *unused, Workbook *wb) { dialog_define_names (wb); } static void insert_sheet_cmd (GtkWidget *unused, Workbook *wb) { Sheet *sheet; char *name; name = workbook_sheet_get_free_name (wb); sheet = sheet_new (wb, name); g_free (name); workbook_attach_sheet (wb, sheet); } static void insert_cells_cmd (GtkWidget *unused, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); dialog_insert_cells (wb, sheet); } static void insert_cols_cmd (GtkWidget *unused, Workbook *wb) { SheetSelection *ss; Sheet *sheet; int cols; sheet = workbook_get_current_sheet (wb); if (!sheet_verify_selection_simple (sheet, _("Insert rows"))) return; ss = sheet->selections->data; cols = ss->end_col - ss->start_col + 1; sheet_insert_col (sheet, ss->start_col, cols); } static void insert_rows_cmd (GtkWidget *unused, Workbook *wb) { SheetSelection *ss; Sheet *sheet; int rows; sheet = workbook_get_current_sheet (wb); if (!sheet_verify_selection_simple (sheet, _("Insert rows"))) return; ss = sheet->selections->data; rows = ss->end_row - ss->start_row + 1; sheet_insert_row (sheet, ss->start_row, rows); } static void clear_all_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_selection_clear (sheet); } static void clear_formats_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_selection_clear_formats (sheet); } static void clear_comments_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_selection_clear_comments (sheet); } static void clear_content_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_selection_clear_content (sheet); } static void zoom_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); dialog_zoom (wb, sheet); } static void format_cells_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); dialog_cell_format (wb, sheet); } static void recalc_cmd (GtkWidget *widget, Workbook *wb) { workbook_recalc_all (wb); } static void insert_at_cursor (Sheet *sheet, double n, char *format) { char buffer [40]; Cell *cell; snprintf (buffer, sizeof (buffer)-1, "%g", n); cell = sheet_cell_fetch (sheet, sheet->cursor_col, sheet->cursor_row); cell_set_text (cell, buffer); cell_set_format (cell, format); workbook_recalc (sheet->workbook); } static void insert_current_date_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet = workbook_get_current_sheet (wb); char *preferred_date_format = _(">mm/dd/yyyy"); int n; GDate *date = g_date_new(); g_date_set_time (date, time (NULL)); n = g_date_serial (date); g_date_free( date ); insert_at_cursor (sheet, n, preferred_date_format+1); } static void insert_current_time_cmd (GtkWidget *widget, Workbook *wb) { Sheet *sheet = workbook_get_current_sheet (wb); time_t t = time (NULL); struct tm *tm = localtime (&t); char *preferred_time_format = _(">hh:mm"); double n; n = (tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec)/(24*3600.0); insert_at_cursor (sheet, n, preferred_time_format); } static void workbook_edit_comment (GtkWidget *widget, Workbook *wb) { Sheet *sheet = workbook_get_current_sheet (wb); Cell *cell; cell = sheet_cell_get (sheet, sheet->cursor_col, sheet->cursor_row); if (!cell){ cell = sheet_cell_new (sheet, sheet->cursor_col, sheet->cursor_row); cell_set_text (cell, ""); } dialog_cell_comment (wb, cell); } static void about_cmd (GtkWidget *widget, Workbook *wb) { dialog_about (wb); } static void filenames_dropped (GtkWidget * widget, GdkDragContext *context, gint x, gint y, GtkSelectionData *selection_data, guint info, guint time) { GList *names, *tmp_list; names = gnome_uri_list_extract_filenames ((char *)selection_data->data); tmp_list = names; while (tmp_list) { Workbook *new_wb; if ((new_wb = workbook_read (tmp_list->data))) gtk_widget_show (new_wb->toplevel); tmp_list = tmp_list->next; } } /* File menu */ static GnomeUIInfo workbook_menu_file [] = { GNOMEUIINFO_MENU_NEW_ITEM(N_("_New"), N_("Create a new spreadsheet"), new_cmd, NULL), GNOMEUIINFO_MENU_OPEN_ITEM(open_cmd, NULL), GNOMEUIINFO_MENU_SAVE_ITEM(save_cmd, NULL), GNOMEUIINFO_MENU_SAVE_AS_ITEM(save_as_cmd, NULL), GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Plu_g-ins..."), N_("Gnumeric plugins"), plugins_cmd }, GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_CLOSE_ITEM(close_cmd, NULL), GNOMEUIINFO_MENU_EXIT_ITEM(quit_cmd, NULL), GNOMEUIINFO_END }; /* Edit menu */ static GnomeUIInfo workbook_menu_edit_clear [] = { { GNOME_APP_UI_ITEM, N_("_All"), N_("Clear the selected cells' formats, comments, and contents"), NULL, clear_all_cmd }, { GNOME_APP_UI_ITEM, N_("_Formats"), N_("Clear the selected cells' formats"), clear_formats_cmd }, { GNOME_APP_UI_ITEM, N_("_Comments"), N_("Clear the selected cells' comments"), clear_comments_cmd }, { GNOME_APP_UI_ITEM, N_("_Content"), N_("Clear the selected cells' contents"), clear_content_cmd }, GNOMEUIINFO_END }; static GnomeUIInfo workbook_menu_edit [] = { GNOMEUIINFO_MENU_CUT_ITEM(cut_cmd, NULL), GNOMEUIINFO_MENU_COPY_ITEM(copy_cmd, NULL), GNOMEUIINFO_MENU_PASTE_ITEM(paste_cmd, NULL), { GNOME_APP_UI_ITEM, N_("P_aste special..."), NULL, paste_special_cmd }, { GNOME_APP_UI_SUBTREE, N_("C_lear"), N_("Clear the selected cell(s)"), workbook_menu_edit_clear }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("_Select All"), N_("Select all cells in the spreadsheet"), select_all_cmd, NULL, NULL, 0, 0, 'a', GDK_CONTROL_MASK }, { GNOME_APP_UI_ITEM, N_("_Goto cell.."), N_("Jump to a specified cell"), goto_cell_cmd, NULL, NULL, 0, 0, 'i', GDK_CONTROL_MASK }, GNOMEUIINFO_SEPARATOR, #if 0 { GNOME_APP_UI_ITEM, N_("_Define cell names"), NULL, define_cell_cmd }, GNOMEUIINFO_SEPARATOR, #endif { GNOME_APP_UI_ITEM, N_("_Recalculate"), N_("Recalculate the spreadsheet"), recalc_cmd, NULL, NULL, 0, 0, GDK_F9, 0 }, GNOMEUIINFO_END }; /* View menu */ static GnomeUIInfo workbook_menu_view [] = { { GNOME_APP_UI_ITEM, N_("_Zoom..."), N_("Zoom the spreadsheet in or out"), zoom_cmd }, GNOMEUIINFO_END }; /* Insert menu */ static GnomeUIInfo workbook_menu_insert_special [] = { { GNOME_APP_UI_ITEM, N_("Current _date"), N_("Insert the current data into the selected cell(s)"), insert_current_date_cmd, NULL, NULL, 0, 0, ';', GDK_CONTROL_MASK }, { GNOME_APP_UI_ITEM, N_("Current _time"), N_("Insert the current time into the selected cell(s)"), insert_current_time_cmd, NULL, NULL, 0, 0, ';', GDK_CONTROL_MASK | GDK_SHIFT_MASK }, GNOMEUIINFO_END }; static GnomeUIInfo workbook_menu_insert [] = { { GNOME_APP_UI_ITEM, N_("_Sheet"), N_("Insert a new spreadsheet"), insert_sheet_cmd }, { GNOME_APP_UI_ITEM, N_("_Cells..."), N_("Insert new cells"), insert_cells_cmd }, { GNOME_APP_UI_ITEM, N_("_Rows"), N_("Insert new rows"), insert_rows_cmd }, { GNOME_APP_UI_ITEM, N_("C_olumns"), N_("Insert new columns"), insert_cols_cmd }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("_Add/Modify comment"), N_("Edit the selected cell's comment"), workbook_edit_comment }, { GNOME_APP_UI_SUBTREE, N_("_Special"), NULL, workbook_menu_insert_special }, GNOMEUIINFO_END }; /* Format menu */ #if 0 static GnomeUIInfo workbook_menu_format_column [] = { { GNOME_APP_UI_ITEM, N_("_Autoadjust"), NULL, format_column_autoadjust_cmd }, { GNOME_APP_UI_ITEM, N_("_Width"), NULL, format_column_width_cmd }, GNOMEUIINFO_END }; static GnomeUIInfo workbook_menu_format_row [] = { { GNOME_APP_UI_ITEM, N_("_Autoadjust"), NULL, format_row_autoadjust_cmd }, { GNOME_APP_UI_ITEM, N_("_Height"), NULL, format_row_height_cmd }, GNOMEUIINFO_END }; static GnomeUIInfo workbook_menu_format_sheet [] = { { GNOME_APP_UI_ITEM, N_("_Change name"), NULL, format_sheet_change_name_cmd }, GNOMEUIINFO_END }; #endif static GnomeUIInfo workbook_menu_format [] = { { GNOME_APP_UI_ITEM, N_("_Cells..."), N_("Modify the formatting of the selected cells"), format_cells_cmd, NULL, NULL, 0, 0, GDK_1, GDK_CONTROL_MASK }, #if 0 { GNOME_APP_UI_SUBTREE, N_("C_olumn"), NULL, workbook_menu_format_column }, { GNOME_APP_UI_SUBTREE, N_("_Row"), NULL, workbook_menu_format_row }, { GNOME_APP_UI_SUBTREE, N_("_Sheet"), NULL, workbook_menu_format_sheet }, #endif GNOMEUIINFO_END }; static GnomeUIInfo workbook_menu_help [] = { GNOMEUIINFO_MENU_ABOUT_ITEM(about_cmd, NULL), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_HELP ("gnumeric"), GNOMEUIINFO_END }; static GnomeUIInfo workbook_menu [] = { GNOMEUIINFO_MENU_FILE_TREE(workbook_menu_file), GNOMEUIINFO_MENU_EDIT_TREE(workbook_menu_edit), GNOMEUIINFO_MENU_VIEW_TREE(workbook_menu_view), { GNOME_APP_UI_SUBTREE, N_("_Insert"), NULL, workbook_menu_insert }, { GNOME_APP_UI_SUBTREE, N_("F_ormat"), NULL, workbook_menu_format }, GNOMEUIINFO_MENU_HELP_TREE(workbook_menu_help), GNOMEUIINFO_END }; #define TOOLBAR_BOLD_BUTTON_INDEX 12 #define TOOLBAR_ITALIC_BUTTON_INDEX 13 static GnomeUIInfo workbook_toolbar [] = { GNOMEUIINFO_ITEM_STOCK ( N_("New"), N_("Create a new sheet"), new_cmd, GNOME_STOCK_PIXMAP_NEW), GNOMEUIINFO_ITEM_STOCK ( N_("Open"), N_("Opens an existing workbook"), open_cmd, GNOME_STOCK_PIXMAP_OPEN), GNOMEUIINFO_ITEM_STOCK ( N_("Save"), N_("Saves the workbook"), save_cmd, GNOME_STOCK_PIXMAP_SAVE), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_STOCK ( N_("Cut"), N_("Cuts the selection to the clipboard"), cut_cmd, GNOME_STOCK_PIXMAP_CUT), GNOMEUIINFO_ITEM_STOCK ( N_("Copy"), N_("Copies the selection to the clipboard"), copy_cmd, GNOME_STOCK_PIXMAP_COPY), GNOMEUIINFO_ITEM_STOCK ( N_("Paste"), N_("Pastes the clipboard"), paste_cmd, GNOME_STOCK_PIXMAP_PASTE), GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_STOCK ( N_("Left align"), N_("Sets the cell alignment to the left"), left_align_cmd, GNOME_STOCK_PIXMAP_ALIGN_LEFT), GNOMEUIINFO_ITEM_STOCK ( N_("Center"), N_("Centers the cell contents"), center_cmd, GNOME_STOCK_PIXMAP_ALIGN_CENTER), GNOMEUIINFO_ITEM_STOCK ( N_("Right align"), N_("Sets the cell alignment to the right"), right_align_cmd, GNOME_STOCK_PIXMAP_ALIGN_RIGHT), GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_TOGGLEITEM, N_("Bold"), N_("Sets the bold attribute on the cell"), bold_cmd, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_TEXT_BOLD }, { GNOME_APP_UI_TOGGLEITEM, N_("Italic"), N_("Sets the italic attribute on the cell"), italic_cmd, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_PIXMAP_TEXT_ITALIC }, GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_ITEM_DATA ( N_("Line"), N_("Creates a line object"), create_line_cmd, NULL, line_xpm), GNOMEUIINFO_ITEM_DATA ( N_("Arrow"), N_("Creates an arrow object"), create_arrow_cmd, NULL, arrow_xpm), GNOMEUIINFO_ITEM_DATA ( N_("Rectangle"), N_("Creates a rectangle object"), create_rectangle_cmd, NULL, rect_xpm), GNOMEUIINFO_ITEM_DATA ( N_("Ellipse"), N_("Creates an ellipse object"), create_ellipse_cmd, NULL, oval_xpm), GNOMEUIINFO_END }; static void do_focus_sheet (GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, Workbook *wb) { workbook_focus_current_sheet (wb); } static void workbook_setup_sheets (Workbook *wb) { wb->notebook = gtk_notebook_new (); GTK_WIDGET_UNSET_FLAGS (wb->notebook, GTK_CAN_FOCUS); gtk_signal_connect_after (GTK_OBJECT (wb->notebook), "switch_page", GTK_SIGNAL_FUNC(do_focus_sheet), wb); gtk_notebook_set_tab_pos (GTK_NOTEBOOK (wb->notebook), GTK_POS_BOTTOM); gtk_table_attach (GTK_TABLE (wb->table), wb->notebook, 0, WB_COLS, WB_EA_SHEETS, WB_EA_SHEETS+1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0); } Sheet * workbook_get_current_sheet (Workbook *wb) { GtkWidget *current_notebook; Sheet *sheet; g_return_val_if_fail (wb != NULL, NULL); current_notebook = GTK_NOTEBOOK (wb->notebook)->cur_page->child; sheet = gtk_object_get_data (GTK_OBJECT (current_notebook), "sheet"); if (sheet == NULL) g_warning ("There is no current sheet in this workbook"); return sheet; } Sheet * workbook_focus_current_sheet (Workbook *wb) { SheetView *sheet_view; Sheet *sheet; g_return_val_if_fail (wb != NULL, NULL); sheet = workbook_get_current_sheet (wb); sheet_view = SHEET_VIEW (sheet->sheet_views->data); gtk_window_set_focus (GTK_WINDOW (wb->toplevel), sheet_view->sheet_view); return sheet; } static void wb_input_finished (GtkEntry *entry, Workbook *wb) { Sheet *sheet; sheet = workbook_get_current_sheet (wb); sheet_set_current_value (sheet); workbook_focus_current_sheet (wb); } int workbook_parse_and_jump (Workbook *wb, char *text) { int col, row; col = row = 0; if (!parse_cell_name (text, &col, &row)){ gnumeric_notice (wb, GNOME_MESSAGE_BOX_ERROR, _("You should introduce a valid cell name")); return FALSE; } else { Sheet *sheet = workbook_get_current_sheet (wb); if (col > SHEET_MAX_COLS-1){ gnumeric_notice (wb, GNOME_MESSAGE_BOX_ERROR, _("Column out of range")); return FALSE; } if (row > SHEET_MAX_ROWS-1){ gnumeric_notice (wb, GNOME_MESSAGE_BOX_ERROR, _("Row number out of range")); return FALSE; } sheet_make_cell_visible (sheet, col, row); sheet_cursor_move (sheet, col, row); return TRUE; } } static void wb_jump_to_cell (GtkEntry *entry, Workbook *wb) { char *text = gtk_entry_get_text (entry); workbook_parse_and_jump (wb, text); workbook_focus_current_sheet (wb); } void workbook_set_region_status (Workbook *wb, char *str) { g_return_if_fail (wb != NULL); g_return_if_fail (str != NULL); gtk_entry_set_text (GTK_ENTRY (wb->ea_status), str); } static void accept_input (GtkWidget *widget, Workbook *wb) { Sheet *sheet = workbook_get_current_sheet (wb); sheet_set_current_value (sheet); workbook_focus_current_sheet (wb); } static void cancel_input (GtkWidget *widget, Workbook *wb) { Sheet *sheet = workbook_get_current_sheet (wb); sheet_cancel_pending_input (sheet); workbook_focus_current_sheet (wb); } static void workbook_setup_edit_area (Workbook *wb) { GtkWidget *ok_button, *cancel_button, *box, *box2; GtkWidget *pix; wb->ea_status = gtk_entry_new (); wb->ea_input = gtk_entry_new (); ok_button = gtk_button_new (); cancel_button = gtk_button_new (); box = gtk_hbox_new (0, 0); box2 = gtk_hbox_new (0, 0); gtk_widget_set_usize (wb->ea_status, 100, 0); /* Ok */ pix = gnome_stock_pixmap_widget_new (wb->toplevel, GNOME_STOCK_BUTTON_OK); gtk_container_add (GTK_CONTAINER (ok_button), pix); GTK_WIDGET_UNSET_FLAGS (ok_button, GTK_CAN_FOCUS); gtk_signal_connect (GTK_OBJECT (ok_button), "clicked", GTK_SIGNAL_FUNC(accept_input), wb); /* Cancel */ pix = gnome_stock_pixmap_widget_new (wb->toplevel, GNOME_STOCK_BUTTON_CANCEL); gtk_container_add (GTK_CONTAINER (cancel_button), pix); GTK_WIDGET_UNSET_FLAGS (cancel_button, GTK_CAN_FOCUS); gtk_signal_connect (GTK_OBJECT (cancel_button), "clicked", GTK_SIGNAL_FUNC(cancel_input), wb); gtk_box_pack_start (GTK_BOX (box2), wb->ea_status, 0, 0, 0); gtk_box_pack_start (GTK_BOX (box), ok_button, 0, 0, 0); gtk_box_pack_start (GTK_BOX (box), cancel_button, 0, 0, 0); gtk_box_pack_start (GTK_BOX (box2), box, 0, 0, 0); gtk_box_pack_end (GTK_BOX (box2), wb->ea_input, 1, 1, 0); gtk_table_attach (GTK_TABLE (wb->table), box2, 0, 1, 0, 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); /* Do signal setup for the editing input line */ gtk_signal_connect (GTK_OBJECT (wb->ea_input), "activate", GTK_SIGNAL_FUNC(wb_input_finished), wb); #if 0 gtk_signal_connect (GTK_OBJECT (wb->ea_input), "key_press_event", GTK_SIGNAL_FUNC(wb_edit_key_pressed), wb); #endif /* Do signal setup for the status input line */ gtk_signal_connect (GTK_OBJECT (wb->ea_status), "activate", GTK_SIGNAL_FUNC (wb_jump_to_cell), wb); } static struct { char *displayed_name; char *function; } quick_compute_routines [] = { { N_("Sum"), "SUM(SELECTION())" }, { N_("Min"), "MIN(SELECTION())" }, { N_("Max"), "MAX(SELECTION())" }, { N_("Average"), "AVERAGE(SELECTION())" }, { N_("Count"), "COUNT(SELECTION())" }, { NULL, NULL } }; /* * Sets the expression that gets evaluated whenever the * selection in the sheet changes */ static char * workbook_set_auto_expr (Workbook *wb, char *description, char *expression) { char *error = NULL; if (wb->auto_expr){ g_assert (wb->auto_expr->ref_count == 1); expr_tree_unref (wb->auto_expr); string_unref (wb->auto_expr_desc); } wb->auto_expr = expr_parse_string (expression, 0, 0, 0, NULL, &error); wb->auto_expr_desc = string_get (description); return error; } static void change_auto_expr (GtkWidget *item, Workbook *wb) { char *expr, *name; expr = gtk_object_get_data (GTK_OBJECT (item), "expr"); name = gtk_object_get_data (GTK_OBJECT (item), "name"); workbook_set_auto_expr (wb, name, expr); sheet_update_auto_expr (workbook_get_current_sheet (wb)); } static void change_auto_expr_menu (GtkWidget *widget, GdkEventButton *event, Workbook *wb) { static GtkWidget *menu; if (!menu){ GtkWidget *item; int i; menu = gtk_menu_new (); for (i = 0; quick_compute_routines [i].displayed_name; i++){ item = gtk_menu_item_new_with_label ( _(quick_compute_routines [i].displayed_name)); gtk_menu_append (GTK_MENU (menu), item); gtk_widget_show (item); gtk_signal_connect (GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC(change_auto_expr), wb); gtk_object_set_data (GTK_OBJECT (item), "expr", quick_compute_routines [i].function); gtk_object_set_data (GTK_OBJECT (item), "name", _(quick_compute_routines [i].displayed_name)); } } gtk_menu_popup (GTK_MENU (menu), NULL, NULL, 0, NULL, event->button, event->time); } /* * Sets up the autocalc label on the workbook. * * This code is more complex than it should for a number of * reasons: * * 1. GtkLabels flicker a lot, so we use a GnomeCanvas to * avoid the unnecessary flicker * * 2. Using a Canvas to display a label is tricky, there * are a number of ugly hacks here to do what we want * to do. * * When GTK+ gets a flicker free label (Owen mentions that the * new repaint engine in GTK+ he is working on will be flicker free) * we can remove most of these hacks */ static void workbook_setup_auto_calc (Workbook *wb) { GtkWidget *canvas; GnomeCanvasGroup *root; GtkWidget *l, *frame; canvas = gnome_canvas_new (); l = gtk_label_new ("Info"); /* The canvas that displays text */ root = GNOME_CANVAS_GROUP (GNOME_CANVAS (canvas)->root); wb->auto_expr_label = GNOME_CANVAS_ITEM (gnome_canvas_item_new ( root, gnome_canvas_text_get_type (), "text", "x", "x", (double) 0, "y", (double) 0, /* FIXME :-) */ "font_gdk", l->style->font, "anchor", GTK_ANCHOR_NW, "fill_color", "black", NULL)); gtk_widget_set_usize ( GTK_WIDGET (canvas), gdk_text_measure (l->style->font, "W", 1) * 15, -1); frame = gtk_frame_new (NULL); gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_container_add (GTK_CONTAINER (frame), canvas); gtk_box_pack_start (GTK_BOX (wb->appbar), frame, FALSE, TRUE, 0); gtk_signal_connect (GTK_OBJECT (canvas), "button_press_event", GTK_SIGNAL_FUNC (change_auto_expr_menu), wb); gtk_object_destroy (GTK_OBJECT (l)); gtk_widget_show_all (frame); } /* * Sets up the status display area */ static void workbook_setup_status_area (Workbook *wb) { /* * Create the GnomeAppBar */ wb->appbar = GNOME_APPBAR (gnome_appbar_new (FALSE, TRUE, GNOME_PREFERENCES_USER)); gnome_app_set_statusbar (GNOME_APP (wb->toplevel), GTK_WIDGET (wb->appbar)); /* * Add the auto calc widgets. */ workbook_setup_auto_calc (wb); } void workbook_auto_expr_label_set (Workbook *wb, char *text) { char *res; g_return_if_fail (wb != NULL); g_return_if_fail (text != NULL); res = g_strconcat (wb->auto_expr_desc->str, "=", text, NULL); gnome_canvas_item_set (wb->auto_expr_label, "text", res, NULL); g_free (res); } static void workbook_set_focus (GtkWindow *window, GtkWidget *focus, Workbook *wb) { if (!window->focus_widget) workbook_focus_current_sheet (wb); } static void workbook_configure_minimized_pixmap (Workbook *wb) { /* FIXME: Use the new function provided by Raster */ } /** * workbook_new: * * Creates a new empty Workbook. */ Workbook * workbook_new (void) { GnomeDockItem *item; GtkWidget *toolbar; static GtkTargetEntry drag_types[] = { { "text/uri-list", 0, 0 }, }; static gint n_drag_types = sizeof (drag_types) / sizeof (drag_types [0]); Workbook *wb; wb = g_new0 (Workbook, 1); wb->toplevel = gnome_app_new ("Gnumeric", "Gnumeric"); wb->sheets = g_hash_table_new (gnumeric_strcase_hash, gnumeric_strcase_equal); wb->table = gtk_table_new (0, 0, 0); wb->symbol_names = symbol_table_new (); gtk_window_set_policy(GTK_WINDOW(wb->toplevel), 1, 1, 0); wb->max_iterations = 1; workbook_set_title (wb, _("Untitled.gnumeric")); workbook_setup_status_area (wb); workbook_setup_edit_area (wb); workbook_setup_sheets (wb); gnome_app_set_contents (GNOME_APP (wb->toplevel), wb->table); gnome_app_create_menus_with_data (GNOME_APP (wb->toplevel), workbook_menu, wb); gnome_app_install_menu_hints(GNOME_APP (wb->toplevel), workbook_menu); wb->toolbar = g_malloc (sizeof (workbook_toolbar)); memcpy (wb->toolbar, &workbook_toolbar, sizeof (workbook_toolbar)); gnome_app_create_toolbar_with_data (GNOME_APP (wb->toplevel), (GnomeUIInfo *) wb->toolbar, wb); item = gnome_app_get_dock_item_by_name (GNOME_APP (wb->toplevel), GNOME_APP_TOOLBAR_NAME); toolbar = gnome_dock_item_get_child (item); gtk_toolbar_set_style (GTK_TOOLBAR (toolbar), GTK_TOOLBAR_ICONS); /* Minimized pixmap */ workbook_configure_minimized_pixmap (wb); /* Focus handling */ gtk_signal_connect_after ( GTK_OBJECT (wb->toplevel), "set_focus", GTK_SIGNAL_FUNC (workbook_set_focus), wb); gtk_signal_connect ( GTK_OBJECT (wb->toplevel), "destroy", GTK_SIGNAL_FUNC (workbook_widget_destroy), wb); /* Enable toplevel as a drop target */ gtk_drag_dest_set (wb->toplevel, GTK_DEST_DEFAULT_ALL, drag_types, n_drag_types, GDK_ACTION_COPY); gtk_signal_connect (GTK_OBJECT(wb->toplevel), "drag_data_received", GTK_SIGNAL_FUNC(filenames_dropped), NULL); /* clipboard setup */ x_clipboard_bind_workbook (wb); /* delete_event */ gtk_signal_connect ( GTK_OBJECT (wb->toplevel), "delete_event", GTK_SIGNAL_FUNC (workbook_delete_event), wb); /* Set the default operation to be performed over selections */ workbook_set_auto_expr (wb, "SUM", "SUM(SELECTION())"); workbook_count++; workbook_list = g_list_prepend (workbook_list, wb); gtk_widget_show_all (wb->table); return wb; } static void zoom_in (GtkButton *b, Sheet *sheet) { double pix = sheet->last_zoom_factor_used; if (pix < 10.0){ pix += 0.5; sheet_set_zoom_factor (sheet, pix); } } static void zoom_out (GtkButton *b, Sheet *sheet) { double pix = sheet->last_zoom_factor_used; if (pix > 1.0){ pix -= 0.5; sheet_set_zoom_factor (sheet, pix); } } static void buttons (Sheet *sheet, GtkTable *table) { GtkWidget *b; b = gtk_button_new_with_label (_("Zoom out")); GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS); gtk_table_attach (table, b, 0, 1, 1, 2, 0, 0, 0, 0); gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (zoom_out), sheet); b = gtk_button_new_with_label (_("Zoom in")); GTK_WIDGET_UNSET_FLAGS (b, GTK_CAN_FOCUS); gtk_table_attach (table, b, 1, 2, 1, 2, 0, 0, 0, 0); gtk_signal_connect (GTK_OBJECT (b), "clicked", GTK_SIGNAL_FUNC (zoom_in), sheet); } /** * workbook_rename_sheet: * @wb: the workbook where the sheet is * @old_name: the name of the sheet we want to rename * @new_name: new name we want to assing to the sheet. * * Returns TRUE if it was possible to rename the sheet to @new_name, * otherwise it returns FALSE for any possible error condition. */ gboolean workbook_rename_sheet (Workbook *wb, const char *old_name, const char *new_name) { Sheet *sheet; g_return_val_if_fail (wb != NULL, FALSE); g_return_val_if_fail (old_name != NULL, FALSE); g_return_val_if_fail (new_name != NULL, FALSE); /* Do not let two sheets in the workbook have the same name */ if (g_hash_table_lookup (wb->sheets, new_name)) return FALSE; sheet = (Sheet *) g_hash_table_lookup (wb->sheets, old_name); if (sheet == NULL) return FALSE; g_hash_table_remove (wb->sheets, old_name); sheet_rename (sheet, new_name); g_hash_table_insert (wb->sheets, sheet->name, sheet); return TRUE; } /* * Signal handler for EditableLabel's text_changed signal. */ static gboolean sheet_label_text_changed_signal (EditableLabel *el, const char *new_name, Workbook *wb) { if (strchr (new_name, '"')) return FALSE; if (strchr (new_name, '\'')) return FALSE; return workbook_rename_sheet (wb, el->text, new_name); } /** * sheet_action_add_sheet: * Invoked when the user selects the option to add a sheet */ static void sheet_action_add_sheet (GtkWidget *widget, Sheet *current_sheet) { insert_sheet_cmd (NULL, current_sheet->workbook); } /** * sheet_action_add_sheet: * Invoked when the user selects the option to add a sheet */ static void sheet_action_delete_sheet (GtkWidget *widget, Sheet *current_sheet) { GtkWidget *d; Workbook *wb = current_sheet->workbook; char *message; int r; /* * If this is the last sheet left, ignore the request */ if (workbook_sheet_count (wb) == 1) return; message = g_strdup_printf ( _("Are you sure you want to remove the sheet called `%s' "), current_sheet->name); d = gnome_message_box_new ( message, GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); g_free (message); gnome_dialog_set_parent (GNOME_DIALOG (d), GTK_WINDOW (wb->toplevel)); r = gnome_dialog_run (GNOME_DIALOG (d)); if (r != 0) return; if (!workbook_can_detach_sheet (wb, current_sheet)){ gnumeric_notice ( wb, GNOME_MESSAGE_BOX_ERROR, _("Other sheets depend on the values on this sheet, " "I can not remove it")); return; } /* * All is fine, remove the sheet */ workbook_detach_sheet (wb, current_sheet); sheet_destroy (current_sheet); workbook_recalc_all (wb); } #define SHEET_CONTEXT_TEST_SIZE 1 struct { char *text; void (*function) (GtkWidget *widget, Sheet *sheet); int flags; } sheet_label_context_actions [] = { { N_("Add another sheet"), sheet_action_add_sheet, 0 }, { N_("Remove this sheet"), sheet_action_delete_sheet, SHEET_CONTEXT_TEST_SIZE }, { NULL, NULL } }; /** * sheet_menu_label_run: * */ static void sheet_menu_label_run (Sheet *sheet, GdkEventButton *event) { GtkWidget *menu; GtkWidget *item; int i; menu = gtk_menu_new (); for (i = 0; sheet_label_context_actions [i].text != NULL; i++){ int flags = sheet_label_context_actions [i].flags; if (flags & SHEET_CONTEXT_TEST_SIZE){ if (workbook_sheet_count (sheet->workbook) < 2) continue; } item = gtk_menu_item_new_with_label ( _(sheet_label_context_actions [i].text)); gtk_menu_append (GTK_MENU (menu), item); gtk_widget_show (item); gtk_signal_connect ( GTK_OBJECT (item), "activate", GTK_SIGNAL_FUNC (sheet_label_context_actions [i].function), sheet); } gnumeric_popup_menu (GTK_MENU (menu), event); } /** * sheet_label_button_press: * * Invoked when the user has clicked on the EditableLabel widget. * This takes care of switching to the notebook that contains the label */ static gint sheet_label_button_press (GtkWidget *widget, GdkEventButton *event, GtkWidget *child) { GtkWidget *notebook; gint page_number; Sheet *sheet; if (event->type != GDK_BUTTON_PRESS) return FALSE; sheet = gtk_object_get_data (GTK_OBJECT (child), "sheet"); g_return_val_if_fail (sheet != NULL, FALSE); g_return_val_if_fail (IS_SHEET (sheet), FALSE); notebook = child->parent; page_number = gtk_notebook_page_num (GTK_NOTEBOOK (notebook), child); if (event->button == 1){ gtk_notebook_set_page (GTK_NOTEBOOK (notebook), page_number); return TRUE; } if (event->button == 3){ sheet_menu_label_run (sheet, event); return TRUE; } return FALSE; } int workbook_sheet_count (Workbook *wb) { g_return_val_if_fail (wb != NULL, 0); return g_hash_table_size (wb->sheets); } /** * workbook_attach_sheet: * @wb: the target workbook * @sheet: a sheet * * Attaches the @sheet to the @wb. */ void workbook_attach_sheet (Workbook *wb, Sheet *sheet) { GtkWidget *t, *sheet_label; g_return_if_fail (wb != NULL); g_return_if_fail (sheet != NULL); /* * We do not want to attach sheets that are attached * to a different workbook. */ g_return_if_fail (sheet->workbook == wb || sheet->workbook == NULL); sheet->workbook = wb; g_hash_table_insert (wb->sheets, sheet->name, sheet); t = gtk_table_new (0, 0, 0); gtk_table_attach ( GTK_TABLE (t), GTK_WIDGET (sheet->sheet_views->data), 0, 3, 0, 1, GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0); if (gnumeric_debugging) buttons (sheet, GTK_TABLE (t)); gtk_widget_show_all (t); gtk_object_set_data (GTK_OBJECT (t), "sheet", sheet); sheet_label = editable_label_new (sheet->name); gtk_signal_connect ( GTK_OBJECT (sheet_label), "text_changed", GTK_SIGNAL_FUNC (sheet_label_text_changed_signal), wb); gtk_signal_connect ( GTK_OBJECT (sheet_label), "button_press_event", GTK_SIGNAL_FUNC (sheet_label_button_press), t); gtk_widget_show (sheet_label); gtk_notebook_append_page (GTK_NOTEBOOK (wb->notebook), t, sheet_label); } /** * workbook_can_detach_sheet: * @wb: workbook. * @sheet: the sheet that we want to detach from the workbook * * Returns true whether the sheet can be safely detached from the * workbook. */ gboolean workbook_can_detach_sheet (Workbook *wb, Sheet *sheet) { GList *dependency_list; g_return_val_if_fail (wb != NULL, FALSE); g_return_val_if_fail (sheet != NULL, FALSE); g_return_val_if_fail (IS_SHEET (sheet), FALSE); g_return_val_if_fail (sheet->workbook != NULL, FALSE); g_return_val_if_fail (sheet->workbook == wb, FALSE); g_return_val_if_fail (workbook_sheet_lookup (wb, sheet->name) == sheet, FALSE); dependency_list = region_get_dependencies (sheet, 0, 0, SHEET_MAX_COLS, SHEET_MAX_ROWS); if (dependency_list == NULL) return TRUE; g_list_free (dependency_list); return FALSE; } /** * workbook_detach_sheet: * @wb: workbook. * @sheet: the sheet that we want to detach from the workbook * * Detaches @sheet from the workbook @wb. */ gboolean workbook_detach_sheet (Workbook *wb, Sheet *sheet) { GtkNotebook *notebook; int sheets, i; g_return_val_if_fail (wb != NULL, FALSE); g_return_val_if_fail (sheet != NULL, FALSE); g_return_val_if_fail (IS_SHEET (sheet), FALSE); g_return_val_if_fail (sheet->workbook != NULL, FALSE); g_return_val_if_fail (sheet->workbook == wb, FALSE); g_return_val_if_fail (workbook_sheet_lookup (wb, sheet->name) == sheet, FALSE); notebook = GTK_NOTEBOOK (wb->notebook); sheets = workbook_sheet_count (sheet->workbook); if (sheets == 1) return FALSE; if (!workbook_can_detach_sheet (wb, sheet)) return FALSE; /* * Remove our reference to this sheet */ g_hash_table_remove (wb->sheets, sheet->name); for (i = 0; i < sheets; i++){ Sheet *this_sheet; GtkWidget *w; w = gtk_notebook_get_nth_page (notebook, i); this_sheet = gtk_object_get_data (GTK_OBJECT (w), "sheet"); if (this_sheet == sheet){ gtk_notebook_remove_page (notebook, i); break; } } /* * Make the sheet drop its workbook pointer. */ sheet->workbook = NULL; /* * Queue a recalc */ workbook_recalc_all (wb); return TRUE; } /** * workbook_sheet_lookup: * @wb: workbook to lookup the sheet on * @sheet_name: the sheet name we are looking for. * * Returns a pointer to a Sheet or NULL if the sheet * was not found. */ Sheet * workbook_sheet_lookup (Workbook *wb, char *sheet_name) { Sheet *sheet; g_return_val_if_fail (wb != NULL, NULL); g_return_val_if_fail (sheet_name != NULL, NULL); sheet = g_hash_table_lookup (wb->sheets, sheet_name); return sheet; } /** * workbook_sheet_get_free_name: * @wb: workbook to look for * * Gets a new name for a sheets such that it does * not exist on the workbook. * * Returns the name assigned to the sheet. */ char * workbook_sheet_get_free_name (Workbook *wb) { char name [80]; int i; g_return_val_if_fail (wb != NULL, NULL); for (i = 0; ; i++){ g_snprintf (name, sizeof (name), _("Sheet %d"), i); if (workbook_sheet_lookup (wb, name) == NULL) return g_strdup (name); } g_assert_not_reached (); return NULL; } /** * workbook_new_with_sheets: * @sheet_count: initial number of sheets to create. * * Returns a Workbook with @sheet_count allocated * sheets on it */ Workbook * workbook_new_with_sheets (int sheet_count) { Workbook *wb; Sheet *first_sheet = 0; int i; wb = workbook_new (); for (i = 0; i < sheet_count; i++){ Sheet *sheet; char name [80]; snprintf (name, sizeof (name), _("Sheet %d"), i); sheet = sheet_new (wb, name); workbook_attach_sheet (wb, sheet); if (!first_sheet) first_sheet = sheet; } workbook_focus_current_sheet (wb); return wb; } /* * This routine sets up the default styles for the * workbook */ void workbook_realized (Workbook *workbook, GdkWindow *window) { } void workbook_feedback_set (Workbook *workbook, WorkbookFeedbackType type, void *data) { GtkToggleButton *t; GnomeUIInfo *toolbar = workbook->toolbar; int set; g_return_if_fail (workbook != NULL); switch (type){ case WORKBOOK_FEEDBACK_BOLD: t = GTK_TOGGLE_BUTTON ( toolbar [TOOLBAR_BOLD_BUTTON_INDEX].widget); set = data != NULL; gtk_toggle_button_set_active (t, set); break; case WORKBOOK_FEEDBACK_ITALIC: t = GTK_TOGGLE_BUTTON ( toolbar [TOOLBAR_ITALIC_BUTTON_INDEX].widget); set = data != NULL; gtk_toggle_button_set_active (t, set); } } /** * workbook_set_title: * @wb: the workbook to modify * @title: the title for the toplevel window * * Sets the toplelve window title of @wb to be @title */ void workbook_set_title (Workbook *wb, char *title) { char *full_title; g_return_if_fail (wb != NULL); g_return_if_fail (title != NULL); full_title = g_strconcat ("Gnumeric: ", title, NULL); gtk_window_set_title (GTK_WINDOW (wb->toplevel), full_title); g_free (full_title); } /** * workbook_set_filename: * @wb: the workkbook to modify * @name: the file name for this worksheet. * * Sets the internal filename to @name and changes * the title bar for the toplevel window to be the name * of this file. */ void workbook_set_filename (Workbook *wb, char *name) { g_return_if_fail (wb != NULL); g_return_if_fail (name != NULL); if (wb->filename) g_free (wb->filename); wb->filename = g_strdup (name); workbook_set_title (wb, g_basename (name)); }