]> SALOME platform Git repositories - modules/gui.git/blob - src/SUIT/SUIT_ViewWindow.cxx
Salome HOME
e8beaf491e60d99c20f30c17fbfecf8ec8f0d79d
[modules/gui.git] / src / SUIT / SUIT_ViewWindow.cxx
1 // Copyright (C) 2007-2016  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 // SUIT_ViewWindow.cxx: implementation of the SUIT_ViewWindow class.
24 //
25 #include "SUIT_ViewWindow.h"
26
27 #include "SUIT_Tools.h"
28 #include "SUIT_Session.h"
29 #include "SUIT_Study.h"
30 #include "SUIT_Desktop.h"
31 #include "SUIT_MessageBox.h"
32 #include "SUIT_Application.h"
33 #include "SUIT_ViewManager.h"
34 #include "SUIT_ResourceMgr.h"
35 #include "QtxActionToolMgr.h"
36 #include "QtxMultiAction.h"
37
38 #include <QEvent>
39 #include <QIcon>
40 #include <QMenu>
41 #include <QApplication>
42 #include <QContextMenuEvent>
43
44 /*!\class SUIT_ViewWindow
45  * Class provide view window.
46  */
47
48 /*! Dump view custom event*/
49 const int DUMP_EVENT = QEvent::User + 123;
50
51 /*! Constructor.*/
52 SUIT_ViewWindow::SUIT_ViewWindow( SUIT_Desktop* theDesktop )
53   : QMainWindow( theDesktop ), myManager( 0 ), myIsDropDown( true ), mySyncAction( 0 )
54 {
55   myDesktop = theDesktop;
56
57   setWindowIcon( myDesktop ? myDesktop->windowIcon() : QApplication::windowIcon() );
58
59   setAttribute( Qt::WA_DeleteOnClose );
60
61   myToolMgr = new QtxActionToolMgr( this );
62
63   setProperty( "VectorsMode", false );
64 }
65
66 /*! Destructor.*/
67 SUIT_ViewWindow::~SUIT_ViewWindow()
68 {
69 }
70
71 /*!
72   Sets new view manager for window
73   \param theManager - new view manager
74 */
75 void SUIT_ViewWindow::setViewManager( SUIT_ViewManager* theManager )
76 {
77   myManager = theManager;
78 }
79
80 /*!
81   \return view manager of window
82 */
83 SUIT_ViewManager* SUIT_ViewWindow::getViewManager() const
84 {
85   return myManager;
86 }
87
88 /*!
89   \return QImage, containing all scene rendering in window
90 */
91 QImage SUIT_ViewWindow::dumpView()
92 {
93   return QImage();
94 }
95
96 bool SUIT_ViewWindow::dumpViewToPSFormat(const QString& fileName)
97 {
98   return false;
99 }
100
101 /*!
102   Saves image to file according to the format
103   \param image - image
104   \param fileName - name of file
105   \param format - string contains name of format (for example, "BMP"(default) or "JPEG", "JPG")
106 */
107 bool SUIT_ViewWindow::dumpViewToFormat( const QImage& img, const QString& fileName, const QString& format )
108 {
109   if( img.isNull() )
110     return false;
111
112   QString fmt = format;
113   if( fmt.isEmpty() )
114     fmt = QString( "BMP" ); // default format
115   else if( fmt == "JPG" )
116     fmt = "JPEG";
117
118   QApplication::setOverrideCursor( Qt::WaitCursor );
119   bool res = img.save( fileName, fmt.toLatin1() );
120   QApplication::restoreOverrideCursor();
121   return res;
122 }
123
124 /*!
125   Saves scene rendering in window to file
126   \param fileName - name of file
127   \param format - string contains name of format (for example, "BMP"(default) or "JPEG", "JPG")
128 */
129 bool SUIT_ViewWindow::dumpViewToFormat( const QString& fileName, const QString& format )
130 {
131   Qtx::Localizer loc;
132   return dumpViewToFormat( dumpView(), fileName, format );
133 }
134
135 /*!
136   Set or clear flag Qt::WDestructiveClose
137 */
138 void SUIT_ViewWindow::setDestructiveClose( const bool on )
139 {
140   setAttribute( Qt::WA_DeleteOnClose, on );
141 }
142
143 /*! Close event \a theEvent.
144 */
145 void SUIT_ViewWindow::closeEvent( QCloseEvent* e )
146 {
147   e->ignore();
148   emit tryClosing( this );
149   if ( closable() ) emit closing( this );
150 }
151
152 /*! Context menu requested for event \a e.
153 */
154 void SUIT_ViewWindow::contextMenuEvent( QContextMenuEvent* e )
155 {
156   e->ignore();
157
158   QMainWindow::contextMenuEvent( e );
159
160   if ( e->isAccepted() )
161     return;
162
163   if ( e->reason() != QContextMenuEvent::Mouse )
164     emit contextMenuRequested( e );
165 }
166
167 /*! Post events on dump view.
168 */
169 void SUIT_ViewWindow::onDumpView()
170 {
171   // VSV (TRIPOLI dev): next line commented: causes error messages
172   //QApplication::postEvent( this, new QPaintEvent( QRect( 0, 0, width(), height() ) ) );
173   QApplication::postEvent( this, new QEvent( (QEvent::Type)DUMP_EVENT ) );
174 }
175
176 /*!
177   \return filters for image files
178 */
179 QString SUIT_ViewWindow::filter(bool includePS) const
180 {
181   QString aFilter = tr( "TLT_IMAGE_FILES" );
182   if (!includePS)
183     return aFilter;
184   else
185   {
186     aFilter+=";;"+tr( "POSTSCRIPT_FILES" );
187     return aFilter;
188   }
189 }
190
191 /*! Reaction view window on event \a e.
192 */
193 bool SUIT_ViewWindow::event( QEvent* e )
194 {
195   if ( e->type() == DUMP_EVENT )
196   {
197     bool bOk = false;
198     if ( myManager && myManager->study() && myManager->study()->application() )
199     {
200       // get file name
201       SUIT_Application* app = myManager->study()->application();
202       bool IncludePs = true; //TODO for oscar only
203       QString fileName = app->getFileName( false, QString(), filter(IncludePs), tr( "TLT_DUMP_VIEW" ), 0 );
204       if ( !fileName.isEmpty() )
205       {
206         QString fmt = SUIT_Tools::extension( fileName ).toUpper();
207         if (fmt == "PS" || fmt == "EPS" )
208           bOk = dumpViewToPSFormat(fileName);
209         else
210         {
211           QImage im = dumpView();       
212           Qtx::Localizer loc;
213           bOk = dumpViewToFormat( im, fileName, fmt );
214         }
215       }
216       else
217         bOk = true; // cancelled
218     }
219     if ( !bOk )
220       SUIT_MessageBox::critical( this, tr( "ERROR" ), tr( "ERR_CANT_DUMP_VIEW" ) );
221
222     return true;
223   }
224   return QMainWindow::event( e );
225 }
226
227 /*! Called by SUIT_Accel::onActivated() when a key accelerator was activated and this window was active
228 */
229 bool SUIT_ViewWindow::onAccelAction( int _action )
230 {
231   return action( _action );
232 }
233
234 /*! action  handle standard action (zoom, pan) or custom action.  to be redefined in successors.
235 */
236 bool SUIT_ViewWindow::action( const int  )
237 {
238   return true;
239 }
240
241 /*! Returns \c true if view window can be closed by the user
242 */
243 bool SUIT_ViewWindow::closable() const
244 {
245   QVariant val = property( "closable" );
246   return !val.isValid() || val.toBool();
247 }
248
249 /*! Set / reset "closable" option of the view window
250 */
251 bool SUIT_ViewWindow::setClosable( const bool on )
252 {
253   bool prev = closable();
254   setProperty( "closable", on );
255   return prev;
256 }
257
258 /*!
259   \return string containing visual parameters of window
260 */
261 QString SUIT_ViewWindow::getVisualParameters()
262 {
263   return "empty";
264 }
265
266 /*!
267   Sets visual parameters of window by its string representation
268   \param parameters - string with visual parameters
269 */
270 void SUIT_ViewWindow::setVisualParameters( const QString& /*parameters*/ )
271 {
272 }
273
274 /*!
275   \return associated tool bar manager
276 */
277 QtxActionToolMgr* SUIT_ViewWindow::toolMgr() const
278 {
279   return myToolMgr;
280 }
281
282 /*!
283   \brief Set buttons mode to drop-down (\a on = \c true) or ligned (\a on = \c false)
284   \param on new buttons mode
285   \sa dropDownButtons()
286 */
287 void SUIT_ViewWindow::setDropDownButtons( bool on )
288 {
289   if ( myIsDropDown != on ) {
290     myIsDropDown = on;
291     if ( myIsDropDown ) {
292       ActionsMap::const_iterator it;
293       for( it = myMultiActions.constBegin(); it != myMultiActions.constEnd(); ++it )
294       {
295         int tid = it.key();
296         const QList<QtxMultiAction*>& mlist = it.value();
297         QList<QtxMultiAction*>::const_iterator mit;
298         for ( mit = mlist.constBegin(); mit != mlist.constEnd(); ++mit )
299         {
300           QtxMultiAction* ma = *mit;
301           const QList<QAction*> alist = ma->actions();
302           if ( alist.isEmpty() ) continue;
303           int idx = toolMgr()->index( toolMgr()->actionId( alist[0] ), tid );
304           if ( idx == -1 ) continue;
305           foreach ( QAction* a, alist ) toolMgr()->remove( toolMgr()->actionId( a ), tid );
306           toolMgr()->insert( ma, tid, idx );
307         }
308       }
309       myMultiActions.clear();
310     }
311     else {
312       QIntList tblist = toolMgr()->toolBarsIds();
313       QIntList alist  = toolMgr()->idList();
314       foreach( int aid, alist )
315       {
316         QtxMultiAction* ma = qobject_cast<QtxMultiAction*>( toolMgr()->action( aid ) );
317         if ( !ma ) continue;
318         foreach( int tid, tblist )
319         {
320           int idx = toolMgr()->index( aid, tid );
321           if ( idx >= 0 )
322           {
323             myMultiActions[ tid ].append( ma );
324             toolMgr()->remove( aid, tid );
325             foreach( QAction* a, ma->actions() ) toolMgr()->insert( a, tid, idx++ );
326           }
327         }
328       }
329     }
330   }
331 }
332
333 /*!
334   \brief Get current buttons mode
335   \return current buttons mode
336   \sa setDropDownButtons()
337 */
338 bool SUIT_ViewWindow::dropDownButtons() const
339 {
340   return myIsDropDown;
341 }
342
343 /*!
344   \return window unique identifier
345 */
346 int SUIT_ViewWindow::getId() const
347 {
348   return int(long(this));
349 }
350
351 /*!
352   Get camera properties for the view window.
353   \return shared pointer on camera properties. Base implementation
354           returns null properties.
355 */
356 SUIT_CameraProperties SUIT_ViewWindow::cameraProperties()
357 {
358   return SUIT_CameraProperties();
359 }
360
361 /*!
362   Synchronize this view window's camera properties with specified
363   view window.
364
365   This method is a part of general views synchronization mechanism.
366   It should be redefined in successors. Base imlementation does nothing.
367
368   \param otherWindow other view window
369 */
370 void SUIT_ViewWindow::synchronize( SUIT_ViewWindow* /*otherWindow*/ )
371 {
372   // base implementation does nothing
373 }
374
375 /*!
376   Get action for views syncronization.
377
378   This method is a part of general views synchronization mechanism.
379   It creates an action that can be inserted, for instance, to the toolbar.
380
381   \return action for views synchronization
382 */
383 QAction* SUIT_ViewWindow::synchronizeAction()
384 {
385   if ( !mySyncAction ) {
386     SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
387     mySyncAction = new QtxAction( tr( "MNU_SYNCHRONIZE_VIEW" ),
388                                   resMgr->loadPixmap( "SUIT", tr( "ICON_VIEW_SYNC" ) ),
389                                   tr( "MNU_SYNCHRONIZE_VIEW" ), 0, this );
390     mySyncAction->setStatusTip( tr( "DSC_SYNCHRONIZE_VIEW" ) );
391     mySyncAction->setMenu( new QMenu( this ) );
392     mySyncAction->setCheckable( true );
393     connect( mySyncAction->menu(), SIGNAL( aboutToShow() ),     this, SLOT( updateSyncViews() ) );
394     connect( mySyncAction,         SIGNAL( triggered( bool ) ), this, SLOT( onSynchronizeView( bool ) ) );
395   }
396   return mySyncAction;
397 }
398
399 /*!
400   Emit notification signal that the view is transformed.
401   Other views can use the signal for synchronization.
402 */
403 void SUIT_ViewWindow::emitViewModified()
404 {
405   emit viewModified( this );
406 }
407
408 /*!
409   Update list of available view for the "Synchronize View" action
410 */
411 void SUIT_ViewWindow::updateSyncViews()
412 {
413   SUIT_CameraProperties props = cameraProperties();
414   if ( !props.isValid() )
415     return;
416
417   QAction* anAction = synchronizeAction();
418   if ( anAction && anAction->menu() ) {
419     int currentId = anAction->data().toInt();
420     anAction->menu()->clear();
421     SUIT_Application* app = SUIT_Session::session()->activeApplication();
422     if ( app ) {
423       SUIT_Desktop* d = app->desktop();
424       QList<SUIT_ViewWindow*> allViews = d->findChildren<SUIT_ViewWindow*>();
425       foreach( SUIT_ViewWindow* vw, allViews ) {
426         if ( !vw || vw == this ) continue; // skip invalid views and this one
427         SUIT_CameraProperties otherProps = vw->cameraProperties();
428         if ( otherProps.isCompatible( props ) ) {
429           QAction* a = anAction->menu()->addAction( vw->windowTitle() );
430           if ( vw->getId() == currentId ) {
431             QFont f = a->font();
432             f.setBold( true );
433             a->setFont( f );
434           }
435           a->setData( vw->getId() );
436           connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onSynchronizeView( bool ) ) );
437         }
438         else if ( vw->getId() == currentId ) {
439           // other view, this one is being currently synchronized to, seems has become incompatible
440           // we have to break synchronization
441           vw->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), this, SLOT( synchronize( SUIT_ViewWindow* ) ) );
442           this->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), vw, SLOT( synchronize( SUIT_ViewWindow* ) ) );
443           // 
444           bool blocked = anAction->blockSignals( true );
445           anAction->setChecked( false );
446           anAction->blockSignals( blocked );
447           anAction->setData( 0 );
448           //
449           QAction* a = vw->synchronizeAction();
450           if ( a ) {
451             blocked = a->blockSignals( true );
452             a->setChecked( false );
453             a->blockSignals( blocked );
454           }
455         }
456       }
457     }
458     if ( anAction->menu()->actions().isEmpty() ) {
459       anAction->setData( 0 );
460       anAction->menu()->addAction( tr( "MNU_SYNC_NO_VIEW" ) );
461     }
462   }
463 }
464
465 /*!
466   "Synchronize View" action slot.
467 */
468 void SUIT_ViewWindow::onSynchronizeView( bool checked )
469 {
470   QAction* a = qobject_cast<QAction*>( sender() );
471   if ( a ) {
472     synchronizeView( this, a->data().toInt() );
473   }
474 }
475
476 /*!
477   Synchronize camera properties of view \a viewWindow with
478   camera properties of view specified via \a id
479 */
480 void SUIT_ViewWindow::synchronizeView( SUIT_ViewWindow* viewWindow, int id )
481 {
482   SUIT_ViewWindow* sourceView = 0;
483   QList<SUIT_ViewWindow*> otherViews;
484
485   bool isSync = viewWindow->synchronizeAction() && viewWindow->synchronizeAction()->isChecked();
486
487   int vwid = viewWindow->getId();
488
489   SUIT_Application* app = SUIT_Session::session()->activeApplication();
490   if ( !app ) return;
491   SUIT_Desktop* d = app->desktop();
492   if ( !d ) return;
493
494   QList<SUIT_ViewWindow*> allViews = d->findChildren<SUIT_ViewWindow*>();
495   foreach( SUIT_ViewWindow* vw, allViews ) {
496     if ( !vw->cameraProperties().isValid() )
497       continue;                    // omit views not supporting camera properties
498     if ( vw->getId() == id )
499       sourceView = vw;             // remember source view
500     else if ( vw != viewWindow )
501       otherViews.append( vw );     // collect all remaining views
502   }
503
504   if ( isSync && id ) {
505     // remove all possible disconnections
506     foreach( SUIT_ViewWindow* vw, otherViews ) {
507       // disconnect target view
508       vw->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), viewWindow, SLOT( synchronize( SUIT_ViewWindow* ) ) );
509       viewWindow->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), vw, SLOT( synchronize( SUIT_ViewWindow* ) ) );
510       if ( sourceView ) {
511         // disconnect source view
512         vw->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), sourceView, SLOT( synchronize( SUIT_ViewWindow* ) ) );
513         sourceView->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), vw, SLOT( synchronize( SUIT_ViewWindow* ) ) );
514       }
515       QAction* a = vw->synchronizeAction();
516       if ( a ) {
517         int anid = a->data().toInt();
518         if ( a->isChecked() && ( anid == id || anid == vwid ) ) {
519           bool blocked = a->blockSignals( true );
520           a->setChecked( false );
521           a->blockSignals( blocked );
522         }
523       }
524     }
525     if ( sourceView ) {
526       // reconnect source and target views
527       sourceView->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), viewWindow, SLOT( synchronize( SUIT_ViewWindow* ) ) );
528       viewWindow->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), sourceView, SLOT( synchronize( SUIT_ViewWindow* ) ) );
529       sourceView->connect( viewWindow, SIGNAL( viewModified( SUIT_ViewWindow* ) ), SLOT( synchronize( SUIT_ViewWindow* ) ) );
530       viewWindow->connect( sourceView, SIGNAL( viewModified( SUIT_ViewWindow* ) ), SLOT( synchronize( SUIT_ViewWindow* ) ) );
531       // synchronize target view with source view
532       viewWindow->synchronize( sourceView );
533       if ( viewWindow->synchronizeAction() )
534         viewWindow->synchronizeAction()->setData( sourceView->getId() );
535       QAction* sourceAction = sourceView->synchronizeAction();
536       if ( sourceAction ) {
537         sourceAction->setData( viewWindow->getId() );
538         if ( !sourceAction->isChecked() ) {
539           bool blocked = sourceAction->blockSignals( true );
540           sourceAction->setChecked( true );
541           sourceAction->blockSignals( blocked );
542         }
543       }
544     }
545   }
546   else if ( sourceView ) {
547     // reconnect source and target view
548     sourceView->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), viewWindow, SLOT( synchronize( SUIT_ViewWindow* ) ) );
549     viewWindow->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), sourceView, SLOT( synchronize( SUIT_ViewWindow* ) ) );
550     viewWindow->synchronize( sourceView );
551     if ( viewWindow->synchronizeAction() )
552       viewWindow->synchronizeAction() ->setData( sourceView->getId() );
553     QAction* sourceAction = sourceView->synchronizeAction();
554     if ( sourceAction ) {
555       if ( sourceAction->data().toInt() == viewWindow->getId() && sourceAction->isChecked() ) {
556         bool blocked = sourceAction->blockSignals( true );
557         sourceAction->setChecked( false );
558         sourceAction->blockSignals( blocked );
559       }
560     }
561   }
562 }