1 /*******************************************************
2  Copyright (C) 2006 Madhan Kanagavel
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  ********************************************************/
18 
19 #include "attachmentdialog.h"
20 #include "billsdepositspanel.h"
21 #include "billsdepositsdialog.h"
22 #include "constants.h"
23 
24 #include "model/Model_Account.h"
25 #include "model/Model_Attachment.h"
26 #include "model/Model_Category.h"
27 #include "model/Model_Payee.h"
28 #include "model/Model_Setting.h"
29 
30 #include "../resources/attachment.xpm"
31 #include "../resources/downarrow.xpm"
32 #include "../resources/error.xpm"
33 #include "../resources/rightarrow.xpm"
34 #include "../resources/rt_exec_auto.xpm"
35 #include "../resources/rt_exec_user.xpm"
36 #include "../resources/tipicon.xpm"
37 #include "../resources/uparrow.xpm"
38 
39 
40 enum
41 {
42     MENU_TREEPOPUP_NEW = wxID_HIGHEST + 1300,
43     MENU_TREEPOPUP_EDIT,
44     MENU_TREEPOPUP_DELETE,
45     MENU_POPUP_BD_ENTER_OCCUR,
46     MENU_POPUP_BD_SKIP_OCCUR,
47     MENU_TREEPOPUP_ORGANIZE_ATTACHMENTS,
48 };
49 
50 const wxString BILLSDEPOSITS_REPEATS[] =
51 {
52     wxTRANSLATE("None"),
53     wxTRANSLATE("Weekly"),
54     wxTRANSLATE("Bi-Weekly"),
55     wxTRANSLATE("Monthly"),
56     wxTRANSLATE("Bi-Monthly"),
57     wxTRANSLATE("Quarterly"),
58     wxTRANSLATE("Half-Yearly"),
59     wxTRANSLATE("Yearly"),
60     wxTRANSLATE("Four Months"),
61     wxTRANSLATE("Four Weeks"),
62     wxTRANSLATE("Daily"),
63     wxTRANSLATE("In %s Days"),
64     wxTRANSLATE("In %s Months"),
65     wxTRANSLATE("Every %s Days"),
66     wxTRANSLATE("Every %s Months"),
67     wxTRANSLATE("Monthly (last day)"),
68     wxTRANSLATE("Monthly (last business day)")
69 
70 };
71 
72 /*******************************************************/
wxBEGIN_EVENT_TABLE(mmBillsDepositsPanel,wxPanel)73 wxBEGIN_EVENT_TABLE(mmBillsDepositsPanel, wxPanel)
74     EVT_BUTTON(wxID_NEW, mmBillsDepositsPanel::OnNewBDSeries)
75     EVT_BUTTON(wxID_EDIT, mmBillsDepositsPanel::OnEditBDSeries)
76     EVT_BUTTON(wxID_DELETE, mmBillsDepositsPanel::OnDeleteBDSeries)
77     EVT_BUTTON(wxID_PASTE, mmBillsDepositsPanel::OnEnterBDTransaction)
78     EVT_BUTTON(wxID_IGNORE, mmBillsDepositsPanel::OnSkipBDTransaction)
79     EVT_BUTTON(wxID_FILE, mmBillsDepositsPanel::OnOpenAttachment)
80 wxEND_EVENT_TABLE()
81 /*******************************************************/
82 wxBEGIN_EVENT_TABLE(billsDepositsListCtrl, mmListCtrl)
83     EVT_LIST_ITEM_ACTIVATED(wxID_ANY,   billsDepositsListCtrl::OnListItemActivated)
84     EVT_RIGHT_DOWN(billsDepositsListCtrl::OnItemRightClick)
85     EVT_LEFT_DOWN(billsDepositsListCtrl::OnListLeftClick)
86     EVT_LIST_ITEM_SELECTED(wxID_ANY, billsDepositsListCtrl::OnListItemSelected)
87 
88     EVT_MENU(MENU_TREEPOPUP_NEW,              billsDepositsListCtrl::OnNewBDSeries)
89     EVT_MENU(MENU_TREEPOPUP_EDIT,             billsDepositsListCtrl::OnEditBDSeries)
90     EVT_MENU(MENU_TREEPOPUP_DELETE,           billsDepositsListCtrl::OnDeleteBDSeries)
91     EVT_MENU(MENU_POPUP_BD_ENTER_OCCUR,       billsDepositsListCtrl::OnEnterBDTransaction)
92     EVT_MENU(MENU_POPUP_BD_SKIP_OCCUR,        billsDepositsListCtrl::OnSkipBDTransaction)
93     EVT_MENU(MENU_TREEPOPUP_ORGANIZE_ATTACHMENTS, billsDepositsListCtrl::OnOrganizeAttachments)
94 
95     EVT_LIST_KEY_DOWN(wxID_ANY,   billsDepositsListCtrl::OnListKeyDown)
96 wxEND_EVENT_TABLE()
97 /*******************************************************/
98 
99 billsDepositsListCtrl::billsDepositsListCtrl(mmBillsDepositsPanel* bdp, wxWindow *parent, wxWindowID winid)
100 : mmListCtrl(parent, winid)
101 , m_bdp(bdp)
102 {
103     // load the global variables
104     m_selected_col = Model_Setting::instance().GetIntSetting("BD_SORT_COL", m_bdp->col_sort());
105     m_asc = Model_Setting::instance().GetBoolSetting("BD_ASC", true);
106 
107     m_columns.push_back(std::make_tuple(" ", 25, wxLIST_FORMAT_LEFT));
108     m_columns.push_back(std::make_tuple(_("ID"), wxLIST_AUTOSIZE, wxLIST_FORMAT_RIGHT));
109     m_columns.push_back(std::make_tuple(_("Payment Date"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
110     m_columns.push_back(std::make_tuple(_("Due Date"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
111     m_columns.push_back(std::make_tuple(_("Account"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
112     m_columns.push_back(std::make_tuple(_("Payee"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
113     m_columns.push_back(std::make_tuple(_("Status"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
114     m_columns.push_back(std::make_tuple(_("Category"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
115     m_columns.push_back(std::make_tuple(_("Type"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
116     m_columns.push_back(std::make_tuple(_("Amount"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_RIGHT));
117     m_columns.push_back(std::make_tuple(_("Frequency"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
118     m_columns.push_back(std::make_tuple(_("Repetitions"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
119     m_columns.push_back(std::make_tuple(_("Autorepeat"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
120     m_columns.push_back(std::make_tuple(_("Payment"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
121     m_columns.push_back(std::make_tuple(_("Number"), wxLIST_AUTOSIZE_USEHEADER, wxLIST_FORMAT_LEFT));
122     m_columns.push_back(std::make_tuple(_("Notes"), 150, wxLIST_FORMAT_LEFT));
123 
124     m_col_width = "BD_COL%d_WIDTH";
125     m_default_sort_column = m_bdp->col_sort();
126 }
127 
~billsDepositsListCtrl()128 billsDepositsListCtrl::~billsDepositsListCtrl()
129 {
130 }
131 
OnColClick(wxListEvent & event)132 void billsDepositsListCtrl::OnColClick(wxListEvent& event)
133 {
134     int ColumnNr;
135     if (event.GetId() != MENU_HEADER_SORT)
136         ColumnNr = event.GetColumn();
137     else
138         ColumnNr = m_ColumnHeaderNbr;
139     if (0 > ColumnNr || ColumnNr >= m_bdp->getColumnsNumber() || ColumnNr == 0) return;
140 
141     if (m_selected_col == ColumnNr && event.GetId() != MENU_HEADER_SORT) m_asc = !m_asc;
142 
143     wxListItem item;
144     item.SetMask(wxLIST_MASK_IMAGE);
145     item.SetImage(-1);
146     SetColumn(m_selected_col, item);
147 
148     m_selected_col = ColumnNr;
149 
150     Model_Setting::instance().Set("BD_ASC", m_asc);
151     Model_Setting::instance().Set("BD_SORT_COL", m_selected_col);
152 
153     if (m_selected_row >= 0)
154         refreshVisualList(m_bdp->initVirtualListControl(m_bdp->bills_[m_selected_row].BDID));
155     else
156         refreshVisualList(m_bdp->initVirtualListControl(-1));
157 }
158 
mmBillsDepositsPanel(wxWindow * parent,wxWindowID winid,const wxPoint & pos,const wxSize & size,long style,const wxString & name)159 mmBillsDepositsPanel::mmBillsDepositsPanel(wxWindow *parent, wxWindowID winid
160     , const wxPoint& pos, const wxSize& size, long style, const wxString& name)
161     : m_imageList(nullptr)
162     , listCtrlAccount_(nullptr)
163     , transFilterDlg_(nullptr)
164     , bitmapTransFilter_(nullptr)
165     , m_infoTextMini(nullptr)
166     , m_infoText(nullptr)
167 {
168     this->tips_.Add(_("MMEX allows regular payments to be set up as transactions. These transactions can also be regular deposits, or transfers that will occur at some future time. These transactions act as a reminder that an event is about to occur, and appears on the Home Page 14 days before the transaction is due. "));
169     this->tips_.Add(_("Tip: These transactions can be set up to activate – allowing the user to adjust any values on the due date."));
170 
171     Create(parent, winid, pos, size, style, name);
172 }
173 
Create(wxWindow * parent,wxWindowID winid,const wxPoint & pos,const wxSize & size,long style,const wxString & name)174 bool mmBillsDepositsPanel::Create(wxWindow *parent
175     , wxWindowID winid, const wxPoint& pos
176     , const wxSize& size, long style, const wxString& name)
177 {
178     SetExtraStyle(GetExtraStyle()|wxWS_EX_BLOCK_EVENTS);
179     wxPanel::Create(parent, winid, pos, size, style, name);
180 
181     this->windowsFreezeThaw();
182 
183     CreateControls();
184     GetSizer()->Fit(this);
185     GetSizer()->SetSizeHints(this);
186 
187     /* Set up the transaction filter.  The transFilter dialog will be destroyed
188        when the checking panel is destroyed. */
189     transFilterActive_ = false;
190     transFilterDlg_ = new mmFilterTransactionsDialog(this);
191 
192     initVirtualListControl();
193 
194     this->windowsFreezeThaw();
195 
196     return TRUE;
197 }
198 
~mmBillsDepositsPanel()199 mmBillsDepositsPanel::~mmBillsDepositsPanel()
200 {
201     if (m_imageList)
202         delete m_imageList;
203     if (transFilterDlg_)
204         delete transFilterDlg_;
205 }
206 
CreateControls()207 void mmBillsDepositsPanel::CreateControls()
208 {
209     wxBoxSizer* itemBoxSizer9 = new wxBoxSizer(wxVERTICAL);
210     this->SetSizer(itemBoxSizer9);
211 
212     /* ---------------------- */
213     wxPanel* headerPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition
214         , wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL);
215     itemBoxSizer9->Add(headerPanel, 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
216 
217     wxBoxSizer* itemBoxSizerVHeader = new wxBoxSizer(wxVERTICAL);
218     headerPanel->SetSizer(itemBoxSizerVHeader);
219 
220     wxStaticText* itemStaticText9 = new wxStaticText(headerPanel, wxID_ANY
221         , _("Recurring Transactions"));
222     itemStaticText9->SetFont(this->GetFont().Larger().Bold());
223     itemBoxSizerVHeader->Add(itemStaticText9, 0, wxALL, 1);
224 
225     wxBoxSizer* itemBoxSizerHHeader2 = new wxBoxSizer(wxHORIZONTAL);
226     itemBoxSizerVHeader->Add(itemBoxSizerHHeader2);
227 
228     wxBitmap itemStaticBitmap(rightarrow_xpm);
229     bitmapTransFilter_ = new wxStaticBitmap(headerPanel, wxID_ANY, itemStaticBitmap);
230     itemBoxSizerHHeader2->Add(bitmapTransFilter_, 0, wxALL, 1);
231     bitmapTransFilter_->Connect(wxID_ANY, wxEVT_LEFT_DOWN
232         , wxMouseEventHandler(mmBillsDepositsPanel::OnFilterTransactions), nullptr, this);
233     bitmapTransFilter_->Connect(wxID_ANY, wxEVT_RIGHT_DOWN
234         , wxMouseEventHandler(mmBillsDepositsPanel::OnFilterTransactions), nullptr, this);
235 
236     itemBoxSizerHHeader2->AddSpacer(5);
237     wxStaticText* statTextTransFilter_ = new wxStaticText(headerPanel, wxID_ANY
238         , _("Transaction Filter"));
239     itemBoxSizerHHeader2->Add(statTextTransFilter_, 0, wxALIGN_CENTER_VERTICAL, 0);
240 
241     /* ---------------------- */
242     wxSplitterWindow* itemSplitterWindowBillsDeposit = new wxSplitterWindow(this
243         , wxID_ANY, wxDefaultPosition, wxSize(200, 200)
244         , wxSP_3DBORDER | wxSP_3DSASH | wxNO_BORDER);
245 
246     wxSize imageSize(16, 16);
247     m_imageList = new wxImageList(imageSize.GetWidth(), imageSize.GetHeight());
248     m_imageList->Add(wxBitmap(wxImage(error_xpm).Scale(16, 16)));
249     m_imageList->Add(wxBitmap(wxImage(rt_exec_auto_xpm).Scale(16, 16)));
250     m_imageList->Add(wxBitmap(wxImage(rt_exec_user_xpm).Scale(16, 16)));
251     m_imageList->Add(wxBitmap(wxImage(uparrow_xpm).Scale(16, 16)));
252     m_imageList->Add(wxBitmap(wxImage(downarrow_xpm).Scale(16, 16)));
253 
254     listCtrlAccount_ = new billsDepositsListCtrl(this, itemSplitterWindowBillsDeposit);
255 
256     listCtrlAccount_->SetImageList(m_imageList, wxIMAGE_LIST_SMALL);
257 
258     int i = 0;
259     for (const auto& entry : listCtrlAccount_->m_columns)
260     {
261         const wxString& heading = std::get<0>(entry);
262         int width = Model_Setting::instance().GetIntSetting(wxString::Format(listCtrlAccount_->m_col_width, i), std::get<1>(entry));
263         int format = std::get<2>(entry);
264         listCtrlAccount_->InsertColumn(i++, heading, format, width);
265     }
266 
267     wxPanel* bdPanel = new wxPanel(itemSplitterWindowBillsDeposit, wxID_ANY
268         , wxDefaultPosition, wxDefaultSize, wxNO_BORDER | wxTAB_TRAVERSAL);
269 
270     itemSplitterWindowBillsDeposit->SplitHorizontally(listCtrlAccount_, bdPanel);
271     itemSplitterWindowBillsDeposit->SetMinimumPaneSize(100);
272     itemSplitterWindowBillsDeposit->SetSashGravity(1.0);
273     itemBoxSizer9->Add(itemSplitterWindowBillsDeposit, 1, wxGROW | wxALL, 1);
274 
275     wxBoxSizer* itemBoxSizer4 = new wxBoxSizer(wxVERTICAL);
276     bdPanel->SetSizer(itemBoxSizer4);
277 
278     wxBoxSizer* itemBoxSizer5 = new wxBoxSizer(wxHORIZONTAL);
279     itemBoxSizer4->Add(itemBoxSizer5, g_flags);
280 
281     wxButton* itemButtonNew = new wxButton(bdPanel, wxID_NEW, _("&New "));
282     itemButtonNew->SetToolTip(_("New Bills & Deposit Series"));
283     itemBoxSizer5->Add(itemButtonNew, g_flags);
284 
285     wxButton* itemButton81 = new wxButton(bdPanel, wxID_EDIT, _("&Edit "));
286     itemButton81->SetToolTip(_("Edit Bills & Deposit Series"));
287     itemBoxSizer5->Add(itemButton81, g_flags);
288     itemButton81->Enable(false);
289 
290     wxButton* itemButton7 = new wxButton(bdPanel, wxID_DELETE, _("&Delete "));
291     itemButton7->SetToolTip(_("Delete Bills & Deposit Series"));
292     itemBoxSizer5->Add(itemButton7, g_flags);
293     itemButton7->Enable(false);
294 
295     wxButton* itemButton8 = new wxButton(bdPanel, wxID_PASTE, _("En&ter"));
296     itemButton8->SetToolTip(_("Enter Next Bills & Deposit Occurrence"));
297     itemBoxSizer5->Add(itemButton8, g_flags);
298     itemButton8->Enable(false);
299 
300     wxButton* buttonSkipTrans = new wxButton(bdPanel, wxID_IGNORE, _("&Skip"));
301     buttonSkipTrans->SetToolTip(_("Skip Next Bills & Deposit Occurrence"));
302     itemBoxSizer5->Add(buttonSkipTrans, g_flags);
303     buttonSkipTrans->Enable(false);
304 
305     wxBitmapButton* btnAttachment_ = new wxBitmapButton(bdPanel, wxID_FILE
306         , wxBitmap(attachment_xpm), wxDefaultPosition
307         , wxSize(30, itemButton8->GetSize().GetY()));
308     btnAttachment_->SetToolTip(_("Open attachments"));
309     itemBoxSizer5->Add(btnAttachment_, g_flags);
310     btnAttachment_->Enable(false);
311 
312     //Infobar-mini
313     m_infoTextMini = new wxStaticText(bdPanel, wxID_STATIC, "");
314     itemBoxSizer5->Add(m_infoTextMini, 1, wxGROW | wxTOP, 12);
315 
316     //Infobar
317     m_infoText = new wxStaticText(bdPanel, wxID_ANY, ""
318         , wxPoint(-1, -1), wxSize(200, -1), wxNO_BORDER | wxTE_MULTILINE | wxTE_WORDWRAP | wxST_NO_AUTORESIZE);
319     itemBoxSizer4->Add(m_infoText, 1, wxGROW | wxLEFT | wxRIGHT, 14);
320 
321     mmBillsDepositsPanel::updateBottomPanelData(-1);
322 }
323 
initVirtualListControl(int id)324 int mmBillsDepositsPanel::initVirtualListControl(int id)
325 {
326     listCtrlAccount_->DeleteAllItems();
327 
328     wxListItem item;
329     item.SetMask(wxLIST_MASK_IMAGE);
330     item.SetImage(listCtrlAccount_->m_asc ? 4 : 3);
331     listCtrlAccount_->SetColumn(listCtrlAccount_->m_selected_col, item);
332 
333     bills_.clear();
334     const auto split = Model_Budgetsplittransaction::instance().get_all();
335     for (const Model_Billsdeposits::Data& data
336         : Model_Billsdeposits::instance().all(Model_Billsdeposits::COL_NEXTOCCURRENCEDATE))
337     {
338         if (transFilterActive_ && !transFilterDlg_->checkAll(data, split))
339             continue;
340 
341         Model_Billsdeposits::Full_Data r(data);
342 
343         if (Model_Attachment::NrAttachments(Model_Attachment::reftype_desc(Model_Attachment::BILLSDEPOSIT), r.BDID))
344             r.NOTES = r.NOTES.Prepend(mmAttachmentManage::GetAttachmentNoteSign());
345         bills_.push_back(r);
346     }
347 
348     sortTable();
349 
350     int cnt = 0, selected_item = -1;
351     for (const auto& entry: bills_)
352     {
353         if (id == entry.BDID)
354         {
355             selected_item = cnt;
356             break;
357         }
358         ++cnt;
359     }
360 
361     listCtrlAccount_->SetItemCount(static_cast<long>(bills_.size()));
362     return selected_item;
363 }
364 
OnNewBDSeries(wxCommandEvent & event)365 void mmBillsDepositsPanel::OnNewBDSeries(wxCommandEvent& event)
366 {
367   listCtrlAccount_->OnNewBDSeries(event);
368 }
369 
OnEditBDSeries(wxCommandEvent & event)370 void mmBillsDepositsPanel::OnEditBDSeries(wxCommandEvent& event)
371 {
372     listCtrlAccount_->OnEditBDSeries(event);
373 }
374 
OnDeleteBDSeries(wxCommandEvent & event)375 void mmBillsDepositsPanel::OnDeleteBDSeries(wxCommandEvent& event)
376 {
377     listCtrlAccount_->OnDeleteBDSeries(event);
378 }
379 
OnEnterBDTransaction(wxCommandEvent & event)380 void mmBillsDepositsPanel::OnEnterBDTransaction(wxCommandEvent& event)
381 {
382     listCtrlAccount_->OnEnterBDTransaction(event);
383 }
384 
OnSkipBDTransaction(wxCommandEvent & event)385 void mmBillsDepositsPanel::OnSkipBDTransaction(wxCommandEvent& event)
386 {
387     listCtrlAccount_->OnSkipBDTransaction(event);
388     listCtrlAccount_->SetFocus();
389 }
390 
OnOpenAttachment(wxCommandEvent & event)391 void mmBillsDepositsPanel::OnOpenAttachment(wxCommandEvent& event)
392 {
393     listCtrlAccount_->OnOpenAttachment(event);
394     listCtrlAccount_->SetFocus();
395 }
396 
397 /*******************************************************/
OnItemRightClick(wxMouseEvent & event)398 void billsDepositsListCtrl::OnItemRightClick(wxMouseEvent& event)
399 {
400     if (m_selected_row > -1)
401         SetItemState(m_selected_row, 0, wxLIST_STATE_SELECTED | wxLIST_STATE_FOCUSED);
402     int Flags = wxLIST_HITTEST_ONITEM;
403     m_selected_row = HitTest(wxPoint(event.m_x, event.m_y), Flags);
404 
405     if (m_selected_row >= 0)
406     {
407         SetItemState(m_selected_row, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
408         SetItemState(m_selected_row, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
409     }
410     m_bdp->updateBottomPanelData(m_selected_row);
411     bool item_active = (m_selected_row >= 0);
412     wxMenu menu;
413     menu.Append(MENU_POPUP_BD_ENTER_OCCUR, _("Enter next Occurrence..."));
414     menu.AppendSeparator();
415     menu.Append(MENU_POPUP_BD_SKIP_OCCUR, _("Skip next Occurrence"));
416     menu.AppendSeparator();
417     menu.Append(MENU_TREEPOPUP_NEW, _("&New Bills && Deposit Series..."));
418     menu.Append(MENU_TREEPOPUP_EDIT, _("&Edit Bills && Deposit Series..."));
419     menu.Append(MENU_TREEPOPUP_DELETE, _("&Delete Bills && Deposit Series..."));
420     menu.AppendSeparator();
421     menu.Append(MENU_TREEPOPUP_ORGANIZE_ATTACHMENTS, _("&Organize Attachments"));
422 
423     menu.Enable(MENU_POPUP_BD_ENTER_OCCUR, item_active);
424     menu.Enable(MENU_POPUP_BD_SKIP_OCCUR, item_active);
425     menu.Enable(MENU_TREEPOPUP_EDIT, item_active);
426     menu.Enable(MENU_TREEPOPUP_DELETE, item_active);
427     menu.Enable(MENU_TREEPOPUP_ORGANIZE_ATTACHMENTS, item_active);
428 
429     PopupMenu(&menu, event.GetPosition());
430     this->SetFocus();
431 }
432 
getItem(long item,long column)433 wxString mmBillsDepositsPanel::getItem(long item, long column)
434 {
435     const Model_Billsdeposits::Full_Data& bill = this->bills_.at(item);
436     switch (column)
437     {
438     case COL_ID:
439         return wxString::Format("%i", bill.BDID).Trim();
440     case COL_PAYMENT_DATE:
441         return mmGetDateForDisplay(Model_Billsdeposits::NEXTOCCURRENCEDATE(bill));
442     case COL_DUE_DATE:
443         return mmGetDateForDisplay(Model_Billsdeposits::TRANSDATE(bill));
444     case COL_ACCOUNT:
445         return bill.ACCOUNTNAME;
446     case COL_PAYEE:
447         return bill.PAYEENAME;
448     case COL_STATUS:
449         return bill.STATUS;
450     case COL_CATEGORY:
451         return bill.CATEGNAME;
452     case COL_TYPE:
453         return wxGetTranslation(bill.TRANSCODE);
454     case COL_AMOUNT:
455         return Model_Account::toCurrency(bill.TRANSAMOUNT, Model_Account::instance().get(bill.ACCOUNTID));
456     case COL_FREQUENCY:
457         return GetFrequency(&bill);
458     case COL_REPEATS:
459         if (bill.NUMOCCURRENCES == -1)
460             return L"\x221E";
461         else
462             return wxString::Format("%i", bill.NUMOCCURRENCES).Trim();
463     case COL_AUTO:
464     {
465         int repeats = bill.REPEATS;
466         wxString repeatSTR = _("Manual");
467         if (repeats >= BD_REPEATS_MULTIPLEX_BASE)
468         {
469             repeats -= BD_REPEATS_MULTIPLEX_BASE;
470             repeatSTR = _("Suggested");
471             if (repeats >= BD_REPEATS_MULTIPLEX_BASE)
472             {
473                 repeats -= BD_REPEATS_MULTIPLEX_BASE;
474                 repeatSTR = _("Automated");
475             }
476         }
477         return repeatSTR;
478     }
479     case COL_DAYS:
480         return GetRemainingDays(&bill);
481     case COL_NUMBER:
482         return bill.TRANSACTIONNUMBER;
483     case COL_NOTES:
484         return bill.NOTES;
485     default:
486         return wxEmptyString;
487     }
488 }
489 
GetFrequency(const Model_Billsdeposits::Data * item)490 wxString mmBillsDepositsPanel::GetFrequency(const Model_Billsdeposits::Data* item)
491 {
492     int repeats = item->REPEATS;
493     // DeMultiplex the Auto Executable fields.
494     if (repeats >= BD_REPEATS_MULTIPLEX_BASE)    // Auto Execute User Acknowlegement required
495         repeats -= BD_REPEATS_MULTIPLEX_BASE;
496     if (repeats >= BD_REPEATS_MULTIPLEX_BASE)    // Auto Execute Silent mode
497         repeats -= BD_REPEATS_MULTIPLEX_BASE;
498 
499     wxString text = wxGetTranslation(BILLSDEPOSITS_REPEATS[repeats]);
500     if (repeats > 10 && repeats < 15)
501         text = wxString::Format(text, wxString::Format("%d", item->NUMOCCURRENCES));
502     return text;
503 }
504 
GetRemainingDays(const Model_Billsdeposits::Data * item)505 wxString mmBillsDepositsPanel::GetRemainingDays(const Model_Billsdeposits::Data* item)
506 {
507     int repeats = item->REPEATS;
508     // DeMultiplex the Auto Executable fields.
509     if (repeats >= BD_REPEATS_MULTIPLEX_BASE)    // Auto Execute User Acknowlegement required
510         repeats -= BD_REPEATS_MULTIPLEX_BASE;
511     if (repeats >= BD_REPEATS_MULTIPLEX_BASE)    // Auto Execute Silent mode
512         repeats -= BD_REPEATS_MULTIPLEX_BASE;
513 
514     int daysRemaining = Model_Billsdeposits::daysPayment(item);
515     int daysOverdue = Model_Billsdeposits::daysOverdue(item);
516     wxString text = wxString::Format(_("%d days remaining"), daysRemaining);
517 
518     if (daysRemaining == 0)
519     {
520         if (((repeats > 10) && (repeats < 15)) && (item->NUMOCCURRENCES < 0))
521             text = _("Inactive");
522     }
523 
524     if (daysRemaining < 0)
525     {
526         text = wxString::Format(_("%d days delay!"), abs(daysRemaining));
527         if (((repeats > 10) && (repeats < 15)) && (item->NUMOCCURRENCES < 0))
528             text = _("Inactive");
529     }
530 
531     if (daysOverdue < 0)
532     {
533         text = wxString::Format(_("%d days overdue!"), abs(daysOverdue));
534         if (((repeats > 10) && (repeats < 15)) && (item->NUMOCCURRENCES < 0))
535             text = _("Inactive");
536     }
537 
538     return text;
539 }
540 
OnGetItemText(long item,long column) const541 wxString billsDepositsListCtrl::OnGetItemText(long item, long column) const
542 {
543     return m_bdp->getItem(item, column);
544 }
545 
OnListItemSelected(wxListEvent & event)546 void billsDepositsListCtrl::OnListItemSelected(wxListEvent& event)
547 {
548     m_selected_row = event.GetIndex();
549     m_bdp->updateBottomPanelData(m_selected_row);
550 }
551 
OnListLeftClick(wxMouseEvent & event)552 void billsDepositsListCtrl::OnListLeftClick(wxMouseEvent& event)
553 {
554     int Flags = wxLIST_HITTEST_ONITEM;
555     long index = HitTest(wxPoint(event.m_x, event.m_y), Flags);
556     if (index == -1)
557     {
558         m_selected_row = -1;
559         m_bdp->updateBottomPanelData(m_selected_row);
560     }
561     event.Skip();
562 }
563 
OnGetItemImage(long item) const564 int billsDepositsListCtrl::OnGetItemImage(long item) const
565 {
566     bool bd_repeat_user = false;
567     bool bd_repeat_auto = false;
568     int repeats = m_bdp->bills_[item].REPEATS;
569     // DeMultiplex the Auto Executable fields.
570     if (repeats >= BD_REPEATS_MULTIPLEX_BASE)    // Auto Execute User Acknowlegement required
571     {
572         repeats -= BD_REPEATS_MULTIPLEX_BASE;
573         bd_repeat_user = true;
574     }
575     if (repeats >= BD_REPEATS_MULTIPLEX_BASE)    // Auto Execute Silent mode
576     {
577         repeats -= BD_REPEATS_MULTIPLEX_BASE;
578         bd_repeat_auto = true;
579     }
580 
581     int daysRemaining = Model_Billsdeposits::daysPayment(&m_bdp->bills_[item]);
582     wxString daysRemainingStr = wxString::Format(_("%d days remaining"), daysRemaining);
583 
584     if (daysRemaining == 0)
585     {
586         if (((repeats > 10) && (repeats < 15)) && (m_bdp->bills_[item].NUMOCCURRENCES < 0))
587             daysRemainingStr = _("Inactive");
588     }
589 
590     if (daysRemaining < 0)
591     {
592         daysRemainingStr = wxString::Format(_("%d days overdue!"), abs(daysRemaining));
593         if (((repeats > 10) && (repeats < 15)) && (m_bdp->bills_[item].NUMOCCURRENCES < 0))
594             daysRemainingStr = _("Inactive");
595     }
596 
597     /* Returns the icon to be shown for each entry */
598     if (daysRemainingStr == _("Inactive")) return -1;
599     if (daysRemaining < 0) return 0;
600     if (bd_repeat_auto) return 1;
601     if (bd_repeat_user) return 2;
602 
603     return -1;
604 }
605 
OnListKeyDown(wxListEvent & event)606 void billsDepositsListCtrl::OnListKeyDown(wxListEvent& event)
607 {
608   switch ( event.GetKeyCode() )
609     {
610         case WXK_DELETE:
611             {
612                 wxCommandEvent evt(wxEVT_COMMAND_MENU_SELECTED,
613                     MENU_TREEPOPUP_DELETE);
614                 OnDeleteBDSeries(evt);
615             }
616             break;
617 
618         default:
619             event.Skip();
620     }
621 }
622 
OnNewBDSeries(wxCommandEvent &)623 void billsDepositsListCtrl::OnNewBDSeries(wxCommandEvent& /*event*/)
624 {
625     mmBDDialog dlg(this, 0, false, false);
626     if ( dlg.ShowModal() == wxID_OK )
627         refreshVisualList(m_bdp->initVirtualListControl(dlg.GetTransID()));
628 }
629 
OnEditBDSeries(wxCommandEvent &)630 void billsDepositsListCtrl::OnEditBDSeries(wxCommandEvent& /*event*/)
631 {
632     if (m_selected_row == -1) return;
633 
634     mmBDDialog dlg(this, m_bdp->bills_[m_selected_row].BDID, true, false);
635     if ( dlg.ShowModal() == wxID_OK )
636         refreshVisualList(m_bdp->initVirtualListControl(dlg.GetTransID()));
637 }
638 
OnDeleteBDSeries(wxCommandEvent &)639 void billsDepositsListCtrl::OnDeleteBDSeries(wxCommandEvent& /*event*/)
640 {
641     if (m_selected_row < 0) return;
642     if (m_bdp->bills_.size() == 0) return;
643 
644     wxMessageDialog msgDlg(this, _("Do you really want to delete the series?")
645         , _("Confirm Series Deletion")
646         , wxYES_NO | wxNO_DEFAULT | wxICON_ERROR);
647     if (msgDlg.ShowModal() == wxID_YES)
648     {
649         int BdId = m_bdp->bills_[m_selected_row].BDID;
650         Model_Billsdeposits::instance().remove(BdId);
651         mmAttachmentManage::DeleteAllAttachments(Model_Attachment::reftype_desc(Model_Attachment::BILLSDEPOSIT), BdId);
652         m_bdp->initVirtualListControl();
653         refreshVisualList(m_selected_row);
654     }
655 }
656 
OnEnterBDTransaction(wxCommandEvent &)657 void billsDepositsListCtrl::OnEnterBDTransaction(wxCommandEvent& /*event*/)
658 {
659     if (m_selected_row == -1) return;
660 
661     int id = m_bdp->bills_[m_selected_row].BDID;
662     mmBDDialog dlg(this, id, false, true);
663     if ( dlg.ShowModal() == wxID_OK )
664         refreshVisualList(m_bdp->initVirtualListControl(id));
665 }
666 
OnSkipBDTransaction(wxCommandEvent &)667 void billsDepositsListCtrl::OnSkipBDTransaction(wxCommandEvent& /*event*/)
668 {
669     if (m_selected_row == -1) return;
670 
671     int id = m_bdp->bills_[m_selected_row].BDID;
672     Model_Billsdeposits::instance().completeBDInSeries(id);
673     refreshVisualList(m_bdp->initVirtualListControl(id));
674 }
675 
OnOrganizeAttachments(wxCommandEvent &)676 void billsDepositsListCtrl::OnOrganizeAttachments(wxCommandEvent& /*event*/)
677 {
678     if (m_selected_row == -1) return;
679 
680     int RefId = m_bdp->bills_[m_selected_row].BDID;
681     const wxString& RefType = Model_Attachment::reftype_desc(Model_Attachment::BILLSDEPOSIT);
682 
683     mmAttachmentDialog dlg(this, RefType, RefId);
684     dlg.ShowModal();
685 
686     refreshVisualList(m_bdp->initVirtualListControl(RefId));
687 }
688 
OnOpenAttachment(wxCommandEvent & event)689 void billsDepositsListCtrl::OnOpenAttachment(wxCommandEvent& event)
690 {
691     if (m_selected_row == -1) return;
692     int RefId = m_bdp->bills_[m_selected_row].BDID;
693     const wxString& RefType = Model_Attachment::reftype_desc(Model_Attachment::BILLSDEPOSIT);
694 
695     mmAttachmentManage::OpenAttachmentFromPanelIcon(this, RefType, RefId);
696     refreshVisualList(m_bdp->initVirtualListControl(RefId));
697 }
698 
OnListItemActivated(wxListEvent &)699 void billsDepositsListCtrl::OnListItemActivated(wxListEvent& /*event*/)
700 {
701     if (m_selected_row == -1) return;
702 
703     mmBDDialog dlg(this, m_bdp->bills_[m_selected_row].BDID, true, false);
704     if ( dlg.ShowModal() == wxID_OK )
705         refreshVisualList(m_bdp->initVirtualListControl(dlg.GetTransID()));
706 }
707 
updateBottomPanelData(int selIndex)708 void mmBillsDepositsPanel::updateBottomPanelData(int selIndex)
709 {
710     enableEditDeleteButtons(selIndex >= 0);
711     if (selIndex != -1)
712     {
713         m_infoTextMini->SetLabelText(Model_Category::full_name(bills_[selIndex].CATEGID, bills_[selIndex].SUBCATEGID));
714         m_infoText->SetLabelText(bills_[selIndex].NOTES);
715     }
716 }
717 
enableEditDeleteButtons(bool en)718 void mmBillsDepositsPanel::enableEditDeleteButtons(bool en)
719 {
720     wxButton* bE = (wxButton*) FindWindow(wxID_EDIT);
721     wxButton* bD = (wxButton*) FindWindow(wxID_DELETE);
722     wxButton* bN = (wxButton*) FindWindow(wxID_PASTE);
723     wxButton* bS = (wxButton*) FindWindow(wxID_IGNORE);
724     wxButton* bA = (wxButton*)FindWindow(wxID_FILE);
725     if (bE) bE->Enable(en);
726     if (bD) bD->Enable(en);
727     if (bN) bN->Enable(en);
728     if (bS) bS->Enable(en);
729     if (bA) bA->Enable(en);
730 
731     m_infoText->SetLabelText(this->tips());
732     m_infoTextMini->ClearBackground();
733 }
734 
sortTable()735 void mmBillsDepositsPanel::sortTable()
736 {
737     std::sort(bills_.begin(), bills_.end());
738     switch (listCtrlAccount_->m_selected_col)
739     {
740     case COL_ID:
741         std::stable_sort(bills_.begin(), bills_.end(), SorterByBDID());
742         break;
743     case COL_PAYMENT_DATE:
744         std::stable_sort(bills_.begin(), bills_.end(), SorterByNEXTOCCURRENCEDATE());
745         break;
746     case COL_DUE_DATE:
747         std::stable_sort(bills_.begin(), bills_.end(), SorterByTRANSDATE());
748         break;
749     case COL_ACCOUNT:
750         std::stable_sort(bills_.begin(), bills_.end(), SorterByACCOUNTNAME());
751         break;
752     case COL_PAYEE:
753         std::stable_sort(bills_.begin(), bills_.end(), SorterByPAYEENAME());
754         break;
755     case COL_STATUS:
756         std::stable_sort(bills_.begin(), bills_.end(), SorterBySTATUS());
757         break;
758     case COL_CATEGORY:
759         std::stable_sort(bills_.begin(), bills_.end(), SorterByCATEGNAME());
760         break;
761     case COL_TYPE:
762         std::stable_sort(bills_.begin(), bills_.end(), SorterByTRANSCODE());
763         break;
764     case COL_AMOUNT:
765         std::stable_sort(bills_.begin(), bills_.end(), SorterByTRANSAMOUNT());
766         break;
767     case COL_FREQUENCY:
768         std::stable_sort(bills_.begin(), bills_.end()
769             , [&](const Model_Billsdeposits::Full_Data& x, const Model_Billsdeposits::Full_Data& y)
770         {
771             wxString x_text = this->GetFrequency(&x);
772             wxString y_text = this->GetFrequency(&y);
773             return x_text < y_text;
774         });
775         break;
776     case COL_REPEATS:
777         std::stable_sort(bills_.begin(), bills_.end(), SorterByREPEATS());
778         break;
779     case COL_DAYS:
780         std::stable_sort(bills_.begin(), bills_.end()
781             , [&](const Model_Billsdeposits::Data& x, const Model_Billsdeposits::Data& y)
782         {
783             bool x_useText = false;
784             wxString x_text = this->GetRemainingDays(&x);
785             long x_num = 0;
786             if (isdigit(x_text[0]))
787             {
788                 x_num = wxAtoi(x_text);
789                 wxString removed;
790                 if (x_text.EndsWith(wxString("!"), &removed))
791                     x_num = -x_num;
792             }
793             else
794                 x_useText = true;
795 
796             bool y_useText = false;
797             wxString y_text = this->GetRemainingDays(&y);
798             long y_num = 0;
799             if (isdigit(y_text[0]))
800             {
801                 y_num = wxAtoi(y_text);
802                 wxString removed;
803                 if (y_text.EndsWith(wxString("!"), &removed))
804                     y_num = -y_num;
805             }
806             else
807                 y_useText = true;
808             return ((!x_useText && !y_useText) ? x_num < y_num : x_text < y_text);
809         });
810         break;
811     case COL_NOTES:
812         std::stable_sort(bills_.begin(), bills_.end(), SorterByNOTES());
813         break;
814     default:
815         break;
816     }
817     if (!listCtrlAccount_->m_asc) std::reverse(bills_.begin(), bills_.end());
818 }
819 
tips()820 wxString mmBillsDepositsPanel::tips()
821 {
822     return this->tips_[rand() % this->tips_.GetCount()];
823 }
824 
refreshVisualList(int selected_index)825 void billsDepositsListCtrl::refreshVisualList(int selected_index)
826 {
827 
828     if (selected_index >= (long)m_bdp->bills_.size() || selected_index < 0)
829         selected_index = - 1;
830     if (!m_bdp->bills_.empty()) {
831         RefreshItems(0, m_bdp->bills_.size() - 1);
832     }
833     else
834         selected_index = -1;
835 
836     if (selected_index >= 0 && !m_bdp->bills_.empty())
837     {
838         SetItemState(selected_index, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);
839         SetItemState(selected_index, wxLIST_STATE_FOCUSED, wxLIST_STATE_FOCUSED);
840         EnsureVisible(selected_index);
841     }
842     m_selected_row = selected_index;
843     m_bdp->updateBottomPanelData(selected_index);
844 }
845 
RefreshList()846 void billsDepositsListCtrl::RefreshList()
847 {
848     if (m_bdp->bills_.size() == 0) return;
849     int id = -1;
850     if (m_selected_row != -1)
851     {
852         id = m_bdp->bills_[m_selected_row].BDID;
853     }
854     refreshVisualList(m_bdp->initVirtualListControl(id));
855 }
856 
RefreshList()857 void mmBillsDepositsPanel::RefreshList()
858 {
859     listCtrlAccount_->RefreshList();
860 }
861 
OnFilterTransactions(wxMouseEvent & event)862 void mmBillsDepositsPanel::OnFilterTransactions(wxMouseEvent& event)
863 {
864 
865     int e = event.GetEventType();
866 
867     wxBitmap bitmapFilterIcon(rightarrow_xpm);
868 
869     if (e == wxEVT_LEFT_DOWN)
870     {
871 
872         if (transFilterDlg_->ShowModal() == wxID_OK && transFilterDlg_->somethingSelected())
873         {
874             transFilterActive_ = true;
875             wxBitmap activeBitmapFilterIcon(tipicon_xpm);
876             bitmapFilterIcon = activeBitmapFilterIcon;
877         }
878         else
879         {
880             transFilterActive_ = false;
881         }
882 
883     } else {
884         if (transFilterActive_ == false) return;
885         transFilterActive_ = false;
886     }
887 
888     wxImage pic = bitmapFilterIcon.ConvertToImage();
889     bitmapTransFilter_->SetBitmap(pic);
890 
891     initVirtualListControl();
892 }
893 
BuildPage() const894 wxString  mmBillsDepositsPanel::BuildPage() const
895 {
896     return listCtrlAccount_->BuildPage(_("Recurring Transactions"));
897 }