1 /**
2 * UGENE - Integrated Bioinformatics Tools.
3 * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4 * http://ugene.net
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #include "GTUtilsMdi.h"
23 #include <base_dialogs/MessageBoxFiller.h>
24 #include <drivers/GTKeyboardDriver.h>
25 #include <drivers/GTMouseDriver.h>
26
27 #include <QApplication>
28 #include <QMainWindow>
29 #include <QMdiArea>
30 #include <QMdiSubWindow>
31 #include <QMenu>
32
33 #include <U2Core/AppContext.h>
34 #include <U2Core/U2SafePoints.h>
35
36 #include <U2Gui/MainWindow.h>
37 #include <U2Gui/ObjectViewModel.h>
38
39 #include "GTGlobals.h"
40 #include "primitives/GTMenu.h"
41 #include "utils/GTThread.h"
42
43 namespace U2 {
44 using namespace HI;
45
46 #define GT_CLASS_NAME "GTUtilsMdi"
47
48 #define GT_METHOD_NAME "click"
click(HI::GUITestOpStatus & os,GTGlobals::WindowAction action)49 void GTUtilsMdi::click(HI::GUITestOpStatus &os, GTGlobals::WindowAction action) {
50 MainWindow *mw = AppContext::getMainWindow();
51 GT_CHECK(mw != nullptr, "MainWindow == NULL");
52
53 QMainWindow *mainWindow = mw->getQMainWindow();
54 GT_CHECK(mainWindow != nullptr, "QMainWindow == NULL");
55
56 // TODO: batch tests run fails because of not maximized window by default from settings
57 // if ((action == GTGlobals::Maximize) || (action == GTGlobals::Minimize)) {
58 // return;
59 // }
60
61 #ifndef Q_OS_DARWIN
62 switch (action) {
63 case GTGlobals::Close: {
64 # ifdef Q_OS_UNIX
65 GTMenu::clickMainMenuItem(os, QStringList() << "Window"
66 << "Close active view");
67 # else
68 GTKeyboardDriver::keyPress(Qt::Key_Control);
69 GTKeyboardDriver::keyClick(Qt::Key_F4);
70 GTKeyboardDriver::keyRelease(Qt::Key_Control);
71 # endif
72 break;
73 }
74 default:
75 GTMenuBar::clickCornerMenu(os, mainWindow->menuBar(), action);
76 break;
77 }
78 #else
79 MWMDIWindow *mdiWindow = mw->getMDIManager()->getActiveWindow();
80 GT_CHECK(mdiWindow != nullptr, "MDIWindow == NULL");
81
82 // TODO: make click on button
83 switch (action) {
84 case GTGlobals::Maximize:
85 GTWidget::showMaximized(os, mdiWindow);
86 break;
87 case GTGlobals::Close: {
88 int left = mdiWindow->rect().left();
89 int top = mdiWindow->rect().top();
90 QPoint p(left + 15, top - 10);
91 GTMouseDriver::moveTo(mdiWindow->mapToGlobal(p));
92 GTMouseDriver::click();
93 break;
94 }
95 default:
96 assert(false);
97 break;
98 }
99 #endif
100 }
101 #undef GT_METHOD_NAME
102
103 #define GT_METHOD_NAME "findWindow"
findWindow(HI::GUITestOpStatus & os,const QString & windowName,const GTGlobals::FindOptions & options)104 QWidget *GTUtilsMdi::findWindow(HI::GUITestOpStatus &os, const QString &windowName, const GTGlobals::FindOptions &options) {
105 GT_CHECK_RESULT(!windowName.isEmpty(), "windowname is empty", nullptr);
106
107 MainWindow *mainWindow = AppContext::getMainWindow();
108 GT_CHECK_RESULT(mainWindow != nullptr, "MainWindow == nullptr", nullptr);
109
110 for (int time = 0; time < GT_OP_WAIT_MILLIS; time += GT_OP_CHECK_MILLIS) {
111 GTGlobals::sleep(time > 0 ? GT_OP_CHECK_MILLIS : 0);
112
113 QList<MWMDIWindow *> mdiWindows = mainWindow->getMDIManager()->getWindows();
114 foreach (MWMDIWindow *window, mdiWindows) {
115 QString mdiTitle = window->windowTitle();
116 switch (options.matchPolicy) {
117 case Qt::MatchExactly:
118 if (mdiTitle == windowName) {
119 GTThread::waitForMainThread();
120 return window;
121 }
122 break;
123 case Qt::MatchContains:
124 if (mdiTitle.contains(windowName, Qt::CaseInsensitive)) {
125 GTThread::waitForMainThread();
126 return window;
127 }
128 break;
129 default:
130 GT_CHECK_RESULT(false, "Not implemented", nullptr);
131 }
132 }
133 if (!options.failIfNotFound) {
134 break;
135 }
136 }
137
138 GT_CHECK_RESULT(!options.failIfNotFound, "Widget " + windowName + " not found", nullptr);
139 return nullptr;
140 }
141 #undef GT_METHOD_NAME
142
143 #define GT_METHOD_NAME "closeActiveWindow"
closeActiveWindow(GUITestOpStatus & os)144 void GTUtilsMdi::closeActiveWindow(GUITestOpStatus &os) {
145 closeWindow(os, activeWindowTitle(os));
146 }
147 #undef GT_METHOD_NAME
148
149 #define GT_METHOD_NAME "closeWindow"
closeWindow(HI::GUITestOpStatus & os,const QString & windowName,const GTGlobals::FindOptions & options)150 void GTUtilsMdi::closeWindow(HI::GUITestOpStatus &os, const QString &windowName, const GTGlobals::FindOptions &options) {
151 GT_CHECK(windowName.isEmpty() == false, "windowname is empty");
152
153 MainWindow *mw = AppContext::getMainWindow();
154 GT_CHECK(mw != nullptr, "MainWindow == NULL");
155
156 MWMDIWindow *window = qobject_cast<MWMDIWindow *>(findWindow(os, windowName, options));
157 GT_CHECK(window != nullptr, "Cannot find MDI window");
158 GTWidget::close(os, window->parentWidget());
159 }
160 #undef GT_METHOD_NAME
161
162 #define GT_METHOD_NAME "closeAllWindows"
closeAllWindows(HI::GUITestOpStatus & os)163 void GTUtilsMdi::closeAllWindows(HI::GUITestOpStatus &os) {
164 #ifndef Q_OS_DARWIN
165 class Scenario : public CustomScenario {
166 public:
167 void run(HI::GUITestOpStatus &os) {
168 const QList<QMdiSubWindow *> mdiWindows = AppContext::getMainWindow()->getQMainWindow()->findChildren<QMdiSubWindow *>();
169 foreach (QMdiSubWindow *mdiWindow, mdiWindows) {
170 MessageBoxDialogFiller *filler = new MessageBoxDialogFiller(os, QMessageBox::Discard);
171 GTUtilsDialog::waitForDialogWhichMayRunOrNot(os, filler);
172 mdiWindow->close();
173 GTGlobals::sleep(100);
174 GTUtilsDialog::removeRunnable(filler);
175 }
176 }
177 };
178
179 GTThread::runInMainThread(os, new Scenario());
180 #else
181 // GUI on Mac hangs because of bug in QCocoaEventDispatcher
182 // It looks like this issue: https://bugreports.qt.io/browse/QTBUG-45389
183 // This part can be removed after Qt bug will be fixed
184 // And now: some magic!
185
186 QWidget *prevWindow = nullptr;
187 QWidget *mdiWindow = nullptr;
188 GTGlobals::FindOptions options(false);
189
190 bool tabbedView = isTabbedLayout(os);
191
192 while ((mdiWindow = GTUtilsMdi::activeWindow(os, options)) != nullptr) {
193 GT_CHECK(mdiWindow != prevWindow, "Can't close MDI window");
194 prevWindow = mdiWindow;
195
196 MessageBoxDialogFiller *filler = new MessageBoxDialogFiller(os, QMessageBox::Discard);
197 GTUtilsDialog::waitForDialogWhichMayRunOrNot(os, filler);
198
199 if (!tabbedView) {
200 QPoint closeButtonPos = GTWidget::getWidgetGlobalTopLeftPoint(os, mdiWindow) + QPoint(10, 5);
201 GTMouseDriver::moveTo(closeButtonPos);
202 GTMouseDriver::click();
203 } else {
204 GTMenu::clickMainMenuItem(os, QStringList() << "Actions"
205 << "Close active view");
206 }
207 GTGlobals::sleep(100);
208 GTThread::waitForMainThread();
209 GTUtilsDialog::removeRunnable(filler);
210 }
211 #endif
212 }
213 #undef GT_METHOD_NAME
214
215 #define GT_METHOD_NAME "isTabbedLayout"
isTabbedLayout(HI::GUITestOpStatus & os)216 bool GTUtilsMdi::isTabbedLayout(HI::GUITestOpStatus &os) {
217 MainWindow *mainWindow = AppContext::getMainWindow();
218 GT_CHECK_RESULT(mainWindow != nullptr, "MainWindow == NULL", false);
219 QMdiArea *mdiArea = GTWidget::findExactWidget<QMdiArea *>(os, "MDI_Area", mainWindow->getQMainWindow());
220 GT_CHECK_RESULT(mdiArea != nullptr, "mdiArea == NULL", false);
221 return mdiArea->viewMode() == QMdiArea::TabbedView;
222 }
223 #undef GT_METHOD_NAME
224
225 #define GT_METHOD_NAME "activeWindow"
activeWindow(HI::GUITestOpStatus & os,const GTGlobals::FindOptions & options)226 QWidget *GTUtilsMdi::activeWindow(HI::GUITestOpStatus &os, const GTGlobals::FindOptions &options) {
227 MainWindow *mw = AppContext::getMainWindow();
228 GT_CHECK_RESULT(mw != nullptr, "MainWindow == NULL", nullptr);
229
230 QWidget *w = mw->getMDIManager()->getActiveWindow();
231 if (options.failIfNotFound) {
232 GT_CHECK_RESULT(w != nullptr, "Active window is not found", nullptr);
233 }
234 return w;
235 }
236 #undef GT_METHOD_NAME
237
getActiveMdiWindowTitle()238 static QString getActiveMdiWindowTitle() {
239 MainWindow *mainWindow = AppContext::getMainWindow();
240 QWidget *mdiWindow = mainWindow == nullptr ? nullptr : mainWindow->getMDIManager()->getActiveWindow();
241 return mdiWindow == nullptr ? "<no active window>" : mdiWindow->windowTitle();
242 }
243
244 #define GT_METHOD_NAME "getActiveObjectViewWindow"
getActiveObjectViewWindow(GUITestOpStatus & os,const QString & viewId)245 QWidget *GTUtilsMdi::getActiveObjectViewWindow(GUITestOpStatus &os, const QString &viewId) {
246 GObjectViewWindow *viewWindow = nullptr;
247 for (int time = 0; time < GT_OP_WAIT_MILLIS && viewWindow == nullptr; time += GT_OP_CHECK_MILLIS) {
248 GTGlobals::sleep(time > 0 ? GT_OP_CHECK_MILLIS : 0);
249 MainWindow *mainWindow = AppContext::getMainWindow();
250 QWidget *mdiWindow = mainWindow == nullptr ? nullptr : mainWindow->getMDIManager()->getActiveWindow();
251 if (mdiWindow == nullptr) {
252 continue;
253 }
254 GObjectViewWindow *activeViewWindow = qobject_cast<GObjectViewWindow *>(mdiWindow);
255 if (activeViewWindow != nullptr && activeViewWindow->getViewFactoryId() == viewId) {
256 viewWindow = activeViewWindow;
257 }
258 }
259 GT_CHECK_RESULT(viewWindow != nullptr, "View window is not found: " + viewId + ", active window: " + getActiveMdiWindowTitle(), nullptr);
260 return viewWindow;
261 }
262 #undef GT_METHOD_NAME
263
264 #define GT_METHOD_NAME "checkNoObjectViewWindowIsOpened"
checkNoObjectViewWindowIsOpened(GUITestOpStatus & os,const QString & viewId)265 void GTUtilsMdi::checkNoObjectViewWindowIsOpened(GUITestOpStatus &os, const QString &viewId) {
266 QList<QWidget *> allWindows = getAllObjectViewWindows(viewId);
267 for (int time = 0; time < GT_OP_WAIT_MILLIS && !allWindows.isEmpty(); time += GT_OP_CHECK_MILLIS) {
268 GTGlobals::sleep(time > 0 ? GT_OP_CHECK_MILLIS : 0);
269 allWindows = getAllObjectViewWindows(viewId);
270 }
271 GT_CHECK(allWindows.isEmpty(), "Found object view windows: " + viewId + ", when expected no window to be present");
272 GTThread::waitForMainThread();
273 }
274 #undef GT_METHOD_NAME
275
276 #define GT_METHOD_NAME "getAllObjectViewWindows"
getAllObjectViewWindows(const QString & viewId)277 QList<QWidget *> GTUtilsMdi::getAllObjectViewWindows(const QString &viewId) {
278 MainWindow *mainWindow = AppContext::getMainWindow();
279 QList<QWidget *> result;
280 if (mainWindow != nullptr) {
281 foreach (QWidget *window, mainWindow->getMDIManager()->getWindows()) {
282 GObjectViewWindow *objectViewWindow = qobject_cast<GObjectViewWindow *>(window);
283 if (objectViewWindow != nullptr && objectViewWindow->getViewFactoryId() == viewId) {
284 result << objectViewWindow;
285 }
286 }
287 }
288 return result;
289 }
290 #undef GT_METHOD_NAME
291
292 #define GT_METHOD_NAME "activeWindowTitle"
activeWindowTitle(HI::GUITestOpStatus & os)293 QString GTUtilsMdi::activeWindowTitle(HI::GUITestOpStatus &os) {
294 QWidget *w = activeWindow(os);
295 MWMDIWindow *mdi = qobject_cast<MWMDIWindow *>(w);
296 GT_CHECK_RESULT(mdi, "unexpected object type", QString());
297 return mdi->windowTitle();
298 }
299 #undef GT_METHOD_NAME
300
301 #define GT_METHOD_NAME "activateWindow"
activateWindow(HI::GUITestOpStatus & os,const QString & windowTitlePart)302 void GTUtilsMdi::activateWindow(HI::GUITestOpStatus &os, const QString &windowTitlePart) {
303 MainWindow *mainWindow = AppContext::getMainWindow();
304
305 GT_CHECK(mainWindow != nullptr, "MainWindow == nullptr");
306 CHECK(!activeWindowTitle(os).contains(windowTitlePart, Qt::CaseInsensitive), );
307
308 GTGlobals::FindOptions options;
309 options.matchPolicy = Qt::MatchContains;
310 QWidget *window = findWindow(os, windowTitlePart, options);
311
312 GTMenu::clickMainMenuItem(os, QStringList() << "Window" << window->windowTitle(), GTGlobals::UseMouse, Qt::MatchContains);
313 GTThread::waitForMainThread();
314 }
315 #undef GT_METHOD_NAME
316
317 #define GT_METHOD_NAME "checkWindowIsActive"
checkWindowIsActive(HI::GUITestOpStatus & os,const QString & windowTitlePart)318 QWidget *GTUtilsMdi::checkWindowIsActive(HI::GUITestOpStatus &os, const QString &windowTitlePart) {
319 GT_CHECK_RESULT(!windowTitlePart.isEmpty(), "windowTitlePart is empty", nullptr);
320
321 MainWindow *mainWindow = AppContext::getMainWindow();
322 GT_CHECK_RESULT(mainWindow != nullptr, "MainWindow == nullptr", nullptr);
323
324 QWidget *window = nullptr;
325 for (int time = 0; time < GT_OP_WAIT_MILLIS && window == nullptr; time += GT_OP_CHECK_MILLIS) {
326 GTGlobals::sleep(time > 0 ? GT_OP_CHECK_MILLIS : 0);
327 QWidget *activeWindow = mainWindow->getMDIManager()->getActiveWindow();
328 if (activeWindow->windowTitle().contains(windowTitlePart, Qt::CaseInsensitive)) {
329 window = activeWindow;
330 }
331 }
332 GT_CHECK_RESULT(window != nullptr, "Window with title part '" + windowTitlePart + "' is not found", nullptr);
333 GTThread::waitForMainThread();
334 return window;
335 }
336 #undef GT_METHOD_NAME
337
338 #define GT_METHOD_NAME "getMdiItemPosition"
getMdiItemPosition(HI::GUITestOpStatus & os,const QString & windowName)339 QPoint GTUtilsMdi::getMdiItemPosition(HI::GUITestOpStatus &os, const QString &windowName) {
340 QWidget *w = findWindow(os, windowName);
341 GT_CHECK_RESULT(w != nullptr, "MDI window not found", QPoint());
342 const QRect r = w->rect();
343 return w->mapToGlobal(r.center());
344 }
345 #undef GT_METHOD_NAME
346
347 #define GT_METHOD_NAME "selectRandomRegion"
selectRandomRegion(HI::GUITestOpStatus & os,const QString & windowName)348 void GTUtilsMdi::selectRandomRegion(HI::GUITestOpStatus &os, const QString &windowName) {
349 QWidget *w = findWindow(os, windowName);
350 GT_CHECK(w != nullptr, "MDI window not found");
351 const QRect r = w->rect();
352 QPoint p = QPoint((r.topLeft().x() + r.bottomLeft().x()) / 2 + 5, r.center().y() / 2);
353 GTMouseDriver::moveTo(w->mapToGlobal(p));
354 GTMouseDriver::press();
355 GTMouseDriver::moveTo(w->mapToGlobal(r.center()));
356 GTMouseDriver::release();
357 GTThread::waitForMainThread();
358 }
359 #undef GT_METHOD_NAME
360
361 namespace {
362
isWidgetPartVisible(QWidget * widget)363 bool isWidgetPartVisible(QWidget *widget) {
364 CHECK(nullptr != widget, false);
365
366 if (!widget->visibleRegion().isEmpty()) {
367 return true;
368 }
369
370 foreach (QObject *child, widget->children()) {
371 if (child->isWidgetType() && isWidgetPartVisible(qobject_cast<QWidget *>(child))) {
372 return true;
373 }
374 }
375
376 return false;
377 }
378
379 } // namespace
380
381 #define GT_METHOD_NAME "isAnyPartOfWindowVisible"
isAnyPartOfWindowVisible(HI::GUITestOpStatus & os,const QString & windowName)382 bool GTUtilsMdi::isAnyPartOfWindowVisible(HI::GUITestOpStatus &os, const QString &windowName) {
383 GTGlobals::FindOptions options;
384 options.failIfNotFound = false;
385 QWidget *window = findWindow(os, windowName, options);
386 CHECK(nullptr != window, false);
387 return isWidgetPartVisible(window);
388 }
389 #undef GT_METHOD_NAME
390
391 #define GT_METHOD_NAME "getTabBar"
getTabBar(HI::GUITestOpStatus & os)392 QTabBar *GTUtilsMdi::getTabBar(HI::GUITestOpStatus &os) {
393 MainWindow *mainWindow = AppContext::getMainWindow();
394 GT_CHECK_RESULT(mainWindow != nullptr, "MainWindow == nullptr", nullptr);
395
396 QMdiArea *mdiArea = GTWidget::findExactWidget<QMdiArea *>(os, "MDI_Area", mainWindow->getQMainWindow());
397 GT_CHECK_RESULT(mdiArea != nullptr, "mdiArea == nullptr", nullptr);
398
399 QTabBar *tabBar = mdiArea->findChild<QTabBar *>("", Qt::FindDirectChildrenOnly);
400 GT_CHECK_RESULT(tabBar != nullptr, "MDI tabbar not found", nullptr);
401
402 return tabBar;
403 }
404 #undef GT_METHOD_NAME
405
406 #define GT_METHOD_NAME "getTabBar"
getCurrentTab(HI::GUITestOpStatus & os)407 int GTUtilsMdi::getCurrentTab(HI::GUITestOpStatus &os) {
408 QTabBar *tabBar = getTabBar(os);
409 GT_CHECK_RESULT(tabBar != nullptr, "tabBar == NULL", -1);
410
411 return tabBar->currentIndex();
412 }
413 #undef GT_METHOD_NAME
414
415 #define GT_METHOD_NAME "clickTab"
clickTab(HI::GUITestOpStatus & os,int tabIndex)416 void GTUtilsMdi::clickTab(HI::GUITestOpStatus &os, int tabIndex) {
417 QTabBar *tabBar = getTabBar(os);
418 GT_CHECK_RESULT(tabBar != nullptr, "tabBar == NULL", );
419
420 coreLog.info(QString("Try to click tab %1(%2)").arg(tabIndex).arg(tabBar->tabText(tabIndex)));
421 QPoint tabCenter = tabBar->mapToGlobal(tabBar->tabRect(tabIndex).center());
422 GTMouseDriver::moveTo(tabCenter);
423 GTMouseDriver::click();
424 }
425 #undef GT_METHOD_NAME
426
427 #undef GT_CLASS_NAME
428
429 } // namespace U2
430