kplato

kptaccountsview.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2005 Dag Andersen kplato@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation;
7 version 2 of the License.
8
9 This library 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 GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include "kptaccountsview.h"
21
22#include "kptaccountsviewconfigdialog.h"
23#include "kptcontext.h"
24#include "kptdatetime.h"
25#include "kptproject.h"
26#include "kptview.h"
27#include "kpteffortcostmap.h"
28
29#include <tqapplication.h>
30#include <tqcombobox.h>
31#include <tqdatetime.h>
32#include <tqdatetimeedit.h>
33#include <tqheader.h>
34#include <tqlabel.h>
35#include <tqlayout.h>
36#include <tqpainter.h>
37#include <tqpalette.h>
38#include <tqpushbutton.h>
39#include <tqvaluelist.h>
40#include <tqpopupmenu.h>
41#include <tqsizepolicy.h>
42#include <tqhbox.h>
43#include <tqpaintdevicemetrics.h>
44
45#include <kcalendarsystem.h>
46#include <tdeglobal.h>
47#include <tdelistview.h>
48#include <tdelocale.h>
49#include <kprinter.h>
50
51#include <kdebug.h>
52
53namespace KPlato
54{
55
56class Label : public TQLabel
57{
58public:
59 Label(TQWidget *w)
60 : TQLabel(w)
61 {}
62 void paintContents(TQPainter *p) {
63 drawContents(p);
64 }
65};
66
67AccountsView::AccountItem::AccountItem(Account *a, TQListView *parent, bool highlight)
68 : DoubleListViewBase::MasterListItem(parent, a->name(), highlight),
69 account(a) {
70 if (parent->columns() >= 3) {
71 setText(2, a->description());
72 }
73 //kdDebug()<<k_funcinfo<<endl;
74}
75AccountsView::AccountItem::AccountItem(Account *a, TQListViewItem *p, bool highlight)
76 : DoubleListViewBase::MasterListItem(p, a->name(), highlight),
77 account(a) {
78 if (listView() && listView()->columns() >= 3) {
79 setText(2, a->description());
80 }
81 //kdDebug()<<k_funcinfo<<endl;
82}
83
84AccountsView::AccountItem::AccountItem(TQString text, Account *a, TQListViewItem *parent, bool highlight)
85 : DoubleListViewBase::MasterListItem(parent, text, highlight),
86 account(a) {
87 //kdDebug()<<k_funcinfo<<endl;
88}
89
90void AccountsView::AccountItem::add(int col, const TQDate &date, const EffortCost &ec) {
91 EffortCost &cm = costMap.add(date, ec);
92 if (m_slaveItem)
93 m_slaveItem->setText(col, TDEGlobal::locale()->formatMoney(cm.cost(), "", 0));
94}
95
96AccountsView::AccountsView(Project &project, View *view, TQWidget *parent)
97 : TQWidget(parent, "Accounts view"),
98 m_mainview(view),
99 m_project(project),
100 m_accounts(project.accounts()) {
101
102 m_date = TQDate::currentDate();
103 m_period = 0;
104 m_periodTexts<<i18n("Day")<<i18n("Week")<<i18n("Month");
105 m_cumulative = false;
106
107 TQVBoxLayout *lay1 = new TQVBoxLayout(this, 0, KDialog::spacingHint());
108
109 TQHBoxLayout *lay2 = new TQHBoxLayout(0, 0, KDialog::spacingHint());
110 m_label = new Label(this);
111 m_label->setFrameShape(TQLabel::StyledPanel);
112 m_label->setFrameShadow(TQLabel::Sunken);
113 m_label->setAlignment(int(TQLabel::WordBreak | TQLabel::AlignVCenter));
114 lay2->addWidget(m_label);
115 m_changeBtn = new TQPushButton(i18n("Configure..."), this);
116 m_changeBtn->setSizePolicy(TQSizePolicy((TQSizePolicy::SizeType)0, (TQSizePolicy::SizeType)0, 0, 0, m_changeBtn->sizePolicy().hasHeightForWidth()));
117 lay2->addWidget(m_changeBtn);
118 lay1->addLayout(lay2);
119
120 m_dlv = new DoubleListViewBase(this, true);
121 m_dlv->setNameHeader(i18n("Account"));
122
123 init();
124
125 lay1->addWidget(m_dlv);
126
127 connect(this, TQ_SIGNAL(update()), TQ_SLOT(slotUpdate()));
128 connect(m_changeBtn, TQ_SIGNAL(clicked()), TQ_SLOT(slotConfigure()));
129
130 TQValueList<int> list = m_dlv->sizes();
131 int tot = list[0] + list[1];
132 list[0] = TQMIN(35, tot);
133 list[1] = tot-list[0];
134 m_dlv->setSizes(list);
135}
136
137void AccountsView::zoom(double zoom) {
138 Q_UNUSED(zoom);
139}
140
141void AccountsView::init() {
142 m_date = TQDate::currentDate();
143 m_period = 0;
144 initAccList(m_accounts.accountList());
145}
146
147void AccountsView::draw() {
148 //kdDebug()<<k_funcinfo<<endl;
149 Context::Accountsview context;
150 getContextClosedItems(context, m_dlv->masterListView()->firstChild());
151 initAccList(m_accounts.accountList());
152 setContextClosedItems(context);
153 slotUpdate();
154}
155
156void AccountsView::initAccList(const AccountList &list) {
157 m_dlv->clearLists();
158 AccountListIterator it = list;
159 for (it.toLast(); it.current(); --it) {
160 AccountsView::AccountItem *a = new AccountsView::AccountItem(it.current(), m_dlv->masterListView());
161 a->setOpen(true);
162 a->setExpandable(!it.current()->isElement());
163 initAccSubItems(it.current(), a);
164 }
165 createPeriods();
166}
167
168void AccountsView::initAccSubItems(Account *acc, AccountsView::AccountItem *parent) {
169 if (!acc->accountList().isEmpty()) {
170/* AccountsView::AccountItem *a = new AccountsView::AccountItem(i18n("Subaccounts"), acc, parent);
171 DoubleListViewBase::SlaveListItem *i = new DoubleListViewBase::SlaveListItem(a, parent->period);
172 a->period = i;*/
173
174 initAccList(acc->accountList(), parent);
175 }
176// AccountsView::AccountItem *a = new AccountsView::AccountItem(i18n("Variance"), acc, parent, true);
177// DoubleListViewBase::SlaveListItem *i = new DoubleListViewBase::SlaveListItem(a, parent->period, true);
178// a->period = i;
179//
180// a = new AccountsView::AccountItem(i18n("Actual"), acc, parent);
181// i = new DoubleListViewBase::SlaveListItem(a, parent->period);
182// a->period = i;
183//
184// a = new AccountsView::AccountItem(i18n("Planned"), acc, parent);
185// i = new DoubleListViewBase::SlaveListItem(a, parent->period);
186// a->period = i;
187
188}
189
190void AccountsView::initAccList(const AccountList &list, AccountsView::AccountItem *parent) {
191 AccountListIterator it = list;
192 for (it.toLast(); it.current(); --it) {
193 AccountsView::AccountItem *a = new AccountsView::AccountItem(it.current(), parent);
194 a->setOpen(true);
195 a->setExpandable(!it.current()->isElement());
196 initAccSubItems(it.current(), a);
197 }
198}
199
200void AccountsView::clearPeriods() {
201 m_dlv->clearSlaveList();
202}
203
204void AccountsView::createPeriods() {
205 m_dlv->createSlaveItems();
206}
207
208void AccountsView::slotUpdate() {
209 //kdDebug()<<k_funcinfo<<endl;
210 TQApplication::setOverrideCursor(TQt::waitCursor);
211 createPeriods();
212 TDELocale *locale = TDEGlobal::locale();
213 const KCalendarSystem *cal = locale->calendar();
214
215 TQString t;
216 if (m_cumulative) {
217 t += " <b>" + i18n("Cumulative") + "</b> ";
218 }
219 t += i18n("Cut-off date:%1").arg("<b>" + locale->formatDate(m_date, true) + "</b>");
220 t += " " + i18n("Periodicity:%1").arg("<b>" + periodText(m_period) + "</b>");
221 m_label->setText(t);
222
223 // Add columns for selected period/periods
224 TQDate start = m_project.startTime().date();
225 TQDate end = m_date;
226 //kdDebug()<<k_funcinfo<<start.toString()<<" - "<<end.toString()<<endl;
227 int c=0;
228 if (m_period == 0) { //Daily
229 for (TQDate dt = start; dt <= end; dt = cal->addDays(dt, 1), ++c) {
230 TQString df = locale->formatDate(dt, true);
231 m_dlv->addSlaveColumn(df);
232 }
233 TQListViewItemIterator it(m_dlv->masterListView());
234 for (;it.current(); ++it) {
235 AccountsView::AccountItem *item = dynamic_cast<AccountsView::AccountItem*>(it.current());
236 if (!item || !item->account || !item->account->isElement()) {
237 continue;
238 }
239 item->costMap = m_accounts.plannedCost(*(item->account), start, end);
240 double cost = 0.0;
241 int col=0;
242 for (TQDate d=start; d <= end; d = cal->addDays(d, 1), ++col) {
243 EffortCost &ec = item->costMap.effortCostOnDate(d);
244 cost = (m_cumulative ? cost + ec.cost() : ec.cost());
245 item->setSlaveItem(col, cost);
246 m_cumulative ? item->setTotal(cost) : item->addToTotal(cost);
247 }
248 }
249 m_dlv->calculate();
250 TQApplication::restoreOverrideCursor();
251 return;
252 }
253 if (m_period == 1) { //Weekly
254 //TODO make this user controlled
255 int weekStartDay = locale->weekStartDay();
256
257 TQDate dt = start;
258 TQDate pend = cal->addDays(dt, 7 + weekStartDay - 1 - cal->dayOfWeek(dt));
259 for (; pend <= end; ++c) {
260 //kdDebug()<<k_funcinfo<<c<<": "<<dt<<"-"<<pend<<" : "<<end<<endl;
261 int y;
262 int w = cal->weekNumber(dt, &y);
263 TQString t = i18n("<week>-<year>", "%1-%2").arg(w).arg(y);
264 m_dlv->addSlaveColumn(t);
265 dt = pend.addDays(1);
266 pend = cal->addDays(pend, 7);
267 if ((pend.year() == end.year()) && (pend.weekNumber() == end.weekNumber())) {
268 pend = end;
269 }
270 }
271 if (c == 0) {
272 TQApplication::restoreOverrideCursor();
273 return;
274 }
275 TQListViewItemIterator it(m_dlv->masterListView());
276 for (;it.current(); ++it) {
277 AccountsView::AccountItem *item = dynamic_cast<AccountsView::AccountItem*>(it.current());
278 if (!item || !item->account || !item->account->isElement()) {
279 continue;
280 }
281 item->costMap = m_accounts.plannedCost(*(item->account), start, end);
282 double cost = 0.0;
283 TQDate d = start;
284 TQDate pend = cal->addDays(d, 7 + weekStartDay - 1 - cal->dayOfWeek(d));
285 for (int col=0; pend <= end; ++col) {
286 double cst = item->costMap.cost(d, d.daysTo(pend)+1);
287 cost = (m_cumulative ? cost + cst : cst);
288 item->setSlaveItem(col, cost);
289 m_cumulative ? item->setTotal(cost) : item->addToTotal(cost);
290 d = pend.addDays(1); // 1. next week
291 pend = cal->addDays(pend, 7);
292 if ((pend.year() == end.year()) && (pend.weekNumber() == end.weekNumber())) {
293 pend = end;
294 }
295 }
296 }
297 m_dlv->calculate();
298 TQApplication::restoreOverrideCursor();
299 return;
300 }
301 if (m_period == 2) { //Monthly
302 //TODO make this user controlled
303 TQDate dt = start;
304 TQDate pend;
305 cal->setYMD(pend, dt.year(), dt.month(), dt.daysInMonth());
306 for (; pend <= end; ++c) {
307 //kdDebug()<<k_funcinfo<<c<<": "<<dt<<"-"<<pend<<" : "<<end<<endl;
308 TQString m = cal->monthName(dt, true) + TQString(" %1").arg( dt.year());
309 m_dlv->addSlaveColumn(m);
310
311 dt = pend.addDays(1); // 1. next month
312 pend = cal->addDays(pend, dt.daysInMonth());
313 if ((pend.year() == end.year()) && (pend.month() == end.month())) {
314 pend = end;
315 }
316 }
317 if (c == 0) {
318 TQApplication::restoreOverrideCursor();
319 return;
320 }
321 TQListViewItemIterator it(m_dlv->masterListView());
322 for (;it.current(); ++it) {
323 AccountsView::AccountItem *item = dynamic_cast<AccountsView::AccountItem*>(it.current());
324 if (!item || !item->account || !item->account->isElement()) {
325 continue;
326 }
327 item->costMap = m_accounts.plannedCost(*(item->account), start, end);
328 double cost = 0.0;
329 TQDate d = start;
330 cal->setYMD(pend, d.year(), d.month(), d.daysInMonth());
331 for (int col=0; pend <= end; ++col) {
332 double cst = item->costMap.cost(d, d.daysTo(pend)+1);
333 cost = (m_cumulative ? cost + cst : cst);
334 item->setSlaveItem(col, cost);
335 m_cumulative ? item->setTotal(cost) : item->addToTotal(cost);
336 d = pend.addDays(1); // 1. next month
337 pend = cal->addDays(pend, d.daysInMonth());
338 if ((pend.year() == end.year()) && (pend.month() == end.month())) {
339 pend = end;
340 }
341 }
342 }
343 m_dlv->calculate();
344 TQApplication::restoreOverrideCursor();
345 return;
346 }
347 TQApplication::restoreOverrideCursor();
348}
349
350void AccountsView::print(KPrinter &printer) {
351 //kdDebug()<<k_funcinfo<<endl;
352 TQPaintDeviceMetrics m = TQPaintDeviceMetrics ( &printer );
353 uint top, left, bottom, right;
354 printer.margins(&top, &left, &bottom, &right);
355 //kdDebug()<<m.width()<<"x"<<m.height()<<" : "<<top<<", "<<left<<", "<<bottom<<", "<<right<<" : "<<size()<<endl;
356 TQPainter p;
357 p.begin(&printer);
358 p.setViewport(left, top, m.width()-left-right, m.height()-top-bottom);
359 p.setClipRect(left, top, m.width()-left-right, m.height()-top-bottom);
360 TQRect preg = p.clipRegion(TQPainter::CoordPainter).boundingRect();
361 //kdDebug()<<"p="<<preg<<endl;
362 //p.drawRect(preg.x(), preg.y(), preg.width()-1, preg.height()-1);
363 double scale = TQMIN((double)preg.width()/(double)size().width(), (double)preg.height()/(double)(size().height()));
364 //kdDebug()<<"scale="<<scale<<endl;
365 if (scale < 1.0) {
366 p.scale(scale, scale);
367 }
368 m_label->paintContents(&p);
369 p.translate(0, m_label->size().height());
370 m_dlv->paintContents(&p);
371 p.end();
372}
373
374bool AccountsView::setContext(Context::Accountsview &context) {
375 //kdDebug()<<k_funcinfo<<"---->"<<endl;
376 TQValueList<int> list;
377 list << context.accountsviewsize << context.periodviewsize;
378 //m_dlv->setSizes(list); //NOTE: This doesn't always work!
379 m_date = context.date;
380 if (!m_date.isValid())
381 m_date = TQDate::currentDate();
382 m_period = context.period;
383 m_cumulative = context.cumulative;
384 setContextClosedItems(context);
385 //kdDebug()<<k_funcinfo<<"<----"<<endl;
386 return true;
387}
388
389void AccountsView::setContextClosedItems(Context::Accountsview &context) {
390 for (TQStringList::ConstIterator it = context.closedItems.begin(); it != context.closedItems.end(); ++it) {
391 if (m_accounts.findAccount(*it)) {
392 TQListViewItemIterator lit(m_dlv->masterListView());
393 for (; lit.current(); ++lit) {
394 if (lit.current()->text(0) == (*it)) {
395 m_dlv->setOpen(lit.current(), false);
396 break;
397 }
398 }
399 }
400 }
401}
402
403void AccountsView::getContext(Context::Accountsview &context) const {
404 //kdDebug()<<k_funcinfo<<endl;
405 context.accountsviewsize = m_dlv->sizes()[0];
406 context.periodviewsize = m_dlv->sizes()[1];
407 context.date = m_date;
408 context.period = m_period;
409 context.cumulative = m_cumulative;
410 //kdDebug()<<k_funcinfo<<"sizes="<<sizes()[0]<<","<<sizes()[1]<<endl;
411
412 getContextClosedItems(context, m_dlv->masterListView()->firstChild());
413}
414
415
416void AccountsView::getContextClosedItems(Context::Accountsview &context, TQListViewItem *item) const {
417 if (item == 0)
418 return;
419 for (TQListViewItem *i = item; i; i = i->nextSibling()) {
420 if (!i->isOpen()) {
421 context.closedItems.append(i->text(0));
422 //kdDebug()<<k_funcinfo<<"add closed "<<i->text(0)<<endl;
423 }
424 getContextClosedItems(context, i->firstChild());
425 }
426}
427
428void AccountsView::slotConfigure() {
429 //kdDebug()<<k_funcinfo<<endl;
430 AccountsviewConfigDialog *dia = new AccountsviewConfigDialog(m_date, m_period, m_periodTexts, m_cumulative, this);
431 if (dia->exec()) {
432 m_date = dia->date();
433 m_period = dia->period();
434 m_cumulative = dia->isCumulative();
435 emit update();
436 }
437 delete dia;
438}
439
440TQString AccountsView::periodText(int offset) {
441 TQString s;
442 TQStringList::const_iterator it = m_periodTexts.at(offset);
443 if (it != m_periodTexts.constEnd()) {
444 s = (*it);
445 }
446 return s;
447}
448
449} //KPlato namespace
450
451#include "kptaccountsview.moc"