File indexing completed on 2024-05-12 09:48:32
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/KompareModelList> 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 Diff2; 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 DiffHunkListConstIterator hunkIt = model->hunks()->begin(); 0366 DiffHunkListConstIterator hEnd = model->hunks()->end(); 0367 0368 KompareListViewItem* item = nullptr; 0369 m_nextPaintOffset = 0; 0370 0371 for (; hunkIt != hEnd; ++hunkIt) 0372 { 0373 if (item) 0374 item = new KompareListViewHunkItem(this, item, *hunkIt, model->isBlended()); 0375 else 0376 item = new KompareListViewHunkItem(this, *hunkIt, model->isBlended()); 0377 0378 DifferenceListConstIterator diffIt = (*hunkIt)->differences().begin(); 0379 DifferenceListConstIterator dEnd = (*hunkIt)->differences().end(); 0380 0381 for (; diffIt != dEnd; ++diffIt) 0382 { 0383 item = new KompareListViewDiffItem(this, item, *diffIt); 0384 0385 int type = (*diffIt)->type(); 0386 0387 if (type != Difference::Unchanged) 0388 { 0389 m_items.append((KompareListViewDiffItem*)item); 0390 m_itemDict.insert(*diffIt, (KompareListViewDiffItem*)item); 0391 } 0392 } 0393 } 0394 0395 resizeColumnToContents(COL_LINE_NO); 0396 resizeColumnToContents(COL_MAIN); 0397 0398 slotSetSelection(diff); 0399 } 0400 0401 KompareListViewDiffItem* KompareListView::diffItemAt(const QPoint& pos) 0402 { 0403 KompareListViewItem* item = static_cast<KompareListViewItem*>(itemAt(pos)); 0404 if (!item) 0405 return nullptr; 0406 switch (item->type()) { 0407 case KompareListViewItem::Hunk: 0408 if (item->paintHeight()) return nullptr; // no diff item here 0409 // zero height (fake 1 pixel height), so a diff item shines through 0410 return static_cast<KompareListViewDiffItem*>(itemBelow(item)); 0411 case KompareListViewItem::Line: 0412 case KompareListViewItem::Blank: 0413 return static_cast<KompareListViewLineItem*>(item)->diffItemParent(); 0414 case KompareListViewItem::Container: 0415 return static_cast<KompareListViewLineContainerItem*>(item)->diffItemParent(); 0416 case KompareListViewItem::Diff: 0417 return static_cast<KompareListViewDiffItem*>(item); 0418 default: 0419 return nullptr; 0420 } 0421 } 0422 0423 void KompareListView::mousePressEvent(QMouseEvent* e) 0424 { 0425 QPoint vp = e->pos(); 0426 KompareListViewDiffItem* diffItem = diffItemAt(vp); 0427 if (diffItem && diffItem->difference()->type() != Difference::Unchanged) { 0428 Q_EMIT differenceClicked(diffItem->difference()); 0429 } 0430 } 0431 0432 void KompareListView::mouseDoubleClickEvent(QMouseEvent* e) 0433 { 0434 QPoint vp = e->pos(); 0435 KompareListViewDiffItem* diffItem = diffItemAt(vp); 0436 if (diffItem && diffItem->difference()->type() != Difference::Unchanged) { 0437 // FIXME: make a new signal that does both 0438 Q_EMIT differenceClicked(diffItem->difference()); 0439 Q_EMIT applyDifference(!diffItem->difference()->applied()); 0440 } 0441 } 0442 0443 void KompareListView::renumberLines() 0444 { 0445 // qCDebug(KOMPAREPART) << "Begin" ; 0446 unsigned int newLineNo = 1; 0447 if (!topLevelItemCount()) return; 0448 KompareListViewItem* item = (KompareListViewItem*)topLevelItem(0); 0449 while (item) { 0450 // qCDebug(KOMPAREPART) << "type: " << item->type() ; 0451 if (item->type() != KompareListViewItem::Container 0452 && item->type() != KompareListViewItem::Blank 0453 && item->type() != KompareListViewItem::Hunk) 0454 { 0455 // qCDebug(KOMPAREPART) << QString::number( newLineNo ) ; 0456 item->setText(COL_LINE_NO, QString::number(newLineNo++)); 0457 } 0458 item = (KompareListViewItem*)itemBelow(item); 0459 } 0460 } 0461 0462 void KompareListView::slotApplyDifference(bool apply) 0463 { 0464 m_itemDict[ m_selectedDifference ]->applyDifference(apply); 0465 // now renumber the line column if this is the destination 0466 if (!m_isSource) 0467 renumberLines(); 0468 } 0469 0470 void KompareListView::slotApplyAllDifferences(bool apply) 0471 { 0472 QHash<const Diff2::Difference*, KompareListViewDiffItem*>::ConstIterator it = m_itemDict.constBegin(); 0473 QHash<const Diff2::Difference*, KompareListViewDiffItem*>::ConstIterator end = m_itemDict.constEnd(); 0474 for (; it != end; ++it) 0475 it.value()->applyDifference(apply); 0476 0477 // now renumber the line column if this is the destination 0478 if (!m_isSource) 0479 renumberLines(); 0480 update(); 0481 } 0482 0483 void KompareListView::slotApplyDifference(const Difference* diff, bool apply) 0484 { 0485 m_itemDict[ diff ]->applyDifference(apply); 0486 // now renumber the line column if this is the destination 0487 if (!m_isSource) 0488 renumberLines(); 0489 } 0490 0491 void KompareListView::wheelEvent(QWheelEvent* e) 0492 { 0493 e->ignore(); // we want the parent to catch wheel events 0494 } 0495 0496 void KompareListView::resizeEvent(QResizeEvent* e) 0497 { 0498 QTreeWidget::resizeEvent(e); 0499 Q_EMIT resized(); 0500 } 0501 0502 KompareListViewItemDelegate::KompareListViewItemDelegate(QObject* parent) 0503 : QStyledItemDelegate(parent) 0504 { 0505 } 0506 0507 KompareListViewItemDelegate::~KompareListViewItemDelegate() 0508 { 0509 } 0510 0511 void KompareListViewItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 0512 { 0513 int column = index.column(); 0514 QStyleOptionViewItem changedOption = option; 0515 if (column == COL_LINE_NO) 0516 changedOption.displayAlignment = Qt::AlignRight; 0517 KompareListViewItem* item = static_cast<KompareListViewItem*>(static_cast<KompareListView*>(parent())->itemFromIndex(index)); 0518 item->paintCell(painter, changedOption, column); 0519 } 0520 0521 QSize KompareListViewItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const 0522 { 0523 KompareListViewItem* item = static_cast<KompareListViewItem*>(static_cast<KompareListView*>(parent())->itemFromIndex(index)); 0524 QSize hint = QStyledItemDelegate::sizeHint(option, index); 0525 return QSize(hint.width() + ITEM_MARGIN, item->height()); 0526 } 0527 0528 KompareListViewItem::KompareListViewItem(KompareListView* parent, int type) 0529 : QTreeWidgetItem(parent, type), 0530 m_scrollId(0), 0531 m_height(0), 0532 m_paintHeight(0), 0533 m_paintOffset(parent->nextPaintOffset()) 0534 { 0535 // qCDebug(KOMPAREPART) << "Created KompareListViewItem with scroll id " << m_scrollId ; 0536 } 0537 0538 KompareListViewItem::KompareListViewItem(KompareListView* parent, KompareListViewItem* after, int type) 0539 : QTreeWidgetItem(parent, after, type), 0540 m_scrollId(after->scrollId() + after->maxHeight()), 0541 m_height(0), 0542 m_paintHeight(0), 0543 m_paintOffset(parent->nextPaintOffset()) 0544 { 0545 // qCDebug(KOMPAREPART) << "Created KompareListViewItem with scroll id " << m_scrollId ; 0546 } 0547 0548 KompareListViewItem::KompareListViewItem(KompareListViewItem* parent, int type) 0549 : QTreeWidgetItem(parent, type), 0550 m_scrollId(0), 0551 m_height(0), 0552 m_paintHeight(0), 0553 m_paintOffset(parent->kompareListView()->nextPaintOffset()) 0554 { 0555 } 0556 0557 KompareListViewItem::KompareListViewItem(KompareListViewItem* parent, KompareListViewItem* /*after*/, int type) 0558 : QTreeWidgetItem(parent, type), 0559 m_scrollId(0), 0560 m_height(0), 0561 m_paintHeight(0), 0562 m_paintOffset(parent->kompareListView()->nextPaintOffset()) 0563 { 0564 } 0565 0566 int KompareListViewItem::height() const 0567 { 0568 return m_height; 0569 } 0570 0571 void KompareListViewItem::setHeight(int h) 0572 { 0573 m_height = m_paintHeight = h; 0574 // QTreeWidget doesn't like zero height, fudge around it. 0575 m_height -= m_paintOffset; 0576 if (m_height <= 0) { 0577 kompareListView()->setNextPaintOffset(1 - m_height); 0578 m_height = 1; 0579 } else kompareListView()->setNextPaintOffset(0); 0580 } 0581 0582 int KompareListViewItem::paintHeight() const 0583 { 0584 return m_paintHeight; 0585 } 0586 0587 int KompareListViewItem::paintOffset() const 0588 { 0589 return m_paintOffset; 0590 } 0591 0592 bool KompareListViewItem::isCurrent() const 0593 { 0594 return treeWidget()->currentItem() == this; 0595 } 0596 0597 KompareListView* KompareListViewItem::kompareListView() const 0598 { 0599 return (KompareListView*)treeWidget(); 0600 } 0601 0602 void KompareListViewItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column) 0603 { 0604 // Default implementation for zero-height items. 0605 // We have to paint the item which shines through or we'll end up with glitches. 0606 KompareListViewItem* nextItem = (KompareListViewItem*)kompareListView()->itemBelow(this); 0607 if (nextItem) { 0608 QStyleOptionViewItem changedOption = option; 0609 changedOption.rect.translate(0, height()); 0610 nextItem->paintCell(p, changedOption, column); 0611 } 0612 } 0613 0614 KompareListViewDiffItem::KompareListViewDiffItem(KompareListView* parent, Difference* difference) 0615 : KompareListViewItem(parent, Diff), 0616 m_difference(difference), 0617 m_sourceItem(nullptr), 0618 m_destItem(nullptr) 0619 { 0620 init(); 0621 } 0622 0623 KompareListViewDiffItem::KompareListViewDiffItem(KompareListView* parent, KompareListViewItem* after, Difference* difference) 0624 : KompareListViewItem(parent, after, Diff), 0625 m_difference(difference), 0626 m_sourceItem(nullptr), 0627 m_destItem(nullptr) 0628 { 0629 init(); 0630 } 0631 0632 KompareListViewDiffItem::~KompareListViewDiffItem() 0633 { 0634 m_difference = nullptr; 0635 } 0636 0637 void KompareListViewDiffItem::init() 0638 { 0639 setHeight(0); 0640 setExpanded(true); 0641 int nextPaintOffset = kompareListView()->nextPaintOffset(); 0642 m_destItem = new KompareListViewLineContainerItem(this, false); 0643 kompareListView()->setNextPaintOffset(nextPaintOffset); 0644 m_sourceItem = new KompareListViewLineContainerItem(this, true); 0645 setVisibility(); 0646 } 0647 0648 void KompareListViewDiffItem::setVisibility() 0649 { 0650 m_sourceItem->setHidden(!(kompareListView()->isSource() || m_difference->applied())); 0651 m_destItem->setHidden(!m_sourceItem->isHidden()); 0652 } 0653 0654 void KompareListViewDiffItem::applyDifference(bool apply) 0655 { 0656 qCDebug(KOMPAREPART) << "KompareListViewDiffItem::applyDifference( " << apply << " )" ; 0657 setVisibility(); 0658 } 0659 0660 int KompareListViewDiffItem::maxHeight() 0661 { 0662 int lines = qMax(m_difference->sourceLineCount(), m_difference->destinationLineCount()); 0663 if (lines == 0) 0664 return BLANK_LINE_HEIGHT; 0665 else 0666 return lines * treeWidget()->fontMetrics().height(); 0667 } 0668 0669 KompareListViewLineContainerItem::KompareListViewLineContainerItem(KompareListViewDiffItem* parent, bool isSource) 0670 : KompareListViewItem(parent, Container), 0671 m_blankLineItem(nullptr), 0672 m_isSource(isSource) 0673 { 0674 // qCDebug(KOMPAREPART) << "isSource ? " << (isSource ? " Yes!" : " No!") ; 0675 setHeight(0); 0676 setExpanded(true); 0677 0678 int lines = lineCount(); 0679 int line = lineNumber(); 0680 // qCDebug(KOMPAREPART) << "LineNumber : " << lineNumber() ; 0681 if (lines == 0) { 0682 m_blankLineItem = new KompareListViewBlankLineItem(this); 0683 return; 0684 } 0685 0686 for (int i = 0; i < lines; ++i, ++line) { 0687 new KompareListViewLineItem(this, line, lineAt(i)); 0688 } 0689 } 0690 0691 KompareListViewLineContainerItem::~KompareListViewLineContainerItem() 0692 { 0693 } 0694 0695 KompareListViewDiffItem* KompareListViewLineContainerItem::diffItemParent() const 0696 { 0697 return (KompareListViewDiffItem*)parent(); 0698 } 0699 0700 int KompareListViewLineContainerItem::lineCount() const 0701 { 0702 return m_isSource ? diffItemParent()->difference()->sourceLineCount() : 0703 diffItemParent()->difference()->destinationLineCount(); 0704 } 0705 0706 int KompareListViewLineContainerItem::lineNumber() const 0707 { 0708 return m_isSource ? diffItemParent()->difference()->sourceLineNumber() : 0709 diffItemParent()->difference()->destinationLineNumber(); 0710 } 0711 0712 DifferenceString* KompareListViewLineContainerItem::lineAt(int i) const 0713 { 0714 return m_isSource ? diffItemParent()->difference()->sourceLineAt(i) : 0715 diffItemParent()->difference()->destinationLineAt(i); 0716 } 0717 0718 KompareListViewLineItem::KompareListViewLineItem(KompareListViewLineContainerItem* parent, int line, DifferenceString* text) 0719 : KompareListViewItem(parent, Line) 0720 { 0721 init(line, text); 0722 } 0723 0724 KompareListViewLineItem::KompareListViewLineItem(KompareListViewLineContainerItem* parent, int line, DifferenceString* text, int type) 0725 : KompareListViewItem(parent, type) 0726 { 0727 init(line, text); 0728 } 0729 0730 KompareListViewLineItem::~KompareListViewLineItem() 0731 { 0732 m_text = nullptr; 0733 } 0734 0735 void KompareListViewLineItem::init(int line, DifferenceString* text) 0736 { 0737 setHeight(treeWidget()->fontMetrics().height()); 0738 setText(COL_LINE_NO, QString::number(line)); 0739 setText(COL_MAIN, text->string()); 0740 m_text = text; 0741 } 0742 0743 void KompareListViewLineItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column) 0744 { 0745 int width = option.rect.width(); 0746 Qt::Alignment align = option.displayAlignment; 0747 0748 p->setRenderHint(QPainter::Antialiasing); 0749 p->translate(option.rect.topLeft()); 0750 p->translate(0, -paintOffset()); 0751 0752 QColor bg(Qt::white); // Always make the background white when it is not a real difference 0753 if (diffItemParent()->difference()->type() == Difference::Unchanged) 0754 { 0755 if (column == COL_LINE_NO) 0756 { 0757 bg = QColor(Qt::lightGray); 0758 } 0759 } 0760 else 0761 { 0762 bg = kompareListView()->settings()->colorForDifferenceType( 0763 diffItemParent()->difference()->type(), 0764 diffItemParent()->isCurrent(), 0765 diffItemParent()->difference()->applied()); 0766 } 0767 0768 // Paint background 0769 p->fillRect(0, 0, width, paintHeight(), bg); 0770 0771 // Paint foreground 0772 if (diffItemParent()->difference()->type() == Difference::Unchanged) 0773 p->setPen(QColor(Qt::darkGray)); // always make normal text gray 0774 else 0775 p->setPen(QColor(Qt::black)); // make text with changes black 0776 0777 paintText(p, bg, column, width, align); 0778 0779 // Paint darker lines around selected item 0780 if (diffItemParent()->isCurrent()) 0781 { 0782 p->translate(0.5, 0.5); 0783 p->setPen(bg.darker(135)); 0784 QTreeWidgetItem* parentItem = parent(); 0785 if (this == parentItem->child(0)) 0786 p->drawLine(0, 0, width, 0); 0787 if (this == parentItem->child(parentItem->childCount() - 1)) 0788 p->drawLine(0, paintHeight() - 1, width, paintHeight() - 1); 0789 } 0790 0791 p->resetTransform(); 0792 } 0793 0794 void KompareListViewLineItem::paintText(QPainter* p, const QColor& bg, int column, int width, int align) 0795 { 0796 if (column == COL_MAIN) 0797 { 0798 QString textChunk; 0799 int offset = ITEM_MARGIN; 0800 int prevValue = 0; 0801 int charsDrawn = 0; 0802 int chunkWidth; 0803 QBrush changeBrush(bg, Qt::Dense3Pattern); 0804 QBrush normalBrush(bg, Qt::SolidPattern); 0805 QBrush brush; 0806 0807 if (m_text->string().isEmpty()) 0808 { 0809 p->fillRect(0, 0, width, paintHeight(), normalBrush); 0810 return; 0811 } 0812 0813 p->fillRect(0, 0, offset, paintHeight(), normalBrush); 0814 0815 if (!m_text->markerList().isEmpty()) 0816 { 0817 MarkerListConstIterator markerIt = m_text->markerList().begin(); 0818 MarkerListConstIterator mEnd = m_text->markerList().end(); 0819 Marker* m = *markerIt; 0820 0821 for (; markerIt != mEnd; ++markerIt) 0822 { 0823 m = *markerIt; 0824 textChunk = m_text->string().mid(prevValue, m->offset() - prevValue); 0825 // qCDebug(KOMPAREPART) << "TextChunk = \"" << textChunk << "\"" ; 0826 // qCDebug(KOMPAREPART) << "c->offset() = " << c->offset() ; 0827 // qCDebug(KOMPAREPART) << "prevValue = " << prevValue ; 0828 expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn); 0829 charsDrawn += textChunk.length(); 0830 prevValue = m->offset(); 0831 if (m->type() == Marker::End) 0832 { 0833 QFont font(p->font()); 0834 font.setBold(true); 0835 p->setFont(font); 0836 // p->setPen( Qt::blue ); 0837 brush = changeBrush; 0838 } 0839 else 0840 { 0841 QFont font(p->font()); 0842 font.setBold(false); 0843 p->setFont(font); 0844 // p->setPen( Qt::black ); 0845 brush = normalBrush; 0846 } 0847 chunkWidth = p->fontMetrics().horizontalAdvance(textChunk); 0848 p->fillRect(offset, 0, chunkWidth, paintHeight(), brush); 0849 p->drawText(offset, 0, 0850 chunkWidth, paintHeight(), 0851 align, textChunk); 0852 offset += chunkWidth; 0853 } 0854 } 0855 if (prevValue < m_text->string().length()) 0856 { 0857 // Still have to draw some string without changes 0858 textChunk = m_text->string().mid(prevValue, qMax(1, m_text->string().length() - prevValue)); 0859 expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn); 0860 // qCDebug(KOMPAREPART) << "TextChunk = \"" << textChunk << "\"" ; 0861 QFont font(p->font()); 0862 font.setBold(false); 0863 p->setFont(font); 0864 chunkWidth = p->fontMetrics().horizontalAdvance(textChunk); 0865 p->fillRect(offset, 0, chunkWidth, paintHeight(), normalBrush); 0866 p->drawText(offset, 0, 0867 chunkWidth, paintHeight(), 0868 align, textChunk); 0869 offset += chunkWidth; 0870 } 0871 p->fillRect(offset, 0, width - offset, paintHeight(), normalBrush); 0872 } 0873 else 0874 { 0875 p->fillRect(0, 0, width, paintHeight(), bg); 0876 p->drawText(ITEM_MARGIN, 0, 0877 width - ITEM_MARGIN, paintHeight(), 0878 align, text(column)); 0879 } 0880 } 0881 0882 void KompareListViewLineItem::expandTabs(QString& text, int tabstop, int startPos) const 0883 { 0884 int index; 0885 while ((index = text.indexOf(QChar(9))) != -1) 0886 text.replace(index, 1, QString(tabstop - ((startPos + index) % tabstop), QLatin1Char(' '))); 0887 } 0888 0889 KompareListViewDiffItem* KompareListViewLineItem::diffItemParent() const 0890 { 0891 KompareListViewLineContainerItem* p = (KompareListViewLineContainerItem*)parent(); 0892 return p->diffItemParent(); 0893 } 0894 0895 KompareListViewBlankLineItem::KompareListViewBlankLineItem(KompareListViewLineContainerItem* parent) 0896 : KompareListViewLineItem(parent, 0, new DifferenceString(), Blank) 0897 { 0898 setHeight(BLANK_LINE_HEIGHT); 0899 } 0900 0901 void KompareListViewBlankLineItem::paintText(QPainter* p, const QColor& bg, int column, int width, int /* align */) 0902 { 0903 if (column == COL_MAIN) 0904 { 0905 QBrush normalBrush(bg, Qt::SolidPattern); 0906 p->fillRect(0, 0, width, paintHeight(), normalBrush); 0907 } 0908 } 0909 0910 KompareListViewHunkItem::KompareListViewHunkItem(KompareListView* parent, DiffHunk* hunk, bool zeroHeight) 0911 : KompareListViewItem(parent, Hunk), 0912 m_zeroHeight(zeroHeight), 0913 m_hunk(hunk) 0914 { 0915 setHeight(maxHeight()); 0916 setFlags(flags() & ~Qt::ItemIsSelectable); 0917 } 0918 0919 KompareListViewHunkItem::KompareListViewHunkItem(KompareListView* parent, KompareListViewItem* after, DiffHunk* hunk, bool zeroHeight) 0920 : KompareListViewItem(parent, after, Hunk), 0921 m_zeroHeight(zeroHeight), 0922 m_hunk(hunk) 0923 { 0924 setHeight(maxHeight()); 0925 setFlags(flags() & ~Qt::ItemIsSelectable); 0926 } 0927 0928 KompareListViewHunkItem::~KompareListViewHunkItem() 0929 { 0930 m_hunk = nullptr; 0931 } 0932 0933 int KompareListViewHunkItem::maxHeight() 0934 { 0935 if (m_zeroHeight) { 0936 return 0; 0937 } else if (m_hunk->function().isEmpty()) { 0938 return HUNK_LINE_HEIGHT; 0939 } else { 0940 return treeWidget()->fontMetrics().height(); 0941 } 0942 } 0943 0944 void KompareListViewHunkItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column) 0945 { 0946 if (m_zeroHeight) { 0947 KompareListViewItem::paintCell(p, option, column); 0948 } else { 0949 int x = option.rect.left(); 0950 int y = option.rect.top() - paintOffset(); 0951 int width = option.rect.width(); 0952 Qt::Alignment align = option.displayAlignment; 0953 0954 p->fillRect(x, y, width, paintHeight(), QColor(Qt::lightGray)); // Hunk headers should be lightgray 0955 p->setPen(QColor(Qt::black)); // Text color in hunk should be black 0956 if (column == COL_MAIN) { 0957 p->drawText(x + ITEM_MARGIN, y, width - ITEM_MARGIN, paintHeight(), 0958 align, m_hunk->function()); 0959 } 0960 } 0961 } 0962 0963 #include "moc_komparelistview.cpp"