Logo Search packages:      
Sourcecode: ugene version File versions

AnnotatedDNAView.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 "AnnotatedDNAView.h"
#include "AnnotatedDNAViewState.h"
#include "AnnotatedDNAViewFactory.h"
#include "AnnotatedDNAViewTasks.h"

#include "AnnotationsTreeView.h"
#include "ADVAnnotationCreation.h"
#include "ADVClipboard.h"
#include "ADVConstants.h"
#include "ADVAlignmentSupport.h"
#include "ADVSequenceObjectContext.h"
#include "ADVSingleSequenceWidget.h"
#include "ADVSplitWidget.h"

#include <core_api/AppContext.h>
#include <core_api/Log.h>
#include <core_api/ProjectModel.h>
#include <core_api/Task.h>
#include <core_api/DocumentModel.h>

#include <gobjects/DNASequenceObject.h>
#include <gobjects/AnnotationTableObject.h>
#include <gobjects/GObjectTypes.h>
#include <gobjects/AnnotationSettings.h>
#include <gobjects/GObjectUtils.h>
#include <gobjects/GObjectRelationRoles.h>

#include <selection/SelectionUtils.h>
#include <selection/AnnotationSelection.h>
#include <selection/DNASequenceSelection.h>

#include <util_find_dialog/FindDialog.h>//BUG:423: move to plugins!?

#include <util_gui/AnnotationSettingsDialogController.h>
#include <util_gui/GUIUtils.h>
#include <util_gui/CreateObjectRelationDialogController.h>
#include <util_gui/PositionSelector.h>

#include <QtGui/QVBoxLayout>
#include <QtGui/QScrollArea>
#include <QtGui/QToolBar>
#include <QtGui/QAction>
#include <QtGui/QMenu>
#include <QtGui/QMessageBox>

#include <memory>

namespace GB2 {

/* TRANSLATOR GB2::AnnotatedDNAView */

static LogCategory log(ULOG_CAT_ADV);

AnnotatedDNAView::AnnotatedDNAView(const QString& viewName, const QList<DNASequenceObject*>& dnaObjects) 
: GObjectView(AnnotatedDNAViewFactory::ID, viewName)
{
    timerId = 0;

    annotationSelection = new AnnotationSelection(this);
    annotationGroupSelection = new AnnotationGroupSelection(this);
    
    clipb = NULL;
    aliSupport = NULL;
    
    createAnnotationAction = (new ADVAnnotationCreation(this))->getCreateAnnotationAction();
    
    findDialogAction = new QAction(QIcon(":core/images/find_dialog.png"), tr("find"), this);
    findDialogAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_F));
    findDialogAction->setShortcutContext(Qt::WindowShortcut);
    connect(findDialogAction, SIGNAL(triggered()), SLOT(sl_onFindDialog()));

    annotationSettingsAction  = new QAction(QIcon(":core/images/annotation_settings.png"), tr("annotation_settings"), this);
    connect(annotationSettingsAction, SIGNAL(triggered()), SLOT(sl_onAnnotationSettings()));

    posSelectorAction = new QAction(QIcon(":core/images/goto.png"), tr("goto"), this);
    posSelectorAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_G));
    posSelectorAction->setShortcutContext(Qt::WindowShortcut);
    posSelectorAction->setObjectName(ADV_GOTO_ACTION);
    connect(posSelectorAction, SIGNAL(triggered()), SLOT(sl_onShowPosSelectorRequest()));

    toggleHLAction = new QAction("", this);
    connect(toggleHLAction, SIGNAL(triggered()), SLOT(sl_toggleHL()));

    mainSplitter = NULL;
    scrollArea = NULL;
    posSelector = NULL;
    posSelectorWidgetAction = NULL;
    annotationsView = NULL;
    focusedWidget = NULL;
    
    foreach(DNASequenceObject* dnaObj, dnaObjects) {
        addObject(dnaObj);
    }
}

QWidget* AnnotatedDNAView::createWidget() {
    assert(scrollArea == NULL);
    
    mainSplitter = new QSplitter(Qt::Vertical);
    //mainSplitter->setOpaqueResize(false);
    mainSplitter->setMaximumHeight(200);
    connect(mainSplitter, SIGNAL(splitterMoved(int, int)), SLOT(sl_splitterMoved(int, int)));

    mainSplitter->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(mainSplitter, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(sl_onContextMenuRequested(const QPoint &)));

    scrollArea = new QScrollArea();
    scrollArea->setWidgetResizable(true);
    mainSplitter->addWidget(scrollArea);
    mainSplitter->setStretchFactor(mainSplitter->count()-1, 5);
    
    
    scrolledWidget = new QWidget(scrollArea);
    scrolledWidgetLayout = new QVBoxLayout();
    scrolledWidgetLayout->setContentsMargins(0, 0, 0, 0);
    scrolledWidgetLayout->setSpacing(0);
    scrolledWidget->setBackgroundRole(QPalette::Light);

    foreach(ADVSequenceObjectContext* seqCtx, seqContexts) {
        ADVSingleSequenceWidget* block = new ADVSingleSequenceWidget(seqCtx, this);
        addSequenceWidget(block);
    }
    
    annotationsView = new AnnotationsTreeView(this);
    mainSplitter->addWidget(annotationsView);
    mainSplitter->setStretchFactor(mainSplitter->count()-1, 1);

    scrolledWidget->setLayout(scrolledWidgetLayout);
    
    //TODO: scroll area does not restore focus for last active child widget after Alt-Tab...
    scrollArea->setWidget(scrolledWidget);
    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
    
    clipb = new ADVClipboard(this);
    aliSupport = new ADVAlignmentSupport(this);

    mainSplitter->installEventFilter(this);
    mainSplitter->setAcceptDrops(true);
    
    if (!seqViews.isEmpty()) {
        setFocusedSequenceWidget(seqViews.first());
    }

//add view global shortcuts
    mainSplitter->addAction(toggleHLAction);

    return mainSplitter;
}

void AnnotatedDNAView::sl_splitterMoved(int pos, int index) {
    // WORKAROUND: looks like a QT bug:
    // ADVSequenceWidgets get paint events as needed, but scrolledWidget is over-painted by splitter's handle
    // to reproduce it open any complex (like 3d structure) view and pull the splitter handle upward slowly
    // -> workaround: update geometry for scrollArea or repaint main splitter's ares (todo: recheck effect)
    Q_UNUSED(pos);
    Q_UNUSED(index);
    mainSplitter->repaint(scrollArea->geometry());

    /*if (timerId!=0) {
        killTimer(timerId);
    }
    timerId = startTimer(100);*/
}

void AnnotatedDNAView::timerEvent(QTimerEvent *e) {
    //see comment for sl_splitterMoved()
    Q_UNUSED(e);
    assert(timerId!=0);
    killTimer(timerId);
    timerId = 0;

    QWidget* w = scrollArea;
    QRect orig = w->geometry();
    QRect tmp = orig; tmp.adjust(0, 0, 1, 1);
    w->setGeometry(tmp);
    w->setGeometry(orig);
}

void AnnotatedDNAView::updateScrollAreaHeight() {
    if (!scrolledWidget->isVisible()) {
        return;
    }

    int fw = scrollArea->frameWidth();
    int mh = fw * 2;
    foreach(ADVSequenceWidget* v, seqViews) {
        mh+=v->height();
    }
    scrollArea->setMaximumHeight(mh);
    scrolledWidgetLayout->activate();
}

AnnotatedDNAView::~AnnotatedDNAView() {
    if (posSelector!=NULL) {
        delete posSelector;
    }
}

bool AnnotatedDNAView::eventFilter(QObject* o, QEvent* e) {
    if (o == mainSplitter) {
        if (e->type() == QEvent::DragEnter || e->type() == QEvent::Drop) {
            QDropEvent* de = (QDropEvent*)e;
            const QMimeData* md = de->mimeData();
            const GObjectMimeData* gomd = qobject_cast<const GObjectMimeData*>(md);
            if (gomd != NULL) {
                if (e->type() == QEvent::DragEnter) {
                    de->acceptProposedAction();
                } else {
                    GObject* obj = gomd->objPtr.data();
                    if (obj!=NULL) {
                        QString err = tryAddObject(obj);
                        if (!err.isEmpty()) {
                            QMessageBox::critical(NULL, tr("error"), err);
                        } 
                    }
                }
            }
        } 
    } else if (e->type() == QEvent::Resize) {
        ADVSequenceWidget* v = qobject_cast<ADVSequenceWidget*>(o);
        if ( v!=NULL ) {
            updateScrollAreaHeight();
        }
    }

    return false;
}

void AnnotatedDNAView::setFocusedSequenceWidget(ADVSequenceWidget* v) {
    if (v == focusedWidget) {
        return;
    }
    ADVSequenceWidget* prevFocus = focusedWidget;
    focusedWidget = v;
    emit si_focusChanged(prevFocus, focusedWidget);
}

bool AnnotatedDNAView::onObjectRemoved(GObject* o) {
    if (o->getGObjectType() == GObjectTypes::ANNOTATION_TABLE) {
        AnnotationTableObject* ao = qobject_cast<AnnotationTableObject*>(o);
        annotationSelection->removeObjectAnnotations(ao);
        foreach(ADVSequenceObjectContext* seqCtx, seqContexts) {
            if (seqCtx->getAnnotationObjects().contains(ao)) {
                seqCtx->removeAnnotationObject(ao);
                break;
            }
        }
        annotations.removeOne(ao);
        emit si_annotationObjectRemoved(ao);
    } else if (o->getGObjectType() == GObjectTypes::DNA_SEQUENCE) {
        DNASequenceObject* seqObj = qobject_cast<DNASequenceObject*>(o);
        ADVSequenceObjectContext* seqCtx = getSequenceContext(seqObj);
        if (seqCtx!=NULL) {
            foreach(ADVSequenceWidget* w, seqCtx->getSequenceWidgets()) {
                removeSequenceWidget(w);
            }
            foreach(AnnotationTableObject* ao, seqCtx->getAnnotationObjects()) {
                removeObject(ao);
            }
            seqContexts.removeOne(seqCtx);
            delete seqCtx;
        }
    }

    GObjectView::onObjectRemoved(o);
    return seqContexts.isEmpty();
}

void AnnotatedDNAView::buildStaticToolbar(QToolBar* tb) {
    tb->addAction(createAnnotationAction);
    tb->addAction(annotationSettingsAction);

    tb->addSeparator();
    tb->addAction(clipb->getCopySequenceAction());
    tb->addAction(clipb->getCopyComplementAction());
    tb->addAction(clipb->getCopyTranslationAction());
    tb->addAction(clipb->getCopyComplementTranslationAction());
    tb->addAction(clipb->getCopyAnnotationSequenceAction());
    tb->addAction(clipb->getCopyAnnotationSequenceTranslationAction());
    tb->addSeparator();
    
    if (posSelector == NULL && !seqContexts.isEmpty()) {
        int len = seqContexts.first()->getSequenceLen();
        posSelector = new PositionSelector(tb, 1, len);
        connect(posSelector, SIGNAL(si_positionChanged(int)), SLOT(sl_onPosChangeRequest(int)));
        posSelectorWidgetAction = tb->addWidget(posSelector);
    }  else {
        tb->addAction(posSelectorWidgetAction);
    }

    
    GObjectView::buildStaticToolbar(tb);
}

void AnnotatedDNAView::buildStaticMenu(QMenu* m) {
    m->addAction(posSelectorAction);
    clipb->addCopyMenu(m);
    m->addSeparator();
    addAddMenu(m);
    addAnalyseMenu(m);
    addExportMenu(m);
    addRemoveMenu(m);
    m->addSeparator();

 
    m->addAction(annotationSettingsAction);

    annotationsView->adjustStaticMenu(m);

    GObjectView::buildStaticMenu(m);
}

ADVSequenceWidget* AnnotatedDNAView::findSequenceWidgetByPos(const QPoint& globalPos) const {
    foreach(ADVSequenceWidget* slv, seqViews) {
        const QRect& rect = slv->rect();
        QPoint localPos = slv->mapFromGlobal(globalPos);
        if (rect.contains(localPos)) {
            return slv;
        }
    }
    return NULL;
}

void AnnotatedDNAView::addAnalyseMenu(QMenu* m) {
    QMenu* am = m->addMenu(tr("analyse_menu"));
    am->menuAction()->setObjectName(ADV_MENU_ANALYSE);
    am->addAction(findDialogAction);
}


void AnnotatedDNAView::addAddMenu(QMenu* m) {
    QMenu* am = m->addMenu(tr("add_menu"));
    am->menuAction()->setObjectName(ADV_MENU_ADD);
    am->addAction(createAnnotationAction);
}

void AnnotatedDNAView::addExportMenu(QMenu* m) {
    QMenu* em = m->addMenu(tr("export_menu"));
    em->menuAction()->setObjectName(ADV_MENU_EXPORT); //at least export alignment action will be here
}

void AnnotatedDNAView::addRemoveMenu(QMenu* m) {
    QMenu* rm = m->addMenu(tr("remove_menu"));
    rm->menuAction()->setObjectName(ADV_MENU_REMOVE);
}


Task* AnnotatedDNAView::updateViewTask(const QString& stateName, const QVariantMap& stateData) {
    return new UpdateAnnotatedDNAViewTask(this, stateName, stateData);
}

QVariantMap AnnotatedDNAView::saveState() {
    if (closing) {
        return QVariantMap();
    }
    QVariantMap state = AnnotatedDNAViewState::saveState(this);
    foreach(ADVSequenceWidget* sw, seqViews) {
        sw->saveState(state);
    }
    foreach(ADVSplitWidget* w, splitWidgets) {
        w->saveState(state);
    }
    annotationsView->saveState(state);
    return state;
}

void AnnotatedDNAView::saveWidgetState() {
    annotationsView->saveWidgetState();
}


bool AnnotatedDNAView::canAddObject(GObject* obj) {
    if (GObjectView::canAddObject(obj)) {
        return true;
    }
    if (isChildWidgetObject(obj)) {
            return true;
    }
    if (obj->getGObjectType() == GObjectTypes::DNA_SEQUENCE) {
        return true;
    }
    if (obj->getGObjectType()!=GObjectTypes::ANNOTATION_TABLE) {
            return false;
    }
    //todo: add annotations related to sequence object not in view (sobj) and add 'sobj' too the view ?
    bool hasRelation = false;
    foreach(ADVSequenceObjectContext* soc, seqContexts) {
        if (obj->hasObjectRelation(soc->getSequenceObject(), GObjectRelationRole::SEQUENCE)) {
            hasRelation = true;
            break;
        }
    }
    return hasRelation;
}

bool AnnotatedDNAView::isChildWidgetObject(GObject* obj) const {
    foreach(ADVSequenceWidget* lv, seqViews) {
        if (lv->isWidgetOnlyObject(obj)) {
            return true;
        }
    }
    
    foreach(ADVSplitWidget* sw,  splitWidgets) {
        if (sw->acceptsGObject(obj)) {
            return true;
        }
    }
    
     return false;
}


void AnnotatedDNAView::addSequenceWidget(ADVSequenceWidget* v) {
    assert(!seqViews.contains(v));
    seqViews.append(v);
    QList<ADVSequenceObjectContext*> contexts = v->getSequenceContexts();
    foreach(ADVSequenceObjectContext* c, contexts) {
        c->addSequenceWidget(v);
    }
    scrolledWidgetLayout->insertWidget(0, v);
    v->setVisible(true);
    v->installEventFilter(this);
    updateScrollAreaHeight();
    emit si_sequenceWidgetAdded(v);
}


void AnnotatedDNAView::removeSequenceWidget(ADVSequenceWidget* v) {
    assert(seqViews.contains(v));
    int idx = seqViews.indexOf(v);
    assert(idx>=0);
    
    //fix focus
    if (focusedWidget == v) {
        if (idx + 1 < seqViews.size()) {
            setFocusedSequenceWidget(seqViews[idx+1]);
        } else if (idx -1 >= 0) {
            setFocusedSequenceWidget(seqViews[idx-1]);
        } else {
            setFocusedSequenceWidget(NULL);
        }
    }
    
    //remove widget
    seqViews.removeOne(v);
    v->hide();

    QList<ADVSequenceObjectContext*> contexts = v->getSequenceContexts();
    foreach(ADVSequenceObjectContext* c, contexts) {
        c->removeSequenceWidget(v);
    }
    emit si_sequenceWidgetRemoved(v);
    scrolledWidgetLayout->removeWidget(v);
    delete v;
    //v->deleteLater(); //problem: updates for 'v' after seqCtx is destroyed
    updateScrollAreaHeight();
}


void AnnotatedDNAView::sl_onContextMenuRequested(const QPoint & scrollAreaPos) {
    QMenu m;

    QPoint globalPos = scrollArea->mapToGlobal(scrollAreaPos);
    m.addAction(posSelectorAction); 
    m.addSeparator();
    clipb->addCopyMenu(&m);
    m.addSeparator()->setObjectName(ADV_MENU_SECTION1_SEP);;
    addAddMenu(&m);
    addAnalyseMenu(&m);
    addExportMenu(&m);
    addRemoveMenu(&m);
    m.addSeparator()->setObjectName(ADV_MENU_SECTION2_SEP);
    
    if (annotationSelection->getSelection().size() == 1) {
        Annotation* a = annotationSelection->getSelection().first().annotation;
        toggleHLAction->setText(tr("Toggle '%1' highlight").arg(a->getAnnotationName()));

        AnnotationSettingsRegistry* asr = AppContext::getAnnotationsSettingsRegistry();
        const AnnotationSettings* asettings = asr->getSettings(a->getAnnotationName());
        QIcon icon = GUIUtils::createSquareIcon(asettings->color, 10);
        toggleHLAction->setIcon(icon);

        m.addAction(toggleHLAction);
    }
    m.addAction(annotationSettingsAction);

    if (focusedWidget!=NULL) {
        focusedWidget->buildPopupMenu(m);
    }
    emit si_buildPopupMenu(this, &m);

    m.exec(QCursor::pos());
}


void AnnotatedDNAView::sl_onFindDialog() {
    ADVSequenceObjectContext* c = getSequenceInFocus();
    if (c != NULL) {
        FindDialog::runDialog(c);
    }
}

void AnnotatedDNAView::sl_onAnnotationSettings() {
    AnnotationSettingsDialogController ad(scrollArea);
    ad.exec();
}

void AnnotatedDNAView::sl_toggleHL() {
    if (annotationSelection->isEmpty()) {
        return;
    }
    QString name = annotationSelection->getSelection().first().annotation->getAnnotationName();
    AnnotationSettings* as = new AnnotationSettings(AppContext::getAnnotationsSettingsRegistry()->getSettings(name));
    as->visible = !as->visible;
    QList<AnnotationSettings*> l; l<<as;
    AppContext::getAnnotationsSettingsRegistry()->changeSettings(l);
}

QString AnnotatedDNAView::tryAddObject(GObject* o) {
    QList<ADVSequenceObjectContext*> rCtx;
    if (o->getGObjectType() == GObjectTypes::ANNOTATION_TABLE) {
        rCtx = findRelatedSequenceContexts(o);
        if (rCtx.isEmpty()) {
            //ask user if to create new association
            CreateObjectRelationDialogController d(o, getSequenceGObjectsWithContexts(), GObjectRelationRole::SEQUENCE, true);
            d.relationHintLabel->setText(tr("associate_with_sequence_label"));
            d.exec();
            rCtx = findRelatedSequenceContexts(o);
            if (rCtx.isEmpty()) {
                return "";
            }
        }
    }
    return addObject(o);
}

QString AnnotatedDNAView::addObject(GObject* o) {
    QList<ADVSequenceObjectContext*> rCtx;
    if (o->getGObjectType() == GObjectTypes::ANNOTATION_TABLE) {
        rCtx = findRelatedSequenceContexts(o);
        if (rCtx.isEmpty()) {
            return tr("no_object_relation_found");
        }
    } 
    QString res = GObjectView::addObject(o);
    if (!res.isEmpty()) {
        return res;
    }

    bool internalViewObject = isChildWidgetObject(o);
    if (internalViewObject) {
        return "";
    }
   
    if (o->getGObjectType() == GObjectTypes::DNA_SEQUENCE) {
        DNASequenceObject* dnaObj = qobject_cast<DNASequenceObject*>(o);
        ADVSequenceObjectContext* sc = new ADVSequenceObjectContext(this, dnaObj);
        seqContexts.append(sc);
        //if mainSplitter==NULL -> its view initialization and widgets will be added later
        if (mainSplitter!=NULL && !isChildWidgetObject(dnaObj)) { 
            ADVSingleSequenceWidget* block = new ADVSingleSequenceWidget(sc, this);
            addSequenceWidget(block);
        }
        addRelatedAnnotations(sc);
        emit si_sequenceAdded(sc);
    } else if (o->getGObjectType() == GObjectTypes::ANNOTATION_TABLE) {
        AnnotationTableObject* ao = qobject_cast<AnnotationTableObject*>(o);
        assert(ao!=NULL);
        annotations.append(ao);
        foreach(ADVSequenceObjectContext* sc, rCtx) {
            sc->addAnnotationObject(ao);
        }
        emit si_annotationObjectAdded(ao);

    }
    return "";
}

QList<ADVSequenceObjectContext*> AnnotatedDNAView::findRelatedSequenceContexts(GObject* obj) const {
    QSet<GObject*> relatedObjects = GObjectUtils::selectRelations(obj, GObjectTypes::DNA_SEQUENCE, GObjectRelationRole::SEQUENCE, objects);
    QList<ADVSequenceObjectContext*> res;
    foreach(GObject* seqObj, relatedObjects) {
        DNASequenceObject* dnaObj = qobject_cast<DNASequenceObject*>(seqObj);
        ADVSequenceObjectContext* ctx = getSequenceContext(dnaObj);
        res.append(ctx);
    }
    return res;
}

void AnnotatedDNAView::sl_onPosChangeRequest(int pos) {
    log.trace(tr("center_change_request_%1").arg(pos));
    ADVSequenceWidget* seqBlock = getSequenceWidgetInFocus();
    assert(seqBlock!=NULL);
    seqBlock->centerPosition(pos-1);
}

void AnnotatedDNAView::sl_onShowPosSelectorRequest() {
    ADVSequenceObjectContext* seqCtx = getSequenceInFocus();
    assert(seqCtx!=NULL);
    QDialog dlg;
    dlg.setModal(true);
    dlg.setWindowTitle(tr("Go To"));
    std::auto_ptr<PositionSelector> ps(new PositionSelector(&dlg, 1, seqCtx->getSequenceLen(), true));
    connect(ps.get(), SIGNAL(si_positionChanged(int)), SLOT(sl_onPosChangeRequest(int)));
    dlg.exec();
}

void AnnotatedDNAView::insertWidgetIntoSplitter(ADVSplitWidget* splitWidget) {
    assert(mainSplitter!=NULL);
    mainSplitter->insertWidget(0, splitWidget);
    mainSplitter->setStretchFactor(0, 1);
    splitWidgets.append(splitWidget);
}

void AnnotatedDNAView::unregisterSplitWidget(ADVSplitWidget* splitWidget) {
    splitWidgets.removeOne(splitWidget);
}

ADVSequenceObjectContext* AnnotatedDNAView::getSequenceContext(AnnotationTableObject* obj) const {
    assert(annotations.contains(obj));
    foreach(ADVSequenceObjectContext* seqCtx, seqContexts) {
        if(seqCtx->getAnnotationObjects().contains(obj)) {
            return seqCtx;
        }
    }
    return NULL;
}

ADVSequenceObjectContext* AnnotatedDNAView::getSequenceInFocus() const {
    ADVSequenceWidget* w = getSequenceWidgetInFocus();
    return w == NULL ? NULL : w->getActiveSequenceContext();
}

QList<ADVSequenceObjectContext*> AnnotatedDNAView::getAllSeqContextsInFocus() const {
    return getSequenceWidgetInFocus()->getSequenceContexts();
}

ADVSequenceObjectContext* AnnotatedDNAView::getSequenceContext(DNASequenceObject* obj) const {
    foreach(ADVSequenceObjectContext* seqCtx, seqContexts) {
        if(seqCtx->getSequenceObject() == obj) {
            return seqCtx;
        }
    }
    return NULL;
}

ADVSequenceObjectContext* AnnotatedDNAView::getSequenceContext(const GObjectReference& r) const {
    foreach(ADVSequenceObjectContext* seqCtx, seqContexts) {
        GObjectReference ref(seqCtx->getSequenceObject());
        if (ref == r) {
            return seqCtx;
        }
    }
    return NULL;
}

void AnnotatedDNAView::addRelatedAnnotations(ADVSequenceObjectContext* seqCtx) {
    QList<GObject*> annotations = GObjectUtils::findObjectsRelatedToObjectByRole(seqCtx->getSequenceObject(), 
        GObjectTypes::ANNOTATION_TABLE, GObjectRelationRole::SEQUENCE, GObjectUtils::findAllObjects(GObjectTypes::ANNOTATION_TABLE));

    foreach(GObject* ao, annotations) {
        if (objects.contains(ao)) {
            seqCtx->addAnnotationObject(qobject_cast<AnnotationTableObject*>(ao));
        } else {
            addObject(ao);
        }
    }
}


void AnnotatedDNAView::sl_onDocumentAdded(Document* d) {
    GObjectView::sl_onDocumentAdded(d);
    importDocAnnotations(d);
}
 
void AnnotatedDNAView::importDocAnnotations(Document* doc) {
    QList<GObject*> docObjects = doc->getObjects();
    foreach(GObject* o, docObjects) {
        if (o->getGObjectType() != GObjectTypes::ANNOTATION_TABLE) {
            continue;
        }
        QList<ADVSequenceObjectContext*> cList = findRelatedSequenceContexts(o);
        if (cList.isEmpty()) {
            continue;
        }
        addObject(o);
    }
}

void AnnotatedDNAView::sl_onDocumentLoadedStateChanged() {
    Document* d = qobject_cast<Document*>(sender());
    importDocAnnotations(d);
    GObjectView::sl_onDocumentLoadedStateChanged();
}

QList<DNASequenceObject*> AnnotatedDNAView::getSequenceObjectsWithContexts() const {
    QList<DNASequenceObject*> res;
    foreach(ADVSequenceObjectContext* cx, seqContexts) {
        res.append(cx->getSequenceObject());
    }
    return res;
}

QList<GObject*> AnnotatedDNAView::getSequenceGObjectsWithContexts() const {
    QList<GObject*> res;
    foreach(ADVSequenceObjectContext* cx, seqContexts) {
        res.append(cx->getSequenceObject());
    }
    return res;
}

void AnnotatedDNAView::updateState(const AnnotatedDNAViewState& s) {
    if (!s.isValid()) {
        return;
    }
    QList<GObjectReference> objs =  s.getSequenceObjects();
    QList<LRegion> regs =  s.getSequenceSelections();
    assert(objs.size() == regs.size());
    
    //TODO: sync seq object lists
    //TODO: sync annotation object lists

    for (int i=0; i < objs.size(); i++) {
        const GObjectReference& ref = objs[i];
        const LRegion& reg = regs[i];
        ADVSequenceObjectContext* seqCtx = getSequenceContext(ref);
        if (seqCtx == NULL) {
            continue;
        }
        LRegion wholeSeq(0, seqCtx->getSequenceLen());
        LRegion finalSel = reg.intersect(wholeSeq);
        seqCtx->getSequenceSelection()->clear();
        if (!finalSel.isEmpty()) {
            seqCtx->getSequenceSelection()->addRegion(finalSel);
        }
    }
    foreach(ADVSequenceWidget* sw, seqViews) {
        sw->updateState(s.stateData);
    }

    foreach (ADVSplitWidget* w, splitWidgets) {
        w->updateState(s.stateData);
    }
    
    annotationsView->updateState(s.stateData);
}

}//namespace

Generated by  Doxygen 1.6.0   Back to index