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 "PairAlign.h"
23 
24 #include <QMessageBox>
25 #include <QString>
26 #include <QStringList>
27 
28 #include <U2Algorithm/AlignmentAlgorithmsRegistry.h>
29 #include <U2Algorithm/BuiltInDistanceAlgorithms.h>
30 #include <U2Algorithm/MSADistanceAlgorithm.h>
31 #include <U2Algorithm/MSADistanceAlgorithmRegistry.h>
32 #include <U2Algorithm/PairwiseAlignmentTask.h>
33 
34 #include <U2Core/AppContext.h>
35 #include <U2Core/AppSettings.h>
36 #include <U2Core/BaseDocumentFormats.h>
37 #include <U2Core/DNAAlphabet.h>
38 #include <U2Core/GUrlUtils.h>
39 #include <U2Core/MultipleSequenceAlignmentObject.h>
40 #include <U2Core/Theme.h>
41 #include <U2Core/U2Alphabet.h>
42 #include <U2Core/U2DbiUtils.h>
43 #include <U2Core/U2Msa.h>
44 #include <U2Core/U2MsaDbi.h>
45 #include <U2Core/U2OpStatusUtils.h>
46 #include <U2Core/U2SafePoints.h>
47 #include <U2Core/U2SequenceDbi.h>
48 #include <U2Core/UserApplicationsSettings.h>
49 
50 #include <U2Gui/SaveDocumentController.h>
51 #include <U2Gui/ShowHideSubgroupWidget.h>
52 #include <U2Gui/U2WidgetStateStorage.h>
53 
54 #include <U2View/AlignmentAlgorithmGUIExtension.h>
55 #include <U2View/MSAEditor.h>
56 #include <U2View/MSAEditorSequenceArea.h>
57 #include <U2View/MaEditorNameList.h>
58 
59 #include "ov_msa/view_rendering/MaEditorSelection.h"
60 
61 #define BadAlphabetWarning 0
62 #define DuplicateSequenceWarning 1
63 
getSequenceIdByRowId(U2::MSAEditor * msa,qint64 rowId,U2::U2OpStatus & os)64 inline U2::U2DataId getSequenceIdByRowId(U2::MSAEditor *msa, qint64 rowId, U2::U2OpStatus &os) {
65     const U2::MultipleSequenceAlignmentRow row = msa->getMaObject()->getMsa()->getMsaRowByRowId(rowId, os);
66     CHECK_OP(os, U2::U2DataId());
67     return row->getRowDbInfo().sequenceId;
68 }
69 
70 namespace U2 {
71 
PairAlign(MSAEditor * _msa)72 PairAlign::PairAlign(MSAEditor *_msa)
73     : msa(_msa), pairwiseAlignmentWidgetsSettings(_msa->getPairwiseAlignmentWidgetsSettings()),
74       distanceCalcTask(nullptr), settingsWidget(nullptr),
75       showHideSequenceWidget(nullptr), showHideSettingsWidget(nullptr), showHideOutputWidget(nullptr),
76       saveController(nullptr), savableTab(this, GObjectViewUtils::findViewByName(_msa->getName())),
77       showSequenceWidget(_msa->getPairwiseAlignmentWidgetsSettings()->showSequenceWidget),
78       showAlgorithmWidget(_msa->getPairwiseAlignmentWidgetsSettings()->showAlgorithmWidget),
79       showOutputWidget(_msa->getPairwiseAlignmentWidgetsSettings()->showOutputWidget),
80       firstSequenceSelectionOn(false), secondSequenceSelectionOn(false),
81       sequencesChanged(true), sequenceNamesIsOk(false), alphabetIsOk(false) {
82     SAFE_POINT(nullptr != msa, "MSA Editor is NULL.", );
83     SAFE_POINT(nullptr != pairwiseAlignmentWidgetsSettings, "pairwiseAlignmentWidgetsSettings is NULL.", );
84 
85     setupUi(this);
86 
87     firstSeqSelectorWC = new SequenceSelectorWidgetController(msa);
88     firstSeqSelectorWC->setObjectName("firstSeqSelectorWC");
89     secondSeqSelectorWC = new SequenceSelectorWidgetController(msa);
90     secondSeqSelectorWC->setObjectName("secondSeqSelectorWC");
91 
92     firstSequenceLayout->addWidget(firstSeqSelectorWC);
93     secondSequenceLayout->addWidget(secondSeqSelectorWC);
94 
95     initLayout();
96     initSaveController();
97     initParameters();
98 
99     U2WidgetStateStorage::restoreWidgetState(savableTab);
100 
101     connectSignals();
102 
103     checkState();
104 }
105 
initLayout()106 void PairAlign::initLayout() {
107     showHideSequenceWidget = new ShowHideSubgroupWidget("PA_SEQUENCES", tr("Sequences"), sequenceContainerWidget, showSequenceWidget);
108     showHideSettingsWidget = new ShowHideSubgroupWidget("PA_SETTINGS", tr("Algorithm settings"), settingsContainerWidget, showAlgorithmWidget);
109     showHideOutputWidget = new ShowHideSubgroupWidget("PA_OUTPUT", tr("Output settings"), outputContainerWidget, showOutputWidget);
110 
111     mainLayout->insertWidget(0, showHideSequenceWidget);
112     mainLayout->insertWidget(1, showHideSettingsWidget);
113     mainLayout->insertWidget(2, showHideOutputWidget);
114 }
115 
isValidSequenceId(qint64 sequenceId) const116 bool PairAlign::isValidSequenceId(qint64 sequenceId) const {
117     return msa->getMaObject()->getRowPosById(sequenceId) >= 0;
118 }
119 
initParameters()120 void PairAlign::initParameters() {
121     const MaEditorSelection &selection = msa->getSelection();
122     QList<int> selectedViewRowIndexes = selection.getSelectedRowIndexes();
123     if (selectedViewRowIndexes.size() == 2) {
124         qint64 firstRowId = msa->getRowByViewRowIndex(selectedViewRowIndexes[0])->getRowId();
125         firstSeqSelectorWC->setSequenceId(firstRowId);
126         qint64 secondRowId = msa->getRowByViewRowIndex(selectedViewRowIndexes[1])->getRowId();
127         secondSeqSelectorWC->setSequenceId(secondRowId);
128     } else {
129         if (isValidSequenceId(pairwiseAlignmentWidgetsSettings->firstSequenceId)) {
130             firstSeqSelectorWC->setSequenceId(pairwiseAlignmentWidgetsSettings->firstSequenceId);
131         }
132         if (isValidSequenceId(pairwiseAlignmentWidgetsSettings->secondSequenceId)) {
133             secondSeqSelectorWC->setSequenceId(pairwiseAlignmentWidgetsSettings->secondSequenceId);
134         }
135     }
136 
137     inNewWindowCheckBox->setChecked(pairwiseAlignmentWidgetsSettings->inNewWindow);
138 
139     QString outputFileName = pairwiseAlignmentWidgetsSettings->resultFileName;
140     if (outputFileName.isEmpty()) {
141         saveController->setPath(getDefaultFilePath());  // controller will roll file name here
142     } else {
143         outputFileLineEdit->setText(outputFileName);
144     }
145     outputFileLineEdit->setEnabled(inNewWindowCheckBox->isChecked());
146     outputFileSelectButton->setEnabled(inNewWindowCheckBox->isChecked());
147 
148     canDoAlign = false;
149 
150     AlignmentAlgorithmsRegistry *par = AppContext::getAlignmentAlgorithmsRegistry();
151     SAFE_POINT(par != nullptr, "AlignmentAlgorithmsRegistry is NULL.", );
152     QStringList algList = par->getAvailableAlgorithmIds(PairwiseAlignment);
153     algorithmListComboBox->setEnabled(algList.length() > 0);
154     CHECK(algList.length() > 0, );
155     algorithmListComboBox->addItems(algList);
156     if (pairwiseAlignmentWidgetsSettings->algorithmName.isEmpty()) {
157         pairwiseAlignmentWidgetsSettings->algorithmName = algList[0];
158     } else {
159         int index = algorithmListComboBox->findText(pairwiseAlignmentWidgetsSettings->algorithmName);
160         if (index != -1) {
161             algorithmListComboBox->setCurrentIndex(index);
162         } else {
163             pairwiseAlignmentWidgetsSettings->algorithmName = algList[0];
164         }
165     }
166     sl_algorithmSelected(pairwiseAlignmentWidgetsSettings->algorithmName);
167 
168     lblMessage->setStyleSheet("color: " + Theme::errorColorLabelStr() + ";"
169                                                                         "font: bold;"
170                                                                         "padding-top: 15px;");
171     sl_alignmentChanged();
172 }
173 
updateWarningMessage(int type)174 void PairAlign::updateWarningMessage(int type) {
175     QString text;
176     switch (type) {
177         case DuplicateSequenceWarning:
178             text = tr("Please select 2 different sequences to align");
179             break;
180         case BadAlphabetWarning: {
181             QString alphabetName = msa->getMaObject()->getAlphabet()->getName();
182             text = tr("Pairwise alignment is not available for alignments with \"%1\" alphabet.").arg(alphabetName);
183             break;
184         }
185         default:
186             text = tr("Unexpected error");
187     }
188     lblMessage->setText(text);
189 }
190 
initSaveController()191 void PairAlign::initSaveController() {
192     SaveDocumentControllerConfig config;
193     config.defaultFormatId = BaseDocumentFormats::CLUSTAL_ALN;
194     config.fileDialogButton = outputFileSelectButton;
195     config.fileNameEdit = outputFileLineEdit;
196     config.parentWidget = this;
197     config.saveTitle = tr("Save file");
198 
199     const QList<DocumentFormatId> formats = QList<DocumentFormatId>() << BaseDocumentFormats::CLUSTAL_ALN;
200 
201     saveController = new SaveDocumentController(config, formats, this);
202     saveController->setPath(getDefaultFilePath());  // controller will roll file name here
203 }
204 
getDefaultFilePath()205 QString PairAlign::getDefaultFilePath() {
206     return GUrlUtils::getDefaultDataPath() + "/" + PairwiseAlignmentTaskSettings::DEFAULT_NAME;
207 }
208 
connectSignals()209 void PairAlign::connectSignals() {
210     connect(showHideSequenceWidget, SIGNAL(si_subgroupStateChanged(QString)), SLOT(sl_subwidgetStateChanged(QString)));
211     connect(showHideSettingsWidget, SIGNAL(si_subgroupStateChanged(QString)), SLOT(sl_subwidgetStateChanged(QString)));
212     connect(showHideOutputWidget, SIGNAL(si_subgroupStateChanged(QString)), SLOT(sl_subwidgetStateChanged(QString)));
213     connect(algorithmListComboBox, SIGNAL(currentIndexChanged(QString)), SLOT(sl_algorithmSelected(QString)));
214     connect(inNewWindowCheckBox, SIGNAL(clicked(bool)), SLOT(sl_inNewWindowCheckBoxChangeState(bool)));
215     connect(alignButton, SIGNAL(clicked()), SLOT(sl_alignButtonPressed()));
216     connect(outputFileSelectButton, SIGNAL(clicked()), SLOT(sl_checkState()));
217     connect(outputFileLineEdit, SIGNAL(textChanged(QString)), SLOT(sl_outputFileChanged()));
218 
219     connect(firstSeqSelectorWC, SIGNAL(si_selectionChanged()), SLOT(sl_selectorTextChanged()));
220     connect(secondSeqSelectorWC, SIGNAL(si_selectionChanged()), SLOT(sl_selectorTextChanged()));
221     connect(msa->getMaObject(), SIGNAL(si_lockedStateChanged()), SLOT(sl_checkState()));
222     connect(msa->getMaObject(), SIGNAL(si_alignmentChanged(const MultipleAlignment &, const MaModificationInfo &)), SLOT(sl_alignmentChanged()));
223 }
224 
sl_checkState()225 void PairAlign::sl_checkState() {
226     checkState();
227 }
228 
sl_alignmentChanged()229 void PairAlign::sl_alignmentChanged() {
230     const DNAAlphabet *dnaAlphabet = msa->getMaObject()->getAlphabet();
231     SAFE_POINT(dnaAlphabet != nullptr, "Alignment alphabet is not defined.", );
232 
233     pairwiseAlignmentWidgetsSettings->customSettings.insert("alphabet", dnaAlphabet->getId());
234 
235     QString curAlgorithmId = pairwiseAlignmentWidgetsSettings->algorithmName;
236     AlignmentAlgorithm *alg = getAlgorithmById(curAlgorithmId);
237     SAFE_POINT(alg != nullptr, QString("Algorithm %1 not found.").arg(curAlgorithmId), );
238     alphabetIsOk = alg->checkAlphabet(dnaAlphabet);
239 
240     if (settingsWidget != nullptr) {
241         settingsWidget->updateWidget();
242     }
243     checkState();
244 }
245 
checkState()246 void PairAlign::checkState() {
247     SAFE_POINT((firstSequenceSelectionOn && secondSequenceSelectionOn) == false,
248                tr("Either addFirstButton and addSecondButton are pressed. Sequence selection mode works incorrect."), );
249 
250     sequenceNamesIsOk = checkSequenceNames();
251 
252     outputFileLineEdit->setEnabled(inNewWindowCheckBox->isChecked());
253     outputFileSelectButton->setEnabled(inNewWindowCheckBox->isChecked());
254 
255     if (sequencesChanged) {
256         updatePercentOfSimilarity();
257     }
258 
259     qint64 firstSequenceId = firstSeqSelectorWC->sequenceId();
260     qint64 secondSequenceId = secondSeqSelectorWC->sequenceId();
261     bool sameSequenceInBothSelectors = firstSequenceId == secondSequenceId && firstSequenceId != U2MsaRow::INVALID_ROW_ID;
262     if (!alphabetIsOk) {
263         updateWarningMessage(BadAlphabetWarning);
264     } else if (sameSequenceInBothSelectors) {
265         updateWarningMessage(DuplicateSequenceWarning);
266     }
267     lblMessage->setVisible(!alphabetIsOk || sameSequenceInBothSelectors);
268 
269     showHideSettingsWidget->setEnabled(alphabetIsOk);
270     showHideOutputWidget->setEnabled(alphabetIsOk);
271 
272     bool readOnly = msa->getMaObject()->isStateLocked();
273     canDoAlign = ((U2MsaRow::INVALID_ROW_ID != firstSequenceId) && (U2MsaRow::INVALID_ROW_ID != secondSequenceId) && (firstSequenceId != secondSequenceId) && sequenceNamesIsOk && alphabetIsOk && (!readOnly || inNewWindowCheckBox->isChecked()));
274 
275     alignButton->setEnabled(canDoAlign);
276 
277     pairwiseAlignmentWidgetsSettings->firstSequenceId = firstSequenceId;
278     pairwiseAlignmentWidgetsSettings->secondSequenceId = secondSequenceId;
279     pairwiseAlignmentWidgetsSettings->algorithmName = algorithmListComboBox->currentText();
280     pairwiseAlignmentWidgetsSettings->inNewWindow = inNewWindowCheckBox->isChecked();
281     pairwiseAlignmentWidgetsSettings->resultFileName = saveController->getSaveFileName();
282     pairwiseAlignmentWidgetsSettings->showSequenceWidget = showSequenceWidget;
283     pairwiseAlignmentWidgetsSettings->showAlgorithmWidget = showAlgorithmWidget;
284     pairwiseAlignmentWidgetsSettings->showOutputWidget = showOutputWidget;
285     pairwiseAlignmentWidgetsSettings->sequenceSelectionModeOn = firstSequenceSelectionOn || secondSequenceSelectionOn;
286 }
287 
updatePercentOfSimilarity()288 void PairAlign::updatePercentOfSimilarity() {
289     similarityValueLabel->setText(tr("Not defined"));
290     similarityWidget->setVisible(false);
291     sequencesChanged = false;
292     if (!sequenceNamesIsOk) {
293         return;
294     }
295 
296     MSADistanceAlgorithmRegistry *distanceReg = AppContext::getMSADistanceAlgorithmRegistry();
297     SAFE_POINT(distanceReg != nullptr, "MSADistanceAlgorithmRegistry is NULL.", );
298     MSADistanceAlgorithmFactory *distanceFactory = distanceReg->getAlgorithmFactory(BuiltInDistanceAlgorithms::SIMILARITY_ALGO);
299     SAFE_POINT(distanceFactory != nullptr, QString("%1 algorithm factory not found.").arg(BuiltInDistanceAlgorithms::SIMILARITY_ALGO), );
300 
301     U2OpStatusImpl os;
302     MultipleSequenceAlignment ma;
303     const MultipleSequenceAlignment currentAlignment = msa->getMaObject()->getMultipleAlignment();
304     ma->addRow(firstSeqSelectorWC->text(), currentAlignment->getMsaRowByRowId(firstSeqSelectorWC->sequenceId(), os)->getData(), -1);
305     ma->addRow(secondSeqSelectorWC->text(), currentAlignment->getMsaRowByRowId(secondSeqSelectorWC->sequenceId(), os)->getData(), -1);
306     distanceCalcTask = distanceFactory->createAlgorithm(ma);
307     distanceCalcTask->setExcludeGaps(true);
308     connect(distanceCalcTask, SIGNAL(si_stateChanged()), SLOT(sl_distanceCalculated()));
309     AppContext::getTaskScheduler()->registerTopLevelTask(distanceCalcTask);
310 }
311 
checkSequenceNames()312 bool PairAlign::checkSequenceNames() {
313     QList<qint64> rowIds = msa->getMaObject()->getMultipleAlignment()->getRowsIds();
314     return (rowIds.contains(firstSeqSelectorWC->sequenceId()) && rowIds.contains(secondSeqSelectorWC->sequenceId()));
315 }
316 
getAlgorithmById(const QString & algorithmId)317 AlignmentAlgorithm *PairAlign::getAlgorithmById(const QString &algorithmId) {
318     AlignmentAlgorithmsRegistry *par = AppContext::getAlignmentAlgorithmsRegistry();
319     SAFE_POINT(par != nullptr, "AlignmentAlgorithmsRegistry is NULL.", nullptr);
320     return par->getAlgorithm(algorithmId);
321 }
322 
sl_algorithmSelected(const QString & algorithmName)323 void PairAlign::sl_algorithmSelected(const QString &algorithmName) {
324     if (settingsWidget != nullptr) {
325         delete settingsWidget;
326         settingsWidget = nullptr;
327     }
328 
329     AlignmentAlgorithm *alg = getAlgorithmById(algorithmName);
330     SAFE_POINT(alg != nullptr, QString("Algorithm %1 not found.").arg(algorithmName), );
331     QString firstAlgorithmRealization = alg->getRealizationsList().first();
332     alphabetIsOk = alg->checkAlphabet(msa->getMaObject()->getAlphabet());
333 
334     AlignmentAlgorithmGUIExtensionFactory *algGUIFactory = alg->getGUIExtFactory(firstAlgorithmRealization);
335     SAFE_POINT(algGUIFactory != nullptr, QString("Algorithm %1 GUI factory not found.").arg(firstAlgorithmRealization), );
336     settingsWidget = algGUIFactory->createMainWidget(this, &pairwiseAlignmentWidgetsSettings->customSettings);
337     connect(msa, SIGNAL(destroyed()), settingsWidget, SLOT(sl_externSettingsInvalide()));
338     settingsContainerWidgetLayout->addWidget(settingsWidget);
339 
340     checkState();
341 }
342 
sl_subwidgetStateChanged(const QString & id)343 void PairAlign::sl_subwidgetStateChanged(const QString &id) {
344     if (id == "PA_SEQUENCES") {
345         showSequenceWidget = showHideSequenceWidget->isSubgroupOpened();
346     }
347     if (id == "PA_SETTINGS") {
348         showAlgorithmWidget = showHideSettingsWidget->isSubgroupOpened();
349     }
350     if (id == "PA_OUTPUT") {
351         showOutputWidget = showHideOutputWidget->isSubgroupOpened();
352     }
353     checkState();
354 }
355 
sl_inNewWindowCheckBoxChangeState(bool newState)356 void PairAlign::sl_inNewWindowCheckBoxChangeState(bool newState) {
357     Q_UNUSED(newState);
358     checkState();
359 }
360 
sl_alignButtonPressed()361 void PairAlign::sl_alignButtonPressed() {
362     firstSequenceSelectionOn = false;
363     secondSequenceSelectionOn = false;
364     checkState();
365     SAFE_POINT(canDoAlign, "Invalid state of PairAlign options panel widget. startAlignButton is not disabled.", );
366 
367     U2OpStatus2Log os;
368     U2EntityRef msaRef = msa->getMaObject()->getEntityRef();
369     DbiConnection con(msaRef.dbiRef, os);
370     CHECK_OP(os, );
371 
372     U2DataId firstSeqId = getSequenceIdByRowId(msa, pairwiseAlignmentWidgetsSettings->firstSequenceId, os);
373     CHECK_OP(os, );
374     U2EntityRef firstSequenceRef = U2EntityRef(msaRef.dbiRef, firstSeqId);
375 
376     U2DataId secondSeqId = getSequenceIdByRowId(msa, pairwiseAlignmentWidgetsSettings->secondSequenceId, os);
377     CHECK_OP(os, );
378     U2EntityRef secondSequenceRef = U2EntityRef(msaRef.dbiRef, secondSeqId);
379 
380     PairwiseAlignmentTaskSettings settings;
381     settings.algorithmId = algorithmListComboBox->currentText();
382 
383     if (!saveController->getSaveFileName().isEmpty()) {
384         settings.resultFileName = GUrl(saveController->getSaveFileName());
385     } else {
386         settings.resultFileName = GUrl(AppContext::getAppSettings()->getUserAppsSettings()->getCurrentProcessTemporaryDirPath() +
387                                        "/" + PairwiseAlignmentTaskSettings::DEFAULT_NAME);
388     }
389     GUrlUtils::validateLocalFileUrl(settings.resultFileName, os);
390     if (os.hasError()) {
391         QMessageBox::warning(this, tr("Error"), tr("Please, change the output file.") + "\n" + os.getError());
392         outputFileLineEdit->setFocus(Qt::MouseFocusReason);
393         return;
394     }
395 
396     settings.inNewWindow = inNewWindowCheckBox->isChecked();
397     settings.msaRef = msaRef;
398     settings.alphabet = U2AlphabetId(msa->getMaObject()->getAlphabet()->getId());
399     settings.firstSequenceRef = firstSequenceRef;
400     settings.secondSequenceRef = secondSequenceRef;
401     settingsWidget->getAlignmentAlgorithmCustomSettings(true);
402     settings.appendCustomSettings(pairwiseAlignmentWidgetsSettings->customSettings);
403     settings.convertCustomSettings();
404 
405     if (!pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask.isNull()) {
406         disconnect(this, SLOT(sl_alignComplete()));
407         pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask->cancel();
408         pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask.clear();
409     }
410 
411     AlignmentAlgorithmsRegistry *par = AppContext::getAlignmentAlgorithmsRegistry();
412     SAFE_POINT(par != nullptr, "AlignmentAlgorithmsRegistry is NULL.", );
413     AbstractAlignmentTaskFactory *factory = par->getAlgorithm(settings.algorithmId)->getFactory(settings.realizationName);
414     SAFE_POINT(factory != nullptr, QString("Task factory for algorithm %1, realization %2 not found.").arg(settings.algorithmId, settings.realizationName), );
415 
416     PairwiseAlignmentTask *task = qobject_cast<PairwiseAlignmentTask *>(factory->getTaskInstance(&settings));
417     SAFE_POINT(task != nullptr, "Task is null!", );
418     connect(task, SIGNAL(si_stateChanged()), SLOT(sl_alignComplete()));
419     pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask = task;
420     AppContext::getTaskScheduler()->registerTopLevelTask(task);
421 
422     con.close(os);
423     checkState();
424 }
425 
sl_outputFileChanged()426 void PairAlign::sl_outputFileChanged() {
427     if (saveController->getSaveFileName().isEmpty()) {
428         saveController->setPath(getDefaultFilePath());
429     }
430     checkState();
431 }
432 
sl_distanceCalculated()433 void PairAlign::sl_distanceCalculated() {
434     if (distanceCalcTask == nullptr) {
435         return;
436     }
437     if (distanceCalcTask->isFinished()) {
438         const MSADistanceMatrix &distanceMatrix = distanceCalcTask->getMatrix();
439         similarityValueLabel->setText(QString::number(distanceMatrix.getSimilarity(0, 1, true)) + "%");
440         similarityWidget->setVisible(true);
441         distanceCalcTask = nullptr;
442     }
443 }
444 
sl_alignComplete()445 void PairAlign::sl_alignComplete() {
446     CHECK(pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask == sender(), );
447     SAFE_POINT(!pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask.isNull(), "Can't process an unexpected align task", );
448     if (pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask->isFinished()) {
449         if (!inNewWindowCheckBox->isChecked()) {
450             MaModificationInfo mi;
451             mi.rowListChanged = false;
452             mi.modifiedRowIds.append(pairwiseAlignmentWidgetsSettings->firstSequenceId);
453             mi.modifiedRowIds.append(pairwiseAlignmentWidgetsSettings->secondSequenceId);
454             msa->getMaObject()->updateCachedMultipleAlignment(mi);
455         }
456         pairwiseAlignmentWidgetsSettings->pairwiseAlignmentTask.clear();
457     }
458     checkState();
459 }
460 
sl_selectorTextChanged()461 void PairAlign::sl_selectorTextChanged() {
462     sequencesChanged = true;
463     checkState();
464 }
465 
466 }  // namespace U2
467