/** * sv_select_cur_col: * @sv: The sheet * * Selects an entire column */ void sv_select_cur_col (SheetView *sv) { GnmRange const *sel = selection_first_range (sv, NULL, NULL); if (sel != NULL) { GnmRange r = *sel; sv_selection_reset (sv); sv_selection_add_full (sv, sv->edit_pos.col, sv->edit_pos.row, r.start.col, 0, r.end.col, gnm_sheet_get_last_row (sv->sheet)); sheet_update (sv->sheet); } }
/** * sv_select_cur_array : * @sv: The sheet * * If the editpos is part of an array clear the selection and select the array. **/ void sv_select_cur_array (SheetView *sv) { GnmRange a; int const c = sv->edit_pos.col; int const r = sv->edit_pos.row; if (!gnm_cell_array_bound (sheet_cell_get (sv->sheet, c, r), &a)) return; /* leave the edit pos where it is, select the entire array. */ sv_selection_reset (sv); sv_selection_add_full (sv, c, r, a.start.col, a.start.row, a.end.col, a.end.row); sheet_update (sv->sheet); }
/** * sv_select_cur_inputs : * @sv: The sheet * * Select all cells that are direct potential inputs to the * current cell. **/ void sv_select_cur_inputs (SheetView *sv) { GnmCell *cell; GSList *ranges, *ptr; GnmEvalPos ep; g_return_if_fail (IS_SHEET_VIEW (sv)); cell = sheet_cell_get (sv->sheet, sv->edit_pos.col, sv->edit_pos.row); if (cell == NULL || !gnm_cell_has_expr (cell)) return; ranges = gnm_expr_top_get_ranges (cell->base.texpr); if (ranges == NULL) return; ep.eval = sv->edit_pos; ep.sheet = sv->sheet; ep.dep = NULL; sv_selection_reset (sv); for (ptr = ranges ; ptr != NULL ; ptr = ptr->next) { GnmValue *v = ptr->data; GnmRangeRef const *r = value_get_rangeref (v); #warning "FIXME: What do we do in these 3D cases?" if (r->a.sheet != r->b.sheet) continue; if (r->a.sheet != NULL && r->a.sheet != sv->sheet) continue; sv_selection_add_full (sv, gnm_cellref_get_col (&r->a, &ep), gnm_cellref_get_row (&r->a, &ep), gnm_cellref_get_col (&r->a, &ep), gnm_cellref_get_row (&r->a, &ep), gnm_cellref_get_col (&r->b, &ep), gnm_cellref_get_row (&r->b, &ep)); value_release (v); } g_slist_free (ranges); sheet_update (sv->sheet); }
/** * sv_select_cur_depends : * @sv: The sheet * * Select all cells that depend on the expression in the current cell. */ void sv_select_cur_depends (SheetView *sv) { GnmCell *cur_cell, dummy; GList *deps = NULL, *ptr = NULL; g_return_if_fail (IS_SHEET_VIEW (sv)); cur_cell = sheet_cell_get (sv->sheet, sv->edit_pos.col, sv->edit_pos.row); if (cur_cell == NULL) { dummy.base.sheet = sv_sheet (sv); dummy.pos = sv->edit_pos; cur_cell = &dummy; } cell_foreach_dep (cur_cell, cb_collect_deps, &deps); if (deps == NULL) return; sv_selection_reset (sv); /* Short circuit */ if (g_list_length (deps) == 1) { GnmCell *cell = deps->data; sv_selection_add_pos (sv, cell->pos.col, cell->pos.row); } else { GnmRange *cur = NULL; ptr = NULL; /* Merge the sorted list of cells into rows */ for (deps = g_list_sort (deps, &cb_compare_deps) ; deps ; ) { GnmCell *cell = deps->data; if (cur == NULL || cur->end.row != cell->pos.row || cur->end.col+1 != cell->pos.col) { if (cur) ptr = g_list_prepend (ptr, cur); cur = g_new (GnmRange, 1); cur->start.row = cur->end.row = cell->pos.row; cur->start.col = cur->end.col = cell->pos.col; } else cur->end.col = cell->pos.col; deps = g_list_remove (deps, cell); } if (cur) ptr = g_list_prepend (ptr, cur); /* Merge the coalesced rows into ranges */ deps = ptr; for (ptr = NULL ; deps ; ) { GnmRange *r1 = deps->data; GList *fwd; for (fwd = deps->next ; fwd ; ) { GnmRange *r2 = fwd->data; if (r1->start.col == r2->start.col && r1->end.col == r2->end.col && r1->start.row-1 == r2->end.row) { r1->start.row = r2->start.row; g_free (fwd->data); fwd = g_list_remove (fwd, r2); } else fwd = fwd->next; } ptr = g_list_prepend (ptr, r1); deps = g_list_remove (deps, r1); } /* now select the ranges */ while (ptr) { sv_selection_add_range (sv, ptr->data); g_free (ptr->data); ptr = g_list_remove (ptr, ptr->data); } } sheet_update (sv->sheet); }
int main (int argc, char const **argv) { gboolean opened_workbook = FALSE; gboolean with_gui; GOIOContext *ioc; WorkbookView *wbv; GSList *wbcgs_to_kill = NULL; GOCmdContext *cc; #ifdef G_OS_WIN32 gboolean has_console; #endif /* No code before here, we need to init threads */ argv = gnm_pre_parse_init (argc, argv); /* * Attempt to disable Ubuntu's funky, non-working scroll * bars. This needs to be done before gtk starts loading * modules. Note: the following call will not replace * an existing setting, so you can run with =1 if you like. */ g_setenv ("LIBOVERLAY_SCROLLBAR", "0", FALSE); #ifdef G_OS_WIN32 has_console = FALSE; { typedef BOOL (CALLBACK* LPFNATTACHCONSOLE)(DWORD); LPFNATTACHCONSOLE MyAttachConsole; HMODULE hmod; if ((hmod = GetModuleHandle("kernel32.dll"))) { MyAttachConsole = (LPFNATTACHCONSOLE) GetProcAddress(hmod, "AttachConsole"); if (MyAttachConsole && MyAttachConsole(ATTACH_PARENT_PROCESS)) { freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); dup2(fileno(stdout), 1); dup2(fileno(stderr), 2); has_console = TRUE; } } } #endif gnumeric_arg_parse (argc, (char **)argv); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); bind_textdomain_codeset (GETTEXT_PACKAGE "-functions", "UTF-8"); with_gui = !func_def_file && !func_state_file && !split_funcdocs; if (with_gui) { gnm_session_init (argv[0]); } gnm_init (); /* These are useful for the build process only. */ if (func_state_file) return gnm_dump_func_defs (func_state_file, 0); if (func_def_file) return gnm_dump_func_defs (func_def_file, 1); if (split_funcdocs) return gnm_dump_func_defs (NULL, 2); if (ext_refs_file) return gnm_dump_func_defs (ext_refs_file, 4); if (with_gui) { go_component_set_default_command_context (cc = cmd_context_stderr_new ()); g_object_unref (cc); cc = g_object_new (GNM_TYPE_IO_CONTEXT_GTK, "show-splash", !gnumeric_no_splash, "show-warnings", !gnumeric_no_warnings, NULL); ioc = GO_IO_CONTEXT (g_object_ref (cc)); handle_paint_events (); pathetic_qt_workaround (); } else { /* TODO: Make this inconsistency go away */ cc = cmd_context_stderr_new (); ioc = go_io_context_new (cc); go_component_set_default_command_context (cc); } /* Keep in sync with .desktop file */ g_set_application_name (_("Gnumeric Spreadsheet")); gnm_plugins_init (GO_CMD_CONTEXT (ioc)); if (startup_files) { int i; for (i = 0; startup_files [i]; i++) ; go_io_context_set_num_files (ioc, i); for (i = 0; startup_files [i] && !initial_workbook_open_complete; i++) { char *uri = go_shell_arg_to_uri (startup_files[i]); if (uri == NULL) { g_warning ("Ignoring invalid URI."); continue; } go_io_context_processing_file (ioc, uri); wbv = workbook_view_new_from_uri (uri, NULL, ioc, NULL); g_free (uri); if (go_io_error_occurred (ioc) || go_io_warning_occurred (ioc)) { go_io_error_display (ioc); go_io_error_clear (ioc); } if (wbv != NULL) { WBCGtk *wbcg; workbook_update_history (wb_view_get_workbook (wbv), GNM_FILE_SAVE_AS_STYLE_SAVE); wbcg = wbc_gtk_new (wbv, NULL, NULL, geometry); geometry = NULL; sheet_update (wb_view_cur_sheet (wbv)); opened_workbook = TRUE; gnm_io_context_gtk_set_transient_for (GNM_IO_CONTEXT_GTK (ioc), wbcg_toplevel (wbcg)); if (immediate_exit_flag) wbcgs_to_kill = g_slist_prepend (wbcgs_to_kill, wbcg); } /* cheesy attempt to keep the ui from freezing during load */ handle_paint_events (); if (gnm_io_context_gtk_get_interrupted (GNM_IO_CONTEXT_GTK (ioc))) break; /* Don't load any more workbooks */ } } g_object_unref (cc); cc = NULL; /* FIXME: Maybe we should quit here if we were asked to open files and failed to do so. */ /* If we were intentionally short circuited exit now */ if (!initial_workbook_open_complete) { initial_workbook_open_complete = TRUE; if (!opened_workbook) { gint n_of_sheets = gnm_conf_get_core_workbook_n_sheet (); wbc_gtk_new (NULL, workbook_new_with_sheets (n_of_sheets), NULL, geometry); } if (immediate_exit_flag) { GSList *l; for (l = wbcgs_to_kill; l; l = l->next) g_idle_add ((GSourceFunc)cb_kill_wbcg, l->data); } g_signal_connect (gnm_app_get_app (), "workbook_removed", G_CALLBACK (cb_workbook_removed), NULL); gnm_io_context_gtk_discharge_splash (GNM_IO_CONTEXT_GTK (ioc)); g_object_unref (ioc); g_idle_add ((GSourceFunc)pathetic_qt_workaround, NULL); gtk_main (); } else { g_object_unref (ioc); g_slist_foreach (wbcgs_to_kill, (GFunc)cb_kill_wbcg, NULL); } g_slist_free (wbcgs_to_kill); gnumeric_arg_shutdown (); store_plugin_state (); gnm_shutdown (); #if defined(G_OS_WIN32) if (has_console) { close(1); close(2); FreeConsole(); } #endif gnm_pre_parse_shutdown (); go_component_set_default_command_context (NULL); /* * This helps finding leaks. We might want it in developent * only. */ if (with_gui && gnm_debug_flag ("close-displays")) { GSList *displays; gdk_flush(); while (g_main_context_iteration (NULL, FALSE)) ;/* nothing */ displays = gdk_display_manager_list_displays (gdk_display_manager_get ()); g_slist_foreach (displays, (GFunc)gdk_display_close, NULL); g_slist_free (displays); } return 0; }
static int item_grid_button_pressed (GocItem *item, int button, double x_, double y_) { GnmItemGrid *ig = GNM_ITEM_GRID (item); GocCanvas *canvas = item->canvas; GnmPane *pane = GNM_PANE (canvas); SheetControlGUI *scg = ig->scg; WBCGtk *wbcg = scg_wbcg (scg); SheetControl *sc = (SheetControl *)scg; SheetView *sv = sc_view (sc); Sheet *sheet = sv_sheet (sv); GnmCellPos pos; gboolean edit_showed_dialog; gboolean already_selected; GdkEvent *event = goc_canvas_get_cur_event (item->canvas); gint64 x = x_ * canvas->pixels_per_unit, y = y_ * canvas->pixels_per_unit; gnm_pane_slide_stop (pane); pos.col = gnm_pane_find_col (pane, x, NULL); pos.row = gnm_pane_find_row (pane, y, NULL); /* GnmRange check first */ if (pos.col >= gnm_sheet_get_max_cols (sheet)) return TRUE; if (pos.row >= gnm_sheet_get_max_rows (sheet)) return TRUE; /* A new object is ready to be realized and inserted */ if (wbcg->new_object != NULL) return ig_obj_create_begin (ig, button, x, y); /* If we are not configuring an object then clicking on the sheet * ends the edit. */ if (scg->selected_objects == NULL) wbcg_focus_cur_scg (wbcg); else if (wbc_gtk_get_guru (wbcg) == NULL) scg_mode_edit (scg); /* If we were already selecting a range of cells for a formula, * reset the location to a new place, or extend the selection. */ if (button == 1 && scg->rangesel.active) { ig->selecting = GNM_ITEM_GRID_SELECTING_FORMULA_RANGE; if (event->button.state & GDK_SHIFT_MASK) scg_rangesel_extend_to (scg, pos.col, pos.row); else scg_rangesel_bound (scg, pos.col, pos.row, pos.col, pos.row); gnm_pane_slide_init (pane); gnm_simple_canvas_grab (item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, gdk_event_get_time (event)); return TRUE; } /* If the user is editing a formula (wbcg_rangesel_possible) then we * enable the dynamic cell selection mode. */ if (button == 1 && wbcg_rangesel_possible (wbcg)) { scg_rangesel_start (scg, pos.col, pos.row, pos.col, pos.row); ig->selecting = GNM_ITEM_GRID_SELECTING_FORMULA_RANGE; gnm_pane_slide_init (pane); gnm_simple_canvas_grab (item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, gdk_event_get_time (event)); return TRUE; } /* While a guru is up ignore clicks */ if (wbc_gtk_get_guru (wbcg) != NULL) return TRUE; /* This was a regular click on a cell on the spreadsheet. Select it. * but only if the entered expression is valid */ if (!wbcg_edit_finish (wbcg, WBC_EDIT_ACCEPT, &edit_showed_dialog)) return TRUE; if (button == 1 && !sheet_selection_is_allowed (sheet, &pos)) return TRUE; /* Button == 1 is used to trigger hyperlinks (and possibly similar */ /* special cases. Otherwise button == 2 should behave exactly like */ /* button == 1. See bug #700792 */ /* buttons 1 and 2 will always change the selection, the other buttons will * only effect things if the target is not already selected. */ already_selected = sv_is_pos_selected (sv, pos.col, pos.row); if (button == 1 || button == 2 || !already_selected) { if (!(event->button.state & (GDK_CONTROL_MASK|GDK_SHIFT_MASK))) sv_selection_reset (sv); if ((event->button.button != 1 && event->button.button != 2) || !(event->button.state & GDK_SHIFT_MASK) || sv->selections == NULL) { sv_selection_add_pos (sv, pos.col, pos.row, (already_selected && (event->button.state & GDK_CONTROL_MASK)) ? GNM_SELECTION_MODE_REMOVE : GNM_SELECTION_MODE_ADD); sv_make_cell_visible (sv, pos.col, pos.row, FALSE); } else sv_selection_extend_to (sv, pos.col, pos.row); sheet_update (sheet); } if (edit_showed_dialog) return TRUE; /* we already ignored the button release */ switch (button) { case 1: case 2: { guint32 double_click_time; /* * If the second click is on a different cell than the * first one this cannot be a double-click */ if (already_selected) { g_object_get (gtk_widget_get_settings (GTK_WIDGET (canvas)), "gtk-double-click-time", &double_click_time, NULL); if ((ig->last_click_time + double_click_time) > gdk_event_get_time (event) && wbcg_edit_start (wbcg, FALSE, FALSE)) { break; } } ig->last_click_time = gdk_event_get_time (event); ig->selecting = GNM_ITEM_GRID_SELECTING_CELL_RANGE; gnm_pane_slide_init (pane); gnm_simple_canvas_grab (item, GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, NULL, gdk_event_get_time (event)); break; } case 3: scg_context_menu (scg, event, FALSE, FALSE); break; default : break; } return TRUE; }