00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #include <qpainter.h>
00010 #include <qapplication.h>
00011 #include <qheader.h>
00012 #include <qdragobject.h>
00013 #include <qdatetime.h>
00014 #include "common.h"
00015 #include "domain.h"
00016 #include "git.h"
00017 #include "listview.h"
00018 
00019 using namespace QGit;
00020 
00021 ListView::ListView(Domain* dm, Git* g, QListView* l, FileHistory* f, const QFont& fnt) :
00022                    QObject(dm), d(dm), git(g), lv(l), fh(f) {
00023 
00024         st = &(d->st);
00025         filterNextContextMenuRequest = currentChangedEmitted = false;
00026         setupListView(fnt);
00027         clear(); 
00028 
00029         lv->setAcceptDrops(git->isMainHistory(fh));
00030         lv->viewport()->setAcceptDrops(git->isMainHistory(fh));
00031         lv->viewport()->installEventFilter(this); 
00032 
00033         connect(lv, SIGNAL(currentChanged(QListViewItem*)),
00034                 this, SLOT(on_currentChanged(QListViewItem*)));
00035 
00036         connect(lv, SIGNAL(mouseButtonPressed(int,QListViewItem*,const QPoint&,int)),
00037                 this, SLOT(on_mouseButtonPressed(int,QListViewItem*,const QPoint&,int)));
00038 
00039         connect(lv, SIGNAL(clicked(QListViewItem*)),
00040                 this, SLOT(on_clicked(QListViewItem*)));
00041 
00042         connect(lv, SIGNAL(onItem(QListViewItem*)),
00043                 this, SLOT(on_onItem(QListViewItem*)));
00044 
00045         connect(lv, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&,int)),
00046                 this, SLOT(on_contextMenuRequested(QListViewItem*)));
00047 }
00048 
00049 ListView::~ListView() {
00050 
00051         git->cancelDataLoading(fh); 
00052 }
00053 
00054 void ListView::setupListView(const QFont& fnt) {
00055 
00056         lv->setItemMargin(0);
00057         lv->setSorting(-1);
00058         lv->setFont(fnt);
00059 
00060         int adj = !git->isMainHistory(fh) ? 0 : -1;
00061 
00062         lv->setColumnWidthMode(GRAPH_COL, QListView::Manual);
00063         lv->setColumnWidthMode(LOG_COL + adj, QListView::Manual);
00064         lv->setColumnWidthMode(AUTH_COL + adj, QListView::Manual);
00065         lv->setColumnWidthMode(TIME_COL + adj, QListView::Maximum); 
00066 
00067         lv->setColumnWidth(GRAPH_COL, DEF_GRAPH_COL_WIDTH);
00068         lv->setColumnWidth(LOG_COL + adj, DEF_LOG_COL_WIDTH);
00069         lv->setColumnWidth(AUTH_COL + adj, DEF_AUTH_COL_WIDTH);
00070         lv->setColumnWidth(TIME_COL + adj, DEF_TIME_COL_WIDTH);
00071 
00072         lv->header()->setStretchEnabled(false);
00073         lv->header()->setStretchEnabled(true, LOG_COL + adj);
00074 }
00075 
00076 void ListView::on_repaintListViews(const QFont& f) {
00077 
00078         lv->setFont(f);
00079         lv->ensureItemVisible(lv->currentItem());
00080 }
00081 
00082 void ListView::clear() {
00083 
00084         git->cancelDataLoading(fh);
00085         lv->clear();
00086         diffTarget = NULL; 
00087 
00088         int adj = !git->isMainHistory(fh) ? 0 : -1;
00089 
00090         if (testFlag(REL_DATE_F)) {
00091                 secs = QDateTime::currentDateTime().toTime_t();
00092                 lv->setColumnText(TIME_COL + adj, "Last Change");
00093         } else {
00094                 secs = 0;
00095                 lv->setColumnText(TIME_COL + adj, "Author Date");
00096         }
00097 }
00098 
00099 void ListView::updateIdValues() {
00100 
00101         if (git->isMainHistory(fh))
00102                 return;
00103 
00104         uint id = lv->childCount();
00105         QListViewItem* item = lv->firstChild();
00106         while (item) {
00107                 item->setText(ANN_ID_COL, QString::number(id--) + "  ");
00108                 item = item->itemBelow();
00109         }
00110 }
00111 
00112 void ListView::getSelectedItems(QStringList& selectedItems) {
00113 
00114         selectedItems.clear();
00115         QListViewItem* item = lv->firstChild();
00116         while (item) {
00117                 if (item->isSelected())
00118                         selectedItems.append(((ListViewItem*)item)->sha());
00119 
00120                 item = item->itemBelow();
00121         }
00122 }
00123 
00124 const QString ListView::getSha(int id) {
00125 
00126         if (git->isMainHistory(fh))
00127                 return "";
00128 
00129         
00130         QListViewItem* item = lv->currentItem();
00131         if (item && item->text(ANN_ID_COL).toInt() == id)
00132                 return ((ListViewItem*)item)->sha();
00133 
00134         item = lv->firstChild();
00135         while (item) {
00136                 if (item->text(ANN_ID_COL).toInt() == id)
00137                         return ((ListViewItem*)item)->sha();
00138 
00139                 item = item->itemBelow();
00140         }
00141         return "";
00142 }
00143 
00144 ListViewItem* ListView::findItemSha(SCRef sha) const {
00145 
00146 
00147         if (sha.isEmpty())
00148                 return NULL;
00149 
00150         QListViewItemIterator it(lv->currentItem() ? lv->currentItem() : lv->firstChild());
00151         QListViewItem *sentinel = NULL;
00152         ListViewItem *item;
00153 
00154         for (int pass = 0; pass < 2; pass++) {
00155                 while ((item = (ListViewItem*)it.current()) != sentinel) {
00156                         if (sha == item->sha())
00157                                 return item;
00158                         ++it;
00159                 }
00160                 it = QListViewItemIterator(lv->firstChild());
00161                 sentinel = lv->currentItem() ? lv->currentItem() : lv->firstChild();
00162         }
00163         return NULL;
00164 }
00165 
00166 void ListView::setHighlight(SCRef diffToSha) {
00167 
00168         if (diffTarget && diffTarget->sha() == diffToSha)
00169                 return;
00170 
00171         
00172         if (diffTarget) {
00173                 diffTarget->setDiffTarget(false);
00174                 diffTarget = NULL;
00175         }
00176         if (diffToSha.isEmpty())
00177                 return;
00178 
00179         diffTarget = findItemSha(diffToSha);
00180         if (diffTarget && (diffTarget->sha() != ZERO_SHA))
00181                 diffTarget->setDiffTarget(true); 
00182 }
00183 
00184 bool ListView::update() {
00185 
00186         ListViewItem* item = static_cast<ListViewItem*>(lv->currentItem());
00187 
00188         if (item && (item->sha() == st->sha())) {
00189                 lv->setSelected(item, st->selectItem()); 
00190                 lv->ensureItemVisible(item);
00191         } else {
00192                 
00193                 
00194                 lv->clearSelection();
00195 
00196                 item = findItemSha(st->sha());
00197                 if (item) {
00198                         lv->setCurrentItem(item); 
00199                         lv->setSelected(item, st->selectItem());
00200                         lv->ensureItemVisible(item);
00201                 }
00202         }
00203         if (git->isMainHistory(fh))
00204                 setHighlight(st->diffToSha());
00205 
00206         return (item != NULL);
00207 }
00208 
00209 
00210 
00211 void ListView::on_newRevsAdded(const FileHistory* f, const QValueVector<QString>& shaVec) {
00212 
00213         if (f != fh) 
00214                 return;
00215 
00216         bool evenLine = !(lv->childCount() % 2);
00217 
00218         if (lv->childCount() == 0)
00219                 lastItem = NULL;
00220 
00221         lv->setUpdatesEnabled(false);
00222         for (uint i = lv->childCount(); i < shaVec.count(); i++) {
00223                 lastItem = new ListViewItem(lv, lastItem, git, shaVec[i], evenLine, secs, fh);
00224                 evenLine = !evenLine;
00225         }
00226         lv->setUpdatesEnabled(true);
00227 }
00228 
00229 void ListView::on_currentChanged(QListViewItem* item) {
00230 
00231         currentChangedEmitted = true;
00232         SCRef selRev(item ? (static_cast<ListViewItem*>(item))->sha() : "");
00233         if (st->sha() != selRev) { 
00234                 st->setSha(selRev);
00235                 st->setSelectItem(true);
00236                 UPDATE_DOMAIN(d);
00237         }
00238 }
00239 
00240 void ListView::on_mouseButtonPressed(int b, QListViewItem* item, const QPoint&, int) {
00241 
00242         if (item && b == Qt::LeftButton)
00243                 d->setReadyToDrag(true);
00244 
00245         
00246 
00247 
00248 
00249 
00250 
00251         if (item && !currentChangedEmitted && item == lv->currentItem() && item->isSelected())
00252                 on_currentChanged(item);
00253 
00254         currentChangedEmitted = false; 
00255 }
00256 
00257 void ListView::on_clicked(QListViewItem*) {
00258 
00259         d->setReadyToDrag(false); 
00260 }
00261 
00262 void ListView::on_onItem(QListViewItem*) {
00263 
00264         if (!d->isReadyToDrag() || !d->setDragging(true))
00265                 return;
00266 
00267         QStringList selRevs;
00268         getSelectedItems(selRevs);
00269         selRevs.remove(ZERO_SHA);
00270 
00271         if (!selRevs.empty()) {
00272                 const QString h(d->dragHostName() + '\n');
00273                 QString dragRevs = selRevs.join(h).append(h).stripWhiteSpace();
00274                 QDragObject* drObj = new QTextDrag(dragRevs, lv);
00275                 drObj->dragCopy(); 
00276         }
00277         d->setDragging(false);
00278 }
00279 
00280 void ListView::on_contextMenuRequested(QListViewItem* item) {
00281 
00282         if (!item)
00283                 return;
00284 
00285         if (filterNextContextMenuRequest) {
00286                 
00287                 filterNextContextMenuRequest = false;
00288                 return;
00289         }
00290         emit contextMenu(((ListViewItem*)item)->sha(), POPUP_LIST_EV);
00291 }
00292 
00293 
00294 bool ListView::eventFilter(QObject* obj, QEvent* ev) {
00295 
00296 
00297 
00298 
00299         if (obj == lv->viewport() && ev->type() == QEvent::MouseButtonPress) {
00300                 QMouseEvent* e = static_cast<QMouseEvent*>(ev);
00301                 if (e->button() == Qt::RightButton)
00302                         return filterRightButtonPressed(e);
00303         }
00304         if (obj == lv->viewport() && ev->type() == QEvent::Drop) {
00305                 QDropEvent* e = static_cast<QDropEvent*>(ev);
00306                 return filterDropEvent(e);
00307         }
00308         return QObject::eventFilter(obj, ev);
00309 }
00310 
00311 bool ListView::filterRightButtonPressed(QMouseEvent* e) {
00312 
00313         ListViewItem* item = static_cast<ListViewItem*>(lv->itemAt(e->pos()));
00314         if (!item)
00315                 return false;
00316 
00317         if (e->state() == Qt::ControlButton) { 
00318 
00319                 SCRef diffToSha(item->sha());
00320 
00321                 if (diffToSha != ZERO_SHA && st->sha() != ZERO_SHA) {
00322 
00323                         if (diffToSha != st->diffToSha())
00324                                 st->setDiffToSha(diffToSha);
00325                         else
00326                                 st->setDiffToSha(""); 
00327 
00328                         filterNextContextMenuRequest = true;
00329                         UPDATE_DOMAIN(d);
00330                         return true; 
00331                 }
00332         }
00333         
00334         int column = lv->header()->sectionAt(e->pos().x());
00335         if (column == GRAPH_COL) {
00336 
00337                 filterNextContextMenuRequest = true;
00338                 QStringList parents, children;
00339                 if (getLaneParentsChilds(item, e->pos().x(), parents, children))
00340                         emit lanesContextMenuRequested(parents, children);
00341 
00342                 return true; 
00343         }
00344         return false;
00345 }
00346 
00347 bool ListView::getLaneParentsChilds(ListViewItem* item, int x, SList p, SList c) {
00348 
00349         uint lane = x / item->laneWidth();
00350         int t = item->getLaneType(lane);
00351         if (t == EMPTY || t == -1)
00352                 return false;
00353 
00354         
00355         p.clear();
00356         QString root;
00357         SCRef sha(item->sha());
00358         if (!isFreeLane(t)) {
00359                 p = git->revLookup(sha)->parents(); 
00360                 root = sha;
00361         } else {
00362                 SCRef par(git->getLaneParent(sha, lane));
00363                 if (par.isEmpty()) {
00364                         dbs("ASSERT getLaneParentsChilds: parent not found");
00365                         return false;
00366                 }
00367                 p.append(par);
00368                 root = p.first();
00369         }
00370         
00371         c = git->getChilds(root);
00372         return true;
00373 }
00374 
00375 bool ListView::filterDropEvent(QDropEvent* e) {
00376 
00377         QString text;
00378         if (QTextDrag::decode(e, text) && !text.isEmpty()) {
00379 
00380                 SCList remoteRevs(QStringList::split('\n', text));
00381 
00382                 
00383                 SCRef sha(remoteRevs[0].section('@', 0, 0));
00384                 SCRef remoteRepo(remoteRevs[0].section('@', 1));
00385 
00386                 if (sha.length() == 40 && !remoteRepo.isEmpty())
00387                         emit droppedRevisions(remoteRevs);
00388         }
00389         return true; 
00390 }
00391 
00392 
00393 
00394 ListViewItem::ListViewItem(QListView* p, ListViewItem* a, Git* g, SCRef s,
00395               bool e, unsigned long t, FileHistory* f) : QListViewItem(p, a),
00396               listView_(p), git(g), fh(f), _sha(s), secs(t), isEvenLine(e) {
00397 
00398         populated = isDiffTarget = isHighlighted = false;
00399 }
00400 
00401 int ListViewItem::getLaneType(uint pos) const {
00402 
00403         const Rev* r = git->revLookup(_sha, fh); 
00404         return (pos < r->lanes.count() ? r->lanes[pos] : -1);
00405 }
00406 
00407 void ListViewItem::setDiffTarget(bool b) {
00408 
00409         isDiffTarget = b;
00410         repaint();
00411 }
00412 
00413 
00414 
00415 void ListViewItem::paintGraphLane(QPainter* p, int type, int x1, int x2,
00416                                   const QColor& col, const QBrush& back) {
00417 
00418         int h =  height() / 2;
00419         int m = (x1 + x2) / 2;
00420         int r = (x2 - x1) / 3;
00421         int d =  2 * r;
00422 
00423         #define P_CENTER m , h
00424         #define P_0      x2, h
00425         #define P_90     m , 0
00426         #define P_180    x1, h
00427         #define P_270    m , 2 * h
00428         #define R_CENTER m - r, h - r, d, d
00429 
00430         p->setPen(QPen(col, 2));
00431 
00432         
00433         switch (type) {
00434         case ACTIVE:
00435         case NOT_ACTIVE:
00436         case MERGE_FORK:
00437         case MERGE_FORK_R:
00438         case MERGE_FORK_L:
00439         case JOIN:
00440         case JOIN_R:
00441         case JOIN_L:
00442                 p->drawLine(P_90, P_270);
00443                 break;
00444         case HEAD:
00445         case HEAD_R:
00446         case HEAD_L:
00447         case BRANCH:
00448                 p->drawLine(P_CENTER, P_270);
00449                 break;
00450         case TAIL:
00451         case TAIL_R:
00452         case TAIL_L:
00453         case INITIAL:
00454         case BOUNDARY:
00455         case BOUNDARY_C:
00456         case BOUNDARY_R:
00457         case BOUNDARY_L:
00458                 p->drawLine(P_90, P_CENTER);
00459                 break;
00460         default:
00461                 break;
00462         }
00463 
00464         
00465         switch (type) {
00466         case MERGE_FORK:
00467         case JOIN:
00468         case HEAD:
00469         case TAIL:
00470         case CROSS:
00471         case CROSS_EMPTY:
00472         case BOUNDARY_C:
00473                 p->drawLine(P_180, P_0);
00474                 break;
00475         case MERGE_FORK_R:
00476         case JOIN_R:
00477         case HEAD_R:
00478         case TAIL_R:
00479         case BOUNDARY_R:
00480                 p->drawLine(P_180, P_CENTER);
00481                 break;
00482         case MERGE_FORK_L:
00483         case JOIN_L:
00484         case HEAD_L:
00485         case TAIL_L:
00486         case BOUNDARY_L:
00487                 p->drawLine(P_CENTER, P_0);
00488                 break;
00489         default:
00490                 break;
00491         }
00492 
00493         
00494         switch (type) {
00495         case ACTIVE:
00496         case INITIAL:
00497         case BRANCH:
00498                 p->setPen(Qt::NoPen);
00499                 p->setBrush(col);
00500                 p->drawEllipse(R_CENTER);
00501                 break;
00502         case MERGE_FORK:
00503         case MERGE_FORK_R:
00504         case MERGE_FORK_L:
00505                 p->setPen(Qt::NoPen);
00506                 p->setBrush(col);
00507                 p->drawRect(R_CENTER);
00508                 break;
00509         case UNAPPLIED:
00510                 
00511                 p->setPen(Qt::NoPen);
00512                 p->setBrush(red);
00513                 p->drawRect(m - r, h - 1, d, 2);
00514                 break;
00515         case APPLIED:
00516                 
00517                 p->setPen(Qt::NoPen);
00518                 p->setBrush(DARK_GREEN);
00519                 p->drawRect(m - r, h - 1, d, 2);
00520                 p->drawRect(m - 1, h - r, 2, d);
00521                 break;
00522         case BOUNDARY:
00523                 p->setBrush(back);
00524                 p->drawEllipse(R_CENTER);
00525                 break;
00526         case BOUNDARY_C:
00527         case BOUNDARY_R:
00528         case BOUNDARY_L:
00529                 p->setBrush(back);
00530                 p->drawRect(R_CENTER);
00531                 break;
00532         default:
00533                 break;
00534         }
00535         #undef P_CENTER
00536         #undef P_0
00537         #undef P_90
00538         #undef P_180
00539         #undef P_270
00540         #undef R_CENTER
00541 }
00542 
00543 void ListViewItem::paintGraph(const Rev& c, QPainter* p, const QColorGroup& cg, int width) {
00544 
00545         static const QColor colors[COLORS_NUM] = { Qt::black, Qt::red, DARK_GREEN,
00546                                                    Qt::blue,  Qt::darkGray, BROWN,
00547                                                    Qt::magenta, ORANGE };
00548         QListView* lv = myListView();
00549         if (!lv)
00550                 return;
00551 
00552         QColorGroup::ColorRole crole = QColorGroup::Base;
00553         if (isSelected() && lv->allColumnsShowFocus())
00554                 crole = QColorGroup::Highlight;
00555 
00556         QBrush back = cg.brush(crole);
00557         p->fillRect(0, 0, width, height(), back);
00558 
00559         const QValueVector<int>& lanes(c.lanes);
00560         uint laneNum = lanes.count();
00561         uint mergeLane = 0;
00562         for (uint i = 0; i < laneNum; i++)
00563                 if (isMerge(lanes[i])) {
00564                         mergeLane = i;
00565                         break;
00566                 }
00567 
00568         int x1 = 0, x2 = 0;
00569         int lw = laneWidth();
00570         for (uint i = 0; i < laneNum && x1 < width; i++) {
00571 
00572                 x1 = x2;
00573                 x2 += lw;
00574 
00575                 int ln = lanes[i];
00576                 if (ln == EMPTY)
00577                         continue;
00578 
00579                 uint col = (   isHead(ln) || isTail(ln) || isJoin(ln)
00580                             || ln == CROSS_EMPTY) ? mergeLane : i;
00581 
00582                 if (ln == CROSS) {
00583                         paintGraphLane(p, NOT_ACTIVE, x1, x2, colors[col % COLORS_NUM], back);
00584                         paintGraphLane(p, CROSS, x1, x2, colors[mergeLane % COLORS_NUM], back);
00585                 } else
00586                         paintGraphLane(p, ln, x1, x2, colors[col % COLORS_NUM], back);
00587         }
00588 }
00589 
00590 void ListViewItem::paintCell(QPainter* p, const QColorGroup& cg,
00591                              int column, int width, int alignment) {
00592         QColorGroup _cg(cg);
00593         const Rev& c = *git->revLookup(_sha, fh);
00594 
00595         
00596         if (!populated) {
00597                 populated = true;
00598                 setupData(c);
00599         }
00600         if (column == GRAPH_COL) {
00601                 paintGraph(c, p, _cg, width);
00602                 return;
00603         }
00604 
00605         
00606         int mycolumn = (!git->isMainHistory(fh) ? column : column + 1);
00607 
00608         
00609         if (isInfoCol(mycolumn))
00610                 _cg.setColor(QColorGroup::Base, isEvenLine ? EVEN_LINE_COL : ODD_LINE_COL);
00611 
00612         
00613         if (mycolumn == LOG_COL) {
00614 
00615                 paintTagMarks(column);
00616 
00617                 if (isHighlighted) {
00618                         QFont f(p->font());
00619                         f.setBold(true);
00620                         p->save();
00621                         p->setFont(f);
00622                 }
00623                 if (c.isDiffCache) {
00624                         if (changedFiles(ZERO_SHA))
00625                                 _cg.setColor(QColorGroup::Base, ORANGE);
00626                         else
00627                                 _cg.setColor(QColorGroup::Base, DARK_ORANGE);
00628                 }
00629         }
00630         
00631         if (isDiffTarget && isInfoCol(mycolumn))
00632                 _cg.setColor(QColorGroup::Base, LIGHT_BLUE);
00633 
00634         QListViewItem::paintCell(p, _cg, column, width, alignment);
00635 
00636         if (isHighlighted && mycolumn == LOG_COL)
00637                 p->restore();
00638 }
00639 
00640 void ListViewItem::paintTagMarks(int col) {
00641 
00642         uint rt = git->checkRef(_sha);
00643 
00644         if (!pixmap(col) && rt == 0)
00645                 return; 
00646 
00647         QPixmap* newPm = new QPixmap();
00648 
00649         if (rt & Git::BRANCH)
00650                 addBranchPixmap(&newPm);
00651 
00652         if (rt & Git::RMT_BRANCH)
00653                 addRefPixmap(&newPm, git->getRefName(_sha, Git::RMT_BRANCH), LIGHT_ORANGE);
00654 
00655         if (rt & Git::TAG)
00656                 addRefPixmap(&newPm, git->getRefName(_sha, Git::TAG), Qt::yellow);
00657 
00658         if (rt & Git::REF)
00659                 addRefPixmap(&newPm, git->getRefName(_sha, Git::REF), PURPLE);
00660 
00661         if (!pixmap(col) || (newPm->rect() != pixmap(col)->rect()))
00662                 setPixmap(col, *newPm);
00663 
00664         delete newPm;
00665 }
00666 
00667 void ListViewItem::addBranchPixmap(QPixmap** pp) {
00668 
00669         QString curBranch;
00670         SCList refs = git->getRefName(_sha, Git::BRANCH, &curBranch);
00671         FOREACH_SL (it, refs) {
00672                 bool isCur = (curBranch == *it);
00673                 QColor color(isCur ? Qt::green : DARK_GREEN);
00674                 addTextPixmap(pp, *it, color, isCur);
00675         }
00676 }
00677 
00678 void ListViewItem::addRefPixmap(QPixmap** pp, SCList refs, const QColor& color) {
00679 
00680         FOREACH_SL (it, refs)
00681                 addTextPixmap(pp, *it, color, false);
00682 }
00683 
00684 void ListViewItem::addTextPixmap(QPixmap** pp, SCRef text, const QColor& color, bool bold) {
00685 
00686         QFont fnt(myListView()->font());
00687         if (bold)
00688                 fnt.setBold(true);
00689 
00690         QFontMetrics fm(fnt);
00691         QPixmap* pm = *pp;
00692         int ofs = pm->isNull() ? 0 : pm->width() + 2;
00693         int spacing = 2;
00694         int pw = fm.boundingRect(text).width() + 2 * (spacing + int(bold));
00695         int ph = fm.height() + 1;
00696 
00697         QPixmap* newPm = new QPixmap(ofs + pw, ph);
00698 
00699         QPainter p;
00700         p.begin(newPm);
00701         if (!pm->isNull()) {
00702                 newPm->fill(isEvenLine ? EVEN_LINE_COL : ODD_LINE_COL);
00703                 p.drawPixmap(0, 0, *pm);
00704         }
00705         p.setPen(Qt::black);
00706         p.setBrush(color);
00707         p.setFont(fnt);
00708         p.drawRect(ofs, 0, pw, ph);
00709         p.drawText(ofs + spacing, fm.ascent(), text);
00710         p.end();
00711 
00712         delete pm;
00713         *pp = newPm;
00714 }
00715 
00716 bool ListViewItem::changedFiles(SCRef c) {
00717 
00718         const RevFile* f = git->getFiles(c);
00719         if (f)
00720                 for (int i = 0; i < f->count(); i++)
00721                         if (!f->statusCmp(i, RevFile::UNKNOWN))
00722                                 return true;
00723         return false;
00724 }
00725 
00726 void ListViewItem::setupData(const Rev& c) {
00727 
00728         
00729         if (c.lanes.count() == 0)
00730                 git->setLane(_sha, fh);
00731 
00732         
00733         int adj = !git->isMainHistory(fh) ? 0 : -1;
00734         if (_sha != ZERO_SHA) {
00735                 if (secs != 0) { 
00736                         secs -= c.authorDate().toULong();
00737                         setText(TIME_COL + adj, timeDiff(secs));
00738                 } else
00739                         setText(TIME_COL + adj, Git::getLocalDate(c.authorDate()));
00740         }
00741         setText(LOG_COL + adj, c.shortLog());
00742         setText(AUTH_COL + adj, c.author());
00743 }
00744 
00745 const QString ListViewItem::timeDiff(unsigned long secs) const {
00746 
00747         uint days  =  secs / (3600 * 24);
00748         uint hours = (secs - days * 3600 * 24) / 3600;
00749         uint min   = (secs - days * 3600 * 24 - hours * 3600) / 60;
00750         uint sec   =  secs - days * 3600 * 24 - hours * 3600 - min * 60;
00751         QString tmp;
00752         if (days > 0)
00753                 tmp.append(QString::number(days) + "d ");
00754 
00755         if (hours > 0 || !tmp.isEmpty())
00756                 tmp.append(QString::number(hours) + "h ");
00757 
00758         if (min > 0 || !tmp.isEmpty())
00759                 tmp.append(QString::number(min) + "m ");
00760 
00761         tmp.append(QString::number(sec) + "s");
00762         return tmp;
00763 }