File indexing completed on 2024-05-12 16:06:01

0001 /*
0002     SPDX-FileCopyrightText: 2020 Simone Gaiarin <simgunz@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // clazy:excludeall=qstring-allocations
0008 
0009 #include <QTest>
0010 
0011 #include <QMenu>
0012 #include <QTabBar>
0013 #include <QTabWidget>
0014 #include <QToolBar>
0015 #include <QWidget>
0016 
0017 #include <KActionCollection>
0018 #include <KSelectAction>
0019 
0020 #include "../core/page.h"
0021 #include "../part/pageview.h"
0022 #include "../part/part.h"
0023 #include "../part/toggleactionmenu.h"
0024 #include "../settings.h"
0025 #include "../shell/okular_main.h"
0026 #include "../shell/shell.h"
0027 #include "../shell/shellutils.h"
0028 #include "closedialoghelper.h"
0029 
0030 namespace Okular
0031 {
0032 class PartTest
0033 {
0034 public:
0035     Okular::Document *partDocument(Okular::Part *part) const
0036     {
0037         return part->m_document;
0038     }
0039     PageView *pageView(Okular::Part *part) const
0040     {
0041         return part->m_pageView;
0042     }
0043 };
0044 }
0045 
0046 class AnnotationToolBarTest : public QObject, public Okular::PartTest
0047 {
0048     Q_OBJECT
0049 
0050 public:
0051     static void initMain();
0052     static QTabWidget *tabWidget(Shell *s)
0053     {
0054         return s->m_tabWidget;
0055     }
0056 
0057 private Q_SLOTS:
0058     void initTestCase();
0059     void init();
0060     void cleanup();
0061 
0062     void testAnnotationToolBar();
0063     void testAnnotationToolBar_data();
0064     void testAnnotationToolBarActionsEnabledState();
0065     void testAnnotationToolBarActionsEnabledState_data();
0066     void testAnnotationToolBarConfigActionsEnabledState();
0067     void testAnnotationToolBarConfigActionsEnabledState_data();
0068 
0069 private:
0070     bool simulateAddPopupAnnotation(Okular::Part *part, int mouseX, int mouseY);
0071 };
0072 
0073 Shell *findShell(Shell *ignore = nullptr)
0074 {
0075     const QWidgetList wList = QApplication::topLevelWidgets();
0076     for (QWidget *widget : wList) {
0077         Shell *s = qobject_cast<Shell *>(widget);
0078         if (s && s != ignore) {
0079             return s;
0080         }
0081     }
0082     return nullptr;
0083 }
0084 
0085 void AnnotationToolBarTest::initMain()
0086 {
0087     // Ensure consistent configs/caches and Default UI
0088     QTemporaryDir homeDir;
0089     Q_ASSERT(homeDir.isValid());
0090     QByteArray homePath = QFile::encodeName(homeDir.path());
0091     qputenv("USERPROFILE", homePath);
0092     qputenv("HOME", homePath);
0093     qputenv("XDG_DATA_HOME", QByteArray(homePath + "/.local"));
0094     qputenv("XDG_CONFIG_HOME", QByteArray(homePath + "/.kde-unit-test/xdg/config"));
0095 }
0096 
0097 void AnnotationToolBarTest::initTestCase()
0098 {
0099     QStandardPaths::setTestModeEnabled(true);
0100     // Don't pollute people's okular settings
0101     Okular::Settings::instance(QStringLiteral("annotationtoolbartest"));
0102 }
0103 
0104 void AnnotationToolBarTest::init()
0105 {
0106     // Default settings for every test
0107     Okular::Settings::self()->setDefaults();
0108 }
0109 
0110 void AnnotationToolBarTest::cleanup()
0111 {
0112     Shell *s;
0113     while ((s = findShell())) {
0114         delete s;
0115     }
0116 }
0117 
0118 bool AnnotationToolBarTest::simulateAddPopupAnnotation(Okular::Part *part, int mouseX, int mouseY)
0119 {
0120     int annotationCount = partDocument(part)->page(0)->annotations().size();
0121     QTest::mouseMove(pageView(part)->viewport(), QPoint(mouseX, mouseY));
0122     QTest::mouseClick(pageView(part)->viewport(), Qt::LeftButton, Qt::NoModifier, QPoint(mouseX, mouseY));
0123     bool annotationAdded = partDocument(part)->page(0)->annotations().size() == annotationCount + 1;
0124     return annotationAdded;
0125 }
0126 
0127 void AnnotationToolBarTest::testAnnotationToolBar()
0128 {
0129     // Using tabs we test that the annotation toolbar works on each Okular::Part
0130     Okular::Settings::self()->setShellOpenFileInTabs(true);
0131 
0132     const QStringList paths = {QStringLiteral(KDESRCDIR "data/file1.pdf"), QStringLiteral(KDESRCDIR "data/file2.pdf")};
0133     QString serializedOptions = ShellUtils::serializeOptions(false, false, false, false, false, QString(), QString(), QString());
0134 
0135     Okular::Status status = Okular::main(paths, serializedOptions);
0136     QCOMPARE(status, Okular::Success);
0137     Shell *s = findShell();
0138     QVERIFY(s);
0139     QVERIFY(QTest::qWaitForWindowExposed(s));
0140     QFETCH(int, tabIndex);
0141     s->m_tabWidget->tabBar()->setCurrentIndex(tabIndex);
0142     Okular::Part *part = dynamic_cast<Okular::Part *>(s->m_tabs[tabIndex].part);
0143     QVERIFY(part);
0144 
0145     QToolBar *annToolBar = s->findChild<QToolBar *>(QStringLiteral("annotationToolBar"));
0146     QVERIFY(annToolBar);
0147 
0148     // Check config action default enabled states
0149     QAction *aQuickTools = part->actionCollection()->action(QStringLiteral("annotation_favorites"));
0150     QAction *aAddToQuickTools = part->actionCollection()->action(QStringLiteral("annotation_bookmark"));
0151     QAction *aAdvancedSettings = part->actionCollection()->action(QStringLiteral("annotation_settings_advanced"));
0152     QAction *aContinuousMode = part->actionCollection()->action(QStringLiteral("annotation_settings_pin"));
0153     QVERIFY(aQuickTools->isEnabled());
0154     QVERIFY(!aAddToQuickTools->isEnabled());
0155     QVERIFY(!aAdvancedSettings->isEnabled());
0156     QVERIFY(aContinuousMode->isEnabled());
0157 
0158     // Ensure that the 'Quick Annotations' action is correctly populated
0159     // (at least the 'Configure Annotations...' action must be present)
0160     QVERIFY(!aQuickTools->menu()->actions().isEmpty());
0161 
0162     // Test annotation toolbar visibility triggers
0163     QAction *toggleAnnotationToolBar = part->actionCollection()->action(QStringLiteral("mouse_toggle_annotate"));
0164     QAction *aHideToolBar = part->actionCollection()->action(QStringLiteral("hide_annotation_toolbar"));
0165     QVERIFY(toggleAnnotationToolBar);
0166     QVERIFY(aHideToolBar);
0167     toggleAnnotationToolBar->setChecked(false);
0168     QTRY_VERIFY(!annToolBar->isVisible());
0169     toggleAnnotationToolBar->trigger();
0170     QTRY_VERIFY2(annToolBar->isVisible(), "Annotation action failed to show.");
0171     toggleAnnotationToolBar->trigger();
0172     QTRY_VERIFY2(!annToolBar->isVisible(), "Annotation action failed to hide.");
0173 
0174     toggleAnnotationToolBar->setChecked(true);
0175     QTRY_VERIFY(annToolBar->isVisible());
0176     aHideToolBar->trigger();
0177     QTRY_VERIFY2(!annToolBar->isVisible(), "Hide toolbar action failed to hide.");
0178 
0179     toggleAnnotationToolBar->setChecked(false);
0180     QTRY_VERIFY(!annToolBar->isVisible());
0181     QTest::keyClick(part->widget(), Qt::Key_1, Qt::AltModifier);
0182     QTRY_VERIFY2(annToolBar->isVisible(), "ToolBar not shown when triggering annotation using shortcut.");
0183     toggleAnnotationToolBar->setChecked(false);
0184     QTRY_VERIFY(!annToolBar->isVisible());
0185     QTest::keyClick(part->widget(), Qt::Key_3);
0186     QTRY_VERIFY2(!annToolBar->isVisible(), "ToolBar shown when triggering quick annotation using shortcut.");
0187 
0188     // set mouse mode to browse before starting the tests on the annotation actions
0189     QAction *aMouseNormal = part->actionCollection()->action(QStringLiteral("mouse_drag"));
0190     QVERIFY(aMouseNormal);
0191     aMouseNormal->trigger();
0192     QTRY_COMPARE(Okular::Settings::mouseMode(), static_cast<int>(Okular::Settings::EnumMouseMode::Browse));
0193 
0194     // Click an annotation action to enable it
0195     QAction *aPopupNote = part->actionCollection()->action(QStringLiteral("annotation_popup_note"));
0196     QVERIFY(aPopupNote);
0197     aPopupNote->trigger();
0198     int mouseX = 350;
0199     int mouseY = 100;
0200     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), true);
0201     QTRY_COMPARE(aMouseNormal->isChecked(), false);
0202 
0203     // Click again the same annotation action to disable it
0204     aPopupNote->trigger();
0205     mouseY = 150;
0206     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), false);
0207     QTRY_COMPARE(aMouseNormal->isChecked(), true);
0208 
0209     // Trigger the action using a shortcut
0210     QTest::keyClick(part->widget(), Qt::Key_7, Qt::AltModifier);
0211     mouseY = 200;
0212     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), true);
0213     QTRY_COMPARE(aMouseNormal->isChecked(), false);
0214 
0215     // Click Esc to disable all annotations
0216     QTest::keyClick(pageView(part), Qt::Key_Escape);
0217     mouseY = 250;
0218     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), false);
0219     QTRY_COMPARE(aMouseNormal->isChecked(), true);
0220 
0221     // Trigger the action using a quick annotation shortcut
0222     QTest::keyClick(part->widget(), Qt::Key_6);
0223     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), true);
0224     QTRY_COMPARE(aMouseNormal->isChecked(), false);
0225 
0226     // Test pin/continuous mode action
0227     QVERIFY(aContinuousMode->isEnabled());
0228     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), true);
0229     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), true);
0230     aContinuousMode->trigger();
0231     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), true);
0232     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), false);
0233 
0234     // Test adding a tool to the quick tool list using the bookmark action
0235     QScopedPointer<TestingUtils::CloseDialogHelper> closeDialogHelper;
0236     closeDialogHelper.reset(new TestingUtils::CloseDialogHelper(QDialogButtonBox::Ok));
0237     aPopupNote->trigger();
0238     QVERIFY(aPopupNote->isChecked());
0239     int quickActionCount = aQuickTools->menu()->actions().size();
0240     aAddToQuickTools->trigger();
0241     QTRY_COMPARE(aQuickTools->menu()->actions().size(), quickActionCount + 1);
0242     // Trigger the quick tool that was just added
0243     aQuickTools->menu()->actions().at(6)->trigger();
0244     QCOMPARE(simulateAddPopupAnnotation(part, mouseX, mouseY), true);
0245 }
0246 
0247 void AnnotationToolBarTest::testAnnotationToolBar_data()
0248 {
0249     QTest::addColumn<int>("tabIndex");
0250     QTest::addRow("first tab") << 0;
0251     QTest::addRow("second tab") << 1;
0252 }
0253 
0254 void AnnotationToolBarTest::testAnnotationToolBarActionsEnabledState()
0255 {
0256     QFETCH(QString, document);
0257 
0258     const QStringList paths = {document};
0259     QString serializedOptions = ShellUtils::serializeOptions(false, false, false, false, false, QString(), QString(), QString());
0260 
0261     Okular::Status status = Okular::main(paths, serializedOptions);
0262     QCOMPARE(status, Okular::Success);
0263     Shell *s = findShell();
0264     QVERIFY(s);
0265     QVERIFY(QTest::qWaitForWindowExposed(s));
0266 
0267     Okular::Part *part = s->findChild<Okular::Part *>();
0268     QVERIFY(part);
0269 
0270     KActionCollection *ac = part->actionCollection();
0271     QAction *aQuickTools = ac->action(QStringLiteral("annotation_favorites"));
0272     QAction *aHighlighter = ac->action(QStringLiteral("annotation_highlighter"));
0273     QAction *aUnderline = ac->action(QStringLiteral("annotation_underline"));
0274     QAction *aSquiggle = ac->action(QStringLiteral("annotation_squiggle"));
0275     QAction *aStrikeout = ac->action(QStringLiteral("annotation_strike_out"));
0276     QAction *aTypewriter = ac->action(QStringLiteral("annotation_typewriter"));
0277     QAction *aInlineNote = ac->action(QStringLiteral("annotation_inline_note"));
0278     QAction *aPopupNote = ac->action(QStringLiteral("annotation_popup_note"));
0279     QAction *aFreehandLine = ac->action(QStringLiteral("annotation_freehand_line"));
0280     QAction *aGeomShapes = ac->action(QStringLiteral("annotation_geometrical_shape"));
0281     QAction *aStamp = ac->action(QStringLiteral("annotation_stamp"));
0282 
0283     QFETCH(bool, aQuickToolsEnabled);
0284     QFETCH(bool, aHighlighterEnabled);
0285     QFETCH(bool, aUnderlineEnabled);
0286     QFETCH(bool, aSquiggleEnabled);
0287     QFETCH(bool, aStrikeoutEnabled);
0288     QFETCH(bool, aTypewriterEnabled);
0289     QFETCH(bool, aInlineNoteEnabled);
0290     QFETCH(bool, aPopupNoteEnabled);
0291     QFETCH(bool, aFreehandLineEnabled);
0292     QFETCH(bool, aGeomShapesEnabled);
0293     QFETCH(bool, aStampEnabled);
0294 
0295     QCOMPARE(aQuickTools->isEnabled(), aQuickToolsEnabled);
0296     QCOMPARE(aHighlighter->isEnabled(), aHighlighterEnabled);
0297     QCOMPARE(aUnderline->isEnabled(), aUnderlineEnabled);
0298     QCOMPARE(aSquiggle->isEnabled(), aSquiggleEnabled);
0299     QCOMPARE(aStrikeout->isEnabled(), aStrikeoutEnabled);
0300     QCOMPARE(aTypewriter->isEnabled(), aTypewriterEnabled);
0301     QCOMPARE(aInlineNote->isEnabled(), aInlineNoteEnabled);
0302     QCOMPARE(aPopupNote->isEnabled(), aPopupNoteEnabled);
0303     QCOMPARE(aFreehandLine->isEnabled(), aFreehandLineEnabled);
0304     QCOMPARE(aGeomShapes->isEnabled(), aGeomShapesEnabled);
0305     QCOMPARE(aStamp->isEnabled(), aStampEnabled);
0306 
0307     // trigger a reparsing of the tools to ensure that the enabled/disabled state is not changed (bug: 424296)
0308     QAction *aMouseSelect = ac->action(QStringLiteral("mouse_select"));
0309     QAction *aMouseNormal = ac->action(QStringLiteral("mouse_drag"));
0310     aMouseSelect->trigger();
0311     aMouseNormal->trigger();
0312 
0313     QCOMPARE(aQuickTools->isEnabled(), aQuickToolsEnabled);
0314     QCOMPARE(aHighlighter->isEnabled(), aHighlighterEnabled);
0315     QCOMPARE(aUnderline->isEnabled(), aUnderlineEnabled);
0316     QCOMPARE(aSquiggle->isEnabled(), aSquiggleEnabled);
0317     QCOMPARE(aStrikeout->isEnabled(), aStrikeoutEnabled);
0318     QCOMPARE(aTypewriter->isEnabled(), aTypewriterEnabled);
0319     QCOMPARE(aInlineNote->isEnabled(), aInlineNoteEnabled);
0320     QCOMPARE(aPopupNote->isEnabled(), aPopupNoteEnabled);
0321     QCOMPARE(aFreehandLine->isEnabled(), aFreehandLineEnabled);
0322     QCOMPARE(aGeomShapes->isEnabled(), aGeomShapesEnabled);
0323     QCOMPARE(aStamp->isEnabled(), aStampEnabled);
0324 }
0325 
0326 void AnnotationToolBarTest::testAnnotationToolBarActionsEnabledState_data()
0327 {
0328     QTest::addColumn<QString>("document");
0329     QTest::addColumn<bool>("aQuickToolsEnabled");
0330     QTest::addColumn<bool>("aHighlighterEnabled");
0331     QTest::addColumn<bool>("aUnderlineEnabled");
0332     QTest::addColumn<bool>("aSquiggleEnabled");
0333     QTest::addColumn<bool>("aStrikeoutEnabled");
0334     QTest::addColumn<bool>("aTypewriterEnabled");
0335     QTest::addColumn<bool>("aInlineNoteEnabled");
0336     QTest::addColumn<bool>("aPopupNoteEnabled");
0337     QTest::addColumn<bool>("aFreehandLineEnabled");
0338     QTest::addColumn<bool>("aGeomShapesEnabled");
0339     QTest::addColumn<bool>("aStampEnabled");
0340 
0341     QTest::addRow("pdf") << QStringLiteral(KDESRCDIR "data/file1.pdf") << true << true << true << true << true << true << true << true << true << true << true;
0342     QTest::addRow("protected-pdf") << QStringLiteral(KDESRCDIR "data/protected.pdf") << false << false << false << false << false << false << false << false << false << false << false;
0343     QTest::addRow("image") << QStringLiteral(KDESRCDIR "data/potato.jpg") << true << false << false << false << false << true << true << true << true << true << true;
0344 }
0345 
0346 void AnnotationToolBarTest::testAnnotationToolBarConfigActionsEnabledState()
0347 {
0348     const QStringList paths = {QStringLiteral(KDESRCDIR "data/file1.pdf")};
0349     QString serializedOptions = ShellUtils::serializeOptions(false, false, false, false, false, QString(), QString(), QString());
0350 
0351     Okular::Status status = Okular::main(paths, serializedOptions);
0352     QCOMPARE(status, Okular::Success);
0353     Shell *s = findShell();
0354     QVERIFY(s);
0355     QVERIFY(QTest::qWaitForWindowExposed(s));
0356 
0357     Okular::Part *part = s->findChild<Okular::Part *>();
0358     QVERIFY(part);
0359 
0360     KActionCollection *ac = part->actionCollection();
0361     QAction *aWidth = ac->action(QStringLiteral("annotation_settings_width"));
0362     QAction *aColor = ac->action(QStringLiteral("annotation_settings_color"));
0363     QAction *aInnerColor = ac->action(QStringLiteral("annotation_settings_inner_color"));
0364     QAction *aOpacity = ac->action(QStringLiteral("annotation_settings_opacity"));
0365     QAction *aFont = ac->action(QStringLiteral("annotation_settings_font"));
0366 
0367     QFETCH(QString, annotationActionName);
0368     QFETCH(bool, widthEnabled);
0369     QFETCH(bool, colorEnabled);
0370     QFETCH(bool, innerColorEnabled);
0371     QFETCH(bool, opacityEnabled);
0372     QFETCH(bool, fontEnabled);
0373 
0374     QAction *annotationAction = ac->action(annotationActionName);
0375     annotationAction->trigger();
0376 
0377     QCOMPARE(aWidth->isEnabled(), widthEnabled);
0378     QCOMPARE(aColor->isEnabled(), colorEnabled);
0379     QCOMPARE(aInnerColor->isEnabled(), innerColorEnabled);
0380     QCOMPARE(aOpacity->isEnabled(), opacityEnabled);
0381     QCOMPARE(aFont->isEnabled(), fontEnabled);
0382 }
0383 
0384 void AnnotationToolBarTest::testAnnotationToolBarConfigActionsEnabledState_data()
0385 {
0386     QTest::addColumn<QString>("annotationActionName");
0387     QTest::addColumn<bool>("widthEnabled");
0388     QTest::addColumn<bool>("colorEnabled");
0389     QTest::addColumn<bool>("innerColorEnabled");
0390     QTest::addColumn<bool>("opacityEnabled");
0391     QTest::addColumn<bool>("fontEnabled");
0392 
0393     QTest::addRow("annotation_highlighter") << QStringLiteral("annotation_highlighter") << false << true << false << true << false;
0394     QTest::addRow("annotation_underline") << QStringLiteral("annotation_underline") << false << true << false << true << false;
0395     QTest::addRow("annotation_squiggle") << QStringLiteral("annotation_squiggle") << false << true << false << true << false;
0396     QTest::addRow("annotation_strike_out") << QStringLiteral("annotation_strike_out") << false << true << false << true << false;
0397     QTest::addRow("annotation_typewriter") << QStringLiteral("annotation_typewriter") << false << true << false << true << true;
0398     QTest::addRow("annotation_inline_note") << QStringLiteral("annotation_inline_note") << false << true << false << true << true;
0399     QTest::addRow("annotation_popup_note") << QStringLiteral("annotation_popup_note") << false << true << false << true << false;
0400     QTest::addRow("annotation_freehand_line") << QStringLiteral("annotation_freehand_line") << true << true << false << true << false;
0401     QTest::addRow("annotation_line") << QStringLiteral("annotation_straight_line") << true << true << false << true << false;
0402     QTest::addRow("annotation_rectangle") << QStringLiteral("annotation_rectangle") << true << true << true << true << false;
0403 }
0404 
0405 QTEST_MAIN(AnnotationToolBarTest)
0406 #include "annotationtoolbartest.moc"