Salome HOME
updated copyright message
[modules/gui.git] / src / SUIT / SUIT_ViewManager.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 #include "SUIT_ViewManager.h"
24
25 #include "SUIT_Desktop.h"
26 #include "SUIT_ViewModel.h"
27 #include "SUIT_ViewWindow.h"
28 #include "SUIT_Study.h"
29 #include "SUIT_Session.h"
30
31 #include <QMap>
32 #include <QRegExp>
33 #include <QIcon>
34
35 #ifdef WIN32
36 #include <windows.h>
37 #endif
38
39 QMap<QString, int> SUIT_ViewManager::_ViewMgrId;
40
41 /*!\class SUIT_ViewManager.
42  * Class provide manipulation with view windows.
43  */
44
45 /*!Constructor.*/
46 SUIT_ViewManager::SUIT_ViewManager( SUIT_Study* theStudy,
47                                     SUIT_Desktop* theDesktop,
48                                     SUIT_ViewModel* theViewModel )
49 : QObject( 0 ),
50   myDesktop( theDesktop ),
51   myTitle( "Default: %M - viewer %V" ),
52   myStudy( NULL ),
53   myIsDetached( false )
54 {
55   myViewModel = 0;
56   myActiveView = 0;
57   setViewModel( theViewModel );
58
59   myId = useNewId( getType() );
60
61   if( theDesktop )
62   {
63     connect( theDesktop, SIGNAL( windowActivated( SUIT_ViewWindow* ) ),
64              this,       SLOT( onWindowActivated( SUIT_ViewWindow* ) ) );
65   }
66
67   myStudy = theStudy;
68   if ( myStudy )
69     connect( myStudy, SIGNAL( destroyed() ), this, SLOT( onDeleteStudy() ) );
70 }
71
72 /*!Destructor.*/
73 SUIT_ViewManager::~SUIT_ViewManager()
74 {
75   if ( myViewModel )
76   {
77     myViewModel->setViewManager( 0 );
78     delete myViewModel;
79   }
80 }
81
82 int SUIT_ViewManager::useNewId( const QString& type )
83 {
84   if ( !_ViewMgrId.contains( type ) )
85     _ViewMgrId.insert( type, 0 );
86
87   int id = _ViewMgrId[type];
88   _ViewMgrId[type]++;
89   return id;
90 }
91
92
93 int SUIT_ViewManager::getGlobalId() const {
94   int id = -1;
95   SUIT_Application* app = SUIT_Session::session()->activeApplication();
96   if(app) {
97     id = app->viewManagerId(this);
98   }
99   return id;
100 }
101
102 void SUIT_ViewManager::setTitle( const QString& theTitle )
103 {
104   if ( myTitle == theTitle )
105     return;
106
107   myTitle = theTitle;
108   for ( int i = 0; i < myViews.count(); i++ )
109     setViewName( myViews[i] );
110 }
111
112 void SUIT_ViewManager::setIcon( const QPixmap& theIcon )
113 {
114   myIcon = theIcon;
115   for ( int i = 0; i < myViews.count(); i++ )
116     myViews[i]->setWindowIcon( QIcon( myIcon ) );
117 }
118
119 /*!Sets view model \a theViewModel to view manager.*/
120 void SUIT_ViewManager::setViewModel(SUIT_ViewModel* theViewModel)
121 {
122   if (myViewModel && myViewModel != theViewModel) {
123     myViewModel->setViewManager(0);
124     delete myViewModel;
125   }
126   myViewModel = theViewModel;
127   if (myViewModel)
128     myViewModel->setViewManager(this);
129 }
130
131 /*!Sets view name for view window \a theView.*/
132 void SUIT_ViewManager::setViewName( SUIT_ViewWindow* theView )
133 {
134   QString title = prepareTitle( getTitle(), myId + 1, myViews.indexOf( theView ) + 1 );
135   theView->setWindowTitle( title );
136 }
137
138 QString SUIT_ViewManager::prepareTitle( const QString& title, const int mId, const int vId )
139 {
140   QString res = title;
141   QRegExp re( "%[%MV]" );
142   int i = 0;
143   while ( ( i = re.indexIn( res, i ) ) != -1 )
144   {
145     QString rplc;
146     QString str = res.mid( i, re.matchedLength() );
147     if ( str == QString( "%%" ) )
148       rplc = QString( "%" );
149     else if ( str == QString( "%M" ) )
150       rplc = QString::number( mId );
151     else if ( str == QString( "%V" ) )
152       rplc = QString::number( vId );
153     res.replace( i, re.matchedLength(), rplc );
154     i += rplc.length();
155   }
156   return res;
157 }
158
159 /*! Creates View, adds it into list of views and returns just created view window*/
160 SUIT_ViewWindow* SUIT_ViewManager::createViewWindow()
161 {
162   SUIT_ViewWindow* aView = myViewModel->createView(myDesktop);
163
164   if ( !insertView( aView ) ){
165     delete aView;
166     return 0;
167   }
168
169   setViewName( aView );
170   aView->setWindowIcon( QIcon( myIcon ) );
171
172   //myDesktop->addViewWindow( aView );
173   //it is done automatically during creation of view
174
175   aView->setViewManager( this );
176   emit viewCreated( aView );
177
178   // Special treatment for the case when <aView> is the first one in this view manager
179   // -> call onWindowActivated() directly, because somebody may always want
180   // to use getActiveView()
181   if ( !myActiveView )
182     onWindowActivated( aView );
183
184   return aView;
185 }
186
187 /*! Get identifier */
188 int SUIT_ViewManager::getId() const
189 {
190   return myId;
191 }
192
193 /*!Create view window.*/
194 void SUIT_ViewManager::createView()
195 {
196   createViewWindow();
197 }
198
199 QVector<SUIT_ViewWindow*> SUIT_ViewManager::getViews() const
200 {
201   QVector<SUIT_ViewWindow*> res;
202   for ( int i = 0; i < myViews.count(); i++ )
203   {
204     if ( myViews[i] )
205       res.append( myViews[i] );
206   }
207
208   return res;
209 }
210
211 /*!Insert view window to view manager.
212  *\retval false - if something wrong, else true.
213  */
214 bool SUIT_ViewManager::insertView(SUIT_ViewWindow* theView)
215 {
216   int aSize = myViews.size();
217   int aNbItems = myViews.count() + 1;
218   if ( aNbItems > aSize )
219   {
220     myViews.resize( aNbItems );
221     aSize = myViews.size();
222   }
223
224   connect(theView, SIGNAL(closing(SUIT_ViewWindow*)),
225           this,    SLOT(onClosingView(SUIT_ViewWindow*)));
226
227   connect(theView, SIGNAL(tryClosing(SUIT_ViewWindow*)),
228           this,    SIGNAL(tryCloseView(SUIT_ViewWindow*)));
229
230   connect(theView, SIGNAL(mousePressed(SUIT_ViewWindow*, QMouseEvent*)),
231           this,    SLOT(onMousePressed(SUIT_ViewWindow*, QMouseEvent*)));
232
233   connect(theView, SIGNAL(mouseReleased(SUIT_ViewWindow*, QMouseEvent*)),
234           this,    SIGNAL(mouseRelease(SUIT_ViewWindow*, QMouseEvent*)));
235
236   connect(theView, SIGNAL(mouseDoubleClicked(SUIT_ViewWindow*, QMouseEvent*)),
237           this,    SIGNAL(mouseDoubleClick(SUIT_ViewWindow*, QMouseEvent*)));
238
239   connect(theView, SIGNAL(mouseMoving(SUIT_ViewWindow*, QMouseEvent*)),
240           this,    SIGNAL(mouseMove(SUIT_ViewWindow*, QMouseEvent*)));
241
242   connect(theView, SIGNAL(wheeling(SUIT_ViewWindow*, QWheelEvent*)),
243           this,    SIGNAL(wheel(SUIT_ViewWindow*, QWheelEvent*)));
244
245   connect(theView, SIGNAL(keyPressed(SUIT_ViewWindow*, QKeyEvent*)),
246           this,    SIGNAL(keyPress(SUIT_ViewWindow*, QKeyEvent*)));
247
248   connect(theView, SIGNAL(keyReleased(SUIT_ViewWindow*, QKeyEvent*)),
249           this,    SIGNAL(keyRelease(SUIT_ViewWindow*, QKeyEvent*)));
250
251   connect(theView, SIGNAL(contextMenuRequested( QContextMenuEvent * )),
252           this,    SLOT  (onContextMenuRequested( QContextMenuEvent * )));
253
254   for ( int i = 0; i < aSize; i++ )
255   {
256     if ( myViews[i] == 0 )
257     {
258       myViews[i] = theView;
259       return true;
260     }
261   }
262   return false;
263 }
264
265 /*!Emit delete view. Remove view window \a theView from view manager.
266 */
267 void SUIT_ViewManager::onClosingView( SUIT_ViewWindow* theView )
268 {
269   closeView( theView );
270 }
271
272 /*!
273   Remove the view window \a theView from view manager and destroy it.
274 */
275 void SUIT_ViewManager::closeView( SUIT_ViewWindow* theView )
276 {
277   if ( !theView )
278     return;
279
280   QPointer<SUIT_ViewWindow> view( theView );
281
282   view->setClosable( false );
283   view->hide();
284
285   if ( !view->testAttribute( Qt::WA_DeleteOnClose ) )
286     return;
287
288   emit deleteView( view );
289   removeView( view );
290
291   if ( view )
292     delete view;
293 }
294
295 /*!Remove view window \a theView from view manager.
296  *And close the last view, if it has \a theView.
297 */
298 void SUIT_ViewManager::removeView( SUIT_ViewWindow* theView )
299 {
300   theView->disconnect( this );
301   myViews.remove( myViews.indexOf( theView ) );
302   if ( myActiveView == theView )
303     myActiveView = 0;
304   if ( !myViews.count() )
305     emit lastViewClosed( this );
306 }
307
308 /*!
309   Set or clear flag Qt::WDestructiveClose for all views
310 */
311 void SUIT_ViewManager::setDestructiveClose( const bool on )
312 {
313   for ( int i = 0; i < myViews.count(); i++ )
314     myViews[i]->setDestructiveClose( on );
315 }
316
317 /*!
318   Returns 'true' if any of views (view windows) is visible.
319 */
320 bool SUIT_ViewManager::isVisible() const
321 {
322   bool res = false;
323   for ( int i = 0; i < myViews.count() && !res; i++ )
324     res = myViews[i]->isVisibleTo( myViews[i]->parentWidget() );
325   return res;
326 }
327
328 /*!
329   Show or hide all views (view windows)
330 */
331 void SUIT_ViewManager::setShown( const bool on )
332 {
333   for ( int i = 0; i < myViews.count(); i++ )
334     myViews.at( i )->setVisible( on );
335 }
336
337 /*!Emit on \a theEvent mouse pressed in \a theView.*/
338 void SUIT_ViewManager::onMousePressed(SUIT_ViewWindow* theView, QMouseEvent* theEvent)
339 {
340   emit mousePress(theView, theEvent);
341 }
342
343 /*!Emit activated for view \a view.
344 */
345 void SUIT_ViewManager::onWindowActivated(SUIT_ViewWindow* view)
346 {
347   if (view) {
348     int aSize = myViews.size();
349     for (int i = 0; i < aSize; i++) {
350       if (myViews[i] && myViews[i] == view) {
351         myActiveView = view;
352         emit activated( this );
353         return;
354       }
355     }
356   }
357 }
358
359 /*!Close all views.
360 */
361 void SUIT_ViewManager::closeAllViews()
362 {
363   for ( int i = 0; i < myViews.size(); i++ )
364     delete myViews[i];
365   myViews.clear();
366 }
367
368 /*!
369  *\retval QString - type of view model.
370  */
371 QString SUIT_ViewManager::getType() const
372 {
373   return (!myViewModel)? "": myViewModel->getType();
374 }
375
376 /*!
377  *\retval SUIT_Study* - current study.
378  */
379 SUIT_Study* SUIT_ViewManager::study() const
380 {
381     return myStudy;
382 }
383
384 /*!
385  * Sets stydy to NULL.
386  */
387 void SUIT_ViewManager::onDeleteStudy()
388 {
389     myStudy = NULL;
390 }
391
392 /*! invoke method of SUIT_PopupClient, which notifies about popup*/
393 void SUIT_ViewManager::onContextMenuRequested( QContextMenuEvent* e )
394 {
395   contextMenuRequest( e );
396 }
397
398 /*!Context menu popup for \a popup.*/
399 void SUIT_ViewManager::contextMenuPopup( QMenu* popup )
400 {
401   SUIT_ViewModel* vm = getViewModel();
402   if ( vm )
403     vm->contextMenuPopup( popup );
404 }
405
406 /*! option detached (false by default) to set before the viewWindow is added to Desktop TabBar */
407 void SUIT_ViewManager::setDetached(bool detached)
408 {
409   myIsDetached = detached;
410 }
411
412 /*! get option detached (false by default) to decide if the viewWindow is to be added to Desktop TabBar */
413 bool SUIT_ViewManager::getDetached() const
414 {
415   return myIsDetached;
416 }