Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqfinance / src / fox / lib / modules / accounts / fm_accstmpage.cpp @ 242027ca

History | View | Annotate | Download (50 KB)

1
/****************************************************************************
2
 * This file is part of the project AqFinance.
3
 * AqFinance (c) by 2009 Martin Preuss, all rights reserved.
4
 *
5
 * The license for this file can be found in the file COPYING which you
6
 * should have received along with this file.
7
 ****************************************************************************/
8

    
9
#ifdef HAVE_CONFIG_H
10
# include <config.h>
11
#endif
12

    
13

    
14
#include "fm_accstmpage.hpp"
15
#include "fm_accpage.hpp"
16
#include "ff_transactiontable.hpp"
17
#include "ff_app.hpp"
18
#include "ff_edittransaction.hpp"
19
#include "ff_selectjob.hpp"
20
#include "ff_editpayment.hpp"
21
#include "ff_selectaccount.hpp"
22
#include "ff_editsimpletransaction.hpp"
23

    
24
#include <gwenhywfar/debug.h>
25
#include <gwenhywfar/i18n.h>
26

    
27
#include <gwen-gui-fox16/fox16_htmllabel.hpp>
28

    
29

    
30
#define I18N(msg) GWEN_I18N_Translate(PACKAGE, msg)
31

    
32

    
33

    
34
FXDEFMAP(FM_AccountStmPage) FM_AccountStmPageMap[]= {
35
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_SPLIT_TABLE, FM_AccountStmPage::onCmdTable),
36
  FXMAPFUNC(SEL_REPLACED, FM_AccountStmPage::ID_SPLIT_TABLE, FM_AccountStmPage::onTableContentReplaced),
37
  FXMAPFUNC(SEL_RIGHTBUTTONRELEASE, FM_AccountStmPage::ID_SPLIT_TABLE, FM_AccountStmPage::onTableRightButtonRelease),
38
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_CMD_DELSPLIT, FM_AccountStmPage::onCmdDelStm),
39
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_CMD_ADDTRANS, FM_AccountStmPage::onCmdAddStm),
40

    
41
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_CMD_ASSIGN_TO_BUY_PAYMENT, FM_AccountStmPage::onCmdAssignToOutgoingPayment),
42
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_CMD_ASSIGN_TO_SELL_PAYMENT, FM_AccountStmPage::onCmdAssignToIncomingPayment),
43
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_CMD_CREATE_BUY_PAYMENT, FM_AccountStmPage::onCmdCreateOutgoingPayment),
44
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_CMD_CREATE_SELL_PAYMENT, FM_AccountStmPage::onCmdCreateIncomingPayment),
45

    
46
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_CMD_MOVE_TO_ACCOUNT, FM_AccountStmPage::onCmdMoveToAccount),
47

    
48
  FXMAPFUNC(SEL_COMMAND, FM_AccountStmPage::ID_EDIT_SPLITS, FM_AccountStmPage::onCmdSplitEditor),
49
  FXMAPFUNC(SEL_CHANGED, FM_AccountStmPage::ID_MATCHER, FM_AccountStmPage::onChgMatcher),
50
};
51

    
52

    
53

    
54
FXIMPLEMENT(FM_AccountStmPage, FF_ModTabPage, FM_AccountStmPageMap, ARRAYNUMBER(FM_AccountStmPageMap))
55

    
56

    
57

    
58
FM_AccountStmPage::FM_AccountStmPage(const FXString &pageId,
59
                                     FM_AccountPage *mainPage,
60
                                     const AE_ACCOUNT *acc,
61
                                     FXuint opts,
62
                                     FXint x, FXint y, FXint w, FXint h)
63
:FF_ModTabPage(pageId, mainPage, opts, x, y, w, h)
64
, m_mainPage(mainPage)
65
, m_accountId(AE_Account_GetId(acc))
66
, m_hLabel(NULL)
67
, m_fLabel(NULL)
68
, m_transTable(NULL)
69
, m_account(NULL)
70
, m_accountCommodity(NULL)
71
, m_needReload(true)
72
, m_isVisible(false)
73
, m_blockReload(false)
74
, m_transactions(NULL)
75
{
76
  FXVerticalFrame *vf;
77
  FXHorizontalFrame *hf;
78
  FF_App *app;
79

    
80
  flags|=FLAG_SHOWN | FLAG_ENABLED;
81

    
82
  app=dynamic_cast<FF_App *>(getApp());
83

    
84
  vf=new FXVerticalFrame(this, LAYOUT_FILL_X|LAYOUT_FILL_Y);
85
  new FXHorizontalSeparator(vf, LAYOUT_FILL_X | SEPARATOR_GROOVE);
86
  m_hLabel=new FOX16_HtmlLabel(vf, "",
87
                               LAYOUT_FILL_X | LAYOUT_MIN_HEIGHT |
88
                               FOX16_HtmlLabel::FLAGS_USE_FULL_WIDTH);
89
  m_hLabel->setMinimumWidth(150);
90
  m_hLabel->setMaxDefaultWidth(600);
91
  new FXHorizontalSeparator(vf, LAYOUT_FILL_X | SEPARATOR_GROOVE);
92

    
93
  hf=new FXHorizontalFrame(vf, LAYOUT_FILL_X);
94
  new FXLabel(hf, I18N("Filter"), NULL, LABEL_NORMAL | JUSTIFY_LEFT);
95
  m_matcher=new FXTextField(hf, 64, this, ID_MATCHER, TEXTFIELD_NORMAL);
96

    
97
  m_transTable=new FF_TransactionTable(vf, this, ID_SPLIT_TABLE,
98
                                       FXXTable::TABLE_TRACK_SCROLLBARS |
99
                                       LAYOUT_FILL_X | LAYOUT_FILL_Y|
100
                                       FRAME_SUNKEN | FRAME_THICK);
101
  if (AE_AccountType_GetGroup(AE_Account_GetType(acc))==AE_AccountGroup_Equity)
102
    m_transTable->setColorizeCounterAccounts(true);
103
  m_transTable->setShowGrid(false);
104
  m_transTable->setCellBackColor(0, 0, FXRGB(183, 220, 159));
105
  m_transTable->setCellBackColor(0, 1, FXRGB(183, 220, 159));
106
  m_transTable->setCellBackColor(1, 0, FXRGB(255, 255, 255));
107
  m_transTable->setCellBackColor(1, 1, FXRGB(255, 255, 255));
108

    
109
  m_transTable->setMinRowHeight(20);
110
  m_transTable->setAccountId(m_accountId);
111

    
112
  m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_DATE, 100);
113
  m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_MEMO, 100);
114
  m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_COUNTER_ACCOUNT, 100);
115
  if (app->getUseAccountingTerms()) {
116
    m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_DEBIT_VALUE, 100);
117
    m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_CREDIT_VALUE, 100);
118
  }
119
  else {
120
    m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_DEPOSIT_VALUE, 100);
121
    m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_WITHDRAWAL_VALUE, 100);
122
  }
123
  m_transTable->addColumn(FF_TransactionTable::COLUMN_TYPE_FLAGS, 100);
124

    
125
  new FXHorizontalSeparator(vf, LAYOUT_FILL_X | SEPARATOR_GROOVE);
126
  m_fLabel=new FOX16_HtmlLabel(vf, "", LAYOUT_FILL_X | LAYOUT_MIN_HEIGHT | FOX16_HtmlLabel::FLAGS_USE_FULL_WIDTH);
127
  m_fLabel->setMinimumWidth(150);
128
}
129

    
130

    
131

    
132
FM_AccountStmPage::FM_AccountStmPage()
133
:FF_ModTabPage()
134
, m_accountId(0)
135
, m_hLabel(NULL)
136
, m_fLabel(NULL)
137
, m_transTable(NULL)
138
, m_account(NULL)
139
, m_accountCommodity(NULL)
140
{
141
}
142

    
143

    
144

    
145
FM_AccountStmPage::~FM_AccountStmPage()
146
{
147
  AE_Transaction_List_free(m_transactions);
148
  AE_Commodity_free(m_accountCommodity);
149
  AE_Account_free(m_account);
150
}
151

    
152

    
153

    
154
void FM_AccountStmPage::create()
155
{
156
  FF_ModTabPage::create();
157
  m_hLabel->create();
158
  m_transTable->create();
159
}
160

    
161

    
162

    
163

    
164
void FM_AccountStmPage::init(GWEN_DB_NODE *db)
165
{
166
  GWEN_DB_NODE *dbSplitPage;
167
  GWEN_DB_NODE *dbT=NULL;
168
  char numbuf[32];
169
  int rv;
170

    
171
  DBG_INFO(0, "Init");
172
  if (m_accountId) {
173
    FF_App *app;
174
    AE_BOOK *b;
175
    AE_ACCOUNT_TREE *at;
176

    
177
    app=dynamic_cast<FF_App *>(getApp());
178
    b=app->getBook();
179
    at=AE_Account_Tree_new();
180
    rv=AE_Book_ReadAccountTree(b, AE_Book_TableType_Account, at);
181
    if (rv>=0) {
182
      AE_ACCOUNT *a;
183

    
184
      a=AE_Account_Tree_GetById(at, m_accountId);
185
      if (a) {
186
        GWEN_BUFFER *tbuf;
187
        FXString str;
188

    
189
        tbuf=GWEN_Buffer_new(0, 256, 0, 1);
190
        AE_Account_PathToBuffer(a, tbuf);
191
        str=FXStringFormat(I18N("<h2>%s</h2>"), GWEN_Buffer_GetStart(tbuf));
192
        GWEN_Buffer_free(tbuf);
193
        m_hLabel->setText(str);
194
      }
195
    }
196
    AE_Account_Tree_free(at);
197
  }
198

    
199
  snprintf(numbuf, sizeof(numbuf)-1, "acc-%x", m_accountId);
200
  numbuf[sizeof(numbuf)-1]=0;
201
  dbSplitPage=GWEN_DB_GetGroup(db, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "splitPage");
202
  if (dbSplitPage) {
203
    dbT=GWEN_DB_GetGroup(dbSplitPage, GWEN_PATH_FLAGS_NAMEMUSTEXIST, numbuf);
204
    if (dbT==NULL)
205
      dbT=GWEN_DB_GetGroup(dbSplitPage, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "last");
206
  }
207
  if (dbT) {
208
    int i;
209
    int sortByColumn;
210
    int sortUp;
211

    
212
    sortByColumn=GWEN_DB_GetIntValue(dbT, "sortByColumn", 0, -1);
213
    sortUp=GWEN_DB_GetIntValue(dbT, "sortUp", 0, 0);
214

    
215
    for (i=0; i<m_transTable->getNumHeaders(); i++) {
216
      int j=GWEN_DB_GetIntValue(dbT, "columns", i, m_transTable->getHeaderSize(i));
217
      m_transTable->setHeaderSize(i, j);
218
      if (i==sortByColumn) {
219
        if (sortUp)
220
          m_transTable->setHeaderArrowDir(i, TRUE);
221
        else
222
          m_transTable->setHeaderArrowDir(i, FALSE);
223
      }
224
    }
225
  }
226
}
227

    
228

    
229

    
230
void FM_AccountStmPage::fini(GWEN_DB_NODE *db)
231
{
232
  GWEN_DB_NODE *dbSplitPage;
233
  GWEN_DB_NODE *dbT;
234
  GWEN_DB_NODE *dbLast;
235
  int i;
236
  char numbuf[32];
237

    
238
  DBG_INFO(0, "Fini");
239
  snprintf(numbuf, sizeof(numbuf)-1, "acc-%x", m_accountId);
240
  numbuf[sizeof(numbuf)-1]=0;
241
  dbSplitPage=GWEN_DB_GetGroup(db, GWEN_DB_FLAGS_DEFAULT, "splitPage");
242
  dbT=GWEN_DB_GetGroup(dbSplitPage, GWEN_DB_FLAGS_OVERWRITE_GROUPS, numbuf);
243

    
244
  GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS, "sortByColumn", -1);
245
  for (i=0; i<m_transTable->getNumHeaders(); i++) {
246
    FXbool b;
247

    
248
    GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_DEFAULT, "columns",
249
                        m_transTable->getHeaderSize(i));
250
    b=m_transTable->getHeaderArrowDir(i);
251
    if (b!=MAYBE) {
252
      GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS, "sortByColumn", i);
253
      if (b==TRUE)
254
        GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS, "sortUp", 1);
255
      else
256
        GWEN_DB_SetIntValue(dbT, GWEN_DB_FLAGS_OVERWRITE_VARS, "sortUp", 0);
257
    }
258
  }
259

    
260
  dbLast=GWEN_DB_GetGroup(dbSplitPage, GWEN_DB_FLAGS_OVERWRITE_GROUPS, "last");
261
  GWEN_DB_AddGroupChildren(dbLast, dbT);
262
}
263

    
264

    
265

    
266
void FM_AccountStmPage::enter()
267
{
268
  m_isVisible=true;
269

    
270
  layout();
271
  if (m_needReload) {
272
    reload();
273
    m_needReload=false;
274
  }
275
}
276

    
277

    
278

    
279
void FM_AccountStmPage::leave()
280
{
281
  m_isVisible=false;
282
}
283

    
284

    
285

    
286
void FM_AccountStmPage::dbOpened(AE_BOOK *bk)
287
{
288
  if (m_isVisible) {
289
    reload();
290
    m_needReload=false;
291
  }
292
  else
293
    m_needReload=true;
294
}
295

    
296

    
297

    
298
void FM_AccountStmPage::dbClosing()
299
{
300
  AE_Account_free(m_account);
301
  m_account=NULL;
302

    
303
  AE_Commodity_free(m_accountCommodity);
304
  m_accountCommodity=NULL;
305

    
306
  m_transTable->clearItems();
307
}
308

    
309

    
310

    
311
void FM_AccountStmPage::dbClosed()
312
{
313
}
314

    
315

    
316

    
317
void FM_AccountStmPage::dbReload(AE_BOOK_TABLE_TYPE tt)
318
{
319
  if (!m_blockReload) {
320
    if (tt==AE_Book_TableType_Split ||
321
        tt==AE_Book_TableType_Transaction ||
322
        tt==AE_Book_TableType_None) {
323
      if (m_isVisible) {
324
        reload();
325
        m_needReload=false;
326
      }
327
      else
328
        m_needReload=true;
329
    }
330
  }
331
}
332

    
333

    
334

    
335
void FM_AccountStmPage::aboutToSendJobs()
336
{
337
}
338

    
339

    
340

    
341
long FM_AccountStmPage::onCmdTable(FXObject *, FXSelector, void *ptr)
342
{
343
#if 0
344
  int r=m_transTable->getCurrentRow();
345
  if (r>=0) {
346
    AE_STATEMENT *st=m_transTable->getStatementByRow(r);
347
    AE_Statement_Dump(st, stderr, 2);
348
  }
349
#endif
350
  return 1;
351
}
352

    
353

    
354

    
355
long FM_AccountStmPage::onTableContentReplaced(FXObject *, FXSelector, void *ptr)
356
{
357
  FF_App *app;
358
  int r;
359
  AE_TRANSACTION *t;
360
  FXXTable::ColumnInfo *ci=(FXXTable::ColumnInfo *) ptr;
361

    
362
  app=dynamic_cast<FF_App *>(getApp());
363

    
364
  r=ci->getRow();
365

    
366
  t=m_transTable->getTransactionByRow(r);
367
  if (t) {
368
    bool saveBlockRebuild;
369

    
370
    if ((AE_Transaction_GetRuntimeFlags(t) & (AE_TRANSACTION_RTFLAGS_MODIFIED |
371
                                              AE_TRANSACTION_RTFLAGS_SPLITS_MODIFIED))) {
372
      int rv;
373
      AE_BOOK *b;
374
      AE_TRANSACTION *tOld=NULL;
375
      AQDB_ID tid;
376

    
377
      b=app->getBook();
378

    
379
      tid=AE_Transaction_GetId(t);
380
      if (tid!=0) {
381
        /* read original transaction */
382
        rv=AE_Book_ReadTransaction(b, AE_Book_TableType_Transaction, tid, &tOld);
383
        if (rv<0) {
384
          FXMessageBox::error(this, FX::MBOX_OK,
385
                              I18N("Database Error"),
386
                              I18N("The original transaction could not be read (error: %d)"),
387
                              rv);
388
          return 1;
389
        }
390

    
391
        rv=AE_Book_ReadTransactionSubObjects(b, tOld);
392
        if (rv<0) {
393
          FXMessageBox::error(this, FX::MBOX_OK,
394
                              I18N("Database Error"),
395
                              I18N("The original transaction could not be read (error: %d)"),
396
                              rv);
397
          AE_Transaction_free(tOld);
398
          return 1;
399
        }
400
      }
401

    
402
      /* apply transaction */
403
      rv=AE_Book_ApplyTransaction(b, t, tOld, 1);
404
      if (rv<0) {
405
        FXMessageBox::error(this, FX::MBOX_OK,
406
                            I18N("Database Error"),
407
                            I18N("Could not write transaction and splits to database (error: %d)"),
408
                            rv);
409
        AE_Transaction_free(tOld);
410
        return 1;
411
      }
412

    
413
      AE_Transaction_free(tOld);
414
    }
415
    else {
416
      DBG_ERROR(0, "Transaction not modified");
417
    }
418

    
419
    saveBlockRebuild=m_blockReload;
420
    m_blockReload=true;
421
    app->signalDbReload(AE_Book_TableType_Transaction);
422
    m_blockReload=saveBlockRebuild;
423
  }
424
  else {
425
    DBG_ERROR(0, "No transaction");
426
  }
427
  return 1;
428
}
429

    
430

    
431

    
432
long FM_AccountStmPage::onTableRightButtonRelease(FXObject *, FXSelector, void *ptr)
433
{
434
  FXEvent *event=(FXEvent *)ptr;
435

    
436
  if (!event->moved) {
437
    FXMenuPane pmenu(this);
438
    FXMenuPane paneBuy(this);
439
    FXMenuPane paneSell(this);
440
    FXMenuPane paneSelected(this);
441

    
442
    new FXMenuCommand(&pmenu, I18N("Add Transaction(s)"), NULL, this, ID_CMD_ADDTRANS);
443
    new FXMenuCommand(&pmenu, I18N("Split Editor"), NULL, this, ID_EDIT_SPLITS);
444
    new FXMenuSeparator(&pmenu);
445

    
446
    /* create submenu for incoming payment */
447
    new FXMenuCommand(&paneSell, I18N("Assign to Incoming Payment (Sell)"), NULL, this, ID_CMD_ASSIGN_TO_SELL_PAYMENT);
448
    new FXMenuCommand(&paneSell, I18N("Create Incoming Payment (Sell)"), NULL, this, ID_CMD_CREATE_SELL_PAYMENT);
449
    new FXMenuCascade(&pmenu, I18N("Handle As Incoming Payment (Sell)..."), NULL, &paneSell);
450

    
451
    /* create submenu for outgoing payment */
452
    new FXMenuCommand(&paneBuy, I18N("Assign to Outgoing Payment (Buy)"), NULL, this, ID_CMD_ASSIGN_TO_BUY_PAYMENT);
453
    new FXMenuCommand(&paneBuy, I18N("Create Outgoing Payment (Buy)"), NULL, this, ID_CMD_CREATE_BUY_PAYMENT);
454
    new FXMenuCascade(&pmenu, I18N("Handle As Outgoing Payment (Buy)..."), NULL, &paneBuy);
455

    
456
    new FXMenuSeparator(&pmenu);
457

    
458
    /* create submenu for selected transactions */
459
    new FXMenuCommand(&paneSelected, I18N("Move to Another Account"), NULL, this, ID_CMD_MOVE_TO_ACCOUNT);
460
    new FXMenuCommand(&paneSelected, I18N("Delete Transaction(s)"), NULL, this, ID_CMD_DELSPLIT);
461
    new FXMenuCascade(&pmenu, I18N("Selected Transactions..."), NULL, &paneSelected);
462

    
463
    new FXMenuSeparator(&pmenu);
464
    new FXMenuCommand(&pmenu, I18N("Back"), NULL, &pmenu, ID_UNPOST);
465

    
466
    pmenu.create();
467
    pmenu.popup(NULL, event->root_x, event->root_y);
468
    getApp()->runModalWhileShown(&pmenu);
469
  }
470

    
471
  return 1;
472
}
473

    
474

    
475

    
476
long FM_AccountStmPage::onCmdDelStm(FXObject *, FXSelector, void *ptr)
477
{
478
  AE_TRANSACTION_LIST2 *tl;
479
  FF_App *app;
480
  AE_BOOK *b;
481

    
482
  app=dynamic_cast<FF_App *>(getApp());
483
  b=app->getBook();
484

    
485
  tl=AE_Transaction_List2_new();
486
  m_transTable->getSelectedTransactions(tl, FF_TransactionTable::COPYMODE_NONE);
487
  if (AE_Transaction_List2_GetSize(tl)) {
488
    FXuint res;
489

    
490
    res=FXMessageBox::question(this, MBOX_YES_NO,
491
                               I18N("Delete Transactions"),
492
                               "%s",
493
                               I18N("Are you sure you want to delete the selected "
494
                                    "transaction(s)?"));
495
    if (res!=MBOX_CLICKED_YES) {
496
      DBG_ERROR(0, "Aborted");
497
      AE_Transaction_List2_free(tl);
498
      return 1;
499
    }
500
    else {
501
      AE_DBCONFLICT_LIST *clist;
502
      AE_TRANSACTION_LIST2_ITERATOR *it;
503
      int rv;
504

    
505
      clist=AE_DbConflict_List_new();
506

    
507
      rv=AE_Book_BeginEdit(b, 0);
508
      if (rv<0) {
509
        DBG_ERROR(0, "Error on begin edit: %d", rv);
510
        FXMessageBox::error(this, FX::MBOX_OK,
511
                            I18N("Database Error"),
512
                            I18N("Could not lock database for write access (error: %d)"),
513
                            rv);
514
        AE_Transaction_List2_free(tl);
515
        AE_DbConflict_List_free(clist);
516
        return 1;
517
      }
518

    
519
      it=AE_Transaction_List2_First(tl);
520
      if (it) {
521
        AE_TRANSACTION *t;
522

    
523
        t=AE_Transaction_List2Iterator_Data(it);
524
        while (t) {
525
          rv=AE_Book_GetConflicts(b,
526
                                  AQDB_ActionType_Remove,
527
                                  AE_Book_TableType_Transaction,
528
                                  AE_Transaction_GetId(t),
529
                                  clist);
530
          if (rv<0) {
531
            FXMessageBox::error(this, FX::MBOX_OK,
532
                                I18N("Database Error"),
533
                                I18N("Error getting conflicts for transaction %08x (error: %d)"),
534
                                AE_Transaction_GetId(t), rv);
535
            AE_Transaction_List2Iterator_free(it);
536
            AE_Transaction_List2_free(tl);
537
            AE_DbConflict_List_free(clist);
538
            return 1;
539
          }
540
          t=AE_Transaction_List2Iterator_Next(it);
541
        }
542
        AE_Transaction_List2Iterator_free(it);
543
      }
544

    
545
      /* takes over clist in any case */
546
      rv=app->presentConflictList(I18N("Data Conflicts"),
547
                                  I18N("<p>Deleting these transactions leads to the following conflicts. "
548
                                       "Please select appropriate solutions.</p>"
549
                                       "<p>Click <i>Ok</i> when finished or <i>Abort</i> to abort the whole operation.</p>"),
550
                                  clist);
551
      if (rv<0) {
552
        AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
553
        DBG_ERROR(0, "here (%d)", rv);
554
        AE_Transaction_List2_free(tl);
555
        return 1;
556
      }
557

    
558

    
559
      it=AE_Transaction_List2_First(tl);
560
      if (it) {
561
        AE_TRANSACTION *t;
562

    
563
        t=AE_Transaction_List2Iterator_Data(it);
564
        while (t) {
565
          rv=AE_Book_ApplyTransaction(b, NULL, t, 0);
566
          if (rv<0) {
567
            AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
568
            DBG_ERROR(0, "here (%d)", rv);
569
            AE_Transaction_List2Iterator_free(it);
570
            AE_Transaction_List2_free(tl);
571
            return 1;
572
          }
573

    
574
          t=AE_Transaction_List2Iterator_Next(it);
575
        }
576
        AE_Transaction_List2Iterator_free(it);
577
      }
578

    
579
      rv=AE_Book_EndEdit(b, 0);
580
      if (rv<0) {
581
        DBG_ERROR(0, "here (%d)", rv);
582
        AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
583
        FXMessageBox::error(this, FX::MBOX_OK,
584
                            I18N("Database Error"),
585
                            I18N("Could not apply changes to the database (error: %d)"),
586
                            rv);
587
        AE_Transaction_List2_free(tl);
588
        return 1;
589
      }
590
    }
591
  }
592
  AE_Transaction_List2_free(tl);
593

    
594
  app->signalDbReload(AE_Book_TableType_Transaction);
595
  app->signalDbReload(AE_Book_TableType_AccountBalance);
596

    
597
  return 1;
598
}
599

    
600

    
601

    
602
long FM_AccountStmPage::onCmdAddStm(FXObject *, FXSelector, void *ptr)
603
{
604
  FF_App *app;
605
  AE_TRANSACTION *t;
606

    
607
  app=dynamic_cast<FF_App *>(getApp());
608
  t=AE_Transaction_new();
609
  if (m_account) {
610
    AE_SPLIT_LIST *sl;
611
    AE_SPLIT *sp;
612

    
613
    sl=AE_Transaction_GetSplitList(t);
614
    if (sl==NULL) {
615
      sl=AE_Split_List_new();
616
      AE_Transaction_SetSplitList(t, sl);
617
    }
618
    else
619
      AE_Split_List_Clear(sl);
620
    sp=AE_Split_new();
621
    AE_Split_SetAccountId(sp, AE_Account_GetId(m_account));
622
    AE_Split_SetCommodityId(sp, AE_Account_GetPrimaryCommodityId(m_account));
623
    AE_Split_List_Add(sp, sl);
624
  }
625
  FF_EditSimpleTransaction::createTransactions(app, this, I18N("Enter Transaction(s)"), t);
626
  AE_Transaction_free(t);
627
  return 1;
628
}
629

    
630

    
631

    
632
long FM_AccountStmPage::onCmdSplitEditor(FXObject *, FXSelector, void *ptr)
633
{
634
  FF_App *app;
635
  AE_BOOK *b;
636
  AE_TRANSACTION *t;
637

    
638
  app=dynamic_cast<FF_App *>(getApp());
639
  b=app->getBook();
640
  if (b) {
641
    t=m_transTable->getCurrentTransaction();
642
    if (t) {
643
      AE_TRANSACTION *tcpy;
644
      int rv;
645

    
646
      tcpy=AE_Transaction_dup(t);
647

    
648
#if 0
649
      {
650
        AE_SPLIT *sp;
651

652
        DBG_ERROR(0, "Split List for transaction %p", t);
653
        sp=AE_Transaction_GetFirstSplit(t);
654
        while (sp) {
655
          DBG_ERROR(0, "- split %p", sp);
656
          sp=AE_Split_List_Next(sp);
657
        }
658

659
      }
660
#endif
661

    
662
#if 0
663
      /* read original transaction */
664
      rv=AE_Book_ReadTransactionSubObjects(b, tcpy);
665
      if (rv<0) {
666
        FXMessageBox::error(this, FX::MBOX_OK,
667
                            I18N("Database Error"),
668
                            I18N("The original transaction could not be read (error: %d)"),
669
                            rv);
670
        AE_Transaction_free(tcpy);
671
        return 1;
672
      }
673
#endif
674

    
675
      if (FF_EditTransaction::editTransaction(app, this,
676
                                              I18N("Edit Splits"),
677
                                              t)) {
678
        m_transTable->rebuildTransactionflags(t);
679
        rv=AE_Book_ApplyTransaction(b, t, tcpy, 1);
680
        if (rv<0) {
681
          FXMessageBox::error(this, FX::MBOX_OK,
682
                              I18N("Database Error"),
683
                              I18N("The original transaction could not be applied (error: %d)"),
684
                              rv);
685
        }
686
        app->signalDbReload(AE_Book_TableType_Split);
687
        app->signalDbReload(AE_Book_TableType_AccountBalance);
688
      }
689
      AE_Transaction_free(tcpy);
690
#if 0
691
      m_transTable->reload();
692
      m_transTable->rebuild();
693
#endif
694
    }
695
  }
696

    
697
  return 1;
698
}
699

    
700

    
701

    
702
long FM_AccountStmPage::onCmdAssignToOutgoingPayment(FXObject *, FXSelector, void *ptr)
703
{
704
  FF_App *app;
705
  AE_BOOK *b;
706
  AE_TRANSACTION *t;
707

    
708
  app=dynamic_cast<FF_App *>(getApp());
709
  b=app->getBook();
710
  if (b) {
711
    t=m_transTable->getCurrentTransaction();
712
    if (t) {
713
      int rv;
714
      AQDB_ID payId=0;
715
      AE_JOB *j=NULL;
716

    
717
      while (1) {
718
        if (FF_SelectJob::selectJob(app, this,
719
                                    I18N("Select Outgoing Payment"),
720
                                    I18N("Please select the outgoing payment to which you want to assign "
721
                                         "this transaction"),
722
                                    payId,
723
                                    FF_SelectJob::JobSelection_Buys)) {
724
          if (payId!=0) {
725
            rv=AE_Book_ReadJob(b, AE_Book_TableType_Job, payId, &j);
726
            if (rv<0) {
727
              FXMessageBox::error(this, FX::MBOX_OK,
728
                                  I18N("Database Error"),
729
                                  I18N("The selected job could not be read (error: %d)"),
730
                                  rv);
731
              return 1;
732
            }
733
            if (AE_Job_GetType(j)!=AE_Job_TypePayment) {
734
              FXMessageBox::error(this, FX::MBOX_OK,
735
                                  I18N("Input Error"),
736
                                  "%s",
737
                                  I18N("The selected job is not a payment. "
738
                                       "Please select a payment."));
739
            }
740
            else {
741
              AQDB_ID oldId;
742

    
743
              oldId=AE_Job_GetTransactionId(j);
744
              if (oldId!=0) {
745
                FXMessageBox::error(this, FX::MBOX_OK,
746
                                    I18N("Input Error"),
747
                                    "%s",
748
                                    I18N("The selected job already has a transaction assigned to it. "
749
                                         "Please select another payment."));
750
              }
751
              else {
752
                /* set transaction, write job back */
753
                AE_Job_SetTransactionId(j, AE_Transaction_GetId(t));
754
                rv=AE_Book_WriteJob(b, AE_Book_TableType_Job, j, 1);
755
                if (rv<0) {
756
                  FXMessageBox::error(this, FX::MBOX_OK,
757
                                      I18N("Database Error"),
758
                                      I18N("The selected job could not be written (error: %d)"),
759
                                      rv);
760
                  return 1;
761
                }
762
                app->signalDbReload(AE_Book_TableType_Job);
763
                return 1;
764
              }
765
            }
766
          }
767
        }
768
        else {
769
          /* aborted */
770
          return 1;
771
        }
772
      }
773
    }
774
  }
775

    
776
  return 1;
777
}
778

    
779

    
780

    
781
long FM_AccountStmPage::onCmdAssignToIncomingPayment(FXObject *, FXSelector, void *ptr)
782
{
783
  FF_App *app;
784
  AE_BOOK *b;
785
  AE_TRANSACTION *t;
786

    
787
  app=dynamic_cast<FF_App *>(getApp());
788
  b=app->getBook();
789
  if (b) {
790
    t=m_transTable->getCurrentTransaction();
791
    if (t) {
792
      int rv;
793
      AQDB_ID payId=0;
794
      AE_JOB *j=NULL;
795

    
796
      while (1) {
797
        if (FF_SelectJob::selectJob(app, this,
798
                                    I18N("Select Incoming Payment"),
799
                                    I18N("Please select the incoming payment to which you want to assign "
800
                                         "this transaction"),
801
                                    payId,
802
                                    FF_SelectJob::JobSelection_Sells)) {
803
          if (payId!=0) {
804
            rv=AE_Book_ReadJob(b, AE_Book_TableType_Job, payId, &j);
805
            if (rv<0) {
806
              FXMessageBox::error(this, FX::MBOX_OK,
807
                                  I18N("Database Error"),
808
                                  I18N("The selected job could not be read (error: %d)"),
809
                                  rv);
810
              return 1;
811
            }
812
            if (AE_Job_GetType(j)!=AE_Job_TypePayment) {
813
              FXMessageBox::error(this, FX::MBOX_OK,
814
                                  I18N("Input Error"),
815
                                  "%s",
816
                                  I18N("The selected job is not a payment. "
817
                                       "Please select a payment."));
818
            }
819
            else {
820
              AQDB_ID oldId;
821

    
822
              oldId=AE_Job_GetTransactionId(j);
823
              if (oldId!=0) {
824
                FXMessageBox::error(this, FX::MBOX_OK,
825
                                    I18N("Input Error"),
826
                                    "%s",
827
                                    I18N("The selected job already has a transaction assigned to it. "
828
                                         "Please select another payment."));
829
              }
830
              else {
831
                /* set transaction, write job back */
832
                AE_Job_SetTransactionId(j, AE_Transaction_GetId(t));
833
                rv=AE_Book_WriteJob(b, AE_Book_TableType_Job, j, 1);
834
                if (rv<0) {
835
                  FXMessageBox::error(this, FX::MBOX_OK,
836
                                      I18N("Database Error"),
837
                                      I18N("The selected job could not be written (error: %d)"),
838
                                      rv);
839
                  return 1;
840
                }
841
                app->signalDbReload(AE_Book_TableType_Job);
842
                return 1;
843
              }
844
            }
845
          }
846
        }
847
        else {
848
          /* aborted */
849
          return 1;
850
        }
851
      }
852
    }
853
  }
854

    
855
  return 1;
856
}
857

    
858

    
859

    
860
long FM_AccountStmPage::onCmdCreateIncomingPayment(FXObject *, FXSelector, void *ptr)
861
{
862
  FF_App *app;
863
  AE_BOOK *b;
864

    
865
  app=dynamic_cast<FF_App *>(getApp());
866
  b=app->getBook();
867
  if (b) {
868
    AE_TRANSACTION *t;
869

    
870
    t=m_transTable->getCurrentTransaction();
871
    if (t) {
872
      int rv;
873
      AQDB_ID invoiceId=0;
874
      AE_JOB *j=NULL;
875

    
876
      while (1) {
877
        if (FF_SelectJob::selectJob(app, this,
878
                                    I18N("Select Outgoing Invoice"),
879
                                    I18N("Please select the outgoing invoice for which you want to "
880
                                         "create a payment."),
881
                                    invoiceId,
882
                                    FF_SelectJob::JobSelection_Sells)) {
883
          if (invoiceId==0) {
884
            DBG_ERROR(0, "No invoice selected");
885
            return 1;
886
          }
887

    
888
          rv=AE_Book_ReadJob(b, AE_Book_TableType_Job, invoiceId, &j);
889
          if (rv<0) {
890
            FXMessageBox::error(this, FX::MBOX_OK,
891
                                I18N("Database Error"),
892
                                I18N("The selected job could not be read (error: %d)"),
893
                                rv);
894
            return 1;
895
          }
896

    
897
          if (AE_Job_GetType(j)!=AE_Job_TypeInvoice) {
898
            FXMessageBox::error(this, FX::MBOX_OK,
899
                                I18N("Input Error"),
900
                                "%s",
901
                                I18N("The selected job is not an invoice. "
902
                                     "Please select an invoice."));
903
          }
904
          else {
905
            AQDB_ID tid=0;
906
            AE_TASK *tk=NULL;
907
            AE_JOB *jPayment;
908
            GWEN_DATE *dt;
909
            AQDB_VALUE *v;
910

    
911
            tid=AE_Job_GetTaskId(j);
912
            assert(tid);
913

    
914
            rv=AE_Book_ReadTask(b, AE_Book_TableType_Task, tid, &tk);
915
            if (rv<0) {
916
              FXMessageBox::error(this, FX::MBOX_OK,
917
                                  I18N("Database Error"),
918
                                  I18N("Error while reading selected task (error: %d)"),
919
                                  rv);
920
              AE_Job_free(j);
921
              return 1;
922
            }
923

    
924
            rv=AE_Book_ReadTaskSubObjects(b, tk, 1); /* outgoing */
925
            if (rv<0) {
926
              FXMessageBox::error(this, FX::MBOX_OK,
927
                                  I18N("Database Error"),
928
                                  I18N("Error while reading sub-objects of the selected task (error: %d)"),
929
                                  rv);
930
              AE_Task_free(tk);
931
              return 1;
932
            }
933
            j=AE_Job_List_GetById(AE_Task_GetJobs(tk), invoiceId);
934
            if (j==NULL) {
935
              DBG_ERROR(0, "Internal error");
936
              FXMessageBox::error(this, FX::MBOX_OK,
937
                                  I18N("Database Error"),
938
                                  "%s",
939
                                  I18N("An internal error occurred: The task doesn't contain the given job."));
940
              AE_Task_free(tk);
941
              return 1;
942
            }
943

    
944
            jPayment=AE_Job_new();
945
            AE_Job_SetTaskId(jPayment, tid);
946
            AE_Job_SetReferenceId(jPayment, invoiceId);
947
            AE_Job_SetType(jPayment, AE_Job_TypePayment);
948
            AE_Job_SetId(jPayment, 0);
949
            AE_Job_SetDbId(jPayment, 0);
950
            AE_Job_SetPartnerId(jPayment, AE_Job_GetPartnerId(j));
951
            AE_Job_SetCommodityId(jPayment, AE_Job_GetCommodityId(j));
952

    
953
            v=AE_Transaction_CalculateAmount(t, AE_Job_GetCommodityId(j));
954
            if (v) {
955
              AE_ITEM *item;
956

    
957
              /* create an item for the open amont */
958
              item=AE_Item_new();
959
              AE_Item_SetSellPriceValue(item, v);
960
              AE_Item_SetCommodityId(item, AE_Job_GetCommodityId(j));
961
              AE_Item_List_Add(item, AE_Job_GetItems(jPayment));
962
              AQDB_Value_free(v);
963
            }
964

    
965
            dt=GWEN_Date_CurrentDate();
966
            AE_Job_SetEnterDate(jPayment, dt);
967
            AE_Job_SetDueDate(jPayment, dt);
968
            GWEN_Date_free(dt);
969
            AE_Job_SetType(jPayment, AE_Job_TypePayment);
970

    
971
            if (FF_EditPayment::editPayment(app, this,
972
                                            I18N("Create Payment for Outgoing Invoice"),
973
                                            jPayment,
974
                                            0)) { /* !isBuy */
975
              rv=AE_Book_BeginEdit(b, 0);
976
              if (rv<0) {
977
                DBG_ERROR(0, "Error on begin edit: %d", rv);
978
                FXMessageBox::error(this, FX::MBOX_OK,
979
                                    I18N("Database Error"),
980
                                    I18N("Could not lock database for write access (error: %d)"),
981
                                    rv);
982
                AE_Task_free(tk);
983
                return 1;
984
              }
985

    
986
              AE_Task_SetWaitingFor(tk, AE_Job_TypeNone);
987

    
988
              DBG_ERROR(0, "Writing task");
989
              rv=AE_Book_WriteTask(b, AE_Book_TableType_Task, tk, 0);
990
              if (rv<0) {
991
                AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
992
                FXMessageBox::error(this, FX::MBOX_OK,
993
                                    I18N("Database Error"),
994
                                    I18N("Error while writing task (error: %d)"),
995
                                    rv);
996
                AE_Task_free(tk);
997
                return 1;
998
              }
999

    
1000
              AE_Job_SetTransactionId(jPayment, AE_Transaction_GetId(t));
1001
              rv=AE_Book_ApplyJob(b, jPayment, NULL, 0);
1002
              if (rv<0) {
1003
                AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
1004
                FXMessageBox::error(this, FX::MBOX_OK,
1005
                                    I18N("Database Error"),
1006
                                    I18N("The selected job could not be written (error: %d)"),
1007
                                    rv);
1008
                AE_Task_free(tk);
1009
                return 1;
1010
              }
1011
              AE_Task_free(tk);
1012

    
1013
              rv=AE_Book_EndEdit(b, 0);
1014
              if (rv<0) {
1015
                DBG_ERROR(0, "here (%d)", rv);
1016
                AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
1017
                FXMessageBox::error(this, FX::MBOX_OK,
1018
                                    I18N("Database Error"),
1019
                                    I18N("Could not apply changes to the database (error: %d)"),
1020
                                    rv);
1021
                return 1;
1022
              }
1023

    
1024
              app->signalDbReload(AE_Book_TableType_Job);
1025
              app->signalDbReload(AE_Book_TableType_Task);
1026
              return 1;
1027
            }
1028
          }
1029
        }
1030
        else {
1031
          /* aborted */
1032
          return 1;
1033
        }
1034
      }
1035
    }
1036
  }
1037

    
1038
  return 1;
1039
}
1040

    
1041

    
1042

    
1043
long FM_AccountStmPage::onCmdCreateOutgoingPayment(FXObject *, FXSelector, void *ptr)
1044
{
1045
  FF_App *app;
1046
  AE_BOOK *b;
1047

    
1048
  app=dynamic_cast<FF_App *>(getApp());
1049
  b=app->getBook();
1050
  if (b) {
1051
    AE_TRANSACTION *t;
1052

    
1053
    t=m_transTable->getCurrentTransaction();
1054
    if (t) {
1055
      int rv;
1056
      AQDB_ID invoiceId=0;
1057
      AE_JOB *j=NULL;
1058

    
1059
      while (1) {
1060
        if (FF_SelectJob::selectJob(app, this,
1061
                                    I18N("Select Outgoing Invoice"),
1062
                                    I18N("Please select the outgoing invoice for which you want to "
1063
                                         "create a payment."),
1064
                                    invoiceId,
1065
                                    FF_SelectJob::JobSelection_Buys)) {
1066
          if (invoiceId==0) {
1067
          }
1068

    
1069
          rv=AE_Book_ReadJob(b, AE_Book_TableType_Job, invoiceId, &j);
1070
          if (rv<0) {
1071
            FXMessageBox::error(this, FX::MBOX_OK,
1072
                                I18N("Database Error"),
1073
                                I18N("The selected job could not be read (error: %d)"),
1074
                                rv);
1075
            return 1;
1076
          }
1077

    
1078
          if (AE_Job_GetType(j)!=AE_Job_TypeInvoice) {
1079
            FXMessageBox::error(this, FX::MBOX_OK,
1080
                                I18N("Input Error"),
1081
                                "%s",
1082
                                I18N("The selected job is not an invoice. "
1083
                                     "Please select an invoice."));
1084
          }
1085
          else {
1086
            AQDB_ID tid=0;
1087
            AE_TASK *tk=NULL;
1088
            AE_JOB *jPayment;
1089
            GWEN_DATE *dt;
1090
            AQDB_VALUE *v;
1091

    
1092
            tid=AE_Job_GetTaskId(j);
1093
            assert(tid);
1094

    
1095
            rv=AE_Book_ReadTask(b, AE_Book_TableType_Task, tid, &tk);
1096
            if (rv<0) {
1097
              FXMessageBox::error(this, FX::MBOX_OK,
1098
                                  I18N("Database Error"),
1099
                                  I18N("Error while reading selected task (error: %d)"),
1100
                                  rv);
1101
              AE_Job_free(j);
1102
              return 1;
1103
            }
1104

    
1105
            rv=AE_Book_ReadTaskSubObjects(b, tk, 1); /* outgoing */
1106
            if (rv<0) {
1107
              FXMessageBox::error(this, FX::MBOX_OK,
1108
                                  I18N("Database Error"),
1109
                                  I18N("Error while reading sub-objects of the selected task (error: %d)"),
1110
                                  rv);
1111
              AE_Task_free(tk);
1112
              return 1;
1113
            }
1114
            j=AE_Job_List_GetById(AE_Task_GetJobs(tk), invoiceId);
1115
            if (j==NULL) {
1116
              DBG_ERROR(0, "Internal error");
1117
              FXMessageBox::error(this, FX::MBOX_OK,
1118
                                  I18N("Database Error"),
1119
                                  "%s",
1120
                                  I18N("An internal error occurred: The task doesn't contain the given job."));
1121
              AE_Task_free(tk);
1122
              return 1;
1123
            }
1124

    
1125
            jPayment=AE_Job_new();
1126
            AE_Job_SetTaskId(jPayment, tid);
1127
            AE_Job_SetReferenceId(jPayment, invoiceId);
1128
            AE_Job_SetType(jPayment, AE_Job_TypePayment);
1129
            AE_Job_SetId(jPayment, 0);
1130
            AE_Job_SetDbId(jPayment, 0);
1131
            AE_Job_SetPartnerId(jPayment, AE_Job_GetPartnerId(j));
1132
            AE_Job_SetCommodityId(jPayment, AE_Job_GetCommodityId(j));
1133

    
1134
            v=AE_Transaction_CalculateAmount(t, AE_Job_GetCommodityId(j));
1135
            if (v) {
1136
              AE_ITEM *item;
1137

    
1138
              /* create an item for the open amont */
1139
              item=AE_Item_new();
1140
              AE_Item_SetBuyPriceValue(item, v);
1141
              AE_Item_SetCommodityId(item, AE_Job_GetCommodityId(j));
1142
              AE_Item_List_Add(item, AE_Job_GetItems(jPayment));
1143
              AQDB_Value_free(v);
1144
            }
1145

    
1146
            dt=GWEN_Date_CurrentDate();
1147
            AE_Job_SetEnterDate(jPayment, dt);
1148
            AE_Job_SetDueDate(jPayment, dt);
1149
            GWEN_Date_free(dt);
1150
            AE_Job_SetType(jPayment, AE_Job_TypePayment);
1151

    
1152
            if (FF_EditPayment::editPayment(app, this,
1153
                                            I18N("Create Payment for Incoming Invoice"),
1154
                                            jPayment,
1155
                                            1)) { /* isBuy */
1156
              rv=AE_Book_BeginEdit(b, 0);
1157
              if (rv<0) {
1158
                DBG_ERROR(0, "Error on begin edit: %d", rv);
1159
                FXMessageBox::error(this, FX::MBOX_OK,
1160
                                    I18N("Database Error"),
1161
                                    I18N("Could not lock database for write access (error: %d)"),
1162
                                    rv);
1163
                AE_Task_free(tk);
1164
                return 1;
1165
              }
1166

    
1167
              AE_Task_SetWaitingFor(tk, AE_Job_TypeNone);
1168

    
1169
              DBG_ERROR(0, "Writing task");
1170
              rv=AE_Book_WriteTask(b, AE_Book_TableType_Task, tk, 0);
1171
              if (rv<0) {
1172
                AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
1173
                FXMessageBox::error(this, FX::MBOX_OK,
1174
                                    I18N("Database Error"),
1175
                                    I18N("Error while writing task (error: %d)"),
1176
                                    rv);
1177
                AE_Task_free(tk);
1178
                return 1;
1179
              }
1180

    
1181
              AE_Job_SetTransactionId(jPayment, AE_Transaction_GetId(t));
1182
              rv=AE_Book_ApplyJob(b, jPayment, NULL, 0);
1183
              if (rv<0) {
1184
                AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
1185
                FXMessageBox::error(this, FX::MBOX_OK,
1186
                                    I18N("Database Error"),
1187
                                    I18N("The selected job could not be written (error: %d)"),
1188
                                    rv);
1189
                AE_Task_free(tk);
1190
                return 1;
1191
              }
1192
              AE_Task_free(tk);
1193

    
1194
              rv=AE_Book_EndEdit(b, 0);
1195
              if (rv<0) {
1196
                DBG_ERROR(0, "here (%d)", rv);
1197
                AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
1198
                FXMessageBox::error(this, FX::MBOX_OK,
1199
                                    I18N("Database Error"),
1200
                                    I18N("Could not apply changes to the database (error: %d)"),
1201
                                    rv);
1202
                return 1;
1203
              }
1204

    
1205
              app->signalDbReload(AE_Book_TableType_Job);
1206
              app->signalDbReload(AE_Book_TableType_Task);
1207
              return 1;
1208
            }
1209
          }
1210
        }
1211
        else {
1212
          /* aborted */
1213
          return 1;
1214
        }
1215
      }
1216
    }
1217
  }
1218

    
1219
  return 1;
1220
}
1221

    
1222

    
1223

    
1224
long FM_AccountStmPage::onCmdMoveToAccount(FXObject *, FXSelector, void *ptr)
1225
{
1226
  AE_TRANSACTION_LIST2 *tl;
1227
  FF_App *app;
1228
  AE_BOOK *b;
1229

    
1230
  app=dynamic_cast<FF_App *>(getApp());
1231
  b=app->getBook();
1232

    
1233
  tl=AE_Transaction_List2_new();
1234
  m_transTable->getSelectedTransactions(tl, FF_TransactionTable::COPYMODE_NONE);
1235
  if (AE_Transaction_List2_GetSize(tl)) {
1236
    AQDB_ID aid=0;
1237

    
1238
    if (FF_SelectAccount::selectAccount(app, this,
1239
                                        I18N("Select Target Account"),
1240
                                        aid)) {
1241
      if (aid) {
1242
        AE_TRANSACTION_LIST2_ITERATOR *it;
1243
        int rv;
1244

    
1245
        rv=AE_Book_BeginEdit(b, 0);
1246
        if (rv<0) {
1247
          DBG_ERROR(0, "Error on begin edit: %d", rv);
1248
          FXMessageBox::error(this, FX::MBOX_OK,
1249
                              I18N("Database Error"),
1250
                              I18N("Could not lock database for write access (error: %d)"),
1251
                              rv);
1252
          AE_Transaction_List2_free(tl);
1253
          return 1;
1254
        }
1255

    
1256
        it=AE_Transaction_List2_First(tl);
1257
        if (it) {
1258
          AE_TRANSACTION *t;
1259

    
1260
          t=AE_Transaction_List2Iterator_Data(it);
1261
          while (t) {
1262
            AE_SPLIT *sp;
1263
            AE_TRANSACTION *cpy;
1264

    
1265
            cpy=AE_Transaction_dup(t);
1266
            sp=AE_Split_List_First(AE_Transaction_GetSplitList(cpy));
1267
            while (sp) {
1268
              if (AE_Split_GetAccountId(sp)==m_accountId) {
1269
                AE_Split_SetAccountId(sp, aid);
1270
                AE_Split_AddRuntimeFlags(sp, AE_SPLIT_RTFLAGS_MODIFIED);
1271
                AE_Transaction_AddRuntimeFlags(cpy,
1272
                                               AE_TRANSACTION_RTFLAGS_MODIFIED |
1273
                                               AE_TRANSACTION_RTFLAGS_SPLITS_MODIFIED);
1274
              }
1275
              sp=AE_Split_List_Next(sp);
1276
            }
1277

    
1278
            if (AE_Transaction_GetRuntimeFlags(cpy) & AE_TRANSACTION_RTFLAGS_MODIFIED) {
1279
              rv=AE_Book_ApplyTransaction(b, cpy, t, 0);
1280
              if (rv<0) {
1281
                DBG_ERROR(0, "here (%d)", rv);
1282
                AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
1283
                AE_Transaction_free(cpy);
1284
                AE_Transaction_List2Iterator_free(it);
1285
                AE_Transaction_List2_free(tl);
1286
                FXMessageBox::error(this, FX::MBOX_OK,
1287
                                    I18N("Database Error"),
1288
                                    I18N("Could not apply changes to the database (error: %d)"),
1289
                                    rv);
1290
                return 1;
1291
              }
1292
            }
1293
            AE_Transaction_free(cpy);
1294

    
1295
            t=AE_Transaction_List2Iterator_Next(it);
1296
          }
1297
          AE_Transaction_List2Iterator_free(it);
1298
        }
1299

    
1300
        rv=AE_Book_EndEdit(b, 0);
1301
        if (rv<0) {
1302
          DBG_ERROR(0, "here (%d)", rv);
1303
          AE_Book_EndEdit(b, AQDB_ACTION_FLAGS_ABORT);
1304
          FXMessageBox::error(this, FX::MBOX_OK,
1305
                              I18N("Database Error"),
1306
                              I18N("Could not apply changes to the database (error: %d)"),
1307
                              rv);
1308
          AE_Transaction_List2_free(tl);
1309
          return 1;
1310
        }
1311
      } /* if aid */
1312
    } /* if selectAccount */
1313
  }
1314
  AE_Transaction_List2_free(tl);
1315

    
1316
  app->signalDbReload(AE_Book_TableType_Transaction);
1317
  app->signalDbReload(AE_Book_TableType_AccountBalance);
1318

    
1319
  return 1;
1320
}
1321

    
1322

    
1323

    
1324
long FM_AccountStmPage::onChgMatcher(FXObject *, FXSelector, void *ptr)
1325
{
1326
  rebuild();
1327
  return 1;
1328
}
1329

    
1330

    
1331

    
1332
void FM_AccountStmPage::reset()
1333
{
1334
}
1335

    
1336

    
1337

    
1338
int FM_AccountStmPage::readAccountSplits(AE_SPLIT_LIST *splits)
1339
{
1340
  FF_App *app;
1341
  int rv;
1342
  char qexpr[256];
1343

    
1344
  app=dynamic_cast<FF_App *>(getApp());
1345

    
1346
  /* read splits for this account */
1347
  snprintf(qexpr, sizeof(qexpr)-1,
1348
           "$accountId==%d",
1349
           m_accountId);
1350
  rv=AE_Book_QuerySplitList(app->getBook(), AE_Book_TableType_Split, 0, qexpr, splits);
1351
  if (rv<0) {
1352
    DBG_ERROR(0, "here (%d)", rv);
1353
    return rv;
1354
  }
1355

    
1356
  return 0;
1357
}
1358

    
1359

    
1360

    
1361
int FM_AccountStmPage::readAccountTransactions(AE_SPLIT_IDMAP *sMap,
1362
                                               AE_TRANSACTION_LIST *transactions,
1363
                                               AE_TRANSACTION_IDMAP *tMap)
1364
{
1365
  FF_App *app;
1366
  AE_BOOK *b;
1367
  AQDB_ID qid=0;
1368
  AQDB_DB *db;
1369
  AQDB_ID tid;
1370
  int rv;
1371
  AQDB_ID oids[16];
1372
  int len;
1373

    
1374
  app=dynamic_cast<FF_App *>(getApp());
1375
  b=app->getBook();
1376
  db=AE_Book_GetDataBase(b);
1377
  tid=AE_Book_GetTableId(b, AE_Book_TableType_Transaction);
1378

    
1379
  /* query every transaction */
1380
  rv=AQDB_DB_QuerySubmit(db, tid, 0, NULL, 0, &qid);
1381
  if (rv<0) {
1382
    DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
1383
    return rv;
1384
  }
1385

    
1386
  /* browse all objects */
1387
  len=16;
1388
  rv=AQDB_DB_QueryGetFirst(db, qid, oids, &len);
1389
  while (rv==0) {
1390
    int i;
1391

    
1392
    for (i=0; i<len; i++) {
1393
      AQDB_OBJECT *o=NULL;
1394
      AE_TRANSACTION *t=NULL;
1395
      AQDB_ID transId;
1396
      AE_SPLIT *sp;
1397

    
1398
      rv=AQDB_DB_ReadObject(db, tid, oids[i], &o);
1399
      if (rv<0) {
1400
        DBG_INFO(AE_LOGDOMAIN, "Error reading object %d (%d)", oids[i], rv);
1401
        AQDB_DB_QueryClose(db, qid);
1402
        return rv;
1403
      }
1404

    
1405
      rv=AE_Transaction_fromObject(o, &t);
1406
      if (rv<0) {
1407
        DBG_INFO(AE_LOGDOMAIN, "Error reading object %d (%d)", oids[i], rv);
1408
        AQDB_Object_free(o);
1409
        AQDB_DB_QueryClose(db, qid);
1410
        return rv;
1411
      }
1412
      AE_Transaction_SetDbId(t, AQDB_Object_GetObjectId(o));
1413

    
1414
      /* find split to which the transaction belongs */
1415
      transId=AE_Transaction_GetId(t);
1416
      sp=AE_Split_IdMap_Find(sMap, transId);
1417
      if (sp==NULL)
1418
        /* no split is part of that transaction, free it */
1419
        AE_Transaction_free(t);
1420
      else {
1421
        /* otherwise add to the list */
1422
        AE_Transaction_List_Add(t, transactions);
1423
        AE_Transaction_IdMap_Insert(tMap, transId, t);
1424
      }
1425
      AQDB_Object_free(o);
1426
    }
1427

    
1428
    len=16;
1429
    rv=AQDB_DB_QueryGetNext(db, qid, oids, &len);
1430
  }
1431
  AQDB_DB_QueryClose(db, qid);
1432
  if (rv<0) {
1433
    if (rv!=GWEN_ERROR_NOT_FOUND) {
1434
      DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
1435
      return rv;
1436
    }
1437
  }
1438

    
1439
  return 0;
1440
}
1441

    
1442

    
1443

    
1444
int FM_AccountStmPage::readTransactionSplits(AE_TRANSACTION_IDMAP *tMap)
1445
{
1446
  FF_App *app;
1447
  AE_BOOK *b;
1448
  AQDB_ID qid=0;
1449
  AQDB_DB *db;
1450
  AQDB_ID tid;
1451
  int rv;
1452
  AQDB_ID oids[16];
1453
  int len;
1454

    
1455
  app=dynamic_cast<FF_App *>(getApp());
1456
  b=app->getBook();
1457
  db=AE_Book_GetDataBase(b);
1458
  tid=AE_Book_GetTableId(b, AE_Book_TableType_Split);
1459

    
1460
  /* query */
1461
  rv=AQDB_DB_QuerySubmit(db, tid, 0, NULL, 0, &qid);
1462
  if (rv<0) {
1463
    DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
1464
    return rv;
1465
  }
1466

    
1467
  /* browse all objects */
1468
  len=16;
1469
  rv=AQDB_DB_QueryGetFirst(db, qid, oids, &len);
1470
  while (rv==0) {
1471
    int i;
1472

    
1473
    for (i=0; i<len; i++) {
1474
      AQDB_OBJECT *o=NULL;
1475
      AE_SPLIT *sp=NULL;
1476
      AQDB_ID transId;
1477
      AE_TRANSACTION *t;
1478

    
1479
      rv=AQDB_DB_ReadObject(db, tid, oids[i], &o);
1480
      if (rv<0) {
1481
        DBG_INFO(AE_LOGDOMAIN, "Error reading object %d (%d)", oids[i], rv);
1482
        AQDB_DB_QueryClose(db, qid);
1483
        return rv;
1484
      }
1485

    
1486
      rv=AE_Split_fromObject(o, &sp);
1487
      if (rv<0) {
1488
        DBG_INFO(AE_LOGDOMAIN, "Error reading object %d (%d)", oids[i], rv);
1489
        AQDB_Object_free(o);
1490
        AQDB_DB_QueryClose(db, qid);
1491
        return rv;
1492
      }
1493
      AE_Split_SetDbId(sp, AQDB_Object_GetObjectId(o));
1494

    
1495
      /* find transaction to which the split belongs */
1496
      transId=AE_Split_GetTransactionId(sp);
1497
      t=AE_Transaction_IdMap_Find(tMap, transId);
1498
      if (t) {
1499
        AE_Transaction_AddSplit(t, sp);
1500
        if (AE_Split_List_GetCount(AE_Transaction_GetSplitList(t))>2)
1501
          AE_Transaction_AddRuntimeFlags(t, AE_TRANSACTION_RTFLAGS_MULTISPLIT);
1502
      }
1503
      else
1504
        AE_Split_free(sp);
1505

    
1506
      AQDB_Object_free(o);
1507
    }
1508

    
1509
    len=16;
1510
    rv=AQDB_DB_QueryGetNext(db, qid, oids, &len);
1511
  }
1512
  AQDB_DB_QueryClose(db, qid);
1513
  if (rv<0) {
1514
    if (rv!=GWEN_ERROR_NOT_FOUND) {
1515
      DBG_INFO(AE_LOGDOMAIN, "here (%d)", rv);
1516
      return rv;
1517
    }
1518
  }
1519

    
1520
  return 0;
1521
}
1522

    
1523

    
1524

    
1525
void FM_AccountStmPage::reload()
1526
{
1527
  FF_App *app;
1528
  AE_BOOK *b;
1529
  AE_SPLIT_LIST *splits;
1530
  AE_SPLIT_IDMAP *sMap;
1531
  AE_SPLIT *sp;
1532
  AE_TRANSACTION_LIST *transactions;
1533
  AE_TRANSACTION_IDMAP *tMap;
1534
  int rv;
1535
  FXString str;
1536

    
1537
  app=dynamic_cast<FF_App *>(getApp());
1538
  b=app->getBook();
1539

    
1540
  AE_Account_free(m_account);
1541
  m_account=NULL;
1542

    
1543
  AE_Commodity_free(m_accountCommodity);
1544
  m_accountCommodity=NULL;
1545

    
1546
  m_transTable->clearItems();
1547
  m_transTable->setMarkBeyondId(m_mainPage->getTransactionMarkId());
1548
  m_transTable->reload();
1549

    
1550
  /* read account */
1551
  if (m_accountId) {
1552
    AQDB_ID id;
1553

    
1554
    rv=AE_Book_ReadAccount(b, AE_Book_TableType_Account, m_accountId, &m_account);
1555
    if (rv<0) {
1556
      FXMessageBox::error(this, FX::MBOX_OK,
1557
                          I18N("Database Error"),
1558
                          I18N("Could not read account from database (error: %d)"),
1559
                          rv);
1560
      return;
1561
    }
1562

    
1563
    id=AE_Account_GetPrimaryCommodityId(m_account);
1564
    if (id) {
1565
      /* read primary commodity */
1566
      rv=AE_Book_ReadCommodity(b, AE_Book_TableType_Commodity, id, &m_accountCommodity);
1567
      if (rv<0) {
1568
        DBG_ERROR(0, "here (%d)", rv);
1569
        FXMessageBox::error(this, FX::MBOX_OK,
1570
                            I18N("Database Error"),
1571
                            I18N("Could not read commodity (error: %d)"),
1572
                            rv);
1573
        return;
1574
      }
1575
    }
1576
  }
1577

    
1578
  /* read splits of this account */
1579
  splits=AE_Split_List_new();
1580
  rv=readAccountSplits(splits);
1581
  if (rv<0) {
1582
    DBG_ERROR(0, "here (%d)", rv);
1583
    AE_Split_List_free(splits);
1584
    return;
1585
  }
1586

    
1587
  /* store split by transactionId in map for faster access */
1588
  sMap=AE_Split_IdMap_new(GWEN_IdMapAlgo_Hex4);
1589
  sp=AE_Split_List_First(splits);
1590
  while (sp) {
1591
    AE_Split_IdMap_Insert(sMap, AE_Split_GetTransactionId(sp), sp);
1592
    sp=AE_Split_List_Next(sp);
1593
  }
1594

    
1595
  /* read transactions which have a split in this account */
1596
  transactions=AE_Transaction_List_new();
1597
  tMap=AE_Transaction_IdMap_new(GWEN_IdMapAlgo_Hex4);
1598
  rv=readAccountTransactions(sMap, transactions, tMap);
1599
  if (rv<0) {
1600
    DBG_ERROR(0, "here (%d)", rv);
1601
    AE_Transaction_List_free(transactions);
1602
    AE_Split_List_free(splits);
1603
    return;
1604
  }
1605
  AE_Split_IdMap_free(sMap);
1606
  AE_Split_List_free(splits);
1607

    
1608
  /* read splits for every transaction */
1609
  rv=readTransactionSplits(tMap);
1610
  if (rv<0) {
1611
    DBG_ERROR(0, "here (%d)", rv);
1612
    AE_Transaction_List_free(transactions);
1613
    AE_Transaction_IdMap_free(tMap);
1614
    return;
1615
  }
1616

    
1617
  AE_Transaction_List_free(m_transactions);
1618
  m_transactions=transactions;
1619
  AE_Transaction_IdMap_free(tMap);
1620

    
1621
  rebuild();
1622
}
1623

    
1624

    
1625

    
1626
void FM_AccountStmPage::rebuild()
1627
{
1628
  m_transTable->clearItems();
1629
  if (m_transactions) {
1630
    AE_TRANSACTION *t;
1631
    FXString str;
1632
    int i;
1633

    
1634
    str=m_matcher->getText().simplify().trim();
1635
    AE_Transaction_List_SelectMatching(m_transactions, str.text());
1636

    
1637
    i=0;
1638
    t=AE_Transaction_List_First(m_transactions);
1639
    while (t) {
1640
      if (AE_Transaction_GetRuntimeFlags(t) & AE_TRANSACTION_RTFLAGS_SELECTED) {
1641
        AE_Transaction_Attach(t);
1642
        m_transTable->addTransaction(t);
1643
        i++;
1644
      }
1645
      t=AE_Transaction_List_Next(t);
1646
    }
1647

    
1648
    str=FXStringFormat(I18N("%d transactions (of %d)"), i, AE_Transaction_List_GetCount(m_transactions));
1649
    m_fLabel->setText(str);
1650

    
1651
    /* sort table */
1652
    m_transTable->sort();
1653

    
1654
    if (m_account) {
1655

    
1656
    }
1657

    
1658
    layout();
1659
  }
1660
}
1661

    
1662

    
1663

    
1664