COPASI API  4.16.103
CQAutolayoutWizard.cpp
Go to the documentation of this file.
1 // Copyright (C) 2011 - 2013 by Pedro Mendes, Virginia Tech Intellectual
2 // Properties, Inc., University of Heidelberg, and The University
3 // of Manchester.
4 // All rights reserved.
5 
6 #include "CQAutolayoutWizard.h"
7 
8 #include <QtGui/QCheckBox>
9 #include <QtGui/QFrame>
10 #include <QtGui/QLabel>
11 #include <QtCore/QList>
12 #include <QtGui/QListWidget>
13 #include <QtGui/QMessageBox>
14 #include <QtGui/QPushButton>
15 #include <QtCore/QString>
16 #include <QtCore/QStringList>
17 #include <QtGui/QTreeWidget>
18 #include <QtGui/QVBoxLayout>
19 
20 #include <assert.h>
21 #include <map>
22 
23 class QStringList;
24 
26 #include "copasi/model/CMetab.h"
27 #include "copasi/model/CModel.h"
28 #include "copasi/model/CReaction.h"
31 
32 /**
33  * Constructor which in addition to the attributes of the original class
34  * also takes a string which is the key of the object that is represented
35  * by the item.
36  */
37 CQModelElementTreeWidgetItem::CQModelElementTreeWidgetItem(const QStringList & strings, const std::string& key, int type) :
38  QTreeWidgetItem(strings, type)
39  , mKey(key)
40 {
41 }
42 
43 /**
44  * Returns a const reference to the key of the object.
45  */
46 const std::string& CQModelElementTreeWidgetItem::getKey() const
47 {
48  return this->mKey;
49 }
50 
51 /**
52  * Returns a pointer to the COPASI object
53  * represented by this item.
54  */
56 {
57  CCopasiObject* pObject = NULL;
58 
59  if (!this->mKey.empty())
60  {
61  pObject = CCopasiRootContainer::getKeyFactory()->get(this->mKey);
62  }
63 
64  return pObject;
65 }
66 
67 // Error dialog if nothing has been selected int the tree
68 
70  QWizardPage()
71 {
72  this->setTitle(tr("No selection Error"));
73  QVBoxLayout* pLayout = new QVBoxLayout;
74  this->setLayout(pLayout);
75  QLabel* pLabel = new QLabel("<font color='red'>Please go back to the selection page and select some model elements for which to create a layout.</font>");
76  QFont font = pLabel->font();
77  font.setBold(true);
78  font.setPointSize(font.pointSize() * 2);
79  pLabel->setFont(font);
80  pLabel->setWordWrap(true);
81  pLayout->addWidget(pLabel);
82 }
83 
85 {
86  return false;
87 }
88 
89 // Selection Page
90 
92  QWizardPage()
93  , mCreateCompartmentElements(false)
94  , mpSelectionTree(new QTreeWidget)
95  , mpCompartmentsItem(new QTreeWidgetItem((QTreeWidget*)NULL, QStringList(QString(tr("Compartments")))))
96  , mpReactionsItem(new QTreeWidgetItem((QTreeWidget*)NULL, QStringList(QString(tr("Reactions")))))
97 {
98  this->setTitle(tr("Model Element Selection"));
99  this->setSubTitle("Please select the model elements for which you want to create layout elements.\nPlease Note the the \"All ...\" elements only turn their immediate children on or off.");
100  QVBoxLayout* pLayout = new QVBoxLayout;
101  this->setLayout(pLayout);
102  pLayout->addWidget(this->mpSelectionTree);
103  this->fillTree(model);
104  QCheckBox* pCheckBox = new QCheckBox("create compartment elements");
105  pCheckBox->setChecked(false);
106  connect(pCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotCreateCompartments(int)));
107  pLayout->addWidget(pCheckBox);
108  this->mpSelectionTree->setColumnCount(1);
109  this->mpSelectionTree->setHeaderLabel(tr("Elements"));
110  // add a top level element for the compartments
111  // add a top level element for the reactions
112  QList<QTreeWidgetItem*> items;
113  items.append(this->mpCompartmentsItem);
114  items.append(this->mpReactionsItem);
115  this->mpSelectionTree->insertTopLevelItems(0, items);
116  connect(this->mpSelectionTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotItemChanged(QTreeWidgetItem*, int)));
117 }
118 
119 void CQSelectionWizardPage::slotItemChanged(QTreeWidgetItem* pItem, int /*column*/)
120 {
121  disconnect(this->mpSelectionTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotItemChanged(QTreeWidgetItem*, int)));
122  QTreeWidgetItem* pParent = pItem->parent();
123  assert(pParent != NULL);
124  bool found = false;
125 
126  if (this->mpCompartmentsItem->childCount() > 0)
127  {
128  // check if it was the "All compartments" entry
129  QTreeWidgetItem* pChild = this->mpCompartmentsItem->child(0);
130 
131  if (pItem == pChild)
132  {
133  // we have to select or deselect all immediate children
134  found = true;
135  unsigned int i = 0, iMax = pItem->childCount();
136  Qt::CheckState state = pItem->checkState(0);
137 
138  while (i < iMax)
139  {
140  pItem->child(i)->setCheckState(0, state);
141  ++i;
142  }
143  }
144  else
145  {
146  // check if it was one of the compartments entries
147  // the "All metabolite" entry, or one of the metabolites
148  int i = 0, iMax = pChild->childCount();
149  QTreeWidgetItem* pAll = NULL;
150 
151  while (i < iMax && !found)
152  {
153  if (pItem == pChild->child(i))
154  {
155  // it is a compartment node
156  // , we might have to change the state of the parent
157  found = true;
158  unsigned int j = 0, jMax = pParent->childCount();
159  bool allSelected = true;
160  bool allUnselected = true;
161 
162  while (j < jMax && (allSelected == true || allUnselected == true))
163  {
164  if (pParent->child(j)->checkState(0) == Qt::Checked)
165  {
166  allUnselected = false;
167  }
168  else if (pParent->child(j)->checkState(0) == Qt::Unchecked)
169  {
170  allSelected = false;
171  }
172  else
173  {
174  allSelected = false;
175  allUnselected = false;
176  }
177 
178  ++j;
179  }
180 
181  if (allSelected == true)
182  {
183  pParent->setCheckState(0, Qt::Checked);
184  }
185  else if (allUnselected == true)
186  {
187  pParent->setCheckState(0, Qt::Unchecked);
188  }
189  else
190  {
191  pParent->setCheckState(0, Qt::PartiallyChecked);
192  }
193  }
194  else
195  {
196  pAll = pChild->child(i)->child(0);
197 
198  if (pAll != NULL)
199  {
200  if (pItem == pAll)
201  {
202  // we have to select or deselect all immediate children
203  found = true;
204  unsigned int j = 0, jMax = pItem->childCount();
205  Qt::CheckState state = pItem->checkState(0);
206 
207  while (j < jMax)
208  {
209  pItem->child(j)->setCheckState(0, state);
210  ++j;
211  }
212  }
213  else if (pAll == pParent)
214  {
215  found = true;
216  // a metabolites selection status has changed
217  // we have to change the state of the parent
218  unsigned int j = 0, jMax = pParent->childCount();
219  bool allSelected = true;
220  bool allUnselected = true;
221 
222  while (j < jMax && (allSelected == true || allUnselected == true))
223  {
224  if (pParent->child(j)->checkState(0) == Qt::Checked)
225  {
226  allUnselected = false;
227  }
228  else if (pParent->child(j)->checkState(0) == Qt::Unchecked)
229  {
230  allSelected = false;
231  }
232  else
233  {
234  allSelected = false;
235  allUnselected = false;
236  }
237 
238  ++j;
239  }
240 
241  if (allSelected == true)
242  {
243  pParent->setCheckState(0, Qt::Checked);
244  }
245  else if (allUnselected == true)
246  {
247  pParent->setCheckState(0, Qt::Unchecked);
248  }
249  else
250  {
251  pParent->setCheckState(0, Qt::PartiallyChecked);
252  }
253  }
254  }
255  }
256 
257  ++i;
258  }
259  }
260  }
261 
262  if (!found && this->mpReactionsItem->childCount() > 0)
263  {
264  // check if it was the "All reactions" entry
265  QTreeWidgetItem* pChild = this->mpReactionsItem->child(0);
266 
267  if (pItem == pChild)
268  {
269  // we have to select or deselect all immediate children
270  found = true;
271  unsigned int j = 0, jMax = pItem->childCount();
272  Qt::CheckState state = pItem->checkState(0);
273 
274  while (j < jMax)
275  {
276  pItem->child(j)->setCheckState(0, state);
277  ++j;
278  }
279  }
280  else
281  {
282  // check if it was one of the reaction entries
283  int i = 0, iMax = pChild->childCount();
284 
285  while (i < iMax && !found)
286  {
287  if (pItem == pChild->child(i))
288  {
289  found = true;
290  // it is a reaction node
291  // , we might have to change the state of the parent
292  unsigned int j = 0, jMax = pParent->childCount();
293  bool allSelected = true;
294  bool allUnselected = true;
295 
296  while (j < jMax && (allSelected == true || allUnselected == true))
297  {
298  if (pParent->child(j)->checkState(0) == Qt::Checked)
299  {
300  allUnselected = false;
301  }
302  else if (pParent->child(j)->checkState(0) == Qt::Unchecked)
303  {
304  allSelected = false;
305  }
306  else
307  {
308  allSelected = false;
309  allUnselected = false;
310  }
311 
312  ++j;
313  }
314 
315  if (allSelected == true)
316  {
317  pParent->setCheckState(0, Qt::Checked);
318  }
319  else if (allUnselected == true)
320  {
321  pParent->setCheckState(0, Qt::Unchecked);
322  }
323  else
324  {
325  pParent->setCheckState(0, Qt::PartiallyChecked);
326  }
327  }
328 
329  ++i;
330  }
331  }
332  }
333 
334  assert(found == true);
335  connect(this->mpSelectionTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotItemChanged(QTreeWidgetItem*, int)));
336 }
337 
338 // is called when the state of the compartment layout creation checkbox changes
340 {
341  // set the flags on the compartment items and the All items in compartments
342  // to be checkable but leave them unchecked
343  disconnect(this->mpSelectionTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotItemChanged(QTreeWidgetItem*, int)));
344 
345  if (state == Qt::Checked)
346  {
347  this->mCreateCompartmentElements = true;
348  QTreeWidgetItem* pItem = this->mpCompartmentsItem->child(0);
349 
350  if (pItem != NULL)
351  {
352  pItem->setFlags(pItem->flags() | Qt::ItemIsUserCheckable);
353  pItem->setCheckState(0, Qt::Unchecked);
354  // now we do the same on all the children of this item
355  unsigned int i = 0, iMax = pItem->childCount();
356 
357  while (i < iMax)
358  {
359  pItem->child(i)->setFlags(pItem->child(i)->flags() | Qt::ItemIsUserCheckable);
360  pItem->child(i)->setCheckState(0, Qt::Unchecked);
361  ++i;
362  }
363  }
364  }
365  else
366  {
367  this->mCreateCompartmentElements = false;
368  this->mpCompartmentsItem->setFlags(this->mpCompartmentsItem->flags() & (~Qt::ItemIsUserCheckable));
369  this->mpCompartmentsItem->setData(0, Qt::CheckStateRole, QVariant());
370  QTreeWidgetItem* pItem = this->mpCompartmentsItem->child(0);
371 
372  if (pItem != NULL)
373  {
374  pItem->setFlags(pItem->flags() & (~Qt::ItemIsUserCheckable));
375  pItem->setData(0, Qt::CheckStateRole, QVariant());
376  // now we do the same on all the children of this item
377  unsigned int i = 0, iMax = pItem->childCount();
378 
379  while (i < iMax)
380  {
381  pItem->child(i)->setFlags(pItem->child(i)->flags() & (~Qt::ItemIsUserCheckable));
382  pItem->child(i)->setData(0, Qt::CheckStateRole, QVariant());
383  ++i;
384  }
385  }
386  }
387 
388  connect(this->mpSelectionTree, SIGNAL(itemChanged(QTreeWidgetItem*, int)), this, SLOT(slotItemChanged(QTreeWidgetItem*, int)));
389 }
390 
391 // fills the selection tree with elements from the model
393 {
394  const CCopasiVectorNS < CCompartment >& compartments = model.getCompartments();
395  const CCopasiVector< CMetab >& metabs = model.getMetabolites();
396  const CCopasiVectorNS < CReaction >& reactions = model.getReactions();
397 
398  if (compartments.size() > 0 && metabs.size() > 0)
399  {
400  // make all items checkable but the ones for the compartments
401  // and the ones for All compartments
402  // check all checkable items
403 
404  // add the compartments
405  // first we have to add two items to the top level items that we can use to
406  // specify that we want to select all children in a list
407  QTreeWidgetItem* pItem = new QTreeWidgetItem(QStringList(QString(tr("All Compartments"))));
408  pItem->setFlags(pItem->flags() & (!Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
409  this->mpCompartmentsItem->addChild(pItem);
410  // add all compartments to the item
411  QList<QTreeWidgetItem*> children, children2;
412  unsigned int i = 0, iMax = compartments.size();
413  QTreeWidgetItem *pChild1;
414  const CCompartment* pCompartment = NULL;
415  QTreeWidgetItem *pItem2 = NULL, *pItem3 = NULL;
416  const CCopasiVectorNS<CMetab>* pMetabs = NULL;
417  unsigned int j, jMax;
418  const CMetab* pMetab = NULL;
419 
420  while (i < iMax)
421  {
422  pCompartment = compartments[i];
423  assert(pCompartment != NULL);
424  pChild1 = new CQModelElementTreeWidgetItem(QStringList(QString(pCompartment->getObjectDisplayName().c_str())), pCompartment->getKey());
425  pChild1->setFlags(pChild1->flags() & (!Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
426  // add an item to select all children
427  pMetabs = &pCompartment->getMetabolites();
428  assert(pMetabs != NULL);
429 
430  if (pMetabs->size() > 0)
431  {
432  pItem2 = new QTreeWidgetItem(QStringList(QString(tr("All Metabolites in Compartment"))));
433  pItem2->setFlags(pItem2->flags() | (Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
434  pItem2->setCheckState(0, Qt::Checked);
435  pChild1->addChild(pItem2);
436  // now we add all metabolites
437  j = 0;
438  jMax = pMetabs->size();
439 
440  while (j < jMax)
441  {
442  pMetab = (*pMetabs)[j];
443  assert(pMetab != NULL);
444  pItem3 = new CQModelElementTreeWidgetItem(QStringList(QString(pMetab->getObjectDisplayName().c_str())), pMetab->getKey());
445  pItem3->setFlags(pItem3->flags() | (Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
446  pItem3->setCheckState(0, Qt::Checked);
447  children2.append(pItem3);
448  ++j;
449  }
450 
451  pItem2->addChildren(children2);
452  children2.clear();
453  }
454 
455  children.append(pChild1);
456  ++i;
457  }
458 
459  pItem->addChildren(children);
460 
461  if (reactions.size() > 0)
462  {
463  // top level item to select all reactions
464  pItem = new QTreeWidgetItem(QStringList(QString(tr("All Reactions"))));
465  pItem->setFlags(pItem->flags() | (Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
466  pItem->setCheckState(0, Qt::Checked);
467  this->mpReactionsItem->addChild(pItem);
468  // now we add all reactions
469  i = 0;
470  iMax = reactions.size();
471  const CReaction* pReaction = NULL;
472 
473  while (i < iMax)
474  {
475  pReaction = reactions[i];
476  assert(pReaction != NULL);
477  pChild1 = new CQModelElementTreeWidgetItem(QStringList(QString(pReaction->getObjectDisplayName().c_str())), pReaction->getKey());
478  pChild1->setFlags(pChild1->flags() | (Qt::ItemIsUserCheckable | Qt::ItemIsEnabled));
479  pChild1->setCheckState(0, Qt::Checked);
480  // TODO add the substrates and products to the reactions
481  children2.append(pChild1);
482  ++i;
483  }
484 
485  pItem->addChildren(children2);
486  }
487  }
488 }
489 
490 /**
491  * Checks which elements have been selected in the tree
492  * and fills the containers that are passed in with those
493  * elements.
494  */
495 void CQSelectionWizardPage::fillContainers(std::set<const CCompartment*>& compartments, std::set<const CReaction*>& reactions, std::set<const CMetab*>& species) const
496 {
497  // clear all containers
498  compartments.clear();
499  reactions.clear();
500  species.clear();
501 
502  if (this->mpCompartmentsItem->childCount() > 0)
503  {
504  QTreeWidgetItem* pItem = this->mpCompartmentsItem->child(0);
505  unsigned int i = 0, iMax = pItem->childCount();
506  unsigned int j, jMax;
507  const CMetab* pMetab = NULL;
508  QTreeWidgetItem *pItem2 = NULL, *pChild = NULL, *pChild2 = NULL;
509  const CCompartment* pCompartment = NULL;
510  CQModelElementTreeWidgetItem* pModelItem = NULL;
511 
512  while (i < iMax)
513  {
514  pChild = pItem->child(i);
515  assert(pChild != NULL);
516 
517  if ((pChild->flags() & Qt::ItemIsUserCheckable) && pChild->checkState(0) == Qt::Checked)
518  {
519  pModelItem = dynamic_cast<CQModelElementTreeWidgetItem*>(pItem->child(i));
520  assert(pModelItem != NULL);
521  pCompartment = dynamic_cast<const CCompartment*>(pModelItem->getObject());
522  assert(pCompartment != NULL);
523  compartments.insert(pCompartment);
524  }
525 
526  pItem2 = pChild->child(0);
527 
528  // get the All species item
529  if (pItem2 == NULL)
530  {
531  ++i;
532  continue;
533  }
534 
535  j = 0;
536  jMax = pItem2->childCount();
537 
538  while (j < jMax)
539  {
540  pChild2 = pItem2->child(j);
541 
542  if ((pChild2->flags() & Qt::ItemIsUserCheckable) && pChild2->checkState(0) == Qt::Checked)
543  {
544  pModelItem = dynamic_cast<CQModelElementTreeWidgetItem*>(pItem2->child(j));
545  assert(pModelItem != NULL);
546  pMetab = dynamic_cast<const CMetab*>(pModelItem->getObject());
547  assert(pMetab != NULL);
548  species.insert(pMetab);
549  }
550 
551  ++j;
552  }
553 
554  ++i;
555  }
556 
557  // now we add the reactions
558  }
559 
560  if (this->mpReactionsItem->childCount() > 0)
561  {
562  // there should be only one child (All reactions)
563  assert(this->mpReactionsItem->childCount() == 1);
564  QTreeWidgetItem* pItem = this->mpReactionsItem->child(0), *pChild = NULL;
565  CQModelElementTreeWidgetItem* pModelItem = NULL;
566  unsigned int i = 0, iMax;
567  iMax = pItem->childCount();
568  const CReaction* pReaction = NULL;
569 
570  while (i < iMax)
571  {
572  pChild = pItem->child(i);
573 
574  if ((pChild->flags() & Qt::ItemIsUserCheckable) && pChild->checkState(0) == Qt::Checked)
575  {
576  pModelItem = dynamic_cast<CQModelElementTreeWidgetItem*>(pChild);
577  assert(pModelItem != NULL);
578  pReaction = dynamic_cast<const CReaction*>(pModelItem->getObject());
579  assert(pReaction != NULL);
580  reactions.insert(pReaction);
581  }
582 
583  ++i;
584  }
585  }
586 }
587 
588 // this is the page where one can select the side compounds
589 // constructor which takes a string that is displayed for the item
590 // and the key of a model object
592  QListWidgetItem(text)
593  , mKey(key)
594 {
595 }
596 
597 // returns the key of the associated model object
599 {
600  return this->mKey;
601 }
602 
604 {
605  CCopasiObject* pObject = NULL;
606 
607  if (!this->mKey.empty())
608  {
609  pObject = CCopasiRootContainer::getKeyFactory()->get(this->mKey);
610  }
611 
612  return pObject;
613 }
614 
615 // default constructor
617  QWizardPage()
618  , mpSpeciesList(new QListWidget)
619  , mpSideCompoundList(new QListWidget)
620  , mpAddButton(new QPushButton(">>"))
621  , mpRemoveButton(new QPushButton("<<"))
622 {
623  this->setTitle("Side Compounds");
624  this->setSubTitle("Please select the species that you want to be considered as side compounds in the layout.\n\nSide compounds can be duplicated for each reaction they occur in and they might be treated differently by the layout algorithm.");
625  // the page should contain two lists
626  // and the user can push elements back and forth
627  // between the lists
628  this->mpSpeciesList->setSelectionMode(QAbstractItemView::ExtendedSelection);
629  this->mpSideCompoundList->setSelectionMode(QAbstractItemView::ExtendedSelection);
630  QHBoxLayout* pLayout = new QHBoxLayout;
631  this->setLayout(pLayout);
632  QFrame* pFrame = new QFrame;
633  QVBoxLayout* pLayout2 = new QVBoxLayout;
634  pFrame->setLayout(pLayout2);
635  pLayout2->addWidget(new QLabel("Species"));
636  pLayout2->addWidget(this->mpSpeciesList);
637  pLayout->addWidget(pFrame);
638  pLayout2 = new QVBoxLayout;
639  pFrame = new QFrame;
640  pFrame->setLayout(pLayout2);
641  pLayout2->addStretch();
642  this->mpAddButton->setEnabled(false);
643  this->mpRemoveButton->setEnabled(false);
644  pLayout2->addWidget(this->mpAddButton);
645  pLayout2->addSpacing(20);
646  pLayout2->addWidget(this->mpRemoveButton);
647  pLayout2->addStretch();
648  pLayout->addWidget(pFrame);
649  pFrame = new QFrame;
650  pLayout2 = new QVBoxLayout;
651  pFrame->setLayout(pLayout2);
652  pLayout2->addWidget(new QLabel("Side-Species"));
653  pLayout2->addWidget(this->mpSideCompoundList);
654  pLayout->addWidget(pFrame);
655  connect(this->mpAddButton, SIGNAL(clicked()), this, SLOT(slotAddButtonClicked()));
656  connect(this->mpRemoveButton, SIGNAL(clicked()), this, SLOT(slotRemoveButtonClicked()));
657  connect(this->mpSpeciesList, SIGNAL(itemSelectionChanged()), this, SLOT(slotSpeciesSelectionChanged()));
658  connect(this->mpSideCompoundList, SIGNAL(itemSelectionChanged()), this, SLOT(slotSideCompoundSelectionChanged()));
659 }
660 
662 {
663  return (pM1->getObjectDisplayName() < pM2->getObjectDisplayName());
664 }
665 
666 /**
667  * Fills the given set with the side compounds that
668  * have been selected by the user.
669  */
670 void CQSideCompoundWizardPage::getSideCompounds(std::set<const CMetab*>& sideCompounds) const
671 {
672  sideCompounds.clear();
673  unsigned int i, iMax = this->mpSideCompoundList->count();
674  const CQListWidgetModelItem* pItem = NULL;
675  const CMetab* pMetab = NULL;
676 
677  for (i = 0; i < iMax; ++i)
678  {
679  pItem = dynamic_cast<const CQListWidgetModelItem*>(this->mpSideCompoundList->item(i));
680  assert(pItem != NULL);
681  pMetab = dynamic_cast<const CMetab*>(pItem->getObject());
682  sideCompounds.insert(pMetab);
683  }
684 }
685 
686 /**
687  * Passes the species that have been selected by the user
688  * for use in the layout to the page.
689  * These species are used to fill the list on the left.
690  */
691 void CQSideCompoundWizardPage::setSpeciesList(const std::set<const CMetab*>& metabs)
692 {
693  this->mSortedSpecies.clear();
694  this->mSortedSpecies.insert(metabs.begin(), metabs.end());
695  std::set<std::string> keys;
696 
697  this->mpSpeciesList->clear();
698  std::set<const CMetab*, alphaSorter>::const_iterator it = this->mSortedSpecies.begin(), endit = this->mSortedSpecies.end();
699  QList<QListWidgetItem*> itemList;
700  int i, iMax;
701 
702  while (it != endit)
703  {
704  std::string displayName = (*it)->getObjectDisplayName();
705  keys.insert((*it)->getKey());
706  // if the item is already marked as a side compound, we don't
707  // have to add it to the species list
708  itemList = this->mpSideCompoundList->findItems(displayName.c_str(), Qt::MatchExactly);
709  i = 0;
710  iMax = itemList.size();
711  bool found = false;
712 
713  while (i < iMax)
714  {
715  if (static_cast<const CQListWidgetModelItem*>(itemList[i])->getKey() == (*it)->getKey())
716  {
717  found = true;
718  }
719 
720  ++i;
721  }
722 
723  if (found == false)
724  {
725  // the item is not a side compound, so we add it to the species list
726  this->mpSpeciesList->addItem(new CQListWidgetModelItem(displayName.c_str(), (*it)->getKey()));
727  }
728 
729  ++it;
730  }
731 
732  // now we have to go through the side compounds again and check
733  // if all the names that are in there are also in the sorted name list
734  // If not, we have to delete the item from the side compounds
735  iMax = this->mpSideCompoundList->count() - 1;
736  std::set<std::string>::const_iterator end = keys.end();
737  QListWidgetItem* pItem = NULL;
738 
739  while (iMax > 0)
740  {
741  if (keys.find(static_cast<const CQListWidgetModelItem*>(this->mpSideCompoundList->item(iMax))->getKey()) == end)
742  {
743  pItem = this->mpSideCompoundList->takeItem(iMax);
744 
745  if (pItem != NULL)
746  {
747  delete pItem;
748  }
749  }
750 
751  --iMax;
752  }
753 }
754 
755 // called when the add button was clicked
757 {
758  // move the selected items from the species list to the side compound list
759  QList<QListWidgetItem*> selection = this->mpSpeciesList->selectedItems();
760  // insert the items into the side compound list in the correct order
761  // and remove them from the species list
762  // the items should be selected in the side compound list
763  int index = 0;
764  QList<QListWidgetItem*>::iterator it = selection.begin(), endit = selection.end();
765 
766  while (it != endit)
767  {
768  while (index < this->mpSideCompoundList->count() && static_cast<CQListWidgetModelItem*>(this->mpSideCompoundList->item(index))->getObject()->getObjectDisplayName() < static_cast<CQListWidgetModelItem*>(*it)->getObject()->getObjectDisplayName())
769  {
770  ++index;
771  }
772 
773  if (index == this->mpSideCompoundList->count())
774  {
775  // we add all items at the end
776  while (it != endit)
777  {
778  this->mpSpeciesList->takeItem(this->mpSpeciesList->row(*it));
779  this->mpSideCompoundList->addItem((*it));
780  ++it;
781  }
782  }
783 
784  // now we insert items until the item is not at the right place
785  while (it != endit && static_cast<CQListWidgetModelItem*>(this->mpSideCompoundList->item(index))->getObject()->getObjectDisplayName() > static_cast<CQListWidgetModelItem*>(*it)->getObject()->getObjectDisplayName())
786  {
787  this->mpSpeciesList->takeItem(this->mpSpeciesList->row(*it));
788  this->mpSideCompoundList->insertItem(index, *it);
789  ++it;
790  }
791  }
792 
793  // TODO set the newly added items as selected
794  // TODO disconnect and reconnect the slot that listend to the selection change
795  // TODO and emit the signal after changing the selection
796  this->mpSpeciesList->update();
797 }
798 
799 // called when the remove button was clicked
801 {
802  // move the selected items from the side compound list to the species list
803  QList<QListWidgetItem*> selection = this->mpSideCompoundList->selectedItems();
804  // insert the items into the species list in the correct order
805  // and remove them from the side compound list
806  // the items should be selected in the species list
807  QList<QListWidgetItem*>::iterator it = selection.begin(), endit = selection.end();
808  int index = 0;
809 
810  while (it != endit)
811  {
812  while (index < this->mpSpeciesList->count() && static_cast<CQListWidgetModelItem*>(this->mpSpeciesList->item(index))->getObject()->getObjectDisplayName() < static_cast<CQListWidgetModelItem*>(*it)->getObject()->getObjectDisplayName())
813  {
814  ++index;
815  }
816 
817  if (index == this->mpSpeciesList->count())
818  {
819  // we add all items at the end
820  while (it != endit)
821  {
822  this->mpSideCompoundList->takeItem(this->mpSideCompoundList->row(*it));
823  this->mpSpeciesList->addItem((*it));
824  ++it;
825  }
826 
827  break;
828  }
829 
830  // now we insert items until the item is not at the right place
831  while (it != endit && static_cast<CQListWidgetModelItem*>(this->mpSpeciesList->item(index))->getObject()->getObjectDisplayName() > static_cast<CQListWidgetModelItem*>(*it)->getObject()->getObjectDisplayName())
832  {
833  this->mpSideCompoundList->takeItem(this->mpSideCompoundList->row(*it));
834  this->mpSpeciesList->insertItem(index, *it);
835  ++it;
836  }
837  }
838 
839  // TODO set the newly added items as selected
840  // TODO disconnect and reconnect the slot that listend to the selection change
841  // TODO and emit the signal after changing the selection
842  this->mpSideCompoundList->update();
843 }
844 
845 // called when the selection in the species list changes
847 {
848  // if something is selected
849  // delete the selection in the side compound list
850  // if nothing is selected deactive the add button, else active the add
851  // button
852  QList<QListWidgetItem*> selection = this->mpSpeciesList->selectedItems();
853 
854  if (selection.size() == 0)
855  {
856  this->mpAddButton->setEnabled(false);
857  }
858  else
859  {
860  this->mpAddButton->setEnabled(true);
861  this->mpSideCompoundList->clearSelection();
862  }
863 }
864 
865 // called when the side compounds selection changes
867 {
868  // if something is selected, delete the selection in the
869  // species list and active the remove button
870  // else deactivate the remove button
871  QList<QListWidgetItem*> selection = this->mpSideCompoundList->selectedItems();
872 
873  if (selection.size() == 0)
874  {
875  this->mpRemoveButton->setEnabled(false);
876  }
877  else
878  {
879  this->mpRemoveButton->setEnabled(true);
880  this->mpSpeciesList->clearSelection();
881  }
882 }
883 
884 // Now comes the wizard itself
885 
886 /**
887  * Constructor needs a const reference to
888  * a COPASI model.
889  */
890 CQAutolayoutWizard::CQAutolayoutWizard(const CModel& model, QWidget * parent , Qt::WindowFlags flags):
891  QWizard(parent, flags)
892  , mModel(model)
893  , mLastPageId(CQAutolayoutWizard::NO_PAGE)
894 {
895  this->setOptions(this->options() | QWizard::HaveFinishButtonOnEarlyPages);
896  this->setOptions(this->options() & ~QWizard::NoCancelButton);
897  this->setWindowTitle(tr("Autolayout Wizard"));
898  this->setPage(SELECTION_PAGE_ID, this->createSelectionPage());
899  this->setPage(NO_SELECTION_ERROR_PAGE_ID, this->createErrorPage());
900  this->setPage(SIDE_COMPOUND_PAGE_ID, this->createSideCompoundPage());
901  //this->setPage(LAYOUT_PARAMETER_PAGE_ID,this->createLayoutParameterPage());
902  connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotCurrentIdChanged(int)));
903 }
904 
905 // Destructor
907 {
908  // do nothing
909 }
910 
911 // creates the first page for the wizard
912 // This is the page where the user selects the model elements
914 {
915  return new CQSelectionWizardPage(this->mModel);
916 }
917 
918 // creates the second page for the wizard
919 // here the user can decide if certain species should be
920 // treated as side components
922 {
923  return new CQSideCompoundWizardPage;
924 }
925 
926 // creates the third page for the wizard
927 // here the user can make settings for the layout
928 // algorithm
930 {
931  return new CQLayoutParametersWizardPage;
932 }
933 
934 // creates the error page for the wizard
935 // where the user is asked to please select element for the layout
937 {
938  return new CQNoSelectionErrorWizardPage;
939 }
940 
941 void CQAutolayoutWizard::done(int result)
942 {
943  // depending on the result, I have to update
944  // the selections
945  if (result == QDialog::Accepted)
946  {
947  // right now, the dialog can only be ended on the second page,
948  // so in theory we only have to update the side compounds
949  // But I would like to change the wizard so that the user is
950  // not forced to go through all pages and that he can close the
951  // wizard at each step
952  if (this->currentId() == CQAutolayoutWizard::SELECTION_PAGE_ID)
953  {
954  static_cast<CQSelectionWizardPage*>(this->currentPage())->fillContainers(this->mCompartments, this->mReactions, this->mSpecies);
955  }
956  else if (this->currentId() == CQAutolayoutWizard::SIDE_COMPOUND_PAGE_ID)
957  {
958  static_cast<CQSideCompoundWizardPage*>(this->currentPage())->getSideCompounds(this->mSideSpecies);
959  }
960  else if (this->currentId() == CQAutolayoutWizard::LAYOUT_PARAMETER_PAGE_ID)
961  {
962  // do nothing right now
963  }
964 
965  // make sure that the side species container does not contain
966  // any species that is not in the species container
967  std::set<const CMetab*>::iterator it = this->mSideSpecies.begin(), endit = this->mSideSpecies.end(), speciesEnd = this->mSpecies.end();
968 
969  while (it != endit)
970  {
971  if (this->mSpecies.find(*it) == speciesEnd)
972  {
973  // remove the item from the side species
974  // this is not very efficient, but should be ok since this code
975  // is probably not critical
976  this->mSideSpecies.erase(*it);
977  // back to start
978  it = this->mSideSpecies.begin();
979  endit = this->mSideSpecies.end();
980  continue;
981  }
982 
983  ++it;
984  }
985  }
986  else
987  {
988  this->mCompartments.clear();
989  this->mReactions.clear();
990  this->mSpecies.clear();
991  this->mSideSpecies.clear();
992  }
993 
994  this->QWizard::done(result);
995 }
996 
998 {
999  // if the last id was the id of the selection widget, we
1000  // have to store the selection data
1002  {
1003  // this is now done in the nextId method
1004  //static_cast<CQSelectionWizardPage*>(this->page(CQAutolayoutWizard::SELECTION_PAGE_ID))->fillContainers(this->mCompartments,this->mReactions,this->mSpecies);
1005  }
1006  // if the last id is that of the side compound page,
1007  // we have to save the side compounds
1009  {
1010  static_cast<CQSideCompoundWizardPage*>(this->page(CQAutolayoutWizard::SIDE_COMPOUND_PAGE_ID))->getSideCompounds(this->mSideSpecies);
1011  }
1012 
1013  // if we are in the side compound page,
1014  // we have to update the species
1016  {
1017  static_cast<CQSideCompoundWizardPage*>(this->page(CQAutolayoutWizard::SIDE_COMPOUND_PAGE_ID))->setSpeciesList(this->mSpecies);
1018  }
1019 
1020  this->mLastPageId = (PageOrder)id;
1021 }
1022 
1024 {
1025  PageOrder nextPage = NO_PAGE;
1026 
1027  switch (this->currentId())
1028  {
1029  case SELECTION_PAGE_ID:
1030  static_cast<CQSelectionWizardPage*>(this->currentPage())->fillContainers(this->mCompartments, this->mReactions, this->mSpecies);
1031 
1032  if (this->mCompartments.empty() && this->mSpecies.empty())
1033  {
1034  nextPage = NO_SELECTION_ERROR_PAGE_ID;
1035  }
1036  else
1037  {
1038  nextPage = SIDE_COMPOUND_PAGE_ID;
1039  }
1040 
1041  break;
1042 
1044  break;
1045 
1046  case SIDE_COMPOUND_PAGE_ID:
1047  //nextPage=LAYOUT_PARAMETER_PAGE_ID;
1048  break;
1049 
1051  break;
1052  }
1053 
1054  return nextPage;
1055 }
virtual int nextId() const
virtual std::string getObjectDisplayName(bool regular=true, bool richtext=false) const
std::set< const CReaction * > mReactions
CCopasiVectorNS< CMetab > & getMetabolites()
const CCopasiVector< CMetab > & getMetabolites() const
Definition: CModel.cpp:1051
void getSideCompounds(std::set< const CMetab * > &sideCompounds) const
std::set< const CMetab * > mSideSpecies
const std::string & getKey() const
virtual size_t size() const
void setSpeciesList(const std::set< const CMetab * > &metabs)
void slotCreateCompartments(int state)
CCopasiObject * get(const std::string &key)
virtual const std::string & getKey() const
Definition: CReaction.cpp:190
virtual std::string getObjectDisplayName(bool regular=true, bool richtext=false) const
Definition: CReaction.cpp:1688
virtual std::string getObjectDisplayName(bool regular=true, bool richtext=false) const
Definition: CMetab.cpp:974
Definition: CMetab.h:178
void fillContainers(std::set< const CCompartment * > &compartments, std::set< const CReaction * > &reactions, std::set< const CMetab * > &species) const
virtual bool isComplete() const
std::set< const CMetab *, alphaSorter > mSortedSpecies
std::set< const CCompartment * > mCompartments
CQModelElementTreeWidgetItem(const QStringList &strings, const std::string &key, int type=QTreeWidgetItem::Type)
CQSelectionWizardPage(const CModel &model)
bool operator()(const CMetab *m1, const CMetab *m2) const
virtual const std::string & getKey() const
std::set< const CMetab * > mSpecies
QTreeWidgetItem * mpReactionsItem
QWizardPage * createErrorPage()
QWizardPage * createSelectionPage()
virtual void done(int result)
CCopasiVectorNS< CCompartment > & getCompartments()
Definition: CModel.cpp:1145
static CKeyFactory * getKeyFactory()
QTreeWidgetItem * mpCompartmentsItem
CCopasiObject * getObject() const
CCopasiVectorNS< CReaction > & getReactions()
Definition: CModel.cpp:1039
void fillTree(const CModel &model)
void slotCurrentIdChanged(int id)
Definition: CModel.h:50
void slotItemChanged(QTreeWidgetItem *pItem, int column)
CQAutolayoutWizard(const CModel &model, QWidget *parent=0, Qt::WindowFlags flags=0)
CQListWidgetModelItem(const QString &text, const std::string &key)
QWizardPage * createLayoutParameterPage()
QWizardPage * createSideCompoundPage()