|
GnuCash 2.4.99
|
00001 /********************************************************************\ 00002 * table-allgui.c -- 2D grid table object, embeds cells for i/o * 00003 * * 00004 * This program is free software; you can redistribute it and/or * 00005 * modify it under the terms of the GNU General Public License as * 00006 * published by the Free Software Foundation; either version 2 of * 00007 * the License, or (at your option) any later version. * 00008 * * 00009 * This program is distributed in the hope that it will be useful, * 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00012 * GNU General Public License for more details. * 00013 * * 00014 * You should have received a copy of the GNU General Public License* 00015 * along with this program; if not, contact: * 00016 * * 00017 * Free Software Foundation Voice: +1-617-542-5942 * 00018 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00019 * Boston, MA 02110-1301, USA gnu@gnu.org * 00020 * * 00021 \********************************************************************/ 00022 00023 /* 00024 * FILE: 00025 * table-allgui.c 00026 * 00027 * FUNCTION: 00028 * Implements the gui-independent parts of the table infrastructure. 00029 * 00030 * HISTORY: 00031 * Copyright (c) 1998,1999,2000 Linas Vepstas 00032 * Copyright (c) 2000 Dave Peticolas 00033 */ 00034 00035 #include "config.h" 00036 00037 #include <stdio.h> 00038 #include <stdlib.h> 00039 #include <string.h> 00040 00041 #include <glib.h> 00042 00043 #include "table-allgui.h" 00044 #include "cellblock.h" 00045 #include "gnc-engine.h" 00046 00047 00050 static TableGUIHandlers default_gui_handlers; 00051 00052 /* This static indicates the debugging module that this .o belongs to. */ 00053 static QofLogModule log_module = GNC_MOD_REGISTER; 00054 00055 00057 static void gnc_table_init (Table * table); 00058 static void gnc_table_free_data (Table * table); 00059 static void gnc_virtual_cell_construct (gpointer vcell, gpointer user_data); 00060 static void gnc_virtual_cell_destroy (gpointer vcell, gpointer user_data); 00061 static void gnc_table_resize (Table * table, int virt_rows, int virt_cols); 00062 00063 00066 void 00067 gnc_table_set_default_gui_handlers (TableGUIHandlers *gui_handlers) 00068 { 00069 if (!gui_handlers) 00070 memset (&default_gui_handlers, 0, sizeof (default_gui_handlers)); 00071 else 00072 default_gui_handlers = *gui_handlers; 00073 } 00074 00075 Table * 00076 gnc_table_new (TableLayout *layout, TableModel *model, TableControl *control) 00077 { 00078 Table *table; 00079 00080 g_return_val_if_fail (layout != NULL, NULL); 00081 g_return_val_if_fail (model != NULL, NULL); 00082 g_return_val_if_fail (control != NULL, NULL); 00083 00084 table = g_new0 (Table, 1); 00085 00086 table->layout = layout; 00087 table->model = model; 00088 table->control = control; 00089 00090 table->gui_handlers = default_gui_handlers; 00091 00092 gnc_table_init (table); 00093 00094 table->virt_cells = g_table_new (sizeof (VirtualCell), 00095 gnc_virtual_cell_construct, 00096 gnc_virtual_cell_destroy, table); 00097 00098 return table; 00099 } 00100 00101 static void 00102 gnc_table_init (Table * table) 00103 { 00104 table->num_virt_rows = -1; 00105 table->num_virt_cols = -1; 00106 00107 table->current_cursor = NULL; 00108 00109 gnc_virtual_location_init (&table->current_cursor_loc); 00110 00111 /* initialize private data */ 00112 00113 table->virt_cells = NULL; 00114 table->ui_data = NULL; 00115 } 00116 00117 void 00118 gnc_table_destroy (Table * table) 00119 { 00120 /* invoke destroy callback */ 00121 if (table->gui_handlers.destroy) 00122 table->gui_handlers.destroy (table); 00123 00124 /* free the dynamic structures */ 00125 gnc_table_free_data (table); 00126 00127 /* free the cell tables */ 00128 g_table_destroy (table->virt_cells); 00129 00130 gnc_table_layout_destroy (table->layout); 00131 table->layout = NULL; 00132 00133 gnc_table_control_destroy (table->control); 00134 table->control = NULL; 00135 00136 gnc_table_model_destroy (table->model); 00137 table->model = NULL; 00138 00139 /* intialize vars to null value so that any access is voided. */ 00140 gnc_table_init (table); 00141 00142 g_free (table); 00143 } 00144 00145 int 00146 gnc_table_current_cursor_changed (Table *table, 00147 gboolean include_conditional) 00148 { 00149 if (!table) 00150 return FALSE; 00151 00152 return gnc_cellblock_changed (table->current_cursor, include_conditional); 00153 } 00154 00155 void 00156 gnc_table_clear_current_cursor_changes (Table *table) 00157 { 00158 if (!table) 00159 return; 00160 00161 gnc_cellblock_clear_changes (table->current_cursor); 00162 } 00163 00164 void 00165 gnc_table_save_current_cursor (Table *table, CursorBuffer *buffer) 00166 { 00167 if (!table || !buffer) 00168 return; 00169 00170 gnc_table_layout_save_cursor (table->layout, table->current_cursor, buffer); 00171 } 00172 00173 void 00174 gnc_table_restore_current_cursor (Table *table, 00175 CursorBuffer *buffer) 00176 { 00177 if (!table || !buffer) 00178 return; 00179 00180 gnc_table_layout_restore_cursor (table->layout, 00181 table->current_cursor, buffer); 00182 } 00183 00184 const char * 00185 gnc_table_get_current_cell_name (Table *table) 00186 { 00187 if (table == NULL) 00188 return NULL; 00189 00190 return gnc_table_get_cell_name (table, table->current_cursor_loc); 00191 } 00192 00193 gboolean 00194 gnc_table_get_current_cell_location (Table *table, 00195 const char *cell_name, 00196 VirtualLocation *virt_loc) 00197 { 00198 if (table == NULL) 00199 return FALSE; 00200 00201 return gnc_table_get_cell_location (table, cell_name, 00202 table->current_cursor_loc.vcell_loc, 00203 virt_loc); 00204 } 00205 00206 gboolean 00207 gnc_table_virtual_cell_out_of_bounds (Table *table, 00208 VirtualCellLocation vcell_loc) 00209 { 00210 if (!table) 00211 return TRUE; 00212 00213 return ((vcell_loc.virt_row < 0) || 00214 (vcell_loc.virt_row >= table->num_virt_rows) || 00215 (vcell_loc.virt_col < 0) || 00216 (vcell_loc.virt_col >= table->num_virt_cols)); 00217 } 00218 00219 gboolean 00220 gnc_table_virtual_location_in_header (Table *table, 00221 VirtualLocation virt_loc) 00222 { 00223 return (virt_loc.vcell_loc.virt_row == 0); 00224 } 00225 00226 VirtualCell * 00227 gnc_table_get_virtual_cell (Table *table, VirtualCellLocation vcell_loc) 00228 { 00229 if (table == NULL) 00230 return NULL; 00231 00232 return g_table_index (table->virt_cells, 00233 vcell_loc.virt_row, vcell_loc.virt_col); 00234 } 00235 00236 VirtualCell * 00237 gnc_table_get_header_cell (Table *table) 00238 { 00239 VirtualCellLocation vcell_loc = { 0, 0 }; 00240 00241 return gnc_table_get_virtual_cell (table, vcell_loc); 00242 } 00243 00244 static const char * 00245 gnc_table_get_entry_internal (Table *table, VirtualLocation virt_loc, 00246 gboolean *conditionally_changed) 00247 { 00248 TableGetEntryHandler entry_handler; 00249 const char *cell_name; 00250 const char *entry; 00251 00252 cell_name = gnc_table_get_cell_name (table, virt_loc); 00253 00254 entry_handler = gnc_table_model_get_entry_handler (table->model, cell_name); 00255 if (!entry_handler) return ""; 00256 00257 entry = entry_handler (virt_loc, FALSE, 00258 conditionally_changed, 00259 table->model->handler_user_data); 00260 if (!entry) 00261 entry = ""; 00262 00263 return entry; 00264 } 00265 00266 const char * 00267 gnc_table_get_entry (Table *table, VirtualLocation virt_loc) 00268 { 00269 TableGetEntryHandler entry_handler; 00270 const char *entry; 00271 BasicCell *cell; 00272 00273 cell = gnc_table_get_cell (table, virt_loc); 00274 if (!cell || !cell->cell_name) 00275 return ""; 00276 00277 if (virt_cell_loc_equal (table->current_cursor_loc.vcell_loc, 00278 virt_loc.vcell_loc)) 00279 { 00280 CellIOFlags io_flags; 00281 00282 io_flags = gnc_table_get_io_flags (table, virt_loc); 00283 00284 if (io_flags & XACC_CELL_ALLOW_INPUT) 00285 return cell->value; 00286 } 00287 00288 entry_handler = gnc_table_model_get_entry_handler (table->model, 00289 cell->cell_name); 00290 if (!entry_handler) return ""; 00291 00292 entry = entry_handler (virt_loc, TRUE, NULL, 00293 table->model->handler_user_data); 00294 if (!entry) 00295 entry = ""; 00296 00297 return entry; 00298 } 00299 00300 CellIOFlags 00301 gnc_table_get_io_flags (Table *table, VirtualLocation virt_loc) 00302 { 00303 TableGetCellIOFlagsHandler io_flags_handler; 00304 const char *cell_name; 00305 CellIOFlags flags; 00306 00307 if (!table || !table->model) 00308 return XACC_CELL_ALLOW_NONE; 00309 00310 cell_name = gnc_table_get_cell_name (table, virt_loc); 00311 00312 io_flags_handler = gnc_table_model_get_io_flags_handler (table->model, 00313 cell_name); 00314 if (!io_flags_handler) 00315 return XACC_CELL_ALLOW_NONE; 00316 00317 flags = io_flags_handler (virt_loc, table->model->handler_user_data); 00318 00319 if (gnc_table_model_read_only (table->model)) 00320 flags &= XACC_CELL_ALLOW_SHADOW; 00321 00322 return flags; 00323 } 00324 00325 const char * 00326 gnc_table_get_label (Table *table, VirtualLocation virt_loc) 00327 { 00328 TableGetLabelHandler label_handler; 00329 const char *cell_name; 00330 const char *label; 00331 00332 if (!table || !table->model) 00333 return ""; 00334 00335 cell_name = gnc_table_get_cell_name (table, virt_loc); 00336 00337 label_handler = gnc_table_model_get_label_handler (table->model, cell_name); 00338 if (!label_handler) 00339 return ""; 00340 00341 label = label_handler (virt_loc, table->model->handler_user_data); 00342 if (!label) 00343 return ""; 00344 00345 return label; 00346 } 00347 00348 guint32 00349 gnc_table_get_fg_color (Table *table, VirtualLocation virt_loc) 00350 { 00351 TableGetFGColorHandler fg_color_handler; 00352 const char *cell_name; 00353 00354 if (!table || !table->model) 00355 return 0x0; /* black */ 00356 00357 cell_name = gnc_table_get_cell_name (table, virt_loc); 00358 00359 fg_color_handler = gnc_table_model_get_fg_color_handler (table->model, 00360 cell_name); 00361 if (!fg_color_handler) 00362 return 0x0; 00363 00364 return fg_color_handler (virt_loc, table->model->handler_user_data); 00365 } 00366 00367 guint32 00368 gnc_table_get_bg_color (Table *table, VirtualLocation virt_loc, 00369 gboolean *hatching) 00370 { 00371 TableGetBGColorHandler bg_color_handler; 00372 const char *cell_name; 00373 00374 if (hatching) 00375 *hatching = FALSE; 00376 00377 if (!table || !table->model) 00378 return 0xffffff; /* white */ 00379 00380 cell_name = gnc_table_get_cell_name (table, virt_loc); 00381 00382 bg_color_handler = gnc_table_model_get_bg_color_handler (table->model, 00383 cell_name); 00384 if (!bg_color_handler) 00385 return 0xffffff; 00386 00387 return bg_color_handler (virt_loc, hatching, 00388 table->model->handler_user_data); 00389 } 00390 00391 guint32 00392 gnc_table_get_gtkrc_bg_color (Table *table, VirtualLocation virt_loc, 00393 gboolean *hatching) 00394 { 00395 TableGetBGColorHandler bg_color_handler; 00396 const char *cell_name; 00397 00398 if (hatching) 00399 *hatching = FALSE; 00400 00401 if (!table || !table->model) 00402 return 0xffffff; /* white */ 00403 00404 cell_name = gnc_table_get_cell_name (table, virt_loc); 00405 00406 bg_color_handler = gnc_table_model_get_bg_color_handler (table->model, 00407 "gtkrc"); 00408 if (!bg_color_handler) 00409 return 0xffffff; 00410 00411 return bg_color_handler (virt_loc, hatching, 00412 table->model->handler_user_data); 00413 } 00414 00415 void 00416 gnc_table_get_borders (Table *table, VirtualLocation virt_loc, 00417 PhysicalCellBorders *borders) 00418 { 00419 TableGetCellBorderHandler cell_border_handler; 00420 const char *cell_name; 00421 00422 if (!table || !table->model) 00423 return; 00424 00425 cell_name = gnc_table_get_cell_name (table, virt_loc); 00426 00427 cell_border_handler = gnc_table_model_get_cell_border_handler (table->model, 00428 cell_name); 00429 if (!cell_border_handler) 00430 return; 00431 00432 cell_border_handler (virt_loc, borders, table->model->handler_user_data); 00433 } 00434 00435 CellAlignment 00436 gnc_table_get_align (Table *table, VirtualLocation virt_loc) 00437 { 00438 BasicCell *cell; 00439 00440 cell = gnc_table_get_cell (table, virt_loc); 00441 if (!cell) 00442 return CELL_ALIGN_RIGHT; 00443 00444 return cell->alignment; 00445 } 00446 00447 gboolean 00448 gnc_table_is_popup (Table *table, VirtualLocation virt_loc) 00449 { 00450 BasicCell *cell; 00451 00452 cell = gnc_table_get_cell (table, virt_loc); 00453 if (!cell) 00454 return FALSE; 00455 00456 return cell->is_popup; 00457 } 00458 00459 char * 00460 gnc_table_get_help (Table *table) 00461 { 00462 TableGetHelpHandler help_handler; 00463 VirtualLocation virt_loc; 00464 const char * cell_name; 00465 00466 if (!table) 00467 return NULL; 00468 00469 virt_loc = table->current_cursor_loc; 00470 00471 cell_name = gnc_table_get_cell_name (table, virt_loc); 00472 00473 help_handler = gnc_table_model_get_help_handler (table->model, cell_name); 00474 if (!help_handler) 00475 return NULL; 00476 00477 return help_handler (virt_loc, table->model->handler_user_data); 00478 } 00479 00480 BasicCell * 00481 gnc_table_get_cell (Table *table, VirtualLocation virt_loc) 00482 { 00483 VirtualCell *vcell; 00484 00485 if (!table) 00486 return NULL; 00487 00488 vcell = gnc_table_get_virtual_cell (table, virt_loc.vcell_loc); 00489 if (!vcell) 00490 return NULL; 00491 00492 return gnc_cellblock_get_cell (vcell->cellblock, 00493 virt_loc.phys_row_offset, 00494 virt_loc.phys_col_offset); 00495 } 00496 00497 const char * 00498 gnc_table_get_cell_name (Table *table, VirtualLocation virt_loc) 00499 { 00500 BasicCell *cell; 00501 00502 cell = gnc_table_get_cell (table, virt_loc); 00503 if (cell == NULL) 00504 return NULL; 00505 00506 return cell->cell_name; 00507 } 00508 00509 const gchar * 00510 gnc_table_get_cell_type_name (Table *table, VirtualLocation virt_loc) 00511 { 00512 BasicCell *cell; 00513 00514 cell = gnc_table_get_cell (table, virt_loc); 00515 if (cell == NULL) 00516 return NULL; 00517 00518 return cell->cell_type_name; 00519 } 00520 00521 00522 gboolean 00523 gnc_table_get_cell_location (Table *table, 00524 const char *cell_name, 00525 VirtualCellLocation vcell_loc, 00526 VirtualLocation *virt_loc) 00527 { 00528 VirtualCell *vcell; 00529 CellBlock *cellblock; 00530 int cell_row, cell_col; 00531 00532 if (table == NULL) 00533 return FALSE; 00534 00535 vcell = gnc_table_get_virtual_cell (table, vcell_loc); 00536 if (vcell == NULL) 00537 return FALSE; 00538 00539 cellblock = vcell->cellblock; 00540 00541 for (cell_row = 0; cell_row < cellblock->num_rows; cell_row++) 00542 for (cell_col = 0; cell_col < cellblock->num_cols; cell_col++) 00543 { 00544 BasicCell *cell; 00545 00546 cell = gnc_cellblock_get_cell (cellblock, cell_row, cell_col); 00547 if (!cell) 00548 continue; 00549 00550 if (gnc_basic_cell_has_name (cell, cell_name)) 00551 { 00552 if (virt_loc != NULL) 00553 { 00554 virt_loc->vcell_loc = vcell_loc; 00555 00556 virt_loc->phys_row_offset = cell_row; 00557 virt_loc->phys_col_offset = cell_col; 00558 } 00559 00560 return TRUE; 00561 } 00562 } 00563 00564 return FALSE; 00565 } 00566 00567 void 00568 gnc_table_save_cells (Table *table, gpointer save_data) 00569 { 00570 TableSaveHandler save_handler; 00571 GList * cells; 00572 GList * node; 00573 00574 g_return_if_fail (table); 00575 00576 /* ignore any changes to read-only tables */ 00577 if (gnc_table_model_read_only (table->model)) 00578 return; 00579 00580 // gnc_table_leave_update (table, table->current_cursor_loc); 00581 00582 save_handler = gnc_table_model_get_pre_save_handler (table->model); 00583 if (save_handler) 00584 save_handler (save_data, table->model->handler_user_data); 00585 00586 cells = gnc_table_layout_get_cells (table->layout); 00587 for (node = cells; node; node = node->next) 00588 { 00589 BasicCell * cell = node->data; 00590 TableSaveCellHandler save_cell_handler; 00591 00592 if (!cell) continue; 00593 00594 if (!gnc_table_layout_get_cell_changed (table->layout, 00595 cell->cell_name, TRUE)) 00596 continue; 00597 00598 save_cell_handler = gnc_table_model_get_save_handler (table->model, 00599 cell->cell_name); 00600 if (save_cell_handler) 00601 save_cell_handler (cell, save_data, table->model->handler_user_data); 00602 } 00603 00604 save_handler = gnc_table_model_get_post_save_handler (table->model); 00605 if (save_handler) 00606 save_handler (save_data, table->model->handler_user_data); 00607 } 00608 00609 void 00610 gnc_table_set_size (Table * table, int virt_rows, int virt_cols) 00611 { 00612 /* Invalidate the current cursor position, if the array is 00613 * shrinking. This must be done since the table is probably 00614 * shrinking because some rows were deleted, and the cursor 00615 * could be on the deleted rows. */ 00616 if ((virt_rows < table->num_virt_rows) || 00617 (virt_cols < table->num_virt_cols)) 00618 { 00619 gnc_virtual_location_init (&table->current_cursor_loc); 00620 table->current_cursor = NULL; 00621 } 00622 00623 gnc_table_resize (table, virt_rows, virt_cols); 00624 } 00625 00626 static void 00627 gnc_table_free_data (Table * table) 00628 { 00629 if (table == NULL) 00630 return; 00631 00632 g_table_resize (table->virt_cells, 0, 0); 00633 } 00634 00635 void 00636 gnc_virtual_location_init (VirtualLocation *vloc) 00637 { 00638 if (vloc == NULL) 00639 return; 00640 00641 vloc->phys_row_offset = -1; 00642 vloc->phys_col_offset = -1; 00643 vloc->vcell_loc.virt_row = -1; 00644 vloc->vcell_loc.virt_col = -1; 00645 } 00646 00647 static void 00648 gnc_virtual_cell_construct (gpointer _vcell, gpointer user_data) 00649 { 00650 VirtualCell *vcell = _vcell; 00651 Table *table = user_data; 00652 00653 vcell->cellblock = NULL; 00654 00655 if (table && table->model->cell_data_allocator) 00656 vcell->vcell_data = table->model->cell_data_allocator (); 00657 else 00658 vcell->vcell_data = NULL; 00659 00660 vcell->visible = 1; 00661 } 00662 00663 static void 00664 gnc_virtual_cell_destroy (gpointer _vcell, gpointer user_data) 00665 { 00666 VirtualCell *vcell = _vcell; 00667 Table *table = user_data; 00668 00669 if (vcell->vcell_data && table && table->model->cell_data_deallocator) 00670 table->model->cell_data_deallocator (vcell->vcell_data); 00671 00672 vcell->vcell_data = NULL; 00673 } 00674 00675 static void 00676 gnc_table_resize (Table * table, int new_virt_rows, int new_virt_cols) 00677 { 00678 if (!table) return; 00679 00680 g_table_resize (table->virt_cells, new_virt_rows, new_virt_cols); 00681 00682 table->num_virt_rows = new_virt_rows; 00683 table->num_virt_cols = new_virt_cols; 00684 } 00685 00686 void 00687 gnc_table_set_vcell (Table *table, 00688 CellBlock *cursor, 00689 gconstpointer vcell_data, 00690 gboolean visible, 00691 gboolean start_primary_color, 00692 VirtualCellLocation vcell_loc) 00693 { 00694 VirtualCell *vcell; 00695 00696 if ((table == NULL) || (cursor == NULL)) 00697 return; 00698 00699 if ((vcell_loc.virt_row >= table->num_virt_rows) || 00700 (vcell_loc.virt_col >= table->num_virt_cols)) 00701 gnc_table_resize (table, 00702 MAX (table->num_virt_rows, vcell_loc.virt_row + 1), 00703 MAX (table->num_virt_cols, vcell_loc.virt_col + 1)); 00704 00705 vcell = gnc_table_get_virtual_cell (table, vcell_loc); 00706 if (vcell == NULL) 00707 return; 00708 00709 /* this cursor is the handler for this block */ 00710 vcell->cellblock = cursor; 00711 00712 /* copy the vcell user data */ 00713 if (table->model->cell_data_copy) 00714 table->model->cell_data_copy (vcell->vcell_data, vcell_data); 00715 else 00716 vcell->vcell_data = (gpointer) vcell_data; 00717 00718 vcell->visible = visible ? 1 : 0; 00719 vcell->start_primary_color = start_primary_color ? 1 : 0; 00720 } 00721 00722 void 00723 gnc_table_set_virt_cell_data (Table *table, 00724 VirtualCellLocation vcell_loc, 00725 gconstpointer vcell_data) 00726 { 00727 VirtualCell *vcell; 00728 00729 if (table == NULL) 00730 return; 00731 00732 vcell = gnc_table_get_virtual_cell (table, vcell_loc); 00733 if (vcell == NULL) 00734 return; 00735 00736 if (table->model->cell_data_copy) 00737 table->model->cell_data_copy (vcell->vcell_data, vcell_data); 00738 else 00739 vcell->vcell_data = (gpointer) vcell_data; 00740 } 00741 00742 void 00743 gnc_table_set_virt_cell_visible (Table *table, 00744 VirtualCellLocation vcell_loc, 00745 gboolean visible) 00746 { 00747 VirtualCell *vcell; 00748 00749 if (table == NULL) 00750 return; 00751 00752 vcell = gnc_table_get_virtual_cell (table, vcell_loc); 00753 if (vcell == NULL) 00754 return; 00755 00756 vcell->visible = visible ? 1 : 0; 00757 } 00758 00759 void 00760 gnc_table_set_virt_cell_cursor (Table *table, 00761 VirtualCellLocation vcell_loc, 00762 CellBlock *cursor) 00763 { 00764 VirtualCell *vcell; 00765 00766 if (table == NULL) 00767 return; 00768 00769 vcell = gnc_table_get_virtual_cell (table, vcell_loc); 00770 if (vcell == NULL) 00771 return; 00772 00773 vcell->cellblock = cursor; 00774 } 00775 00776 static void 00777 gnc_table_move_cursor_internal (Table *table, 00778 VirtualLocation new_virt_loc, 00779 gboolean do_move_gui) 00780 { 00781 int cell_row, cell_col; 00782 VirtualLocation virt_loc; 00783 VirtualCell *vcell; 00784 CellBlock *curs; 00785 00786 ENTER("new_virt=(%d %d) do_move_gui=%d\n", 00787 new_virt_loc.vcell_loc.virt_row, 00788 new_virt_loc.vcell_loc.virt_col, do_move_gui); 00789 00790 /* call the callback, allowing the app to commit any changes 00791 * associated with the current location of the cursor. Note that 00792 * this callback may recursively call this routine. */ 00793 if (table->control->move_cursor && table->control->allow_move) 00794 { 00795 table->control->move_cursor (&new_virt_loc, table->control->user_data); 00796 00797 /* The above callback can cause this routine to be called 00798 * recursively. As a result of this recursion, the cursor may 00799 * have gotten repositioned. We need to make sure we make 00800 * passive again. */ 00801 if (do_move_gui) 00802 gnc_table_refresh_current_cursor_gui (table, FALSE); 00803 } 00804 00805 /* invalidate the cursor for now; we'll fix it back up below */ 00806 gnc_virtual_location_init (&table->current_cursor_loc); 00807 00808 curs = table->current_cursor; 00809 table->current_cursor = NULL; 00810 00811 /* check for out-of-bounds conditions (which may be deliberate) */ 00812 if ((new_virt_loc.vcell_loc.virt_row < 0) || 00813 (new_virt_loc.vcell_loc.virt_col < 0)) 00814 { 00815 /* if the location is invalid, then we should take this 00816 * as a command to unmap the cursor gui. */ 00817 if (do_move_gui && curs) 00818 { 00819 for (cell_row = 0; cell_row < curs->num_rows; cell_row++) 00820 for (cell_col = 0; cell_col < curs->num_cols; cell_col++) 00821 { 00822 BasicCell *cell; 00823 00824 cell = gnc_cellblock_get_cell (curs, cell_row, cell_col); 00825 if (cell) 00826 { 00827 cell->changed = FALSE; 00828 cell->conditionally_changed = FALSE; 00829 00830 if (cell->gui_move) 00831 cell->gui_move (cell); 00832 } 00833 } 00834 } 00835 00836 LEAVE("out of bounds\n"); 00837 return; 00838 } 00839 00840 if (!gnc_table_virtual_loc_valid (table, new_virt_loc, TRUE)) 00841 { 00842 PWARN("bad table location"); 00843 LEAVE(""); 00844 return; 00845 } 00846 00847 /* ok, we now have a valid position. Find the new cursor to use, 00848 * and initialize its cells */ 00849 vcell = gnc_table_get_virtual_cell (table, new_virt_loc.vcell_loc); 00850 curs = vcell->cellblock; 00851 table->current_cursor = curs; 00852 00853 /* record the new position */ 00854 table->current_cursor_loc = new_virt_loc; 00855 00856 virt_loc.vcell_loc = new_virt_loc.vcell_loc; 00857 00858 /* update the cell values to reflect the new position */ 00859 for (cell_row = 0; cell_row < curs->num_rows; cell_row++) 00860 for (cell_col = 0; cell_col < curs->num_cols; cell_col++) 00861 { 00862 BasicCell *cell; 00863 CellIOFlags io_flags; 00864 00865 virt_loc.phys_row_offset = cell_row; 00866 virt_loc.phys_col_offset = cell_col; 00867 00868 cell = gnc_cellblock_get_cell(curs, cell_row, cell_col); 00869 if (cell) 00870 { 00871 /* if a cell has a GUI, move that first, before setting 00872 * the cell value. Otherwise, we'll end up putting the 00873 * new values in the old cell locations, and that would 00874 * lead to confusion of all sorts. */ 00875 if (do_move_gui && cell->gui_move) 00876 cell->gui_move (cell); 00877 00878 /* OK, now copy the string value from the table at large 00879 * into the cell handler. */ 00880 io_flags = gnc_table_get_io_flags (table, virt_loc); 00881 if (io_flags & XACC_CELL_ALLOW_SHADOW) 00882 { 00883 const char *entry; 00884 gboolean conditionally_changed = FALSE; 00885 00886 entry = gnc_table_get_entry_internal (table, virt_loc, 00887 &conditionally_changed); 00888 00889 gnc_basic_cell_set_value (cell, entry); 00890 00891 cell->changed = FALSE; 00892 cell->conditionally_changed = conditionally_changed; 00893 } 00894 } 00895 } 00896 00897 LEAVE("did move\n"); 00898 } 00899 00900 void 00901 gnc_table_move_cursor (Table *table, VirtualLocation new_virt_loc) 00902 { 00903 if (!table) return; 00904 00905 gnc_table_move_cursor_internal (table, new_virt_loc, FALSE); 00906 } 00907 00908 /* same as above, but be sure to deal with GUI elements as well */ 00909 void 00910 gnc_table_move_cursor_gui (Table *table, VirtualLocation new_virt_loc) 00911 { 00912 if (!table) return; 00913 00914 gnc_table_move_cursor_internal (table, new_virt_loc, TRUE); 00915 } 00916 00917 /* gnc_table_verify_cursor_position checks the location of the cursor 00918 * with respect to a virtual location, and repositions the cursor 00919 * if necessary. Returns true if the cell cursor was repositioned. */ 00920 gboolean 00921 gnc_table_verify_cursor_position (Table *table, VirtualLocation virt_loc) 00922 { 00923 gboolean do_move = FALSE; 00924 gboolean moved_cursor = FALSE; 00925 00926 if (!table) return FALSE; 00927 00928 /* Someone may be trying to intentionally invalidate the cursor, in 00929 * which case the physical addresses could be out of bounds. For 00930 * example, in order to unmap it in preparation for a reconfig. 00931 * So, if the specified location is out of bounds, then the cursor 00932 * MUST be moved. */ 00933 if (gnc_table_virtual_cell_out_of_bounds (table, virt_loc.vcell_loc)) 00934 do_move = TRUE; 00935 00936 if (!virt_cell_loc_equal (virt_loc.vcell_loc, 00937 table->current_cursor_loc.vcell_loc)) 00938 do_move = TRUE; 00939 00940 if (do_move) 00941 { 00942 gnc_table_move_cursor_gui (table, virt_loc); 00943 moved_cursor = TRUE; 00944 } 00945 else if (!virt_loc_equal (virt_loc, table->current_cursor_loc)) 00946 { 00947 table->current_cursor_loc = virt_loc; 00948 moved_cursor = TRUE; 00949 } 00950 00951 return moved_cursor; 00952 } 00953 00954 gpointer 00955 gnc_table_get_vcell_data (Table *table, VirtualCellLocation vcell_loc) 00956 { 00957 VirtualCell *vcell; 00958 00959 if (!table) return NULL; 00960 00961 vcell = gnc_table_get_virtual_cell (table, vcell_loc); 00962 if (vcell == NULL) 00963 return NULL; 00964 00965 return vcell->vcell_data; 00966 } 00967 00968 /* If any of the cells have GUI specific components that need 00969 * initialization, initialize them now. The realize() callback 00970 * on the cursor cell is how we inform the cell handler that 00971 * now is the time to initialize its GUI. */ 00972 void 00973 gnc_table_realize_gui (Table * table) 00974 { 00975 GList *cells; 00976 GList *node; 00977 00978 if (!table) return; 00979 if (!table->ui_data) return; 00980 00981 cells = gnc_table_layout_get_cells (table->layout); 00982 00983 for (node = cells; node; node = node->next) 00984 { 00985 BasicCell *cell = node->data; 00986 00987 if (cell->gui_realize) 00988 cell->gui_realize (cell, table->ui_data); 00989 } 00990 } 00991 00992 void 00993 gnc_table_wrap_verify_cursor_position (Table *table, VirtualLocation virt_loc) 00994 { 00995 VirtualLocation save_loc; 00996 gboolean moved_cursor; 00997 00998 if (!table) return; 00999 01000 ENTER("(%d %d)", virt_loc.vcell_loc.virt_row, virt_loc.vcell_loc.virt_col); 01001 01002 save_loc = table->current_cursor_loc; 01003 01004 /* VerifyCursor will do all sorts of gui-independent machinations */ 01005 moved_cursor = gnc_table_verify_cursor_position (table, virt_loc); 01006 01007 if (moved_cursor) 01008 { 01009 /* make sure *both* the old and the new cursor rows get redrawn */ 01010 gnc_table_refresh_current_cursor_gui (table, TRUE); 01011 gnc_table_refresh_cursor_gui (table, save_loc.vcell_loc, FALSE); 01012 } 01013 01014 LEAVE (""); 01015 } 01016 01017 void 01018 gnc_table_refresh_current_cursor_gui (Table * table, gboolean do_scroll) 01019 { 01020 if (!table) return; 01021 01022 gnc_table_refresh_cursor_gui (table, table->current_cursor_loc.vcell_loc, 01023 do_scroll); 01024 } 01025 01026 gboolean 01027 gnc_table_virtual_loc_valid(Table *table, 01028 VirtualLocation virt_loc, 01029 gboolean exact_pointer) 01030 { 01031 VirtualCell *vcell; 01032 CellIOFlags io_flags; 01033 01034 if (!table) return FALSE; 01035 01036 /* header rows cannot be modified */ 01037 if (virt_loc.vcell_loc.virt_row == 0) 01038 return FALSE; 01039 01040 vcell = gnc_table_get_virtual_cell(table, virt_loc.vcell_loc); 01041 if (vcell == NULL) 01042 return FALSE; 01043 01044 if (!vcell->visible) 01045 return FALSE; 01046 01047 /* verify that offsets are valid. This may occur if the app that is 01048 * using the table has a paritally initialized cursor. (probably due 01049 * to a programming error, but maybe they meant to do this). */ 01050 if ((0 > virt_loc.phys_row_offset) || (0 > virt_loc.phys_col_offset)) 01051 return FALSE; 01052 01053 /* check for a cell handler, but only if cell address is valid */ 01054 if (vcell->cellblock == NULL) return FALSE; 01055 01056 /* if table is read-only, any cell is ok :) */ 01057 if (gnc_table_model_read_only (table->model)) return TRUE; 01058 01059 io_flags = gnc_table_get_io_flags (table, virt_loc); 01060 01061 /* if the cell allows ENTER, then it is ok */ 01062 if (io_flags & XACC_CELL_ALLOW_ENTER) return TRUE; 01063 01064 /* if cell is marked as output-only, you can't enter */ 01065 if (0 == (XACC_CELL_ALLOW_INPUT & io_flags)) return FALSE; 01066 01067 /* if cell is pointer only and this is not an exact pointer test, 01068 * it cannot be entered. */ 01069 if (!exact_pointer && ((XACC_CELL_ALLOW_EXACT_ONLY & io_flags) != 0)) 01070 return FALSE; 01071 01072 return TRUE; 01073 } 01074 01075 /* Handle the non gui-specific parts of a cell enter callback */ 01076 gboolean 01077 gnc_table_enter_update (Table *table, 01078 VirtualLocation virt_loc, 01079 int *cursor_position, 01080 int *start_selection, 01081 int *end_selection) 01082 { 01083 gboolean can_edit = TRUE; 01084 CellEnterFunc enter; 01085 BasicCell *cell; 01086 CellBlock *cb; 01087 int cell_row; 01088 int cell_col; 01089 CellIOFlags io_flags; 01090 01091 if (table == NULL) 01092 return FALSE; 01093 01094 cb = table->current_cursor; 01095 01096 cell_row = virt_loc.phys_row_offset; 01097 cell_col = virt_loc.phys_col_offset; 01098 01099 ENTER("enter %d %d (relrow=%d relcol=%d)", 01100 virt_loc.vcell_loc.virt_row, 01101 virt_loc.vcell_loc.virt_col, 01102 cell_row, cell_col); 01103 01104 /* OK, if there is a callback for this cell, call it */ 01105 cell = gnc_cellblock_get_cell (cb, cell_row, cell_col); 01106 if (!cell) 01107 { 01108 LEAVE("no cell"); 01109 return FALSE; 01110 } 01111 01112 io_flags = gnc_table_get_io_flags (table, virt_loc); 01113 if (io_flags == XACC_CELL_ALLOW_READ_ONLY) 01114 { 01115 LEAVE("read only cell"); 01116 return FALSE; 01117 } 01118 01119 enter = cell->enter_cell; 01120 01121 if (enter) 01122 { 01123 char * old_value; 01124 01125 DEBUG("gnc_table_enter_update(): %d %d has enter handler\n", 01126 cell_row, cell_col); 01127 01128 old_value = g_strdup (cell->value); 01129 01130 can_edit = enter (cell, cursor_position, start_selection, end_selection); 01131 01132 if (safe_strcmp (old_value, cell->value) != 0) 01133 { 01134 if (gnc_table_model_read_only (table->model)) 01135 { 01136 PWARN ("enter update changed read-only table"); 01137 } 01138 01139 cell->changed = TRUE; 01140 } 01141 01142 g_free (old_value); 01143 } 01144 01145 if (table->gui_handlers.redraw_help) 01146 table->gui_handlers.redraw_help (table); 01147 01148 LEAVE("return %d\n", can_edit); 01149 return can_edit; 01150 } 01151 01152 void 01153 gnc_table_leave_update (Table *table, VirtualLocation virt_loc) 01154 { 01155 CellLeaveFunc leave; 01156 BasicCell *cell; 01157 CellBlock *cb; 01158 int cell_row; 01159 int cell_col; 01160 01161 if (table == NULL) 01162 return; 01163 01164 cb = table->current_cursor; 01165 01166 cell_row = virt_loc.phys_row_offset; 01167 cell_col = virt_loc.phys_col_offset; 01168 01169 ENTER("proposed (%d %d) rel(%d %d)\n", 01170 virt_loc.vcell_loc.virt_row, 01171 virt_loc.vcell_loc.virt_col, 01172 cell_row, cell_col); 01173 01174 /* OK, if there is a callback for this cell, call it */ 01175 cell = gnc_cellblock_get_cell (cb, cell_row, cell_col); 01176 if (!cell) 01177 { 01178 LEAVE("no cell"); 01179 return; 01180 } 01181 01182 leave = cell->leave_cell; 01183 01184 if (leave) 01185 { 01186 char * old_value; 01187 01188 old_value = g_strdup (cell->value); 01189 01190 leave (cell); 01191 01192 if (safe_strcmp (old_value, cell->value) != 0) 01193 { 01194 if (gnc_table_model_read_only (table->model)) 01195 { 01196 PWARN ("leave update changed read-only table"); 01197 } 01198 01199 cell->changed = TRUE; 01200 } 01201 01202 g_free (old_value); 01203 } 01204 LEAVE(""); 01205 } 01206 01207 gboolean 01208 gnc_table_confirm_change (Table *table, VirtualLocation virt_loc) 01209 { 01210 TableConfirmHandler confirm_handler; 01211 const char *cell_name; 01212 01213 if (!table || !table->model) 01214 return TRUE; 01215 01216 cell_name = gnc_table_get_cell_name (table, virt_loc); 01217 01218 confirm_handler = gnc_table_model_get_confirm_handler (table->model, 01219 cell_name); 01220 if (!confirm_handler) 01221 return TRUE; 01222 01223 return confirm_handler (virt_loc, table->model->handler_user_data); 01224 } 01225 01226 /* Returned result should not be touched by the caller. 01227 * NULL return value means the edit was rejected. */ 01228 const char * 01229 gnc_table_modify_update (Table *table, 01230 VirtualLocation virt_loc, 01231 const char *change, 01232 int change_len, 01233 const char *newval, 01234 int newval_len, 01235 int *cursor_position, 01236 int *start_selection, 01237 int *end_selection, 01238 gboolean *cancelled) 01239 { 01240 gboolean changed = FALSE; 01241 CellModifyVerifyFunc mv; 01242 BasicCell *cell; 01243 CellBlock *cb; 01244 int cell_row; 01245 int cell_col; 01246 char * old_value; 01247 01248 g_return_val_if_fail (table, NULL); 01249 g_return_val_if_fail (table->model, NULL); 01250 01251 if (gnc_table_model_read_only (table->model)) 01252 { 01253 PWARN ("change to read-only table"); 01254 return NULL; 01255 } 01256 01257 cb = table->current_cursor; 01258 01259 cell_row = virt_loc.phys_row_offset; 01260 cell_col = virt_loc.phys_col_offset; 01261 01262 ENTER (""); 01263 01264 if (!gnc_table_confirm_change (table, virt_loc)) 01265 { 01266 if (cancelled) 01267 *cancelled = TRUE; 01268 01269 LEAVE("change cancelled"); 01270 return NULL; 01271 } 01272 01273 if (cancelled) 01274 *cancelled = FALSE; 01275 01276 /* OK, if there is a callback for this cell, call it */ 01277 cell = gnc_cellblock_get_cell (cb, cell_row, cell_col); 01278 if (!cell) 01279 { 01280 LEAVE("no cell"); 01281 return NULL; 01282 } 01283 01284 mv = cell->modify_verify; 01285 01286 old_value = g_strdup (cell->value); 01287 01288 if (mv) 01289 { 01290 mv (cell, change, change_len, newval, newval_len, 01291 cursor_position, start_selection, end_selection); 01292 } 01293 else 01294 { 01295 gnc_basic_cell_set_value (cell, newval); 01296 } 01297 01298 if (safe_strcmp (old_value, cell->value) != 0) 01299 { 01300 changed = TRUE; 01301 cell->changed = TRUE; 01302 } 01303 01304 g_free (old_value); 01305 01306 if (table->gui_handlers.redraw_help) 01307 table->gui_handlers.redraw_help (table); 01308 01309 LEAVE ("change %d %d (relrow=%d relcol=%d) val=%s\n", 01310 virt_loc.vcell_loc.virt_row, 01311 virt_loc.vcell_loc.virt_col, 01312 cell_row, cell_col, 01313 cell->value ? cell->value : "(null)"); 01314 01315 if (changed) 01316 return cell->value; 01317 else 01318 return NULL; 01319 } 01320 01321 gboolean 01322 gnc_table_direct_update (Table *table, 01323 VirtualLocation virt_loc, 01324 char **newval_ptr, 01325 int *cursor_position, 01326 int *start_selection, 01327 int *end_selection, 01328 gpointer gui_data) 01329 { 01330 gboolean result; 01331 BasicCell *cell; 01332 CellBlock *cb; 01333 int cell_row; 01334 int cell_col; 01335 char * old_value; 01336 01337 g_return_val_if_fail (table, FALSE); 01338 g_return_val_if_fail (table->model, FALSE); 01339 01340 if (gnc_table_model_read_only (table->model)) 01341 { 01342 PWARN ("input to read-only table"); 01343 return FALSE; 01344 } 01345 01346 cb = table->current_cursor; 01347 01348 cell_row = virt_loc.phys_row_offset; 01349 cell_col = virt_loc.phys_col_offset; 01350 01351 cell = gnc_cellblock_get_cell (cb, cell_row, cell_col); 01352 if (!cell) 01353 return FALSE; 01354 01355 ENTER (""); 01356 01357 if (cell->direct_update == NULL) 01358 { 01359 LEAVE("no direct update"); 01360 return FALSE; 01361 } 01362 01363 old_value = g_strdup (cell->value); 01364 01365 result = cell->direct_update (cell, cursor_position, start_selection, 01366 end_selection, gui_data); 01367 01368 if (safe_strcmp (old_value, cell->value) != 0) 01369 { 01370 if (!gnc_table_confirm_change (table, virt_loc)) 01371 { 01372 gnc_basic_cell_set_value (cell, old_value); 01373 *newval_ptr = NULL; 01374 result = TRUE; 01375 } 01376 else 01377 { 01378 cell->changed = TRUE; 01379 *newval_ptr = cell->value; 01380 } 01381 } 01382 else 01383 *newval_ptr = NULL; 01384 01385 g_free (old_value); 01386 01387 if (table->gui_handlers.redraw_help) 01388 table->gui_handlers.redraw_help (table); 01389 01390 LEAVE(""); 01391 return result; 01392 } 01393 01394 static gboolean gnc_table_find_valid_cell_horiz (Table *table, 01395 VirtualLocation *virt_loc, 01396 gboolean exact_cell); 01397 01398 static gboolean 01399 gnc_table_find_valid_row_vert (Table *table, VirtualLocation *virt_loc) 01400 { 01401 VirtualLocation vloc; 01402 VirtualCell *vcell = NULL; 01403 int top; 01404 int bottom; 01405 01406 if (table == NULL) 01407 return FALSE; 01408 01409 if (virt_loc == NULL) 01410 return FALSE; 01411 01412 vloc = *virt_loc; 01413 01414 if (vloc.vcell_loc.virt_row < 1) 01415 vloc.vcell_loc.virt_row = 1; 01416 if (vloc.vcell_loc.virt_row >= table->num_virt_rows) 01417 vloc.vcell_loc.virt_row = table->num_virt_rows - 1; 01418 01419 top = vloc.vcell_loc.virt_row; 01420 bottom = vloc.vcell_loc.virt_row + 1; 01421 01422 while (top >= 1 || bottom < table->num_virt_rows) 01423 { 01424 vloc.vcell_loc.virt_row = top; 01425 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01426 if (vcell && vcell->cellblock && vcell->visible) 01427 { 01428 vloc.phys_row_offset = 0; 01429 vloc.phys_col_offset = 0; 01430 01431 if (gnc_table_find_valid_cell_horiz (table, &vloc, FALSE)) 01432 break; 01433 } 01434 01435 vloc.vcell_loc.virt_row = bottom; 01436 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01437 if (vcell && vcell->cellblock && vcell->visible) 01438 { 01439 vloc.phys_row_offset = 0; 01440 vloc.phys_col_offset = 0; 01441 01442 if (gnc_table_find_valid_cell_horiz (table, &vloc, FALSE)) 01443 break; 01444 } 01445 01446 top--; 01447 bottom++; 01448 } 01449 01450 if (!vcell || !vcell->cellblock || !vcell->visible) 01451 return FALSE; 01452 01453 if (vloc.phys_row_offset < 0) 01454 vloc.phys_row_offset = 0; 01455 if (vloc.phys_row_offset >= vcell->cellblock->num_rows) 01456 vloc.phys_row_offset = vcell->cellblock->num_rows - 1; 01457 01458 virt_loc->vcell_loc = vloc.vcell_loc; 01459 01460 return TRUE; 01461 } 01462 01463 static gboolean 01464 gnc_table_find_valid_cell_horiz (Table *table, 01465 VirtualLocation *virt_loc, 01466 gboolean exact_cell) 01467 { 01468 VirtualLocation vloc; 01469 VirtualCell *vcell; 01470 int left; 01471 int right; 01472 01473 if (table == NULL) 01474 return FALSE; 01475 01476 if (virt_loc == NULL) 01477 return FALSE; 01478 01479 if (gnc_table_virtual_cell_out_of_bounds (table, virt_loc->vcell_loc)) 01480 return FALSE; 01481 01482 if (gnc_table_virtual_loc_valid (table, *virt_loc, exact_cell)) 01483 return TRUE; 01484 01485 vloc = *virt_loc; 01486 01487 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01488 if (vcell == NULL) 01489 return FALSE; 01490 if (vcell->cellblock == NULL) 01491 return FALSE; 01492 01493 if (vloc.phys_col_offset < 0) 01494 vloc.phys_col_offset = 0; 01495 if (vloc.phys_col_offset >= vcell->cellblock->num_cols) 01496 vloc.phys_col_offset = vcell->cellblock->num_cols - 1; 01497 01498 left = vloc.phys_col_offset - 1; 01499 right = vloc.phys_col_offset + 1; 01500 01501 while (left >= 0 || right < vcell->cellblock->num_cols) 01502 { 01503 vloc.phys_col_offset = right; 01504 if (gnc_table_virtual_loc_valid(table, vloc, FALSE)) 01505 { 01506 *virt_loc = vloc; 01507 return TRUE; 01508 } 01509 01510 vloc.phys_col_offset = left; 01511 if (gnc_table_virtual_loc_valid(table, vloc, FALSE)) 01512 { 01513 *virt_loc = vloc; 01514 return TRUE; 01515 } 01516 01517 left--; 01518 right++; 01519 } 01520 01521 return FALSE; 01522 } 01523 01524 gboolean 01525 gnc_table_find_close_valid_cell (Table *table, VirtualLocation *virt_loc, 01526 gboolean exact_pointer) 01527 { 01528 if (!gnc_table_find_valid_row_vert (table, virt_loc)) 01529 return FALSE; 01530 01531 return gnc_table_find_valid_cell_horiz (table, virt_loc, exact_pointer); 01532 } 01533 01534 void 01535 gnc_table_refresh_cursor_gui (Table * table, 01536 VirtualCellLocation vcell_loc, 01537 gboolean do_scroll) 01538 { 01539 g_return_if_fail (table != NULL); 01540 g_return_if_fail (table->gui_handlers.cursor_refresh != NULL); 01541 01542 table->gui_handlers.cursor_refresh (table, vcell_loc, do_scroll); 01543 } 01544 01545 gboolean 01546 gnc_table_move_tab (Table *table, 01547 VirtualLocation *virt_loc, 01548 gboolean move_right) 01549 { 01550 VirtualCell *vcell; 01551 VirtualLocation vloc; 01552 BasicCell *cell; 01553 01554 if ((table == NULL) || (virt_loc == NULL)) 01555 return FALSE; 01556 01557 vloc = *virt_loc; 01558 01559 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01560 if ((vcell == NULL) || (vcell->cellblock == NULL) || !vcell->visible) 01561 return FALSE; 01562 01563 while (1) 01564 { 01565 CellIOFlags io_flags; 01566 01567 if (move_right) 01568 { 01569 vloc.phys_col_offset++; 01570 01571 if (vloc.phys_col_offset >= vcell->cellblock->num_cols) 01572 { 01573 if (!gnc_table_move_vertical_position (table, &vloc, 1)) 01574 return FALSE; 01575 01576 vloc.phys_col_offset = 0; 01577 } 01578 } 01579 else 01580 { 01581 vloc.phys_col_offset--; 01582 01583 if (vloc.phys_col_offset < 0) 01584 { 01585 if (!gnc_table_move_vertical_position (table, &vloc, -1)) 01586 return FALSE; 01587 01588 vloc.phys_col_offset = vcell->cellblock->num_cols - 1; 01589 } 01590 } 01591 01592 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01593 if ((vcell == NULL) || (vcell->cellblock == NULL) || !vcell->visible) 01594 return FALSE; 01595 01596 cell = gnc_cellblock_get_cell (vcell->cellblock, 01597 vloc.phys_row_offset, 01598 vloc.phys_col_offset); 01599 if (!cell) 01600 continue; 01601 01602 io_flags = gnc_table_get_io_flags (table, vloc); 01603 01604 if (!(io_flags & XACC_CELL_ALLOW_INPUT)) 01605 continue; 01606 01607 if (io_flags & XACC_CELL_ALLOW_EXACT_ONLY) 01608 continue; 01609 01610 break; 01611 } 01612 01613 { 01614 gboolean changed = !virt_loc_equal (vloc, *virt_loc); 01615 01616 *virt_loc = vloc; 01617 01618 return changed; 01619 } 01620 } 01621 01622 gboolean 01623 gnc_table_move_vertical_position (Table *table, 01624 VirtualLocation *virt_loc, 01625 int phys_row_offset) 01626 { 01627 VirtualLocation vloc; 01628 VirtualCell *vcell; 01629 gint last_visible_row; 01630 01631 if ((table == NULL) || (virt_loc == NULL)) 01632 return FALSE; 01633 01634 vloc = *virt_loc; 01635 last_visible_row = vloc.vcell_loc.virt_row; 01636 01637 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01638 if ((vcell == NULL) || (vcell->cellblock == NULL)) 01639 return FALSE; 01640 01641 while (phys_row_offset != 0) 01642 { 01643 /* going up */ 01644 if (phys_row_offset < 0) 01645 { 01646 phys_row_offset++; 01647 01648 /* room left in the current cursor */ 01649 if (vloc.phys_row_offset > 0) 01650 { 01651 vloc.phys_row_offset--; 01652 continue; 01653 } 01654 01655 /* end of the line */ 01656 if (vloc.vcell_loc.virt_row == 1) 01657 break; 01658 01659 do 01660 { 01661 vloc.vcell_loc.virt_row--; 01662 01663 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01664 } 01665 while (vcell && vcell->cellblock && !vcell->visible); 01666 01667 if (!vcell || !vcell->cellblock) 01668 break; 01669 01670 last_visible_row = vloc.vcell_loc.virt_row; 01671 vloc.phys_row_offset = vcell->cellblock->num_rows - 1; 01672 } 01673 /* going down */ 01674 else 01675 { 01676 phys_row_offset--; 01677 01678 /* room left in the current cursor */ 01679 if (vloc.phys_row_offset < (vcell->cellblock->num_rows - 1)) 01680 { 01681 vloc.phys_row_offset++; 01682 continue; 01683 } 01684 01685 /* end of the line */ 01686 if (vloc.vcell_loc.virt_row == (table->num_virt_rows - 1)) 01687 break; 01688 01689 do 01690 { 01691 vloc.vcell_loc.virt_row++; 01692 01693 vcell = gnc_table_get_virtual_cell (table, vloc.vcell_loc); 01694 } 01695 while (vcell && vcell->cellblock && !vcell->visible); 01696 01697 if (!vcell || !vcell->cellblock) 01698 break; 01699 01700 last_visible_row = vloc.vcell_loc.virt_row; 01701 vloc.phys_row_offset = 0; 01702 } 01703 } 01704 01705 vloc.vcell_loc.virt_row = last_visible_row; 01706 01707 { 01708 gboolean changed = !virt_loc_equal (vloc, *virt_loc); 01709 01710 *virt_loc = vloc; 01711 01712 return changed; 01713 } 01714 } 01715 01716 gboolean 01717 gnc_table_traverse_update(Table *table, 01718 VirtualLocation virt_loc, 01719 gncTableTraversalDir dir, 01720 VirtualLocation *dest_loc) 01721 { 01722 CellBlock *cb; 01723 gboolean abort_move; 01724 01725 if ((table == NULL) || (dest_loc == NULL)) 01726 return FALSE; 01727 01728 cb = table->current_cursor; 01729 01730 ENTER("proposed (%d %d) -> (%d %d)\n", 01731 virt_loc.vcell_loc.virt_row, virt_loc.vcell_loc.virt_row, 01732 dest_loc->vcell_loc.virt_row, dest_loc->vcell_loc.virt_col); 01733 01734 /* first, make sure our destination cell is valid. If it is out 01735 * of bounds report an error. I don't think this ever happens. */ 01736 if (gnc_table_virtual_cell_out_of_bounds (table, dest_loc->vcell_loc)) 01737 { 01738 PERR("destination (%d, %d) out of bounds (%d, %d)\n", 01739 dest_loc->vcell_loc.virt_row, dest_loc->vcell_loc.virt_col, 01740 table->num_virt_rows, table->num_virt_cols); 01741 LEAVE(""); 01742 return TRUE; 01743 } 01744 01745 /* next, check the current row and column. If they are out of bounds 01746 * we can recover by treating the traversal as a mouse point. This can 01747 * occur whenever the register widget is resized smaller, maybe?. */ 01748 if (!gnc_table_virtual_loc_valid (table, virt_loc, TRUE)) 01749 { 01750 PINFO("source (%d, %d) out of bounds (%d, %d)\n", 01751 virt_loc.vcell_loc.virt_row, virt_loc.vcell_loc.virt_col, 01752 table->num_virt_rows, table->num_virt_cols); 01753 01754 dir = GNC_TABLE_TRAVERSE_POINTER; 01755 } 01756 01757 /* process forward-moving traversals */ 01758 switch (dir) 01759 { 01760 case GNC_TABLE_TRAVERSE_RIGHT: 01761 case GNC_TABLE_TRAVERSE_LEFT: 01762 gnc_table_find_valid_cell_horiz(table, dest_loc, FALSE); 01763 01764 break; 01765 01766 case GNC_TABLE_TRAVERSE_UP: 01767 case GNC_TABLE_TRAVERSE_DOWN: 01768 { 01769 VirtualLocation new_loc = *dest_loc; 01770 int increment; 01771 01772 /* Keep going in the specified direction until we find a valid 01773 * row to land on, or we hit the end of the table. At the end, 01774 * turn around and go back until we find a valid row or we get 01775 * to where we started. If we still can't find anything, try 01776 * going left and right. */ 01777 increment = (dir == GNC_TABLE_TRAVERSE_DOWN) ? 1 : -1; 01778 01779 while (!gnc_table_virtual_loc_valid(table, new_loc, FALSE)) 01780 { 01781 if (virt_loc_equal (new_loc, virt_loc)) 01782 { 01783 new_loc = *dest_loc; 01784 gnc_table_find_valid_cell_horiz(table, &new_loc, FALSE); 01785 break; 01786 } 01787 01788 if (!gnc_table_move_vertical_position (table, &new_loc, increment)) 01789 { 01790 increment *= -1; 01791 new_loc = *dest_loc; 01792 } 01793 } 01794 01795 *dest_loc = new_loc; 01796 } 01797 01798 if (!gnc_table_virtual_loc_valid(table, *dest_loc, FALSE)) 01799 { 01800 LEAVE(""); 01801 return TRUE; 01802 } 01803 01804 break; 01805 01806 case GNC_TABLE_TRAVERSE_POINTER: 01807 if (!gnc_table_find_valid_cell_horiz(table, dest_loc, TRUE)) 01808 { 01809 LEAVE(""); 01810 return TRUE; 01811 } 01812 01813 break; 01814 01815 default: 01816 g_return_val_if_fail (FALSE, TRUE); 01817 break; 01818 } 01819 01820 /* Call the table traverse callback for any modifications. */ 01821 if (table->control->traverse) 01822 abort_move = table->control->traverse (dest_loc, dir, 01823 table->control->user_data); 01824 else 01825 abort_move = FALSE; 01826 01827 LEAVE("dest_row = %d, dest_col = %d\n", 01828 dest_loc->vcell_loc.virt_row, dest_loc->vcell_loc.virt_col); 01829 01830 return abort_move; 01831 }
1.7.4