1 /* $Id: show_hide_manager.cpp 591063 2019-08-09 15:27:34Z wangjiy $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Authors: Paul Thiessen
27 *
28 * File Description:
29 * manager object to track show/hide status of objects at various levels
30 *
31 * ===========================================================================
32 */
33
34 #include <ncbi_pch.hpp>
35 #include <corelib/ncbistd.hpp>
36
37 #include "remove_header_conflicts.hpp"
38
39 #include "show_hide_manager.hpp"
40 #include "structure_set.hpp"
41 #include "molecule.hpp"
42 #include "residue.hpp"
43 #include "chemical_graph.hpp"
44 #include "messenger.hpp"
45 #include "alignment_manager.hpp"
46 #include "opengl_renderer.hpp"
47 #include "cn3d_tools.hpp"
48 #include "molecule_identifier.hpp"
49
50 #include <corelib/ncbistre.hpp>
51 #include <vector>
52
53 USING_NCBI_SCOPE;
54
55
56 BEGIN_SCOPE(Cn3D)
57
58
59 // ShowHideInfo is a generic container class to help organize the list of things that can be
60 // shown/hidden; stuff derived from it allows various types of objects to be shown/hidden
61
62 string indent(" ");
63
64 class ShowHideInfo
65 {
66 protected:
67 string label;
68 public:
~ShowHideInfo(void)69 virtual ~ShowHideInfo(void) { }
70 vector < int > parentIndexes;
GetLabel(string * str) const71 void GetLabel(string *str) const { *str = label; }
72 virtual bool IsVisible(const ShowHideManager *shm) const = 0;
73 virtual void Show(ShowHideManager *shm, bool isShown) const = 0;
74 };
75
76 class ShowHideObject : public ShowHideInfo
77 {
78 private:
79 const StructureObject *object;
80 public:
ShowHideObject(const StructureObject * o)81 ShowHideObject(const StructureObject *o) : object(o) { label = o->GetPDBID(); }
~ShowHideObject(void)82 virtual ~ShowHideObject(void) { }
IsVisible(const ShowHideManager * shm) const83 bool IsVisible(const ShowHideManager *shm) const { return shm->IsVisible(object); }
Show(ShowHideManager * shm,bool isShown) const84 void Show(ShowHideManager *shm, bool isShown) const { shm->Show(object, isShown); }
85 };
86
87 class ShowHideMolecule : public ShowHideInfo
88 {
89 private:
90 const Molecule *molecule;
91 public:
ShowHideMolecule(const Molecule * m)92 ShowHideMolecule(const Molecule *m) : molecule(m)
93 {
94 label = indent + m->identifier->pdbID;
95
96 #ifdef _STRUCTURE_USE_LONG_PDB_CHAINS_
97 if (m->identifier->pdbChain != " ") {
98 label += '_';
99 label += m->identifier->pdbChain;
100 }
101 #else
102 if (m->identifier->pdbChain != ' ') {
103 label += '_';
104 label += (char) m->identifier->pdbChain;
105 }
106 #endif
107 }
~ShowHideMolecule(void)108 virtual ~ShowHideMolecule(void) { }
IsVisible(const ShowHideManager * shm) const109 bool IsVisible(const ShowHideManager *shm) const { return shm->IsVisible(molecule); }
Show(ShowHideManager * shm,bool isShown) const110 void Show(ShowHideManager *shm, bool isShown) const { shm->Show(molecule, isShown); }
111 };
112
113 class ShowHideDomain : public ShowHideInfo
114 {
115 private:
116 const Molecule *molecule;
117 int domainID;
118 public:
ShowHideDomain(const Molecule * m,int d,int labelNum)119 ShowHideDomain(const Molecule *m, int d, int labelNum) : molecule(m), domainID(d)
120 {
121 CNcbiOstrstream oss;
122 oss << indent << indent << m->identifier->pdbID;
123
124 #ifdef _STRUCTURE_USE_LONG_PDB_CHAINS_
125 if (m->identifier->pdbChain != " ") oss << '_' << m->identifier->pdbChain.c_str();
126 #else
127 if (m->identifier->pdbChain != ' ') oss << '_' << (char) m->identifier->pdbChain;
128 #endif
129
130 oss << " d" << labelNum;
131 label = (string) CNcbiOstrstreamToString(oss);
132 }
~ShowHideDomain(void)133 virtual ~ShowHideDomain(void) { }
IsVisible(const ShowHideManager * shm) const134 bool IsVisible(const ShowHideManager *shm) const
135 {
136 bool isVisible = false;
137 for (unsigned int i=0; i<molecule->NResidues(); ++i) {
138 if (molecule->residueDomains[i] == domainID &&
139 shm->IsVisible(molecule->residues.find(i+1)->second)) {
140 isVisible = true; // return true if any residue from this domain is visible
141 break;
142 }
143 }
144 return isVisible;
145 }
Show(ShowHideManager * shm,bool isShown) const146 void Show(ShowHideManager *shm, bool isShown) const
147 {
148 for (unsigned int i=0; i<molecule->NResidues(); ++i)
149 if (molecule->residueDomains[i] == domainID)
150 shm->Show(molecule->residues.find(i+1)->second, isShown);
151 }
152 };
153
154
155 ///// the ShowHideManager class /////
156
~ShowHideManager()157 ShowHideManager::~ShowHideManager()
158 {
159 for (unsigned int i=0; i<structureInfo.size(); ++i) delete structureInfo[i];
160 }
161
PostRedrawEntity(const StructureObject * object,const Molecule * molecule,const Residue * residue)162 static void PostRedrawEntity(const StructureObject *object, const Molecule *molecule, const Residue *residue)
163 {
164 if (residue) {
165 const Molecule *m;
166 if (residue->GetParentOfType(&m))
167 GlobalMessenger()->PostRedrawMolecule(m);
168 }
169
170 else if (molecule) {
171 GlobalMessenger()->PostRedrawMolecule(molecule);
172 }
173
174 else if (object) {
175 // redraw all prot/nuc molecules
176 ChemicalGraph::MoleculeMap::const_iterator m, me = object->graph->molecules.end();
177 for (m=object->graph->molecules.begin(); m!=me; ++m) {
178 if (m->second->IsProtein() || m->second->IsNucleotide())
179 GlobalMessenger()->PostRedrawMolecule(m->second);
180 }
181 }
182
183 GlobalMessenger()->PostRedrawAllSequenceViewers();
184 }
185
Show(const StructureBase * entity,bool isShown)186 void ShowHideManager::Show(const StructureBase *entity, bool isShown)
187 {
188 // make sure this is a valid entity
189 const StructureObject *object = dynamic_cast<const StructureObject *>(entity);
190 const Molecule *molecule = dynamic_cast<const Molecule *>(entity);
191 const Residue *residue = dynamic_cast<const Residue *>(entity);
192 if (!entity || !(object || molecule || residue)) {
193 ERRORMSG("ShowHideManager::Show() - must be a StructureObject, Molecule, or Residue");
194 return;
195 }
196
197 EntitiesHidden::iterator e = entitiesHidden.find(entity);
198
199 // hide an entity that's not already hidden
200 if (!isShown && e == entitiesHidden.end()) {
201 entitiesHidden[entity] = true;
202 PostRedrawEntity(object, molecule, residue);
203 entity->parentSet->renderer->ShowAllFrames();
204 }
205
206 // show an entity that's currently hidden
207 else if (isShown && e != entitiesHidden.end()) {
208 UnHideEntityAndChildren(entity);
209 PostRedrawEntity(object, molecule, residue);
210 entity->parentSet->renderer->ShowAllFrames();
211 }
212 }
213
UnHideEntityAndChildren(const StructureBase * entity)214 void ShowHideManager::UnHideEntityAndChildren(const StructureBase *entity)
215 {
216 if (!entity || !IsHidden(entity)) return;
217 const StructureObject *object = dynamic_cast<const StructureObject *>(entity);
218 const Molecule *molecule = dynamic_cast<const Molecule *>(entity);
219 const Residue *residue = dynamic_cast<const Residue *>(entity);
220
221 // if entity is residue, just remove it from the list if present
222 if (residue) {
223 EntitiesHidden::iterator h = entitiesHidden.find(residue);
224 if (h != entitiesHidden.end()) entitiesHidden.erase(h);
225 return;
226 }
227
228 // otherwise, make sure entity and its descendents are visible
229 // if it isn't already visible, then unhide this entity and all of its children
230 EntitiesHidden::iterator h, he = entitiesHidden.end();
231 for (h=entitiesHidden.begin(); h!=he; ) {
232
233 const StructureObject *hObj = dynamic_cast<const StructureObject *>(h->first);
234 if (object && !hObj)
235 h->first->GetParentOfType(&hObj);
236 const Molecule *hMol = dynamic_cast<const Molecule *>(h->first);
237 if (molecule && hObj != h->first && !hMol) // if not StructureObject or Molecule
238 h->first->GetParentOfType(&hMol); // must be residue
239
240 if (entity == h->first || // unhide the entity itself
241 (object && hObj == object) || // unhide children of a StructureObject
242 (molecule && hMol == molecule)) // unhide children of a Molecule
243 {
244 EntitiesHidden::iterator d(h);
245 ++h;
246 entitiesHidden.erase(d);
247 } else {
248 ++h;
249 }
250 }
251 PostRedrawEntity(object, molecule, residue);
252 entity->parentSet->renderer->ShowAllFrames();
253 }
254
IsHidden(const StructureBase * entity) const255 bool ShowHideManager::IsHidden(const StructureBase *entity) const
256 {
257 if (entitiesHidden.size() == 0) return false;
258
259 const StructureObject *object;
260 const Molecule *molecule;
261 const Residue *residue;
262
263 EntitiesHidden::const_iterator e = entitiesHidden.find(entity);
264
265 if ((object = dynamic_cast<const StructureObject *>(entity)) != NULL) {
266 return (e != entitiesHidden.end());
267 }
268
269 else if ((molecule = dynamic_cast<const Molecule *>(entity)) != NULL) {
270 if (!molecule->GetParentOfType(&object)) return false;
271 return (entitiesHidden.find(object) != entitiesHidden.end() ||
272 e != entitiesHidden.end());
273 }
274
275 else if ((residue = dynamic_cast<const Residue *>(entity)) != NULL) {
276 if (!residue->GetParentOfType(&molecule) ||
277 !molecule->GetParentOfType(&object)) return false;
278 return (entitiesHidden.find(object) != entitiesHidden.end() ||
279 entitiesHidden.find(molecule) != entitiesHidden.end() ||
280 e != entitiesHidden.end());
281 }
282
283 ERRORMSG("ShowHideManager::IsHidden() - must be a StructureObject, Molecule, or Residue");
284 return false;
285 }
286
ConstructShowHideArray(const StructureSet * structureSet)287 void ShowHideManager::ConstructShowHideArray(const StructureSet *structureSet)
288 {
289 ShowHideInfo *info;
290 int objectIndex, moleculeIndex;
291
292 StructureSet::ObjectList::const_iterator o, oe = structureSet->objects.end();
293 for (o=structureSet->objects.begin(); o!=oe; ++o) {
294
295 objectIndex = structureInfo.size();
296 structureInfo.push_back(new ShowHideObject(*o));
297
298 // list interesting (prot/nuc) chains
299 ChemicalGraph::MoleculeMap::const_iterator m, me = (*o)->graph->molecules.end();
300 for (m=(*o)->graph->molecules.begin(); m!=me; ++m) {
301 int nDom = 1; // # domains in this chain
302
303 if (m->second->IsProtein() || m->second->IsNucleotide()) {
304 moleculeIndex = structureInfo.size();
305 info = new ShowHideMolecule(m->second);
306 info->parentIndexes.push_back(objectIndex);
307 structureInfo.push_back(info);
308
309 // if there at least one domain, enumerate them
310 if (m->second->nDomains >= 1) {
311 StructureObject::DomainMap::const_iterator d, de = (*o)->domainMap.end();
312 for (d=(*o)->domainMap.begin(); d!=de; ++d) {
313 if (d->second == m->second) {
314 info = new ShowHideDomain(m->second, d->first, nDom++);
315 info->parentIndexes.push_back(objectIndex);
316 info->parentIndexes.push_back(moleculeIndex);
317 structureInfo.push_back(info);
318 }
319 }
320 }
321 }
322 }
323 }
324 }
325
GetShowHideInfo(vector<string> * names,vector<bool> * visibilities) const326 void ShowHideManager::GetShowHideInfo(
327 vector < string > *names, vector < bool > *visibilities) const
328 {
329 names->resize(structureInfo.size());
330 visibilities->resize(structureInfo.size());
331 for (unsigned int i=0; i<structureInfo.size(); ++i) {
332 structureInfo[i]->GetLabel(&((*names)[i]));
333 (*visibilities)[i] = structureInfo[i]->IsVisible(this);
334 }
335 }
336
ShowHideCallbackFunction(const vector<bool> & itemsEnabled)337 void ShowHideManager::ShowHideCallbackFunction(const vector < bool >& itemsEnabled)
338 {
339 if (itemsEnabled.size() != structureInfo.size()) {
340 ERRORMSG("ShowHideManager::ShowHideCallbackFunction() - wrong size list");
341 return;
342 }
343
344 for (unsigned int i=0; i<itemsEnabled.size(); ++i)
345 structureInfo[i]->Show(this, itemsEnabled[i]);
346 TRACEMSG("entities hidden: " << entitiesHidden.size());
347 }
348
SelectionChangedCallback(const vector<bool> & original,vector<bool> & itemsEnabled)349 bool ShowHideManager::SelectionChangedCallback(
350 const vector < bool >& original, vector < bool >& itemsEnabled)
351 {
352 // count number of changes
353 unsigned int i, nChanges = 0, itemChanged = 0, nEnabled = 0, itemEnabled = 0;
354 for (i=0; i<itemsEnabled.size(); ++i) {
355 if (itemsEnabled[i] != original[i]) {
356 ++nChanges;
357 itemChanged = i;
358 }
359 if (itemsEnabled[i]) {
360 ++nEnabled;
361 itemEnabled = i;
362 }
363 }
364
365 // if change was a single de/selection, then turn off/on the children of that item
366 bool anyChange = false;
367 if (nChanges == 1 || nEnabled == 1) {
368 int item = (nChanges == 1) ? itemChanged : itemEnabled;
369 for (i=item+1; i<structureInfo.size(); ++i) {
370 for (unsigned int j=0; j<structureInfo[i]->parentIndexes.size(); ++j) {
371 if (structureInfo[i]->parentIndexes[j] == item) {
372 if (itemsEnabled[i] != itemsEnabled[item]) {
373 itemsEnabled[i] = itemsEnabled[item];
374 anyChange = true;
375 }
376 }
377 }
378 }
379 }
380
381 // check all items to make sure that when an object is on, its parents are also on
382 for (i=0; i<itemsEnabled.size(); ++i) {
383 if (itemsEnabled[i]) {
384 for (unsigned int j=0; j<structureInfo[i]->parentIndexes.size(); ++j) {
385 if (!itemsEnabled[structureInfo[i]->parentIndexes[j]]) {
386 itemsEnabled[structureInfo[i]->parentIndexes[j]] = true;
387 anyChange = true;
388 }
389 }
390 }
391 }
392
393 return anyChange;
394 }
395
MakeAllVisible(void)396 void ShowHideManager::MakeAllVisible(void)
397 {
398 while (entitiesHidden.size() > 0) Show(entitiesHidden.begin()->first, true);
399 }
400
ShowAlignedDomains(const StructureSet * set)401 void ShowHideManager::ShowAlignedDomains(const StructureSet *set)
402 {
403 MakeAllVisible();
404 StructureSet::ObjectList::const_iterator o, oe = set->objects.end();
405 for (o=set->objects.begin(); o!=oe; ++o) {
406 ChemicalGraph::MoleculeMap::const_iterator m, me = (*o)->graph->molecules.end();
407 for (m=(*o)->graph->molecules.begin(); m!=me; ++m) {
408
409 if (m->second->IsNucleotide()) { // hide all nucleotides
410 Show(m->second, false);
411 continue;
412 }
413
414 if (!m->second->IsProtein()) continue; // but leave all hets/solvents visible
415
416 if (!set->alignmentManager->IsInAlignment(m->second->sequence)) {
417 Show(m->second, false);
418 continue;
419 }
420
421 map < int, bool > domains;
422 Molecule::ResidueMap::const_iterator r, re = m->second->residues.end();
423
424 // first pass determines which domains have any aligned residues
425 for (r=m->second->residues.begin(); r!=re; ++r)
426 if (set->alignmentManager->IsAligned(m->second->sequence, r->first - 1))
427 domains[m->second->residueDomains[r->first - 1]] = true;
428
429 // second pass does hides domains not represented
430 for (r=m->second->residues.begin(); r!=re; ++r)
431 if (domains.find(m->second->residueDomains[r->first - 1]) == domains.end())
432 Show(r->second, false);
433 }
434 }
435 }
436
ShowAlignedOrAnnotatedDomains(const StructureSet * set)437 void ShowHideManager::ShowAlignedOrAnnotatedDomains(const StructureSet *set)
438 {
439 MakeAllVisible();
440 StructureSet::ObjectList::const_iterator o, oe = set->objects.end();
441 for (o=set->objects.begin(); o!=oe; ++o) {
442 ChemicalGraph::MoleculeMap::const_iterator m, me = (*o)->graph->molecules.end();
443 for (m=(*o)->graph->molecules.begin(); m!=me; ++m) {
444
445 if (!(m->second->IsProtein() || m->second->IsNucleotide()))
446 continue; // but leave all hets/solvents visible
447
448 if (!(set->alignmentManager->IsInAlignment(m->second->sequence) || set->styleManager->MoleculeHasUserStyle(*o, m->second->id))) {
449 Show(m->second, false);
450 continue;
451 }
452
453 map < int, bool > domains;
454 Molecule::ResidueMap::const_iterator r, re = m->second->residues.end();
455
456 // first pass determines which domains have any aligned or annotated residues
457 for (r=m->second->residues.begin(); r!=re; ++r)
458 if (set->alignmentManager->IsAligned(m->second->sequence, r->first - 1) || set->styleManager->ResidueHasUserStyle(*o, m->second->id, r->first))
459 domains[m->second->residueDomains[r->first - 1]] = true;
460
461 // second pass does hides domains not represented
462 for (r=m->second->residues.begin(); r!=re; ++r)
463 if (domains.find(m->second->residueDomains[r->first - 1]) == domains.end())
464 Show(r->second, false);
465 }
466 }
467 }
468
ShowAlignedChains(const StructureSet * set)469 void ShowHideManager::ShowAlignedChains(const StructureSet *set)
470 {
471 MakeAllVisible();
472 StructureSet::ObjectList::const_iterator o, oe = set->objects.end();
473 for (o=set->objects.begin(); o!=oe; ++o) {
474 ChemicalGraph::MoleculeMap::const_iterator m, me = (*o)->graph->molecules.end();
475 for (m=(*o)->graph->molecules.begin(); m!=me; ++m) {
476
477 // hide all nucleotides but leave all aligned proteins + hets/solvents visible
478 if (m->second->IsNucleotide() ||
479 (m->second->IsProtein() && !set->alignmentManager->IsInAlignment(m->second->sequence)))
480 {
481 Show(m->second, false);
482 }
483 }
484 }
485 }
486
PrivateShowResidues(const StructureSet * set,bool showAligned)487 void ShowHideManager::PrivateShowResidues(const StructureSet *set, bool showAligned)
488 {
489 StructureSet::ObjectList::const_iterator o, oe = set->objects.end();
490 for (o=set->objects.begin(); o!=oe; ++o) {
491 ChemicalGraph::MoleculeMap::const_iterator m, me = (*o)->graph->molecules.end();
492 for (m=(*o)->graph->molecules.begin(); m!=me; ++m) {
493
494 if (m->second->IsNucleotide()) { // hide all nucleotides
495 Show(m->second, false);
496 continue;
497 }
498 if (!m->second->IsProtein()) continue; // but leave all hets/solvents visible
499
500 if (!set->alignmentManager->IsInAlignment(m->second->sequence)) {
501 if (showAligned) Show(m->second, false);
502 continue;
503 }
504
505 Molecule::ResidueMap::const_iterator r, re = m->second->residues.end();
506 for (r=m->second->residues.begin(); r!=re; ++r) {
507 bool aligned = set->alignmentManager->IsAligned(m->second->sequence, r->first - 1);
508 if ((showAligned && !aligned) || (!showAligned && aligned))
509 Show(r->second, false);
510 }
511 }
512 }
513 }
514
ShowResidues(const StructureSet * set,bool showAligned)515 void ShowHideManager::ShowResidues(const StructureSet *set, bool showAligned)
516 {
517 MakeAllVisible();
518 PrivateShowResidues(set, showAligned);
519 }
520
ShowUnalignedResiduesInAlignedDomains(const StructureSet * set)521 void ShowHideManager::ShowUnalignedResiduesInAlignedDomains(const StructureSet *set)
522 {
523 ShowAlignedDomains(set);
524 PrivateShowResidues(set, false);
525 }
526
ShowSelectedResidues(const StructureSet * set)527 void ShowHideManager::ShowSelectedResidues(const StructureSet *set)
528 {
529 MakeAllVisible();
530 if (!GlobalMessenger()->IsAnythingHighlighted()) return;
531
532 StructureSet::ObjectList::const_iterator o, oe = set->objects.end();
533 for (o=set->objects.begin(); o!=oe; ++o) {
534 bool anyResidueInObjectVisible = false;
535 ChemicalGraph::MoleculeMap::const_iterator m, me = (*o)->graph->molecules.end();
536 for (m=(*o)->graph->molecules.begin(); m!=me; ++m) {
537 Molecule::ResidueMap::const_iterator r, re = m->second->residues.end();
538 bool anyResidueInMoleculeVisible = false;
539 for (r=m->second->residues.begin(); r!=re; ++r) {
540 if (!GlobalMessenger()->IsHighlighted(m->second, r->first))
541 Show(r->second, false);
542 else
543 anyResidueInMoleculeVisible = anyResidueInObjectVisible = true;
544 }
545 if (!anyResidueInMoleculeVisible) {
546 for (r=m->second->residues.begin(); r!=re; ++r)
547 Show(r->second, true); // un-flag individual residues
548 Show(m->second, false); // flag whole molecule as hidden
549 }
550 }
551 if (!anyResidueInObjectVisible) {
552 for (m=(*o)->graph->molecules.begin(); m!=me; ++m)
553 Show(m->second, true); // un-flag individual molecules
554 Show(*o, false); // flag whole object as hidden
555 }
556 }
557 }
558
ShowDomainsWithHighlights(const StructureSet * set)559 void ShowHideManager::ShowDomainsWithHighlights(const StructureSet *set)
560 {
561 // first, show all highlighted stuff
562 MakeAllVisible();
563 if (!GlobalMessenger()->IsAnythingHighlighted()) return;
564 ShowSelectedResidues(set);
565
566 // then, also show all domains that contain highlighted residues
567 StructureSet::ObjectList::const_iterator o, oe = set->objects.end();
568 for (o=set->objects.begin(); o!=oe; ++o) {
569 ChemicalGraph::MoleculeMap::const_iterator m, me = (*o)->graph->molecules.end();
570 for (m=(*o)->graph->molecules.begin(); m!=me; ++m) {
571 Molecule::ResidueMap::const_iterator r, re = m->second->residues.end();
572
573 // find domains in this molecule that have highlights
574 map < int , bool > domains;
575 int domain;
576 for (r=m->second->residues.begin(); r!=re; ++r) {
577 if (GlobalMessenger()->IsHighlighted(m->second, r->first)) {
578 domain = m->second->residueDomains[r->first - 1];
579 if (domain != Molecule::NO_DOMAIN_SET)
580 domains[domain] = true;
581 }
582 }
583
584 // now show all residues in these domains
585 for (r=m->second->residues.begin(); r!=re; ++r) {
586 domain = m->second->residueDomains[r->first - 1];
587 if (domain != Molecule::NO_DOMAIN_SET && domains.find(domain) != domains.end())
588 Show(r->second, true);
589 }
590 }
591 }
592 }
593
594 END_SCOPE(Cn3D)
595