source: src/UIElements/Views/Qt4/MoleculeList/QtMoleculeList.cpp@ d1831e

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since d1831e was 68989c, checked in by Frederik Heber <heber@…>, 9 years ago

Avoided use of getId() on molecules and atoms in Qt code where possible.

  • it is ok if we are inside O/O functions or functions called from these functions.
  • Property mode set to 100644
File size: 30.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * QtMoleculeList.cpp
25 *
26 * Created on: Jan 21, 2010
27 * Author: crueger
28 */
29
30// include config.h
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34
35#include "QtMoleculeList.hpp"
36
37#include <QModelIndex>
38#include <QDebug>
39
40#include "UIElements/Views/Qt4/MoleculeList/QtMoleculeItem.hpp"
41#include "UIElements/Views/Qt4/MoleculeList/QtMoleculeItemFactory.hpp"
42
43#include <boost/bind.hpp>
44#include <boost/thread/locks.hpp>
45#include <iostream>
46
47#include "CodePatterns/MemDebug.hpp"
48
49#include "CodePatterns/Log.hpp"
50#include "CodePatterns/Observer/Notification.hpp"
51
52#include "Atom/atom.hpp"
53#include "Actions/MoleculeAction/ChangeNameAction.hpp"
54#include "Actions/SelectionAction/Molecules/PopMoleculesAction.hpp"
55#include "Actions/SelectionAction/Molecules/PushMoleculesAction.hpp"
56#include "Actions/SelectionAction/Molecules/MoleculeByIdAction.hpp"
57#include "Actions/ActionQueue.hpp"
58#include "Actions/ActionSequence.hpp"
59#include "Actions/ActionTrait.hpp"
60#include "Actions/MakroAction.hpp"
61#include "Descriptors/MoleculeIdDescriptor.hpp"
62#include "Formula.hpp"
63#include "molecule.hpp"
64#include "MoleculeListClass.hpp"
65
66using namespace std;
67
68const unsigned int QtMoleculeList::update_times_per_second = 20;
69
70QtMoleculeList::QtMoleculeList() :
71 Observer("QtMoleculeList"),
72 ChangingChildrensVisibility(false),
73 update_timer(NULL),
74 callback_DirtyItems(boost::bind(&QtMoleculeList::informDirtyState, this, _1, _2, _3)),
75 callback_subjectKilledItems(boost::bind(&QtMoleculeList::receiveSubjectKilled, this, _1))
76{
77 setColumnCount(QtMoleculeItemFactory::COLUMNCOUNT);
78
79 World::getInstance().signOn(this, World::MoleculeInserted);
80
81 refill();
82
83 connect(this,SIGNAL(itemChanged(QStandardItem*)),this,SLOT(moleculeNameChanged(QStandardItem*)));
84 connect(this, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(checkForVisibilityChange(QStandardItem*)), Qt::DirectConnection);
85}
86
87QtMoleculeList::~QtMoleculeList()
88{
89 World::getInstance().signOff(this, World::MoleculeInserted);
90}
91
92QVariant QtMoleculeList::headerData(int section, Qt::Orientation orientation, int role) const
93{
94 if (role == Qt::DisplayRole) {
95 if (orientation == Qt::Horizontal) {
96 if (section < QtMoleculeItem::COLUMNTYPES_MAX)
97 return QString(QtMoleculeItemFactory::COLUMNNAMES[section]);
98 }
99 }
100 return QVariant();
101}
102
103void QtMoleculeList::update(Observable *publisher) {
104 ASSERT(0,
105 "QtMoleculeList::update() - we did not sign up for any global updates.");
106}
107
108bool QtMoleculeList::isMoleculeItemPresent(const moleculeId_t _molid) const
109{
110 boost::recursive_mutex::scoped_lock lock(map_mutex);
111 MoleculeItemBiMap_t::left_const_iterator iter =
112 MoleculeItemBiMap.left.find(_molid);
113 return ( iter != MoleculeItemBiMap.left.end());
114}
115
116QtMoleculeItem * QtMoleculeList::MoleculeIdToItem(const moleculeId_t _molid) const
117{
118 boost::recursive_mutex::scoped_lock lock(map_mutex);
119 MoleculeItemBiMap_t::left_const_iterator iter =
120 MoleculeItemBiMap.left.find(_molid);
121 ASSERT( iter != MoleculeItemBiMap.left.end(),
122 "QtMoleculeList::MoleculeIdToItem() - could not find item to id "
123 +toString(_molid));
124 return iter->second;
125}
126
127const moleculeId_t QtMoleculeList::ItemToMoleculeId(const QtMoleculeItem * const _item) const
128{
129 boost::recursive_mutex::scoped_lock lock(map_mutex);
130 const MoleculeItemBiMap_t::right_const_iterator iter =
131 MoleculeItemBiMap.right.find(const_cast<QtMoleculeItem * const>(_item));
132 if (iter != MoleculeItemBiMap.right.end())
133 return iter->second;
134 else
135 return -1;
136}
137
138QtMoleculeItem * QtMoleculeList::getSpecificMoleculeItem(
139 const QtMoleculeItem * const _item,
140 const enum QtMoleculeItem::COLUMNTYPES _type) const
141{
142 QStandardItem *parent_item = _item->parent();
143 ASSERT( parent_item != NULL,
144 "QtMoleculeList::getSpecificMoleculeItem() - parent of molecule item is NULL");
145 return static_cast<QtMoleculeItem *>(parent_item->child(_item->index().row(), _type));
146}
147
148bool QtMoleculeList::isGroupItemPresent(const std::string &_formula) const
149{
150 boost::recursive_mutex::scoped_lock lock(map_mutex);
151 FormulaTreeItemBiMap_t::left_const_iterator iter =
152 FormulaItemBiMap.left.find(_formula);
153 return ( iter != FormulaItemBiMap.left.end());
154}
155
156QStandardItem * QtMoleculeList::FormulaToGroupItem(const std::string &_formula) const
157{
158 boost::recursive_mutex::scoped_lock lock(map_mutex);
159 FormulaTreeItemBiMap_t::left_const_iterator iter =
160 FormulaItemBiMap.left.find(_formula);
161 ASSERT( iter != FormulaItemBiMap.left.end(),
162 "QtMoleculeList::FormulaToGroupItem() - could not find item to formula "
163 +toString(_formula));
164 return iter->second;
165}
166
167const std::string& QtMoleculeList::GroupItemToFormula(const QStandardItem * const _item) const
168{
169 boost::recursive_mutex::scoped_lock lock(map_mutex);
170 static std::string emptystring;
171 const FormulaTreeItemBiMap_t::right_const_iterator iter =
172 FormulaItemBiMap.right.find(const_cast<QStandardItem * const>(_item));
173 if (iter != FormulaItemBiMap.right.end())
174 return iter->second;
175 else
176 return emptystring;
177}
178
179QStandardItem * QtMoleculeList::getSpecificGroupItem(
180 const QStandardItem * const _item,
181 const enum QtMoleculeItem::COLUMNTYPES _type) const
182{
183 return invisibleRootItem()->child(_item->index().row(), _type);
184}
185
186const QModelIndex QtMoleculeList::MoleculeIdToIndex(const moleculeId_t _id) const
187{
188 boost::recursive_mutex::scoped_lock lock(refill_mutex);
189 QtMoleculeItem * const item = MoleculeIdToItem(_id);
190 ASSERT(item != NULL,
191 "QtMoleculeList::MoleculeIdToIndex() - could not find item to "
192 +toString(_id));
193 return indexFromItem(item);
194}
195
196const moleculeId_t QtMoleculeList::IndexToMoleculeId(const QModelIndex &_index) const
197{
198 boost::recursive_mutex::scoped_lock lock(refill_mutex);
199 QtMoleculeItem * const item = dynamic_cast<QtMoleculeItem *>(itemFromIndex(_index));
200 if (item == NULL)
201 return -1;
202 else
203 return ItemToMoleculeId(item);
204}
205
206void QtMoleculeList::receiveSubjectKilled(const moleculeId_t _id)
207{
208 boost::recursive_mutex::scoped_lock lock(map_mutex);
209 KilledItemsPerMolecule_t::iterator iter = KilledItemsPerMolecule.find(_id);
210 if (iter == KilledItemsPerMolecule.end())
211 KilledItemsPerMolecule.insert( std::make_pair(_id, 1));
212 else
213 ++(iter->second);
214 if (iter->second == QtMoleculeItem::COLUMNTYPES_MAX) {
215 boost::recursive_mutex::scoped_lock lock(listAccessing_mutex);
216 removedMolecules.push_back( _id );
217 }
218}
219
220void QtMoleculeList::recieveNotification(Observable *publisher, Notification_ptr notification)
221{
222 if (dynamic_cast<World *>(publisher) != NULL) {
223 switch (notification->getChannelNo()) {
224 case World::MoleculeInserted:
225 {
226 boost::recursive_mutex::scoped_lock lock(listAccessing_mutex);
227 const moleculeId_t molid = const_cast<const World &>(World::getInstance()).lastChangedMolId();
228 if (molid != (unsigned int )-1)
229 newMolecules.push_back( molid );
230 break;
231 }
232 default:
233 ASSERT(0, "QtMoleculeList::recieveNotification() - cannot get here, not subscribed to channel "
234 +toString(notification->getChannelNo()));
235 break;
236 }
237 }
238}
239
240void QtMoleculeList::addGroupItem(
241 QStandardItem *&mainitem,
242 const std::string &_molecule_formula)
243{
244 QList<QStandardItem *> groupItems =
245 QtMoleculeItemFactory::getInstance().createGroupItems(_molecule_formula);
246 mainitem = groupItems.front();
247 {
248 boost::recursive_mutex::scoped_lock lock(map_mutex);
249 FormulaItemBiMap.left.insert( std::make_pair(_molecule_formula, mainitem) );
250 }
251 invisibleRootItem()->appendRow(groupItems);
252}
253
254QList<QStandardItem *> QtMoleculeList::createMoleculeItems(
255 const moleculeId_t _molid,
256 std::string &_molecule_formula)
257{
258 QList<QStandardItem *> molItems =
259 QtMoleculeItemFactory::getInstance().createMoleculeItems(
260 _molid,
261 callback_DirtyItems,
262 callback_subjectKilledItems);
263 QtMoleculeItem *mol_item = dynamic_cast<QtMoleculeItem *>(molItems.front());
264 ASSERT( mol_item != NULL,
265 "QtMoleculeList::createMoleculeItems() - item from factory was not a QtMoleculeItem?");
266 {
267 boost::recursive_mutex::scoped_lock lock(map_mutex);
268 MoleculeItemBiMap.left.insert( std::make_pair(_molid, mol_item) );
269 }
270
271 QStandardItem *formulaitem = molItems.at(QtMoleculeItem::FORMULA);
272 ASSERT( formulaitem != NULL,
273 "QtMoleculeList::createMoleculeItems() - Formula item not created by factory?");
274 _molecule_formula = formulaitem->text().toStdString();
275 {
276 boost::recursive_mutex::scoped_lock lock(map_mutex);
277 LOG(1, "Adding " << _molecule_formula << " for " << _molid << " to MoleculeFormulaMap.");
278 MoleculeFormulaMap.insert( std::make_pair( _molid, _molecule_formula) );
279 }
280// LOG(1, "Inserting molecule " << _molid << ": " << _molecule_formula);
281 return molItems;
282}
283
284std::string QtMoleculeList::addMolecule(const molecule * const _mol)
285{
286 const moleculeId_t molid = _mol->getId();
287 // find group if already in list
288 QStandardItem *groupItem = NULL;
289
290 // create molecule items and obtain the molecule's formula
291 std::string molecule_formula;
292 QList<QStandardItem *> molItems = createMoleculeItems(molid, molecule_formula);
293
294 // new molecule type -> create new group
295 if (!isGroupItemPresent(molecule_formula)){
296 // insert new formula entry into visibility
297#ifndef NDEBUG
298 std::pair< FormulaVisibilityCountMap_t::iterator, bool> visibilityinserter =
299#endif
300 FormulaVisibilityCountMap.insert(
301 std::make_pair( molecule_formula, (unsigned int)0) );
302 ASSERT( visibilityinserter.second,
303 "QtMoleculeList::refill() - molecule with formula "
304 +molecule_formula+" already in FormulaVisibilityCountMap.");
305
306 // create item and place into Map with formula as key
307 addGroupItem(groupItem, molecule_formula);
308 } else {
309 groupItem = FormulaToGroupItem(molecule_formula);
310 }
311 ASSERT( groupItem != NULL,
312 "QtMoleculeList::addMolecule() - item with id "+toString(molid)
313 +" has no parent?");
314 groupItem->appendRow(molItems);
315
316 return molecule_formula;
317}
318
319void QtMoleculeList::removeMoleculeItem(QtMoleculeItem * const _item)
320{
321 boost::recursive_mutex::scoped_lock lock(refill_mutex);
322 const QModelIndex mol_index = indexFromItem(_item);
323 QStandardItem *groupitem = _item->parent();
324 const QModelIndex group_index = groupitem->index();
325 {
326 boost::recursive_mutex::scoped_lock lock(map_mutex);
327 MoleculeItemBiMap_t::right_iterator removeiter =
328 MoleculeItemBiMap.right.find(_item);
329 ASSERT( removeiter != MoleculeItemBiMap.right.end(),
330 "QtMoleculeList::removeMoleculeItem() - could not find item in MoleculeBiMap.");
331 // LOG(1, "Erasing molecule " << (removeiter->second));
332 {
333 MoleculeFormulaMap_t::iterator removeformulaiter =
334 MoleculeFormulaMap.find(removeiter->second);
335 ASSERT( removeformulaiter != MoleculeFormulaMap.end(),
336 "QtMoleculeList::removeMoleculeItem() - could not find id "
337 +toString(removeiter->second)+" in MoleculeFormulaMap.");
338 LOG(1, "Removing " << removeformulaiter->second << " for "
339 << removeformulaiter->first << " from MoleculeFormulaMap.");
340 MoleculeFormulaMap.erase( removeformulaiter );
341 }
342 MoleculeItemBiMap.right.erase(removeiter);
343 }
344 removeRows(mol_index.row(), 1, group_index);
345}
346
347void QtMoleculeList::refill()
348{
349 // check timer's presence
350 if (update_timer == NULL) {
351 update_timer = new QTimer(this);
352 connect( update_timer, SIGNAL(timeout()), this, SLOT(checkState()));
353 } else
354 update_timer->stop();
355
356 {
357 boost::recursive_mutex::scoped_lock refill_lock(refill_mutex);
358 boost::recursive_mutex::scoped_lock listAccessing_lock(listAccessing_mutex);
359
360 // LOG(1, "Clearing list.");
361
362 clear();
363 FormulaVisibilityCountMap.clear();
364 {
365 boost::recursive_mutex::scoped_lock lock(map_mutex);
366 FormulaItemBiMap.clear();
367 MoleculeFormulaMap.clear();
368 MoleculeItemBiMap.clear();
369 KilledItemsPerMolecule.clear();
370 }
371 dirtyMolItems.clear();
372 visibilityMolItems.clear();
373 visibilityGroupItems.clear();
374 newMolecules.clear();
375 removedMolecules.clear();
376 toBeMovedItems.clear();
377 }
378
379 const std::vector<const molecule*> &molecules =
380 const_cast<const World &>(World::getInstance()).getAllMolecules();
381 for (std::vector<const molecule*>::const_iterator iter = molecules.begin();
382 iter != molecules.end();
383 iter++)
384 addMolecule(*iter);
385
386 // activate timer
387 update_timer->start(1000/update_times_per_second);
388}
389
390bool QtMoleculeList::areAnyItemsDirty()
391{
392 // get whether any items are dirty
393 boost::recursive_mutex::scoped_lock lock(listAccessing_mutex);
394 bool dirty = false;
395 dirty |= !dirtyMolItems.empty();
396 dirty |= !visibilityMolItems.empty();
397 dirty |= !dirtyGroupItems.empty();
398 dirty |= !visibilityGroupItems.empty();
399 dirty |= !newMolecules.empty();
400 dirty |= !removedMolecules.empty();
401 dirty |= !toBeMovedItems.empty();
402 return dirty;
403}
404
405void QtMoleculeList::checkState()
406{
407 const bool dirty = areAnyItemsDirty();
408 // update if required
409 if (dirty)
410 updateItemStates();
411}
412
413void QtMoleculeList::subjectKilled(Observable *publisher)
414{}
415
416void QtMoleculeList::checkForVisibilityChange(QStandardItem* _item)
417{
418// qDebug() << "Item changed called.";
419
420 boost::recursive_mutex::scoped_lock lock(refill_mutex);
421 if (_item->index().column() == QtMoleculeItem::VISIBILITY) {
422// qDebug() << "visibilityItem changed: " << (_item->checkState() ? "checked" : "unchecked");
423 boost::recursive_mutex::scoped_lock lock(listAccessing_mutex);
424 if ((_item->parent() == NULL) || (_item->parent() == invisibleRootItem()))
425 visibilityGroupItems.insert( std::make_pair(
426 GroupItemToFormula(_item->parent()), QtMoleculeItem::VISIBILITY) );
427 else
428 visibilityMolItems.insert(
429 static_cast<QtMoleculeItem *>(_item)->getMoleculeId()
430 );
431 }
432}
433
434void QtMoleculeList::setVisibilityForMoleculeItem(QtMoleculeItem* _item)
435{
436 if (ChangingChildrensVisibility)
437 return;
438
439 boost::recursive_mutex::scoped_lock lock(refill_mutex);
440 const bool visible = _item->checkState();
441 const moleculeId_t molid = _item->getMoleculeId();
442 std::string molecule_formula("illegal");
443 {
444 boost::recursive_mutex::scoped_lock lock(map_mutex);
445 MoleculeFormulaMap_t::const_iterator formulaiter =
446 MoleculeFormulaMap.find(molid);
447 ASSERT( formulaiter != MoleculeFormulaMap.end(),
448 "QtMoleculeList::setVisibilityForMoleculeItem() - formula of molecule "
449 +toString(molid)+" unknown.");
450 molecule_formula = formulaiter->second;
451 }
452 ASSERT( FormulaVisibilityCountMap.count(molecule_formula) != 0,
453 "QtMoleculeList::setVisibilityForMoleculeItem() - molecule with formula " +molecule_formula
454 +" is not present in FormulaVisibilityCountMap.");
455
456 // get parent
457 QStandardItem *groupItem = _item->parent();
458 QStandardItem *visgroupItem = getSpecificGroupItem(groupItem, QtMoleculeItem::VISIBILITY);
459 ASSERT( groupItem != NULL,
460 "QtMoleculeList::setVisibilityForMoleculeItem() - item with id "
461 +toString(_item->getMoleculeId())+" has not parent?");
462 // check whether we have to set the group item
463
464 ChangingChildrensVisibility = true;
465 if (visible) {
466 ++(FormulaVisibilityCountMap[molecule_formula]);
467 // compare with occurence/total number of molecules
468 if (FormulaVisibilityCountMap[molecule_formula] ==
469 (unsigned int)(groupItem->rowCount()))
470 visgroupItem->setCheckState(Qt::Checked);
471 } else {
472 --(FormulaVisibilityCountMap[molecule_formula]);
473 // none selected anymore?
474 if (FormulaVisibilityCountMap[molecule_formula] == 0)
475 visgroupItem->setCheckState(Qt::Unchecked);
476 }
477 ChangingChildrensVisibility = false;
478
479 emit moleculesVisibilityChanged(_item->getMoleculeId(), visible);
480}
481
482void QtMoleculeList::setVisibilityForGroupItem(QStandardItem* _item)
483{
484 if (ChangingChildrensVisibility)
485 return;
486
487 ChangingChildrensVisibility = true;
488
489 boost::recursive_mutex::scoped_lock lock(refill_mutex);
490 // go through all children, but don't enter for groupItem once more
491 const bool visible = _item->checkState();
492 QStandardItem *groupitem = getSpecificGroupItem(_item, QtMoleculeItem::NAME);
493 for (int i=0;i<groupitem->rowCount();++i) {
494 QtMoleculeItem *molItem = dynamic_cast<QtMoleculeItem *>(
495 groupitem->child(i, QtMoleculeItem::VISIBILITY));
496 if (molItem->checkState() != visible) {
497 molItem->setCheckState(visible ? Qt::Checked : Qt::Unchecked);
498
499 // emit signal
500 emit moleculesVisibilityChanged(molItem->getMoleculeId(), visible);
501 }
502 }
503 // set current number of visible children
504 const std::string molecule_formula =
505 GroupItemToFormula( getSpecificGroupItem(_item, QtMoleculeItem::NAME) );
506 FormulaVisibilityCountMap_t::iterator countiter =
507 FormulaVisibilityCountMap.find(molecule_formula);
508 ASSERT( countiter != FormulaVisibilityCountMap.end(),
509 "QtMoleculeList::setVisibilityForGroupItem() - molecules "+molecule_formula
510 +" have no entry in visibility count map?");
511 countiter->second = visible ? groupitem->rowCount() : 0;
512
513 ChangingChildrensVisibility = false;
514}
515
516static
517MoleCuilder::MakroAction *constructMakroRenameAction(
518 MoleCuilder::ActionSequence &sequence,
519 const std::string &_new_name,
520 const moleculeId_t _molid
521 )
522{
523 MoleCuilder::ActionQueue &AQ = MoleCuilder::ActionQueue::getInstance();
524 MoleCuilder::ActionTrait trait("change-single-molecule-name");
525 sequence.addAction(AQ.getActionByName("push-molecule-selection").clone(MoleCuilder::Action::NonInteractive));
526 MoleCuilder::Action * const selectaction =
527 AQ.getActionByName("select-molecule-by-id").clone(MoleCuilder::Action::NonInteractive);
528 {
529 std::stringstream molid_string;
530 molid_string << toString(_molid);
531 selectaction->setOptionValue("select-molecule-by-id", molid_string.str());
532 }
533 sequence.addAction(selectaction);
534 MoleCuilder::Action * const changeaction =
535 AQ.getActionByName("change-molname").clone(MoleCuilder::Action::NonInteractive);
536 changeaction->setOptionValue("change-molname", _new_name);
537 sequence.addAction(changeaction);
538 sequence.addAction(AQ.getActionByName("pop-molecule-selection").clone(MoleCuilder::Action::NonInteractive));
539
540 MoleCuilder::MakroAction* makroaction =
541 new MoleCuilder::MakroAction(trait, sequence);
542 return makroaction;
543}
544
545void QtMoleculeList::moleculeNameChanged(QStandardItem* item)
546{
547 boost::recursive_mutex::scoped_lock lock(refill_mutex);
548 // obtain molecule id
549 if ( item->index().column() == QtMoleculeItem::NAME) {
550 QtMoleculeItem *molitem = assert_cast<QtMoleculeItem *>(item);
551 MoleculeItemBiMap_t::right_const_iterator iter = MoleculeItemBiMap.right.find(molitem);
552 ASSERT( iter != MoleculeItemBiMap.right.end(),
553 "QtMoleculeList::moleculeChanged() - name of unknown molecule changed.");
554 const moleculeId_t molid = iter->second;
555 // change the name
556 molecule * const mol = World::getInstance().getMolecule(MoleculeById(molid));
557 std::string cellValue = item->text().toStdString();
558 if ((mol->getName() != cellValue) && (!cellValue.empty())) {
559 // create actions such that we may undo
560 static MoleCuilder::ActionSequence sequence;
561 MoleCuilder::MakroAction *makroaction =
562 constructMakroRenameAction(sequence, cellValue, molid);
563 MoleCuilder::ActionQueue &AQ = MoleCuilder::ActionQueue::getInstance();
564 AQ.registerAction(makroaction);
565 AQ.queueAction("change-single-molecule-name", MoleCuilder::Action::NonInteractive);
566 } else if(cellValue=="") {
567 item->setText(QString(mol->getName().c_str()));
568 }
569}
570}
571
572
573int QtMoleculeList::setOccurrence(QStandardItem * const _groupitem)
574{
575 boost::recursive_mutex::scoped_lock lock(refill_mutex);
576 QModelIndex modelindex = _groupitem->index();
577 ASSERT( modelindex.isValid(),
578 "QtMoleculeList::setOccurrence() - groupitem not associated to model anymore.");
579 const int index = modelindex.row();
580 QStandardItem *parent_item =
581 _groupitem->parent() == NULL ? invisibleRootItem() : _groupitem->parent();
582 ASSERT( parent_item != NULL,
583 "QtMoleculeList::setOccurrence() - group item at "+toString(index)
584 +" does not have a parent?");
585 QStandardItem *occ_item = parent_item->child(index, QtMoleculeItem::OCCURRENCE);
586 ASSERT( occ_item != NULL,
587 "QtMoleculeList::setOccurrence() - group item at "+toString(index)
588 +" does not have an occurrence?");
589 const int count = _groupitem->rowCount();
590 if (count == 0) {
591 // we have to remove the group item completely
592 boost::recursive_mutex::scoped_lock lock(map_mutex);
593 const std::string molecule_formula = _groupitem->text().toStdString();
594 FormulaItemBiMap.left.erase(molecule_formula);
595 FormulaVisibilityCountMap.erase(molecule_formula);
596 return index;
597 } else {
598 occ_item->setText(QString::number(count));
599 return -1;
600 }
601}
602
603std::string QtMoleculeList::readdItem(QtMoleculeItem *_molitem)
604{
605 boost::recursive_mutex::scoped_lock lock(refill_mutex);
606 // use takeRows of molecule ..
607 QStandardItem *groupitem = _molitem->parent();
608 ASSERT( groupitem != NULL,
609 "QtMoleculeList::readdItem() - mol item at "+toString(_molitem->index().row())
610 +" does not have a groupitem?");
611 // get updated formula from the item
612 QStandardItem *formulaitem =
613 _molitem->parent()->child(_molitem->index().row(), QtMoleculeItem::FORMULA);
614 const std::string molecule_formula = formulaitem->text().toStdString();
615 QList<QStandardItem *> mol_row = _molitem->parent()->takeRow(_molitem->index().row());
616 // .. and re-add where new formula fits
617 if (!isGroupItemPresent(molecule_formula)) {
618 // add new group item and formula entry
619 addGroupItem(groupitem, molecule_formula);
620 } else {
621 groupitem = FormulaToGroupItem(molecule_formula);
622 }
623 ASSERT( groupitem != NULL,
624 "QtMoleculeList::readdItem() - failed to create a sensible new groupitem");
625 // finally add again
626 groupitem->appendRow(mol_row);
627
628 return molecule_formula;
629}
630
631void QtMoleculeList::informDirtyState(
632 const moleculeId_t _id,
633 const QtMoleculeItem::COLUMNTYPES _type,
634 const QtMoleculeItem::MoveTypes _movetype)
635{
636 listAccessing_mutex.lock();
637 dirtyMolItems.insert( std::make_pair(_id, _type) );
638 listAccessing_mutex.unlock();
639
640 if (_movetype == QtMoleculeItem::NeedsMove) {
641 // we have to convert whatever item raised the dirty signal to the first
642 // item in the row as otherwise multiple items in the row are selected
643 // as to be moved, i.e. the same row is moved multiple times
644 listAccessing_mutex.lock();
645 toBeMovedItems.insert(_id);
646 listAccessing_mutex.unlock();
647 }
648}
649
650void QtMoleculeList::updateItemStates()
651{
652 /// copy lists such that new signals for dirty/.. may come in right away
653 // TODO: if we had move semantics ...
654 listAccessing_mutex.lock();
655 list_of_molecule_items_t dirtyMolItems_copy = dirtyMolItems;
656 dirtyMolItems.clear();
657 list_of_molecules_t visibilityMolItems_copy = visibilityMolItems;
658 visibilityMolItems.clear();
659 list_of_group_items_t dirtyGroupItems_copy = dirtyGroupItems;
660 dirtyGroupItems.clear();
661 list_of_group_items_t visibilityGroupItems_copy = visibilityGroupItems;
662 visibilityGroupItems.clear();
663 std::vector<moleculeId_t> newMolecules_copy = newMolecules;
664 newMolecules.clear();
665 std::vector<moleculeId_t> removedMolecules_copy = removedMolecules;
666 removedMolecules.clear();
667 list_of_molecules_t toBeMovedItems_copy = toBeMovedItems;
668 toBeMovedItems.clear();
669 listAccessing_mutex.unlock();
670
671 // wait till initial refill has been executed
672 boost::recursive_mutex::scoped_lock lock(refill_mutex);
673
674// LOG(1, "Starting update.");
675
676 // remove removedMolecules from other lists.
677 for (std::vector<moleculeId_t>::const_iterator removeiter = removedMolecules_copy.begin();
678 removeiter != removedMolecules_copy.end(); ++removeiter) {
679 for (unsigned int i=0;i< QtMoleculeItem::COLUMNTYPES_MAX; ++i)
680 dirtyMolItems_copy.erase( std::make_pair(*removeiter,(QtMoleculeItem::COLUMNTYPES)i) );
681 toBeMovedItems_copy.erase(*removeiter);
682 visibilityMolItems_copy.erase(*removeiter);
683 }
684
685 /// 1a. do the update for each dirty item
686 for (list_of_molecule_items_t::const_iterator dirtyiter = dirtyMolItems_copy.begin();
687 dirtyiter != dirtyMolItems_copy.end(); ++dirtyiter) {
688 if (!isMoleculeItemPresent(dirtyiter->first))
689 continue;
690 QtMoleculeItem * const mol_item =
691 getSpecificMoleculeItem(
692 MoleculeIdToItem(dirtyiter->first),
693 dirtyiter->second);
694// LOG(1, "Updating item " << mol_item);
695 mol_item->updateState();
696 }
697
698 /// 1b. do the visibility update for each dirty item
699 for (list_of_molecules_t::const_iterator visiter = visibilityMolItems_copy.begin();
700 visiter != visibilityMolItems_copy.end(); ++visiter) {
701 if (!isMoleculeItemPresent(*visiter))
702 continue;
703 QtMoleculeItem * const visitem =
704 getSpecificMoleculeItem(
705 MoleculeIdToItem(*visiter),
706 QtMoleculeItem::VISIBILITY );
707// LOG(1, "Updating visibility of item " << visitem);
708 setVisibilityForMoleculeItem(visitem);
709 }
710
711 /// 2. move all items that need to be moved
712 typedef std::set<std::string> formulas_t;
713 formulas_t toBeSetOccurrence;
714 for (list_of_molecules_t::const_iterator moveiter = toBeMovedItems_copy.begin();
715 moveiter != toBeMovedItems_copy.end(); ++moveiter) {
716 boost::recursive_mutex::scoped_lock lock(map_mutex);
717// LOG(1, "Moving item " << molitem);
718 MoleculeFormulaMap_t::iterator formulaiter =
719 MoleculeFormulaMap.find(*moveiter);
720 ASSERT( formulaiter != MoleculeFormulaMap.end(),
721 "QtMoleculeList::updateItemStates() - formula of molecule "
722 +toString(*moveiter)+" unknown.");
723// LOG(1, "Adding " << formulaiter->second << " to toBeSetOccurrence.");
724 toBeSetOccurrence.insert( formulaiter->second );
725 if (!isMoleculeItemPresent(*moveiter))
726 continue;
727 QtMoleculeItem *const molitem = MoleculeIdToItem(*moveiter);
728 LOG(1, "Moving item " << molitem);
729 const molecule *mol = molitem->getMolecule();
730 if (mol != NULL) {
731 // remove from formula<->molecule bimap with old formula
732 LOG(1, "Removing " << formulaiter->second << " for " << formulaiter->first << " from MoleculeFormulaMap.");
733 MoleculeFormulaMap.erase( formulaiter );
734 const std::string formula = readdItem(molitem);
735 // and add to formula<->molecule bimap with updated formula
736 LOG(1, "Adding " << formula << " for " << *moveiter << " to MoleculeFormulaMap.");
737 MoleculeFormulaMap.insert( std::make_pair(*moveiter, formula) );
738// LOG(1, "Adding " << formula << " to toBeSetOccurrence.");
739 toBeSetOccurrence.insert( formula );
740 }
741 }
742
743 /// 3. remove all items whose molecules have been removed
744 for (std::vector<moleculeId_t>::const_iterator removeiter = removedMolecules_copy.begin();
745 removeiter != removedMolecules_copy.end(); ++removeiter) {
746// LOG(1, "Removing molecule " << *removeiter);
747 if (!isMoleculeItemPresent(*removeiter))
748 continue;
749 QtMoleculeItem *item = MoleculeIdToItem(*removeiter);
750 if (item != NULL) {
751 const std::string formula = item->parent()->text().toStdString();
752// LOG(1, "Adding " << formula << " to toBeSetOccurrence.");
753 toBeSetOccurrence.insert( formula );
754 removeMoleculeItem(item);
755 KilledItemsPerMolecule.erase( *removeiter );
756 }
757 }
758
759 // throw out items that we added by an update() while we are in this function
760 listAccessing_mutex.lock();
761 for (std::vector<moleculeId_t>::const_iterator removeiter = removedMolecules_copy.begin();
762 removeiter != removedMolecules_copy.end(); ++removeiter) {
763 for (unsigned int i=0;i< QtMoleculeItem::COLUMNTYPES_MAX; ++i)
764 dirtyMolItems.erase( std::make_pair(*removeiter,(QtMoleculeItem::COLUMNTYPES)i) );
765 toBeMovedItems.erase(*removeiter);
766 visibilityMolItems.erase(*removeiter);
767 }
768 listAccessing_mutex.unlock();
769 // after that it is not a problem as items have been removed (hence signOff() was called)
770
771 /// 4. instantiate all new items
772 for (std::vector<moleculeId_t>::const_iterator moliter = newMolecules_copy.begin();
773 moliter != newMolecules_copy.end(); ++moliter) {
774// LOG(1, "Adding molecule " << *moliter);
775 // check that World knows the molecule still
776 const molecule * const mol = const_cast<const World &>(World::getInstance()).
777 getMolecule(MoleculeById(*moliter));
778 if ((mol != NULL) && (mol->getId() == *moliter)) {
779 const std::string formula = addMolecule(mol);;
780// LOG(1, "Adding " << formula << " to toBeSetOccurrence.");
781 toBeSetOccurrence.insert( formula );
782 } else {
783 ELOG(2, "Molecule " << *moliter
784 << " disappeared before we could render it in QtMoleculeList.");
785 }
786 }
787
788 /// 5a. update the group item's occurrence and visibility
789 std::set<int> RowsToRemove;
790 for (std::set<std::string>::const_iterator groupiter = toBeSetOccurrence.begin();
791 groupiter != toBeSetOccurrence.end(); ++groupiter) {
792// LOG(1, "Updating group item's occurence " << *groupiter);
793 QStandardItem *groupitem = FormulaToGroupItem(*groupiter);
794 const int index = setOccurrence(groupitem);
795 if (index != -1) {
796// LOG(1, "Removing row of group item " << groupitem);
797 RowsToRemove.insert(index);
798 }
799 }
800 toBeSetOccurrence.clear();
801
802 // remove all visibility updates whose row is removed
803 for (list_of_group_items_t::iterator visiter = visibilityGroupItems_copy.begin();
804 visiter != visibilityGroupItems_copy.end(); ) {
805 QStandardItem * const groupitem = FormulaToGroupItem(visiter->first);
806 if (RowsToRemove.count(groupitem->index().row()) != 0) {
807// LOG(1, "Removing vis item " << *visiter << " because of removed group item.");
808 visibilityGroupItems_copy.erase(visiter++);
809 } else
810 ++visiter;
811 }
812
813 // update visibility of all group items
814 for (list_of_group_items_t::iterator visiter = visibilityGroupItems_copy.begin();
815 visiter != visibilityGroupItems_copy.end(); ++visiter) {
816// LOG(1, "Updating visibility of item " << *visiter);
817 QStandardItem * const groupitem =
818 getSpecificGroupItem(FormulaToGroupItem(visiter->first),
819 visiter->second);
820 setVisibilityForGroupItem(groupitem);
821 }
822
823 /// 5b. remove all rows with 0 occurrence starting from last
824 for (std::set<int>::reverse_iterator riter = RowsToRemove.rbegin();
825 riter != RowsToRemove.rend(); ++riter) {
826// LOG(1, "Removing group item at row " << *riter);
827 removeRows(*riter, 1, invisibleRootItem()->index());
828 }
829
830 // and done
831// LOG(1, "Done with update.");
832}
Note: See TracBrowser for help on using the repository browser.