FreeDebks  1.0.3
 All Classes Files Functions Variables Friends Pages
FdViewAccountSummary.cpp
Go to the documentation of this file.
1 // --------------------------------------------------------------------
2 // Copyright © 2011-2013 Mathieu Schopfer
3 //
4 // This file is part of FreeDebks.
5 //
6 // FreeDebks is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // FreeDebks is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with FreeDebks. If not, see <http://www.gnu.org/licenses/>.
18 // --------------------------------------------------------------------
19 
20 #include "FdViewAccountSummary.hpp"
21 #include "../../data/FdModelJournal.hpp"
22 #include "../../data/FdItemCoa.hpp"
23 #include "../../data/FdItemJournal.hpp"
24 #include "../FdMainWindow.hpp"
25 #include "../FdSubWindow.hpp"
26 
27 FdViewAccountSummary::FdViewAccountSummary(FdSubWindow *parent, FdItemCoa_p account) :
28  QTableView(0), mSubwindow(parent), mAccount(account)
29 {
30  setProperty("TabRole", TabRole(AccountRole));
31  mModel = new FdModelAccountSummary(mSubwindow, account);
32  connect(this, SIGNAL(refresh()), mModel, SLOT(refresh()));
33  setModel(mModel);
34  setSelectionBehavior(QAbstractItemView::SelectRows);
35  QHeaderView* header = verticalHeader();
36  header->setDefaultSectionSize(16);
37  setVerticalHeader(header);
38  setEditTriggers(NoEditTriggers);
39 
40  setAlternatingRowColors(true);
41 
42  QSettings settings;
43  settings.beginGroup("ViewAccountSummary");
44  setColumnWidth(AccountDate, settings.value("date", 70).toInt());
45  setColumnWidth(AccountLabel, settings.value("label", 70).toInt());
46  setColumnWidth(AccountCounterpart, settings.value("counterpart", 70).toInt());
47  setColumnWidth(AccountDebit, settings.value("debit", 70).toInt());
48  setColumnWidth(AccountCredit, settings.value("credit", 70).toInt());
49  settings.endGroup();
50  horizontalHeader()->setResizeMode(AccountBalance, QHeaderView::Stretch);
51 
52  mDelegate = new FdDelegateAccountSummary(mModel, mSubwindow);
53  setItemDelegate(mDelegate);
54 
55  setContextMenuPolicy(Qt::CustomContextMenu);
56  connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(contextMenu(const QPoint&)));
57 
58  mSearchTimer = new QTimer();
59  mSearchTimer->setInterval(qApp->keyboardInputInterval());
60  mSearchTimer->setSingleShot(true);
61  connect(mSearchTimer, SIGNAL(timeout()), this, SLOT(searchTimeout()));
62 }
63 
67 void FdViewAccountSummary::mouseReleaseEvent(QMouseEvent* event)
68 {
69  if(event->button() == Qt::LeftButton && !(indexAt(event->pos()).isValid()))
70  setCurrentIndex(QModelIndex());
72 }
73 
79 void FdViewAccountSummary::keyboardSearch(const QString &search)
80 {
81  mSearchTimer->start();
82  mSearchText.append(search);
83  mainWindow->setDockText(tr("Searched string : %1", "Text displayed in the dock widget while keyboardsearching in views. The argument is the user input string to search.").arg(mSearchText));
84 }
85 
86 int FdViewAccountSummary::print(QPrinter &printer, QPainter &painter, QRect &area, QRect& remainingArea, FdSubWindow* subwindow, int pageNumber)
87 {
88  refreshView();
89  const int rows = model()->rowCount();
90  bool subtitlePrinted = false;
91  bool headerPrinted = false;
92 
93  struct tableElement dateHeader;
94  dateHeader.width = 0.08*area.width();
95  dateHeader.text = tr("Date", "Accounts summaries column header on printed pages.");
96  dateHeader.alignement = Qt::AlignLeft;
97  dateHeader.color = Qt::black;
98 
99  struct tableElement labelHeader;
100  labelHeader.width = 0.36*area.width();
101  labelHeader.text = tr("Label", "Accounts summaries column header on printed pages.");
102  labelHeader.alignement = Qt::AlignLeft;
103  labelHeader.color = Qt::black;
104 
105  struct tableElement counterpartHeader;
106  counterpartHeader.width = 0.3*area.width();
107  counterpartHeader.text = tr("Counterpart", "Accounts summaries column header on printed pages.");
108  counterpartHeader.alignement = Qt::AlignLeft;
109  counterpartHeader.color = Qt::black;
110 
111  struct tableElement debitHeader;
112  debitHeader.width = 0.08*area.width();
113  debitHeader.text = tr("Debit", "Accounts summaries column header on printed pages.");
114  debitHeader.alignement = Qt::AlignRight;
115  debitHeader.color = Qt::black;
116 
117  struct tableElement creditHeader;
118  creditHeader.width = 0.08*area.width();
119  creditHeader.text = tr("Credit", "Accounts summaries column header on printed pages.");
120  creditHeader.alignement = Qt::AlignRight;
121  creditHeader.color = Qt::black;
122 
123  struct tableElement balanceHeader;
124  balanceHeader.width = 0.1*area.width();
125  balanceHeader.text = tr("Balance", "Accounts summaries column header on printed pages.");
126  balanceHeader.alignement = Qt::AlignRight;
127  balanceHeader.color = Qt::black;
128 
129  QList<tableElement*> header;
130  header << &dateHeader << &labelHeader << &counterpartHeader << &debitHeader << &creditHeader << &balanceHeader;
131 
132  struct tableElement date = dateHeader;
133  struct tableElement label = labelHeader;
134  struct tableElement counterpart = counterpartHeader;
135  struct tableElement debit = debitHeader;
136  struct tableElement credit = creditHeader;
137  struct tableElement balance = balanceHeader;
138  QList<tableElement*> row;
139  row << &date << &label << &counterpart << &debit << &credit << &balance;
140 
141  QModelIndex index;
142 
143  QString subtitle = mAccount->displayLabel();
144 
145  // The first value must match FdSubWindow::printSubtitle.
146  // The second value must match FdSubWindow::printTableRow.
147  int neededHeight = 350 + (rows+1)*185;
148 
149  if(pageNumber && neededHeight > remainingArea.height() && neededHeight < area.height())
150  remainingArea.setHeight(0);
151  // Last value : 350+2*185
152  else if(pageNumber && neededHeight > remainingArea.height() && remainingArea.height() < 720)
153  remainingArea.setHeight(0);
154 
155  for(int i = 0; i < rows; ++i)
156  {
157 
158  if(!remainingArea.height() || !pageNumber)
159  {
160  if(!remainingArea.height())
161  remainingArea = area;
162 
163  if(pageNumber)
164  printer.newPage();
165 
166 // painter.drawRect(area);
167 
168  ++pageNumber;
169 
170  subwindow->printHeaderFooter(printer, painter, tr("Accounts summaries", "Text displayed on accounts summaries printed pages footer.")+" - "+subtitle, pageNumber);
171  headerPrinted = false;
172  }
173 
174  if(!subtitlePrinted)
175  {
176  FdSubWindow::printSubtitle(painter, remainingArea, subtitle);
177  subtitlePrinted = true;
178  }
179 
180  if(!headerPrinted)
181  {
182  FdSubWindow::printColumnsHeader(painter, remainingArea, header);
183  headerPrinted = true;
184  }
185 
186  index = model()->index(i, AccountDate);
187  date.text = mDelegate->displayText(model()->data(index));
188 
189  index = model()->index(i, AccountLabel);
190  label.text = model()->data(index).toString();
191 
192  index = model()->index(i, AccountCounterpart);
193  counterpart.text = model()->data(index).toString();
194 
195  index = model()->index(i, AccountDebit);
196  debit.text = mDelegate->displayText(model()->data(index));
197 
198  index = model()->index(i, AccountCredit);
199  credit.text = mDelegate->displayText(model()->data(index));
200 
201  index = model()->index(i, AccountBalance);
202  balance.text = mDelegate->displayText(model()->data(index));
203  if(balance.text.toDouble() < 0)
204  balance.color = Qt::red;
205  else
206  balance.color = Qt::black;
207 
208  FdSubWindow::printTableRow(painter, remainingArea, row);
209  }
210 
211  // Sets spacing between accounts
212  if(remainingArea.height())
213  remainingArea.setRect(area.x(), remainingArea.y()+300, area.width(), remainingArea.height()-300);
214 
215  return pageNumber;
216 }
217 
222 {
223  return mModel->selectedCounterpart(currentIndex());
224 }
225 
229 FdItemJournal_p FdViewAccountSummary::currentEntry()
230 {
231  return mModel->selectedEntry(currentIndex());
232 }
233 
235 {
236  // Get selected rows.
237  QModelIndexList indexes = selectedIndexes();
238  QList<int> rows;
239  for(int i = 0; i < indexes.size(); ++i)
240  {
241  if(indexes[i].column() == 0)
242  rows << indexes[i].row();
243  }
244 
246  if(rows.size() == 1)
247  {
248  FdItemCoa_p account = currentCounterpart();
249 
250  if(!account.isNull())
251  {
252  QString text;
253  text = account->displayLabel()+" : "+mDelegate->displayText(account->balance());
254  mainWindow->setDockText(text);
255  }
256  }
257 }
258 
260 {
261  QSettings settings;
262  settings.beginGroup("ViewAccountSummary");
263  settings.setValue("date", columnWidth(AccountDate));
264  settings.setValue("label", columnWidth(AccountLabel));
265  settings.setValue("counterpart", columnWidth(AccountCounterpart));
266  settings.setValue("debit", columnWidth(AccountDebit));
267  settings.setValue("credit", columnWidth(AccountCredit));
268  settings.endGroup();
269 }
270 
272 {
273  currentChanged(currentIndex(), QModelIndex());
274 }
275 
276 void FdViewAccountSummary::currentChanged(const QModelIndex &current, const QModelIndex &previous)
277 {
278  if(current.isValid() && current.row())
279  {
280  mainWindow->enableShowAccountAction(true);
281  mainWindow->enableShowEntryAction(true);
282  }
283  else
284  {
285  mainWindow->enableShowAccountAction(false);
286  mainWindow->enableShowEntryAction(false);
287  }
288 
289  QTableView::currentChanged(current, previous);
290 }
291 
292 void FdViewAccountSummary::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
293 {
294  setDockText();
295  QTableView::selectionChanged(selected, deselected);
296 }
297 
298 void FdViewAccountSummary::contextMenu(const QPoint &position)
299 {
300  QModelIndex index = currentIndex();
301 
302  if(index.isValid())
303  {
304  QMenu* menu = new QMenu();
305  menu->addActions(mainWindow->getContextMenuActionsAccount());
306  menu->exec(mapToGlobal(position));
307  }
308 }
309 
315 {
317  if(mSearchResults.size())
318  {
319  mCurrentResult = -1;
321  }
322  else
323  mainWindow->setDockText(tr("Sorry, no matches found.", "No matches found when searching item by text."));
324 
325  mSearchText = QString();
326 }
327 
329 {
330  if(mSearchResults.size())
331  {
332  if(mCurrentResult < mSearchResults.size() - 1)
333  {
334  ++ mCurrentResult;
335  setCurrentIndex(mSearchResults[mCurrentResult]);
336  }
337  else
338  {
339  mCurrentResult = -1;
341  }
342  }
343  else
344  mainWindow->setDockText(tr("Sorry, no matches found.", "No matches found when searching item by text."));
345 }
346 
348 {
349  emit(refresh());
350 }
351 
352 FdModelAccountSummary::FdModelAccountSummary(FdSubWindow *subwindow, FdItemCoa_p account) :
353  QAbstractTableModel(0), mSubwindow(subwindow), mAccount(account)
354 {
355 }
356 
357 QVariant FdModelAccountSummary::data(const QModelIndex &index, int role) const
358 {
359  if(!index.isValid())
360  return QVariant();
361  if(role == Qt::TextAlignmentRole && (index.column() == AccountDebit || index.column() == AccountCredit || index.column() == AccountBalance))
362  return Qt::AlignRight;
363  if (role != Qt::DisplayRole && role != Qt::EditRole)
364  return QVariant();
365 
366  int column = index.column();
367  FdItemJournal_p entry = mEntries[index.row()];
368 
369  if(index.row() == 0)
370  {
371  switch(column)
372  {
373  case AccountLabel: return tr("Initial balance", "Initial balance of an account, entry label for accounts summaries first row.");
374  case AccountDebit:
375  if(mAccount->signature() == PlusMinus)
376  return mAccount->initialBalance();
377  else
378  break;
379  case AccountCredit:
380  if(mAccount->signature() == MinusPlus)
381  return mAccount->initialBalance();
382  else
383  break;
384  case AccountBalance:
385  return mAccount->initialBalance();
386  }
387 
388  return QVariant();
389  }
390  else
391  {
392  switch(column)
393  {
394  case AccountDate: return entry->date();
395  case AccountLabel: return entry->label();
396  case AccountCounterpart:
397  if(mAccount == entry->debit())
398  return entry->credit()->displayLabel();
399  else
400  return entry->debit()->displayLabel();
401  case AccountDebit:
402  if(mAccount == entry->debit())
403  return entry->amount();
404  else
405  break;
406  case AccountCredit:
407  if(mAccount == entry->credit())
408  return entry->amount();
409  else
410  break;
411  case AccountBalance:
412  double balance = data(this->index(index.row()-1, index.column())).toDouble();
413  if(mAccount == entry->debit())
414  return balance + entry->amount()*mAccount->signature();
415  else
416  return balance - entry->amount()*mAccount->signature();
417  }
418  }
419 
420  return QVariant();
421 }
422 
423 QVariant FdModelAccountSummary::headerData(int section, Qt::Orientation orientation, int role) const
424 {
425  if(role == Qt::DisplayRole)
426  {
427  if (orientation == Qt::Horizontal)
428  {
429  switch(section)
430  {
431  case AccountDate: return tr("Date", "Accounts summaries view column header.");
432  case AccountLabel: return tr("Label", "Accounts summaries view column header.");
433  case AccountCounterpart: return tr("Counterpart", "Accounts summaries view column header.");
434  case AccountDebit: return tr("Debit", "Accounts summaries view column header.");
435  case AccountCredit: return tr("Credit", "Accounts summaries view column header.");
436  case AccountBalance: return tr("Balance", "Accounts summaries view column header.");
437  }
438  }
439  else
440  return section+1;
441  }
442 
443  return QVariant();
444 }
445 
446 int FdModelAccountSummary::rowCount(const QModelIndex &parent) const
447 {
448  return mEntries.size();
449 }
450 
451 int FdModelAccountSummary::columnCount(const QModelIndex &parent) const
452 {
453  return AccountColumnCount;
454 }
455 
459 QModelIndexList FdModelAccountSummary::entryByPartialText(QString text) const
460 {
461  QModelIndexList results;
462  for(int i = 1; i < rowCount(); ++i)
463  {
464  if(mEntries[i]->label().contains(text, Qt::CaseInsensitive) || mEntries[i]->amount() == text.toDouble())
465  results << index(i, 0);
466  }
467  return results;
468 }
469 
471 {
472  if(rowCount())
473  {
474  beginRemoveRows(QModelIndex(), 0, rowCount()-1);
475  mEntries.clear();
476  endRemoveRows();
477  }
478 
479  QList<FdItemJournal_p> entries = mSubwindow->journal()->accountEntries(mAccount);
480  entries.prepend(FdItemJournal_p(0));
481  beginInsertRows(QModelIndex(), 0, entries.size()-1);
482  mEntries = entries;
483  endInsertRows();
484  emit(dataChanged(index(0,0), index(rowCount()-1, columnCount()-1)));
485 }
486 
490 FdItemCoa_p FdModelAccountSummary::selectedCounterpart(const QModelIndex& index) const
491 {
492  if(!mAccount.isNull() && index.row())
493  {
494  FdItemJournal_p entry = mEntries[index.row()];
495  if(mAccount == entry->debit())
496  return entry->credit();
497  else
498  return entry->debit();
499  }
500 
501  return FdItemCoa_p(0);
502 }
503 
507 FdItemJournal_p FdModelAccountSummary::selectedEntry(const QModelIndex &index) const
508 {
509  if(index.row())
510  {
511  return mEntries[index.row()];
512  }
513 
514  return FdItemJournal_p(0);
515 }
516 
518  QStyledItemDelegate(0), mModel(model), mSubwindow(subwindow)
519 {
520 }
521 
522 QString FdDelegateAccountSummary::displayText(const QVariant &value) const
523 {
524  return displayText(value, QLocale::system());
525 }
526 
530 QString FdDelegateAccountSummary::displayText(const QVariant &value, const QLocale &locale) const
531 {
532  if(value.type() == QVariant::Date)
533  return value.toDate().toString(Qt::SystemLocaleShortDate);
534  else if(value.type() == QVariant::Double)
535  return QLocale::system().toString(value.toDouble(), 'f', 2);
536 
537  return QStyledItemDelegate::displayText(value, locale);
538 }
539 
543 void FdDelegateAccountSummary::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
544 {
545  QStyleOptionViewItem viewOption(option);
546 
547  if(index.column() == AccountBalance && mModel->data(index).toDouble() < 0)
548  viewOption.palette.setColor(QPalette::Text, Qt::red);
549 
550  QStyledItemDelegate::paint(painter, viewOption, index);
551 }