listview.cpp

Go to the documentation of this file.
00001 /*
00002         Description: qgit revision list view
00003 
00004         Author: Marco Costalba (C) 2005-2006
00005 
00006         Copyright: See COPYING file that comes with this distribution
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(); // to init some stuff
00028 
00029         lv->setAcceptDrops(git->isMainHistory(fh));
00030         lv->viewport()->setAcceptDrops(git->isMainHistory(fh));
00031         lv->viewport()->installEventFilter(this); // filter out some right clicks
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); // non blocking
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); // width is almost constant
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; // avoid a dangling pointer
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         // check to early skip common case of list mouse browsing
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 // code taken from QListView::findItem() sources
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         // remove highlight on any previous target
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); // do highlight
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()); // just a refresh
00190                 lv->ensureItemVisible(item);
00191         } else {
00192                 // setCurrentItem() does not clear previous
00193                 // selections in a multi selection QListView
00194                 lv->clearSelection();
00195 
00196                 item = findItemSha(st->sha());
00197                 if (item) {
00198                         lv->setCurrentItem(item); // calls on_currentChanged()
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 // ************************************ SLOTS ********************************
00210 
00211 void ListView::on_newRevsAdded(const FileHistory* f, const QValueVector<QString>& shaVec) {
00212 
00213         if (f != fh) // signal newRevsAdded() is broadcast
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) { // to avoid looping and spurious calls
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            when current item is not selected, as example after opening a new
00247            file history tab, then clicking on it does not fires currentChanged()
00248            signal. We use this kludge to trigger that case and force an update.
00249            It works because this slot is called always after on_currentChanged()
00250         */
00251         if (item && !currentChangedEmitted && item == lv->currentItem() && item->isSelected())
00252                 on_currentChanged(item);
00253 
00254         currentChangedEmitted = false; // reset the flag
00255 }
00256 
00257 void ListView::on_clicked(QListViewItem*) {
00258 
00259         d->setReadyToDrag(false); // in case of just click without moving
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(); // do not delete drObj. Blocking until drop event
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                 // event filter does not work on them
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 // we need an event filter for:
00296 //  - filter out some right click mouse events
00297 //  - intercept drop events sent to listview
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) { // check for 'diff to' function
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(""); // restore std view
00327 
00328                         filterNextContextMenuRequest = true;
00329                         UPDATE_DOMAIN(d);
00330                         return true; // filter event out
00331                 }
00332         }
00333         // check for 'children & parents' function, i.e. if mouse is on the graph
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; // filter event out
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         // first find the parents
00355         p.clear();
00356         QString root;
00357         SCRef sha(item->sha());
00358         if (!isFreeLane(t)) {
00359                 p = git->revLookup(sha)->parents(); // pointer cannot be NULL
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         // then find children
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                 // some sanity check on dropped data
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; // filter out
00390 }
00391 
00392 // ****************************** ListViewItem *****************************
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); // 'r' cannot be NULL
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 /* Draw graph part for a lane
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         // vertical line
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         // horizontal line
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         // center symbol, e.g. rect or ellipse
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                 // Red minus sign
00511                 p->setPen(Qt::NoPen);
00512                 p->setBrush(red);
00513                 p->drawRect(m - r, h - 1, d, 2);
00514                 break;
00515         case APPLIED:
00516                 // Green plus sign
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         // lazy setup, only once when visible
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         // adjust for annotation id column presence
00606         int mycolumn = (!git->isMainHistory(fh) ? column : column + 1);
00607 
00608         // alternate background color
00609         if (isInfoCol(mycolumn))
00610                 _cg.setColor(QColorGroup::Base, isEvenLine ? EVEN_LINE_COL : ODD_LINE_COL);
00611 
00612         // tags, heads, refs and working dir colouring
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         // diff target colouring
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; // common case
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         // calculate lanes
00729         if (c.lanes.count() == 0)
00730                 git->setLane(_sha, fh);
00731 
00732         // set time/date column
00733         int adj = !git->isMainHistory(fh) ? 0 : -1;
00734         if (_sha != ZERO_SHA) {
00735                 if (secs != 0) { // secs is 0 for absolute date
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 }

Generated on Fri Dec 7 21:57:37 2007 for QGit by  doxygen 1.5.3