File indexing completed on 2024-10-13 06:37:52

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 2018 Dominik Haumann <dhaumann@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "inlinenote_test.h"
0009 #include "moc_inlinenote_test.cpp"
0010 
0011 #include <katedocument.h>
0012 #include <kateglobal.h>
0013 #include <kateview.h>
0014 #include <ktexteditor/inlinenote.h>
0015 #include <ktexteditor/inlinenoteprovider.h>
0016 
0017 #include <QPainter>
0018 #include <QTemporaryFile>
0019 #include <QTest>
0020 #include <QTestMouseEvent>
0021 
0022 using namespace KTextEditor;
0023 
0024 QTEST_MAIN(InlineNoteTest)
0025 
0026 namespace
0027 {
0028 QWidget *findViewInternal(KTextEditor::View *view)
0029 {
0030     for (QObject *child : view->children()) {
0031         if (child->metaObject()->className() == QByteArrayLiteral("KateViewInternal")) {
0032             return qobject_cast<QWidget *>(child);
0033         }
0034     }
0035     return nullptr;
0036 }
0037 
0038 class NoteProvider : public InlineNoteProvider
0039 {
0040 public:
0041     QList<int> inlineNotes(int line) const override
0042     {
0043         if (line == 0) {
0044             return {5, 10};
0045         }
0046 
0047         return {};
0048     }
0049 
0050     QSize inlineNoteSize(const InlineNote &note) const override
0051     {
0052         if (note.position().column() == 5) {
0053             const auto xWidth = QFontMetrics(note.font()).boundingRect(QStringLiteral("x")).width();
0054             return QSize(xWidth, note.lineHeight());
0055         } else if (note.position().column() == 10) {
0056             return QSize(note.lineHeight(), note.lineHeight());
0057         }
0058 
0059         return QSize();
0060     }
0061 
0062     void paintInlineNote(const InlineNote &note, QPainter &painter, Qt::LayoutDirection) const override
0063     {
0064         if (note.position().column() == 5) {
0065             painter.setPen(Qt::darkGreen);
0066             painter.setBrush(Qt::green);
0067             painter.drawEllipse(1, 1, note.width() - 2, note.lineHeight() - 2);
0068         } else if (note.position().column() == 10) {
0069             painter.setPen(Qt::darkRed);
0070             if (note.underMouse()) {
0071                 painter.setBrush(Qt::red);
0072             } else {
0073                 painter.setBrush(Qt::yellow);
0074             }
0075             painter.drawRoundedRect(1, 1, note.width() - 2, note.lineHeight() - 2, 2, 2);
0076         }
0077     }
0078 
0079     void inlineNoteActivated(const InlineNote &note, Qt::MouseButtons buttons, const QPoint &globalPos) override
0080     {
0081         Q_UNUSED(buttons)
0082         Q_UNUSED(globalPos)
0083         ++noteActivatedCount;
0084         lastUnderMouse = note.underMouse();
0085     }
0086 
0087     void inlineNoteFocusInEvent(const InlineNote &note, const QPoint &globalPos) override
0088     {
0089         Q_UNUSED(globalPos)
0090         ++focusInCount;
0091         lastUnderMouse = note.underMouse();
0092     }
0093 
0094     void inlineNoteFocusOutEvent(const InlineNote &note) override
0095     {
0096         ++focusOutCount;
0097         // Here it should not be under the mosu
0098         lastUnderMouse = note.underMouse();
0099     }
0100 
0101     void inlineNoteMouseMoveEvent(const InlineNote &note, const QPoint &globalPos) override
0102     {
0103         Q_UNUSED(globalPos)
0104         ++mouseMoveCount;
0105         lastUnderMouse = note.underMouse();
0106     }
0107 
0108 public:
0109     int noteActivatedCount = 0;
0110     int focusInCount = 0;
0111     int focusOutCount = 0;
0112     int mouseMoveCount = 0;
0113     bool lastUnderMouse = false;
0114 };
0115 }
0116 
0117 InlineNoteTest::InlineNoteTest()
0118     : QObject()
0119 {
0120     KTextEditor::EditorPrivate::enableUnitTestMode();
0121 }
0122 
0123 InlineNoteTest::~InlineNoteTest()
0124 {
0125 }
0126 
0127 void InlineNoteTest::testInlineNote()
0128 {
0129     KTextEditor::DocumentPrivate doc;
0130     doc.setText(QStringLiteral("xxxxxxxxxx\nxxxxxxxxxx"));
0131 
0132     KTextEditor::ViewPrivate view(&doc, nullptr);
0133     view.show();
0134     view.resize(400, 300);
0135 
0136     view.setCursorPosition({0, 5});
0137     QCOMPARE(view.cursorPosition(), Cursor(0, 5));
0138 
0139     const auto coordCol04 = view.cursorToCoordinate({0, 4});
0140     const auto coordCol05 = view.cursorToCoordinate({0, 5});
0141     const auto coordCol10 = view.cursorToCoordinate({0, 10});
0142     QVERIFY(coordCol05.x() > coordCol04.x());
0143     QVERIFY(coordCol10.x() > coordCol05.x());
0144 
0145     const auto xWidth = coordCol05.x() - coordCol04.x();
0146 
0147     NoteProvider noteProvider;
0148     const QList<int> expectedColumns = {5, 10};
0149     QCOMPARE(noteProvider.inlineNotes(0), expectedColumns);
0150     QCOMPARE(noteProvider.inlineNotes(1), QList<int>());
0151     view.registerInlineNoteProvider(&noteProvider);
0152 
0153     const auto newCoordCol04 = view.cursorToCoordinate({0, 4});
0154     const auto newCoordCol05 = view.cursorToCoordinate({0, 5});
0155     const auto newCoordCol10 = view.cursorToCoordinate({0, 10});
0156 
0157     QVERIFY(newCoordCol05.x() > newCoordCol04.x());
0158     QVERIFY(newCoordCol10.x() > newCoordCol05.x());
0159 
0160     QCOMPARE(newCoordCol04, coordCol04);
0161     QVERIFY(newCoordCol05.x() > coordCol05.x());
0162     QVERIFY(newCoordCol10.x() > coordCol10.x());
0163 
0164     // so far, we should not have any activation event
0165     QCOMPARE(noteProvider.noteActivatedCount, 0);
0166     QCOMPARE(noteProvider.focusInCount, 0);
0167     QCOMPARE(noteProvider.focusOutCount, 0);
0168     QCOMPARE(noteProvider.mouseMoveCount, 0);
0169     QVERIFY(noteProvider.lastUnderMouse == false);
0170 
0171     // mouse move only on X11
0172     if (qApp->platformName() != QLatin1String("xcb")) {
0173         view.unregisterInlineNoteProvider(&noteProvider);
0174         QSKIP("mouse moving only on X11");
0175     }
0176 
0177     // move mouse onto first note
0178     auto internalView = findViewInternal(&view);
0179     QVERIFY(internalView);
0180 
0181     // focus in
0182     QTest::mouseMove(&view, coordCol05 + QPoint(xWidth / 2, 1));
0183     QTest::qWait(100);
0184     QCOMPARE(noteProvider.focusInCount, 1);
0185     QCOMPARE(noteProvider.focusOutCount, 0);
0186     QCOMPARE(noteProvider.mouseMoveCount, 0);
0187     QCOMPARE(noteProvider.noteActivatedCount, 0);
0188     QVERIFY(noteProvider.lastUnderMouse);
0189 
0190     // move one pixel
0191     QTest::mouseMove(&view, coordCol05 + QPoint(xWidth / 2 + 1, 1));
0192     QTest::qWait(100);
0193     QCOMPARE(noteProvider.focusInCount, 1);
0194     QCOMPARE(noteProvider.focusOutCount, 0);
0195     QCOMPARE(noteProvider.mouseMoveCount, 1);
0196     QCOMPARE(noteProvider.noteActivatedCount, 0);
0197     QVERIFY(noteProvider.lastUnderMouse);
0198 
0199     // activate
0200     QTest::mousePress(internalView, Qt::LeftButton, Qt::NoModifier, internalView->mapFromGlobal(view.mapToGlobal(coordCol05 + QPoint(xWidth / 2 + 1, 1))));
0201     QTest::mouseRelease(internalView, Qt::LeftButton, Qt::NoModifier, internalView->mapFromGlobal(view.mapToGlobal(coordCol05 + QPoint(xWidth / 2 + 1, 1))));
0202     QTest::qWait(100);
0203     QCOMPARE(noteProvider.focusInCount, 1);
0204     QCOMPARE(noteProvider.focusOutCount, 0);
0205     QCOMPARE(noteProvider.mouseMoveCount, 1);
0206     QCOMPARE(noteProvider.noteActivatedCount, 1);
0207     QVERIFY(noteProvider.lastUnderMouse);
0208 
0209     // focus out
0210     QTest::mouseMove(&view, coordCol04 + QPoint(0, 1));
0211     QTest::mouseMove(&view, coordCol04 + QPoint(-1, 1));
0212     QTest::qWait(200);
0213     QCOMPARE(noteProvider.focusInCount, 1);
0214     QCOMPARE(noteProvider.focusOutCount, 1);
0215     QCOMPARE(noteProvider.mouseMoveCount, 1);
0216     QCOMPARE(noteProvider.noteActivatedCount, 1);
0217     QVERIFY(noteProvider.lastUnderMouse == false);
0218 
0219     view.unregisterInlineNoteProvider(&noteProvider);
0220 }
0221 
0222 // kate: indent-mode cstyle; indent-width 4; replace-tabs on;