1 /*
2 SPDX-FileCopyrightText: 2007 Alexander Dymo <adymo@kdevelop.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "test_viewactivation.h"
8
9 #include <QTest>
10 #include <QSignalSpy>
11
12 #include <QListView>
13 #include <QTextEdit>
14 #include <QDockWidget>
15 #include <QFocusEvent>
16 #include <QStandardPaths>
17
18 #include <sublime/view.h>
19 #include <sublime/area.h>
20 #include <sublime/controller.h>
21 #include <sublime/mainwindow.h>
22 #include <sublime/container.h>
23 #include <sublime/tooldocument.h>
24
25 using namespace Sublime;
26
27 template <class Widget>
28 class SpecialWidgetFactory: public SimpleToolWidgetFactory<Widget> {
29 public:
SpecialWidgetFactory(const QString & id)30 explicit SpecialWidgetFactory(const QString &id): SimpleToolWidgetFactory<Widget>(id) {}
create(ToolDocument * doc,QWidget * parent=nullptr)31 QWidget* create(ToolDocument *doc, QWidget *parent = nullptr) override
32 {
33 auto* w = new QWidget(parent);
34 auto *inner = new Widget(w);
35 inner->setObjectName(doc->title()+"_inner");
36 w->setObjectName(doc->title()+"_outer");
37 return w;
38 }
39 };
40
initTestCase()41 void TestViewActivation::initTestCase()
42 {
43 QStandardPaths::setTestModeEnabled(true);
44 qRegisterMetaType<View*>("View*");
45 }
46
init()47 void TestViewActivation::init()
48 {
49 controller = new Controller(this);
50 doc1 = new ToolDocument(QStringLiteral("doc1"), controller, new SimpleToolWidgetFactory<QListView>(QStringLiteral("doc1")));
51 //this document will create special widgets - QListView nested in QWidget
52 doc2 = new ToolDocument(QStringLiteral("doc2"), controller, new SpecialWidgetFactory<QListView>(QStringLiteral("doc2")));
53 doc3 = new ToolDocument(QStringLiteral("doc3"), controller, new SimpleToolWidgetFactory<QListView>(QStringLiteral("doc3")));
54 doc4 = new ToolDocument(QStringLiteral("doc4"), controller, new SimpleToolWidgetFactory<QListView>(QStringLiteral("doc4")));
55
56 tool1 = new ToolDocument(QStringLiteral("tool1"), controller, new SimpleToolWidgetFactory<QListView>(QStringLiteral("tool1")));
57 tool2 = new ToolDocument(QStringLiteral("tool2"), controller, new SimpleToolWidgetFactory<QTextEdit>(QStringLiteral("tool2")));
58 tool3 = new ToolDocument(QStringLiteral("tool3"), controller, new SimpleToolWidgetFactory<QTextEdit>(QStringLiteral("tool3")));
59
60 area = new Area(controller, QStringLiteral("Area"));
61
62 view211 = doc1->createView();
63 view211->setObjectName(QStringLiteral("view211"));
64 area->addView(view211);
65 view212 = doc1->createView();
66 view212->setObjectName(QStringLiteral("view212"));
67 area->addView(view212);
68 view221 = doc2->createView();
69 area->addView(view221, view211, Qt::Vertical);
70 view231 = doc3->createView();
71 area->addView(view231, view221, Qt::Horizontal);
72 view241 = doc4->createView();
73 area->addView(view241, view212, Qt::Vertical);
74 viewT11 = tool1->createView();
75 area->addToolView(viewT11, Sublime::Bottom);
76 viewT21 = tool2->createView();
77 area->addToolView(viewT21, Sublime::Right);
78 viewT31 = tool3->createView();
79 area->addToolView(viewT31, Sublime::Top);
80 viewT32 = tool3->createView();
81 area->addToolView(viewT32, Sublime::Top);
82 }
83
cleanup()84 void TestViewActivation::cleanup()
85 {
86 delete controller;
87 }
88
signalsOnViewCreationAndDeletion()89 void TestViewActivation::signalsOnViewCreationAndDeletion()
90 {
91 auto *controller = new Controller(this);
92 auto* doc1 = new ToolDocument(QStringLiteral("doc1"), controller, new SimpleToolWidgetFactory<QListView>(QStringLiteral("doc1")));
93 Area *area = new Area(controller, QStringLiteral("Area"));
94
95 QSignalSpy spy(controller, SIGNAL(viewAdded(Sublime::View*)));
96 View *v = doc1->createView();
97 area->addView(v);
98 QCOMPARE(spy.count(), 1);
99
100 QSignalSpy spy2(controller, SIGNAL(aboutToRemoveView(Sublime::View*)));
101 area->removeView(v);
102 QCOMPARE(spy2.count(), 1);
103
104 QSignalSpy spy3(controller, SIGNAL(toolViewAdded(Sublime::View*)));
105 v = doc1->createView();
106 area->addToolView(v, Sublime::Bottom);
107 QCOMPARE(spy3.count(), 1);
108
109 QSignalSpy spy4(controller, SIGNAL(aboutToRemoveToolView(Sublime::View*)));
110 area->removeToolView(v);
111 QCOMPARE(spy4.count(), 1);
112
113 delete controller;
114 }
115
viewActivation()116 void TestViewActivation::viewActivation()
117 {
118 auto* mw = new MainWindow(controller);
119 controller->addDefaultArea(area); // Q_ASSERT without this.
120 controller->addMainWindow(mw);
121
122 controller->showArea(area, mw);
123 //we should have an active view immediatelly after the area is shown
124 QCOMPARE(mw->activeView(), view211);
125
126 //add some widgets that are not in layout
127 auto *breaker = new QTextEdit(mw);
128 breaker->setObjectName(QStringLiteral("breaker"));
129 auto *toolBreaker = new QTextEdit(mw);
130 toolBreaker->setObjectName(QStringLiteral("toolBreaker"));
131
132 auto* dock = new QDockWidget(mw);
133 dock->setWidget(toolBreaker);
134 mw->addDockWidget(Qt::LeftDockWidgetArea, dock);
135
136 QFocusEvent focusEvent(QEvent::FocusIn);
137 //now post events to the widgets and see if mainwindow has the right active views
138 //activate view
139 qApp->sendEvent(view212->widget(), &focusEvent);
140 QString failMsg = QStringLiteral("\nWas expecting %1 to be active but got %2").
141 arg(view212->objectName(), mw->activeView()->objectName());
142 QVERIFY2(mw->activeView() == view212, failMsg.toLatin1().data());
143
144 //activate tool view and check that both view and tool view are active
145 qApp->sendEvent(viewT31->widget(), &focusEvent);
146 QCOMPARE(mw->activeView(), view212);
147 QCOMPARE(mw->activeToolView(), viewT31);
148
149 //active another view
150 qApp->sendEvent(view241->widget(), &focusEvent);
151 QCOMPARE(mw->activeView(), view241);
152 QCOMPARE(mw->activeToolView(), viewT31);
153
154 //focus a widget not in the area
155 qApp->sendEvent(breaker, &focusEvent);
156 QCOMPARE(mw->activeView(), view241);
157 QCOMPARE(mw->activeToolView(), viewT31);
158
159 //focus a dock not in the area
160 qApp->sendEvent(toolBreaker, &focusEvent);
161 QCOMPARE(mw->activeView(), view241);
162 QCOMPARE(mw->activeToolView(), viewT31);
163
164 //focus inner widget for view221
165 auto *inner = mw->findChild<QListView*>(QStringLiteral("doc2_inner"));
166 QVERIFY(inner);
167 qApp->sendEvent(inner, &focusEvent);
168 QCOMPARE(mw->activeView(), view221);
169 QCOMPARE(mw->activeToolView(), viewT31);
170 }
171
activationInMultipleMainWindows()172 void TestViewActivation::activationInMultipleMainWindows()
173 {
174 MainWindow mw(controller);
175 controller->showArea(area, &mw);
176 QCOMPARE(mw.activeView(), view211);
177
178 //check that new mainwindow always have active view right after displaying area
179 MainWindow mw2(controller);
180 controller->showArea(area, &mw2);
181 QVERIFY(mw2.activeView());
182 QCOMPARE(mw2.activeView()->document(), doc1);
183 }
184
activationAfterViewRemoval()185 void TestViewActivation::activationAfterViewRemoval()
186 {
187 MainWindow mw(controller);
188 controller->showArea(area, &mw);
189 QCOMPARE(mw.activeView(), view211);
190
191 //check what happens if we remove a view which is not the only one in container
192 delete area->removeView(view211);
193 QCOMPARE(mw.activeView(), view212);
194
195 //check what happens if we remove a view which is alone in container
196 mw.activateView(view231);
197 QCOMPARE(mw.activeView(), view231);
198 delete area->removeView(view231);
199 QCOMPARE(mw.activeView(), view221);
200 }
201
activationAfterRemovalSimplestCase()202 void TestViewActivation::activationAfterRemovalSimplestCase()
203 {
204 //we don't have split views - just two views in one area index
205 MainWindow mw(controller);
206 Area *area = new Area(controller, QStringLiteral("Area"));
207 View *v1 = doc1->createView();
208 View *v2 = doc2->createView();
209 area->addView(v1);
210 area->addView(v2, v1);
211 controller->showArea(area, &mw);
212 mw.activateView(v2);
213
214 //delete active view and check that previous is activated
215 delete area->removeView(v2);
216 QCOMPARE(mw.activeView(), v1);
217 }
218
219 QTEST_MAIN(TestViewActivation)
220