/* * 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; const unsigned int QtMoleculeList::update_times_per_second = 20; QtMoleculeList::QtMoleculeList( QtObservedInstanceBoard *_board) : update_timer(NULL), board(_board), callback_DirtyItems(boost::bind(&QtMoleculeList::informDirtyState, this, _1, _2, _3)) { setColumnCount(QtMoleculeItemFactory::COLUMNCOUNT); resetUpdateTimer(); connect(this,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(moleculeNameChanged(QStandardItem*))); connect(this, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(checkForVisibilityChange(QStandardItem*))); connect(board, SIGNAL(moleculeInserted(const moleculeId_t)), this, SLOT(moleculeInserted(const moleculeId_t))); connect(board, SIGNAL(moleculeRemoved(const moleculeId_t)), this, SLOT(moleculeRemoved(const moleculeId_t))); connect(board, SIGNAL(moleculeIndexChanged(const moleculeId_t,const moleculeId_t)), this, SLOT(moleculeIndexChanged(const moleculeId_t, const moleculeId_t))); } 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(const moleculeId_t _id) { // get ObservedMolecule from board QtObservedMolecule::ptr ObservedMolecule = board->getObservedMolecule(_id); boost::recursive_mutex::scoped_lock lock(listAccessing_mutex); newMolecules.push_back( ObservedMolecule ); } void QtMoleculeList::moleculeRemoved(const moleculeId_t _id) { boost::recursive_mutex::scoped_lock lock(map_mutex); KilledItemsPerMolecule_t::iterator iter = KilledItemsPerMolecule.find(_id); if (iter == KilledItemsPerMolecule.end()) KilledItemsPerMolecule.insert( std::make_pair(_id, 1)); else ++(iter->second); if (iter->second == QtMoleculeItem::COLUMNTYPES_MAX) { boost::recursive_mutex::scoped_lock lock(listAccessing_mutex); removedMolecules.push_back( _id ); } } template void exchangeKeys( T &_container, const moleculeId_t _oldid, const moleculeId_t _newid) { typename T::iterator iter = _container.find(_oldid); ASSERT(_container.find(_newid) == _container.end(), "exchangeKeys() - new id "+toString(_newid) +" already exists in container."); _container.insert( std::make_pair(_newid, iter->second) ); _container.erase(iter); } template void exchangeKeysInSet( T &_container, const moleculeId_t _oldid, const moleculeId_t _newid) { typename T::iterator iter = _container.find(_oldid); ASSERT(_container.find(_newid) == _container.end(), "exchangeKeys() - new id "+toString(_newid) +" already exists in container."); _container.insert( _newid ); _container.erase(iter); } template void exchangeKeysOverAllColumns( T &_container, const moleculeId_t _oldid, const moleculeId_t _newid) { for (int i=0;isecond) ); MoleculeItemBiMap.left.erase(iter); } exchangeKeys(KilledItemsPerMolecule, _oldid, _newid); exchangeKeysOverAllColumns(dirtyMolItems, _oldid, _newid); exchangeKeysInSet(visibilityMolItems, _oldid, _newid); { std::vector::iterator iter = std::find(removedMolecules.begin(), removedMolecules.end(), _oldid); removedMolecules.erase(iter); removedMolecules.push_back(_newid); } exchangeKeysInSet(toBeMovedItems, _oldid, _newid); } bool QtMoleculeList::isMoleculeItemPresent(const moleculeId_t _molid) const { boost::recursive_mutex::scoped_lock lock(map_mutex); MoleculeItemBiMap_t::left_const_iterator iter = MoleculeItemBiMap.left.find(_molid); return ( iter != MoleculeItemBiMap.left.end()); } QtMoleculeItem * QtMoleculeList::MoleculeIdToItem(const moleculeId_t _molid) const { boost::recursive_mutex::scoped_lock lock(map_mutex); 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; } const moleculeId_t QtMoleculeList::ItemToMoleculeId(const QtMoleculeItem * const _item) const { boost::recursive_mutex::scoped_lock lock(map_mutex); const MoleculeItemBiMap_t::right_const_iterator iter = MoleculeItemBiMap.right.find(const_cast(_item)); if (iter != MoleculeItemBiMap.right.end()) return iter->second; else return -1; } 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 { boost::recursive_mutex::scoped_lock lock(map_mutex); FormulaTreeItemBiMap_t::left_const_iterator iter = FormulaItemBiMap.left.find(_formula); return ( iter != FormulaItemBiMap.left.end()); } QStandardItem * QtMoleculeList::FormulaToGroupItem(const std::string &_formula) const { boost::recursive_mutex::scoped_lock lock(map_mutex); 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 { boost::recursive_mutex::scoped_lock lock(map_mutex); 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(const moleculeId_t _id) const { boost::recursive_mutex::scoped_lock lock(refill_mutex); QtMoleculeItem * const item = MoleculeIdToItem(_id); ASSERT(item != NULL, "QtMoleculeList::MoleculeIdToIndex() - could not find item to " +toString(_id)); return indexFromItem(item); } const moleculeId_t QtMoleculeList::IndexToMoleculeId(const QModelIndex &_index) const { boost::recursive_mutex::scoped_lock lock(refill_mutex); QtMoleculeItem * const item = dynamic_cast(itemFromIndex(_index)); if (item == NULL) return -1; else return ItemToMoleculeId(item); } void QtMoleculeList::addGroupItem( QStandardItem *&mainitem, const std::string &_molecule_formula) { QList groupItems = QtMoleculeItemFactory::getInstance().createGroupItems(_molecule_formula); mainitem = groupItems.front(); { boost::recursive_mutex::scoped_lock lock(map_mutex); FormulaItemBiMap.left.insert( std::make_pair(_molecule_formula, mainitem) ); } invisibleRootItem()->appendRow(groupItems); } QList QtMoleculeList::createMoleculeItems( QtObservedMolecule::ptr &_ObservedMolecule, std::string &_molecule_formula) { QList molItems = QtMoleculeItemFactory::getInstance().createMoleculeItems( _ObservedMolecule, callback_DirtyItems); 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->getMolIndex(), 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->getMolIndex(), _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) { boost::recursive_mutex::scoped_lock lock(refill_mutex); const QModelIndex mol_index = indexFromItem(_item); QStandardItem *groupitem = _item->parent(); const QModelIndex group_index = groupitem->index(); { boost::recursive_mutex::scoped_lock lock(map_mutex); 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::resetUpdateTimer() { // check timer's presence if (update_timer == NULL) { update_timer = new QTimer(this); connect( update_timer, SIGNAL(timeout()), this, SLOT(checkState())); } else update_timer->stop(); // activate timer update_timer->start(1000/update_times_per_second); } bool QtMoleculeList::areAnyItemsDirty() { // get whether any items are dirty boost::recursive_mutex::scoped_lock lock(listAccessing_mutex); bool dirty = false; dirty |= !dirtyMolItems.empty(); dirty |= !visibilityMolItems.empty(); dirty |= !dirtyGroupItems.empty(); dirty |= !visibilityGroupItems.empty(); dirty |= !newMolecules.empty(); dirty |= !removedMolecules.empty(); dirty |= !toBeMovedItems.empty(); return dirty; } void QtMoleculeList::checkState() { const bool dirty = areAnyItemsDirty(); // update if required if (dirty) updateItemStates(); } void QtMoleculeList::checkForVisibilityChange(QStandardItem* _item) { // qDebug() << "Item changed called."; boost::recursive_mutex::scoped_lock lock(refill_mutex); if (_item->index().column() == QtMoleculeItem::VISIBILITY) { // qDebug() << "visibilityItem changed: " << (_item->checkState() ? "checked" : "unchecked"); boost::recursive_mutex::scoped_lock lock(listAccessing_mutex); if ((_item->parent() == NULL) || (_item->parent() == invisibleRootItem())) visibilityGroupItems.insert( std::make_pair( GroupItemToFormula(_item->parent()), QtMoleculeItem::VISIBILITY) ); else visibilityMolItems.insert( static_cast(_item)->getMoleculeId() ); } } void QtMoleculeList::setVisibilityForMoleculeItem(QtMoleculeItem* _item) { if (ChangingChildrensVisibility) return; boost::recursive_mutex::scoped_lock lock(refill_mutex); const bool visible = _item->checkState(); const moleculeId_t molid = _item->getMoleculeId(); std::string molecule_formula("illegal"); { boost::recursive_mutex::scoped_lock lock(map_mutex); 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 with id " +toString(_item->getMoleculeId())+" has not parent?"); // check whether we have to set the group item ChangingChildrensVisibility = true; 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); } ChangingChildrensVisibility = false; emit moleculesVisibilityChanged(_item->getMoleculeId(), visible); } void QtMoleculeList::setVisibilityForGroupItem(QStandardItem* _item) { if (ChangingChildrensVisibility) return; ChangingChildrensVisibility = true; boost::recursive_mutex::scoped_lock lock(refill_mutex); // 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 *molItem = dynamic_cast( groupitem->child(i, QtMoleculeItem::VISIBILITY)); if (molItem->checkState() != visible) { molItem->setCheckState(visible ? Qt::Checked : Qt::Unchecked); // emit signal emit moleculesVisibilityChanged(molItem->getMoleculeId(), 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; ChangingChildrensVisibility = false; } 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) { boost::recursive_mutex::scoped_lock lock(refill_mutex); // 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 moleculeId_t molid = iter->second; // change the name molecule * const mol = World::getInstance().getMolecule(MoleculeById(molid)); std::string cellValue = item->text().toStdString(); if ((mol->getName() != cellValue) && (!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(cellValue=="") { item->setText(QString(mol->getName().c_str())); } } } int QtMoleculeList::setOccurrence(QStandardItem * const _groupitem) { boost::recursive_mutex::scoped_lock lock(refill_mutex); 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 boost::recursive_mutex::scoped_lock lock(map_mutex); 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; } } std::string QtMoleculeList::readdItem(QtMoleculeItem *_molitem) { boost::recursive_mutex::scoped_lock lock(refill_mutex); // use takeRows of molecule .. QStandardItem *groupitem = _molitem->parent(); ASSERT( groupitem != NULL, "QtMoleculeList::readdItem() - mol item at "+toString(_molitem->index().row()) +" does not have a groupitem?"); // get updated formula from the item QStandardItem *formulaitem = _molitem->parent()->child(_molitem->index().row(), QtMoleculeItem::FORMULA); const std::string molecule_formula = formulaitem->text().toStdString(); QList mol_row = _molitem->parent()->takeRow(_molitem->index().row()); // .. and re-add where new formula fits if (!isGroupItemPresent(molecule_formula)) { // add new group item and formula entry addGroupItem(groupitem, molecule_formula); } else { groupitem = FormulaToGroupItem(molecule_formula); } ASSERT( groupitem != NULL, "QtMoleculeList::readdItem() - failed to create a sensible new groupitem"); // finally add again groupitem->appendRow(mol_row); return molecule_formula; } void QtMoleculeList::informDirtyState( const moleculeId_t _id, const QtMoleculeItem::COLUMNTYPES _type, const QtMoleculeItem::MoveTypes _movetype) { listAccessing_mutex.lock(); dirtyMolItems.insert( std::make_pair(_id, _type) ); listAccessing_mutex.unlock(); if (_movetype == QtMoleculeItem::NeedsMove) { // we have to convert whatever item raised the dirty signal to the first // item in the row as otherwise multiple items in the row are selected // as to be moved, i.e. the same row is moved multiple times listAccessing_mutex.lock(); toBeMovedItems.insert(_id); listAccessing_mutex.unlock(); } } void QtMoleculeList::updateItemStates() { /// copy lists such that new signals for dirty/.. may come in right away // TODO: if we had move semantics ... listAccessing_mutex.lock(); list_of_molecule_items_t dirtyMolItems_copy = dirtyMolItems; dirtyMolItems.clear(); list_of_molecules_t visibilityMolItems_copy = visibilityMolItems; visibilityMolItems.clear(); list_of_group_items_t dirtyGroupItems_copy = dirtyGroupItems; dirtyGroupItems.clear(); list_of_group_items_t visibilityGroupItems_copy = visibilityGroupItems; visibilityGroupItems.clear(); std::vector newMolecules_copy = newMolecules; newMolecules.clear(); std::vector removedMolecules_copy = removedMolecules; removedMolecules.clear(); list_of_molecules_t toBeMovedItems_copy = toBeMovedItems; toBeMovedItems.clear(); listAccessing_mutex.unlock(); // wait till initial refill has been executed boost::recursive_mutex::scoped_lock lock(refill_mutex); // LOG(1, "Starting update."); // remove removedMolecules from other lists. for (std::vector::const_iterator removeiter = removedMolecules_copy.begin(); removeiter != removedMolecules_copy.end(); ++removeiter) { for (unsigned int i=0;i< QtMoleculeItem::COLUMNTYPES_MAX; ++i) dirtyMolItems_copy.erase( std::make_pair(*removeiter,(QtMoleculeItem::COLUMNTYPES)i) ); toBeMovedItems_copy.erase(*removeiter); visibilityMolItems_copy.erase(*removeiter); } /// 1a. do the update for each dirty item for (list_of_molecule_items_t::const_iterator dirtyiter = dirtyMolItems_copy.begin(); dirtyiter != dirtyMolItems_copy.end(); ++dirtyiter) { if (!isMoleculeItemPresent(dirtyiter->first)) continue; QtMoleculeItem * const mol_item = getSpecificMoleculeItem( MoleculeIdToItem(dirtyiter->first), dirtyiter->second); // LOG(1, "Updating item " << mol_item); mol_item->updateState(); } /// 1b. do the visibility update for each dirty item for (list_of_molecules_t::const_iterator visiter = visibilityMolItems_copy.begin(); visiter != visibilityMolItems_copy.end(); ++visiter) { if (!isMoleculeItemPresent(*visiter)) continue; QtMoleculeItem * const visitem = getSpecificMoleculeItem( MoleculeIdToItem(*visiter), QtMoleculeItem::VISIBILITY ); // LOG(1, "Updating visibility of item " << visitem); setVisibilityForMoleculeItem(visitem); } /// 2. move all items that need to be moved typedef std::set formulas_t; formulas_t toBeSetOccurrence; for (list_of_molecules_t::const_iterator moveiter = toBeMovedItems_copy.begin(); moveiter != toBeMovedItems_copy.end(); ++moveiter) { boost::recursive_mutex::scoped_lock lock(map_mutex); // LOG(1, "Moving item " << molitem); MoleculeFormulaMap_t::iterator formulaiter = MoleculeFormulaMap.find(*moveiter); ASSERT( formulaiter != MoleculeFormulaMap.end(), "QtMoleculeList::updateItemStates() - formula of molecule " +toString(*moveiter)+" unknown."); // LOG(1, "Adding " << formulaiter->second << " to toBeSetOccurrence."); toBeSetOccurrence.insert( formulaiter->second ); if (!isMoleculeItemPresent(*moveiter)) continue; QtMoleculeItem *const molitem = MoleculeIdToItem(*moveiter); LOG(1, "Moving item " << molitem); // remove from formula<->molecule bimap with old formula LOG(1, "Removing " << formulaiter->second << " for " << formulaiter->first << " from MoleculeFormulaMap."); MoleculeFormulaMap.erase( formulaiter ); const std::string formula = readdItem(molitem); // and add to formula<->molecule bimap with updated formula LOG(1, "Adding " << formula << " for " << *moveiter << " to MoleculeFormulaMap."); MoleculeFormulaMap.insert( std::make_pair(*moveiter, formula) ); // LOG(1, "Adding " << formula << " to toBeSetOccurrence."); toBeSetOccurrence.insert( formula ); } /// 3. remove all items whose molecules have been removed for (std::vector::const_iterator removeiter = removedMolecules_copy.begin(); removeiter != removedMolecules_copy.end(); ++removeiter) { // LOG(1, "Removing molecule " << *removeiter); if (!isMoleculeItemPresent(*removeiter)) continue; QtMoleculeItem *item = MoleculeIdToItem(*removeiter); if (item != NULL) { const std::string formula = item->parent()->text().toStdString(); // LOG(1, "Adding " << formula << " to toBeSetOccurrence."); toBeSetOccurrence.insert( formula ); removeMoleculeItem(item); KilledItemsPerMolecule.erase( *removeiter ); } } // throw out items that we added by an update() while we are in this function listAccessing_mutex.lock(); for (std::vector::const_iterator removeiter = removedMolecules_copy.begin(); removeiter != removedMolecules_copy.end(); ++removeiter) { for (unsigned int i=0;i< QtMoleculeItem::COLUMNTYPES_MAX; ++i) dirtyMolItems.erase( std::make_pair(*removeiter,(QtMoleculeItem::COLUMNTYPES)i) ); toBeMovedItems.erase(*removeiter); visibilityMolItems.erase(*removeiter); } listAccessing_mutex.unlock(); // after that it is not a problem as items have been removed (hence signOff() was called) /// 4. instantiate all new items for (std::vector::iterator moliter = newMolecules_copy.begin(); moliter != newMolecules_copy.end(); ++moliter) { // LOG(1, "Adding molecule " << *moliter); // check that World knows the molecule still const std::string formula = addMolecule(*moliter); // LOG(1, "Adding " << formula << " to toBeSetOccurrence."); toBeSetOccurrence.insert( formula ); } /// 5a. update the group item's occurrence and visibility std::set RowsToRemove; for (std::set::const_iterator groupiter = toBeSetOccurrence.begin(); groupiter != toBeSetOccurrence.end(); ++groupiter) { // LOG(1, "Updating group item's occurence " << *groupiter); QStandardItem *groupitem = FormulaToGroupItem(*groupiter); const int index = setOccurrence(groupitem); if (index != -1) { // LOG(1, "Removing row of group item " << groupitem); RowsToRemove.insert(index); } } toBeSetOccurrence.clear(); // remove all visibility updates whose row is removed for (list_of_group_items_t::iterator visiter = visibilityGroupItems_copy.begin(); visiter != visibilityGroupItems_copy.end(); ) { QStandardItem * const groupitem = FormulaToGroupItem(visiter->first); if (RowsToRemove.count(groupitem->index().row()) != 0) { // LOG(1, "Removing vis item " << *visiter << " because of removed group item."); visibilityGroupItems_copy.erase(visiter++); } else ++visiter; } // update visibility of all group items for (list_of_group_items_t::iterator visiter = visibilityGroupItems_copy.begin(); visiter != visibilityGroupItems_copy.end(); ++visiter) { // LOG(1, "Updating visibility of item " << *visiter); QStandardItem * const groupitem = getSpecificGroupItem(FormulaToGroupItem(visiter->first), visiter->second); setVisibilityForGroupItem(groupitem); } /// 5b. remove all rows with 0 occurrence starting from last for (std::set::reverse_iterator riter = RowsToRemove.rbegin(); riter != RowsToRemove.rend(); ++riter) { // LOG(1, "Removing group item at row " << *riter); removeRows(*riter, 1, invisibleRootItem()->index()); } // and done // LOG(1, "Done with update."); }