GnuCash 2.4.99
split-register-util.c
00001 /********************************************************************\
00002  * split-register-util.c -- split register utilities                *
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 #include "config.h"
00024 
00025 #include <glib.h>
00026 
00027 #include "pricecell.h"
00028 #include "split-register-p.h"
00029 
00030 
00031 static QofLogModule log_module = GNC_MOD_LEDGER;
00032 
00033 
00034 /* The routines below create, access, and destroy the SRInfo structure
00035  * used by SplitLedger routines to store data for a particular register.
00036  * This is the only code that should access the user_data member of a
00037  * SplitRegister directly. If additional user data is needed, just add
00038  * it to the SRInfo structure above. */
00039 static void
00040 gnc_split_register_init_info (SplitRegister *reg)
00041 {
00042     SRInfo *info;
00043 
00044     if (reg == NULL)
00045         return;
00046 
00047     info = g_new0 (SRInfo, 1);
00048 
00049     info->blank_split_guid = *guid_null ();
00050     info->pending_trans_guid = *guid_null ();
00051     info->default_account = *guid_null ();
00052     info->template_account = *guid_null ();
00053 
00054     info->last_date_entered = gnc_timet_get_today_start ();
00055 
00056     info->first_pass = TRUE;
00057     info->full_refresh = TRUE;
00058     info->separator_changed = TRUE;
00059 
00060     reg->sr_info = info;
00061 }
00062 
00063 SRInfo *
00064 gnc_split_register_get_info (SplitRegister *reg)
00065 {
00066     if (!reg)
00067         return NULL;
00068 
00069     if (reg->sr_info == NULL)
00070         gnc_split_register_init_info (reg);
00071 
00072     return reg->sr_info;
00073 }
00074 
00075 GtkWidget *
00076 gnc_split_register_get_parent (SplitRegister *reg)
00077 {
00078     SRInfo *info = gnc_split_register_get_info (reg);
00079 
00080     if (reg == NULL)
00081         return NULL;
00082 
00083     if (info->get_parent == NULL)
00084         return NULL;
00085 
00086     return info->get_parent (info->user_data);
00087 }
00088 
00089 Split *
00090 gnc_split_register_get_split (SplitRegister *reg,
00091                               VirtualCellLocation vcell_loc)
00092 {
00093     GncGUID *guid;
00094 
00095     if (reg == NULL)
00096         return NULL;
00097 
00098     guid = gnc_table_get_vcell_data (reg->table, vcell_loc);
00099     if (guid == NULL)
00100         return NULL;
00101 
00102     return xaccSplitLookup (guid, gnc_get_current_book ());
00103 }
00104 
00105 Account *
00106 gnc_split_register_get_default_account (SplitRegister *reg)
00107 {
00108     SRInfo *info = gnc_split_register_get_info (reg);
00109 
00110     return xaccAccountLookup (&info->default_account,
00111                               gnc_get_current_book ());
00112 }
00113 
00114 void
00115 gnc_split_register_set_template_account (SplitRegister *reg,
00116         Account *template_account)
00117 {
00118     SRInfo *info = gnc_split_register_get_info (reg);
00119 
00120     g_return_if_fail (reg != NULL);
00121 
00122     info->template_account = *xaccAccountGetGUID (template_account);
00123 }
00124 
00125 Transaction *
00126 gnc_split_register_get_trans (SplitRegister *reg,
00127                               VirtualCellLocation vcell_loc)
00128 {
00129     Split *split;
00130 
00131     if (!reg || !reg->table)
00132         return NULL;
00133 
00134     split = gnc_split_register_get_split (reg, vcell_loc);
00135 
00136     if (split != NULL)
00137         return xaccSplitGetParent(split);
00138 
00139     /* Split is blank. Assume it is the blank split of a multi-line
00140      * transaction. Go back one row to find a split in the transaction. */
00141     vcell_loc.virt_row--;
00142 
00143     split = gnc_split_register_get_split (reg, vcell_loc);
00144 
00145     /* This split could be NULL during register initialization. */
00146     if (split == NULL)
00147         return NULL;
00148 
00149     return xaccSplitGetParent(split);
00150 }
00151 
00152 Split *
00153 gnc_split_register_get_trans_split (SplitRegister *reg,
00154                                     VirtualCellLocation vcell_loc,
00155                                     VirtualCellLocation *trans_split_loc)
00156 {
00157     CursorClass cursor_class;
00158 
00159     if (reg == NULL)
00160         return NULL;
00161 
00162     while (TRUE)
00163     {
00164         if ((0 > vcell_loc.virt_row) || (0 > vcell_loc.virt_col))
00165         {
00166             PERR ("bad row \n");
00167             return NULL;
00168         }
00169 
00170         cursor_class = gnc_split_register_get_cursor_class (reg, vcell_loc);
00171 
00172         if (cursor_class == CURSOR_CLASS_TRANS)
00173         {
00174             if (trans_split_loc)
00175                 *trans_split_loc = vcell_loc;
00176 
00177             return gnc_split_register_get_split (reg, vcell_loc);
00178         }
00179 
00180         vcell_loc.virt_row--;
00181     }
00182 }
00183 
00184 Split *
00185 gnc_split_register_get_current_trans_split(
00186     SplitRegister *reg, VirtualCellLocation *trans_split_loc)
00187 {
00188     VirtualCellLocation vcell_loc;
00189 
00190     if (reg == NULL)
00191         return NULL;
00192 
00193     vcell_loc = reg->table->current_cursor_loc.vcell_loc;
00194 
00195     return gnc_split_register_get_trans_split (reg, vcell_loc, trans_split_loc);
00196 }
00197 
00198 gboolean
00199 gnc_split_register_find_split (SplitRegister *reg,
00200                                Transaction *trans, Split *trans_split,
00201                                Split *split, CursorClass find_class,
00202                                VirtualCellLocation *vcell_loc)
00203 {
00204     Table *table = reg->table;
00205     gboolean found_trans = FALSE;
00206     gboolean found_trans_split = FALSE;
00207     gboolean found_something = FALSE;
00208     CursorClass cursor_class;
00209     int v_row, v_col;
00210     Transaction *t;
00211     Split *s;
00212 
00213     for (v_row = 1; v_row < table->num_virt_rows; v_row++)
00214         for (v_col = 0; v_col < table->num_virt_cols; v_col++)
00215         {
00216             VirtualCellLocation vc_loc = { v_row, v_col };
00217 
00218             s = gnc_split_register_get_split (reg, vc_loc);
00219             t = xaccSplitGetParent(s);
00220 
00221             cursor_class = gnc_split_register_get_cursor_class (reg, vc_loc);
00222 
00223             if (t == trans)
00224             {
00225                 /* A register entry for the correct transaction. */
00226                 found_trans = TRUE;
00227 
00228                 if (cursor_class == CURSOR_CLASS_TRANS)
00229                 {
00230                     /* This row is the transaction split for this transaction. */
00231                     if (s == trans_split)
00232                         /* It's the copy of the transaction that we want. */
00233                         found_trans_split = TRUE;
00234                     else
00235                         found_trans_split = FALSE;
00236 
00237                     if (find_class == CURSOR_CLASS_TRANS &&
00238                             (s == split || reg->style == REG_STYLE_JOURNAL))
00239                     {
00240                         /* We're looking for a transaction split and this is the split we're looking for
00241                            or there is only one entry for this transaction in this register (since it's
00242                            a journal style register) so we must return the only transaction split there is. */
00243                         if (vcell_loc != NULL)
00244                             *vcell_loc = vc_loc;
00245                         return TRUE;
00246                     }
00247                 }
00248             }
00249             else
00250             {
00251                 /* Not the correct transaction.  We shouldn't get here if these are true, but just
00252                    to be safe reset them. */
00253                 found_trans = FALSE;
00254                 found_trans_split = FALSE;
00255             }
00256 
00257             if (found_trans && (s == split) && s)
00258             {
00259                 /* We're on the right transaction, but perhaps not the copy of it we want, and
00260                    this is the correct split, return it if we don't find anything better. */
00261                 if (vcell_loc != NULL)
00262                     *vcell_loc = vc_loc;
00263 
00264                 found_something = TRUE;
00265             }
00266 
00267             if (found_trans_split && (s == split))
00268             {
00269                 /* We're on the right copy of the right transaction, and this is the split we
00270                    want, return it (it should be the right class since if we wanted a transaction
00271                    split we would have returned it above. */
00272                 if (vcell_loc != NULL)
00273                     *vcell_loc = vc_loc;
00274 
00275                 if (cursor_class == find_class)
00276                     return TRUE;
00277             }
00278         }
00279 
00280     return found_something;
00281 }
00282 
00283 void
00284 gnc_split_register_show_trans (SplitRegister *reg,
00285                                VirtualCellLocation start_loc)
00286 {
00287     VirtualCellLocation end_loc;
00288     int v_row;
00289 
00290     end_loc = start_loc;
00291 
00292     for (v_row = end_loc.virt_row + 1;
00293             v_row < reg->table->num_virt_rows; v_row++)
00294     {
00295         VirtualCellLocation vc_loc = { v_row, 0 };
00296         CursorClass cursor_class;
00297 
00298         cursor_class = gnc_split_register_get_cursor_class (reg, vc_loc);
00299         if (cursor_class == CURSOR_CLASS_TRANS)
00300             break;
00301 
00302         if (cursor_class != CURSOR_CLASS_SPLIT)
00303         {
00304             v_row--;
00305             break;
00306         }
00307     }
00308 
00309     end_loc.virt_row = MIN (v_row, reg->table->num_virt_rows - 1);
00310 
00311     gnc_table_show_range (reg->table, start_loc, end_loc);
00312 }
00313 
00314 void
00315 gnc_split_register_set_trans_visible (SplitRegister *reg,
00316                                       VirtualCellLocation vcell_loc,
00317                                       gboolean visible,
00318                                       gboolean only_blank_split)
00319 {
00320     CursorClass cursor_class;
00321 
00322     while (TRUE)
00323     {
00324         vcell_loc.virt_row++;
00325 
00326         cursor_class = gnc_split_register_get_cursor_class (reg, vcell_loc);
00327         if (cursor_class != CURSOR_CLASS_SPLIT)
00328             return;
00329 
00330         if (only_blank_split && gnc_split_register_get_split (reg, vcell_loc))
00331             continue;
00332 
00333         gnc_table_set_virt_cell_visible (reg->table, vcell_loc, visible);
00334     }
00335 }
00336 
00337 void
00338 gnc_split_register_set_cell_fractions (SplitRegister *reg, Split *split)
00339 {
00340     Account *account;
00341     Transaction *trans;
00342     gnc_commodity *currency;
00343     PriceCell *cell;
00344     int fraction;
00345 
00346     trans = xaccSplitGetParent (split);
00347     currency = xaccTransGetCurrency (trans);
00348     if (!currency)
00349         currency = gnc_default_currency ();
00350 
00351     fraction = gnc_commodity_get_fraction (currency);
00352 
00353     cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
00354             DEBT_CELL);
00355     gnc_price_cell_set_fraction (cell, fraction);
00356 
00357     cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
00358             CRED_CELL);
00359     gnc_price_cell_set_fraction (cell, fraction);
00360 
00361     account = xaccSplitGetAccount (split);
00362 
00363     cell = (PriceCell *) gnc_table_layout_get_cell (reg->table->layout,
00364             SHRS_CELL);
00365 
00366     if (account)
00367         gnc_price_cell_set_fraction (cell, xaccAccountGetCommoditySCU (account));
00368     else
00369         gnc_price_cell_set_fraction (cell, 1000000);
00370 }
00371 
00372 CellBlock *
00373 gnc_split_register_get_passive_cursor (SplitRegister *reg)
00374 {
00375     const char *cursor_name = NULL;
00376 
00377     switch (reg->style)
00378     {
00379     case REG_STYLE_LEDGER:
00380     case REG_STYLE_AUTO_LEDGER:
00381         cursor_name = reg->use_double_line ?
00382                       CURSOR_DOUBLE_LEDGER : CURSOR_SINGLE_LEDGER;
00383         break;
00384 
00385     case REG_STYLE_JOURNAL:
00386         cursor_name = reg->use_double_line ?
00387                       CURSOR_DOUBLE_JOURNAL : CURSOR_SINGLE_JOURNAL;
00388         break;
00389     }
00390 
00391     if (!cursor_name)
00392     {
00393         PWARN ("bad register style");
00394         return NULL;
00395     }
00396 
00397     return gnc_table_layout_get_cursor (reg->table->layout, cursor_name);
00398 }
00399 
00400 CellBlock *
00401 gnc_split_register_get_active_cursor (SplitRegister *reg)
00402 {
00403     SRInfo *info = gnc_split_register_get_info (reg);
00404     const char *cursor_name = NULL;
00405 
00406     switch (reg->style)
00407     {
00408     case REG_STYLE_LEDGER:
00409         if (!info->trans_expanded)
00410         {
00411             cursor_name = reg->use_double_line ?
00412                           CURSOR_DOUBLE_LEDGER : CURSOR_SINGLE_LEDGER;
00413             break;
00414         }
00415 
00416         /* fall through */
00417     case REG_STYLE_AUTO_LEDGER:
00418     case REG_STYLE_JOURNAL:
00419         cursor_name = reg->use_double_line ?
00420                       CURSOR_DOUBLE_JOURNAL : CURSOR_SINGLE_JOURNAL;
00421         break;
00422     }
00423 
00424     if (!cursor_name)
00425     {
00426         PWARN ("bad register style");
00427         return NULL;
00428     }
00429 
00430     return gnc_table_layout_get_cursor (reg->table->layout, cursor_name);
00431 }
00432 
00433 void
00434 gnc_split_register_set_last_num (SplitRegister *reg, const char *num)
00435 {
00436     Account *account;
00437 
00438     account = gnc_split_register_get_default_account (reg);
00439     if (!account)
00440         return;
00441 
00442     xaccAccountSetLastNum (account, num);
00443 }
00444 
00445 static CursorClass
00446 gnc_split_register_cursor_class (SplitRegister *reg,
00447                                  CellBlock *cursor)
00448 {
00449     if (cursor == NULL)
00450         return CURSOR_CLASS_NONE;
00451 
00452     return gnc_split_register_cursor_name_to_class (cursor->cursor_name);
00453 }
00454 
00455 CursorClass
00456 gnc_split_register_get_cursor_class (SplitRegister *reg,
00457                                      VirtualCellLocation vcell_loc)
00458 {
00459     VirtualCell *vcell;
00460     Table *table;
00461 
00462     if (reg == NULL)
00463         return CURSOR_CLASS_NONE;
00464 
00465     table = reg->table;
00466     if (table == NULL)
00467         return CURSOR_CLASS_NONE;
00468 
00469     vcell = gnc_table_get_virtual_cell (table, vcell_loc);
00470     if (vcell == NULL)
00471         return CURSOR_CLASS_NONE;
00472 
00473     return gnc_split_register_cursor_class (reg, vcell->cellblock);
00474 }
00475 
00476 CursorClass
00477 gnc_split_register_get_current_cursor_class (SplitRegister *reg)
00478 {
00479     Table *table;
00480 
00481     if (reg == NULL)
00482         return CURSOR_CLASS_NONE;
00483 
00484     table = reg->table;
00485     if (table == NULL)
00486         return CURSOR_CLASS_NONE;
00487 
00488     return gnc_split_register_cursor_class (reg, table->current_cursor);
00489 }
00490 
00491 CursorClass
00492 gnc_split_register_cursor_name_to_class (const char *cursor_name)
00493 {
00494     if (cursor_name == NULL)
00495         return CURSOR_CLASS_NONE;
00496 
00497     if (strcmp (cursor_name, CURSOR_SINGLE_LEDGER) == 0  ||
00498             strcmp (cursor_name, CURSOR_DOUBLE_LEDGER) == 0  ||
00499             strcmp (cursor_name, CURSOR_SINGLE_JOURNAL) == 0 ||
00500             strcmp (cursor_name, CURSOR_DOUBLE_JOURNAL) == 0)
00501         return CURSOR_CLASS_TRANS;
00502 
00503     if (strcmp (cursor_name, CURSOR_SPLIT) == 0)
00504         return CURSOR_CLASS_SPLIT;
00505 
00506     return CURSOR_CLASS_NONE;
00507 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines