Salome HOME
Copyright update 2022
[modules/gui.git] / src / LightApp / LightApp_SelectionMgr.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 #include "LightApp_SelectionMgr.h"
24
25 #include "LightApp_Study.h"
26 #include "LightApp_DataOwner.h"
27 #include "LightApp_DataSubOwner.h"
28 #include "LightApp_Application.h"
29
30 #include <SUIT_Session.h>
31 #include <SUIT_Selector.h>
32
33 #ifndef DISABLE_SALOMEOBJECT
34   #include <SALOME_ListIO.hxx>
35
36   // Open CASCADE Include
37   #include <TColStd_MapIteratorOfMapOfInteger.hxx>
38   #include <TCollection_AsciiString.hxx>
39 #endif
40
41 #include <QtCore/QSet>
42
43 /*!
44   Constructor.
45 */
46 LightApp_SelectionMgr::LightApp_SelectionMgr( LightApp_Application* app, const bool fb )
47 : SUIT_SelectionMgr( fb ),
48   myApp( app ),
49   myTimeStamp( QTime::currentTime() ),
50   myCacheState( false )
51 {
52 }
53
54 /*!
55   Destructor.
56 */
57 LightApp_SelectionMgr::~LightApp_SelectionMgr()
58 {
59 }
60
61 /*!
62   Gets application.
63 */
64 LightApp_Application* LightApp_SelectionMgr::application() const
65 {
66   return myApp;
67 }
68
69 void LightApp_SelectionMgr::setSelected( const SUIT_DataOwnerPtrList& lst, const bool append )
70 {
71   SUIT_SelectionMgr::setSelected( lst, append );
72
73   myTimeStamp = QTime::currentTime();
74 }
75
76 #ifndef DISABLE_SALOMEOBJECT
77 /*!
78   Get a sole selected objects from selection manager. If more than one object selected, return NULL.
79   Useful to optimize performance in case of large number of objects (IPAL0054049)
80 */
81 Handle(SALOME_InteractiveObject)
82   LightApp_SelectionMgr::soleSelectedObject( const QString& theType,
83                                              const bool convertReferences ) const
84 {
85   SALOME_ListIO list;
86   selectedObjects( list, theType, convertReferences, true );
87   return  list.Extent() == 1 ? list.First() : Handle(SALOME_InteractiveObject)();
88 }
89
90 /*!
91   Get all selected objects from selection manager
92 */
93 void LightApp_SelectionMgr::selectedObjects( SALOME_ListIO& theList,
94                                              const QString& theType,
95                                              const bool     convertReferences,
96                                              const bool     sole) const
97 {
98   LightApp_Study* study = dynamic_cast<LightApp_Study*>( application()->activeStudy() );
99   if ( !study )
100     return;
101   
102   theList.Clear();
103
104   QList<Handle(SALOME_InteractiveObject)> selList;
105
106   if ( !sole && isActualSelectionCache( theType )) {
107     selList = selectionCache( theType );
108   }
109   else {
110     QStringList types;
111     if ( !theType.isEmpty() )
112       types.append( theType );
113     else
114       types = selectorTypes();
115
116     QSet<QString> aSet;
117     for ( QStringList::iterator it = types.begin(); it != types.end(); ++it ) {
118       SUIT_DataOwnerPtrList aList;
119       selected( aList, *it, sole );
120
121       QList<Handle(SALOME_InteractiveObject)> typeSelList;
122
123       for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) {
124         const LightApp_DataOwner* owner = dynamic_cast<const LightApp_DataOwner*>( (*itr).operator->() );
125         if ( !owner )
126           continue;
127
128         if ( !aSet.contains( owner->entry() ) && !owner->IO().IsNull() ) {
129           selList.append( owner->IO() );
130           aSet.insert( owner->entry() );
131         }
132
133         typeSelList.append( owner->IO() );
134       }
135
136       if ( !sole && isSelectionCacheEnabled() ) {
137         LightApp_SelectionMgr* that = (LightApp_SelectionMgr*)this;
138         that->myCacheSelection.insert( *it, typeSelList );
139         that->myCacheTimes.insert( *it, QTime::currentTime() );
140       }
141     }
142   }
143
144   QSet<QString> entrySet;
145   for ( QList<Handle(SALOME_InteractiveObject)>::const_iterator itr = selList.begin(); itr != selList.end(); ++itr )
146   {
147     Handle(SALOME_InteractiveObject) io = *itr;
148     QString entry( io->getEntry() );
149     // Entry to check object uniqueness.
150     // It is selected owner entry in the case, when we do not convert references,
151     // and entry of a real object, when we convert references.
152     if ( convertReferences ) {
153       QString refEntry = study->referencedToEntry( entry );
154       if ( !entrySet.contains( refEntry ) ) {
155         if ( refEntry != entry ) {
156           entry = refEntry;
157           QString component = study->componentDataType( entry );
158           theList.Append( new SALOME_InteractiveObject( (const char*)entry.toUtf8(),
159                                                         (const char*)component.toLatin1(),
160                                                         ""/*refobj->Name().c_str()*/ ) );
161         }
162         else if ( !io.IsNull() )
163           theList.Append( io );
164       }
165     }
166     else if ( !entrySet.contains( entry ) && !io.IsNull() )
167       theList.Append( io );
168
169     entrySet.insert( entry );
170   }
171
172   if ( sole && theList.Extent() > 1 )
173     theList.Clear();
174 }
175
176 /*!
177   Append selected objects.
178 */
179 void LightApp_SelectionMgr::setSelectedObjects( const SALOME_ListIO& lst, const bool append )
180 {
181   SUIT_DataOwnerPtrList owners;
182   for ( SALOME_ListIteratorOfListIO it( lst ); it.More(); it.Next() )
183   {
184     if ( it.Value()->hasEntry() )
185       owners.append( new LightApp_DataOwner( it.Value() ) );
186   }
187
188   setSelected( owners, append );
189 }
190
191 #else
192 /*!
193   Get all selected objects from selection manager
194 */
195 void LightApp_SelectionMgr::selectedObjects( QStringList& theList, const QString& theType,
196                                              const bool convertReferences ) const
197 {
198   LightApp_Study* study = dynamic_cast<LightApp_Study*>( application()->activeStudy() );
199   if ( !study )
200     return;
201
202   theList.clear();
203
204   QStringList selList;
205
206   if ( isActualSelectionCache( theType ) )
207     selList = selectionCache( theType );
208   else {
209     QStringList types;
210     if ( !theType.isEmpty() )
211       types.append( theType );
212     else
213       types = selectorTypes();
214
215     QSet<QString> aSet;
216     for ( QStringList::iterator it = types.begin(); it != types.end(); ++it ) {
217       SUIT_DataOwnerPtrList aList;
218       selected( aList, *it );
219
220       QStringList typeSelList;
221
222       for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr ) {
223         const LightApp_DataOwner* owner = dynamic_cast<const LightApp_DataOwner*>( (*itr).operator->() );
224         if ( !owner )
225           continue;
226
227         if ( !aSet.contains( owner->entry() ) ) {
228           selList.append( owner->entry() );
229           aSet.insert( owner->entry() );
230         }
231
232         typeSelList.append( owner->entry() );
233       }
234
235       if ( isSelectionCacheEnabled() ) {
236         LightApp_SelectionMgr* that = (LightApp_SelectionMgr*)this;
237         that->myCacheSelection.insert( *it, typeSelList );
238         that->myCacheTimes.insert( *it, QTime::currentTime() );
239       }
240     }
241   }
242
243   theList = selList;
244 }
245
246 /*!
247   Append selected objects.
248 */
249 void LightApp_SelectionMgr::setSelectedObjects( const QStringList& lst, const bool append )
250 {
251   SUIT_DataOwnerPtrList owners;
252   foreach( const QString& aValue, lst ) {
253     if ( !aValue.isNull() )
254       owners.append( new LightApp_DataOwner( aValue ) );
255   }
256
257   setSelected( owners, append );
258 }
259
260 #endif
261
262 /*!
263   Emit current selection changed.
264 */
265 void LightApp_SelectionMgr::selectionChanged( SUIT_Selector* theSel )
266 {
267   SUIT_SelectionMgr::selectionChanged( theSel );
268
269   myTimeStamp = QTime::currentTime();
270
271   emit currentSelectionChanged();
272 }
273
274 #ifndef DISABLE_SALOMEOBJECT
275
276 /*!
277   get map of indexes for the given SALOME_InteractiveObject
278 */
279 void LightApp_SelectionMgr::GetIndexes( const Handle(SALOME_InteractiveObject)& IObject,
280                                         TColStd_IndexedMapOfInteger& theIndex)
281 {
282   theIndex.Clear();
283
284   SUIT_DataOwnerPtrList aList;
285   selected( aList );
286
287   for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr )
288   {
289     LightApp_DataSubOwner* subOwner = dynamic_cast<LightApp_DataSubOwner*>( (*itr).operator->() );
290     if ( subOwner && subOwner->entry() == QString(IObject->getEntry()) )
291       theIndex.Add( subOwner->index() );
292   }
293 }
294
295 /*!
296   get map of indexes for the given entry of SALOME_InteractiveObject
297 */
298 void LightApp_SelectionMgr::GetIndexes( const QString& theEntry, TColStd_IndexedMapOfInteger& theIndex )
299 {
300   theIndex.Clear();
301
302   SUIT_DataOwnerPtrList aList;
303   selected( aList );
304
305   for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr )
306   {
307     const LightApp_DataSubOwner* subOwner = dynamic_cast<const LightApp_DataSubOwner*>( (*itr).operator->() );
308     if ( subOwner )
309       if ( subOwner->entry() == theEntry )
310         theIndex.Add( subOwner->index() );
311   }
312
313 }
314
315 /*!
316   Add or remove interactive objects from selection manager.
317 */
318 //bool LightApp_SelectionMgr::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& IObject,
319 void LightApp_SelectionMgr::AddOrRemoveIndex( const Handle(SALOME_InteractiveObject)& IObject,
320                                               const TColStd_MapOfInteger& theIndexes,
321                                               bool modeShift)
322 {
323   SUIT_DataOwnerPtrList remainsOwners;
324
325   SUIT_DataOwnerPtrList aList;
326   selected( aList );
327
328   QString ioEntry (IObject->getEntry());
329
330   if ( !modeShift ) {
331     for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr )
332     {
333       const LightApp_DataOwner* owner = dynamic_cast<const LightApp_DataOwner*>( (*itr).operator->() );
334       if ( owner )
335       {
336         if ( owner->entry() != ioEntry )
337         {
338           const LightApp_DataSubOwner* subOwner = dynamic_cast<const LightApp_DataSubOwner*>( owner );
339           if ( subOwner )
340             remainsOwners.append( new LightApp_DataSubOwner( subOwner->entry(), subOwner->index() ) );
341           else
342             remainsOwners.append( new LightApp_DataOwner( owner->entry() ) );
343         }
344       }
345     }
346   }
347   else
348     remainsOwners = aList;
349
350   TColStd_MapIteratorOfMapOfInteger It;
351   It.Initialize(theIndexes);
352   for(;It.More();It.Next())
353     remainsOwners.append( new LightApp_DataSubOwner( ioEntry, It.Key() ) );
354
355   bool append = false;
356   setSelected( remainsOwners, append );
357
358   emit currentSelectionChanged();
359
360   // Bug 17269: To avoid calling of selected(aList)
361   //TColStd_IndexedMapOfInteger anIndexes;
362   //GetIndexes( IObject, anIndexes );
363   //return !anIndexes.IsEmpty();
364 }
365
366 /*!
367   select 'subobjects' with given indexes
368 */
369 void LightApp_SelectionMgr::selectObjects( const Handle(SALOME_InteractiveObject)& IObject,
370                                             TColStd_IndexedMapOfInteger theIndex, bool append )
371 {
372   SUIT_DataOwnerPtrList aList;
373
374   if ( theIndex.IsEmpty() )
375     aList.append( new LightApp_DataOwner( QString(IObject->getEntry()) ) );
376   else
377     {
378       int i;
379       for ( i = 1; i <= theIndex.Extent(); i++ )
380         aList.append( new LightApp_DataSubOwner( QString(IObject->getEntry()), theIndex( i ) ) );
381     }
382
383   setSelected( aList, append );
384 }
385
386 /*!
387   select 'subobjects' with given indexes
388 */
389 void LightApp_SelectionMgr::selectObjects( MapIOOfMapOfInteger theMapIO, bool append )
390 {
391   SUIT_DataOwnerPtrList aList;
392
393   MapIOOfMapOfInteger::Iterator it(theMapIO);
394   for ( ; it.More(); it.Next() )
395     {
396       if ( it.Value().IsEmpty() )
397         aList.append( new LightApp_DataOwner( QString(it.Key()->getEntry()) ) );
398       else
399         {
400           int i;
401           for ( i = 1; i <= it.Value().Extent(); i++ )
402             aList.append( new LightApp_DataSubOwner( QString(it.Key()->getEntry()), it.Value()( i ) ) );
403         }
404     }
405
406   setSelected( aList, append );
407 }
408
409 /*!
410   get map of selected subowners : object's entry <-> map of indexes
411 */
412 void LightApp_SelectionMgr::selectedSubOwners( MapEntryOfMapOfInteger& theMap )
413 {
414   theMap.Clear();
415
416   TColStd_IndexedMapOfInteger anIndexes;
417
418   SUIT_DataOwnerPtrList aList;
419   selected( aList );
420
421   for ( SUIT_DataOwnerPtrList::const_iterator itr = aList.begin(); itr != aList.end(); ++itr )
422   {
423     const LightApp_DataSubOwner* subOwner =
424       dynamic_cast<const LightApp_DataSubOwner*>( (*itr).operator->() );
425     if ( subOwner )
426     {
427 //#ifndef WIN32
428       if ( !theMap.IsBound( TCollection_AsciiString(subOwner->entry().toUtf8().data()) ) )
429 //#else
430 //      if ( !theMap.IsBound( subOwner->entry().toLatin1().data() ) )
431 //#endif
432       {
433         anIndexes.Clear();
434         //Bug 17269: GetIndexes( subOwner->entry(), anIndexes );
435         //Bug 17269: To avoid multiple calling of selected(aList)
436         for ( SUIT_DataOwnerPtrList::const_iterator itr2 = itr; itr2 != aList.end(); ++itr2 )
437         {
438           const LightApp_DataSubOwner* subOwner2 =
439             dynamic_cast<const LightApp_DataSubOwner*>( (*itr2).operator->() );
440           if ( subOwner2 )
441             if ( subOwner2->entry() == subOwner->entry() )
442               anIndexes.Add( subOwner2->index() );
443         }
444         //
445         theMap.Bind( subOwner->entry().toUtf8().data(), anIndexes );
446       }
447     }
448   }
449 }
450
451 #endif
452
453 void LightApp_SelectionMgr::clearSelectionCache()
454 {
455   myCacheTimes.clear();
456   myCacheSelection.clear();
457 }
458
459 bool LightApp_SelectionMgr::isSelectionCacheEnabled() const
460 {
461   return myCacheState;
462 }
463
464 void LightApp_SelectionMgr::setSelectionCacheEnabled( bool on )
465 {
466   if ( myCacheState == on )
467     return;
468
469   myCacheState = on;
470
471   if ( !myCacheState )
472     clearSelectionCache();
473 }
474
475 #ifndef DISABLE_SALOMEOBJECT
476
477 QList<Handle(SALOME_InteractiveObject)> LightApp_SelectionMgr::selectionCache( const QString& type ) const
478 {
479   QList<Handle(SALOME_InteractiveObject)> res;
480
481   QStringList types;
482   if ( !type.isEmpty() )
483     types.append( type );
484   else
485     types = selectorTypes();
486
487   QSet<QString> set;
488   for ( QStringList::iterator it = types.begin(); it != types.end(); ++it ) {
489     if ( myCacheSelection.contains( *it ) ) {
490       const SelList& lst = myCacheSelection[*it];
491       for ( SelList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
492         if ( !(*itr).IsNull() && !set.contains( (*itr)->getEntry() ) ) {
493           res.append( *itr );
494           set.insert( (*itr)->getEntry() );
495         }
496       }
497     }
498   }
499   return res;
500 }
501
502 #else
503
504 QStringList LightApp_SelectionMgr::selectionCache( const QString& type ) const
505 {
506   QStringList res;
507
508   QStringList types;
509   if ( !type.isEmpty() )
510     types.append( type );
511   else
512     types = selectorTypes();
513
514   QSet<QString> set;
515   for ( QStringList::iterator it = types.begin(); it != types.end(); ++it ) {
516     if ( myCacheSelection.contains( *it ) ) {
517       const SelList& lst = myCacheSelection[*it];
518       for ( SelList::const_iterator itr = lst.begin(); itr != lst.end(); ++itr ) {
519         if ( !set.contains( *itr ) ) {
520           res.append( *itr );
521           set.insert( *itr );
522         }
523       }
524     }
525   }
526   return res;
527 }
528
529 #endif
530
531 bool LightApp_SelectionMgr::isActualSelectionCache( const QString& type ) const
532 {
533   bool ok = true;
534
535   QStringList types;
536   if ( !type.isEmpty() )
537     types.append( type );
538   else
539     types = selectorTypes();
540
541   for ( QStringList::iterator it = types.begin(); it != types.end() && ok; ++it )
542     ok = myCacheTimes.contains( *it ) && myCacheTimes[*it].isValid() && myCacheTimes[*it] >= myTimeStamp;
543
544   return ok;
545 }
546
547 QStringList LightApp_SelectionMgr::selectorTypes() const
548 {
549   QStringList types;
550   QList<SUIT_Selector*> selectorList;
551   selectors( selectorList );
552   for ( QList<SUIT_Selector*>::const_iterator it = selectorList.begin(); it != selectorList.end(); ++it ) {
553     if ( (*it)->isEnabled() )
554       types.append( (*it)->type() );
555   }
556   return types;
557 }