static void set_value_combo_cell(BasicCell *cell, const char *new_value) { if (!cell || !new_value) return; if (safe_strcmp (new_value, gnc_basic_cell_get_value (cell)) == 0) return; gnc_combo_cell_set_value ((ComboCell *) cell, new_value); gnc_basic_cell_set_changed (cell, TRUE); }
static void set_value_price_cell(BasicCell *cell, gnc_numeric new_value) { PriceCell *pcell = (PriceCell*) cell; if (!cell) return; if (gnc_numeric_equal (new_value, gnc_price_cell_get_value(pcell))) return; gnc_price_cell_set_value (pcell, new_value); gnc_basic_cell_set_changed (cell, TRUE); }
void gnc_cellblock_clear_changes (CellBlock *cursor) { int r, c; if (!cursor) return; for (r = 0; r < cursor->num_rows; r++) for (c = 0; c < cursor->num_cols; c++) { BasicCell *cell; cell = gnc_cellblock_get_cell (cursor, r, c); if (cell == NULL) continue; gnc_basic_cell_set_changed (cell, FALSE); gnc_basic_cell_set_conditionally_changed (cell, FALSE); } }
static gboolean gnc_entry_ledger_traverse (VirtualLocation *p_new_virt_loc, gncTableTraversalDir dir, gpointer user_data) { GncEntryLedger *ledger = user_data; GncEntry *entry, *new_entry; gint response; VirtualLocation virt_loc; int changed; char const *cell_name; gboolean exact_traversal; if (!ledger) return FALSE; exact_traversal = (dir == GNC_TABLE_TRAVERSE_POINTER); entry = gnc_entry_ledger_get_current_entry (ledger); if (!entry) return FALSE; /* no changes, make sure we aren't going off the end */ changed = gnc_table_current_cursor_changed (ledger->table, FALSE); if (!changed) return FALSE; virt_loc = *p_new_virt_loc; cell_name = gnc_table_get_current_cell_name (ledger->table); /* See if we are leaving the account field */ do { ComboCell *cell; char *name; char *cell_name = NULL; switch (ledger->type) { case GNCENTRY_INVOICE_ENTRY: case GNCENTRY_INVOICE_VIEWER: case GNCENTRY_CUST_CREDIT_NOTE_ENTRY: case GNCENTRY_CUST_CREDIT_NOTE_VIEWER: cell_name = ENTRY_IACCT_CELL; break; case GNCENTRY_BILL_ENTRY: case GNCENTRY_BILL_VIEWER: case GNCENTRY_EXPVOUCHER_ENTRY: case GNCENTRY_EXPVOUCHER_VIEWER: case GNCENTRY_VEND_CREDIT_NOTE_ENTRY: case GNCENTRY_VEND_CREDIT_NOTE_VIEWER: case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY: case GNCENTRY_EMPL_CREDIT_NOTE_VIEWER: cell_name = ENTRY_BACCT_CELL; break; default: g_warning ("Unhandled ledger type"); break; } if (!cell_name) break; if (!gnc_cell_name_equal (cell_name, cell_name)) break; if (!gnc_table_layout_get_cell_changed (ledger->table->layout, cell_name, FALSE)) break; cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout, cell_name); if (!cell) break; name = cell->cell.value; if (!name || *name == '\0') break; /* Create the account if necessary. Also checks for a placeholder */ if (!gnc_entry_ledger_get_account_by_name (ledger, (BasicCell *) cell, cell->cell.value, &ledger->full_refresh)) return TRUE; } while (FALSE); /* See if we are leaving the TaxTable field */ do { ComboCell *cell; GncTaxTable *table; char *name; if (!gnc_cell_name_equal (cell_name, ENTRY_TAXTABLE_CELL)) break; if (!gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_TAXTABLE_CELL, FALSE)) break; cell = (ComboCell *) gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL); if (!cell) break; name = cell->cell.value; if (!name || *name == '\0') break; table = gncTaxTableLookupByName (ledger->book, cell->cell.value); if (table) break; { const char *format = _("The tax table %s does not exist. " "Would you like to create it?"); if (!gnc_verify_dialog (ledger->parent, TRUE, format, name)) break; } ledger->full_refresh = FALSE; table = gnc_ui_tax_table_new_from_name (ledger->book, name); if (!table) break; ledger->full_refresh = TRUE; name = (char *)gncTaxTableGetName (table); gnc_combo_cell_set_value (cell, name); gnc_basic_cell_set_changed (&cell->cell, TRUE); } while (FALSE); /* See if we are tabbing off the end of the very last line * (i.e. the blank entry) */ do { VirtualLocation virt_loc; if (!changed && !ledger->blank_entry_edited) break; if (dir != GNC_TABLE_TRAVERSE_RIGHT) break; virt_loc = ledger->table->current_cursor_loc; if (gnc_table_move_vertical_position (ledger->table, &virt_loc, 1)) break; virt_loc = ledger->table->current_cursor_loc; if (gnc_table_move_tab (ledger->table, &virt_loc, TRUE)) break; *p_new_virt_loc = ledger->table->current_cursor_loc; /* Yep, we're trying to leave the blank entry -- make sure * we are allowed to do so by verifying the current cursor. * If the current cursor is ok, then move on! */ /* Verify that the cursor is ok. If we can't save the cell, don't move! */ if (!gnc_entry_ledger_verify_can_save (ledger)) { return TRUE; } (p_new_virt_loc->vcell_loc.virt_row)++; p_new_virt_loc->phys_row_offset = 0; p_new_virt_loc->phys_col_offset = 0; ledger->traverse_to_new = TRUE; /* If we're here, we're tabbing off the end of the 'blank entry' */ return FALSE; } while (FALSE); /* Now see if we are changing cursors. If not, we may be able to * auto-complete. */ if (!gnc_table_virtual_cell_out_of_bounds (ledger->table, virt_loc.vcell_loc)) { if (gnc_entry_ledger_auto_completion (ledger, dir, p_new_virt_loc)) return FALSE; } /* Check for going off the end */ gnc_table_find_close_valid_cell (ledger->table, &virt_loc, exact_traversal); /* Same entry, no problem -- we're just moving backwards in the cursor */ new_entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc); if (entry == new_entry) { *p_new_virt_loc = virt_loc; return FALSE; } /* If we are here, then we are trying to leave the cursor. Make sure * the cursor we are leaving is valid. If so, ask the user if the * changes should be recorded. If not, don't go anywhere. */ /* Verify this cursor -- if it's not valid, don't let them move on */ if (!gnc_entry_ledger_verify_can_save (ledger)) { *p_new_virt_loc = ledger->table->current_cursor_loc; return TRUE; } /* * XXX GNCENTRY_INVOICE_EDIT processing to be added: * 1) check if the qty field changed. * 2) if so, check if this entry is part of an order. * 3) if so, ask if they want to change the entry or * split the entry into two parts. */ /* Ok, we are changing lines and the current entry has * changed. We only ask them what they want to do in * limited cases -- usually just let the change go through. */ { GtkWidget *dialog; const char *title = _("Save the current entry?"); const char *message = _("The current entry has been changed. However, this entry is " "part of an existing order. Would you like to record the change " "and effectively change your order?"); switch (ledger->type) { case GNCENTRY_INVOICE_ENTRY: case GNCENTRY_CUST_CREDIT_NOTE_ENTRY: if (gncEntryGetOrder (entry) != NULL) { dialog = gtk_message_dialog_new(GTK_WINDOW(ledger->parent), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE, "%s", title); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", message); gtk_dialog_add_buttons(GTK_DIALOG(dialog), _("_Don't Record"), GTK_RESPONSE_REJECT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, _("_Record"), GTK_RESPONSE_ACCEPT, NULL); response = gnc_dialog_run(GTK_DIALOG(dialog), "invoice_entry_changed"); gtk_widget_destroy(dialog); break; } /* FALL THROUGH */ default: response = GTK_RESPONSE_ACCEPT; break; } } switch (response) { case GTK_RESPONSE_ACCEPT: break; case GTK_RESPONSE_REJECT: { VirtualCellLocation vcell_loc; GncEntry *new_entry; new_entry = gnc_entry_ledger_get_entry (ledger, virt_loc.vcell_loc); gnc_entry_ledger_cancel_cursor_changes (ledger); if (gnc_entry_ledger_find_entry (ledger, new_entry, &vcell_loc)) virt_loc.vcell_loc = vcell_loc; gnc_table_find_close_valid_cell (ledger->table, &virt_loc, exact_traversal); *p_new_virt_loc = virt_loc; } break; case GTK_RESPONSE_CANCEL: default: return TRUE; } return FALSE; }
static gboolean gnc_entry_ledger_auto_completion (GncEntryLedger *ledger, gncTableTraversalDir dir, VirtualLocation *p_new_virt_loc) { GncEntry *entry; GncEntry *blank_entry; GncEntry *auto_entry; const char* cell_name; const char *desc; BasicCell *cell = NULL; char *account_name = NULL; char *new_value = NULL; g_assert(ledger); g_assert(ledger->table); blank_entry = gnc_entry_ledger_get_blank_entry (ledger); /* auto-completion is only triggered by a tab out */ if (dir != GNC_TABLE_TRAVERSE_RIGHT) return FALSE; entry = gnc_entry_ledger_get_current_entry (ledger); if (entry == NULL) return FALSE; cell_name = gnc_table_get_current_cell_name (ledger->table); /* Auto-completion is done only in an entry ledger */ switch (ledger->type) { case GNCENTRY_ORDER_ENTRY: case GNCENTRY_INVOICE_ENTRY: case GNCENTRY_BILL_ENTRY: case GNCENTRY_EXPVOUCHER_ENTRY: case GNCENTRY_CUST_CREDIT_NOTE_ENTRY: case GNCENTRY_VEND_CREDIT_NOTE_ENTRY: case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY: break; default: return FALSE; } /* Further conditions before we actually do auto-completion: */ /* There must be a blank entry */ if (blank_entry == NULL) return FALSE; /* we must be on the blank entry */ if (entry != blank_entry) return FALSE; /* and leaving the description cell */ if (!gnc_cell_name_equal (cell_name, ENTRY_DESC_CELL)) return FALSE; /* nothing but the date and description should be changed */ /* FIXME, this should be refactored. */ if (gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_ACTN_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_QTY_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_PRIC_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_DISC_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_DISTYPE_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_DISHOW_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_IACCT_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_BACCT_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_TAXABLE_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_TAXINCLUDED_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_TAXTABLE_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_VALUE_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_TAXVAL_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_BILLABLE_CELL, TRUE) || gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_PAYMENT_CELL, TRUE)) return FALSE; /* and the description should indeed be changed */ if (!gnc_table_layout_get_cell_changed (ledger->table->layout, ENTRY_DESC_CELL, TRUE)) return FALSE; /* to a non-empty value */ desc = gnc_table_layout_get_cell_value (ledger->table->layout, ENTRY_DESC_CELL); if ((desc == NULL) || (*desc == '\0')) return FALSE; /* Ok, we are sure we want to trigger auto-completion. Now find an * entry to copy the values from. FIXME: Currently we only use * the entries from the current invoice/bill, but it would be * better to draw this from a larger set of entries. */ auto_entry = /* Use this for book-wide auto-completion of the invoice entries */ find_entry_in_book_by_desc(ledger, desc); /* #else */ /* gnc_find_entry_in_reg_by_desc(ledger, desc); */ /* #endif */ if (auto_entry == NULL) return FALSE; /* now perform the completion */ gnc_suspend_gui_refresh (); /* Auto-complete the action field */ cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_ACTN_CELL); set_value_combo_cell (cell, gncEntryGetAction (auto_entry)); /* Auto-complete the account field */ switch (ledger->type) { case GNCENTRY_INVOICE_ENTRY: case GNCENTRY_CUST_CREDIT_NOTE_ENTRY: cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_IACCT_CELL); account_name = gnc_get_account_name_for_register (gncEntryGetInvAccount(auto_entry)); break; case GNCENTRY_EXPVOUCHER_ENTRY: case GNCENTRY_BILL_ENTRY: case GNCENTRY_VEND_CREDIT_NOTE_ENTRY: case GNCENTRY_EMPL_CREDIT_NOTE_ENTRY: cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_BACCT_CELL); account_name = gnc_get_account_name_for_register (gncEntryGetBillAccount(auto_entry)); break; case GNCENTRY_ORDER_ENTRY: default: cell = NULL; account_name = NULL; break; } set_value_combo_cell (cell, account_name); g_free (account_name); /* Auto-complete quantity cell * Note: we always autofill a positive quantity value. This allows us to * - reuse invoice entries on credit note ledgers, meaning you can credit * some invoice entry via autofill without having to manually fix the sign * on the credit note. * - autofill credit note entries on other credit note entries (without having * to juggle sign reversals internally) * - autofill credit note entries on invoice ledgers * * Disadvantage: invoice entries with explicitly set negative quantities will * be autofilled to positive quantities in later uses. But it seems less common * to me to require a negative entry again next time. */ cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_QTY_CELL); set_value_price_cell (cell, gnc_numeric_abs(gncEntryGetQuantity (auto_entry))); /* Auto-complete price cell */ { gnc_numeric price; switch (ledger->type) { case GNCENTRY_INVOICE_ENTRY: case GNCENTRY_CUST_CREDIT_NOTE_ENTRY: price = gncEntryGetInvPrice (auto_entry); break; default: price = gncEntryGetBillPrice (auto_entry); } /* Auto-complete price cell */ cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_PRIC_CELL); set_value_price_cell (cell, price); } /* We intentionally skip the discount column */ /* Taxable?, Tax-include?, Tax table */ { gboolean taxable, taxincluded; GncTaxTable *taxtable; switch (ledger->type) { case GNCENTRY_INVOICE_ENTRY: case GNCENTRY_CUST_CREDIT_NOTE_ENTRY: taxable = gncEntryGetInvTaxable (auto_entry); taxincluded = gncEntryGetInvTaxIncluded (auto_entry); taxtable = gncEntryGetInvTaxTable (auto_entry); break; default: taxable = gncEntryGetBillTaxable (auto_entry); taxincluded = gncEntryGetBillTaxIncluded (auto_entry); taxtable = gncEntryGetBillTaxTable (auto_entry); } /* Taxable? cell */ cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXABLE_CELL); gnc_checkbox_cell_set_flag ((CheckboxCell *) cell, taxable); gnc_basic_cell_set_changed (cell, TRUE); /* taxincluded? cell */ cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXINCLUDED_CELL); gnc_checkbox_cell_set_flag ((CheckboxCell *) cell, taxincluded); gnc_basic_cell_set_changed (cell, TRUE); /* Taxable? cell */ cell = gnc_table_layout_get_cell (ledger->table->layout, ENTRY_TAXTABLE_CELL); set_value_combo_cell(cell, gncTaxTableGetName (taxtable)); } gnc_resume_gui_refresh (); /* now move to the non-empty amount column unless config setting says not */ if ( !gnc_gconf_get_bool(GCONF_GENERAL_REGISTER, "tab_includes_transfer_on_memorised", NULL) ) { VirtualLocation new_virt_loc; const char *cell_name = ENTRY_QTY_CELL; if (gnc_table_get_current_cell_location (ledger->table, cell_name, &new_virt_loc)) *p_new_virt_loc = new_virt_loc; } return TRUE; }