~neon/kompare/master

« back to all changes in this revision

Viewing changes to src/komparepart/komparelistview.cpp

  • Committer: Friedrich W. H. Kossebau
  • Date: 2020-11-13 21:43:33 UTC
  • Revision ID: git-v1:79fce0df862602a8e2790d7d14f4037744a006f6
Reorganize sources into src/ subfolder

NO_CHANGELOG

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                                komparelistview.h
 
3
                                -----------------
 
4
        begin                   : Sun Mar 4 2001
 
5
        Copyright 2001-2009 Otto Bruggeman <bruggie@gmail.com>
 
6
        Copyright 2001-2003 John Firebaugh <jfirebaugh@kde.org>
 
7
        Copyright 2004      Jeff Snyder    <jeff@caffeinated.me.uk>
 
8
        Copyright 2007-2012 Kevin Kofler   <kevin.kofler@chello.at>
 
9
****************************************************************************/
 
10
 
 
11
/***************************************************************************
 
12
**
 
13
**   This program is free software; you can redistribute it and/or modify
 
14
**   it under the terms of the GNU General Public License as published by
 
15
**   the Free Software Foundation; either version 2 of the License, or
 
16
**   (at your option) any later version.
 
17
**
 
18
***************************************************************************/
 
19
 
 
20
#include "komparelistview.h"
 
21
 
 
22
#include <QStyle>
 
23
#include <QPainter>
 
24
#include <QRegExp>
 
25
#include <QTimer>
 
26
#include <QResizeEvent>
 
27
#include <QMouseEvent>
 
28
#include <QWheelEvent>
 
29
#include <QScrollBar>
 
30
 
 
31
#include <KSharedConfig>
 
32
 
 
33
#include <libkomparediff2/diffmodel.h>
 
34
#include <libkomparediff2/diffhunk.h>
 
35
#include <libkomparediff2/difference.h>
 
36
#include <libkomparediff2/komparemodellist.h>
 
37
 
 
38
#include <komparepartdebug.h>
 
39
#include "viewsettings.h"
 
40
#include "komparesplitter.h"
 
41
 
 
42
#define COL_LINE_NO      0
 
43
#define COL_MAIN         1
 
44
 
 
45
#define BLANK_LINE_HEIGHT 3
 
46
#define HUNK_LINE_HEIGHT  5
 
47
 
 
48
#define ITEM_MARGIN 3
 
49
 
 
50
using namespace Diff2;
 
51
 
 
52
KompareListViewFrame::KompareListViewFrame(bool isSource,
 
53
                                           ViewSettings* settings,
 
54
                                           KompareSplitter* parent,
 
55
                                           const char* name):
 
56
    QFrame(parent),
 
57
    m_view(isSource, settings, this, name),
 
58
    m_label(isSource ? QStringLiteral("Source") : QStringLiteral("Dest"), this),
 
59
    m_layout(this)
 
60
{
 
61
    setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
 
62
    m_label.setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
 
63
    QFrame* bottomLine = new QFrame(this);
 
64
    bottomLine->setFrameShape(QFrame::HLine);
 
65
    bottomLine->setFrameShadow(QFrame::Plain);
 
66
    bottomLine->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
 
67
    bottomLine->setFixedHeight(1);
 
68
    m_label.setMargin(3);
 
69
    m_layout.setSpacing(0);
 
70
    m_layout.setContentsMargins(0, 0, 0, 0);
 
71
    m_layout.addWidget(&m_label);
 
72
    m_layout.addWidget(bottomLine);
 
73
    m_layout.addWidget(&m_view);
 
74
 
 
75
    connect(&m_view, &KompareListView::differenceClicked,
 
76
            parent, &KompareSplitter::slotDifferenceClicked);
 
77
 
 
78
    connect(parent, &KompareSplitter::scrollViewsToId, &m_view, &KompareListView::scrollToId);
 
79
    connect(parent, &KompareSplitter::setXOffset, &m_view, &KompareListView::setXOffset);
 
80
    connect(&m_view, &KompareListView::resized, parent, &KompareSplitter::slotUpdateScrollBars);
 
81
}
 
82
 
 
83
void KompareListViewFrame::slotSetModel(const DiffModel* model)
 
84
{
 
85
    if (model)
 
86
    {
 
87
        if (view()->isSource()) {
 
88
            if (!model->sourceRevision().isEmpty())
 
89
                m_label.setText(model->sourceFile() + QLatin1String(" (") + model->sourceRevision() + QLatin1Char(')'));
 
90
            else
 
91
                m_label.setText(model->sourceFile());
 
92
        } else {
 
93
            if (!model->destinationRevision().isEmpty())
 
94
                m_label.setText(model->destinationFile() + QLatin1String(" (") + model->destinationRevision() + QLatin1Char(')'));
 
95
            else
 
96
                m_label.setText(model->destinationFile());
 
97
        }
 
98
    } else {
 
99
        m_label.setText(QString());
 
100
    }
 
101
}
 
102
 
 
103
KompareListView::KompareListView(bool isSource,
 
104
                                 ViewSettings* settings,
 
105
                                 QWidget* parent, const char* name) :
 
106
    QTreeWidget(parent),
 
107
    m_isSource(isSource),
 
108
    m_settings(settings),
 
109
    m_scrollId(-1),
 
110
    m_selectedModel(nullptr),
 
111
    m_selectedDifference(nullptr)
 
112
{
 
113
    setObjectName(QLatin1String(name));
 
114
    setItemDelegate(new KompareListViewItemDelegate(this));
 
115
    setHeaderHidden(true);
 
116
    setColumnCount(3);   // Line Number, Main, Blank
 
117
    setAllColumnsShowFocus(true);
 
118
    setRootIsDecorated(false);
 
119
    setIndentation(0);
 
120
    setFrameStyle(QFrame::NoFrame);
 
121
    setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
 
122
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
123
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
 
124
    setFocusPolicy(Qt::NoFocus);
 
125
    setFont(m_settings->m_font);
 
126
    setFocusProxy(parent->parentWidget());
 
127
}
 
128
 
 
129
KompareListView::~KompareListView()
 
130
{
 
131
    m_settings = nullptr;
 
132
    m_selectedModel = nullptr;
 
133
    m_selectedDifference = nullptr;
 
134
}
 
135
 
 
136
KompareListViewItem* KompareListView::itemAtIndex(int i)
 
137
{
 
138
    return m_items[ i ];
 
139
}
 
140
 
 
141
int KompareListView::firstVisibleDifference()
 
142
{
 
143
    QTreeWidgetItem* item = itemAt(QPoint(0, 0));
 
144
 
 
145
    if (item == nullptr)
 
146
    {
 
147
        qCDebug(KOMPAREPART) << "no item at viewport coordinates (0,0)" ;
 
148
    }
 
149
 
 
150
    while (item) {
 
151
        KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item);
 
152
        if (lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged)
 
153
            break;
 
154
        item = itemBelow(item);
 
155
    }
 
156
 
 
157
    if (item)
 
158
        return m_items.indexOf(((KompareListViewLineItem*)item)->diffItemParent());
 
159
 
 
160
    return -1;
 
161
}
 
162
 
 
163
int KompareListView::lastVisibleDifference()
 
164
{
 
165
    QTreeWidgetItem* item = itemAt(QPoint(0, visibleHeight() - 1));
 
166
 
 
167
    if (item == nullptr)
 
168
    {
 
169
        qCDebug(KOMPAREPART) << "no item at viewport coordinates (0," << visibleHeight() - 1 << ")" ;
 
170
        // find last item
 
171
        item = itemAt(QPoint(0, 0));
 
172
        if (item) {
 
173
            QTreeWidgetItem* nextItem = item;
 
174
            do {
 
175
                item = nextItem;
 
176
                nextItem = itemBelow(item);
 
177
            } while (nextItem);
 
178
        }
 
179
    }
 
180
 
 
181
    while (item) {
 
182
        KompareListViewLineItem* lineItem = dynamic_cast<KompareListViewLineItem*>(item);
 
183
        if (lineItem && lineItem->diffItemParent()->difference()->type() != Difference::Unchanged)
 
184
            break;
 
185
        item = itemAbove(item);
 
186
    }
 
187
 
 
188
    if (item)
 
189
        return m_items.indexOf(((KompareListViewLineItem*)item)->diffItemParent());
 
190
 
 
191
    return -1;
 
192
}
 
193
 
 
194
QRect KompareListView::totalVisualItemRect(QTreeWidgetItem* item)
 
195
{
 
196
    QRect total = visualItemRect(item);
 
197
    int n = item->childCount();
 
198
    for (int i = 0; i < n; ++i) {
 
199
        QTreeWidgetItem* child = item->child(i);
 
200
        if (!child->isHidden())
 
201
            total = total.united(totalVisualItemRect(child));
 
202
    }
 
203
    return total;
 
204
}
 
205
 
 
206
QRect KompareListView::itemRect(int i)
 
207
{
 
208
    QTreeWidgetItem* item = itemAtIndex(i);
 
209
    return totalVisualItemRect(item);
 
210
}
 
211
 
 
212
int KompareListView::minScrollId()
 
213
{
 
214
    return visibleHeight() / 2;
 
215
}
 
216
 
 
217
int KompareListView::maxScrollId()
 
218
{
 
219
    int n = topLevelItemCount();
 
220
    if (!n) return 0;
 
221
    KompareListViewItem* item = (KompareListViewItem*)topLevelItem(n - 1);
 
222
    int maxId = item->scrollId() + item->maxHeight() - minScrollId();
 
223
    qCDebug(KOMPAREPART) << "Max ID = " << maxId ;
 
224
    return maxId;
 
225
}
 
226
 
 
227
int KompareListView::contentsHeight()
 
228
{
 
229
    return verticalScrollBar()->maximum() + viewport()->height() - style()->pixelMetric(QStyle::PM_ScrollBarExtent);
 
230
}
 
231
 
 
232
int KompareListView::contentsWidth()
 
233
{
 
234
    return (columnWidth(COL_LINE_NO) + columnWidth(COL_MAIN));
 
235
}
 
236
 
 
237
int KompareListView::visibleHeight()
 
238
{
 
239
    return viewport()->height();
 
240
}
 
241
 
 
242
int KompareListView::visibleWidth()
 
243
{
 
244
    return viewport()->width();
 
245
}
 
246
 
 
247
int KompareListView::contentsX()
 
248
{
 
249
    return horizontalOffset();
 
250
}
 
251
 
 
252
int KompareListView::contentsY()
 
253
{
 
254
    return verticalOffset();
 
255
}
 
256
 
 
257
int KompareListView::nextPaintOffset() const
 
258
{
 
259
    return m_nextPaintOffset;
 
260
}
 
261
 
 
262
void KompareListView::setNextPaintOffset(int offset)
 
263
{
 
264
    m_nextPaintOffset = offset;
 
265
}
 
266
 
 
267
void KompareListView::setXOffset(int x)
 
268
{
 
269
    qCDebug(KOMPAREPART) << "SetXOffset : Scroll to x position: " << x ;
 
270
    horizontalScrollBar()->setValue(x);
 
271
}
 
272
 
 
273
void KompareListView::scrollToId(int id)
 
274
{
 
275
//     qCDebug(KOMPAREPART) << "ScrollToID : Scroll to id : " << id ;
 
276
    int n = topLevelItemCount();
 
277
    KompareListViewItem* item = nullptr;
 
278
    if (n) {
 
279
        int i = 1;
 
280
        for (; i < n; ++i) {
 
281
            if (((KompareListViewItem*)topLevelItem(i))->scrollId() > id)
 
282
                break;
 
283
        }
 
284
        item = (KompareListViewItem*)topLevelItem(i - 1);
 
285
    }
 
286
 
 
287
    if (item) {
 
288
        QRect rect = totalVisualItemRect(item);
 
289
        int pos = rect.top() + verticalOffset();
 
290
        int itemId = item->scrollId();
 
291
        int height = rect.height();
 
292
        double r = (double)(id - itemId) / (double)item->maxHeight();
 
293
        int y = pos + (int)(r * (double)height) - minScrollId();
 
294
//         qCDebug(KOMPAREPART) << "scrollToID: " ;
 
295
//         qCDebug(KOMPAREPART) << "            id = " << id ;
 
296
//         qCDebug(KOMPAREPART) << "           pos = " << pos ;
 
297
//         qCDebug(KOMPAREPART) << "        itemId = " << itemId ;
 
298
//         qCDebug(KOMPAREPART) << "             r = " << r ;
 
299
//         qCDebug(KOMPAREPART) << "        height = " << height ;
 
300
//         qCDebug(KOMPAREPART) << "         minID = " << minScrollId() ;
 
301
//         qCDebug(KOMPAREPART) << "             y = " << y ;
 
302
//         qCDebug(KOMPAREPART) << "contentsHeight = " << contentsHeight() ;
 
303
//         qCDebug(KOMPAREPART) << "         c - y = " << contentsHeight() - y ;
 
304
        verticalScrollBar()->setValue(y);
 
305
    }
 
306
 
 
307
    m_scrollId = id;
 
308
}
 
309
 
 
310
int KompareListView::scrollId()
 
311
{
 
312
    if (m_scrollId < 0)
 
313
        m_scrollId = minScrollId();
 
314
    return m_scrollId;
 
315
}
 
316
 
 
317
void KompareListView::setSelectedDifference(const Difference* diff, bool scroll)
 
318
{
 
319
    qCDebug(KOMPAREPART) << "KompareListView::setSelectedDifference(" << diff << ", " << scroll << ")" ;
 
320
 
 
321
    // When something other than a click causes this function to be called,
 
322
    // it'll only get called once, and all is simple.
 
323
    //
 
324
    // When the user clicks on a diff, this function will get called once when
 
325
    // komparesplitter::slotDifferenceClicked runs, and again when the
 
326
    // setSelection signal from the modelcontroller arrives.
 
327
    //
 
328
    // the first call (which will always be from the splitter) will have
 
329
    // scroll==false, and the second call will bail out here.
 
330
    // Which is why clicking on a difference does not cause the listviews to
 
331
    // scroll.
 
332
    if (m_selectedDifference == diff)
 
333
        return;
 
334
 
 
335
    m_selectedDifference = diff;
 
336
 
 
337
    KompareListViewItem* item = m_itemDict[ diff ];
 
338
    if (!item) {
 
339
        qCDebug(KOMPAREPART) << "KompareListView::slotSetSelection(): couldn't find our selection!" ;
 
340
        return;
 
341
    }
 
342
 
 
343
    // why does this not happen when the user clicks on a diff? see the comment above.
 
344
    if (scroll)
 
345
        scrollToId(item->scrollId());
 
346
    setUpdatesEnabled(false);
 
347
    int x = horizontalScrollBar()->value();
 
348
    int y = verticalScrollBar()->value();
 
349
    setCurrentItem(item);
 
350
    horizontalScrollBar()->setValue(x);
 
351
    verticalScrollBar()->setValue(y);
 
352
    setUpdatesEnabled(true);
 
353
}
 
354
 
 
355
void KompareListView::slotSetSelection(const Difference* diff)
 
356
{
 
357
    qCDebug(KOMPAREPART) << "KompareListView::slotSetSelection( const Difference* diff )" ;
 
358
 
 
359
    setSelectedDifference(diff, true);
 
360
}
 
361
 
 
362
void KompareListView::slotSetSelection(const DiffModel* model, const Difference* diff)
 
363
{
 
364
    qCDebug(KOMPAREPART) << "KompareListView::slotSetSelection( const DiffModel* model, const Difference* diff )" ;
 
365
 
 
366
    if (m_selectedModel && m_selectedModel == model) {
 
367
        slotSetSelection(diff);
 
368
        return;
 
369
    }
 
370
 
 
371
    clear();
 
372
    m_items.clear();
 
373
    m_itemDict.clear();
 
374
    m_selectedModel = model;
 
375
 
 
376
    DiffHunkListConstIterator hunkIt = model->hunks()->begin();
 
377
    DiffHunkListConstIterator hEnd   = model->hunks()->end();
 
378
 
 
379
    KompareListViewItem* item = nullptr;
 
380
    m_nextPaintOffset = 0;
 
381
 
 
382
    for (; hunkIt != hEnd; ++hunkIt)
 
383
    {
 
384
        if (item)
 
385
            item = new KompareListViewHunkItem(this, item, *hunkIt, model->isBlended());
 
386
        else
 
387
            item = new KompareListViewHunkItem(this, *hunkIt, model->isBlended());
 
388
 
 
389
        DifferenceListConstIterator diffIt = (*hunkIt)->differences().begin();
 
390
        DifferenceListConstIterator dEnd   = (*hunkIt)->differences().end();
 
391
 
 
392
        for (; diffIt != dEnd; ++diffIt)
 
393
        {
 
394
            item = new KompareListViewDiffItem(this, item, *diffIt);
 
395
 
 
396
            int type = (*diffIt)->type();
 
397
 
 
398
            if (type != Difference::Unchanged)
 
399
            {
 
400
                m_items.append((KompareListViewDiffItem*)item);
 
401
                m_itemDict.insert(*diffIt, (KompareListViewDiffItem*)item);
 
402
            }
 
403
        }
 
404
    }
 
405
 
 
406
    resizeColumnToContents(COL_LINE_NO);
 
407
    resizeColumnToContents(COL_MAIN);
 
408
 
 
409
    slotSetSelection(diff);
 
410
}
 
411
 
 
412
KompareListViewDiffItem* KompareListView::diffItemAt(const QPoint& pos)
 
413
{
 
414
    KompareListViewItem* item = static_cast<KompareListViewItem*>(itemAt(pos));
 
415
    if (!item)
 
416
        return nullptr;
 
417
    switch (item->type()) {
 
418
        case KompareListViewItem::Hunk:
 
419
            if (item->paintHeight()) return nullptr;  // no diff item here
 
420
            // zero height (fake 1 pixel height), so a diff item shines through
 
421
            return static_cast<KompareListViewDiffItem*>(itemBelow(item));
 
422
        case KompareListViewItem::Line:
 
423
        case KompareListViewItem::Blank:
 
424
            return static_cast<KompareListViewLineItem*>(item)->diffItemParent();
 
425
        case KompareListViewItem::Container:
 
426
            return static_cast<KompareListViewLineContainerItem*>(item)->diffItemParent();
 
427
        case KompareListViewItem::Diff:
 
428
            return static_cast<KompareListViewDiffItem*>(item);
 
429
        default:
 
430
            return nullptr;
 
431
    }
 
432
}
 
433
 
 
434
void KompareListView::mousePressEvent(QMouseEvent* e)
 
435
{
 
436
    QPoint vp = e->pos();
 
437
    KompareListViewDiffItem* diffItem = diffItemAt(vp);
 
438
    if (diffItem && diffItem->difference()->type() != Difference::Unchanged) {
 
439
        Q_EMIT differenceClicked(diffItem->difference());
 
440
    }
 
441
}
 
442
 
 
443
void KompareListView::mouseDoubleClickEvent(QMouseEvent* e)
 
444
{
 
445
    QPoint vp = e->pos();
 
446
    KompareListViewDiffItem* diffItem = diffItemAt(vp);
 
447
    if (diffItem && diffItem->difference()->type() != Difference::Unchanged) {
 
448
        // FIXME: make a new signal that does both
 
449
        Q_EMIT differenceClicked(diffItem->difference());
 
450
        Q_EMIT applyDifference(!diffItem->difference()->applied());
 
451
    }
 
452
}
 
453
 
 
454
void KompareListView::renumberLines()
 
455
{
 
456
//     qCDebug(KOMPAREPART) << "Begin" ;
 
457
    unsigned int newLineNo = 1;
 
458
    if (!topLevelItemCount()) return;
 
459
    KompareListViewItem* item = (KompareListViewItem*)topLevelItem(0);
 
460
    while (item) {
 
461
//         qCDebug(KOMPAREPART) << "type: " << item->type() ;
 
462
        if (item->type() != KompareListViewItem::Container
 
463
                && item->type() != KompareListViewItem::Blank
 
464
                && item->type() != KompareListViewItem::Hunk)
 
465
        {
 
466
//             qCDebug(KOMPAREPART) << QString::number( newLineNo ) ;
 
467
            item->setText(COL_LINE_NO, QString::number(newLineNo++));
 
468
        }
 
469
        item = (KompareListViewItem*)itemBelow(item);
 
470
    }
 
471
}
 
472
 
 
473
void KompareListView::slotApplyDifference(bool apply)
 
474
{
 
475
    m_itemDict[ m_selectedDifference ]->applyDifference(apply);
 
476
    // now renumber the line column if this is the destination
 
477
    if (!m_isSource)
 
478
        renumberLines();
 
479
}
 
480
 
 
481
void KompareListView::slotApplyAllDifferences(bool apply)
 
482
{
 
483
    QHash<const Diff2::Difference*, KompareListViewDiffItem*>::ConstIterator it = m_itemDict.constBegin();
 
484
    QHash<const Diff2::Difference*, KompareListViewDiffItem*>::ConstIterator end = m_itemDict.constEnd();
 
485
    for (; it != end; ++it)
 
486
        it.value()->applyDifference(apply);
 
487
 
 
488
    // now renumber the line column if this is the destination
 
489
    if (!m_isSource)
 
490
        renumberLines();
 
491
    update();
 
492
}
 
493
 
 
494
void KompareListView::slotApplyDifference(const Difference* diff, bool apply)
 
495
{
 
496
    m_itemDict[ diff ]->applyDifference(apply);
 
497
    // now renumber the line column if this is the destination
 
498
    if (!m_isSource)
 
499
        renumberLines();
 
500
}
 
501
 
 
502
void KompareListView::wheelEvent(QWheelEvent* e)
 
503
{
 
504
    e->ignore(); // we want the parent to catch wheel events
 
505
}
 
506
 
 
507
void KompareListView::resizeEvent(QResizeEvent* e)
 
508
{
 
509
    QTreeWidget::resizeEvent(e);
 
510
    Q_EMIT resized();
 
511
}
 
512
 
 
513
KompareListViewItemDelegate::KompareListViewItemDelegate(QObject* parent)
 
514
    : QStyledItemDelegate(parent)
 
515
{
 
516
}
 
517
 
 
518
KompareListViewItemDelegate::~KompareListViewItemDelegate()
 
519
{
 
520
}
 
521
 
 
522
void KompareListViewItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
 
523
{
 
524
    int column = index.column();
 
525
    QStyleOptionViewItem changedOption = option;
 
526
    if (column == COL_LINE_NO)
 
527
        changedOption.displayAlignment = Qt::AlignRight;
 
528
    KompareListViewItem* item = static_cast<KompareListViewItem*>(static_cast<KompareListView*>(parent())->itemFromIndex(index));
 
529
    item->paintCell(painter, changedOption, column);
 
530
}
 
531
 
 
532
QSize KompareListViewItemDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
 
533
{
 
534
    KompareListViewItem* item = static_cast<KompareListViewItem*>(static_cast<KompareListView*>(parent())->itemFromIndex(index));
 
535
    QSize hint = QStyledItemDelegate::sizeHint(option, index);
 
536
    return QSize(hint.width() + ITEM_MARGIN, item->height());
 
537
}
 
538
 
 
539
KompareListViewItem::KompareListViewItem(KompareListView* parent, int type)
 
540
    : QTreeWidgetItem(parent, type),
 
541
      m_scrollId(0),
 
542
      m_height(0),
 
543
      m_paintHeight(0),
 
544
      m_paintOffset(parent->nextPaintOffset())
 
545
{
 
546
//     qCDebug(KOMPAREPART) << "Created KompareListViewItem with scroll id " << m_scrollId ;
 
547
}
 
548
 
 
549
KompareListViewItem::KompareListViewItem(KompareListView* parent, KompareListViewItem* after, int type)
 
550
    : QTreeWidgetItem(parent, after, type),
 
551
      m_scrollId(after->scrollId() + after->maxHeight()),
 
552
      m_height(0),
 
553
      m_paintHeight(0),
 
554
      m_paintOffset(parent->nextPaintOffset())
 
555
{
 
556
//     qCDebug(KOMPAREPART) << "Created KompareListViewItem with scroll id " << m_scrollId ;
 
557
}
 
558
 
 
559
KompareListViewItem::KompareListViewItem(KompareListViewItem* parent, int type)
 
560
    : QTreeWidgetItem(parent, type),
 
561
      m_scrollId(0),
 
562
      m_height(0),
 
563
      m_paintHeight(0),
 
564
      m_paintOffset(parent->kompareListView()->nextPaintOffset())
 
565
{
 
566
}
 
567
 
 
568
KompareListViewItem::KompareListViewItem(KompareListViewItem* parent, KompareListViewItem* /*after*/, int type)
 
569
    : QTreeWidgetItem(parent, type),
 
570
      m_scrollId(0),
 
571
      m_height(0),
 
572
      m_paintHeight(0),
 
573
      m_paintOffset(parent->kompareListView()->nextPaintOffset())
 
574
{
 
575
}
 
576
 
 
577
int KompareListViewItem::height() const
 
578
{
 
579
    return m_height;
 
580
}
 
581
 
 
582
void KompareListViewItem::setHeight(int h)
 
583
{
 
584
    m_height = m_paintHeight = h;
 
585
    // QTreeWidget doesn't like zero height, fudge around it.
 
586
    m_height -= m_paintOffset;
 
587
    if (m_height <= 0) {
 
588
        kompareListView()->setNextPaintOffset(1 - m_height);
 
589
        m_height = 1;
 
590
    } else kompareListView()->setNextPaintOffset(0);
 
591
}
 
592
 
 
593
int KompareListViewItem::paintHeight() const
 
594
{
 
595
    return m_paintHeight;
 
596
}
 
597
 
 
598
int KompareListViewItem::paintOffset() const
 
599
{
 
600
    return m_paintOffset;
 
601
}
 
602
 
 
603
bool KompareListViewItem::isCurrent() const
 
604
{
 
605
    return treeWidget()->currentItem() == this;
 
606
}
 
607
 
 
608
KompareListView* KompareListViewItem::kompareListView() const
 
609
{
 
610
    return (KompareListView*)treeWidget();
 
611
}
 
612
 
 
613
void KompareListViewItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column)
 
614
{
 
615
    // Default implementation for zero-height items.
 
616
    // We have to paint the item which shines through or we'll end up with glitches.
 
617
    KompareListViewItem* nextItem = (KompareListViewItem*)kompareListView()->itemBelow(this);
 
618
    if (nextItem) {
 
619
        QStyleOptionViewItem changedOption = option;
 
620
        changedOption.rect.translate(0, height());
 
621
        nextItem->paintCell(p, changedOption, column);
 
622
    }
 
623
}
 
624
 
 
625
KompareListViewDiffItem::KompareListViewDiffItem(KompareListView* parent, Difference* difference)
 
626
    : KompareListViewItem(parent, Diff),
 
627
      m_difference(difference),
 
628
      m_sourceItem(nullptr),
 
629
      m_destItem(nullptr)
 
630
{
 
631
    init();
 
632
}
 
633
 
 
634
KompareListViewDiffItem::KompareListViewDiffItem(KompareListView* parent, KompareListViewItem* after, Difference* difference)
 
635
    : KompareListViewItem(parent, after, Diff),
 
636
      m_difference(difference),
 
637
      m_sourceItem(nullptr),
 
638
      m_destItem(nullptr)
 
639
{
 
640
    init();
 
641
}
 
642
 
 
643
KompareListViewDiffItem::~KompareListViewDiffItem()
 
644
{
 
645
    m_difference = nullptr;
 
646
}
 
647
 
 
648
void KompareListViewDiffItem::init()
 
649
{
 
650
    setHeight(0);
 
651
    setExpanded(true);
 
652
    int nextPaintOffset = kompareListView()->nextPaintOffset();
 
653
    m_destItem = new KompareListViewLineContainerItem(this, false);
 
654
    kompareListView()->setNextPaintOffset(nextPaintOffset);
 
655
    m_sourceItem = new KompareListViewLineContainerItem(this, true);
 
656
    setVisibility();
 
657
}
 
658
 
 
659
void KompareListViewDiffItem::setVisibility()
 
660
{
 
661
    m_sourceItem->setHidden(!(kompareListView()->isSource() || m_difference->applied()));
 
662
    m_destItem->setHidden(!m_sourceItem->isHidden());
 
663
}
 
664
 
 
665
void KompareListViewDiffItem::applyDifference(bool apply)
 
666
{
 
667
    qCDebug(KOMPAREPART) << "KompareListViewDiffItem::applyDifference( " << apply << " )" ;
 
668
    setVisibility();
 
669
}
 
670
 
 
671
int KompareListViewDiffItem::maxHeight()
 
672
{
 
673
    int lines = qMax(m_difference->sourceLineCount(), m_difference->destinationLineCount());
 
674
    if (lines == 0)
 
675
        return BLANK_LINE_HEIGHT;
 
676
    else
 
677
        return lines * treeWidget()->fontMetrics().height();
 
678
}
 
679
 
 
680
KompareListViewLineContainerItem::KompareListViewLineContainerItem(KompareListViewDiffItem* parent, bool isSource)
 
681
    : KompareListViewItem(parent, Container),
 
682
      m_blankLineItem(nullptr),
 
683
      m_isSource(isSource)
 
684
{
 
685
//     qCDebug(KOMPAREPART) << "isSource ? " << (isSource ? " Yes!" : " No!") ;
 
686
    setHeight(0);
 
687
    setExpanded(true);
 
688
 
 
689
    int lines = lineCount();
 
690
    int line = lineNumber();
 
691
//     qCDebug(KOMPAREPART) << "LineNumber : " << lineNumber() ;
 
692
    if (lines == 0) {
 
693
        m_blankLineItem = new KompareListViewBlankLineItem(this);
 
694
        return;
 
695
    }
 
696
 
 
697
    for (int i = 0; i < lines; ++i, ++line) {
 
698
        new KompareListViewLineItem(this, line, lineAt(i));
 
699
    }
 
700
}
 
701
 
 
702
KompareListViewLineContainerItem::~KompareListViewLineContainerItem()
 
703
{
 
704
}
 
705
 
 
706
KompareListViewDiffItem* KompareListViewLineContainerItem::diffItemParent() const
 
707
{
 
708
    return (KompareListViewDiffItem*)parent();
 
709
}
 
710
 
 
711
int KompareListViewLineContainerItem::lineCount() const
 
712
{
 
713
    return m_isSource ? diffItemParent()->difference()->sourceLineCount() :
 
714
           diffItemParent()->difference()->destinationLineCount();
 
715
}
 
716
 
 
717
int KompareListViewLineContainerItem::lineNumber() const
 
718
{
 
719
    return m_isSource ? diffItemParent()->difference()->sourceLineNumber() :
 
720
           diffItemParent()->difference()->destinationLineNumber();
 
721
}
 
722
 
 
723
DifferenceString* KompareListViewLineContainerItem::lineAt(int i) const
 
724
{
 
725
    return m_isSource ? diffItemParent()->difference()->sourceLineAt(i) :
 
726
           diffItemParent()->difference()->destinationLineAt(i);
 
727
}
 
728
 
 
729
KompareListViewLineItem::KompareListViewLineItem(KompareListViewLineContainerItem* parent, int line, DifferenceString* text)
 
730
    : KompareListViewItem(parent, Line)
 
731
{
 
732
    init(line, text);
 
733
}
 
734
 
 
735
KompareListViewLineItem::KompareListViewLineItem(KompareListViewLineContainerItem* parent, int line, DifferenceString* text, int type)
 
736
    : KompareListViewItem(parent, type)
 
737
{
 
738
    init(line, text);
 
739
}
 
740
 
 
741
KompareListViewLineItem::~KompareListViewLineItem()
 
742
{
 
743
    m_text = nullptr;
 
744
}
 
745
 
 
746
void KompareListViewLineItem::init(int line, DifferenceString* text)
 
747
{
 
748
    setHeight(treeWidget()->fontMetrics().height());
 
749
    setText(COL_LINE_NO, QString::number(line));
 
750
    setText(COL_MAIN, text->string());
 
751
    m_text = text;
 
752
}
 
753
 
 
754
void KompareListViewLineItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column)
 
755
{
 
756
    int width = option.rect.width();
 
757
    Qt::Alignment align = option.displayAlignment;
 
758
 
 
759
    p->setRenderHint(QPainter::Antialiasing);
 
760
    p->translate(option.rect.topLeft());
 
761
    p->translate(0, -paintOffset());
 
762
 
 
763
    QColor bg(Qt::white);   // Always make the background white when it is not a real difference
 
764
    if (diffItemParent()->difference()->type() == Difference::Unchanged)
 
765
    {
 
766
        if (column == COL_LINE_NO)
 
767
        {
 
768
            bg = QColor(Qt::lightGray);
 
769
        }
 
770
    }
 
771
    else
 
772
    {
 
773
        bg = kompareListView()->settings()->colorForDifferenceType(
 
774
                 diffItemParent()->difference()->type(),
 
775
                 diffItemParent()->isCurrent(),
 
776
                 diffItemParent()->difference()->applied());
 
777
    }
 
778
 
 
779
    // Paint background
 
780
    p->fillRect(0, 0, width, paintHeight(), bg);
 
781
 
 
782
    // Paint foreground
 
783
    if (diffItemParent()->difference()->type() == Difference::Unchanged)
 
784
        p->setPen(QColor(Qt::darkGray));     // always make normal text gray
 
785
    else
 
786
        p->setPen(QColor(Qt::black));     // make text with changes black
 
787
 
 
788
    paintText(p, bg, column, width, align);
 
789
 
 
790
    // Paint darker lines around selected item
 
791
    if (diffItemParent()->isCurrent())
 
792
    {
 
793
        p->translate(0.5, 0.5);
 
794
        p->setPen(bg.darker(135));
 
795
        QTreeWidgetItem* parentItem = parent();
 
796
        if (this == parentItem->child(0))
 
797
            p->drawLine(0, 0, width, 0);
 
798
        if (this == parentItem->child(parentItem->childCount() - 1))
 
799
            p->drawLine(0, paintHeight() - 1, width, paintHeight() - 1);
 
800
    }
 
801
 
 
802
    p->resetTransform();
 
803
}
 
804
 
 
805
void KompareListViewLineItem::paintText(QPainter* p, const QColor& bg, int column, int width, int align)
 
806
{
 
807
    if (column == COL_MAIN)
 
808
    {
 
809
        QString textChunk;
 
810
        int offset = ITEM_MARGIN;
 
811
        int prevValue = 0;
 
812
        int charsDrawn = 0;
 
813
        int chunkWidth;
 
814
        QBrush changeBrush(bg, Qt::Dense3Pattern);
 
815
        QBrush normalBrush(bg, Qt::SolidPattern);
 
816
        QBrush brush;
 
817
 
 
818
        if (m_text->string().isEmpty())
 
819
        {
 
820
            p->fillRect(0, 0, width, paintHeight(), normalBrush);
 
821
            return;
 
822
        }
 
823
 
 
824
        p->fillRect(0, 0, offset, paintHeight(), normalBrush);
 
825
 
 
826
        if (!m_text->markerList().isEmpty())
 
827
        {
 
828
            MarkerListConstIterator markerIt = m_text->markerList().begin();
 
829
            MarkerListConstIterator mEnd     = m_text->markerList().end();
 
830
            Marker* m = *markerIt;
 
831
 
 
832
            for (; markerIt != mEnd; ++markerIt)
 
833
            {
 
834
                m  = *markerIt;
 
835
                textChunk = m_text->string().mid(prevValue, m->offset() - prevValue);
 
836
//                 qCDebug(KOMPAREPART) << "TextChunk   = \"" << textChunk << "\"" ;
 
837
//                 qCDebug(KOMPAREPART) << "c->offset() = " << c->offset() ;
 
838
//                 qCDebug(KOMPAREPART) << "prevValue   = " << prevValue ;
 
839
                expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn);
 
840
                charsDrawn += textChunk.length();
 
841
                prevValue = m->offset();
 
842
                if (m->type() == Marker::End)
 
843
                {
 
844
                    QFont font(p->font());
 
845
                    font.setBold(true);
 
846
                    p->setFont(font);
 
847
//                     p->setPen( Qt::blue );
 
848
                    brush = changeBrush;
 
849
                }
 
850
                else
 
851
                {
 
852
                    QFont font(p->font());
 
853
                    font.setBold(false);
 
854
                    p->setFont(font);
 
855
//                     p->setPen( Qt::black );
 
856
                    brush = normalBrush;
 
857
                }
 
858
                chunkWidth = p->fontMetrics().horizontalAdvance(textChunk);
 
859
                p->fillRect(offset, 0, chunkWidth, paintHeight(), brush);
 
860
                p->drawText(offset, 0,
 
861
                            chunkWidth, paintHeight(),
 
862
                            align, textChunk);
 
863
                offset += chunkWidth;
 
864
            }
 
865
        }
 
866
        if (prevValue < m_text->string().length())
 
867
        {
 
868
            // Still have to draw some string without changes
 
869
            textChunk = m_text->string().mid(prevValue, qMax(1, m_text->string().length() - prevValue));
 
870
            expandTabs(textChunk, kompareListView()->settings()->m_tabToNumberOfSpaces, charsDrawn);
 
871
//             qCDebug(KOMPAREPART) << "TextChunk   = \"" << textChunk << "\"" ;
 
872
            QFont font(p->font());
 
873
            font.setBold(false);
 
874
            p->setFont(font);
 
875
            chunkWidth = p->fontMetrics().horizontalAdvance(textChunk);
 
876
            p->fillRect(offset, 0, chunkWidth, paintHeight(), normalBrush);
 
877
            p->drawText(offset, 0,
 
878
                        chunkWidth, paintHeight(),
 
879
                        align, textChunk);
 
880
            offset += chunkWidth;
 
881
        }
 
882
        p->fillRect(offset, 0, width - offset, paintHeight(), normalBrush);
 
883
    }
 
884
    else
 
885
    {
 
886
        p->fillRect(0, 0, width, paintHeight(), bg);
 
887
        p->drawText(ITEM_MARGIN, 0,
 
888
                    width - ITEM_MARGIN, paintHeight(),
 
889
                    align, text(column));
 
890
    }
 
891
}
 
892
 
 
893
void KompareListViewLineItem::expandTabs(QString& text, int tabstop, int startPos) const
 
894
{
 
895
    int index;
 
896
    while ((index = text.indexOf(QChar(9))) != -1)
 
897
        text.replace(index, 1, QString(tabstop - ((startPos + index) % tabstop), QLatin1Char(' ')));
 
898
}
 
899
 
 
900
KompareListViewDiffItem* KompareListViewLineItem::diffItemParent() const
 
901
{
 
902
    KompareListViewLineContainerItem* p = (KompareListViewLineContainerItem*)parent();
 
903
    return p->diffItemParent();
 
904
}
 
905
 
 
906
KompareListViewBlankLineItem::KompareListViewBlankLineItem(KompareListViewLineContainerItem* parent)
 
907
    : KompareListViewLineItem(parent, 0, new DifferenceString(), Blank)
 
908
{
 
909
    setHeight(BLANK_LINE_HEIGHT);
 
910
}
 
911
 
 
912
void KompareListViewBlankLineItem::paintText(QPainter* p, const QColor& bg, int column, int width, int /* align */)
 
913
{
 
914
    if (column == COL_MAIN)
 
915
    {
 
916
        QBrush normalBrush(bg, Qt::SolidPattern);
 
917
        p->fillRect(0, 0, width, paintHeight(), normalBrush);
 
918
    }
 
919
}
 
920
 
 
921
KompareListViewHunkItem::KompareListViewHunkItem(KompareListView* parent, DiffHunk* hunk, bool zeroHeight)
 
922
    : KompareListViewItem(parent, Hunk),
 
923
      m_zeroHeight(zeroHeight),
 
924
      m_hunk(hunk)
 
925
{
 
926
    setHeight(maxHeight());
 
927
    setFlags(flags() & ~Qt::ItemIsSelectable);
 
928
}
 
929
 
 
930
KompareListViewHunkItem::KompareListViewHunkItem(KompareListView* parent, KompareListViewItem* after, DiffHunk* hunk,  bool zeroHeight)
 
931
    : KompareListViewItem(parent, after, Hunk),
 
932
      m_zeroHeight(zeroHeight),
 
933
      m_hunk(hunk)
 
934
{
 
935
    setHeight(maxHeight());
 
936
    setFlags(flags() & ~Qt::ItemIsSelectable);
 
937
}
 
938
 
 
939
KompareListViewHunkItem::~KompareListViewHunkItem()
 
940
{
 
941
    m_hunk = nullptr;
 
942
}
 
943
 
 
944
int KompareListViewHunkItem::maxHeight()
 
945
{
 
946
    if (m_zeroHeight) {
 
947
        return 0;
 
948
    } else if (m_hunk->function().isEmpty()) {
 
949
        return HUNK_LINE_HEIGHT;
 
950
    } else {
 
951
        return treeWidget()->fontMetrics().height();
 
952
    }
 
953
}
 
954
 
 
955
void KompareListViewHunkItem::paintCell(QPainter* p, const QStyleOptionViewItem& option, int column)
 
956
{
 
957
    if (m_zeroHeight) {
 
958
        KompareListViewItem::paintCell(p, option, column);
 
959
    } else {
 
960
        int x = option.rect.left();
 
961
        int y = option.rect.top() - paintOffset();
 
962
        int width = option.rect.width();
 
963
        Qt::Alignment align = option.displayAlignment;
 
964
 
 
965
        p->fillRect(x, y, width, paintHeight(), QColor(Qt::lightGray));     // Hunk headers should be lightgray
 
966
        p->setPen(QColor(Qt::black));     // Text color in hunk should be black
 
967
        if (column == COL_MAIN) {
 
968
            p->drawText(x + ITEM_MARGIN, y, width - ITEM_MARGIN, paintHeight(),
 
969
                        align, m_hunk->function());
 
970
        }
 
971
    }
 
972
}