Salome HOME
Support both 5.5 and 5.6 version of ParaView
[modules/gui.git] / src / SUIT / SUIT_ViewWindow.cxx
index 6bf0ebe3c3a8fb0bcbe60f56659d07fc08d70787..d5d9032faeed6fff80f6bbf0b1d9f253a446034e 100755 (executable)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
@@ -6,7 +6,7 @@
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 // License as published by the Free Software Foundation; either
-// version 2.1 of the License.
+// version 2.1 of the License, or (at your option) any later version.
 //
 // This library is distributed in the hope that it will be useful,
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 #include "SUIT_ViewWindow.h"
 
 #include "SUIT_Tools.h"
+#include "SUIT_Session.h"
 #include "SUIT_Study.h"
 #include "SUIT_Desktop.h"
 #include "SUIT_MessageBox.h"
 #include "SUIT_Application.h"
 #include "SUIT_ViewManager.h"
+#include "SUIT_ResourceMgr.h"
+#include "SUIT_FileDlg.h"
 #include "QtxActionToolMgr.h"
 #include "QtxMultiAction.h"
 
 #include <QEvent>
 #include <QIcon>
+#include <QMenu>
 #include <QApplication>
 #include <QContextMenuEvent>
 
@@ -47,7 +51,7 @@ const int DUMP_EVENT = QEvent::User + 123;
 
 /*! Constructor.*/
 SUIT_ViewWindow::SUIT_ViewWindow( SUIT_Desktop* theDesktop )
-  : QMainWindow( theDesktop ), myManager( 0 ), myIsDropDown( true )
+  : QMainWindow( theDesktop ), myManager( 0 ), myIsDropDown( true ), mySyncAction( 0 )
 {
   myDesktop = theDesktop;
 
@@ -180,21 +184,27 @@ bool SUIT_ViewWindow::event( QEvent* e )
   if ( e->type() == DUMP_EVENT )
   {
     bool bOk = false;
-    if ( myManager && myManager->study() && myManager->study()->application() )
+    SUIT_Application* app = NULL;
+    if (myManager && myManager->study() && myManager->study()->application())
+      app = myManager->study()->application();
+    QString fileName;
+    if (app)
+      fileName = app->getFileName( false, QString(), filter(), tr( "TLT_DUMP_VIEW" ), 0 ); //old way
+    else
     {
-      // get file name
-      SUIT_Application* app = myManager->study()->application();
-      QString fileName = app->getFileName( false, QString(), filter(), tr( "TLT_DUMP_VIEW" ), 0 );
-      if ( !fileName.isEmpty() )
-      {
-        QImage im = dumpView();
-       QString fmt = SUIT_Tools::extension( fileName ).toUpper();
-       Qtx::Localizer loc;
-       bOk = dumpViewToFormat( im, fileName, fmt );
-      }
-      else
-       bOk = true; // cancelled
+      QStringList fls = filter().split( ";;", QString::SkipEmptyParts );
+      fileName = SUIT_FileDlg::getFileName( NULL, QString(), fls, tr( "TLT_DUMP_VIEW" ), false, true );
     }
+    if ( !fileName.isEmpty() )
+    {
+      QString fmt = SUIT_Tools::extension( fileName ).toUpper();
+      QImage im = dumpView();  
+      Qtx::Localizer loc;
+      bOk = dumpViewToFormat( im, fileName, fmt );
+    }
+    else
+      bOk = true; // cancelled
+
     if ( !bOk )
       SUIT_MessageBox::critical( this, tr( "ERROR" ), tr( "ERR_CANT_DUMP_VIEW" ) );
 
@@ -259,7 +269,7 @@ QtxActionToolMgr* SUIT_ViewWindow::toolMgr() const
 }
 
 /*!
-  \brief Set buttons mode to drop-down (\a on = \c true) or ligned (\a on = \c false) 
+  \brief Set buttons mode to drop-down (\a on = \c true) or ligned (\a on = \c false)
   \param on new buttons mode
   \sa dropDownButtons()
 */
@@ -320,9 +330,234 @@ bool SUIT_ViewWindow::dropDownButtons() const
 }
 
 /*!
-  \return window unique identifier  
+  \return window unique identifier
 */
 int SUIT_ViewWindow::getId() const
 {
   return int(long(this));
 }
+
+/*!
+  Get camera properties for the view window.
+  \return shared pointer on camera properties. Base implementation
+          returns null properties.
+*/
+SUIT_CameraProperties SUIT_ViewWindow::cameraProperties()
+{
+  return SUIT_CameraProperties();
+}
+
+/*!
+  Synchronize this view window's camera properties with specified
+  view window.
+
+  This method is a part of general views synchronization mechanism.
+  It should be redefined in successors. Base imlementation does nothing.
+
+  \param otherWindow other view window
+*/
+void SUIT_ViewWindow::synchronize( SUIT_ViewWindow* /*otherWindow*/ )
+{
+  // base implementation does nothing
+}
+
+/*!
+  Get action for views syncronization.
+
+  This method is a part of general views synchronization mechanism.
+  It creates an action that can be inserted, for instance, to the toolbar.
+
+  \return action for views synchronization
+*/
+QAction* SUIT_ViewWindow::synchronizeAction()
+{
+  if ( !mySyncAction ) {
+    SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
+    mySyncAction = new QtxAction( tr( "MNU_SYNCHRONIZE_VIEW" ),
+                                 resMgr->loadPixmap( "SUIT", tr( "ICON_VIEW_SYNC" ) ),
+                                 tr( "MNU_SYNCHRONIZE_VIEW" ), 0, this );
+    mySyncAction->setStatusTip( tr( "DSC_SYNCHRONIZE_VIEW" ) );
+    mySyncAction->setMenu( new QMenu( this ) );
+    mySyncAction->setCheckable( true );
+    connect( mySyncAction->menu(), SIGNAL( aboutToShow() ),     this, SLOT( updateSyncViews() ) );
+    connect( mySyncAction,         SIGNAL( triggered( bool ) ), this, SLOT( onSynchronizeView( bool ) ) );
+  }
+  return mySyncAction;
+}
+
+/*!
+  Emit notification signal that the view is transformed.
+  Other views can use the signal for synchronization.
+*/
+void SUIT_ViewWindow::emitViewModified()
+{
+  emit viewModified( this );
+}
+
+/*!
+  Update list of available view for the "Synchronize View" action
+*/
+void SUIT_ViewWindow::updateSyncViews()
+{
+  SUIT_CameraProperties props = cameraProperties();
+  if ( !props.isValid() )
+    return;
+
+  QAction* anAction = synchronizeAction();
+  if ( anAction && anAction->menu() ) {
+    int currentId = anAction->data().toInt();
+    anAction->menu()->clear();
+    SUIT_Application* app = SUIT_Session::session()->activeApplication();
+    if ( app ) {
+      SUIT_Desktop* d = app->desktop();
+      QList<SUIT_ViewWindow*> allViews = d->findChildren<SUIT_ViewWindow*>();
+      foreach( SUIT_ViewWindow* vw, allViews ) {
+       if ( !vw || vw == this ) continue; // skip invalid views and this one
+       SUIT_CameraProperties otherProps = vw->cameraProperties();
+       if ( otherProps.isCompatible( props ) ) {
+         QAction* a = anAction->menu()->addAction( vw->windowTitle() );
+         if ( vw->getId() == currentId ) {
+           QFont f = a->font();
+           f.setBold( true );
+           a->setFont( f );
+         }
+         a->setData( vw->getId() );
+         connect( a, SIGNAL( triggered( bool ) ), this, SLOT( onSynchronizeView( bool ) ) );
+       }
+       else if ( vw->getId() == currentId ) {
+         // other view, this one is being currently synchronized to, seems has become incompatible
+         // we have to break synchronization
+         vw->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), this, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+         this->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), vw, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+         // 
+         bool blocked = anAction->blockSignals( true );
+         anAction->setChecked( false );
+         anAction->blockSignals( blocked );
+         anAction->setData( 0 );
+         //
+         QAction* a = vw->synchronizeAction();
+         if ( a ) {
+           blocked = a->blockSignals( true );
+           a->setChecked( false );
+           a->blockSignals( blocked );
+         }
+       }
+      }
+    }
+    if ( anAction->menu()->actions().isEmpty() ) {
+      anAction->setData( 0 );
+      anAction->menu()->addAction( tr( "MNU_SYNC_NO_VIEW" ) );
+    }
+  }
+}
+
+/*!
+  "Synchronize View" action slot.
+*/
+void SUIT_ViewWindow::onSynchronizeView( bool checked )
+{
+  QAction* a = qobject_cast<QAction*>( sender() );
+  if ( a ) {
+    synchronizeView( this, a->data().toInt() );
+  }
+}
+
+/*!
+  Synchronize camera properties of view \a viewWindow with
+  camera properties of view specified via \a id
+*/
+void SUIT_ViewWindow::synchronizeView( SUIT_ViewWindow* viewWindow, int id )
+{
+  SUIT_ViewWindow* sourceView = 0;
+  QList<SUIT_ViewWindow*> otherViews;
+
+  bool isSync = viewWindow->synchronizeAction() && viewWindow->synchronizeAction()->isChecked();
+
+  int vwid = viewWindow->getId();
+
+  SUIT_Application* app = SUIT_Session::session()->activeApplication();
+  if ( !app ) return;
+  SUIT_Desktop* d = app->desktop();
+  if ( !d ) return;
+
+  QList<SUIT_ViewWindow*> allViews = d->findChildren<SUIT_ViewWindow*>();
+  foreach( SUIT_ViewWindow* vw, allViews ) {
+    if ( !vw->cameraProperties().isValid() )
+      continue;                    // omit views not supporting camera properties
+    if ( vw->getId() == id )
+      sourceView = vw;             // remember source view
+    else if ( vw != viewWindow )
+      otherViews.append( vw );     // collect all remaining views
+  }
+
+  if ( isSync && id ) {
+    // remove all possible disconnections
+    foreach( SUIT_ViewWindow* vw, otherViews ) {
+      // disconnect target view
+      vw->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), viewWindow, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+      viewWindow->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), vw, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+      if ( sourceView ) {
+       // disconnect source view
+       vw->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), sourceView, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+       sourceView->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), vw, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+      }
+      QAction* a = vw->synchronizeAction();
+      if ( a ) {
+       int anid = a->data().toInt();
+       if ( a->isChecked() && ( anid == id || anid == vwid ) ) {
+         bool blocked = a->blockSignals( true );
+         a->setChecked( false );
+         a->blockSignals( blocked );
+       }
+      }
+    }
+    if ( sourceView ) {
+      // reconnect source and target views
+      sourceView->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), viewWindow, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+      viewWindow->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), sourceView, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+      sourceView->connect( viewWindow, SIGNAL( viewModified( SUIT_ViewWindow* ) ), SLOT( synchronize( SUIT_ViewWindow* ) ) );
+      viewWindow->connect( sourceView, SIGNAL( viewModified( SUIT_ViewWindow* ) ), SLOT( synchronize( SUIT_ViewWindow* ) ) );
+      // synchronize target view with source view
+      viewWindow->synchronize( sourceView );
+      if ( viewWindow->synchronizeAction() )
+       viewWindow->synchronizeAction()->setData( sourceView->getId() );
+      QAction* sourceAction = sourceView->synchronizeAction();
+      if ( sourceAction ) {
+        sourceAction->setData( viewWindow->getId() );
+        if ( !sourceAction->isChecked() ) {
+         bool blocked = sourceAction->blockSignals( true );
+         sourceAction->setChecked( true );
+         sourceAction->blockSignals( blocked );
+        }
+      }
+    }
+  }
+  else if ( sourceView ) {
+    // reconnect source and target view
+    sourceView->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), viewWindow, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+    viewWindow->disconnect( SIGNAL( viewModified( SUIT_ViewWindow* ) ), sourceView, SLOT( synchronize( SUIT_ViewWindow* ) ) );
+    viewWindow->synchronize( sourceView );
+    if ( viewWindow->synchronizeAction() )
+      viewWindow->synchronizeAction() ->setData( sourceView->getId() );
+    QAction* sourceAction = sourceView->synchronizeAction();
+    if ( sourceAction ) {
+      if ( sourceAction->data().toInt() == viewWindow->getId() && sourceAction->isChecked() ) {
+        bool blocked = sourceAction->blockSignals( true );
+        sourceAction->setChecked( false );
+        sourceAction->blockSignals( blocked );
+      }
+    }
+  }
+}
+
+void SUIT_ViewWindow::setVisible( bool on )
+{
+  // This is a workaround to avoid showing view window as a top-level window
+  // before re-parenting it to workstack (issue #23467).
+  // See SUIT_Desktop::childEvent().
+  QApplication::sendPostedEvents( 0, QEvent::ChildRemoved );
+  QApplication::sendPostedEvents( 0, QEvent::ChildAdded );
+  QApplication::sendPostedEvents( 0, QEvent::ChildPolished );
+  if ( !property( "blockShow" ).toBool() )
+    QMainWindow::setVisible( on );
+}