File indexing completed on 2024-05-05 05:45:47
0001 /* 0002 SPDX-FileCopyrightText: 2001-2009 Otto Bruggeman <bruggie@gmail.com> 0003 SPDX-FileCopyrightText: 2001-2003 John Firebaugh <jfirebaugh@kde.org> 0004 SPDX-FileCopyrightText: 2004 Jeff Snyder <jeff@caffeinated.me.uk> 0005 SPDX-FileCopyrightText: 2007-2012 Kevin Kofler <kevin.kofler@chello.at> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 0010 #include "komparelistview.h" 0011 0012 #include <QStyle> 0013 #include <QPainter> 0014 #include <QTimer> 0015 #include <QResizeEvent> 0016 #include <QMouseEvent> 0017 #include <QWheelEvent> 0018 #include <QScrollBar> 0019 0020 #include <KSharedConfig> 0021 0022 #include <KompareDiff2/DiffModel> 0023 #include <KompareDiff2/DiffHunk> 0024 #include <KompareDiff2/Difference> 0025 #include <KompareDiff2/ModelList> 0026 0027 #include <komparepartdebug.h> 0028 #include "viewsettings.h" 0029 #include "komparesplitter.h" 0030 0031 #define COL_LINE_NO 0 0032 #define COL_MAIN 1 0033 0034 #define BLANK_LINE_HEIGHT 3 0035 #define HUNK_LINE_HEIGHT 5 0036 0037 #define ITEM_MARGIN 3 0038 0039 using namespace KompareDiff2; 0040 0041 KompareListViewFrame::KompareListViewFrame(bool isSource, 0042 ViewSettings* settings, 0043 KompareSplitter* parent, 0044 const char* name): 0045 QFrame(parent), 0046 m_view(isSource, settings, this, name), 0047 m_label(isSource ? QStringLiteral("Source") : QStringLiteral("Dest"), this), 0048 m_layout(this) 0049 { 0050 setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored)); 0051 m_label.setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); 0052 QFrame* bottomLine = new QFrame(this); 0053 bottomLine->setFrameShape(QFrame::HLine); 0054 bottomLine->setFrameShadow(QFrame::Plain); 0055 bottomLine->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed)); 0056 bottomLine->setFixedHeight(1); 0057 m_label.setMargin(3); 0058 m_layout.setSpacing(0); 0059 m_layout.setContentsMargins(0, 0, 0, 0); 0060 m_layout.addWidget(&m_label); 0061 m_layout.addWidget(bottomLine); 0062 m_layout.addWidget(&m_view); 0063 0064 connect(&m_view, &KompareListView::differenceClicked, 0065 parent, &KompareSplitter::slotDifferenceClicked); 0066 0067 connect(parent, &KompareSplitter::scrollViewsToId, &m_view, &KompareListView::scrollToId); 0068 connect(parent, &KompareSplitter::setXOffset, &m_view, &KompareListView::setXOffset); 0069 connect(&m_view, &KompareListView::resized, parent, &KompareSplitter::slotUpdateScrollBars); 0070 } 0071 0072 void KompareListViewFrame::slotSetModel(const DiffModel* model) 0073 { 0074 if (model) 0075 { 0076 if (view()->isSource()) { 0077 if (!model->sourceRevision().isEmpty()) 0078 m_label.setText(model->sourceFile() + QLatin1String(" (") + model->sourceRevision() + QLatin1Char(')')); 0079 else 0080 m_label.setText(model->sourceFile()); 0081 } else { 0082 if (!model->destinationRevision().isEmpty()) 0083 m_label.setText(model->destinationFile() + QLatin1String(" (") + model->destinationRevision() + QLatin1Char(')')); 0084 else 0085 m_label.setText(model->destinationFile()); 0086 } 0087 } else { 0088 m_label.setText(QString()); 0089 } 0090 } 0091 0092 KompareListView::KompareListView(bool isSource, 0093 ViewSettings* settings, 0094 QWidget* parent, const char* name) : 0095 QTreeWidget(parent), 0096 m_isSource(isSource), 0097 m_settings(settings), 0098 m_scrollId(-1), 0099 m_selectedModel(nullptr), 0100 m_selectedDifference(nullptr) 0101 { 0102 setObjectName(QLatin1String(name)); 0103 setItemDelegate(new KompareListViewItemDelegate(this)); 0104 setHeaderHidden(true); 0105 setColumnCount(3); // Line Number, Main, Blank 0106 setAllColumnsShowFocus(true); 0107 setRootIsDecorated(false); 0108 setIndentation(0); 0109 setFrameStyle(QFrame::NoFrame); 0110 setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); 0111 setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0112 setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0113 setFocusPolicy(Qt::NoFocus); 0114 setFont(m_settings->m_font); 0115 setFocusProxy(parent->parentWidget()); 0116 } 0117 0118 KompareListView::~KompareListView() 0119 { 0120 m_settings = nullptr; 0121 m_selectedModel = nullptr; 0122 m_selectedDifference = nullptr; 0123 } 0124 0125 KompareListViewItem* KompareListView::itemAtIndex(int i) 0126 { 0127 return m_items[ i ]; 0128 } 0129 0130 int KompareListView::firstVisibleDifference() 0131 { 0132 QTreeWidgetItem* item = itemAt(QPoint(0, 0)); 0133 0134 if (item == nullptr) 0135 { 0136 qCDebug(KOMPAREPART) << "no item at viewport coordinates (0,0)" ; 0137 } 0138 0139 while (item) { 0140 KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item); 0141 if (lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged) 0142 break; 0143 item = itemBelow(item); 0144 } 0145 0146 if (item) 0147 return m_items.indexOf(((KompareListViewLineItem*)item)->diffItemParent()); 0148 0149 return -1; 0150 } 0151 0152 int KompareListView::lastVisibleDifference() 0153 { 0154 QTreeWidgetItem* item = itemAt(QPoint(0, visibleHeight() - 1)); 0155 0156 if (item == nullptr) 0157 { 0158 qCDebug(KOMPAREPART) << "no item at viewport coordinates (0," << visibleHeight() - 1 << ")" ; 0159 // find last item 0160 item = itemAt(QPoint(0, 0)); 0161 if (item) { 0162 QTreeWidgetItem* nextItem = item; 0163 do { 0164 item = nextItem; 0165 nextItem = itemBelow(item); 0166 } while (nextItem); 0167 } 0168 } 0169 0170 while (item) { 0171 KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item); 0172 if (lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged) 0173 break; 0174 item = itemAbove(item); 0175 } 0176 0177 if (item) 0178 return m_items.indexOf(((KompareListViewLineItem*)item)->diffItemParent()); 0179 0180 return -1; 0181 } 0182 0183 QRect KompareListView::totalVisualItemRect(QTreeWidgetItem* item) 0184 { 0185 QRect total = visualItemRect(item); 0186 int n = item->childCount(); 0187 for (int i = 0; i < n; ++i) { 0188 QTreeWidgetItem* child = item->child(i); 0189 if (!child->isHidden()) 0190 total = total.united(totalVisualItemRect(child)); 0191 } 0192 return total; 0193 } 0194 0195 QRect KompareListView::itemRect(int i) 0196 { 0197 QTreeWidgetItem* item = itemAtIndex(i); 0198 return totalVisualItemRect(item); 0199 } 0200 0201 int KompareListView::minScrollId() 0202 { 0203 return visibleHeight() / 2; 0204 } 0205 0206 int KompareListView::maxScrollId() 0207 { 0208 int n = topLevelItemCount(); 0209 if (!n) return 0; 0210 KompareListViewItem* item = (KompareListViewItem*)topLevelItem(n - 1); 0211 int maxId = item->scrollId() + item->maxHeight() - minScrollId(); 0212 qCDebug(KOMPAREPART) << "Max ID = " << maxId ; 0213 return maxId; 0214 } 0215 0216 int KompareListView::contentsHeight() 0217 { 0218 return verticalScrollBar()->maximum() + viewport()->height() - style()->pixelMetric(QStyle::PM_ScrollBarExtent); 0219 } 0220 0221 int KompareListView::contentsWidth() 0222 { 0223 return (columnWidth(COL_LINE_NO) + columnWidth(COL_MAIN)); 0224 } 0225 0226 int KompareListView::visibleHeight() 0227 { 0228 return viewport()->height(); 0229 } 0230 0231 int KompareListView::visibleWidth() 0232 { 0233 return viewport()->width(); 0234 } 0235 0236 int KompareListView::contentsX() 0237 { 0238 return horizontalOffset(); 0239 } 0240 0241 int KompareListView::contentsY() 0242 { 0243 return verticalOffset(); 0244 } 0245 0246 int KompareListView::nextPaintOffset() const 0247 { 0248 return m_nextPaintOffset; 0249 } 0250 0251 void KompareListView::setNextPaintOffset(int offset) 0252 { 0253 m_nextPaintOffset = offset; 0254 } 0255 0256 void KompareListView::setXOffset(int x) 0257 { 0258 qCDebug(KOMPAREPART) << "SetXOffset : Scroll to x position: " << x ; 0259 horizontalScrollBar()->setValue(x); 0260 } 0261 0262 void KompareListView::scrollToId(int id) 0263 { 0264 // qCDebug(KOMPAREPART) << "ScrollToID : Scroll to id : " << id ; 0265 int n = topLevelItemCount(); 0266 KompareListViewItem* item = nullptr; 0267 if (n) { 0268 int i = 1; 0269 for (; i < n; ++i) { 0270 if (((KompareListViewItem*)topLevelItem(i))->scrollId() > id) 0271 break; 0272 } 0273 item = (KompareListViewItem*)topLevelItem(i - 1); 0274 } 0275 0276 if (item) { 0277 QRect rect = totalVisualItemRect(item); 0278 int pos = rect.top() + verticalOffset(); 0279 int itemId = item->scrollId(); 0280 int height = rect.height(); 0281 double r = (double)(id - itemId) / (double)item->maxHeight(); 0282 int y = pos + (int)(r * (double)height) - minScrollId(); 0283 // qCDebug(KOMPAREPART) << "scrollToID: " ; 0284 // qCDebug(KOMPAREPART) << " id = " << id ; 0285 // qCDebug(KOMPAREPART) << " pos = " << pos ; 0286 // qCDebug(KOMPAREPART) << " itemId = " << itemId ; 0287 // qCDebug(KOMPAREPART) << " r = " << r ; 0288 // qCDebug(KOMPAREPART) << " height = " << height ; 0289 // qCDebug(KOMPAREPART) << " minID = " << minScrollId() ; 0290 // qCDebug(KOMPAREPART) << " y = " << y ; 0291 // qCDebug(KOMPAREPART) << "contentsHeight = " << contentsHeight() ; 0292 // qCDebug(KOMPAREPART) << " c - y = " << contentsHeight() - y ; 0293 verticalScrollBar()->setValue(y); 0294 } 0295 0296 m_scrollId = id; 0297 } 0298 0299 int KompareListView::scrollId() 0300 { 0301 if (m_scrollId < 0) 0302 m_scrollId = minScrollId(); 0303 return m_scrollId; 0304 } 0305 0306 void KompareListView::setSelectedDifference(const Difference* diff, bool scroll) 0307 { 0308 qCDebug(KOMPAREPART) << "KompareListView::setSelectedDifference(" << diff << ", " << scroll << ")" ; 0309 0310 // When something other than a click causes this function to be called, 0311 // it'll only get called once, and all is simple. 0312 // 0313 // When the user clicks on a diff, this function will get called once when 0314 // komparesplitter::slotDifferenceClicked runs, and again when the 0315 // setSelection signal from the modelcontroller arrives. 0316 // 0317 // the first call (which will always be from the splitter) will have 0318 // scroll==false, and the second call will bail out here. 0319 // Which is why clicking on a difference does not cause the listviews to 0320 // scroll. 0321 if (m_selectedDifference == diff) 0322 return; 0323 0324 m_selectedDifference = diff; 0325 0326 KompareListViewItem* item = m_itemDict[ diff ]; 0327 if (!item) { 0328 qCDebug(KOMPAREPART) << "KompareListView::slotSetSelection(): couldn't find our selection!" ; 0329 return; 0330 } 0331 0332 // why does this not happen when the user clicks on a diff? see the comment above. 0333 if (scroll) 0334 scrollToId(item->scrollId()); 0335 setUpdatesEnabled(false); 0336 int x = horizontalScrollBar()->value(); 0337 int y = verticalScrollBar()->value(); 0338 setCurrentItem(item); 0339 horizontalScrollBar()->setValue(x); 0340 verticalScrollBar()->setValue(y); 0341 setUpdatesEnabled(true); 0342 } 0343 0344 void KompareListView::slotSetSelection(const Difference* diff) 0345 { 0346 qCDebug(KOMPAREPART) << "KompareListView::slotSetSelection( const Difference* diff )" ; 0347 0348 setSelectedDifference(diff, true); 0349 } 0350 0351 void KompareListView::slotSetSelection(const DiffModel* model, const Difference* diff) 0352 { 0353 qCDebug(KOMPAREPART) << "KompareListView::slotSetSelection( const DiffModel* model, const Difference* diff )" ; 0354 0355 if (m_selectedModel && m_selectedModel == model) { 0356 slotSetSelection(diff); 0357 return; 0358 } 0359 0360 clear(); 0361 m_items.clear(); 0362 m_itemDict.clear(); 0363 m_selectedModel = model; 0364 0365 const DiffHunkList* hunks = model->hunks(); 0366 DiffHunkListConstIterator hunkIt = hunks->begin(); 0367 DiffHunkListConstIterator hEnd = hunks->end(); 0368 0369 KompareListViewItem* item = nullptr; 0370 m_nextPaintOffset = 0; 0371 0372 for (; hunkIt != hEnd; ++hunkIt) 0373 { 0374 if (item) 0375 item = new KompareListViewHunkItem(this, item, *hunkIt, model->isBlended()); 0376 else 0377 item = new KompareListViewHunkItem(this, *hunkIt, model->isBlended()); 0378 0379 const DifferenceList differences = (*hunkIt)->differences(); 0380 DifferenceListConstIterator diffIt = differences.begin(); 0381 DifferenceListConstIterator dEnd = differences.end(); 0382 0383 for (; diffIt != dEnd; ++diffIt) 0384 { 0385 item = new KompareListViewDiffItem(this, item, *diffIt); 0386 0387 int type = (*diffIt)->type(); 0388 0389 if (type != Difference::Unchanged) 0390 { 0391 m_items.append((KompareListViewDiffItem*)item); 0392 m_itemDict.insert(*diffIt, (KompareListViewDiffItem*)item); 0393 } 0394 } 0395 } 0396 0397 resizeColumnToContents(COL_LINE_NO); 0398 resizeColumnToContents(COL_MAIN); 0399 0400 slotSetSelection(diff); 0401 } 0402 0403 KompareListViewDiffItem* KompareListView::diffItemAt(const QPoint& pos) 0404 { 0405 KompareListViewItem* item = static_cast<KompareListViewItem*>(itemAt(pos)); 0406 if (!item) 0407 return nullptr; 0408 switch (item->type()) { 0409 case KompareListViewItem::Hunk: 0410 if (item->paintHeight()) return nullptr; // no diff item here 0411 // zero height (fake 1 pixel height), so a diff item shines through 0412 return static_cast<KompareListViewDiffItem*>(itemBelow(item)); 0413 case KompareListViewItem::Line: 0414 case KompareListViewItem::Blank: 0415 return static_cast<KompareListViewLineItem*>(item)->diffItemParent(); 0416 case KompareListViewItem::Container: 0417 return static_cast<KompareListViewLineContainerItem*>(item)->diffItemParent(); 0418 case KompareListViewItem::Diff: 0419 return static_cast<KompareListViewDiffItem*>(item); 0420 default: 0421 return nullptr; 0422 } 0423 } 0424 0425 void KompareListView::mousePressEvent(QMouseEvent* e) 0426 { 0427 QPoint vp = e->pos(); 0428 KompareListViewDiffItem* diffItem = diffItemAt(vp); 0429 if (diffItem && diffItem->difference()->type() != Difference::Unchanged) { 0430 Q_EMIT differenceClicked(diffItem->difference()); 0431 } 0432 } 0433 0434 void KompareListView::mouseDoubleClickEvent(QMouseEvent* e) 0435 { 0436 QPoint vp = e->pos(); 0437 KompareListViewDiffItem* diffItem = diffItemAt(vp); 0438 if (diffItem && diffItem->difference()->type() != Difference::Unchanged) { 0439 // FIXME: make a new signal that does both 0440 Q_EMIT differenceClicked(diffItem->difference()); 0441 Q_EMIT applyDifference(!diffItem->difference()->applied()); 0442 } 0443 } 0444 0445 void KompareListView::renumberLines() 0446 { 0447 // qCDebug(KOMPAREPART) << "Begin" ; 0448 unsigned int newLineNo = 1; 0449 if (!topLevelItemCount()) return; 0450 KompareListViewItem* item = (KompareListViewItem*)topLevelItem(0); 0451 while (item) { 0452 // qCDebug(KOMPAREPART) << "type: " << item->type() ; 0453 if (item->type() != KompareListViewItem::Container 0454 && item->type() != KompareListViewItem::Blank 0455 && item->type() != KompareListViewItem::Hunk) 0456 { 0457 // qCDebug(KOMPAREPART) << QString::number( newLineNo ) ; 0458 item->setText(COL_LINE_NO, QString::number(newLineNo++)); 0459 } 0460 item = (KompareListViewItem*)itemBelow(item); 0461 } 0462 } 0463 0464 void KompareListView::slotApplyDifference(bool apply) 0465 { 0466 m_itemDict[ m_selectedDifference ]->applyDifference(apply); 0467 // now renumber the line column if this is the destination 0468 if (!m_isSource) 0469 renumberLines(); 0470 } 0471 0472 void KompareListView::slotApplyAllDifferences(bool apply) 0473 { 0474 QHash<const KompareDiff2::Difference*, KompareListViewDiffItem*>::ConstIterator it = m_itemDict.constBegin(); 0475 QHash<const KompareDiff2::Difference*, KompareListViewDiffItem*>::ConstIterator end = m_itemDict.constEnd(); 0476 for (; it != end; ++it) 0477 it.value()->applyDifference(apply); 0478 0479 // now renumber the line column if this is the destination 0480 if (!m_isSource) 0481 renumberLines(); 0482 update(); 0483 } 0484 0485 void KompareListView::slotApplyDifference(const Difference* diff, bool apply) 0486 { 0487 m_itemDict[ diff ]->applyDifference(apply); 0488 // now renumber the line column if this is the destination 0489 if (!m_isSource) 0490 renumberLines(); 0491 } 0492 0493 void KompareListView::wheelEvent(QWheelEvent* e) 0494 { 0495 e->ignore(); // we want the parent to catch wheel events 0496 } 0497 0498 void KompareListView::resizeEvent(QResizeEvent* e) 0499 { 0500 QTreeWidget::resizeEvent(e); 0501 Q_EMIT resized(); 0502 } 0503 0504 KompareListViewItemDelegate::KompareListViewItemDelegate(QObject* parent) 0505 : QStyledItemDelegate(parent) 0506 { 0507 } 0508 0509 KompareListViewItemDelegate::~KompareListViewItemDelegate() 0510 { 0511 } 0512 0513 void KompareListViewItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 0514 { 0515 int column = index.column(); 0516 QStyleOptionViewItem changedOption = option; 0517 if (column == COL_LINE_NO) 0518 changedOption.displayAlignment = Qt::AlignRight; 0519 KompareListViewItem* item = static_cast<KompareListViewItem*>(static_cast<KompareListView*>(parent())->itemFromIndex(index)); 0520 item->paintCell(painter, changedOption, column); 0521 } 0522 0523 QSize KompareListViewItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const 0524 { 0525 KompareListViewItem* item = static_cast<KompareListViewItem*>(static_cast<KompareListView*>(parent())->itemFromIndex(index)); 0526 QSize hint = QStyledItemDelegate::sizeHint(option, index); 0527 return QSize(hint.width() + ITEM_MARGIN, item->height()); 0528 } 0529 0530 KompareListViewItem::KompareListViewItem(KompareListView* parent, int type) 0531 : QTreeWidgetItem(parent, type), 0532 m_scrollId(0), 0533 m_height(0), 0534 m_paintHeight(0), 0535 m_paintOffset(parent->nextPaintOffset()) 0536 { 0537 // qCDebug(KOMPAREPART) << "Created KompareListViewItem with scroll id " << m_scrollId ; 0538 } 0539 0540 KompareListViewItem::KompareListViewItem(KompareListView* parent, KompareListViewItem* after, int type) 0541 : QTreeWidgetItem(parent, after, type), 0542 m_scrollId(after->scrollId() + after->maxHeight()), 0543 m_height(0), 0544 m_paintHeight(0), 0545 m_paintOffset(parent->nextPaintOffset()) 0546 { 0547 // qCDebug(KOMPAREPART) << "Created KompareListViewItem with scroll id " << m_scrollId ; 0548 } 0549 0550 KompareListViewItem::KompareListViewItem(KompareListViewItem* parent, int type) 0551 : QTreeWidgetItem(parent, type), 0552 m_scrollId(0), 0553 m_height(0), 0554 m_paintHeight(0), 0555 m_paintOffset(parent->kompareListView()->nextPaintOffset()) 0556 { 0557 } 0558 0559 KompareListViewItem::KompareListViewItem(KompareListViewItem* parent, KompareListViewItem* /*after*/, int type) 0560 : QTreeWidgetItem(parent, type), 0561 m_scrollId(0), 0562 m_height(0), 0563 m_paintHeight(0), 0564 m_paintOffset(parent->kompareListView()->nextPaintOffset()) 0565 { 0566 } 0567 0568 int KompareListViewItem::height() const 0569 { 0570 return m_height; 0571 } 0572 0573 void KompareListViewItem::setHeight(int h) 0574 { 0575 m_height = m_paintHeight = h; 0576 // QTreeWidget doesn't like zero height, fudge around it. 0577 m_height -= m_paintOffset; 0578 if (m_height <= 0) { 0579 kompareListView()->setNextPaintOffset(1 - m_height); 0580 m_height = 1; 0581 } else kompareListView()->setNextPaintOffset(0); 0582 } 0583 0584 int KompareListViewItem::paintHeight() const 0585 { 0586 return m_paintHeight; 0587 } 0588 0589 int KompareListViewItem::paintOffset() const 0590 { 0591 return m_paintOffset; 0592 } 0593 0594 bool KompareListViewItem::isCurrent() const 0595 { 0596 return treeWidget()->currentItem() == this; 0597 } 0598 0599 KompareListView* KompareListViewItem::kompareListView() const 0600 { 0601 return (KompareListView*)treeWidget(); 0602 } 0603 0604 void KompareListViewItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column) 0605 { 0606 // Default implementation for zero-height items. 0607 // We have to paint the item which shines through or we'll end up with glitches. 0608 KompareListViewItem* nextItem = (KompareListViewItem*)kompareListView()->itemBelow(this); 0609 if (nextItem) { 0610 QStyleOptionViewItem changedOption = option; 0611 changedOption.rect.translate(0, height()); 0612 nextItem->paintCell(p, changedOption, column); 0613 } 0614 } 0615 0616 KompareListViewDiffItem::KompareListViewDiffItem(KompareListView* parent, Difference* difference) 0617 : KompareListViewItem(parent, Diff), 0618 m_difference(difference), 0619 m_sourceItem(nullptr), 0620 m_destItem(nullptr) 0621 { 0622 init(); 0623 } 0624 0625 KompareListViewDiffItem::KompareListViewDiffItem(KompareListView* parent, KompareListViewItem* after, Difference* difference) 0626 : KompareListViewItem(parent, after, Diff), 0627 m_difference(difference), 0628 m_sourceItem(nullptr), 0629 m_destItem(nullptr) 0630 { 0631 init(); 0632 } 0633 0634 KompareListViewDiffItem::~KompareListViewDiffItem() 0635 { 0636 m_difference = nullptr; 0637 } 0638 0639 void KompareListViewDiffItem::init() 0640 { 0641 setHeight(0); 0642 setExpanded(true); 0643 int nextPaintOffset = kompareListView()->nextPaintOffset(); 0644 m_destItem = new KompareListViewLineContainerItem(this, false); 0645 kompareListView()->setNextPaintOffset(nextPaintOffset); 0646 m_sourceItem = new KompareListViewLineContainerItem(this, true); 0647 setVisibility(); 0648 } 0649 0650 void KompareListViewDiffItem::setVisibility() 0651 { 0652 m_sourceItem->setHidden(!(kompareListView()->isSource() || m_difference->applied())); 0653 m_destItem->setHidden(!m_sourceItem->isHidden()); 0654 } 0655 0656 void KompareListViewDiffItem::applyDifference(bool apply) 0657 { 0658 qCDebug(KOMPAREPART) << "KompareListViewDiffItem::applyDifference( " << apply << " )" ; 0659 setVisibility(); 0660 } 0661 0662 int KompareListViewDiffItem::maxHeight() 0663 { 0664 int lines = qMax(m_difference->sourceLineCount(), m_difference->destinationLineCount()); 0665 if (lines == 0) 0666 return BLANK_LINE_HEIGHT; 0667 else 0668 return lines * treeWidget()->fontMetrics().height(); 0669 } 0670 0671 KompareListViewLineContainerItem::KompareListViewLineContainerItem(KompareListViewDiffItem* parent, bool isSource) 0672 : KompareListViewItem(parent, Container), 0673 m_blankLineItem(nullptr), 0674 m_isSource(isSource) 0675 { 0676 // qCDebug(KOMPAREPART) << "isSource ? " << (isSource ? " Yes!" : " No!") ; 0677 setHeight(0); 0678 setExpanded(true); 0679 0680 int lines = lineCount(); 0681 int line = lineNumber(); 0682 // qCDebug(KOMPAREPART) << "LineNumber : " << lineNumber() ; 0683 if (lines == 0) { 0684 m_blankLineItem = new KompareListViewBlankLineItem(this); 0685 return; 0686 } 0687 0688 for (int i = 0; i < lines; ++i, ++line) { 0689 new KompareListViewLineItem(this, line, lineAt(i)); 0690 } 0691 } 0692 0693 KompareListViewLineContainerItem::~KompareListViewLineContainerItem() 0694 { 0695 } 0696 0697 KompareListViewDiffItem* KompareListViewLineContainerItem::diffItemParent() const 0698 { 0699 return (KompareListViewDiffItem*)parent(); 0700 } 0701 0702 int KompareListViewLineContainerItem::lineCount() const 0703 { 0704 return m_isSource ? diffItemParent()->difference()->sourceLineCount() : 0705 diffItemParent()->difference()->destinationLineCount(); 0706 } 0707 0708 int KompareListViewLineContainerItem::lineNumber() const 0709 { 0710 return m_isSource ? diffItemParent()->difference()->sourceLineNumber() : 0711 diffItemParent()->difference()->destinationLineNumber(); 0712 } 0713 0714 DifferenceString* KompareListViewLineContainerItem::lineAt(int i) const 0715 { 0716 return m_isSource ? diffItemParent()->difference()->sourceLineAt(i) : 0717 diffItemParent()->difference()->destinationLineAt(i); 0718 } 0719 0720 KompareListViewLineItem::KompareListViewLineItem(KompareListViewLineContainerItem* parent, int line, DifferenceString* text) 0721 : KompareListViewItem(parent, Line) 0722 { 0723 init(line, text); 0724 } 0725 0726 KompareListViewLineItem::KompareListViewLineItem(KompareListViewLineContainerItem* parent, int line, DifferenceString* text, int type) 0727 : KompareListViewItem(parent, type) 0728 { 0729 init(line, text); 0730 } 0731 0732 KompareListViewLineItem::~KompareListViewLineItem() 0733 { 0734 m_text = nullptr; 0735 } 0736 0737 void KompareListViewLineItem::init(int line, DifferenceString* text) 0738 { 0739 setHeight(treeWidget()->fontMetrics().height()); 0740 setText(COL_LINE_NO, QString::number(line)); 0741 setText(COL_MAIN, text->string()); 0742 m_text = text; 0743 } 0744 0745 void KompareListViewLineItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column) 0746 { 0747 int width = option.rect.width(); 0748 Qt::Alignment align = option.displayAlignment; 0749 0750 p->setRenderHint(QPainter::Antialiasing); 0751 p->translate(option.rect.topLeft()); 0752 p->translate(0, -paintOffset()); 0753 0754 QColor bg(Qt::white); // Always make the background white when it is not a real difference 0755 if (diffItemParent()->difference()->type() == Difference::Unchanged) 0756 { 0757 if (column == COL_LINE_NO) 0758 { 0759 bg = QColor(Qt::lightGray); 0760 } 0761 } 0762 else 0763 { 0764 bg = kompareListView()->settings()->colorForDifferenceType( 0765 diffItemParent()->difference()->type(), 0766 diffItemParent()->isCurrent(), 0767 diffItemParent()->difference()->applied()); 0768 } 0769 0770 // Paint background 0771 p->fillRect(0, 0, width, paintHeight(), bg); 0772 0773 // Paint foreground 0774 if (diffItemParent()->difference()->type() == Difference::Unchanged) 0775 p->setPen(QColor(Qt::darkGray)); // always make normal text gray 0776 else 0777 p->setPen(QColor(Qt::black)); // make text with changes black 0778 0779 paintText(p, bg, column, width, align); 0780 0781 // Paint darker lines around selected item 0782 if (diffItemParent()->isCurrent()) 0783 { 0784 p->translate(0.5, 0.5); 0785 p->setPen(bg.darker(135)); 0786 QTreeWidgetItem* parentItem = parent(); 0787 if (this == parentItem->child(0)) 0788 p->drawLine(0, 0, width, 0); 0789 if (this == parentItem->child(parentItem->childCount() - 1)) 0790 p->drawLine(0, paintHeight() - 1, width, paintHeight() - 1); 0791 } 0792 0793 p->resetTransform(); 0794 } 0795 0796 void KompareListViewLineItem::paintText(QPainter* p, const QColor& bg, int column, int width, int align) 0797 { 0798 if (column == COL_MAIN) 0799 { 0800 QString textChunk; 0801 int offset = ITEM_MARGIN; 0802 int prevValue = 0; 0803 int charsDrawn = 0; 0804 int chunkWidth; 0805 QBrush changeBrush(bg, Qt::Dense3Pattern); 0806 QBrush normalBrush(bg, Qt::SolidPattern); 0807 QBrush brush; 0808 0809 if (m_text->string().isEmpty()) 0810 { 0811 p->fillRect(0, 0, width, paintHeight(), normalBrush); 0812 return; 0813 } 0814 0815 p->fillRect(0, 0, offset, paintHeight(), normalBrush); 0816 0817 const MarkerList markerList = m_text->markerList(); 0818 if (!markerList.isEmpty()) 0819 { 0820 MarkerListConstIterator markerIt = markerList.begin(); 0821 MarkerListConstIterator mEnd = markerList.end(); 0822 Marker* m = *markerIt; 0823 0824 for (; markerIt != mEnd; ++markerIt) 0825 { 0826 m = *markerIt; 0827 textChunk = m_text->string().mid(prevValue, m->offset() - prevValue); 0828 // qCDebug(KOMPAREPART) << "TextChunk = \"" << textChunk << "\"" ; 0829 // qCDebug(KOMPAREPART) << "c->offset() = " << c->offset() ; 0830 // qCDebug(KOMPAREPART) << "prevValue = " << prevValue ; 0831 expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn); 0832 charsDrawn += textChunk.length(); 0833 prevValue = m->offset(); 0834 if (m->type() == Marker::End) 0835 { 0836 QFont font(p->font()); 0837 font.setBold(true); 0838 p->setFont(font); 0839 // p->setPen( Qt::blue ); 0840 brush = changeBrush; 0841 } 0842 else 0843 { 0844 QFont font(p->font()); 0845 font.setBold(false); 0846 p->setFont(font); 0847 // p->setPen( Qt::black ); 0848 brush = normalBrush; 0849 } 0850 chunkWidth = p->fontMetrics().horizontalAdvance(textChunk); 0851 p->fillRect(offset, 0, chunkWidth, paintHeight(), brush); 0852 p->drawText(offset, 0, 0853 chunkWidth, paintHeight(), 0854 align, textChunk); 0855 offset += chunkWidth; 0856 } 0857 } 0858 if (prevValue < m_text->string().length()) 0859 { 0860 // Still have to draw some string without changes 0861 textChunk = m_text->string().mid(prevValue, qMax(1, m_text->string().length() - prevValue)); 0862 expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn); 0863 // qCDebug(KOMPAREPART) << "TextChunk = \"" << textChunk << "\"" ; 0864 QFont font(p->font()); 0865 font.setBold(false); 0866 p->setFont(font); 0867 chunkWidth = p->fontMetrics().horizontalAdvance(textChunk); 0868 p->fillRect(offset, 0, chunkWidth, paintHeight(), normalBrush); 0869 p->drawText(offset, 0, 0870 chunkWidth, paintHeight(), 0871 align, textChunk); 0872 offset += chunkWidth; 0873 } 0874 p->fillRect(offset, 0, width - offset, paintHeight(), normalBrush); 0875 } 0876 else 0877 { 0878 p->fillRect(0, 0, width, paintHeight(), bg); 0879 p->drawText(ITEM_MARGIN, 0, 0880 width - ITEM_MARGIN, paintHeight(), 0881 align, text(column)); 0882 } 0883 } 0884 0885 void KompareListViewLineItem::expandTabs(QString& text, int tabstop, int startPos) const 0886 { 0887 int index; 0888 while ((index = text.indexOf(QChar(9))) != -1) 0889 text.replace(index, 1, QString(tabstop - ((startPos + index) % tabstop), QLatin1Char(' '))); 0890 } 0891 0892 KompareListViewDiffItem* KompareListViewLineItem::diffItemParent() const 0893 { 0894 KompareListViewLineContainerItem* p = (KompareListViewLineContainerItem*)parent(); 0895 return p->diffItemParent(); 0896 } 0897 0898 KompareListViewBlankLineItem::KompareListViewBlankLineItem(KompareListViewLineContainerItem* parent) 0899 : KompareListViewLineItem(parent, 0, new DifferenceString(), Blank) 0900 { 0901 setHeight(BLANK_LINE_HEIGHT); 0902 } 0903 0904 void KompareListViewBlankLineItem::paintText(QPainter* p, const QColor& bg, int column, int width, int /* align */) 0905 { 0906 if (column == COL_MAIN) 0907 { 0908 QBrush normalBrush(bg, Qt::SolidPattern); 0909 p->fillRect(0, 0, width, paintHeight(), normalBrush); 0910 } 0911 } 0912 0913 KompareListViewHunkItem::KompareListViewHunkItem(KompareListView* parent, DiffHunk* hunk, bool zeroHeight) 0914 : KompareListViewItem(parent, Hunk), 0915 m_zeroHeight(zeroHeight), 0916 m_hunk(hunk) 0917 { 0918 setHeight(maxHeight()); 0919 setFlags(flags() & ~Qt::ItemIsSelectable); 0920 } 0921 0922 KompareListViewHunkItem::KompareListViewHunkItem(KompareListView* parent, KompareListViewItem* after, DiffHunk* hunk, bool zeroHeight) 0923 : KompareListViewItem(parent, after, Hunk), 0924 m_zeroHeight(zeroHeight), 0925 m_hunk(hunk) 0926 { 0927 setHeight(maxHeight()); 0928 setFlags(flags() & ~Qt::ItemIsSelectable); 0929 } 0930 0931 KompareListViewHunkItem::~KompareListViewHunkItem() 0932 { 0933 m_hunk = nullptr; 0934 } 0935 0936 int KompareListViewHunkItem::maxHeight() 0937 { 0938 if (m_zeroHeight) { 0939 return 0; 0940 } else if (m_hunk->function().isEmpty()) { 0941 return HUNK_LINE_HEIGHT; 0942 } else { 0943 return treeWidget()->fontMetrics().height(); 0944 } 0945 } 0946 0947 void KompareListViewHunkItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column) 0948 { 0949 if (m_zeroHeight) { 0950 KompareListViewItem::paintCell(p, option, column); 0951 } else { 0952 int x = option.rect.left(); 0953 int y = option.rect.top() - paintOffset(); 0954 int width = option.rect.width(); 0955 Qt::Alignment align = option.displayAlignment; 0956 0957 p->fillRect(x, y, width, paintHeight(), QColor(Qt::lightGray)); // Hunk headers should be lightgray 0958 p->setPen(QColor(Qt::black)); // Text color in hunk should be black 0959 if (column == COL_MAIN) { 0960 p->drawText(x + ITEM_MARGIN, y, width - ITEM_MARGIN, paintHeight(), 0961 align, m_hunk->function()); 0962 } 0963 } 0964 } 0965 0966 #include "moc_komparelistview.cpp"