Logo Search packages:      
Sourcecode: ugene version File versions

MSAEditorSequenceArea.cpp

/*****************************************************************
* Unipro UGENE - Integrated Bioinformatics Suite
* Copyright (C) 2008 Unipro, Russia (http://ugene.unipro.ru)
* All Rights Reserved
* 
*     This source code is distributed under the terms of the
*     GNU General Public License. See the files COPYING and LICENSE
*     for details.
*****************************************************************/

#include "MSAEditorSequenceArea.h"
#include "MSAEditor.h"
#include "MSAEditorNameList.h"

#include <core_api/Log.h>
#include <core_api/DNAAlphabet.h>
#include <datatype/MAlignment.h>
#include <gobjects/MAlignmentObject.h>
#include <util_gui/GUIUtils.h>
#include <util_gui/PositionSelector.h>
#include <util_text/TextUtils.h>


#include <QtGui/QPainter>
#include <QtGui/QMouseEvent>
#include <QtGui/QClipboard>
#include <QtGui/QApplication>
#include <QtGui/QDialog>


namespace GB2 {

/* TRANSLATOR GB2::MSAEditor */

static LogCategory log(ULOG_CAT_MSA);

MSAEditorSequenceArea::MSAEditorSequenceArea(MSAEditorUI* _ui) : editor(_ui->editor), ui(_ui) {
    colorScheme = new MSAEditorColorScheme(this, editor->getMSAObject()->getMAlignment().alphabet->isAmino());

    setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
    setMinimumSize(100, 100);
    startPos = 0;
    seqFont.setFamily("Verdana");
    seqFont.setPointSize(10);
    QFontMetrics seqFM(seqFont);
    seqCharWidth = seqFM.width('W') * 5 / 4;

    delSymAction = new QAction(tr("del_sym"), this);
    delSymAction->setShortcut(QKeySequence(Qt::Key_Delete));
    connect(delSymAction, SIGNAL(triggered()), SLOT(sl_delSym()));
    
    delColAction = new QAction(tr("del_col"), this);
    delColAction->setShortcut(QKeySequence(Qt::SHIFT| Qt::Key_Delete));
    connect(delColAction, SIGNAL(triggered()), SLOT(sl_delCol()));
    
    insSymAction = new QAction(tr("ins_sym"), this);
    insSymAction->setShortcut(QKeySequence(Qt::Key_Space));
    connect(insSymAction, SIGNAL(triggered()), SLOT(sl_insSym()));
    
    insColAction = new QAction(tr("ins_col"), this);
    insColAction->setShortcut(QKeySequence(Qt::SHIFT| Qt::Key_Space));
    connect(insColAction, SIGNAL(triggered()), SLOT(sl_insCol()));
    
    gotoAction = new QAction(QIcon(":core/images/goto.png"), tr("goto_pos"), this);
    gotoAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_G));
    connect(gotoAction, SIGNAL(triggered()), SLOT(sl_goto()));


    removeGapColumnsAction = new QAction(QIcon(":core/images/msaed_remove_columns_with_gaps.png"), tr("Remove columns with gaps"), this);
    connect(removeGapColumnsAction, SIGNAL(triggered()), SLOT(sl_removeColumnsWithGaps()));
    
    removeAllGapsAction = new QAction(QIcon(":core/images/msaed_remove_all_gaps.png"), tr("Remove all gaps"), this);
    connect(removeAllGapsAction, SIGNAL(triggered()), SLOT(sl_removeAllGaps()));
    
    
    connect(ui->nameList, SIGNAL(itemSelectionChanged()), SLOT(sl_nameListItemSelectionChanged()));


    //synchronize 2 vertical scrollbars
    QScrollBar* nlBar = ui->nameList->verticalScrollBar();
    connect(nlBar, SIGNAL(valueChanged(int)), ui->svBar, SLOT(setValue(int)));
    connect(ui->svBar, SIGNAL(valueChanged(int)), nlBar, SLOT(setValue(int)));
    connect(nlBar, SIGNAL(rangeChanged(int, int)),SLOT(sl_vScrollRangeChanged(int, int)));
    connect(ui->svBar, SIGNAL(valueChanged(int)), SLOT(sl_onVScrollMoved(int)));
    connect(editor->getMSAObject(), SIGNAL(si_alignmentModified()), SLOT(sl_alignmentModified()));
    connect(editor->getMSAObject(), SIGNAL(si_sequenceListModified()), SLOT(sl_sequenceListModified()));
    connect(editor, SIGNAL(si_buildStaticMenu(GObjectView*, QMenu*)), SLOT(sl_buildStaticMenu(GObjectView*, QMenu*)));
    connect(editor, SIGNAL(si_buildStaticToolbar(GObjectView*, QToolBar*)), SLOT(sl_buildStaticToolbar(GObjectView*, QToolBar*)));
    connect(editor, SIGNAL(si_buildPopupMenu(GObjectView* , QMenu*)), SLOT(sl_buildContextMenu(GObjectView*, QMenu*)));
    connect(editor->getMSAObject(), SIGNAL(si_lockedStateChanged()), SLOT(sl_lockedStateChanged()));


    updateActions();
}

void MSAEditorSequenceArea::updateActions() {
    bool readOnly = editor->getMSAObject()->isStateLocked();
    
    delColAction->setEnabled(!readOnly);
    delSymAction->setEnabled(!readOnly);
    insColAction->setEnabled(!readOnly);
    insSymAction->setEnabled(!readOnly);
    removeGapColumnsAction->setEnabled(!readOnly);
    removeAllGapsAction->setEnabled(!readOnly);
}

LRegion MSAEditorSequenceArea::getSequenceYRange(int n, bool useVirsualCoords) const {
#ifdef _DEBUG
    int seqAreaY = geometry().y();
    int nameListY = ui->nameList->geometry().y();
    assert(seqAreaY == nameListY);
    int numSeqs = editor->getNumSequences();
    assert(n >=0 && n < numSeqs);
#endif
    return ui->nameList->getSequenceYRange(n, useVirsualCoords);
}



void MSAEditorSequenceArea::paintEvent(QPaintEvent *e) {
    QPainter p(this);
    p.fillRect(rect(), Qt::white);

    drawSequences(p);

    drawCursor(p);

    QWidget::paintEvent(e);
}

void MSAEditorSequenceArea::drawSequences(QPainter& p) {
    p.setFont(seqFont);

    //for every sequence in msa starting from first visible
    //draw it starting from startPos
    int firstVisible = ui->nameList->getFirstVisibleSequence();
    int lastVisible = ui->nameList->getLastVisibleSequence(true);
    int lastPos = getLastVisibleBase(true);
    int w = width();
    int h = height();
    const MAlignment& msa = editor->getMSAObject()->getMAlignment();
    for (int i = firstVisible; i <= lastVisible; i++) {
        const MAlignmentItem& item = msa.alignedSeqs[i];
        LRegion baseYRange = getSequenceYRange(i, true);

        //draw horizontal grid
        //p.drawLine(0, r.startPos, width(), r.startPos); p.drawLine(0, r.endPos(), width(), r.endPos());

        for (int pos = startPos; pos <= lastPos; pos++) {
            LRegion baseXRange = getBaseXRange(pos, true);
            QRect cr(baseXRange.startPos, baseYRange.startPos, baseXRange.len+1, baseYRange.len);
            Q_ASSERT(cr.left() < w && cr.top() < h);
            char c = item.sequence[pos];
            if (c != MAlignment_GapChar) {
                QColor color = colorScheme->getColor(c);
                p.fillRect(cr, color);
            }
            p.drawText(cr, Qt::AlignCenter, QString(c));
        }
    }
}

void MSAEditorSequenceArea::drawCursor(QPainter& p) {
    if (!isPosVisible(cursorPos, true)) {
        return;
    }
    LRegion xRange = getBaseXRange(cursorPos.x(), true);
    LRegion yRange = getSequenceYRange(cursorPos.y(), true);

    QPen pen(hasFocus()? Qt::black : Qt::gray);
    pen.setStyle(Qt::DashLine);
    p.setPen(pen);
    p.drawRect(xRange.startPos, yRange.startPos, xRange.len, yRange.len);
}

bool MSAEditorSequenceArea::isPosInRange(int p) const {
    return p >= 0 && p < editor->getAlignmentLen();
}

bool MSAEditorSequenceArea::isPosInRange(const QPoint& p) const {
    bool xInRange = isPosInRange(p.x());
    int numSeqs = editor->getNumSequences();
    bool res = xInRange && p.y() >= 0 && p.y() < numSeqs;
    return res;
}

bool MSAEditorSequenceArea::isPosVisible(int pos, bool countClipped) const {
    if (pos < getFirstVisibleBase() || pos > getLastVisibleBase(countClipped)) {
        return false;
    }
    return true;
}

bool MSAEditorSequenceArea::isPosVisible(const QPoint& p, bool countClipped) const {
    
    //check that sequence is visible
    bool yVisible = ui->nameList->isSequenceVisible(p.y(), countClipped);
    if (!yVisible) {
        return false;
    }

    //check that pos is sequence visible
    return isPosVisible(p.x(), countClipped);
}

void MSAEditorSequenceArea::setFirstVisibleBase(int pos) {
    Q_ASSERT(isPosInRange(pos));
    if (pos == startPos) {
        return;
    }
    int aliLen = editor->getAlignmentLen();
    int effectiveFirst = qMin(aliLen - countSpaceForBases(false), pos);
    startPos = effectiveFirst;

    updateHScrollBar();
    update();

    emit si_startPosChanged(pos);
}

void MSAEditorSequenceArea::resizeEvent(QResizeEvent *e) {

    int aliLen = editor->getAlignmentLen();
    int visibleSymbolsCount = countSpaceForBases(false);
    if (visibleSymbolsCount > aliLen) {
        setFirstVisibleBase(0);
    } else if (startPos + visibleSymbolsCount > aliLen) {
        setFirstVisibleBase(aliLen - visibleSymbolsCount);
    }

    Q_ASSERT(startPos >= 0);
    Q_ASSERT((aliLen >= startPos + visibleSymbolsCount) || aliLen < visibleSymbolsCount);

    updateHScrollBar();

    QWidget::resizeEvent(e);
}

void MSAEditorSequenceArea::sl_onHScrollMoved(int pos) {
    Q_ASSERT(pos >=0 && pos <= editor->getAlignmentLen() - getNumVisibleBases(false));
    setFirstVisibleBase(pos);
}

void MSAEditorSequenceArea::updateHScrollBar() {
    ui->shBar->disconnect(this);

    int numVisibleBases = getNumVisibleBases(false);
    int alignmentLen = editor->getAlignmentLen();
    Q_ASSERT(numVisibleBases <= alignmentLen);

    ui->shBar->setMinimum(0);
    ui->shBar->setMaximum(alignmentLen - numVisibleBases);
    ui->shBar->setSliderPosition(getFirstVisibleBase());

    ui->shBar->setSingleStep(1);
    ui->shBar->setPageStep(numVisibleBases);

    ui->shBar->setDisabled(numVisibleBases == alignmentLen);

    connect(ui->shBar, SIGNAL(valueChanged(int)), SLOT(sl_onHScrollMoved(int)));
}


int MSAEditorSequenceArea::countSpaceForBases(bool countClipped) const {
    int seqAreaWidth = width();
    int nVisible = seqAreaWidth / seqCharWidth + (countClipped && (seqAreaWidth % seqCharWidth != 0) ? 1 : 0);
    return nVisible;
}

int MSAEditorSequenceArea::getNumVisibleBases(bool countClipped) const {
    int lastVisible =  getLastVisibleBase(countClipped);
    assert(lastVisible >= startPos);
    assert(lastVisible < editor->getAlignmentLen());
    int res = lastVisible - startPos + 1;
    return res;
}

int MSAEditorSequenceArea::getLastVisibleBase(bool countClipped) const {
    int nVisible = countSpaceForBases(countClipped);
    int alignLen = editor->getAlignmentLen();
    int res = qBound(0, startPos + nVisible - 1, alignLen - 1);
    return res;
}

void MSAEditorSequenceArea::sl_onVScrollMoved(int pos) {
    Q_UNUSED(pos);
    update();
}

void MSAEditorSequenceArea::sl_nameListItemSelectionChanged() {
    update();
}

void MSAEditorSequenceArea::sl_vScrollRangeChanged(int min, int max) {
    ui->svBar->setMinimum(min);    
    ui->svBar->setMaximum(max);    
    ui->svBar->setSingleStep(ui->nameList->verticalScrollBar()->singleStep());    
    ui->svBar->setPageStep(ui->nameList->verticalScrollBar()->pageStep());    
}


LRegion MSAEditorSequenceArea::getBaseXRange(int pos, bool useVirtualCoords) const {
    LRegion res(seqCharWidth * (pos - startPos), seqCharWidth);
    if (!useVirtualCoords) {
        int w = width();
        res = res.intersect(LRegion(0, w));
    }
    return res;
}

void MSAEditorSequenceArea::mousePressEvent(QMouseEvent *e) {
    if (!hasFocus()) {
        setFocus();
    }

    if (e->button() != Qt::LeftButton) {
        QWidget::mousePressEvent(e);
        return;
    }
    QPoint p = coordToPos(e->pos());
    if (p.x()!=-1 && p.y()!=-1) {
        setCursorPos(p);
    }
    QWidget::mousePressEvent(e);
}

void MSAEditorSequenceArea::keyPressEvent(QKeyEvent *e) {
    int key = e->key();
    bool shift = e->modifiers().testFlag(Qt::ShiftModifier);
    bool ctrl = e->modifiers().testFlag(Qt::ControlModifier);
    if (ctrl && (key == Qt::Key_Left || key == Qt::Key_Right || key == Qt::Key_Up || key == Qt::Key_Down)) {
        //remap to page_up/page_down
        shift = key == Qt::Key_Up || key == Qt::Key_Down;
        key =  (key == Qt::Key_Up || key == Qt::Key_Left) ? Qt::Key_PageUp : Qt::Key_PageDown;
    }
    //part of these keys are assigned to actions -> so them never passed to keyPressEvent (action handling has higher priority)
    switch(key) {
        case Qt::Key_Left:
            moveCursorRelative(-1, 0);    
            break;
        case Qt::Key_Right:
            moveCursorRelative(1, 0);    
            break;
        case Qt::Key_Up:
            moveCursorRelative(0, -1);    
            break;
        case Qt::Key_Down:
            moveCursorRelative(0, 1);    
            break;
        case Qt::Key_Home:
            if (shift) { //scroll namelist
                ui->nameList->setFirstVisibleSequence(0);
                setCursorPos(QPoint(cursorPos.x(), 0));
            } else { //scroll sequence
                setFirstVisibleBase(0);
                setCursorPos(QPoint(0, cursorPos.y()));
            }
            break;
        case Qt::Key_End:
            if (shift) { //scroll namelist
                int n = editor->getNumSequences() - 1;
                ui->nameList->setFirstVisibleSequence(n);
                setCursorPos(QPoint(cursorPos.x(), n));
            } else { //scroll sequence
                int n = editor->getAlignmentLen() - 1;
                setFirstVisibleBase(n);
                setCursorPos(QPoint(n, cursorPos.y()));
            }
            break;
        case Qt::Key_PageUp:
            if (shift) { //scroll namelist
                int nVis = ui->nameList->getNumVisibleSequences(false);
                int fp = qMax(0, ui->nameList->getFirstVisibleSequence() - nVis);
                int cp = qMax(0, cursorPos.y() - nVis);
                ui->nameList->setFirstVisibleSequence(fp);
                setCursorPos(QPoint(cursorPos.x(), cp));
            } else { //scroll sequence
                int nVis = getNumVisibleBases(false);
                int fp = qMax(0, getFirstVisibleBase() - nVis);
                int cp = qMax(0, cursorPos.x() - nVis);
                setFirstVisibleBase(fp);
                setCursorPos(QPoint(cp, cursorPos.y()));
            }
            break;
        case Qt::Key_PageDown:
            if (shift) { //scroll namelist
                int nVis = ui->nameList->getNumVisibleSequences(false);
                int nSeq = editor->getNumSequences();
                int fp = qMin(nSeq-1, ui->nameList->getFirstVisibleSequence() + nVis);
                int cp = qMin(nSeq-1, cursorPos.y() + nVis);
                ui->nameList->setFirstVisibleSequence(fp);
                setCursorPos(QPoint(cursorPos.x(), cp));
            } else { //scroll sequence
                int nVis = getNumVisibleBases(false);
                int len = editor->getAlignmentLen();
                int fp  = qMin(len-1, getFirstVisibleBase() + nVis);
                int cp  = qMin(len-1, cursorPos.x() + nVis);
                setFirstVisibleBase(fp);
                setCursorPos(QPoint(cp, cursorPos.y()));
            }
            break;
        case Qt::Key_Delete:
            del(cursorPos, shift);
            break;
        case Qt::Key_Backspace:
            if (cursorPos.x() > 0) {
                del(QPoint(cursorPos.x()-1, cursorPos.y()), shift);
            }
            break;
        case Qt::Key_Insert:
        case Qt::Key_Space:
            //printf("key!\n");
            ins(cursorPos, shift);
            break;
    }
    QWidget::keyPressEvent(e);
}


void MSAEditorSequenceArea::moveCursorRelative(int dx, int dy) {
    QPoint p = cursorPos + QPoint(dx, dy);
    if (!isPosInRange(p)) {
        return;
    }   
    if (!isPosVisible(p, false)) {
        if (isPosVisible(cursorPos, true)) {
            if (dx != 0) { 
                setFirstVisibleBase(startPos + dx);
            } 
            if (dy!=0) {
                ui->nameList->setFirstVisibleSequence(ui->nameList->getFirstVisibleSequence()+dy);
            }
        } else {
            setFirstVisibleBase(p.x());
            ui->nameList->setFirstVisibleSequence(p.y());
        }
    }
    setCursorPos(p);
}


QPoint MSAEditorSequenceArea::coordToPos(const QPoint& coord) const {
    QPoint res(-1, -1);
    //Y: row
    for (int i=ui->nameList->getFirstVisibleSequence(), n = ui->nameList->getLastVisibleSequence(true); i<=n; i++) {
        LRegion r = getSequenceYRange(i, false);
        if (r.contains(coord.y())) {
            res.setY(i);
            break;
        }
    }
    
    //X: position in sequence
    for (int i=getFirstVisibleBase(), n = getLastVisibleBase(true); i<=n; i++) {
        LRegion r = getBaseXRange(i, false);
        if (r.contains(coord.x())) {
            res.setX(i);
            break;
        }
    }
    return res;
}


void MSAEditorSequenceArea::setCursorPos(const QPoint& p) {
    assert(isPosInRange(p));
    if (p == cursorPos) {
        return;
    }
    
    bool up = isPosVisible(cursorPos, true) || isPosVisible(p, true);
    bool upNameList = up && cursorPos.y() != p.y();
    QPoint prev = cursorPos;
    cursorPos = p;
    
    emit si_cursorPosChanged(cursorPos, prev);
    
    if (upNameList) {
        QListWidgetItem* item = ui->nameList->item(cursorPos.y());
        ui->nameList->setCurrentItem(item, QItemSelectionModel::ClearAndSelect);
    }
    if (up) {
        update();
    }
    updateActions();
}

void MSAEditorSequenceArea::ins(const QPoint& p, bool columnMode) {
    assert(isPosInRange(p));
    if (editor->getMSAObject()->isStateLocked()) {
        return;
    }
    if (columnMode) {
        editor->getMSAObject()->insertGap(p.x(), 1);
    } else {
        editor->getMSAObject()->insertGap(p.y(), p.x(), 1);
    }
}

void MSAEditorSequenceArea::del(const QPoint& p, bool columnMode) {
    assert(isPosInRange(p));
    if (editor->getMSAObject()->isStateLocked()) {
        return;
    }
    if (columnMode) {
        editor->getMSAObject()->deleteGap(p.x(), 1);
    } else {
        editor->getMSAObject()->deleteGap(p.y(), p.x(), 1);
    }
}

void MSAEditorSequenceArea::sl_alignmentModified() {
    int aliLen = editor->getAlignmentLen();
    setFirstVisibleBase(qBound(0, startPos, aliLen-countSpaceForBases(false)));
    setCursorPos(qMin(cursorPos.x(), aliLen-1));
    updateHScrollBar();
    update();
}

void MSAEditorSequenceArea::sl_sequenceListModified() {
    sl_alignmentModified();
}

void MSAEditorSequenceArea::sl_buildStaticToolbar(GObjectView* v, QToolBar* t) {
    Q_UNUSED(v);
    t->addAction(gotoAction);
    t->addAction(removeGapColumnsAction);
    t->addAction(removeAllGapsAction);
}

void MSAEditorSequenceArea::sl_buildStaticMenu(GObjectView* v, QMenu* m) {
    Q_UNUSED(v);
    buildMenu(m);
}

void MSAEditorSequenceArea::sl_buildContextMenu(GObjectView* v, QMenu* m) {
    Q_UNUSED(v);
    buildMenu(m);
}

void MSAEditorSequenceArea::buildMenu(QMenu* m) {
    QAction* copyMenuAction = GUIUtils::findAction(m->actions(), MSAE_MENU_COPY);
    m->insertAction(copyMenuAction, gotoAction);

    QMenu* editMenu = GUIUtils::findSubMenu(m, MSAE_MENU_EDIT);
    assert(editMenu!=NULL);
    
    QList<QAction*> actions; actions << insSymAction << insColAction 
        << delSymAction << delColAction 
        << removeGapColumnsAction << removeAllGapsAction;

    editMenu->insertActions(editMenu->isEmpty() ? NULL : editMenu->actions().first(), actions);
}


void MSAEditorSequenceArea::sl_delSym() {
    del(cursorPos, false);
}

void MSAEditorSequenceArea::sl_delCol() {
    del(cursorPos, true);
}

void MSAEditorSequenceArea::sl_insSym() {
    ins(cursorPos, false);
}

void MSAEditorSequenceArea::sl_insCol() {
    ins(cursorPos, true);
}

void MSAEditorSequenceArea::sl_goto() {
    QDialog dlg;
    dlg.setModal(true);
    dlg.setWindowTitle(tr("Go To"));
    int aliLen = editor->getAlignmentLen();
    PositionSelector* ps = new PositionSelector(&dlg, 1, aliLen, true);
    connect(ps, SIGNAL(si_positionChanged(int)), SLOT(sl_onPosChangeRequest(int)));
    dlg.exec();
    delete ps;
}

void MSAEditorSequenceArea::sl_onPosChangeRequest(int pos) {
    centerPos(pos-1);
    setCursorPos(pos-1);
}

void MSAEditorSequenceArea::sl_lockedStateChanged() {
    updateActions();
}

void MSAEditorSequenceArea::centerPos(const QPoint& pos) {
    assert(isPosInRange(pos));
    int newStartPos = qMax(0, pos.x() - getNumVisibleBases(false)/2);
    setFirstVisibleBase(newStartPos);

    int newStartSeq = qMax(0, pos.y() - ui->nameList->getNumVisibleSequences(false)/2);
    ui->nameList->setFirstVisibleSequence(newStartSeq);
}


void MSAEditorSequenceArea::centerPos(int pos) {
    centerPos(QPoint(pos, cursorPos.y()));
}


void MSAEditorSequenceArea::wheelEvent (QWheelEvent * we) {
    bool toMin = we->delta() > 0;
    if (we->modifiers() == 0) {
        ui->shBar->triggerAction(toMin ? QAbstractSlider::SliderSingleStepSub : QAbstractSlider::SliderSingleStepAdd);
    }  else if (we->modifiers() & Qt::SHIFT) {
        ui->nameList->verticalScrollBar()->triggerAction(toMin ? QAbstractSlider::SliderSingleStepSub : QAbstractSlider::SliderSingleStepAdd);
    }
    QWidget::wheelEvent(we);
}

void MSAEditorSequenceArea::sl_removeColumnsWithGaps() {
    MAlignmentObject* msa = editor->getMSAObject();
    assert(!msa->isStateLocked());
    MAlignment ma = msa->getMAlignment();
    QList<int> columnsWithGaps;
    for (int c = 0, nc = ma.getLength(); c < nc; c++) {
        bool onlyGaps = true;
        foreach(const MAlignmentItem& item, ma.alignedSeqs) {
            if (item.sequence[c] != MAlignment_GapChar) {
                onlyGaps = false;
                break;
            }
        }
        if (onlyGaps) {
            columnsWithGaps.append(c);
        }
    }
    if (columnsWithGaps.isEmpty()) {
        return;
    }
    foreach(int c, columnsWithGaps) {
        for (int i = 0, n = ma.getNumSequences(); i < n; i++) {
            MAlignmentItem& item = ma.alignedSeqs[i];
            item.sequence[c] = 0;
        }
    }

    QBitArray gapMap(256);
    gapMap[0] = true;
    for (int i = 0, n = ma.getNumSequences(); i < n; i++) {
        MAlignmentItem& item = ma.alignedSeqs[i];
        int newLen = TextUtils::remove(item.sequence.data(), item.sequence.length(), gapMap);
        assert(newLen == item.sequence.length() - columnsWithGaps.size());
        item.sequence.resize(newLen);
    }

    ma.normalizeModel();
    msa->setMAlignment(ma);
}

void MSAEditorSequenceArea::sl_removeAllGaps() {
    QBitArray gapMap(256);
    gapMap[MAlignment_GapChar] = true;
    
    MAlignmentObject* msa = editor->getMSAObject();
    assert(!msa->isStateLocked());
    MAlignment ma = msa->getMAlignment();
    bool changed = false;
    for (int i = 0, n = ma.getNumSequences(); i < n; i++) {
        MAlignmentItem& item = ma.alignedSeqs[i];
        int newLen = TextUtils::remove(item.sequence.data(), item.sequence.length(), gapMap);
        changed = changed || newLen != item.sequence.length();
        item.sequence.resize(newLen);
    }
    if (changed) {
        ma.normalizeModel();
        msa->setMAlignment(ma);
    }
}

//////////////////////////////////////////////////////////////////////////
MSAEditorColorScheme::MSAEditorColorScheme(QObject* p, bool amino) : QObject(p) {
    colorsPerChar.fill(Qt::white, 256);
    for (int i = 0; i < 256; i++) {
        colorsPerChar[i] = GUIUtils::genLightColor(QString((char)i));
    }

    //fine tune most used colors
    colorsPerChar['-'] = Qt::white;
    if (!amino) {
        //DNA
        colorsPerChar['A'] = colorsPerChar['a'] = QColor("#FCFF92"); // yellow
        colorsPerChar['C'] = colorsPerChar['c'] = QColor("#70F970"); // green
        colorsPerChar['T'] = colorsPerChar['t'] = QColor("#FF99B1"); // light red
        colorsPerChar['G'] = colorsPerChar['g'] = QColor("#4EADE1"); // light blue
        colorsPerChar['U'] = colorsPerChar['u'] = colorsPerChar['T'].lighter(120);
        colorsPerChar['N'] = colorsPerChar['n'] = colorsPerChar['-'].darker(103);
    } else {
        //amino groups: "KRH", "GPST", "FWY", "ILM"
        QColor krh("#FFEE00");
        colorsPerChar['K'] = colorsPerChar['k'] = krh;
        colorsPerChar['R'] = colorsPerChar['r'] = krh.darker(120);
        colorsPerChar['H'] = colorsPerChar['h'] = krh.lighter(120);

        QColor gpst("#FF5082");
        colorsPerChar['G'] = colorsPerChar['g'] = gpst;
        colorsPerChar['P'] = colorsPerChar['p'] = gpst.darker(120);
        colorsPerChar['S'] = colorsPerChar['s'] = gpst.lighter(120);
        colorsPerChar['T'] = colorsPerChar['t'] = gpst.lighter(150);

        QColor fwy("#3DF490");
        colorsPerChar['F'] = colorsPerChar['f'] = fwy;
        colorsPerChar['W'] = colorsPerChar['w'] = fwy.darker(120);
        colorsPerChar['Y'] = colorsPerChar['y'] = fwy.lighter(120);

        QColor ilm("#00ABED");
        colorsPerChar['I'] = colorsPerChar['i'] = ilm;
        colorsPerChar['L'] = colorsPerChar['l'] = ilm.darker(120);
        colorsPerChar['M'] = colorsPerChar['m'] = ilm.lighter(120);

        //fix some color overlaps:
        //e looks like q by default
        colorsPerChar['E'] = colorsPerChar['e'] = QColor("#C0BDBB"); //gray
        colorsPerChar['X'] = colorsPerChar['x'] = colorsPerChar['-'].darker(103);
    }
}



}//namespace

Generated by  Doxygen 1.6.0   Back to index