File indexing completed on 2024-10-06 09:42:00

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/inlinenoteinterface.h>
0016 #include <ktexteditor/inlinenoteprovider.h>
0017 
0018 #include <QPainter>
0019 #include <QTemporaryFile>
0020 #include <QtTestWidgets>
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     QVector<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) 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(QLatin1String("xxxxxxxxxx\nxxxxxxxxxx"));
0131 
0132     KTextEditor::ViewPrivate view(&doc, nullptr);
0133     view.show();
0134 
0135     QTest::qWait(100);
0136 
0137     view.setCursorPosition({0, 5});
0138     QCOMPARE(view.cursorPosition(), Cursor(0, 5));
0139 
0140     const auto coordCol04 = view.cursorToCoordinate({0, 4});
0141     const auto coordCol05 = view.cursorToCoordinate({0, 5});
0142     const auto coordCol10 = view.cursorToCoordinate({0, 10});
0143     QVERIFY(coordCol05.x() > coordCol04.x());
0144     QVERIFY(coordCol10.x() > coordCol05.x());
0145 
0146     const auto xWidth = coordCol05.x() - coordCol04.x();
0147 
0148     auto iface = qobject_cast<KTextEditor::InlineNoteInterface *>(&view);
0149     QVERIFY(iface != nullptr);
0150 
0151     NoteProvider noteProvider;
0152     const QVector<int> expectedColumns = {5, 10};
0153     QCOMPARE(noteProvider.inlineNotes(0), expectedColumns);
0154     QCOMPARE(noteProvider.inlineNotes(1), QVector<int>());
0155     iface->registerInlineNoteProvider(&noteProvider);
0156 
0157     QTest::qWait(100);
0158 
0159     const auto newCoordCol04 = view.cursorToCoordinate({0, 4});
0160     const auto newCoordCol05 = view.cursorToCoordinate({0, 5});
0161     const auto newCoordCol10 = view.cursorToCoordinate({0, 10});
0162 
0163     QVERIFY(newCoordCol05.x() > newCoordCol04.x());
0164     QVERIFY(newCoordCol10.x() > newCoordCol05.x());
0165 
0166     QCOMPARE(newCoordCol04, coordCol04);
0167     QVERIFY(newCoordCol05.x() > coordCol05.x());
0168     QVERIFY(newCoordCol10.x() > coordCol10.x());
0169 
0170     // so far, we should not have any activation event
0171     QCOMPARE(noteProvider.noteActivatedCount, 0);
0172     QCOMPARE(noteProvider.focusInCount, 0);
0173     QCOMPARE(noteProvider.focusOutCount, 0);
0174     QCOMPARE(noteProvider.mouseMoveCount, 0);
0175     QVERIFY(noteProvider.lastUnderMouse == false);
0176 
0177     // ATM fails on Windows, mark as such to be able to enforce test success in CI
0178 #ifdef Q_OS_WIN
0179     QSKIP("Fails ATM, please fix");
0180 #endif
0181 
0182     // move mouse onto first note
0183     auto internalView = findViewInternal(&view);
0184     QVERIFY(internalView);
0185 
0186     // focus in
0187     QTest::mouseMove(&view, coordCol05 + QPoint(xWidth / 2, 1));
0188     QTest::qWait(100);
0189     QCOMPARE(noteProvider.focusInCount, 1);
0190     QCOMPARE(noteProvider.focusOutCount, 0);
0191     QCOMPARE(noteProvider.mouseMoveCount, 0);
0192     QCOMPARE(noteProvider.noteActivatedCount, 0);
0193     QVERIFY(noteProvider.lastUnderMouse);
0194 
0195     // move one pixel
0196     QTest::mouseMove(&view, coordCol05 + QPoint(xWidth / 2 + 1, 1));
0197     QTest::qWait(100);
0198     QCOMPARE(noteProvider.focusInCount, 1);
0199     QCOMPARE(noteProvider.focusOutCount, 0);
0200     QCOMPARE(noteProvider.mouseMoveCount, 1);
0201     QCOMPARE(noteProvider.noteActivatedCount, 0);
0202     QVERIFY(noteProvider.lastUnderMouse);
0203 
0204     // activate
0205     QTest::mousePress(internalView, Qt::LeftButton, Qt::NoModifier, internalView->mapFromGlobal(view.mapToGlobal(coordCol05 + QPoint(xWidth / 2 + 1, 1))));
0206     QTest::mouseRelease(internalView, Qt::LeftButton, Qt::NoModifier, internalView->mapFromGlobal(view.mapToGlobal(coordCol05 + QPoint(xWidth / 2 + 1, 1))));
0207     QTest::qWait(100);
0208     QCOMPARE(noteProvider.focusInCount, 1);
0209     QCOMPARE(noteProvider.focusOutCount, 0);
0210     QCOMPARE(noteProvider.mouseMoveCount, 1);
0211     QCOMPARE(noteProvider.noteActivatedCount, 1);
0212     QVERIFY(noteProvider.lastUnderMouse);
0213 
0214     // focus out
0215     QTest::mouseMove(&view, coordCol04 + QPoint(0, 1));
0216     QTest::mouseMove(&view, coordCol04 + QPoint(-1, 1));
0217     QTest::qWait(200);
0218     QCOMPARE(noteProvider.focusInCount, 1);
0219     QCOMPARE(noteProvider.focusOutCount, 1);
0220     QCOMPARE(noteProvider.mouseMoveCount, 1);
0221     QCOMPARE(noteProvider.noteActivatedCount, 1);
0222     QVERIFY(noteProvider.lastUnderMouse == false);
0223 
0224     iface->unregisterInlineNoteProvider(&noteProvider);
0225 }
0226 
0227 // kate: indent-mode cstyle; indent-width 4; replace-tabs on;