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 <GTGlobals.h>
23 #include <drivers/GTKeyboardDriver.h>
24 #include <drivers/GTMouseDriver.h>
25 #include <primitives/GTAction.h>
26 #include <primitives/GTLineEdit.h>
27 #include <primitives/GTMenu.h>
28 #include <primitives/GTToolbar.h>
29 #include <primitives/PopupChooser.h>
30 #include <system/GTClipboard.h>
31 #include <utils/GTKeyboardUtils.h>
32 #include <utils/GTThread.h>
33 
34 #include <QApplication>
35 #include <QClipboard>
36 #include <QDialogButtonBox>
37 #include <QPlainTextEdit>
38 #include <QPushButton>
39 
40 #include <U2Core/AnnotationSettings.h>
41 #include <U2Core/AppContext.h>
42 #include <U2Core/DNASequenceSelection.h>
43 #include <U2Core/U1AnnotationUtils.h>
44 
45 #include <U2Gui/MainWindow.h>
46 
47 #include <U2View/ADVConstants.h>
48 #include <U2View/ADVSequenceObjectContext.h>
49 #include <U2View/ADVSingleSequenceWidget.h>
50 #include <U2View/AnnotatedDNAViewFactory.h>
51 #include <U2View/DetView.h>
52 #include <U2View/DetViewRenderer.h>
53 #include <U2View/DetViewSequenceEditor.h>
54 #include <U2View/GSequenceGraphView.h>
55 #include <U2View/Overview.h>
56 
57 #include "GTUtilsMdi.h"
58 #include "GTUtilsProjectTreeView.h"
59 #include "GTUtilsSequenceView.h"
60 #include "runnables/ugene/corelibs/U2Gui/RangeSelectionDialogFiller.h"
61 #include "utils/GTUtilsDialog.h"
62 
63 namespace U2 {
64 using namespace HI;
65 
66 #define GT_CLASS_NAME "GTSequenceReader"
67 #define GT_METHOD_NAME "commonScenario"
68 class GTSequenceReader : public Filler {
69 public:
GTSequenceReader(HI::GUITestOpStatus & _os,QString * _str)70     GTSequenceReader(HI::GUITestOpStatus &_os, QString *_str)
71         : Filler(_os, "EditSequenceDialog"), str(_str) {
72     }
commonScenario()73     void commonScenario() {
74         QWidget *widget = QApplication::activeModalWidget();
75         GT_CHECK(widget != nullptr, "active widget not found");
76 
77         QPlainTextEdit *textEdit = widget->findChild<QPlainTextEdit *>();
78         GT_CHECK(textEdit != nullptr, "PlainTextEdit not found");
79 
80         *str = textEdit->toPlainText();
81 
82         QDialogButtonBox *box = qobject_cast<QDialogButtonBox *>(GTWidget::findWidget(os, "buttonBox", widget));
83         GT_CHECK(box != nullptr, "buttonBox is NULL");
84         QPushButton *button = box->button(QDialogButtonBox::Cancel);
85         GT_CHECK(button != nullptr, "cancel button is NULL");
86         GTWidget::click(os, button);
87     }
88 
89 private:
90     QString *str;
91 };
92 #undef GT_METHOD_NAME
93 #undef GT_CLASS_NAME
94 
95 #define GT_CLASS_NAME "GTUtilsSequenceView"
96 
97 #define GT_METHOD_NAME "getActiveSequenceViewWindow"
getActiveSequenceViewWindow(GUITestOpStatus & os)98 QWidget *GTUtilsSequenceView::getActiveSequenceViewWindow(GUITestOpStatus &os) {
99     QWidget *widget = GTUtilsMdi::getActiveObjectViewWindow(os, AnnotatedDNAViewFactory::ID);
100     GTThread::waitForMainThread();
101     return widget;
102 }
103 #undef GT_METHOD_NAME
104 
105 #define GT_METHOD_NAME "checkSequenceViewWindowIsActive"
checkSequenceViewWindowIsActive(GUITestOpStatus & os)106 void GTUtilsSequenceView::checkSequenceViewWindowIsActive(GUITestOpStatus &os) {
107     getActiveSequenceViewWindow(os);
108 }
109 #undef GT_METHOD_NAME
110 
111 #define GT_METHOD_NAME "checkNoSequenceViewWindowIsOpened"
checkNoSequenceViewWindowIsOpened(GUITestOpStatus & os)112 void GTUtilsSequenceView::checkNoSequenceViewWindowIsOpened(GUITestOpStatus &os) {
113     GTUtilsMdi::checkNoObjectViewWindowIsOpened(os, AnnotatedDNAViewFactory::ID);
114 }
115 #undef GT_METHOD_NAME
116 
117 #define GT_METHOD_NAME "getSequenceAsString"
getSequenceAsString(HI::GUITestOpStatus & os,QString & sequence)118 void GTUtilsSequenceView::getSequenceAsString(HI::GUITestOpStatus &os, QString &sequence) {
119     QWidget *sequenceWidget = getPanOrDetView(os);
120     GTWidget::click(os, sequenceWidget);
121 
122     GTUtilsDialog::waitForDialog(os, new SelectSequenceRegionDialogFiller(os));
123     GTKeyboardUtils::selectAll();
124     GTUtilsDialog::waitAllFinished(os);
125 
126     GTUtilsDialog::waitForDialog(os, new PopupChooser(os, QStringList() << ADV_MENU_EDIT << ACTION_EDIT_REPLACE_SUBSEQUENCE, GTGlobals::UseKey));
127     GTUtilsDialog::waitForDialog(os, new GTSequenceReader(os, &sequence));
128     GTMenu::showContextMenu(os, sequenceWidget);
129     GTUtilsDialog::waitAllFinished(os);
130 }
131 #undef GT_METHOD_NAME
132 
133 #define GT_METHOD_NAME "getSequenceAsString"
getSequenceAsString(HI::GUITestOpStatus & os,int number)134 QString GTUtilsSequenceView::getSequenceAsString(HI::GUITestOpStatus &os, int number) {
135     getActiveSequenceViewWindow(os);
136     GTWidget::click(os, getSeqWidgetByNumber(os, number));
137 
138     GTUtilsDialog::waitForDialog(os, new SelectSequenceRegionDialogFiller(os));
139     GTKeyboardUtils::selectAll();
140     GTGlobals::sleep(500);
141     GTUtilsDialog::waitForDialog(os, new PopupChooser(os, QStringList() << ADV_MENU_COPY << "Copy sequence"));
142     // Use PanView or DetView but not the sequence widget itself: there are internal scrollbars in the SequenceWidget that may affect popup menu content.
143     QWidget *panOrDetView = getDetViewByNumber(os, number, GTGlobals::FindOptions(false));
144     if (panOrDetView == nullptr) {
145         panOrDetView = getPanViewByNumber(os, number);
146     }
147     GTWidget::click(os, panOrDetView, Qt::RightButton);
148     QString result = GTClipboard::text(os);
149     return result;
150 }
151 #undef GT_METHOD_NAME
152 
153 #define GT_METHOD_NAME "getBeginOfSequenceAsString"
154 
getBeginOfSequenceAsString(HI::GUITestOpStatus & os,int length)155 QString GTUtilsSequenceView::getBeginOfSequenceAsString(HI::GUITestOpStatus &os, int length) {
156     checkSequenceViewWindowIsActive(os);
157     GTUtilsDialog::waitForDialog(os, new SelectSequenceRegionDialogFiller(os, length));
158     GTKeyboardUtils::selectAll();
159     GTThread::waitForMainThread();
160 
161     QString sequence;
162     GTUtilsDialog::waitForDialog(os, new PopupChooser(os, QStringList() << ADV_MENU_EDIT << ACTION_EDIT_REPLACE_SUBSEQUENCE, GTGlobals::UseKey));
163     GTUtilsDialog::waitForDialog(os, new GTSequenceReader(os, &sequence));
164     openPopupMenuOnSequenceViewArea(os);
165     GTUtilsDialog::waitAllFinished(os);
166 
167     return sequence;
168 }
169 #undef GT_METHOD_NAME
170 
171 #define GT_METHOD_NAME "getEndOfSequenceAsString"
getEndOfSequenceAsString(HI::GUITestOpStatus & os,int length)172 QString GTUtilsSequenceView::getEndOfSequenceAsString(HI::GUITestOpStatus &os, int length) {
173     QWidget *mdiWindow = getActiveSequenceViewWindow(os);
174     GTMouseDriver::moveTo(mdiWindow->mapToGlobal(mdiWindow->rect().center()));
175     GTMouseDriver::click();
176 
177     Runnable *filler = new SelectSequenceRegionDialogFiller(os, length, false);
178     GTUtilsDialog::waitForDialog(os, filler);
179 
180     GTKeyboardUtils::selectAll();
181     GTGlobals::sleep(1000);
182     GTGlobals::sleep(1000);  // don't touch
183 
184     QString sequence;
185     Runnable *chooser = new PopupChooser(os, QStringList() << ADV_MENU_EDIT << ACTION_EDIT_REPLACE_SUBSEQUENCE, GTGlobals::UseKey);
186     GTUtilsDialog::waitForDialog(os, chooser);
187     Runnable *reader = new GTSequenceReader(os, &sequence);
188     GTUtilsDialog::waitForDialog(os, reader);
189 
190     GTMenu::showContextMenu(os, mdiWindow);
191     GTGlobals::sleep(1000);
192 
193     return sequence;
194 }
195 #undef GT_METHOD_NAME
196 
197 #define GT_METHOD_NAME "getLengthOfSequence"
getLengthOfSequence(HI::GUITestOpStatus & os)198 int GTUtilsSequenceView::getLengthOfSequence(HI::GUITestOpStatus &os) {
199     MainWindow *mw = AppContext::getMainWindow();
200     GT_CHECK_RESULT(mw != nullptr, "MainWindow == NULL", 0);
201 
202     MWMDIWindow *mdiWindow = mw->getMDIManager()->getActiveWindow();
203     GT_CHECK_RESULT(mdiWindow != nullptr, "MDI window == NULL", 0);
204 
205     GTGlobals::sleep();
206 
207     GTMouseDriver::moveTo(mdiWindow->mapToGlobal(mdiWindow->rect().center()));
208     GTMouseDriver::click();
209 
210     int length = -1;
211     GTUtilsDialog::waitForDialog(os, new SelectSequenceRegionDialogFiller(os, &length));
212     GTKeyboardUtils::selectAll();
213     GTGlobals::sleep(1000);
214 
215     return length;
216 }
217 #undef GT_METHOD_NAME
218 
getVisibleStart(HI::GUITestOpStatus & os,int widgetNumber)219 int GTUtilsSequenceView::getVisibleStart(HI::GUITestOpStatus &os, int widgetNumber) {
220     return getSeqWidgetByNumber(os, widgetNumber)->getDetView()->getVisibleRange().startPos;
221 }
222 
223 #define GT_METHOD_NAME "getVisibleRange"
getVisibleRange(HI::GUITestOpStatus & os,int widgetNumber)224 U2Region GTUtilsSequenceView::getVisibleRange(HI::GUITestOpStatus &os, int widgetNumber) {
225     ADVSingleSequenceWidget *seqWgt = getSeqWidgetByNumber(os, widgetNumber);
226     GT_CHECK_RESULT(seqWgt != nullptr, "Cannot find sequence view", U2Region());
227     return seqWgt->getDetView()->getVisibleRange();
228 }
229 #undef GT_METHOD_NAME
230 
231 #define GT_METHOD_NAME "checkSequence"
checkSequence(HI::GUITestOpStatus & os,const QString & expectedSequence)232 void GTUtilsSequenceView::checkSequence(HI::GUITestOpStatus &os, const QString &expectedSequence) {
233     QString actualSequence;
234     getSequenceAsString(os, actualSequence);
235 
236     GT_CHECK(expectedSequence == actualSequence, "Actual sequence does not match with expected sequence");
237 }
238 #undef GT_METHOD_NAME
239 
240 #define GT_METHOD_NAME "selectSequenceRegion"
selectSequenceRegion(HI::GUITestOpStatus & os,int from,int to)241 void GTUtilsSequenceView::selectSequenceRegion(HI::GUITestOpStatus &os, int from, int to) {
242     GTUtilsDialog::waitForDialog(os, new SelectSequenceRegionDialogFiller(os, from, to));
243     clickMouseOnTheSafeSequenceViewArea(os);
244     GTKeyboardUtils::selectAll();
245 }
246 #undef GT_METHOD_NAME
247 
248 #define GT_METHOD_NAME "selectSeveralRegionsByDialog"
selectSeveralRegionsByDialog(HI::GUITestOpStatus & os,const QString & multipleRangeString)249 void GTUtilsSequenceView::selectSeveralRegionsByDialog(HI::GUITestOpStatus &os, const QString &multipleRangeString) {
250     GTUtilsDialog::waitForDialog(os, new SelectSequenceRegionDialogFiller(os, multipleRangeString));
251     clickMouseOnTheSafeSequenceViewArea(os);
252     GTKeyboardUtils::selectAll();
253 }
254 #undef GT_METHOD_NAME
255 
256 #define GT_METHOD_NAME "openSequenceView"
openSequenceView(HI::GUITestOpStatus & os,const QString & sequenceName)257 void GTUtilsSequenceView::openSequenceView(HI::GUITestOpStatus &os, const QString &sequenceName) {
258     GTUtilsDialog::waitForDialog(os, new PopupChooser(os, QStringList() << "Open View"
259                                                                         << "action_open_view",
260                                                       GTGlobals::UseMouse));
261 
262     QPoint itemPos = GTUtilsProjectTreeView::getItemCenter(os, sequenceName);
263     GTMouseDriver::moveTo(itemPos);
264     GTMouseDriver::click(Qt::RightButton);
265 }
266 #undef GT_METHOD_NAME
267 
268 #define GT_METHOD_NAME "addSequenceView"
addSequenceView(HI::GUITestOpStatus & os,const QString & sequenceName)269 void GTUtilsSequenceView::addSequenceView(HI::GUITestOpStatus &os, const QString &sequenceName) {
270     GTUtilsDialog::waitForDialog(os, new PopupChooser(os, QStringList() << "submenu_add_view"
271                                                                         << "action_add_view",
272                                                       GTGlobals::UseMouse));
273 
274     QPoint itemPos = GTUtilsProjectTreeView::getItemCenter(os, sequenceName);
275     GTMouseDriver::moveTo(itemPos);
276     GTMouseDriver::click(Qt::RightButton);
277 }
278 #undef GT_METHOD_NAME
279 
280 #define GT_METHOD_NAME "goToPosition"
goToPosition(HI::GUITestOpStatus & os,qint64 position)281 void GTUtilsSequenceView::goToPosition(HI::GUITestOpStatus &os, qint64 position) {
282     QToolBar *toolbar = GTToolbar::getToolbar(os, MWTOOLBAR_ACTIVEMDI);
283     GT_CHECK(nullptr != toolbar, "Can't find the toolbar");
284 
285     QLineEdit *positionLineEdit = GTWidget::findExactWidget<QLineEdit *>(os, "go_to_pos_line_edit", toolbar);
286     GT_CHECK(nullptr != positionLineEdit, "Can't find the position line edit");
287 
288     GTLineEdit::setText(os, positionLineEdit, QString::number(position));
289     GTKeyboardDriver::keyClick(Qt::Key_Enter);
290 }
291 #undef GT_METHOD_NAME
292 
293 #define GT_METHOD_NAME "clickMouseOnTheSafeSequenceViewArea"
clickMouseOnTheSafeSequenceViewArea(HI::GUITestOpStatus & os)294 void GTUtilsSequenceView::clickMouseOnTheSafeSequenceViewArea(HI::GUITestOpStatus &os) {
295     QWidget *panOrDetView = getPanOrDetView(os);
296     GT_CHECK(panOrDetView != nullptr, "No pan or det-view found!");
297     GTMouseDriver::moveTo(panOrDetView->mapToGlobal(panOrDetView->rect().center()));
298     GTMouseDriver::click();
299 }
300 #undef GT_METHOD_NAME
301 
302 #define GT_METHOD_NAME "clickMouseOnTheSafeSequenceViewArea"
openPopupMenuOnSequenceViewArea(HI::GUITestOpStatus & os,int number)303 void GTUtilsSequenceView::openPopupMenuOnSequenceViewArea(HI::GUITestOpStatus &os, int number) {
304     QWidget *panOrDetView = getPanOrDetView(os, number);
305     GT_CHECK(panOrDetView != nullptr, "No pan or det-view found!");
306     GTWidget::click(os, panOrDetView, Qt::RightButton);
307 }
308 #undef GT_METHOD_NAME
309 
310 #define GT_METHOD_NAME "getPanOrDetView"
getPanOrDetView(HI::GUITestOpStatus & os,int number)311 QWidget *GTUtilsSequenceView::getPanOrDetView(HI::GUITestOpStatus &os, int number) {
312     QWidget *panOrDetView = getDetViewByNumber(os, number, GTGlobals::FindOptions(false));
313     if (panOrDetView == nullptr) {
314         panOrDetView = getPanViewByNumber(os, number);
315     }
316     return panOrDetView;
317 }
318 #undef GT_METHOD_NAME
319 
320 #define GT_METHOD_NAME "getSeqWidgetByNumber"
getSeqWidgetByNumber(HI::GUITestOpStatus & os,int number,const GTGlobals::FindOptions & options)321 ADVSingleSequenceWidget *GTUtilsSequenceView::getSeqWidgetByNumber(HI::GUITestOpStatus &os, int number, const GTGlobals::FindOptions &options) {
322     QWidget *widget = GTWidget::findWidget(os,
323                                            QString("ADV_single_sequence_widget_%1").arg(number),
324                                            getActiveSequenceViewWindow(os),
325                                            options);
326 
327     ADVSingleSequenceWidget *seqWidget = qobject_cast<ADVSingleSequenceWidget *>(widget);
328 
329     if (options.failIfNotFound) {
330         GT_CHECK_RESULT(widget != nullptr, QString("Sequence widget %1 was not found!").arg(number), nullptr);
331     }
332 
333     return seqWidget;
334 }
335 #undef GT_METHOD_NAME
336 
337 #define GT_METHOD_NAME "getDetViewByNumber"
getDetViewByNumber(HI::GUITestOpStatus & os,int number,const GTGlobals::FindOptions & options)338 DetView *GTUtilsSequenceView::getDetViewByNumber(HI::GUITestOpStatus &os, int number, const GTGlobals::FindOptions &options) {
339     ADVSingleSequenceWidget *seq = getSeqWidgetByNumber(os, number, options);
340     if (options.failIfNotFound) {
341         GT_CHECK_RESULT(seq != nullptr, QString("sequence view with num %1 not found").arg(number), nullptr);
342     } else {
343         return nullptr;
344     }
345 
346     DetView *result = seq->findChild<DetView *>();
347     if (options.failIfNotFound) {
348         GT_CHECK_RESULT(result != nullptr, QString("det view with number %1 not found").arg(number), nullptr);
349     }
350     return result;
351 }
352 #undef GT_METHOD_NAME
353 
354 #define GT_METHOD_NAME "getPanViewByNumber"
getPanViewByNumber(HI::GUITestOpStatus & os,int number,const GTGlobals::FindOptions & options)355 PanView *GTUtilsSequenceView::getPanViewByNumber(HI::GUITestOpStatus &os, int number, const GTGlobals::FindOptions &options) {
356     ADVSingleSequenceWidget *seq = getSeqWidgetByNumber(os, number, options);
357     if (options.failIfNotFound) {
358         GT_CHECK_RESULT(seq != nullptr, QString("sequence view with num %1 not found").arg(number), nullptr);
359     } else {
360         return nullptr;
361     }
362 
363     PanView *result = seq->findChild<PanView *>();
364     if (options.failIfNotFound) {
365         GT_CHECK_RESULT(seq != nullptr, QString("pan view with number %1 not found").arg(number), nullptr)
366     }
367 
368     return result;
369 }
370 #undef GT_METHOD_NAME
371 
372 #define GT_METHOD_NAME "getOverViewByNumber"
getOverviewByNumber(HI::GUITestOpStatus & os,int number,const GTGlobals::FindOptions & options)373 Overview *GTUtilsSequenceView::getOverviewByNumber(HI::GUITestOpStatus &os, int number, const GTGlobals::FindOptions &options) {
374     ADVSingleSequenceWidget *seq = getSeqWidgetByNumber(os, number, options);
375     if (options.failIfNotFound) {
376         GT_CHECK_RESULT(seq != nullptr, QString("sequence view with num %1 not found").arg(number), nullptr);
377     } else {
378         return nullptr;
379     }
380 
381     Overview *result = seq->findChild<Overview *>();
382     if (options.failIfNotFound) {
383         GT_CHECK_RESULT(seq != nullptr, QString("pan view with number %1 not found").arg(number), nullptr)
384     }
385 
386     return result;
387 }
388 #undef GT_METHOD_NAME
389 
390 #define GT_METHOD_NAME "getSeqWidgetsNumber"
getSeqWidgetsNumber(HI::GUITestOpStatus & os)391 int GTUtilsSequenceView::getSeqWidgetsNumber(HI::GUITestOpStatus &os) {
392     QList<ADVSingleSequenceWidget *> seqWidgets = getActiveSequenceViewWindow(os)->findChildren<ADVSingleSequenceWidget *>();
393     return seqWidgets.size();
394 }
395 #undef GT_METHOD_NAME
396 
getSelection(HI::GUITestOpStatus & os,int number)397 QVector<U2Region> GTUtilsSequenceView::getSelection(HI::GUITestOpStatus &os, int number) {
398     PanView *panView = getPanViewByNumber(os, number);
399     QVector<U2Region> result = panView->getSequenceContext()->getSequenceSelection()->getSelectedRegions();
400     return result;
401 }
402 
403 #define GT_METHOD_NAME "getSeqName"
getSeqName(HI::GUITestOpStatus & os,int number)404 QString GTUtilsSequenceView::getSeqName(HI::GUITestOpStatus &os, int number) {
405     return getSeqName(os, getSeqWidgetByNumber(os, number));
406 }
407 #undef GT_METHOD_NAME
408 
409 #define GT_METHOD_NAME "getSeqName"
getSeqName(HI::GUITestOpStatus & os,ADVSingleSequenceWidget * seqWidget)410 QString GTUtilsSequenceView::getSeqName(HI::GUITestOpStatus &os, ADVSingleSequenceWidget *seqWidget) {
411     GT_CHECK_RESULT(nullptr != seqWidget, "Sequence widget is NULL!", "");
412     QLabel *nameLabel = qobject_cast<QLabel *>(GTWidget::findWidget(os, "nameLabel", seqWidget));
413     GT_CHECK_RESULT(nullptr != nameLabel, "Name label is NULL!", "");
414 
415     QString labelText = nameLabel->text();
416     QString result = labelText.left(labelText.indexOf("[") - 1);  // detachment of name from label text
417     return result;
418 }
419 #undef GT_METHOD_NAME
420 
421 #define MIN_ANNOTATION_WIDTH 5
422 
423 #define GT_METHOD_NAME "clickAnnotationDet"
clickAnnotationDet(HI::GUITestOpStatus & os,const QString & annotationName,int annotationRegionStartPos,int sequenceWidgetIndex,const bool isDoubleClick,Qt::MouseButton button)424 void GTUtilsSequenceView::clickAnnotationDet(HI::GUITestOpStatus &os, const QString &annotationName, int annotationRegionStartPos, int sequenceWidgetIndex, const bool isDoubleClick, Qt::MouseButton button) {
425     ADVSingleSequenceWidget *sequenceView = getSeqWidgetByNumber(os, sequenceWidgetIndex);
426     DetView *detView = sequenceView->getDetView();
427     GT_CHECK(detView != nullptr, "detView not found");
428     auto renderArea = qobject_cast<DetViewRenderArea *>(detView->getRenderArea());
429     GT_CHECK(renderArea != nullptr, "detView render area not found");
430 
431     QList<Annotation *> selectedAnnotationList;
432     const QSet<AnnotationTableObject *> annotationObjectSet = sequenceView->getSequenceContext()->getAnnotationObjects(true);
433     for (const AnnotationTableObject *ao : qAsConst(annotationObjectSet)) {
434         for (Annotation *a : ao->getAnnotations()) {
435             QVector<U2Region> regions = a->getLocation()->regions;
436             for (const U2Region &r : qAsConst(regions)) {
437                 if (a->getName() == annotationName && r.startPos == annotationRegionStartPos - 1) {
438                     selectedAnnotationList << a;
439                 }
440             }
441         }
442     }
443     GT_CHECK(selectedAnnotationList.size() != 0, QString("Annotation with annotationName %1 and startPos %2").arg(annotationName).arg(annotationRegionStartPos));
444     GT_CHECK(selectedAnnotationList.size() == 1, QString("Several annotation with annotationName %1 and startPos %2. Number is: %3").arg(annotationName).arg(annotationRegionStartPos).arg(selectedAnnotationList.size()));
445 
446     Annotation *annotation = selectedAnnotationList.first();
447 
448     const SharedAnnotationData &aData = annotation->getData();
449     AnnotationSettingsRegistry *asr = AppContext::getAnnotationsSettingsRegistry();
450     AnnotationSettings *as = asr->getAnnotationSettings(aData);
451 
452     U2Region annotationRegion;
453     int annotationRegionIndex = 0;
454     const QVector<U2Region> regionList = annotation->getRegions();
455     for (const U2Region &reg : qAsConst(regionList)) {
456         if (reg.startPos == annotationRegionStartPos - 1) {
457             annotationRegion = reg;
458             break;
459         }
460         annotationRegionIndex++;
461     }
462     GT_CHECK(!annotationRegion.isEmpty(), "Region not found");
463 
464     if (!annotationRegion.intersects(detView->getVisibleRange())) {
465         int center = annotationRegion.center();
466         goToPosition(os, center);
467     }
468 
469     QList<U2Region> yRegionList = renderArea->getAnnotationYRegions(annotation, annotationRegionIndex, as);
470     GT_CHECK(!yRegionList.isEmpty(), "yRegionList is empty!");
471 
472     U2Region yRegion = yRegionList.first();
473     U2Region visibleRegion = detView->getVisibleRange();
474     U2Region annotationVisibleRegion = annotationRegion.intersect(visibleRegion);
475     int x1 = renderArea->posToCoord(annotationVisibleRegion.startPos, true);
476     int x2 = renderArea->posToCoord(annotationVisibleRegion.endPos() - 1, true) + renderArea->getCharWidth();
477     if (x2 <= x1) {  // In the wrap mode x2 may be on a different line. In this case use [x1...line-end] as the click region.
478         x2 = renderArea->width();
479     }
480 
481     const QRect clickRect(x1, yRegion.startPos, x2 - x1, yRegion.length);
482     GTMouseDriver::moveTo(renderArea->mapToGlobal(clickRect.center()));
483     if (isDoubleClick) {
484         GTMouseDriver::doubleClick();
485     } else {
486         GTMouseDriver::click(button);
487     }
488 }
489 #undef GT_METHOD_NAME
490 
491 #define GT_METHOD_NAME "clickAnnotationPan"
clickAnnotationPan(HI::GUITestOpStatus & os,QString name,int startPos,int number,const bool isDoubleClick,Qt::MouseButton button)492 void GTUtilsSequenceView::clickAnnotationPan(HI::GUITestOpStatus &os, QString name, int startPos, int number, const bool isDoubleClick, Qt::MouseButton button) {
493     ADVSingleSequenceWidget *seq = getSeqWidgetByNumber(os, number);
494     GSequenceLineViewRenderArea *area = seq->getPanView()->getRenderArea();
495     PanViewRenderArea *pan = dynamic_cast<PanViewRenderArea *>(area);
496     GT_CHECK(pan != nullptr, "pan view render area not found");
497 
498     ADVSequenceObjectContext *context = seq->getSequenceContext();
499     context->getAnnotationObjects(true);
500 
501     QList<Annotation *> anns;
502     foreach (const AnnotationTableObject *ao, context->getAnnotationObjects(true)) {
503         foreach (Annotation *a, ao->getAnnotations()) {
504             const int sp = a->getLocation().data()->regions.first().startPos;
505             const QString annName = a->getName();
506             if (sp == startPos - 1 && annName == name) {
507                 anns << a;
508             }
509         }
510     }
511     GT_CHECK(anns.size() != 0, QString("Annotation with name %1 and startPos %2").arg(name).arg(startPos));
512     GT_CHECK(anns.size() == 1, QString("Several annotation with name %1 and startPos %2. Number is: %3").arg(name).arg(startPos).arg(anns.size()));
513 
514     Annotation *a = anns.first();
515 
516     const SharedAnnotationData &aData = a->getData();
517     AnnotationSettingsRegistry *asr = AppContext::getAnnotationsSettingsRegistry();
518     AnnotationSettings *as = asr->getAnnotationSettings(aData);
519 
520     const U2Region &vr = seq->getPanView()->getVisibleRange();
521     QVector<U2Region> regions = a->getLocation().data()->regions;
522     const U2Region &r = regions.first();
523 
524     if (!r.intersects(vr)) {
525         int center = r.center();
526         goToPosition(os, center);
527         GTGlobals::sleep();
528     }
529 
530     const U2Region visibleLocation = r.intersect(vr);
531 
532     U2Region y = pan->getAnnotationYRange(a, 0, as);
533 
534     float start = visibleLocation.startPos;
535     float end = visibleLocation.endPos();
536     float x1f = (float)(start - vr.startPos) * pan->getCurrentScale();
537     float x2f = (float)(end - vr.startPos) * pan->getCurrentScale();
538 
539     int rw = qMax(MIN_ANNOTATION_WIDTH, qRound(x2f - x1f));
540     int x1 = qRound(x1f);
541 
542     const QRect annotationRect(x1, y.startPos, rw, y.length);
543     GTMouseDriver::moveTo(pan->mapToGlobal(annotationRect.center()));
544     if (isDoubleClick) {
545         GTMouseDriver::doubleClick();
546     } else {
547         GTMouseDriver::click(button);
548     }
549 }
550 #undef GT_METHOD_NAME
551 
552 #define GT_METHOD_NAME "getGraphView"
getGraphView(HI::GUITestOpStatus & os)553 GSequenceGraphView *GTUtilsSequenceView::getGraphView(HI::GUITestOpStatus &os) {
554     GSequenceGraphView *graph = getSeqWidgetByNumber(os)->findChild<GSequenceGraphView *>();
555     GT_CHECK_RESULT(graph != nullptr, "Graph view is NULL", nullptr);
556     return graph;
557 }
558 #undef GT_METHOD_NAME
559 
getLabelPositions(HI::GUITestOpStatus & os,GSequenceGraphView * graph)560 QList<QVariant> GTUtilsSequenceView::getLabelPositions(HI::GUITestOpStatus &os, GSequenceGraphView *graph) {
561     Q_UNUSED(os);
562     QList<QVariant> list;
563     graph->getSavedLabelsState(list);
564     return list;
565 }
566 
getGraphLabels(HI::GUITestOpStatus & os,GSequenceGraphView * graph)567 QList<GraphLabelTextBox *> GTUtilsSequenceView::getGraphLabels(HI::GUITestOpStatus &os, GSequenceGraphView *graph) {
568     Q_UNUSED(os);
569     QList<GraphLabelTextBox *> result = graph->findChildren<GraphLabelTextBox *>();
570     return result;
571 }
572 
getGraphColor(HI::GUITestOpStatus &,GSequenceGraphView * graph)573 QColor GTUtilsSequenceView::getGraphColor(HI::GUITestOpStatus & /*os*/, GSequenceGraphView *graph) {
574     ColorMap map = graph->getGraphDrawer()->getColors();
575     QColor result = map.value("Default color");
576     return result;
577 }
578 
579 #define GT_METHOD_NAME "toggleGraphByName"
toggleGraphByName(HI::GUITestOpStatus & os,const QString & graphName,int sequenceViewIndex)580 void GTUtilsSequenceView::toggleGraphByName(HI::GUITestOpStatus &os, const QString &graphName, int sequenceViewIndex) {
581     QWidget *sequenceWidget = getSeqWidgetByNumber(os, sequenceViewIndex);
582     QWidget *graphAction = GTWidget::findWidget(os, "GraphMenuAction", sequenceWidget, false);
583     GTUtilsDialog::waitForDialog(os, new PopupChooser(os, {graphName}));
584     GTWidget::click(os, graphAction);
585 }
586 #undef GT_METHOD_NAME
587 
588 #define GT_METHOD_NAME "zoomIn"
zoomIn(HI::GUITestOpStatus & os,int sequenceViewIndex)589 void GTUtilsSequenceView::zoomIn(HI::GUITestOpStatus &os, int sequenceViewIndex) {
590     QWidget *sequenceWidget = getSeqWidgetByNumber(os, sequenceViewIndex);
591     QAction *zoomInAction = GTAction::findActionByText(os, "Zoom In", sequenceWidget);
592     GTWidget::click(os, GTAction::button(os, zoomInAction));
593 }
594 #undef GT_METHOD_NAME
595 
596 #define GT_METHOD_NAME "enableEditingMode"
enableEditingMode(GUITestOpStatus & os,bool enable,int sequenceNumber)597 void GTUtilsSequenceView::enableEditingMode(GUITestOpStatus &os, bool enable, int sequenceNumber) {
598     DetView *detView = getDetViewByNumber(os, sequenceNumber);
599     CHECK_SET_ERR(detView != nullptr, "DetView is NULL");
600 
601     QToolBar *toolbar = GTWidget::findExactWidget<QToolBar *>(os, "", detView);
602     QToolButton *editButton = qobject_cast<QToolButton *>(GTToolbar::getWidgetForActionObjectName(os, toolbar, "edit_sequence_action"));
603     CHECK_SET_ERR(nullptr != editButton, "'edit_sequence_action' button is NULL");
604     if (editButton->isChecked() != enable) {
605         if (editButton->isVisible()) {
606             GTWidget::click(os, editButton);
607         } else {
608             const QPoint gp = detView->mapToGlobal(QPoint(10, detView->rect().height() - 5));
609             GTMouseDriver::moveTo(gp);
610             GTMouseDriver::click();
611             GTGlobals::sleep(500);
612             GTKeyboardDriver::keyClick(Qt::Key_Up);
613             GTGlobals::sleep(200);
614             GTKeyboardDriver::keyClick(Qt::Key_Enter);
615             GTGlobals::sleep(200);
616         }
617     }
618 }
619 #undef GT_METHOD_NAME
620 
621 #define GT_METHOD_NAME "insertSubsequence"
insertSubsequence(HI::GUITestOpStatus & os,qint64 offset,const QString & subsequence,bool isDirectStrand)622 void GTUtilsSequenceView::insertSubsequence(HI::GUITestOpStatus &os, qint64 offset, const QString &subsequence, bool isDirectStrand) {
623     makeDetViewVisible(os);
624     enableEditingMode(os, true);
625     setCursor(os, offset, isDirectStrand);
626     GTKeyboardDriver::keySequence(subsequence);
627     enableEditingMode(os, false);
628 }
629 #undef GT_METHOD_NAME
630 
631 #define GT_METHOD_NAME "setCursor"
setCursor(GUITestOpStatus & os,qint64 position,bool clickOnDirectLine,bool doubleClick)632 void GTUtilsSequenceView::setCursor(GUITestOpStatus &os, qint64 position, bool clickOnDirectLine, bool doubleClick) {
633     // Multiline view is no supported correctly
634 
635     DetView *detView = getDetViewByNumber(os, 0);
636     CHECK_SET_ERR(nullptr != detView, "DetView is NULL");
637 
638     DetViewRenderArea *renderArea = detView->getDetViewRenderArea();
639     CHECK_SET_ERR(nullptr != renderArea, "DetViewRenderArea is NULL");
640 
641     DetViewRenderer *renderer = renderArea->getRenderer();
642     CHECK_SET_ERR(nullptr != renderer, "DetViewRenderer is NULL");
643 
644     U2Region visibleRange = detView->getVisibleRange();
645     if (!visibleRange.contains(position)) {
646         GTUtilsSequenceView::goToPosition(os, position);
647         GTGlobals::sleep();
648         visibleRange = detView->getVisibleRange();
649     }
650     SAFE_POINT_EXT(visibleRange.contains(position), os.setError("Position is out of visible range"), );
651 
652     const double scale = renderer->getCurrentScale();
653     const int coord = renderer->posToXCoord(position, renderArea->size(), visibleRange) + (int)(scale / 2);
654 
655     const bool wrapMode = detView->isWrapMode();
656     if (!wrapMode) {
657         GTMouseDriver::moveTo(renderArea->mapToGlobal(QPoint(coord, 40)));  // TODO: replace the hardcoded value with method in renderer
658     } else {
659         GTUtilsSequenceView::goToPosition(os, position);
660         GTGlobals::sleep();
661 
662         const int symbolsPerLine = renderArea->getSymbolsPerLine();
663         const int linesCount = renderArea->getLinesCount();
664         visibleRange = GTUtilsSequenceView::getVisibleRange(os);
665         int linesBeforePos = -1;
666         for (int i = 0; i < linesCount; i++) {
667             const U2Region line(visibleRange.startPos + i * symbolsPerLine, symbolsPerLine);
668             if (line.contains(position)) {
669                 linesBeforePos = i;
670                 break;
671             }
672         }
673         SAFE_POINT_EXT(linesBeforePos != -1, os.setError("Position not found"), );
674 
675         const int shiftsCount = renderArea->getShiftsCount();
676         int middleShift = (int)(shiftsCount / 2) + 1;  // TODO: this calculation might consider the case then complementary is turned off or translations are drawn
677         if (clickOnDirectLine) {
678             middleShift--;
679         }
680 
681         const int shiftHeight = renderArea->getShiftHeight();
682         const int lineToClick = linesBeforePos * shiftsCount + middleShift;
683 
684         const int yPos = (lineToClick * shiftHeight) - (shiftHeight / 2);
685 
686         GTMouseDriver::moveTo(renderArea->mapToGlobal(QPoint(coord, yPos)));
687     }
688     if (doubleClick) {
689         GTMouseDriver::doubleClick();
690     } else {
691         GTMouseDriver::click();
692     }
693 }
694 #undef GT_METHOD_NAME
695 
696 #define GT_METHOD_NAME "getCursor"
getCursor(HI::GUITestOpStatus & os)697 qint64 GTUtilsSequenceView::getCursor(HI::GUITestOpStatus &os) {
698     DetView *detView = getDetViewByNumber(os, 0);
699     GT_CHECK_RESULT(nullptr != detView, "DetView is NULL", -1);
700 
701     DetViewSequenceEditor *dwSequenceEditor = detView->getEditor();
702     GT_CHECK_RESULT(dwSequenceEditor != nullptr, "DetViewSequenceEditor is NULL", -1);
703 
704     const bool isEditMode = detView->isEditMode();
705     GT_CHECK_RESULT(isEditMode, "Edit mode is disabled", -1);
706 
707     const qint64 result = dwSequenceEditor->getCursorPosition();
708 
709     return result;
710 }
711 #undef GT_METHOD_NAME
712 
713 #define GT_METHOD_NAME "getRegionAsString"
getRegionAsString(HI::GUITestOpStatus & os,const U2Region & region)714 QString GTUtilsSequenceView::getRegionAsString(HI::GUITestOpStatus &os, const U2Region &region) {
715     GTUtilsSequenceView::selectSequenceRegion(os, region.startPos, region.endPos() - 1);
716     GTGlobals::sleep();
717 
718     GTKeyboardUtils::copy();
719 
720     const QString result = GTClipboard::text(os);
721 
722     return result;
723 }
724 #undef GT_METHOD_NAME
725 
726 #define GT_METHOD_NAME "clickOnDetView"
clickOnDetView(HI::GUITestOpStatus & os)727 void GTUtilsSequenceView::clickOnDetView(HI::GUITestOpStatus &os) {
728     MainWindow *mw = AppContext::getMainWindow();
729     GT_CHECK(mw != nullptr, "MainWindow == NULL");
730 
731     MWMDIWindow *mdiWindow = mw->getMDIManager()->getActiveWindow();
732     GT_CHECK(mdiWindow != nullptr, "MDI window == NULL");
733 
734     GTMouseDriver::moveTo(mdiWindow->mapToGlobal(mdiWindow->rect().center()));
735     GTMouseDriver::click();
736 
737     GTGlobals::sleep(500);
738 }
739 #undef GT_METHOD_NAME
740 
741 #define GT_METHOD_NAME "makeDetViewVisible"
makeDetViewVisible(HI::GUITestOpStatus & os)742 void GTUtilsSequenceView::makeDetViewVisible(HI::GUITestOpStatus &os) {
743     QToolButton *toggleDetViewButton = GTWidget::findToolButton(os, "show_hide_details_view");
744     if (!toggleDetViewButton->isChecked()) {
745         GTWidget::click(os, toggleDetViewButton);
746     }
747 }
748 #undef GT_METHOD_NAME
749 
750 #undef GT_CLASS_NAME
751 
752 }  // namespace U2
753