Salome HOME
7be058d11fe0ff621dc092d7d4f7d5fd43a9965c
[modules/gui.git] / src / LightApp / LightApp_DataObject.cxx
1 // Copyright (C) 2007-2023  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 // File   : LightApp_DataObject.cxx
24 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
25
26 #include "LightApp_DataObject.h"
27 #include "LightApp_Study.h"
28 #include "LightApp_DataModel.h"
29 #include "LightApp_Module.h"
30 #include "LightApp_Application.h"
31
32 #include <CAM_Module.h>
33 #include <SUIT_DataObjectKey.h>
34
35 #include <QVariant>
36
37 #include <iostream>
38
39 /*!
40   \class LightApp_DataObject::Key
41   \brief Represents unique data object key for the LightApp_DataObject
42   class instances.
43   \internal
44 */
45
46 class LightApp_DataObject::Key : public SUIT_DataObjectKey
47 {
48 public:
49   Key( const QString& );
50   virtual ~Key();
51
52   virtual bool isLess( const SUIT_DataObjectKey* ) const;
53   virtual bool isEqual( const SUIT_DataObjectKey* ) const;
54
55 private:
56   QString myEntry;
57 };
58
59 /*!
60   \brief Constructor.
61   \internal
62   \param entry data object entry
63 */
64 LightApp_DataObject::Key::Key( const QString& entry )
65 : SUIT_DataObjectKey(),
66   myEntry( entry )
67 {
68 }
69
70 /*!
71   \brief Destructor.
72   \internal
73 */
74 LightApp_DataObject::Key::~Key()
75 {
76 }
77
78 /*!
79   \brief Compares this key with the another one.
80   \internal
81   \param other another data object key
82   \return \c true if this key is less than \a other.
83 */
84 bool LightApp_DataObject::Key::isLess( const SUIT_DataObjectKey* other ) const
85 {
86   Key* that = (Key*)other;
87   return myEntry < that->myEntry;
88 }
89
90 /*!
91   \brief Compares this key with the another one.
92   \internal
93   \param other another data object key
94   \return \c true if this key is equal to the \a other.
95 */
96 bool LightApp_DataObject::Key::isEqual( const SUIT_DataObjectKey* other ) const
97 {
98   Key* that = (Key*)other;
99   return myEntry == that->myEntry;
100 }
101
102 /*!
103   \class LightApp_DataObject
104   \brief Base data object class to build the data model for all the SALOME modules.
105 */
106
107 /*!
108   \brief Constructor.
109   \param parent parent data object
110 */
111 LightApp_DataObject::LightApp_DataObject( SUIT_DataObject* parent )
112 : CAM_DataObject( parent ),
113   myCompDataType( "" ),
114   myCompObject( 0 )
115 {
116 }
117
118 /*!
119   \brief Destructor.
120 */
121 LightApp_DataObject::~LightApp_DataObject()
122 {
123 }
124
125 int LightApp_DataObject::groupId() const
126 {
127   LightApp_DataModel* m = dynamic_cast<LightApp_DataModel*>( dataModel() );
128   return m ? m->groupId() : CAM_DataObject::groupId();
129 }
130
131 /*!
132   \brief return custom data for data object
133 */
134 QVariant LightApp_DataObject::customData(Qtx::CustomDataType type) {
135   switch(type) {
136   case Qtx::IdType:
137     return EntryId;
138     break;
139   default:
140     return QVariant();
141     break;
142   }
143 }
144
145 /*!
146   \brief Check if the object is visible.
147   \return \c true if this object is displayable or \c false otherwise
148 */
149 bool LightApp_DataObject::isVisible() const
150 {
151   LightApp_RootObject* r = dynamic_cast<LightApp_RootObject*>( root() );
152   return r && r->study() && componentDataType() != r->study()->getVisualComponentName();
153 }
154
155 /*!
156   \brief Check if the object is draggable.
157
158   This method can be re-implemented in the subclasses.
159
160   \return \c true if it is possible to drag this object
161 */
162 bool LightApp_DataObject::isDraggable() const
163 {
164   LightApp_Module* aModule = dynamic_cast<LightApp_Module*>(module());
165   if (aModule) {
166     return aModule->isDraggable(this);
167   }
168   return false;
169 }
170
171 /*!
172   \brief Check if the drop operation fo this object is possible.
173
174   This method can be re-implemented in the subclasses.
175
176   \param obj object being dropped
177   \return \c true if it is possible to drop an object \c obj
178           to this object
179 */
180 bool LightApp_DataObject::isDropAccepted() const
181 {
182   LightApp_Module* aModule = dynamic_cast<LightApp_Module*>(module());
183   if (aModule) {
184     return aModule->isDropAccepted(this);
185   }
186   return false;
187 }
188
189 /*!
190   \brief Check if this object is can't be renamed in place
191
192   This method can be re-implemented in the subclasses.
193   Default implementation returns \c false (all objects can not be renamed).
194
195   \param id column id
196   \return \c true if the item can be renamed by the user in place (e.g. in the Object browser)
197 */
198 bool LightApp_DataObject::renameAllowed( const int id ) const
199 {
200   if ( id == NameId ) {
201     LightApp_Module* m = dynamic_cast<LightApp_Module*>( module() );
202     LightApp_Application* app = 0;
203     LightApp_RootObject* r = dynamic_cast<LightApp_RootObject*>( root() );
204     if(r && r->study())
205       app  = dynamic_cast<LightApp_Application*>(r->study()->application());
206
207     return ( m && m->renameAllowed( entry() ) ) ||
208       ( app && app->renameAllowed( entry() ) );
209   }
210   return CAM_DataObject::renameAllowed( id );
211 }
212
213
214 /*!
215   \brief Set name of the this object.
216
217   This method can be re-implemented in the subclasses.
218   Default implementation returns \c false.
219
220   \return \c true if rename operation finished successfully, \c false otherwise.
221 */
222 bool LightApp_DataObject::setName(const QString& name)
223 {
224     LightApp_Module* m = dynamic_cast<LightApp_Module*>( module() );
225     LightApp_RootObject* r = dynamic_cast<LightApp_RootObject*>( root() );
226     LightApp_Application* app =
227       (r && r->study()) ? dynamic_cast<LightApp_Application*>(r->study()->application()) : 0;
228
229     return ( m && m->renameObject( entry(), name ) ) ||
230            ( app && app->renameObject( entry(), name ) );
231   return CAM_DataObject::setName(name);
232 }
233
234
235 /*!
236   \brief Get object string identifier.
237
238   This method should be reimplemented in the subclasses.
239   Default implementation returns null string.
240
241   \return object ID
242 */
243 QString LightApp_DataObject::entry() const
244 {
245   return QString();
246 }
247
248 /*!
249   \brief Returns the string identifier of the data objects referenced by this one.
250
251   This method should be reimplemented in the subclasses.
252   Default implementation returns null string.
253
254   \return ID string of the referenced data object
255 */
256 QString LightApp_DataObject::refEntry() const
257 {
258   return QString();
259 }
260
261 /*!
262   \brief Tells if this data objects is a reference to some other or not.
263
264   The base implementation retuns true, if refEntry() returns non-empty string.
265
266   \return true if refEntry() is a non-empty string.
267 */
268 bool LightApp_DataObject::isReference() const
269 {
270   return !refEntry().isEmpty();
271 }
272
273 /*!
274   \brief Get the data object unique key.
275   \return data object key
276 */
277 SUIT_DataObjectKey* LightApp_DataObject::key() const
278 {
279   QString str = entry();
280   return new Key( str );
281 }
282
283 /*!
284   \brief Get object text data for the specified column.
285
286   Column with \a id == NameId is supposed to be used
287   to get the object name.
288   Column with \a id == EntryId is supposed to be used
289   to get the object entry.
290   Column with \a id == RefEntryId is supposed to be used
291   to show the entry of the object referenced by this one.
292
293   \param id column id
294   \return object text data
295 */
296 QString LightApp_DataObject::text( const int id ) const
297 {
298   QString txt;
299   
300   switch ( id )
301   {
302   case EntryId:
303     txt = entry();
304     break;
305   case RefEntryId:
306     // Issue 21379: reference support at LightApp level
307     if ( isReference() )
308       txt = refEntry();
309     break;
310   default:
311     // Issue 21379: Note that we cannot return some specially decorated
312     // name string (like "* ref_obj_name") when isReference() returns true, 
313     // since there is no generic way at LightApp level
314     // to query the object name using refEntry() up to now.
315     // TODO: Think how to make reference name generation
316     // more generic at move it here from SalomeApp level...
317     txt = CAM_DataObject::text( id );
318     break;
319   }
320
321   return txt;
322 }
323
324 /*!
325   \brief Get data object color for the specified column.
326   \param role color role
327   \param id column id (not used)
328   \return object color for the specified column
329 */
330 QColor LightApp_DataObject::color( const ColorRole role, const int id) const
331 {
332   QColor c;
333
334   // Issue 21379: reference support at LightApp level
335   // Centralized way for choosing text/background color for references.
336   // Colors for "normal" objects should be chosen by sub-classes.
337   switch ( role )
338   {
339   case Text:
340   case Foreground:
341     // text color (not selected item)
342     // TODO: think how to detect invalid references...
343     if ( isReference() )
344       c = QColor( 255, 0, 0 );      // valid reference (red)
345     break;
346
347   case Highlight:
348     // background color for the highlighted item
349     // TODO: think how to detect invalid references...
350     if ( isReference() ) 
351       c = QColor( 255, 0, 0 );      // valid reference (red)
352     break;
353
354   case HighlightedText:
355     // text color for the highlighted item
356     if ( isReference() )
357       c = QColor( 255, 255, 255 );   // white
358     break;
359
360   default:
361     break;
362   }
363
364   if ( !c.isValid() )
365     c = CAM_DataObject::color( role, id );
366
367   return c;
368 }
369
370 /*!
371   \brief Get the component object.
372   \return component data object
373 */
374 SUIT_DataObject* LightApp_DataObject::componentObject() const
375 {
376   if ( !myCompObject ) {
377     SUIT_DataObject* compObj = (SUIT_DataObject*)this;
378
379     while ( compObj && compObj->parent() && compObj->parent() != root() ) {
380       compObj = compObj->parent();
381     }
382     LightApp_DataObject* that = (LightApp_DataObject*)this;
383     that->myCompObject = compObj;
384   }
385   return myCompObject;
386 }
387
388 /*!
389   \brief Get component type.
390   \return component type
391 */
392 QString LightApp_DataObject::componentDataType() const
393 {
394   if ( myCompDataType.isEmpty() ) {
395     SUIT_DataObject* aCompObj = componentObject();
396     CAM_ModuleObject* anObj = dynamic_cast<CAM_ModuleObject*>( aCompObj );
397     if ( anObj ) {
398       CAM_DataModel* aModel = anObj->dataModel();
399       if ( aModel ) {
400         LightApp_DataObject* that = (LightApp_DataObject*)this;
401         that->myCompDataType = aModel->module()->name();
402       }
403     }
404   }
405   return myCompDataType;
406 }
407
408 /*!
409   \brief Check if the specified column supports custom sorting.
410   \param id column id
411   \return \c true if column sorting should be customized
412   \sa compare()
413 */
414 bool LightApp_DataObject::customSorting( const int id ) const
415 {
416   // perform custom sorting for the "Entry" column
417   return id == EntryId ? true : CAM_DataObject::customSorting( id );
418 }
419
420 /*!
421   \brief Compares data from two items for sorting purposes.
422
423   This method is called only for those columns for which customSorting()
424   method returns \c true.
425
426   \param left first data to compare
427   \param right second data to compare
428   \param id column id
429   \return result of the comparison
430   \sa customSorting()
431 */
432 bool LightApp_DataObject::compare( const QVariant& left, const QVariant& right, const int id ) const
433 {
434   if ( id == EntryId )
435   {
436     // perform custom sorting for the "Entry" column
437     QString leftStr  = left.toString();
438     QString rightStr = right.toString();
439     QStringList idsLeft  = leftStr.split( ":", QString::SkipEmptyParts );
440     QStringList idsRight = rightStr.split( ":", QString::SkipEmptyParts );
441     if ( idsLeft.count() > 1 || idsRight.count() > 1 ) {
442       bool result = true;
443       bool calculated = false;
444       for ( int i = 0; i < idsLeft.count() || i < idsRight.count(); i++ ) {
445         bool okLeft = true, okRight = true;
446         int lid = 0, rid = 0;
447         if ( i < idsLeft.count() )
448           lid = idsLeft[i].toInt( &okLeft );
449         if ( i < idsRight.count() )
450           rid = idsRight[i].toInt( &okRight );
451         if ( okLeft && okRight ) {
452           // both seem to be correct integer ID
453           if ( lid < rid ) return true;
454         }
455         else if ( okLeft || okRight ) {
456           // objects with correct (int) ID have higher priority
457           return okLeft;
458         }
459         else {
460           // both not integer ID
461           int r = QString::localeAwareCompare( idsLeft[i], idsRight[i] );
462           if ( !calculated && r != 0 ) {
463             result = r < 0;
464             calculated = true;
465           }
466         }
467       }
468       // we should reach this if the entries are exactly equal
469       return result;
470     }
471     return QString::localeAwareCompare( leftStr, rightStr ) < 0;
472   }
473   return CAM_DataObject::compare( left, right, id );
474 }
475
476 /*!
477   \class LightApp_ModuleObject
478   \brief Used for optimized access to the data model from the data objects.
479   \sa CAM_ModuleObject class
480 */
481
482 /*!
483   \brief Constructor.
484   \param parent parent data object
485 */
486 LightApp_ModuleObject::LightApp_ModuleObject( SUIT_DataObject* parent )
487 : CAM_DataObject( parent ),
488   LightApp_DataObject( parent ),
489   CAM_ModuleObject( parent )
490 {
491 }
492
493 /*!
494   \brief Constructor.
495   \param dm data model
496   \param parent parent data object
497 */
498 LightApp_ModuleObject::LightApp_ModuleObject( CAM_DataModel* dm, SUIT_DataObject* parent )
499 : CAM_DataObject( parent ),
500   LightApp_DataObject( parent ),
501   CAM_ModuleObject( dm, parent )
502 {
503 }
504
505 /*
506   \brief Destructor.
507 */
508 LightApp_ModuleObject::~LightApp_ModuleObject()
509 {
510 }
511
512 /*!
513   \brief Get module name.
514   \return module name
515 */
516 QString LightApp_ModuleObject::name() const
517 {
518   return CAM_ModuleObject::name();
519 }
520
521 /*!
522   \brief Get data object icon for the specified column.
523   \param id column id
524   \return object icon for the specified column
525 */
526 QPixmap LightApp_ModuleObject::icon( const int id ) const
527 {
528   return CAM_ModuleObject::icon( id );
529 }
530
531 /*!
532   \brief Get data object tooltip for the specified column.
533   \param id column id
534   \return object tooltip for the specified column
535 */
536 QString LightApp_ModuleObject::toolTip( const int id ) const
537 {
538   return CAM_ModuleObject::toolTip( id );
539 }
540
541 /*!
542   \brief Insert new child object to the children list at specified position.
543
544   Adds component in the study for this module object if it is not done yet.
545
546   \param obj object to be inserted
547   \param pos position at which data object should be inserted
548 */
549 void LightApp_ModuleObject::insertChild( SUIT_DataObject* obj, int pos )
550 {
551   LightApp_DataObject::insertChild( obj, pos );
552
553   CAM_DataModel* aModel = dataModel();
554
555   LightApp_RootObject* aRoot = dynamic_cast<LightApp_RootObject*>( parent() );
556
557   if ( aRoot )
558     aRoot->study()->addComponent( aModel );
559 }
560
561 /*!
562   \class LightApp_RootObject
563   \brief Root data object for the light (without CORBA) SALOME application.
564
565   This class is to be instanciated by only one object - the root object
566   of the LightApp data object tree. This object is not shown in the object browser.
567   The goal of this class is to provide a unified access to LightApp_Study
568   object from LightApp_DataObject instances.
569 */
570
571 /*
572   \brief Constructor.
573   \param study study
574 */
575 LightApp_RootObject::LightApp_RootObject( LightApp_Study* study )
576 : CAM_DataObject( 0 ),
577   LightApp_DataObject( 0 ),
578   myStudy( study )
579 {
580 }
581
582 /*
583   \brief Destructor.
584 */
585 LightApp_RootObject::~LightApp_RootObject()
586 {
587 }
588
589 /*
590   \brief Set study.
591   \param study pointer to the study
592 */
593 void LightApp_RootObject::setStudy( LightApp_Study* study )
594 {
595   myStudy = study;
596 }
597
598 /*
599   \brief Get study
600   \return pointer to the study
601 */
602 LightApp_Study* LightApp_RootObject::study() const
603 {
604   return myStudy;
605 }