/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2010-2012 University of Bonn. All rights reserved.
*
*
* This file is part of MoleCuilder.
*
* MoleCuilder 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 2 of the License, or
* (at your option) any later version.
*
* MoleCuilder 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 MoleCuilder. If not, see .
*/
/*
* QtMoleculeList.cpp
*
* Created on: Jan 21, 2010
* Author: crueger
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include "QtMoleculeList.hpp"
#include
#include
#include "UIElements/Views/Qt4/MoleculeList/QtMoleculeItem.hpp"
#include "UIElements/Views/Qt4/MoleculeList/QtMoleculeItemFactory.hpp"
#include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp"
#include
#include
#include
//#include "CodePatterns/MemDebug.hpp"
#include "CodePatterns/Log.hpp"
#include "CodePatterns/Observer/Notification.hpp"
#include "Atom/atom.hpp"
#include "Actions/MoleculeAction/ChangeNameAction.hpp"
#include "Actions/SelectionAction/Molecules/PopMoleculesAction.hpp"
#include "Actions/SelectionAction/Molecules/PushMoleculesAction.hpp"
#include "Actions/SelectionAction/Molecules/MoleculeByIdAction.hpp"
#include "Actions/ActionQueue.hpp"
#include "Actions/ActionSequence.hpp"
#include "Actions/ActionTrait.hpp"
#include "Actions/MakroAction.hpp"
#include "Descriptors/MoleculeIdDescriptor.hpp"
#include "Formula.hpp"
#include "molecule.hpp"
using namespace std;
QtMoleculeList::QtMoleculeList(
QtObservedInstanceBoard *_board,
QObject *_parent) :
QStandardItemModel(_parent),
board(_board),
observer(_board),
nameIsChanged(false)
{
setColumnCount(QtMoleculeItemFactory::COLUMNCOUNT);
connect(this,SIGNAL(itemChanged(QStandardItem*)),
this,SLOT(moleculeNameChanged(QStandardItem*)));
connect(this, SIGNAL(itemChanged(QStandardItem*)),
this, SLOT(checkForVisibilityChange(QStandardItem*)));
connect(&observer, SIGNAL(MoleculeInserted(QtObservedMolecule::ptr)),
this, SLOT(moleculeInserted(QtObservedMolecule::ptr)));
connect(&observer, SIGNAL(MoleculeRemoved(ObservedValue_Index_t)),
this, SLOT(moleculeRemoved(ObservedValue_Index_t)));
connect(&observer, SIGNAL(FormulaChanged(const QtObservedMolecule::ptr)),
this, SLOT(formulaChanged(const QtObservedMolecule::ptr)));
connect(&observer, SIGNAL(NameChanged(const QtObservedMolecule::ptr)),
this, SLOT(nameChanged(const QtObservedMolecule::ptr)));
connect(&observer, SIGNAL(AtomCountChanged(const QtObservedMolecule::ptr)),
this, SLOT(atomcountChanged(const QtObservedMolecule::ptr)));
}
QtMoleculeList::~QtMoleculeList()
{}
QVariant QtMoleculeList::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) {
if (section < QtMoleculeItem::COLUMNTYPES_MAX)
return QString(QtMoleculeItemFactory::COLUMNNAMES[section]);
}
}
return QVariant();
}
void QtMoleculeList::moleculeInserted(QtObservedMolecule::ptr _mol)
{
LOG(1, "Adding molecule " << _mol->getMolName());
// check that World knows the molecule still
const std::string formula = addMolecule(_mol);
LOG(1, "Adding " << formula << " to toBeSetOccurrence.");
setOccurrence(FormulaToGroupItem(formula));
}
void QtMoleculeList::moleculeRemoved(ObservedValue_Index_t _id)
{
LOG(1, "Removing molecule " << _id);
if (!isMoleculeItemPresent(_id)) {
ELOG(1, "QtMoleculeItem to id " << _id << " has disappeared before removal.");
return;
}
QtMoleculeItem *item = MoleculeIdToItem(_id);
if (item != NULL) {
const std::string formula = item->parent()->text().toStdString();
LOG(1, "Adding " << formula << " to toBeSetOccurrence.");
QStandardItem * const groupitem = FormulaToGroupItem(formula);
// first remove molitem to reduce count
removeMoleculeItem(item);
const int removeindex = setOccurrence(groupitem);
if (removeindex != -1) {
LOG(1, "Removing row of group item to " << formula);
removeRows(removeindex, 1, invisibleRootItem()->index());
}
}
}
bool QtMoleculeList::isMoleculeItemPresent(ObservedValue_Index_t _molid) const
{
MoleculeItemBiMap_t::left_const_iterator iter =
MoleculeItemBiMap.left.find(_molid);
return ( iter != MoleculeItemBiMap.left.end());
}
QtMoleculeItem * QtMoleculeList::MoleculeIdToItem(ObservedValue_Index_t _molid) const
{
MoleculeItemBiMap_t::left_const_iterator iter =
MoleculeItemBiMap.left.find(_molid);
ASSERT( iter != MoleculeItemBiMap.left.end(),
"QtMoleculeList::MoleculeIdToItem() - could not find item to id "
+toString(_molid));
return iter->second;
}
ObservedValue_Index_t QtMoleculeList::ItemToMoleculeId(const QtMoleculeItem * const _item) const
{
const MoleculeItemBiMap_t::right_const_iterator iter =
MoleculeItemBiMap.right.find(const_cast(_item));
if (iter != MoleculeItemBiMap.right.end())
return iter->second;
else
return NULL;
}
QtMoleculeItem * QtMoleculeList::getSpecificMoleculeItem(
const QtMoleculeItem * const _item,
const enum QtMoleculeItem::COLUMNTYPES _type) const
{
QStandardItem *parent_item = _item->parent();
ASSERT( parent_item != NULL,
"QtMoleculeList::getSpecificMoleculeItem() - parent of molecule item is NULL");
return static_cast(parent_item->child(_item->index().row(), _type));
}
bool QtMoleculeList::isGroupItemPresent(const std::string &_formula) const
{
FormulaTreeItemBiMap_t::left_const_iterator iter =
FormulaItemBiMap.left.find(_formula);
return ( iter != FormulaItemBiMap.left.end());
}
QStandardItem * QtMoleculeList::FormulaToGroupItem(const std::string &_formula) const
{
FormulaTreeItemBiMap_t::left_const_iterator iter =
FormulaItemBiMap.left.find(_formula);
ASSERT( iter != FormulaItemBiMap.left.end(),
"QtMoleculeList::FormulaToGroupItem() - could not find item to formula "
+toString(_formula));
return iter->second;
}
const std::string& QtMoleculeList::GroupItemToFormula(const QStandardItem * const _item) const
{
static std::string emptystring;
const FormulaTreeItemBiMap_t::right_const_iterator iter =
FormulaItemBiMap.right.find(const_cast(_item));
if (iter != FormulaItemBiMap.right.end())
return iter->second;
else
return emptystring;
}
QStandardItem * QtMoleculeList::getSpecificGroupItem(
const QStandardItem * const _item,
const enum QtMoleculeItem::COLUMNTYPES _type) const
{
return invisibleRootItem()->child(_item->index().row(), _type);
}
const QModelIndex QtMoleculeList::MoleculeIdToIndex(ObservedValue_Index_t _id) const
{
QtMoleculeItem * const item = MoleculeIdToItem(_id);
ASSERT(item != NULL,
"QtMoleculeList::MoleculeIdToIndex() - could not find item to "
+toString(_id));
return indexFromItem(item);
}
ObservedValue_Index_t QtMoleculeList::IndexToMoleculeId(const QModelIndex &_index) const
{
QtMoleculeItem * const item = dynamic_cast(itemFromIndex(_index));
if (item == NULL)
return NULL;
else
return ItemToMoleculeId(item);
}
void QtMoleculeList::addGroupItem(
QStandardItem *&mainitem,
const std::string &_molecule_formula)
{
QList groupItems =
QtMoleculeItemFactory::createGroupItems(_molecule_formula);
mainitem = groupItems.front();
FormulaItemBiMap.left.insert( std::make_pair(_molecule_formula, mainitem) );
if (FormulaVisibilityCountMap.count(_molecule_formula) == 0)
FormulaVisibilityCountMap.insert( std::make_pair(_molecule_formula, 0));
invisibleRootItem()->appendRow(groupItems);
}
QList QtMoleculeList::createMoleculeItems(
QtObservedMolecule::ptr &_ObservedMolecule,
std::string &_molecule_formula)
{
QList molItems =
QtMoleculeItemFactory::createMoleculeItems(_ObservedMolecule);
QtMoleculeItem *mol_item = dynamic_cast(molItems.front());
ASSERT( mol_item != NULL,
"QtMoleculeList::createMoleculeItems() - item from factory was not a QtMoleculeItem?");
MoleculeItemBiMap.left.insert( std::make_pair(_ObservedMolecule->getIndex(), mol_item) );
QStandardItem *formulaitem = molItems.at(QtMoleculeItem::FORMULA);
ASSERT( formulaitem != NULL,
"QtMoleculeList::createMoleculeItems() - Formula item not created by factory?");
_molecule_formula = formulaitem->text().toStdString();
LOG(1, "Adding " << _molecule_formula << " for "
<< _ObservedMolecule->getMolIndex() << " to MoleculeFormulaMap.");
MoleculeFormulaMap.insert( std::make_pair( _ObservedMolecule->getIndex(), _molecule_formula) );
// LOG(1, "Inserting molecule " << _molid << ": " << _molecule_formula);
return molItems;
}
std::string QtMoleculeList::addMolecule(QtObservedMolecule::ptr &_ObservedMolecule)
{
// find group if already in list
QStandardItem *groupItem = NULL;
// create molecule items and obtain the molecule's formula
std::string molecule_formula;
QList molItems = createMoleculeItems(_ObservedMolecule, molecule_formula);
// new molecule type -> create new group
if (!isGroupItemPresent(molecule_formula)){
// insert new formula entry into visibility
#ifndef NDEBUG
std::pair< FormulaVisibilityCountMap_t::iterator, bool> visibilityinserter =
#endif
FormulaVisibilityCountMap.insert(
std::make_pair( molecule_formula, (unsigned int)0) );
ASSERT( visibilityinserter.second,
"QtMoleculeList::refill() - molecule with formula "
+molecule_formula+" already in FormulaVisibilityCountMap.");
// create item and place into Map with formula as key
addGroupItem(groupItem, molecule_formula);
} else {
groupItem = FormulaToGroupItem(molecule_formula);
}
ASSERT( groupItem != NULL,
"QtMoleculeList::addMolecule() - item with id "+toString(_ObservedMolecule->getMolIndex())
+" has no parent?");
groupItem->appendRow(molItems);
return molecule_formula;
}
void QtMoleculeList::removeMoleculeItem(QtMoleculeItem * const _item)
{
const QModelIndex mol_index = indexFromItem(_item);
QStandardItem *groupitem = _item->parent();
const QModelIndex group_index = groupitem->index();
{
MoleculeItemBiMap_t::right_iterator removeiter =
MoleculeItemBiMap.right.find(_item);
ASSERT( removeiter != MoleculeItemBiMap.right.end(),
"QtMoleculeList::removeMoleculeItem() - could not find item in MoleculeBiMap.");
// LOG(1, "Erasing molecule " << (removeiter->second));
{
MoleculeFormulaMap_t::iterator removeformulaiter =
MoleculeFormulaMap.find(removeiter->second);
ASSERT( removeformulaiter != MoleculeFormulaMap.end(),
"QtMoleculeList::removeMoleculeItem() - could not find id "
+toString(removeiter->second)+" in MoleculeFormulaMap.");
LOG(1, "Removing " << removeformulaiter->second << " for "
<< removeformulaiter->first << " from MoleculeFormulaMap.");
MoleculeFormulaMap.erase( removeformulaiter );
}
MoleculeItemBiMap.right.erase(removeiter);
}
removeRows(mol_index.row(), 1, group_index);
}
void QtMoleculeList::checkForVisibilityChange(QStandardItem* _item)
{
// qDebug() << "Item changed called.";
if (_item->index().column() == QtMoleculeItem::VISIBILITY) {
// qDebug() << "visibilityItem changed: " << (_item->checkState() ? "checked" : "unchecked");
if ((_item->parent() == NULL) || (_item->parent() == invisibleRootItem())) {
LOG(1, "Updating visibility of group item " << _item);
setVisibilityForGroupItem(_item);
} else {
LOG(1, "Updating visibility of item " << _item);
setVisibilityForMoleculeItem( assert_cast(_item) );
}
}
}
void QtMoleculeList::setVisibilityForMoleculeItem(QtMoleculeItem* _item)
{
const bool visible = _item->checkState();
const ObservedValue_Index_t molid = _item->getMoleculeIndex();
std::string molecule_formula("illegal");
{
const MoleculeFormulaMap_t::const_iterator formulaiter =
MoleculeFormulaMap.find(molid);
ASSERT( formulaiter != MoleculeFormulaMap.end(),
"QtMoleculeList::setVisibilityForMoleculeItem() - formula of molecule "
+toString(molid)+" unknown.");
molecule_formula = formulaiter->second;
}
ASSERT( FormulaVisibilityCountMap.count(molecule_formula) != 0,
"QtMoleculeList::setVisibilityForMoleculeItem() - molecule with formula " +molecule_formula
+" is not present in FormulaVisibilityCountMap.");
// get parent
QStandardItem *groupItem = _item->parent();
QStandardItem *visgroupItem = getSpecificGroupItem(groupItem, QtMoleculeItem::VISIBILITY);
ASSERT( groupItem != NULL,
"QtMoleculeList::setVisibilityForMoleculeItem() - item to "
+toString(molid)+" has not parent?");
// check whether we have to set the group item
if (visible) {
++(FormulaVisibilityCountMap[molecule_formula]);
// compare with occurence/total number of molecules
if (FormulaVisibilityCountMap[molecule_formula] ==
(unsigned int)(groupItem->rowCount()))
visgroupItem->setCheckState(Qt::Checked);
} else {
--(FormulaVisibilityCountMap[molecule_formula]);
// none selected anymore?
if (FormulaVisibilityCountMap[molecule_formula] == 0)
visgroupItem->setCheckState(Qt::Unchecked);
}
emit moleculesVisibilityChanged(molid, visible);
}
void QtMoleculeList::setVisibilityForGroupItem(QStandardItem* _item)
{
// go through all children, but don't enter for groupItem once more
const bool visible = _item->checkState();
QStandardItem *groupitem = getSpecificGroupItem(_item, QtMoleculeItem::NAME);
for (int i=0;irowCount();++i) {
QtMoleculeItem * const molItem = dynamic_cast(
groupitem->child(i, QtMoleculeItem::VISIBILITY));
if (molItem->checkState() != visible) {
molItem->setCheckState(visible ? Qt::Checked : Qt::Unchecked);
// emit signal
emit moleculesVisibilityChanged(molItem->getMoleculeIndex(), visible);
}
}
// set current number of visible children
const std::string molecule_formula =
GroupItemToFormula( getSpecificGroupItem(_item, QtMoleculeItem::NAME) );
FormulaVisibilityCountMap_t::iterator countiter =
FormulaVisibilityCountMap.find(molecule_formula);
ASSERT( countiter != FormulaVisibilityCountMap.end(),
"QtMoleculeList::setVisibilityForGroupItem() - molecules "+molecule_formula
+" have no entry in visibility count map?");
countiter->second = visible ? groupitem->rowCount() : 0;
}
static
MoleCuilder::MakroAction *constructMakroRenameAction(
MoleCuilder::ActionSequence &sequence,
const std::string &_new_name,
const moleculeId_t _molid
)
{
MoleCuilder::ActionQueue &AQ = MoleCuilder::ActionQueue::getInstance();
MoleCuilder::ActionTrait trait("change-single-molecule-name");
sequence.addAction(AQ.getActionByName("push-molecule-selection").clone(MoleCuilder::Action::NonInteractive));
MoleCuilder::Action * const selectaction =
AQ.getActionByName("select-molecule-by-id").clone(MoleCuilder::Action::NonInteractive);
{
std::stringstream molid_string;
molid_string << toString(_molid);
selectaction->setOptionValue("select-molecule-by-id", molid_string.str());
}
sequence.addAction(selectaction);
MoleCuilder::Action * const changeaction =
AQ.getActionByName("change-molname").clone(MoleCuilder::Action::NonInteractive);
changeaction->setOptionValue("change-molname", _new_name);
sequence.addAction(changeaction);
sequence.addAction(AQ.getActionByName("pop-molecule-selection").clone(MoleCuilder::Action::NonInteractive));
MoleCuilder::MakroAction* makroaction =
new MoleCuilder::MakroAction(trait, sequence);
return makroaction;
}
void QtMoleculeList::moleculeNameChanged(QStandardItem* item)
{
// check whether name change came from outside
if (nameIsChanged)
return;
// obtain molecule id
if ( item->index().column() == QtMoleculeItem::NAME) {
QtMoleculeItem *molitem = assert_cast(item);
MoleculeItemBiMap_t::right_const_iterator iter = MoleculeItemBiMap.right.find(molitem);
ASSERT( iter != MoleculeItemBiMap.right.end(),
"QtMoleculeList::moleculeChanged() - name of unknown molecule changed.");
const ObservedValue_Index_t index = iter->second;
const moleculeId_t molid = board->getMoleculeIdToIndex(index);
// change the name
const std::string cellValue = item->text().toStdString();
const QtObservedMolecule::ptr mol = board->getObservedMolecule(index);
if (cellValue != mol->getMolName()) {
if (!cellValue.empty()) {
// create actions such that we may undo
static MoleCuilder::ActionSequence sequence;
MoleCuilder::MakroAction *makroaction =
constructMakroRenameAction(sequence, cellValue, molid);
MoleCuilder::ActionQueue &AQ = MoleCuilder::ActionQueue::getInstance();
AQ.registerAction(makroaction);
AQ.queueAction("change-single-molecule-name", MoleCuilder::Action::NonInteractive);
} else {
if (mol) {
LOG(2, "WARNING: Not setting changing molecule " << mol->getMolName()
<< " to empty.");
QtMoleculeItem * const molitem = assert_cast(item);
molitem->updateState(mol);
}
}
}
}
}
int QtMoleculeList::setOccurrence(QStandardItem * const _groupitem)
{
ASSERT( _groupitem != NULL,
"QtMoleculeList::setOccurrence() - group item at "+toString(_groupitem)
+" is NULL");
QModelIndex modelindex = _groupitem->index();
ASSERT( modelindex.isValid(),
"QtMoleculeList::setOccurrence() - groupitem not associated to model anymore.");
const int index = modelindex.row();
QStandardItem *parent_item =
_groupitem->parent() == NULL ? invisibleRootItem() : _groupitem->parent();
ASSERT( parent_item != NULL,
"QtMoleculeList::setOccurrence() - group item at "+toString(index)
+" does not have a parent?");
QStandardItem *occ_item = parent_item->child(index, QtMoleculeItem::OCCURRENCE);
ASSERT( occ_item != NULL,
"QtMoleculeList::setOccurrence() - group item at "+toString(index)
+" does not have an occurrence?");
const int count = _groupitem->rowCount();
if (count == 0) {
// we have to remove the group item completely
const std::string molecule_formula = _groupitem->text().toStdString();
FormulaItemBiMap.left.erase(molecule_formula);
FormulaVisibilityCountMap.erase(molecule_formula);
return index;
} else {
occ_item->setText(QString::number(count));
return -1;
}
}
void QtMoleculeList::moveItem(
QtMoleculeItem *_molitem,
const std::string &_new_formula)
{
QStandardItem *groupitem = NULL;
// prohibit starting of selection actions
emit MayNotStartSelections();
// use takeRows of molecule ..
const QList mol_row = _molitem->parent()->takeRow(_molitem->index().row());
// .. and re-add where new formula fits
if (!isGroupItemPresent(_new_formula)) {
// add new group item and formula entry
addGroupItem(groupitem, _new_formula);
} else {
groupitem = FormulaToGroupItem(_new_formula);
}
ASSERT( groupitem != NULL,
"QtMoleculeList::readdItem() - failed to create a sensible new groupitem");
// finally add again
groupitem->appendRow(mol_row);
emit MayStartSelections();
}
void QtMoleculeList::formulaChanged(const QtObservedMolecule::ptr _mol)
{
// we need the id as identifier to the item
const ObservedValue_Index_t molid = _mol->getIndex();
LOG(3, "DEBUG: QtMoleculeList got formulaChanged for id " << molid);
QtMoleculeItem *const molitem = MoleculeIdToItem(molid);
// update item
{
QtMoleculeItem *const formulaitem = getSpecificMoleculeItem(molitem, QtMoleculeItem::FORMULA);
ASSERT(formulaitem != NULL,
"QtMoleculeList::formulaChanged() - could not item for FORMULA.");
formulaitem->updateState(_mol);
}
LOG(3, "DEBUG: Moving item to id " << molid);
const MoleculeFormulaMap_t::iterator formulaiter =
MoleculeFormulaMap.find(molid);
ASSERT( formulaiter != MoleculeFormulaMap.end(),
"QtMoleculeList::updateItemStates() - formula of molecule "
+toString(molid)+" unknown.");
// we get old formula from stored map and new formula from the ObservedMolecule
const std::string old_formula = formulaiter->second;
const std::string new_formula = _mol->getMolFormula();
// then we move the item if necessary
if (old_formula != new_formula) {
LOG(3, "DEBUG: Moving item " << molitem);
// remove from formula<->molecule bimap with old formula
LOG(4, "DEBUG: Removing " << old_formula << " for " << formulaiter->first << " from MoleculeFormulaMap.");
MoleculeFormulaMap.erase( formulaiter );
moveItem(molitem, new_formula);
// changing occurrences for old_formula with possible removal
const int removeindex = setOccurrence( FormulaToGroupItem(old_formula) );
if (removeindex != -1) {
LOG(3, "DEBUG: Removing row of group item to " << old_formula);
removeRows(removeindex, 1, invisibleRootItem()->index());
}
// and add to formula<->molecule bimap with updated new_formula
LOG(4, "DEBUG: Adding " << new_formula << " for " << molid << " to MoleculeFormulaMap.");
MoleculeFormulaMap.insert( std::make_pair(molid, new_formula) );
const int addindex = setOccurrence( FormulaToGroupItem(new_formula) );
ASSERT( addindex == -1,
"QtMoleculeList::formulaChanged() - add mol to new formula "+
toString(new_formula)+" made the row to be removed?");
}
}
void QtMoleculeList::atomcountChanged(const QtObservedMolecule::ptr _mol)
{
// we need the id as identifier to the items
const ObservedValue_Index_t molid = _mol->getIndex();
LOG(3, "DEBUG: QtMoleculeList got atomcountChanged for id " << molid);
QtMoleculeItem *const molitem = MoleculeIdToItem(molid);
// update items
QtMoleculeItem *const atomcountitem = getSpecificMoleculeItem(molitem, QtMoleculeItem::ATOMCOUNT);
ASSERT(atomcountitem != NULL,
"QtMoleculeList::atomcountChanged() - could not item for ATOMCOUNT.");
atomcountitem->updateState(_mol);
}
void QtMoleculeList::nameChanged(const QtObservedMolecule::ptr _mol)
{
nameIsChanged = true;
// we need the id as identifier to the items
const ObservedValue_Index_t molid = _mol->getIndex();
LOG(3, "DEBUG: QtMoleculeList got nameChanged for id " << molid);
QtMoleculeItem *const molitem = MoleculeIdToItem(molid);
// update items
QtMoleculeItem *const nameitem = getSpecificMoleculeItem(molitem, QtMoleculeItem::NAME);
ASSERT(nameitem != NULL,
"QtMoleculeList::nameChanged() - could not item for NAME.");
nameitem->updateState(_mol);
nameIsChanged = false;
}