1 #include <CtrlLib/CtrlLib.h>
2 #include <DropGrid/DropGrid.h>
3 #include <GridCtrl/GridCtrl.h>
4 #include <plugin/sqlite3/Sqlite3.h>
5 
6 using namespace Upp;
7 
8 #define IMAGEFILE <HomeBudget/HomeBudget.iml>
9 #define IMAGECLASS Images
10 #include <Draw/iml.h>
11 
12 #define SCHEMADIALECT <plugin/sqlite3/Sqlite3Schema.h>
13 #define MODEL <HomeBudget/HomeBudget.sch>
14 
15 #include <Sql/sch_schema.h>
16 #include <Sql/sch_header.h>
17 #include <Sql/sch_source.h>
18 
19 #define LAYOUTFILE <HomeBudget/HomeBudget.lay>
20 #include <CtrlCore/lay.h>
21 
22 #define TOPICFILE <HomeBudget/src.tpp/all.i>
23 #include <Core/topic_group.h>
24 #define TOPICFILE <HomeBudget/help.tpp/all.i>
25 #include <Core/topic_group.h>
26 
27 #define TFILE <HomeBudget/HomeBudget.t>
28 #include <Core/t.h>
29 
30 #include "HomeBudget.h"
31 
32 struct ConvMonth : Convert
33 {
FormatConvMonth34 	Value Format(const Value &q) const
35 	{
36 		Date dt = (Date) q;
37 		return q.IsNull() ? "" : UPP::Format("%Month %.4d", dt.month, dt.year);
38 	}
39 };
40 
41 struct ConvDouble : Convert
42 {
FormatConvDouble43 	Value Format(const Value &q) const
44 	{
45 		return q.IsNull() ? Null : UPP::Format("%.2f", q);
46 	}
47 };
48 
49 struct DispPM : GridDisplay
50 {
PaintDispPM51 	virtual void Paint(Draw &w, int x, int y, int cx, int cy, const Value &val, dword style,
52 			           Color &fg, Color &bg, Font &fnt, bool found, int fs, int fe)
53 	{
54 		if(!val.IsNull())
55 		{
56 			int t = int(val) < 0 ? 0 : 1;
57 			SetCenterImage(t ? Images::Plus : Images::Minus);
58 		}
59 		else
60 			SetCenterImage(Null);
61 		GridDisplay::Paint(w, x, y, cx, cy, Value(""), style, fg, bg, fnt, found, fs, fe);
62 	}
63 };
64 
HomeBudget()65 HomeBudget::HomeBudget()
66 {
67 	lang = 0;
68 }
69 
Setup()70 void HomeBudget::Setup()
71 {
72 	CtrlLayout(*this, String(t_("Home budget")) + " 1.0");
73 
74 	Icon(Images::SmallIcon());
75 	LargeIcon(Images::LargeIcon());
76 
77 	tab.Add(money.SizePos(), t_("Expenses"));
78 	tab.Add(spl.Horz(groups, categories), t_("Categories"));
79 	spl.SetPos(2000);
80 
81 	money.AddIndex(ID);
82 	money.AddColumn(CAT_ID, t_("Category")).Edit(category).SetConvert(category);
83 	money.AddColumn(PM, t_("Plus / Minus")).SetDisplay(Single<DispPM>()).Edit(plusminus);
84 	money.AddColumn(VALUE, t_("Value")).Edit(val).Default(0).SetConvert(Single<ConvDouble>());
85 	money.AddColumn(DT, t_("When")).Edit(dt).Default(GetSysDate());
86 	money.AddColumn(DESC, t_("Describe")).Edit(es);
87 	money.Appending().Removing().Editing().Accepting().Canceling();
88 	money.RejectNullRow();
89 	money.WhenInsertRow = THISBACK(InsertMoney);
90 	money.WhenUpdateRow = THISBACK(UpdateMoney);
91 	money.WhenRemoveRow = THISBACK(RemoveMoney);
92 	money.SetToolBar();
93 
94 	Date dt = GetSysDate();
95 	dt.day = 1;
96 
97 	month.AddIndex(ID);
98 	month.AddColumn(DT, t_("Month")).Edit(months).SetConvert(Single<ConvMonth>()).Default(dt);
99 	month.Appending().Removing().Editing().Accepting().Canceling();
100 	month.WhenInsertRow = THISBACK(InsertDate);
101 	month.WhenUpdateRow = THISBACK(UpdateDate);
102 	month.WhenRemoveRow = THISBACK(RemoveDate);
103 	month.WhenChangeRow = THISBACK(ChangeDate);
104 	month.WhenAcceptedRow = THISBACK(AcceptedDate);
105 	month.WhenNewRow    = THISBACK(NewDate);
106 	month.SetToolBar();
107 
108 	groups.AddIndex(ID);
109 	groups.AddColumn(NAME, t_("Name")).Edit(eg);
110 	groups.Appending().Removing().Editing().Accepting().Canceling();
111 	groups.RejectNullRow();
112 	groups.SetToolBar();
113 	groups.WhenInsertRow = THISBACK(InsertGroup);
114 	groups.WhenUpdateRow = THISBACK(UpdateGroup);
115 	groups.WhenRemoveRow = THISBACK(RemoveGroup);
116 	groups.WhenChangeRow = THISBACK(ChangeGroup);
117 
118 	categories.AddIndex(ID);
119 	categories.AddColumn(NAME, t_("Name")).Edit(ec);
120 	categories.AddColumn(DEFVALUE, t_("Default value")).Edit(defval).SetConvert(Single<ConvDouble>());
121 	categories.AddColumn(PM, t_("Plus / Minus")).Edit(dlpm).SetConvert(dlpm).Default(-1);
122 	categories.AddColumn(INNEWMONTH, t_("Default for a new month")).Edit(yesno).SetConvert(yesno).Default(0);
123 	categories.WhenInsertRow = THISBACK(InsertCategory);
124 	categories.WhenUpdateRow = THISBACK(UpdateCategory);
125 	categories.WhenRemoveRow = THISBACK(RemoveCategory);
126 	categories.WhenAcceptedRow = THISBACK(UpdateCategories);
127 	categories.Appending().Removing().Editing();
128 	categories.RejectNullRow();
129 	categories.SetToolBar();
130 
131 	mostpr.AddColumn(t_("Name"));
132 	mostpr.AddColumn(t_("Amount")).SetConvert(Single<ConvDouble>()).AlignCenter();
133 	mostcat.AddColumn(t_("Name"));
134 	mostcat.AddColumn(t_("Amount")).SetConvert(Single<ConvDouble>()).AlignCenter();
135 
136 	tabmost.Add(mostpr.SizePos(), t_("Product"));
137 	tabmost.Add(mostcat.SizePos(), t_("Category"));
138 
139 	dlpm.Add(-1, t_("Minus")).Add(1, t_("Plus"));
140 	plusminus.Add(-1, t_("Minus")).Add(1, t_("Plus"));
141 	yesno.Add(0, t_("No")).Add(1, t_("Yes"));
142 
143 	GenMonthList(dt.year);
144 
145 	SQL * Delete(MONEY).Where(IsNull(CAT_ID));
146 
147 	LoadDates();
148 	LoadGroups();
149 
150 	UpdateCategories();
151 
152 	if(month.GetCount() > 0)
153 	{
154 		month.GoEnd();
155 		UpdateSummary();
156 	}
157 
158 	EnableMoney();
159 	Sizeable().Zoomable();
160 
161 	category <<= THISBACK(UpdateValue);
162 	exit <<= THISBACK(Close);
163 	options <<= THISBACK(Options);
164 	about <<= THISBACK(About);
165 	help <<= THISBACK(Help);
166 
167 	category.Resizeable(false).Header(false);
168 	category.AddPlus(THISBACK(NewCategory));
169 }
170 
Serialize(Stream & s)171 void HomeBudget::Serialize(Stream &s)
172 {
173 	int version = 1;
174 	s / version;
175 	SerializePlacement(s);
176 	s % spl;
177 	s % lang;
178 	//s % categories;
179 	//s % money;
180 }
181 
GenMonthList(int year)182 void HomeBudget::GenMonthList(int year)
183 {
184 	months.Clear();
185 
186 	int curr_year = GetSysDate().year;
187 	int max_year = max(year,curr_year);
188 
189 	for(int scan_year = min(year, curr_year) - 1; scan_year <= max_year; scan_year++)
190 		for(int i = 0; i < 12; i++)
191 			months.Add(Date(scan_year, i + 1, 1), Format("%Month %.4d", i + 1, scan_year));
192 }
193 
LoadMoney(int dtid)194 void HomeBudget::LoadMoney(int dtid)
195 {
196 	money.Clear();
197 	SQL * Select(ID, CAT_ID, PM, VALUE, DT, DESC).From(MONEY).Where(DT_ID == dtid);
198 	while(SQL.Fetch())
199 	{
200 		money.Add();
201 		money(ID) = SQL[ID];
202 		money(CAT_ID) = SQL[CAT_ID];
203 		money(PM) = SQL[PM];
204 		money(VALUE) = SQL[VALUE];
205 		money(DT) = SQL[DT];
206 		money(DESC) = SQL[DESC];
207 	}
208 }
209 
LoadDates()210 void HomeBudget::LoadDates()
211 {
212 	month.Clear();
213 	SQL * Select(ID, DT).From(DATES);
214 	while(SQL.Fetch())
215 		month.Add(SQL);
216 }
217 
LoadGroups()218 void HomeBudget::LoadGroups()
219 {
220 	groups.Clear();
221 	SQL * Select(ID, NAME).From(GROUPS);
222 	while(SQL.Fetch())
223 		groups.Add(SQL);
224 
225 	if(!groups.IsEmpty())
226 		groups.SetCursor(0);
227 	else
228 		categories.Disable();
229 }
230 
LoadCategories(int group_id)231 void HomeBudget::LoadCategories(int group_id)
232 {
233 	categories.Clear();
234 	SQL * Select(ID, NAME, DEFVALUE, PM, INNEWMONTH).From(CATEGORIES).Where(GR_ID == group_id);
235 	while(SQL.Fetch())
236 		categories.Add(SQL);
237 }
238 
GetCategorySign()239 int HomeBudget::GetCategorySign()
240 {
241 	SQL * Select(PM).From(CATEGORIES).Where(ID == money.Get(CAT_ID));
242 	Value v = SQL.Fetch() ? SQL[0] : Value(0);
243 	return v;
244 }
245 
UpdateCategories()246 void HomeBudget::UpdateCategories()
247 {
248 	category.Clear();
249 	SQL & Select(ID.Of(CATEGORIES), NAME.Of(CATEGORIES), NAME.Of(GROUPS))
250 		.From(CATEGORIES, GROUPS)
251 		.Where(GR_ID == ID.Of(GROUPS))
252 		.OrderBy(NAME.Of(GROUPS), NAME.Of(CATEGORIES));
253 
254 	while(SQL.Fetch())
255 		category.Add(SQL[0], Format("%s - %s", SQL[2], SQL[1]));
256 }
257 
InsertGroup()258 void HomeBudget::InsertGroup()
259 {
260 	try
261 	{
262 		SQL & Insert(GROUPS)
263 			(NAME, groups(1));
264 		groups(0) = SQL.GetInsertedId();
265 
266 		categories.Clear();
267 		categories.Enable();
268 	}
269 	catch(SqlExc &e)
270 	{
271 		groups.CancelInsert();
272 		Exclamation("[* " + DeQtfLf(e) + "]");
273 	}
274 
275 }
276 
UpdateGroup()277 void HomeBudget::UpdateGroup()
278 {
279 	try
280 	{
281 		SQL & ::Update(GROUPS)
282 			(NAME, groups(1))
283 			.Where(ID == groups(0));
284 	}
285 	catch(SqlExc &e)
286 	{
287 		groups.CancelUpdate();
288 		Exclamation("[* " + DeQtfLf(e) + "]");
289 	}
290 }
291 
RemoveGroup()292 void HomeBudget::RemoveGroup()
293 {
294 	if(categories.IsEmpty())
295 	{
296 		SQL & Delete(GROUPS).Where(ID == groups(ID));
297 
298 		if(groups.GetCount() == 1)
299 			categories.Disable();
300 	}
301 	else
302 	{
303 		PromptOK(t_("You can't remove this group. It is not empty."));
304 		groups.CancelRemove();
305 	}
306 }
307 
308 struct AddNewCat : WithNewCategoryLayout<TopWindow>
309 {
310 	typedef AddNewCat CLASSNAME;
311 	bool newgroup;
312 
AddNewCatAddNewCat313 	AddNewCat()
314 	{
315 		newgroup = false;
316 		CtrlLayoutOKCancel(*this, t_("New item"));
317 		addgroup.SetImage(Images::SmallPlus());
318 		addgroup <<= THISBACK(NewGroup);
319 		groups <<= THISBACK(SelGroup);
320 		addgroup.NoWantFocus();
321 
322 		int cnt = 0;
323 		SQL * Select(ID, NAME).From(GROUPS);
324 		while(SQL.Fetch())
325 		{
326 			groups.Add(SQL[ID], SQL[NAME]);
327 			cnt++;
328 		}
329 
330 		bool isgroup = cnt > 0;
331 		if(isgroup)
332 			groups.SetIndex(0);
333 		else
334 			ok.Disable();
335 
336 		pm = 1;
337 	}
338 
SelGroupAddNewCat339 	void SelGroup()
340 	{
341 		ok.Enable();
342 	}
343 
NewGroupAddNewCat344 	void NewGroup()
345 	{
346 		WithNewGroupLayout<TopWindow> dlg;
347 		CtrlLayoutOKCancel(dlg, t_("New category"));
348 		if(dlg.Execute() == IDOK)
349 		{
350 			try
351 			{
352 				SQL & Insert(GROUPS)(NAME, ~dlg.name);
353 				int64 id = SQL.GetInsertedId();
354 				groups.Add(id, ~dlg.name);
355 				groups <<= id;
356 				ok.Enable();
357 				newgroup = true;
358 			}
359 			catch(SqlExc &e)
360 			{
361 				Exclamation("[* " + DeQtfLf(e) + "]");
362 			}
363 		}
364 	}
IsNewGroupAddNewCat365 	bool IsNewGroup() { return newgroup; }
366 };
367 
NewCategory()368 void HomeBudget::NewCategory()
369 {
370 	AddNewCat dlg;
371 
372 	if(dlg.Execute() == IDOK)
373 	{
374 		try
375 		{
376 			SQL & Insert(CATEGORIES)
377 			    (GR_ID, ~dlg.groups)
378 				(NAME, ~dlg.name)
379 				(DEFVALUE, 0)
380 				(PM, dlg.pm == 0 ? 1 : -1)
381 				(INNEWMONTH, 0);
382 
383 			int64 id = SQL.GetInsertedId();
384 			UpdateCategories();
385 			money.Set(CAT_ID, id);
386 			UpdateValue();
387 
388 			int gid = ~dlg.groups;
389 
390 			if(dlg.IsNewGroup())
391 			{
392 				groups.Add(Value(gid), dlg.groups.GetValue());
393 				groups.GoEnd();
394 				categories.Enable();
395 			}
396 			int c = groups.GetCursor();
397 			if(c >= 0 && gid == groups(c, 0))
398 				LoadCategories(gid);
399 		}
400 		catch(SqlExc &e)
401 		{
402 			Exclamation("[* " + DeQtfLf(e) + "]");
403 		}
404 	}
405 }
406 
InsertCategory()407 void HomeBudget::InsertCategory()
408 {
409 	try
410 	{
411 		SQL & Insert(CATEGORIES)
412 		    (GR_ID, groups(ID))
413 			(NAME, categories(NAME))
414 			(DEFVALUE, categories(DEFVALUE))
415 			(PM, categories(PM))
416 			(INNEWMONTH, categories(INNEWMONTH));
417 
418 		categories(0) = SQL.GetInsertedId();
419 	}
420 	catch(SqlExc &e)
421 	{
422 		categories.CancelInsert();
423 		Exclamation("[* " + DeQtfLf(e) + "]");
424 	}
425 
426 }
427 
UpdateCategory()428 void HomeBudget::UpdateCategory()
429 {
430 	try
431 	{
432 		SQL & ::Update(CATEGORIES)
433 			(NAME, categories(NAME))
434 			(DEFVALUE, categories(DEFVALUE))
435 			(PM, categories(PM))
436 			(INNEWMONTH, categories(INNEWMONTH))
437 			.Where(ID == categories(ID));
438 
439 		UpdateSummary();
440 	}
441 	catch(SqlExc &e)
442 	{
443 		categories.CancelUpdate();
444 		Exclamation("[* " + DeQtfLf(e) + "]");
445 	}
446 }
447 
ChangeGroup()448 void HomeBudget::ChangeGroup()
449 {
450 	LoadCategories(groups(ID));
451 }
452 
RemoveCategory()453 void HomeBudget::RemoveCategory()
454 {
455 	try
456 	{
457 		SQL * Select(CAT_ID, NAME)
458 			.From(MONEY, CATEGORIES)
459 			.Where(CAT_ID == categories(ID) && ID.Of(CATEGORIES) == categories(ID))
460 			.Limit(1);
461 
462 		if(SQL.Fetch())
463 		{
464 			PromptOK(Format(t_("Item '%s' can't be removed. It is used in calculations."), AsString(SQL[1])));
465 			categories.CancelRemove();
466 		}
467 		else
468 		{
469 			SQL & Delete(CATEGORIES).Where(ID == categories(ID));
470 			UpdateCategories();
471 		}
472 	}
473 	catch(SqlExc &e)
474 	{
475 		categories.CancelRemove();
476 		Exclamation("[* " + DeQtfLf(e) + "]");
477 	}
478 }
479 
InsertMoney()480 void HomeBudget::InsertMoney()
481 {
482 	try
483 	{
484 		SQL & Insert(MONEY)
485 			(DT_ID,  dtid)
486 			(CAT_ID, money(CAT_ID))
487 			(PM,     money(PM))
488 			(VALUE,  money(VALUE))
489 			(DT,     money(DT))
490 			(DESC,   money(DESC));
491 
492 		money(ID) = SQL.GetInsertedId();
493 
494 		UpdateSummary();
495 	}
496 	catch(SqlExc &e)
497 	{
498 		money.CancelInsert();
499 		Exclamation("[* " + DeQtfLf(e) + "]");
500 	}
501 }
502 
UpdateMoney()503 void HomeBudget::UpdateMoney()
504 {
505 	try
506 	{
507 		SQL & ::Update(MONEY)
508 			(DT_ID,  dtid)
509 			(CAT_ID, money(CAT_ID))
510 			(PM,     money(PM))
511 			(VALUE,  money(VALUE))
512 			(DT,     money(DT))
513 			(DESC,   money(DESC))
514 			.Where(ID == money(ID));
515 
516 		UpdateSummary();
517 	}
518 	catch(SqlExc &e)
519 	{
520 		money.CancelUpdate();
521 		Exclamation("[* " + DeQtfLf(e) + "]");
522 	}
523 }
524 
RemoveMoney()525 void HomeBudget::RemoveMoney()
526 {
527 	try
528 	{
529 		SQL & Delete(MONEY).Where(ID == money(ID));
530 		UpdateSummary();
531 	}
532 	catch(SqlExc &e)
533 	{
534 		money.CancelRemove();
535 		Exclamation("[* " + DeQtfLf(e) + "]");
536 	}
537 }
538 
InsertDate()539 void HomeBudget::InsertDate()
540 {
541 	try
542 	{
543 		SQL & Insert(DATES)(DT, month(DT));
544 		month(ID) = dtid = (int) SQL.GetInsertedId();
545 		EnableMoney();
546 	}
547 	catch(SqlExc &e)
548 	{
549 		month.CancelInsert();
550 		Exclamation("[* " + DeQtfLf(e) + "]");
551 	}
552 }
553 
EnableMoney(int cnt)554 void HomeBudget::EnableMoney(int cnt)
555 {
556 	money.Enable(cnt < 0 ? month.GetCount() > 0 : cnt);
557 }
558 
UpdateDate()559 void HomeBudget::UpdateDate()
560 {
561 	try
562 	{
563 		SQL & ::Update(DATES)(DT, month(DT)).Where(ID == month(ID));
564 	}
565 	catch(SqlExc &e)
566 	{
567 		month.CancelUpdate();
568 		Exclamation("[* " + DeQtfLf(e) + "]");
569 	}
570 }
571 
RemoveDate()572 void HomeBudget::RemoveDate()
573 {
574 	try
575 	{
576 		SQL.Begin();
577 		SQL & Delete(MONEY).Where(DT_ID == month(ID));
578 		SQL & Delete(DATES).Where(ID == month(ID));
579 		SQL.Commit();
580 		bool en = month.GetCount() <= 1 ? false : true;
581 		EnableMoney(en);
582 		if(!en)
583 			money.Clear();
584 	}
585 	catch(SqlExc &e)
586 	{
587 		SQL.Rollback();
588 		month.CancelRemove();
589 		Exclamation("[* " + DeQtfLf(e) + "]");
590 	}
591 
592 }
593 
ChangeDate()594 void HomeBudget::ChangeDate()
595 {
596 	dtid = month(ID);
597 	LoadMoney(dtid);
598 	EnableMoney();
599 	UpdateSummary();
600 	GenMonthList(((Date) month(DT)).year);
601 }
602 
NewDate()603 void HomeBudget::NewDate()
604 {
605 	money.Clear();
606 	money.Disable();
607 	UpdateSummary();
608 }
609 
AcceptedDate()610 void HomeBudget::AcceptedDate()
611 {
612 	if(!month.IsNewRow())
613 		return;
614 
615 	Sql q;
616 	SQL.Begin();
617 	SQL * Select(ID, DEFVALUE, PM).From(CATEGORIES).Where(INNEWMONTH == 1);
618 	while(SQL.Fetch())
619 	{
620 		money.Add();
621 		money(CAT_ID) = SQL[ID];
622 		money(VALUE) = SQL[DEFVALUE];
623 		money(PM) = SQL[PM];
624 
625 		q * Insert(MONEY)
626 			(DT_ID,  dtid)
627 			(CAT_ID, money(CAT_ID))
628 			(PM,     money(PM))
629 			(VALUE,  money(VALUE))
630 			(DT,     money(DT))
631 			(DESC,   money(DESC));
632 
633 		money(ID) = SQL.GetInsertedId();
634 
635 		money.RefreshNewRow();
636 	}
637 	SQL.Commit();
638 	UpdateSummary();
639 }
640 
UpdateSummary()641 void HomeBudget::UpdateSummary()
642 {
643 	if(!month.IsCursor())
644 		return;
645 
646 	float p = 0, tp = 0;
647 	float m = 0, tm = 0;
648 	float r = 0, tr = 0;
649 
650 	mostcat.Clear();
651 	mostpr.Clear();
652 
653 	try
654 	{
655 		SQL & Select(PM, SqlSum(VALUE))
656 			.From(MONEY, DATES)
657 			.Where(DT.Of(DATES) < month(DT) && DT_ID == ID.Of(DATES) && NotNull(VALUE))
658 			.GroupBy(PM);
659 
660 		while(SQL.Fetch())
661 		{
662 			int pm = SQL[PM];
663 			float v = (float) int(SQL[1]);
664 			if(pm < 0)
665 				tm = v;
666 			else
667 				tp = v;
668 		}
669 
670 		tr = tp - tm;
671 
672 		SQL & Select(PM, SqlSum(VALUE))
673 			.From(MONEY)
674 			.Where(DT_ID == dtid && NotNull(VALUE))
675 			.GroupBy(PM);
676 
677 		while(SQL.Fetch())
678 		{
679 			int pm = SQL[PM];
680 			float v = (float) int(SQL[1]);
681 			if(pm < 0)
682 				m = v;
683 			else
684 				p = v;
685 		}
686 
687 		SQL & Select(NAME, SqlId("sum(value) as val"))
688 			.From(MONEY, CATEGORIES)
689 			.Where(DT_ID == dtid && CAT_ID == ID.Of(CATEGORIES) && PM.Of(MONEY) < 0)
690 			.GroupBy(CAT_ID)
691 			.OrderBy(Descending(SqlId("val")));
692 
693 		while(SQL.Fetch())
694 			mostpr.Add(SQL);
695 
696 		SQL & Select(NAME.Of(GROUPS), SqlId("sum(value) as val"))
697 			.From(MONEY, GROUPS, CATEGORIES)
698 			.Where(DT_ID == dtid && PM.Of(MONEY) < 0 && CAT_ID == ID.Of(CATEGORIES) && GR_ID == ID.Of(GROUPS))
699 			.GroupBy(GR_ID)
700 			.OrderBy(Descending(SqlId("val")));
701 
702 		while(SQL.Fetch())
703 			mostcat.Add(SQL);
704 	}
705 	catch(SqlExc &e)
706 	{
707 		Exclamation("[* " + DeQtfLf(e) + "]");
708 	}
709 
710 	r = p - m;
711 	plus.SetText(Format("%.2f", p));
712 	minus.SetText(Format("%.2f", m));
713 	SetRest(rest, r);
714 	SetRest(prev_month, tr);
715 	SetRest(real_rest, r + tr);
716 }
717 
ClearSummary()718 void HomeBudget::ClearSummary()
719 {
720 	plus.SetText("");
721 	minus.SetText("");
722 	rest.SetText("");
723 	prev_month.SetText("");
724 	real_rest.SetText("");
725 	mostpr.Clear();
726 	mostcat.Clear();
727 }
728 
SetRest(StaticText & rest,float r)729 void HomeBudget::SetRest(StaticText &rest, float r)
730 {
731 	if(r == 0)
732 	{
733 		rest.SetText("0.00");
734 		rest.SetInk(Black);
735 	}
736 	else if(r > 0)
737 	{
738 		rest.SetText(Format("+%.2f", r));
739 		rest.SetInk(Green);
740 	}
741 	else
742 	{
743 		rest.SetText(Format("%.2f", r));
744 		rest.SetInk(LtRed);
745 	}
746 }
747 
UpdateValue()748 void HomeBudget::UpdateValue()
749 {
750 	if(money.IsEmpty())
751 		return;
752 
753 	try
754 	{
755 		SQL & Select(DEFVALUE, PM).From(CATEGORIES).Where(ID == money.Get(CAT_ID));
756 		Value v = SQL.Fetch() ? SQL[0] : Value(0);
757 		Value s = SQL.Fetch() ? SQL[1] : Value(-1);
758 
759 		if(IsNull(money.Get(VALUE)))
760 			money.Set(VALUE, v);
761 
762 		if(IsNull(money.Get(PM)))
763 			money.Set(PM, s);
764 	}
765 	catch(SqlExc &e)
766 	{
767 		Exclamation("[* " + DeQtfLf(e) + "]");
768 	}
769 }
770 
Options()771 void HomeBudget::Options()
772 {
773 	WithOptionsLayout<TopWindow> dlg;
774 	CtrlLayoutOK(dlg, t_("Options"));
775 	dlg.lang.Add(0, "English")
776 	        .Add(1, "Česky")
777 	        .Add(2, "Polski")
778 	        .SetIndex(lang);
779 	dlg.clear <<= THISBACK(ClearAll);
780 	if(dlg.Execute() != IDOK)
781 		return;
782 	lang = ~dlg.lang;
783 }
784 
ClearAll()785 void HomeBudget::ClearAll()
786 {
787 	try
788 	{
789 		SQL & Delete(CATEGORIES);
790 		SQL & Delete(GROUPS);
791 		SQL & Delete(MONEY);
792 		SQL & Delete(DATES);
793 		//SQL.ExecuteX("VACUUM");
794 
795 		LoadDates();
796 		LoadGroups();
797 		UpdateCategories();
798 		money.Clear();
799 		categories.Clear();
800 		EnableMoney();
801 
802 		PromptOK(t_("Database was cleared"));
803 	}
804 	catch(SqlExc &e)
805 	{
806 		Exclamation("[* " + DeQtfLf(e) + "]");
807 	}
808 }
809 
About()810 void HomeBudget::About()
811 {
812 	WithAboutLayout<TopWindow> dlg;
813 	CtrlLayoutCancel(dlg, t_("About"));
814 	dlg.info.NoSb();
815 	dlg.info.SetQTF(GetTopic(String("HomeBudget/src/About$") + (lang == 0 ? "en-us" : "pl-pl")), Zoom(150, 1400));
816 	dlg.info.SetZoom(Zoom(1, 1));
817 	dlg.Execute();
818 }
819 
Help()820 void HomeBudget::Help()
821 {
822 	PromptOK(t_("No help available yet"));
823 /*	HomeBudgetHelp dlg;
824 	dlg.AddTree(0, Images::Plus(), "HomeBudget/help/Introduction$pl-pl", "Wprowadzenie");
825 	dlg.AddTree(0, Images::Plus(), "HomeBudget/help/T0$pl-pl", "Instrukcja");
826 	dlg.AddTree(0, Images::Plus(), "HomeBudget/src/About$pl-pl", "ala");
827 	dlg.Execute();
828 */
829 }
830 
HomeBudgetHelp()831 HomeBudgetHelp::HomeBudgetHelp()
832 {
833 }
834 
AcquireTopic(const String & topic)835 Topic HomeBudgetHelp::AcquireTopic(const String& topic)
836 {
837 	Topic t;
838 	t = GetTopic(topic);
839 	t.text = (const char *) GetTopic(topic);
840 	//String path = topic;
841 	//if(FileExists(path))
842 	//	t.text = ReadTopic(LoadFile(path)) .text;
843 	return t;
844 }
845 
846 GUI_APP_MAIN
847 {
848 	bool nodb = false;
849 	Sqlite3Session db;
850 	db.LogErrors(true);
851 
852 	#ifdef flagDEBUG
853 	db.SetTrace();
854 	nodb = true;
855 	#endif
856 
857 	FileIn fi("HomeBudget.db3");
858 	if(fi.IsError() || fi.GetSize() <= 0)
859 		nodb = true;
860 	fi.Close();
861 
862 	if(!db.Open(ConfigFile("HomeBudget.db3")))
863 	{
864 		Exclamation(t_("Can't create or open database file"));
865 		return;
866 	}
867 
868 	SQL = db;
869 
870 	if(nodb)
871 	{
872 		SqlSchema sch(SQLITE3);
873 		StdStatementExecutor se(db);
874 		All_Tables(sch);
875 		if(sch.ScriptChanged(SqlSchema::UPGRADE))
876 			Sqlite3PerformScript(sch.Upgrade(), se);
877 		if(sch.ScriptChanged(SqlSchema::ATTRIBUTES))
878 		{
879 			Sqlite3PerformScript(sch.Attributes(), se);
880 		}
881 		if(sch.ScriptChanged(SqlSchema::CONFIG))
882 		{
883 			Sqlite3PerformScript(sch.ConfigDrop(), se);
884 			Sqlite3PerformScript(sch.Config(), se);
885 		}
886 		sch.SaveNormal();
887 	}
888 
889 	HomeBudget hb;
890 
891 	LoadFromFile(hb);
892 
893 	switch(hb.lang) {
894 	case 1:
895 		SetLanguage(LNGC_('C','S','C','Z', CHARSET_UNICODE));
896 		break;
897 	case 2:
898 		SetLanguage(LNGC_('P','L','P','L', CHARSET_UNICODE));
899 		break;
900 	default:
901 		SetLanguage(LNGC_('E','N','U','S', CHARSET_UNICODE));
902 		break;
903 	}
904 	hb.Setup();
905 	hb.Run();
906 	StoreToFile(hb);
907 }
908