//Copyright 2017 Ryan Wick
//This file is part of Bandage.
//Bandage is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//Bandage is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//You should have received a copy of the GNU General Public License
//along with Bandage. If not, see .
#include "querypathsdialog.h"
#include "ui_querypathsdialog.h"
#include "../blast/blastquery.h"
#include "../blast/blastquerypath.h"
#include "tablewidgetitemint.h"
#include "tablewidgetitemdouble.h"
#include "../program/globals.h"
#include "../program/memory.h"
#include
#include "querypathsequencecopybutton.h"
QueryPathsDialog::QueryPathsDialog(QWidget * parent, BlastQuery * query) :
QDialog(parent),
ui(new Ui::QueryPathsDialog)
{
ui->setupUi(this);
setWindowFlags(windowFlags() | Qt::Tool);
connect(this, SIGNAL(rejected()), this, SLOT(hidden()));
connect(ui->tableWidget, SIGNAL(itemSelectionChanged()), this, SLOT(tableSelectionChanged()));
g_memory->queryPathDialogIsVisible = true;
g_memory->queryPaths.clear();
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "Path" << "Length\n(bp)" << "Query\ncovered\nby path" <<
"Query\ncovered\nby hits" << "Mean hit\nidentity" << "Total\nhit mis-\nmatches" <<
"Total\nhit gap\nopens" << "Relative\nlength" << "Length\ndiscre-\npancy" <<
"E-value\nproduct" << "Copy sequence\nto clipboard");
QString queryDescription = "Query name: " + query->getName();
queryDescription += " type: " + query->getTypeString();
queryDescription += " length: " + formatIntForDisplay(query->getLength());
if (query->getSequenceType() == PROTEIN)
queryDescription += " (" + formatIntForDisplay(3 * query->getLength()) + " bp)";
else
queryDescription += " bp";
ui->queryLabel->setText(queryDescription);
ui->tableWidget->clearContents();
ui->tableWidget->setSortingEnabled(false);
int pathCount = query->getPathCount();
ui->tableWidget->setRowCount(pathCount);
if (pathCount == 0)
return;
QList paths = query->getPaths();
for (int i = 0; i < pathCount; ++i)
{
BlastQueryPath * queryPath = &paths[i];
QTableWidgetItem * pathString = new QTableWidgetItem(queryPath->getPath().getString(true));
pathString->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
int length = queryPath->getPath().getLength();
TableWidgetItemInt * pathLength = new TableWidgetItemInt(formatIntForDisplay(length), length);
pathLength->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
double queryCoveragePath = queryPath->getPathQueryCoverage();
TableWidgetItemDouble * pathQueryCoveragePath = new TableWidgetItemDouble(formatDoubleForDisplay(100.0 * queryCoveragePath, 2) + "%", queryCoveragePath);
pathQueryCoveragePath->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
pathLength->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
double queryCoverageHits = queryPath->getHitsQueryCoverage();
TableWidgetItemDouble * pathQueryCoverageHits = new TableWidgetItemDouble(formatDoubleForDisplay(100.0 * queryCoverageHits, 2) + "%", queryCoverageHits);
pathQueryCoverageHits->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
double percIdentity = queryPath->getMeanHitPercIdentity();
TableWidgetItemDouble * pathPercIdentity = new TableWidgetItemDouble(formatDoubleForDisplay(percIdentity, 2) + "%", percIdentity);
pathPercIdentity->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
int mismatches = queryPath->getTotalHitMismatches();
TableWidgetItemInt * pathMismatches = new TableWidgetItemInt(formatIntForDisplay(mismatches), mismatches);
pathMismatches->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
int gapOpens = queryPath->getTotalHitGapOpens();
TableWidgetItemInt * pathGapOpens = new TableWidgetItemInt(formatIntForDisplay(gapOpens), gapOpens);
pathGapOpens->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
double relativeLength = queryPath->getRelativePathLength();
TableWidgetItemDouble * pathRelativeLength = new TableWidgetItemDouble(formatDoubleForDisplay(100.0 * relativeLength, 2) + "%", relativeLength);
pathRelativeLength->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
int lengthDisc = queryPath->getAbsolutePathLengthDifference();
QString lengthDiscString = queryPath->getAbsolutePathLengthDifferenceString(true);
TableWidgetItemInt * pathLengthDisc = new TableWidgetItemInt(lengthDiscString, lengthDisc);
pathLengthDisc->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
SciNot evalueProduct = queryPath->getEvalueProduct();
TableWidgetItemDouble * pathEvalueProduct = new TableWidgetItemDouble(evalueProduct.asString(false), evalueProduct.toDouble());
pathEvalueProduct->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
QByteArray pathSequence = queryPath->getPath().getPathSequence();
QString pathStart;
if (pathSequence.length() <= 8)
pathStart = pathSequence;
else
pathStart = pathSequence.left(8) + "...";
QTableWidgetItem * sequenceCopy = new QTableWidgetItem(pathStart);
QueryPathSequenceCopyButton * sequenceCopyButton = new QueryPathSequenceCopyButton(pathSequence, pathStart);
ui->tableWidget->setItem(i, 0, pathString);
ui->tableWidget->setItem(i, 1, pathLength);
ui->tableWidget->setItem(i, 2, pathQueryCoveragePath);
ui->tableWidget->setItem(i, 3, pathQueryCoverageHits);
ui->tableWidget->setItem(i, 4, pathPercIdentity);
ui->tableWidget->setItem(i, 5, pathMismatches);
ui->tableWidget->setItem(i, 6, pathGapOpens);
ui->tableWidget->setItem(i, 7, pathRelativeLength);
ui->tableWidget->setItem(i, 8, pathLengthDisc);
ui->tableWidget->setItem(i, 9, pathEvalueProduct);
ui->tableWidget->setItem(i, 10, sequenceCopy);
ui->tableWidget->setCellWidget(i, 10, sequenceCopyButton);
}
ui->tableWidget->resizeColumns();
ui->tableWidget->setSortingEnabled(true);
ui->queryPathsInfoText->setInfoText("This table shows information about the possible paths through the graph which "
"represent the query. These paths can be either simple (residing within a single "
"node) or complex (spanning multiple nodes). The columns in the table are as "
"follows:"
"
"
"Path: This is the query path through the graph, as written in Bandage's "
"path notation. The nodes in the path are separated by commas. The start position "
"in the first node is shown in parentheses at the beginning of the path. The end "
"position in the last node is shown in parentheses at the end of the path."
"
"
"Length: This is the path length. It is shown in base pairs, whether the "
"query is a nucleotide query or a protein query."
"
"
"Query covered by path: This is the fraction of the query which is covered "
"by the path. It is calculated by taking 100% and subtracting the fraction of the "
"query which is not captured by the start and the fraction of the query which is "
"not captured by the end."
"
"
"Query covered by hits: This is the fraction of the query which is covered "
"by the BLAST hits in this path. Since a path may contain nodes or parts of nodes which "
"are not covered by BLAST hits, this value will be less than or equal to the 'Query "
"covered by path' value."
"
"
"Mean hit identity: This is the mean of the percent identity for the BLAST "
"hits in this path, weighted by the hits' lengths."
"
"
"Total hit mismatches: This is the sum of the mismatches for the BLAST hits "
"in this path."
"
"
"Total hit gap opens: This is the sum of the gap opens for the BLAST hits "
"in this path."
"
"
"Relative length: This is the length of the path compared to the length for "
"the relevant fraction of the query. A value over 100% indicates that the path is "
"too long; a value under 100% value indicates that the path is too short."
"
"
"Length discrepancy: This is the difference in the path length and "
"the length for the relevant fraction of the query. A positive value "
"indicates that the path is too long; a negative value indicates that the path is "
"too short."
"
"
"E-value product: This is the product of the e-values for the BLAST hits "
"in this path.");
}
QueryPathsDialog::~QueryPathsDialog()
{
delete ui;
g_memory->queryPathDialogIsVisible = false;
}
void QueryPathsDialog::hidden()
{
g_memory->queryPathDialogIsVisible = false;
emit selectionChanged();
}
void QueryPathsDialog::tableSelectionChanged()
{
QList selection = ui->tableWidget->selectedRanges();
int totalSelectedRows = 0;
for (int i = 0; i < selection.size(); ++i)
totalSelectedRows += selection[i].rowCount();
g_memory->queryPaths.clear();
QList selectedRows;
for (int i = 0; i < selection.size(); ++i)
{
QTableWidgetSelectionRange * selectionRange = &(selection[i]);
int top = selectionRange->topRow();
int bottom = selectionRange->bottomRow();
for (int row = top; row <= bottom; ++row)
{
if (!selectedRows.contains(row))
selectedRows.push_back(row);
}
}
for (int i = 0; i < selectedRows.size(); ++i)
{
int row = selectedRows[i];
QString pathString = ui->tableWidget->item(row, 0)->text();
QString pathStringFailure;
g_memory->queryPaths.push_back(Path::makeFromString(pathString, false, &pathStringFailure));
}
emit selectionChanged();
}