| 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 | |
| 11 | LineNumberArea::LineNumberArea(FileDiffView *editor, bool ) |
| 12 | : QWidget(editor) |
| 13 | , mCommentsAllowed(allowComments) |
| 14 | { |
| 15 | fileDiffWidget = editor; |
| 16 | setMouseTracking(true); |
| 17 | } |
| 18 | |
| 19 | int LineNumberArea::widthInDigitsSize() |
| 20 | { |
| 21 | return 3; |
| 22 | } |
| 23 | |
| 24 | QSize LineNumberArea::sizeHint() const |
| 25 | { |
| 26 | return { fileDiffWidget->lineNumberAreaWidth(), 0 }; |
| 27 | } |
| 28 | |
| 29 | void LineNumberArea::setEditor(FileDiffView *editor) |
| 30 | { |
| 31 | fileDiffWidget = editor; |
| 32 | setParent(editor); |
| 33 | } |
| 34 | |
| 35 | void 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 | |
| 90 | void 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 | |
| 129 | void LineNumberArea::mousePressEvent(QMouseEvent *e) |
| 130 | { |
| 131 | if (mCommentsAllowed) |
| 132 | mPressed = rect().contains(e->pos()); |
| 133 | } |
| 134 | |
| 135 | void 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 | |