1#include <LineNumberArea.h>
2
3#include <FileDiffView.h>
4#include <GitQlientStyles.h>
5#include <Colors.h>
6
7#include <QPainter>
8#include <QTextBlock>
9#include <QIcon>
10
11LineNumberArea::LineNumberArea(FileDiffView *editor, bool allowComments)
12 : QWidget(editor)
13 , mCommentsAllowed(allowComments)
14{
15 fileDiffWidget = editor;
16 setMouseTracking(true);
17}
18
19int LineNumberArea::widthInDigitsSize()
20{
21 return 3;
22}
23
24QSize LineNumberArea::sizeHint() const
25{
26 return { fileDiffWidget->lineNumberAreaWidth(), 0 };
27}
28
29void LineNumberArea::setEditor(FileDiffView *editor)
30{
31 fileDiffWidget = editor;
32 setParent(editor);
33}
34
35void LineNumberArea::paintEvent(QPaintEvent *event)
36{
37 QPainter painter(this);
38
39 const auto fontWidth = fileDiffWidget->fontMetrics().horizontalAdvance(QLatin1Char(' '));
40 const auto offset = fontWidth * (mCommentsAllowed ? 4 : 1);
41 auto block = fileDiffWidget->firstVisibleBlock();
42 auto blockNumber = block.blockNumber() + fileDiffWidget->mStartingLine;
43 auto top = fileDiffWidget->blockBoundingGeometry(block).translated(fileDiffWidget->contentOffset()).top();
44 auto bottom = top + fileDiffWidget->blockBoundingRect(block).height();
45 auto lineCorrection = 0;
46
47 while (block.isValid() && top <= event->rect().bottom())
48 {
49
50 if (block.isVisible() && bottom >= event->rect().top())
51 {
52 const auto skipDeletion
53 = fileDiffWidget->mUnified && !block.text().startsWith("-") && !block.text().startsWith("@");
54
55 if (!fileDiffWidget->mUnified || skipDeletion)
56 {
57 const auto height = fileDiffWidget->fontMetrics().height();
58 const auto number = blockNumber + 1 + lineCorrection;
59 painter.setPen(GitQlientStyles::getTextColor());
60
61 if (mBookmarks.contains(number))
62 {
63 painter.drawPixmap(6, static_cast<int>(top), height, height,
64 QIcon(":/icons/comments").pixmap(height, height));
65
66 painter.setPen(gitQlientOrange);
67 }
68 else if (fileDiffWidget->mRow == number)
69 {
70 painter.drawPixmap(width() - height - fontWidth, static_cast<int>(top), height, height,
71 QIcon(":/icons/add_comment").pixmap(height, height));
72
73 painter.setPen(gitQlientOrange);
74 }
75
76 painter.drawText(0, static_cast<int>(top), width() - offset, height, Qt::AlignRight,
77 QString::number(number));
78 }
79 else
80 --lineCorrection;
81 }
82
83 block = block.next();
84 top = bottom;
85 bottom = top + fileDiffWidget->blockBoundingRect(block).height();
86 ++blockNumber;
87 }
88}
89
90void LineNumberArea::mouseMoveEvent(QMouseEvent *e)
91{
92 if (mCommentsAllowed)
93 {
94 if (rect().contains(e->pos()))
95 {
96 const auto height = width();
97 const auto helpPos = mapFromGlobal(QCursor::pos());
98 const auto x = helpPos.x();
99 if (x >= 0 && x <= height)
100 {
101 QTextCursor cursor = fileDiffWidget->cursorForPosition(helpPos);
102 const auto textRow = cursor.block().blockNumber();
103 auto found = false;
104
105 for (const auto &diff : qAsConst(fileDiffWidget->mFileDiffInfo))
106 {
107 if (textRow + 1 >= diff.startLine && textRow + 1 <= diff.endLine)
108 {
109 fileDiffWidget->mRow = textRow + fileDiffWidget->mStartingLine + 1;
110 found = true;
111 break;
112 }
113 }
114
115 if (!found)
116 fileDiffWidget->mRow = -1;
117
118 repaint();
119 }
120 }
121 else
122 {
123 fileDiffWidget->mRow = -1;
124 repaint();
125 }
126 }
127}
128
129void LineNumberArea::mousePressEvent(QMouseEvent *e)
130{
131 if (mCommentsAllowed)
132 mPressed = rect().contains(e->pos());
133}
134
135void LineNumberArea::mouseReleaseEvent(QMouseEvent *e)
136{
137 if (mCommentsAllowed && mPressed && rect().contains(e->pos()))
138 {
139 const auto height = width();
140 const auto helpPos = mapFromGlobal(QCursor::pos());
141 const auto x = helpPos.x();
142 if (x >= 0 && x <= height)
143 {
144 const auto cursor = fileDiffWidget->cursorForPosition(helpPos);
145 const auto position = cursor.block().blockNumber() + 1;
146 const auto row = position + fileDiffWidget->mStartingLine;
147 const auto linkId = mBookmarks.value(row, -1);
148
149 if (linkId == -1)
150 emit addComment(row);
151 else
152 emit gotoReview(linkId);
153 }
154 }
155
156 mPressed = false;
157}
158