Index: ChangeLog =================================================================== RCS file: /cvs/gnome/gnumeric/ChangeLog,v retrieving revision 1.2430 diff -u -3 -p -r1.2430 ChangeLog --- ChangeLog 24 Sep 2002 15:48:59 -0000 1.2430 +++ ChangeLog 24 Sep 2002 21:08:15 -0000 @@ -1,3 +1,12 @@ +2002-09-24 Lutz Müller + + * src/dialogs/dialog-sheet-order.c: Be aware of changes in the + sheet order. + * src/workbook.[c,h]: Provide a "sheet_order_changed" signal. + * src/workbook-control-gui.c: Remove debugging messages. Allow + dropping the sheet anywhere in the workbook - reordering will still + be done. + 2002-09-24 Morten Welinder * src/parser.y (yylex): Handle error constants. (And fix utf8 @@ -33,6 +42,8 @@ * src/parser.y : remove sheet_ref RANGEREF production. RANGEREF already handles sheet references internally. + +2002-09-23 Jody Goldberg * src/expr.c (gnm_expr_eval) : handle empties when implicit intersection is valid but accesses an empty cell. Index: src/workbook.c =================================================================== RCS file: /cvs/gnome/gnumeric/src/workbook.c,v retrieving revision 1.560 diff -u -3 -p -r1.560 workbook.c --- src/workbook.c 17 Sep 2002 16:43:20 -0000 1.560 +++ src/workbook.c 24 Sep 2002 21:08:15 -0000 @@ -48,6 +48,7 @@ static GObjectClass *workbook_parent_cla enum { SUMMARY_CHANGED, FILENAME_CHANGED, + SHEET_ORDER_CHANGED, LAST_SIGNAL }; @@ -359,7 +360,16 @@ workbook_class_init (GObjectClass *objec (GSignalAccumulator) NULL, NULL, gnm__VOID__VOID, G_TYPE_NONE, - 0, G_TYPE_NONE); + 0, G_TYPE_NONE); + + signals [SHEET_ORDER_CHANGED] = g_signal_new ("sheet_order_changed", + WORKBOOK_TYPE, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (WorkbookClass, sheet_order_changed), + (GSignalAccumulator) NULL, NULL, + gnm__VOID__VOID, + G_TYPE_NONE, + 0, G_TYPE_NONE); } /** @@ -798,6 +808,7 @@ post_sheet_index_change (Workbook *wb) if (wb->sheet_order_dependents != NULL) g_hash_table_foreach (wb->sheet_order_dependents, (GHFunc) cb_dep_link, NULL); + g_signal_emit (G_OBJECT (wb), signals [SHEET_ORDER_CHANGED], 0); } static void @@ -1310,6 +1321,7 @@ workbook_sheet_reorganize (WorkbookContr } this_sheet = this_sheet->next; } + return FALSE; } Index: src/workbook.h =================================================================== RCS file: /cvs/gnome/gnumeric/src/workbook.h,v retrieving revision 1.110 diff -u -3 -p -r1.110 workbook.h --- src/workbook.h 17 Sep 2002 16:43:21 -0000 1.110 +++ src/workbook.h 24 Sep 2002 21:08:15 -0000 @@ -49,8 +49,9 @@ struct _Workbook { typedef struct { GObjectClass base; - void (*summary_changed) (Workbook *wb); - void (*filename_changed) (Workbook *wb); + void (*summary_changed) (Workbook *wb); + void (*filename_changed) (Workbook *wb); + void (*sheet_order_changed) (Workbook *wb); } WorkbookClass; GType workbook_get_type (void); Index: src/workbook-control-gui.c =================================================================== RCS file: /cvs/gnome/gnumeric/src/workbook-control-gui.c,v retrieving revision 1.342 diff -u -3 -p -r1.342 workbook-control-gui.c --- src/workbook-control-gui.c 24 Sep 2002 13:25:42 -0000 1.342 +++ src/workbook-control-gui.c 24 Sep 2002 21:08:17 -0000 @@ -728,6 +728,7 @@ cb_sheet_label_drag_data_received (GtkWi guint n, i; g_return_if_fail (IS_WORKBOOK_CONTROL_GUI (wbcg)); + g_return_if_fail (GTK_IS_WIDGET (widget)); w_source = gtk_drag_get_source_widget (context); n_source = gtk_notebook_page_num_by_label (wbcg->notebook, w_source); @@ -796,8 +797,6 @@ cb_sheet_label_drag_begin (GtkWidget *wi g_return_if_fail (IS_WORKBOOK_CONTROL_GUI (wbcg)); - g_message ("cb_sheet_label_drag_begin"); - /* Create the arrow. */ arrow = gtk_window_new (GTK_WINDOW_POPUP); gtk_widget_realize (arrow); @@ -828,6 +827,18 @@ cb_sheet_label_drag_end (GtkWidget *widg g_object_set_data (G_OBJECT (widget), "arrow", NULL); } +static void +cb_sheet_label_drag_leave (GtkWidget *widget, GdkDragContext *context, + guint time, WorkbookControlGUI *wbcg) +{ + GtkWidget *w_source, *arrow; + + /* Hide the arrow. */ + w_source = gtk_drag_get_source_widget (context); + arrow = g_object_get_data (G_OBJECT (w_source), "arrow"); + gtk_widget_hide (arrow); +} + static gboolean cb_sheet_label_drag_motion (GtkWidget *widget, GdkDragContext *context, gint x, gint y, guint time, WorkbookControlGUI *wbcg) @@ -836,18 +847,19 @@ cb_sheet_label_drag_motion (GtkWidget *w gint n_source, n_dest, root_x, root_y, pos_x, pos_y; g_return_val_if_fail (IS_WORKBOOK_CONTROL_GUI (wbcg), FALSE); - - g_message ("cb_sheet_label_drag_motion"); + g_return_val_if_fail (IS_WORKBOOK_CONTROL_GUI (wbcg), FALSE); /* Make sure we are really hovering over another label. */ w_source = gtk_drag_get_source_widget (context); n_source = gtk_notebook_page_num_by_label (wbcg->notebook, w_source); n_dest = gtk_notebook_page_num_by_label (wbcg->notebook, widget); - if (n_source == n_dest) + arrow = g_object_get_data (G_OBJECT (w_source), "arrow"); + if (n_source == n_dest) { + gtk_widget_hide (arrow); return (FALSE); + } /* Move the arrow to the correct position and show it. */ - arrow = g_object_get_data (G_OBJECT (w_source), "arrow"); window = gtk_widget_get_ancestor (widget, GTK_TYPE_WINDOW); gtk_window_get_position (GTK_WINDOW (window), &root_x, &root_y); pos_x = root_x + widget->allocation.x; @@ -920,6 +932,8 @@ wbcg_sheet_add (WorkbookControl *wbc, Sh G_CALLBACK (cb_sheet_label_drag_begin), wbcg); g_signal_connect (G_OBJECT (scg->label), "drag_end", G_CALLBACK (cb_sheet_label_drag_end), wbcg); + g_signal_connect (G_OBJECT (scg->label), "drag_leave", + G_CALLBACK (cb_sheet_label_drag_leave), wbcg); g_signal_connect (G_OBJECT (scg->label), "drag_data_get", G_CALLBACK (cb_sheet_label_drag_data_get), wbcg); g_signal_connect (G_OBJECT (scg->label), "drag_data_received", @@ -4816,37 +4830,113 @@ wbcg_drag_data_get (GtkWidget * } #endif +static GtkWidget * +wbcg_get_label_for_position (WorkbookControlGUI *wbcg, GtkWidget *source, + gint x) +{ + GtkWidget *label = NULL, *page; + guint n, i; + + g_return_val_if_fail (IS_WORKBOOK_CONTROL_GUI (wbcg), NULL); + + n = g_list_length (wbcg->notebook->children); + for (i = 0; i < n; i++) { + page = gtk_notebook_get_nth_page (wbcg->notebook, i); + label = gtk_notebook_get_tab_label (wbcg->notebook, page); + if (label->allocation.x + label->allocation.width >= x) + break; + } + + return (label); +} + +static gboolean +cb_wbcg_drag_motion (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, guint time, WorkbookControlGUI *wbcg) +{ + GtkWidget *source_widget, *arrow; + + source_widget = gtk_drag_get_source_widget (context); + if (IS_EDITABLE_LABEL (source_widget)) { + GtkWidget *label; + + /* + * The user wants to reorder sheets. We simulate a + * drag motion over a label. + */ + label = wbcg_get_label_for_position (wbcg, source_widget, x); + return (cb_sheet_label_drag_motion (label, context, x, y, + time, wbcg)); + } + + return (TRUE); +} + static void -wbcg_filenames_dropped (GtkWidget *widget, GdkDragContext *context, - gint x, gint y, - GtkSelectionData *selection_data, - guint info, guint time, - WorkbookControl *wbc) -{ - GList *ptr, *uris = gnome_vfs_uri_list_parse (selection_data->data); - - for (ptr = uris; ptr != NULL; ptr = ptr->next) { - GnomeVFSURI const *uri = ptr->data; - if (0) { - } else { +cb_wbcg_drag_leave (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, guint time, WorkbookControlGUI *wbcg) +{ + GtkWidget *source_widget, *arrow; + + source_widget = gtk_drag_get_source_widget (context); + if (IS_EDITABLE_LABEL (source_widget)) { + arrow = g_object_get_data (G_OBJECT (source_widget), "arrow"); + gtk_widget_hide (arrow); + } +} + +static void +cb_wbcg_drag_data_received (GtkWidget *widget, GdkDragContext *context, + gint x, gint y, GtkSelectionData *selection_data, + guint info, guint time, WorkbookControlGUI *wbcg) +{ + gchar *target_type; + + target_type = gdk_atom_name (selection_data->target); + + /* First possibility: User dropped some filenames. */ + if (!strcmp (target_type, "text/uri-list")) { + GList *ptr, *uris = gnome_vfs_uri_list_parse (selection_data->data); + + for (ptr = uris; ptr != NULL; ptr = ptr->next) { + GnomeVFSURI const *uri = ptr->data; gchar *str = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE); gchar *msg = g_strdup_printf (_("File \"%s\" has unknown format."), str); - gnumeric_error_read (COMMAND_CONTEXT (wbc), msg); + gnumeric_error_read (COMMAND_CONTEXT (wbcg), msg); g_free (msg); - } #if 0 - if (gnome_vfs_uri_is_local (uri)) { - if (!wb_view_open (file_name, wbc, FALSE, NULL)) { + if (gnome_vfs_uri_is_local (uri)) { + if (!wb_view_open (file_name, wbc, FALSE, NULL)) { + } } - } - /* If it wasn't a workbook, see if we have a control for it */ - SheetObject *so = sheet_object_container_new_file ( - sc->sheet->workbook, file_name); - if (so != NULL) - scg_mode_create_object (gcanvas->simple.scg, so); + /* If it wasn't a workbook, see if we have a control for it */ + SheetObject *so = sheet_object_container_new_file ( + sc->sheet->workbook, file_name); + if (so != NULL) + scg_mode_create_object (gcanvas->simple.scg, so); #endif - } - gnome_vfs_uri_list_free (uris); + } + gnome_vfs_uri_list_free (uris); + + /* Second possibility: User dropped a sheet. */ + } else if (!strcmp (target_type, "GNUMERIC_SHEET")) { + GtkWidget *label; + GtkWidget *source_widget; + + /* + * The user wants to reorder the sheets but hasn't dropped + * the sheet onto a label. Never mind. We figure out + * where the arrow is currently located and simulate a drop + * on that label. + */ + source_widget = gtk_drag_get_source_widget (context); + label = wbcg_get_label_for_position (wbcg, source_widget, x); + cb_sheet_label_drag_data_received (label, context, x, y, + selection_data, info, time, wbcg); + + } else + g_warning ("Unknown target type '%s'!", target_type); + g_free (target_type); } /* @@ -4882,7 +4972,8 @@ workbook_control_gui_init (WorkbookContr WorkbookView *optional_view, Workbook *optional_wb) { static GtkTargetEntry const drag_types[] = { - { (char *) "text/uri-list", 0, TARGET_URI_LIST } + { (char *) "text/uri-list", 0, TARGET_URI_LIST }, + { (char *) "GNUMERIC_SHEET", 0, TARGET_SHEET } }; #ifdef WITH_BONOBO @@ -5041,10 +5132,14 @@ workbook_control_gui_init (WorkbookContr /* Setup a test of Drag and Drop */ gtk_drag_dest_set (GTK_WIDGET (wbcg_toplevel (wbcg)), GTK_DEST_DEFAULT_ALL, drag_types, G_N_ELEMENTS (drag_types), - GDK_ACTION_COPY); + GDK_ACTION_COPY | GDK_ACTION_MOVE); g_signal_connect (G_OBJECT (wbcg_toplevel (wbcg)), "drag_data_received", - G_CALLBACK (wbcg_filenames_dropped), wbcg); + G_CALLBACK (cb_wbcg_drag_data_received), wbcg); + g_signal_connect (G_OBJECT (wbcg_toplevel (wbcg)), + "drag_motion", G_CALLBACK (cb_wbcg_drag_motion), wbcg); + g_signal_connect (G_OBJECT (wbcg_toplevel (wbcg)), + "drag_leave", G_CALLBACK (cb_wbcg_drag_leave), wbcg); #if 0 g_signal_connect (G_OBJECT (gcanvas), "drag_data_get", Index: src/dialogs/dialog-sheet-order.c =================================================================== RCS file: /cvs/gnome/gnumeric/src/dialogs/dialog-sheet-order.c,v retrieving revision 1.37 diff -u -3 -p -r1.37 dialog-sheet-order.c --- src/dialogs/dialog-sheet-order.c 18 Aug 2002 15:48:55 -0000 1.37 +++ src/dialogs/dialog-sheet-order.c 24 Sep 2002 21:08:18 -0000 @@ -67,6 +67,8 @@ typedef struct { gboolean initial_colors_set; GSList *old_order; + + gulong sheet_order_changed_listener; } SheetManager; enum { @@ -676,6 +678,12 @@ cb_ok_clicked (GtkWidget *ignore, SheetM static void cb_sheet_order_destroy (GtkWidget *ignored, SheetManager *state) { + Workbook *wb = wb_control_workbook (WORKBOOK_CONTROL (state->wbcg)); + + /* Stop to listen to changes in the sheet order. */ + g_signal_handler_disconnect (G_OBJECT (wb), + state->sheet_order_changed_listener); + wbcg_edit_detach_guru (state->wbcg); g_object_unref (G_OBJECT (state->gui)); state->gui = NULL; @@ -691,6 +699,144 @@ cb_sheet_order_destroy (GtkWidget *ignor g_free (state); } +static void +dialog_sheet_order_update_sheet_order (SheetManager *state) +{ + gchar *name, *new_name; + gboolean is_deleted; + gboolean is_editable; + gboolean is_locked; + GdkColor *back, *fore; + GtkTreeIter iter; + Workbook *wb = wb_control_workbook (WORKBOOK_CONTROL (state->wbcg)); + gint i, j, n_sheets, n_children; + GtkTreeModel *model = GTK_TREE_MODEL (state->model); + Sheet *sheet_wb, *sheet_model; + GtkTreeSelection *sel = gtk_tree_view_get_selection (state->sheet_list); + gboolean selected; + + n_sheets = workbook_sheet_count (wb); + n_children = gtk_tree_model_iter_n_children (model, NULL); + g_return_if_fail (n_sheets == n_children); + + for (i = 0; i < n_sheets; i++) { + sheet_wb = workbook_sheet_by_index (wb, i); + for (j = i; j < n_children; j++) { + if (!gtk_tree_model_iter_nth_child (model, &iter, + NULL, j)) + break; + gtk_tree_model_get (model, &iter, SHEET_POINTER, + &sheet_model, -1); + if (sheet_model == sheet_wb) + break; + } + if (j == i) + continue; + + if (!gtk_tree_model_iter_nth_child (model, &iter, NULL, j)) + break; + selected = gtk_tree_selection_iter_is_selected (sel, &iter); + gtk_tree_model_get (model, &iter, + SHEET_LOCKED, &is_locked, + SHEET_NAME, &name, + SHEET_NEW_NAME, &new_name, + IS_EDITABLE_COLUMN, &is_editable, + SHEET_POINTER, &sheet_model, + IS_DELETED, &is_deleted, + BACKGROUND_COLOUR_POINTER, &back, + FOREGROUND_COLOUR_POINTER, &fore, + -1); + gtk_list_store_remove (state->model, &iter); + gtk_list_store_insert (state->model, &iter, i); + gtk_list_store_set (state->model, &iter, + SHEET_LOCKED, is_locked, + SHEET_LOCK_IMAGE, is_locked ? + state->image_padlock : state->image_padlock_no, + SHEET_NAME, name, + SHEET_NEW_NAME, new_name, + IS_EDITABLE_COLUMN, is_editable, + SHEET_POINTER, sheet_model, + IS_DELETED, is_deleted, + BACKGROUND_COLOUR_POINTER, back, + FOREGROUND_COLOUR_POINTER, fore, + -1); + if (back) + gdk_color_free (back); + if (fore) + gdk_color_free (fore); + g_free (name); + g_free (new_name); + if (selected) + gtk_tree_selection_select_iter (sel, &iter); + } + + g_slist_free (state->old_order); + state->old_order = NULL; + for (i = 0; i < n_sheets; i++) + state->old_order = g_slist_append (state->old_order, + workbook_sheet_by_index (wb, i)); + + cb_selection_changed (NULL, state); +} + +static void +cb_sheet_order_changed (Workbook *wb, SheetManager *state) +{ + GtkTreeIter iter; + GtkTreeModel *model = GTK_TREE_MODEL (state->model); + guint i, n = 0; + Sheet *sheet; + + /* + * First question: Has the user already changed the order via + * the dialog? If no, we assume that the user wants to see the + * sheet order change reflected in the dialog. + */ + n = g_slist_length (state->old_order); + for (i = 0; i < n; i++) { + if (!gtk_tree_model_iter_nth_child (model, &iter, NULL, i)) + break; + gtk_tree_model_get (model, &iter, SHEET_POINTER, &sheet, -1); + if (sheet != g_slist_nth_data (state->old_order, i)) + break; + } + if (n == i) { + dialog_sheet_order_update_sheet_order (state); + return; + } + + /* + * The user has already changed the order via the dialog. + * Let's check if the new sheet order is already reflected + * in the dialog. If yes, things are easy. + */ + n = workbook_sheet_count (wb); + for (i = 0; i < n; i++) { + if (!gtk_tree_model_iter_nth_child (model, &iter, NULL, i)) + break; + gtk_tree_model_get (model, &iter, SHEET_POINTER, &sheet, -1); + if (sheet != workbook_sheet_by_index (wb, i)) + break; + } + if (i == n) { + g_slist_free (state->old_order); + state->old_order = NULL; + for (i = 0; i < n; i++) + state->old_order = g_slist_append (state->old_order, + workbook_sheet_by_index (wb, i)); + return; + } + + /* + * The order in the dialog and the new sheet order are totally + * different. Ask the user what to do. + */ + if (gnumeric_dialog_question_yes_no (state->wbcg, + _("The sheet order has changed. Do you want to " + "update the list?"), TRUE)) + dialog_sheet_order_update_sheet_order (state); +} + void dialog_sheet_order (WorkbookControlGUI *wbcg) { @@ -698,6 +844,7 @@ dialog_sheet_order (WorkbookControlGUI * GladeXML *gui; GtkTable *table; ColorGroup *cg; + Workbook *wb; g_return_if_fail (wbcg != NULL); @@ -727,6 +874,12 @@ dialog_sheet_order (WorkbookControlGUI * "Gnumeric_PadlockNo", GTK_ICON_SIZE_LARGE_TOOLBAR, "Gnumeric-Sheet-Manger"); + + /* Listen for changes in the sheet order. */ + wb = wb_control_workbook (WORKBOOK_CONTROL (wbcg)); + state->sheet_order_changed_listener = g_signal_connect (G_OBJECT (wb), + "sheet_order_changed", G_CALLBACK (cb_sheet_order_changed), + state); gtk_button_stock_alignment_set (GTK_BUTTON (state->up_btn), 0., .5, 0., 0.); gtk_button_stock_alignment_set (GTK_BUTTON (state->down_btn), 0., .5, 0., 0.);