-// Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
//
-// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
-// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
//
-// 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.
+// 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, 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
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// Lesser General Public License for more details.
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
//
-// You should have received a copy of the GNU Lesser General Public
-// License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
-// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
//
+
#include "STD_Application.h"
#include "STD_MDIDesktop.h"
STD_Application::STD_Application()
: SUIT_Application(),
myActiveViewMgr( 0 ),
+ myNotify( 0 ),
myExitConfirm( true ),
myEditEnabled( true )
{
void STD_Application::start()
{
createActions();
+ customize();
updateDesktopTitle();
updateCommandsStatus();
beforeCloseDoc( study );
study->closeDocument();
-
+ emit appClosed();
setActiveStudy( 0 );
- delete study;
+ //delete study;
afterCloseDoc();
}
tr( "MEN_DESK_FILE_OPEN" ), tr( "PRP_DESK_FILE_OPEN" ),
Qt::CTRL+Qt::Key_O, desk, false, this, SLOT( onOpenDoc() ) );
+ createAction( FileReopenId, tr( "TOT_DESK_FILE_REOPEN" ), QIcon(),
+ tr( "MEN_DESK_FILE_REOPEN" ), tr( "PRP_DESK_FILE_REOPEN" ),
+ 0, desk, false, this, SLOT( onReopenDoc() ) );
+
createAction( FileCloseId, tr( "TOT_DESK_FILE_CLOSE" ),
resMgr->loadPixmap( "STD", tr( "ICON_FILE_CLOSE" ) ),
tr( "MEN_DESK_FILE_CLOSE" ), tr( "PRP_DESK_FILE_CLOSE" ),
Qt::CTRL+Qt::Key_W, desk, false, this, SLOT( onCloseDoc() ) );
+ //no need in this action for mono-study application as it is same as NewDoc
+ action( FileCloseId )->setVisible( false );
createAction( FileExitId, tr( "TOT_DESK_FILE_EXIT" ), QIcon(),
tr( "MEN_DESK_FILE_EXIT" ), tr( "PRP_DESK_FILE_EXIT" ),
createAction( FileSaveAsId, tr( "TOT_DESK_FILE_SAVEAS" ), QIcon(),
tr( "MEN_DESK_FILE_SAVEAS" ), tr( "PRP_DESK_FILE_SAVEAS" ),
- Qt::CTRL+Qt::Key_A, desk, false, this, SLOT( onSaveAsDoc() ) );
+ Qt::CTRL+Qt::SHIFT+Qt::Key_S, desk, false, this, SLOT( onSaveAsDoc() ) );
createAction( EditCopyId, tr( "TOT_DESK_EDIT_COPY" ),
resMgr->loadPixmap( "STD", tr( "ICON_EDIT_COPY" ) ),
QAction* a = createAction( ViewStatusBarId, tr( "TOT_DESK_VIEW_STATUSBAR" ),
QIcon(), tr( "MEN_DESK_VIEW_STATUSBAR" ),
- tr( "PRP_DESK_VIEW_STATUSBAR" ), Qt::SHIFT+Qt::Key_S, desk, true );
+ tr( "PRP_DESK_VIEW_STATUSBAR" ), Qt::ALT+Qt::SHIFT+Qt::Key_S, desk, true );
a->setChecked( desk->statusBar()->isVisibleTo( desk ) );
connect( a, SIGNAL( toggled( bool ) ), this, SLOT( onViewStatusBar( bool ) ) );
createAction( NewWindowId, tr( "TOT_DESK_NEWWINDOW" ), QIcon(),
tr( "MEN_DESK_NEWWINDOW" ), tr( "PRP_DESK_NEWWINDOW" ), 0, desk );
- createAction( HelpAboutId, tr( "TOT_DESK_HELP_ABOUT" ), QIcon(),
+ createAction( HelpAboutId, tr( "TOT_DESK_HELP_ABOUT" ),
+ resMgr->loadPixmap( "STD", tr( "ICON_DESK_ABOUT" ) ),
tr( "MEN_DESK_HELP_ABOUT" ), tr( "PRP_DESK_HELP_ABOUT" ),
- Qt::SHIFT+Qt::Key_A, desk, false, this, SLOT( onHelpAbout() ) );
+ Qt::ALT+Qt::SHIFT+Qt::Key_A, desk, false, this, SLOT( onHelpAbout() ) );
QtxDockAction* dwa = new QtxDockAction( tr( "TOT_DOCKWINDOWS" ), tr( "MEN_DESK_VIEW_DOCKWINDOWS" ), desk );
// Create menus
int fileMenu = createMenu( tr( "MEN_DESK_FILE" ), -1, MenuFileId, 0 );
- int editMenu = createMenu( tr( "MEN_DESK_EDIT" ), -1, MenuEditId, 10 );
+ // Let the application developers insert some menus between Edit and View
+ int editMenu = createMenu( tr( "MEN_DESK_EDIT" ), -1, MenuEditId, 5 );
int viewMenu = createMenu( tr( "MEN_DESK_VIEW" ), -1, MenuViewId, 10 );
int helpMenu = createMenu( tr( "MEN_DESK_HELP" ), -1, MenuHelpId, 1000 );
createMenu( FileNewId, fileMenu, 0 );
createMenu( FileOpenId, fileMenu, 0 );
- createMenu( FileCloseId, fileMenu, 5 );
- createMenu( separator(), fileMenu, -1, 5 );
+ createMenu( FileReopenId, fileMenu, 0 );
createMenu( FileSaveId, fileMenu, 5 );
createMenu( FileSaveAsId, fileMenu, 5 );
+ createMenu( FileCloseId, fileMenu, 5 );
createMenu( separator(), fileMenu, -1, 5 );
createMenu( separator(), fileMenu );
// Create tool bars
- int stdTBar = createTool( tr( "INF_DESK_TOOLBAR_STANDARD" ) );
+ int stdTBar = createTool( tr( "INF_DESK_TOOLBAR_STANDARD" ), // title (language-dependant)
+ QString( "SalomeStandard" ) ); // name (language-independant)
// Create tool items
createTool( EditPasteId, stdTBar );
}
+/*!
+ Customize actions.
+*/
+void STD_Application::customize()
+{
+}
+
/*!Opens new application*/
void STD_Application::onNewDoc()
{
void STD_Application::onOpenDoc()
{
// It is preferrable to use OS-specific file dialog box here !!!
- QString aName = getFileName( true, QString(), getFileFilter(), QString(), 0 );
+ QString aName = getFileName( true, QString(), getFileFilter( true ), QString(), 0 );
if ( aName.isNull() )
return;
onOpenDoc( aName );
}
-/*! \retval true, if document was opened successful, else false.*/
+/*! \retval \c true, if document was opened successful, else \c false.*/
bool STD_Application::onOpenDoc( const QString& aName )
{
+ if ( !abortAllOperations() )
+ return false;
+
QApplication::setOverrideCursor( Qt::WaitCursor );
bool res = openAction( openChoice( aName ), aName );
return res;
}
+/*! Reload document from the file.*/
+bool STD_Application::onReopenDoc()
+{
+ bool res = false;
+
+ SUIT_Study* study = activeStudy();
+ if ( study && study->isSaved() ) {
+ // ask user for the confirmation
+ if ( SUIT_MessageBox::question( desktop(), tr( "REOPEN_STUDY" ), tr( "REOPEN_QUESTION" ),
+ SUIT_MessageBox::Yes | SUIT_MessageBox::No, SUIT_MessageBox::No
+ ) == SUIT_MessageBox::No )
+ return false;
+
+ // remember study name
+ QString studyName = study->studyName();
+
+ // close study
+ beforeCloseDoc( study );
+ study->closeDocument( true );
+
+ // update views / windows / status bar / title
+ clearViewManagers();
+ setActiveStudy( 0 );
+
+ // delete study
+ delete study;
+ study = 0;
+
+ // post closing actions
+ afterCloseDoc();
+
+ // reload study from the file
+ res = useFile( studyName ) && activeStudy();
+
+ // if reloading is failed, close the desktop
+ if ( activeStudy() && !res )
+ closeApplication();
+ else
+ {
+ updateDesktopTitle();
+ updateCommandsStatus();
+ }
+ }
+ return res;
+}
+
/*!Virtual function. Not implemented here.*/
void STD_Application::beforeCloseDoc( SUIT_Study* )
{
/*!Close document, if it's possible.*/
void STD_Application::onCloseDoc( bool ask )
+{
+ closeDoc( ask );
+}
+
+/*!Close document, if it's possible.*/
+bool STD_Application::closeDoc( bool ask )
{
bool closePermanently = true;
if ( ask && !isPossibleToClose( closePermanently ) )
- return;
+ return false;
+
+ return closeActiveDoc( closePermanently );
+}
+/*!Close document.*/
+bool STD_Application::closeActiveDoc( bool permanently )
+{
SUIT_Study* study = activeStudy();
+ if ( !study ) // no active study
+ return true;
beforeCloseDoc( study );
if ( study )
- study->closeDocument( closePermanently );
+ study->closeDocument( permanently );
clearViewManagers();
if ( !desktop() )
closeApplication();
+ return true;
}
/*!Check the application on closing.
- * \retval true if possible, else false
+ * \retval \c true if possible, else \c false
*/
bool STD_Application::isPossibleToClose( bool& closePermanently )
{
return true;
}
-int STD_Application::closeChoice( const QString& docName )
+int STD_Application::closeChoice( const QString& /*docName*/ )
{
- int answer = SUIT_MessageBox::question( desktop(), tr( "CLOSE_STUDY" ), tr( "CLOSE_QUESTION" ).arg( docName ),
+ int answer = SUIT_MessageBox::question( desktop(), tr( "CLOSE_STUDY" ), tr( "CLOSE_QUESTION" ),
SUIT_MessageBox::Save | SUIT_MessageBox::Discard | SUIT_MessageBox::Cancel,
SUIT_MessageBox::Save );
return res;
}
-bool STD_Application::closeAction( const int choice, bool& closePermanently )
+bool STD_Application::closeAction( const int choice, bool& /*closePermanently*/ )
{
bool res = true;
switch( choice )
QList<SUIT_Application*> aAppList = aSession->applications();
for ( QList<SUIT_Application*>::iterator it = aAppList.begin(); it != aAppList.end() && !aApp; ++it )
{
- if ( (*it)->activeStudy() && (*it)->activeStudy()->studyName() == aName )
- aApp = *it;
+ if ( (*it)->activeStudy() && (*it)->activeStudy()->studyName() == aName )
+ aApp = *it;
}
if ( aApp )
- aApp->desktop()->activateWindow();
+ aApp->desktop()->activateWindow();
else
- res = false;
+ res = false;
}
break;
case OpenNew:
{
SUIT_Application* aApp = startApplication( 0, 0 );
if ( aApp )
- res = aApp->useFile( aName );
+ res = aApp->useFile( aName );
if ( !res )
- aApp->closeApplication();
+ aApp->closeApplication();
}
break;
case OpenCancel:
}
/*!Save document if all ok, else error message.*/
-void STD_Application::onSaveDoc()
+bool STD_Application::onSaveDoc()
{
if ( !activeStudy() )
- return;
+ return false;
+
+ if ( !abortAllOperations() )
+ return false;
bool isOk = false;
if ( activeStudy()->isSaved() )
putInfo( "" );
// displaying a message box as SUIT_Validator in case file can't be written (the most frequent case)
SUIT_MessageBox::critical( desktop(), tr( "ERR_ERROR" ),
- tr( "ERR_PERMISSION_DENIED" ).arg( activeStudy()->studyName() ) );
+ tr( "INF_DOC_SAVING_FAILS" ).arg( activeStudy()->studyName() ) );
}
else
putInfo( tr( "INF_DOC_SAVED" ).arg( "" ) );
if ( isOk )
studySaved( activeStudy() );
else
- onSaveAsDoc();
+ isOk = onSaveAsDoc();
+ return isOk;
}
-/*! \retval TRUE, if doument saved successful, else FALSE.*/
+/*! \retval \c true, if document saved successfully, else \c false.*/
bool STD_Application::onSaveAsDoc()
{
SUIT_Study* study = activeStudy();
if ( !study )
return false;
+ if ( !abortAllOperations() )
+ return false;
+
bool isOk = false;
while ( !isOk )
{
- QString aName = getFileName( false, study->studyName(), getFileFilter(), QString(), 0 );
+ QString aName = getFileName( false, study->studyName(), getFileFilter( false ), QString(), 0 );
if ( aName.isNull() )
return false;
}
}
-/*!\retval true, if document opened successful, else false.*/
+/*!\retval \c true, if document opened successfully, else \c false.*/
bool STD_Application::useFile(const QString& theFileName)
{
bool res = SUIT_Application::useFile( theFileName );
{
SUIT_Application::updateCommandsStatus();
- bool aHasStudy = activeStudy() != 0;
- bool aIsNeedToSave = false;
- if ( aHasStudy )
- aIsNeedToSave = !activeStudy()->isSaved() || activeStudy()->isModified();
+ bool aHasStudy = activeStudy() != 0;
+ bool aSaved = aHasStudy && activeStudy()->isSaved();
+ bool aModified = aHasStudy && activeStudy()->isModified();
+ bool aIsNeedToSave = aHasStudy && ( !aSaved || aModified );
- if ( action( FileSaveId ) )
+ if ( action( FileReopenId ) )
+ action( FileReopenId )->setEnabled( aSaved );
+ if ( action( FileSaveId ) )
action( FileSaveId )->setEnabled( aIsNeedToSave );
if ( action( FileSaveAsId ) )
action( FileSaveAsId )->setEnabled( aHasStudy );
action( NewWindowId )->setEnabled( aHasStudy );
}
+/*!
+ \brief Show notification with specified text and title.
+
+ Notification will be automatically hidden after specified \a timeout
+ (given in milliseconds). If \a timeout is zero, the notification
+ is not automatically hidden; it can be only closed by the user manually.
+
+ \param text - Notification text
+ \param title - Notification title
+ \param timeout - Timeout in milliseconds
+ \return Notification's unique identifier
+*/
+int STD_Application::showNotification(const QString& message, const QString& title, int timeout)
+{
+ int uid = -1;
+ QtxNotify* ntfMgr = notifyMgr();
+ if (ntfMgr)
+ {
+ int delay = timeout;
+ if (delay < 0)
+ {
+ SUIT_ResourceMgr* aResMgr = resourceMgr();
+ if (aResMgr)
+ delay = aResMgr->integerValue("notification", "timeout", 0) * 1000;
+ }
+ uid = ntfMgr->showNotification(message, title, qMax(delay, 0));
+ }
+ return uid;
+}
+
+/*!
+ \brief Close notifications with specified text.
+ \param text - Notification text
+*/
+void STD_Application::hideNotification(const QString& message)
+{
+ QtxNotify* ntfMgr = notifyMgr();
+ if (ntfMgr)
+ ntfMgr->hideNotification(message);
+}
+
+/*!
+ \brief Closes the notifications with specified identifier.
+ \param id - Notification identifier
+*/
+void STD_Application::hideNotification(int id)
+{
+ QtxNotify* ntfMgr = notifyMgr();
+ if (ntfMgr)
+ ntfMgr->hideNotification(id);
+}
+
/*!\retval SUIT_ViewManager by viewer manager type name.*/
SUIT_ViewManager* STD_Application::viewManager( const QString& vmType ) const
{
SUIT_ViewManager* vm = 0;
for ( QList<SUIT_ViewManager*>::const_iterator it = myViewMgrs.begin(); it != myViewMgrs.end() && !vm; ++it )
{
- if ( (*it)->getType() == vmType )
+ bool keepDetached = property("keep_detached").toBool();
+ if ( (*it)->getType() == vmType && (!(*it)->getDetached() || keepDetached))
vm = *it;
}
return vm;
}
}
-/*!\retval TRUE, if view manager \a vm, already in view manager list (\a myViewMgrs).*/
+/*!\retval \c true, if view manager \a vm, already in view manager list (\a myViewMgrs).*/
bool STD_Application::containsViewManager( SUIT_ViewManager* vm ) const
{
return myViewMgrs.contains( vm );
setActiveViewManager( vm );
}
-/*!Sets status bar show, if \on = true, else status bar hide.*/
+/*!Shows status bar, if on is \c true, else hides status bar.*/
void STD_Application::onViewStatusBar( bool on )
{
if ( on )
delete popup;
}
+/*!\retval QString - return file extension(s).*/
+QString STD_Application::getFileFilter( bool /*open*/ ) const
+{
+ return QString();
+}
+
/*!\retval QString - return file name from dialog.*/
QString STD_Application::getFileName( bool open, const QString& initial, const QString& filters,
- const QString& caption, QWidget* parent )
+ const QString& caption, QWidget* parent )
{
if ( !parent )
parent = desktop();
isOk = true;
else
{
- int aEnd = aUsedFilter.lastIndexOf( ')' );
- int aStart = aUsedFilter.lastIndexOf( '(', aEnd );
- QString wcStr = aUsedFilter.mid( aStart + 1, aEnd - aStart - 1 );
+ int aEnd = aUsedFilter.lastIndexOf( ')' );
+ int aStart = aUsedFilter.lastIndexOf( '(', aEnd );
+ QString wcStr = aUsedFilter.mid( aStart + 1, aEnd - aStart - 1 );
int idx = 0;
QStringList extList;
if ( !extList.isEmpty() && !extList.contains( SUIT_Tools::extension( aName ) ) )
aName += QString( ".%1" ).arg( extList.first() );
- if ( QFileInfo( aName ).exists() )
+ if ( QFileInfo( aName ).exists() )
{
- int aAnswer = SUIT_MessageBox::question( desktop(), tr( "TIT_FILE_SAVEAS" ),
- tr( "MSG_FILE_EXISTS" ).arg( aName ),
- SUIT_MessageBox::Yes | SUIT_MessageBox::No | SUIT_MessageBox::Cancel, SUIT_MessageBox::Yes );
- if ( aAnswer == SUIT_MessageBox::Cancel )
+ int aAnswer = SUIT_MessageBox::question( desktop(), tr( "TIT_FILE_SAVEAS" ),
+ tr( "MSG_FILE_EXISTS" ).arg( aName ),
+ SUIT_MessageBox::Yes | SUIT_MessageBox::No | SUIT_MessageBox::Cancel, SUIT_MessageBox::Yes );
+ if ( aAnswer == SUIT_MessageBox::Cancel )
{ // cancelled
aName = QString();
- isOk = true;
+ isOk = true;
}
- else if ( aAnswer == SUIT_MessageBox::No ) // not save to this file
- anOldPath = aName; // not to return to the same initial dir at each "while" step
- else // overwrite the existing file
- isOk = true;
+ else if ( aAnswer == SUIT_MessageBox::No ) // not save to this file
+ anOldPath = aName; // not to return to the same initial dir at each "while" step
+ else // overwrite the existing file
+ isOk = true;
}
- else
- isOk = true;
+ else
+ isOk = true;
}
}
return aName;
*/
void STD_Application::setDesktop( SUIT_Desktop* desk )
{
- SUIT_Desktop* prev = desktop();
-
SUIT_Application::setDesktop( desk );
- if ( prev != desk && desk )
+ if ( desk ) {
connect( desk, SIGNAL( closing( SUIT_Desktop*, QCloseEvent* ) ),
- this, SLOT( onDesktopClosing( SUIT_Desktop*, QCloseEvent* ) ) );
+ this, SLOT( onDesktopClosing( SUIT_Desktop*, QCloseEvent* ) ), Qt::UniqueConnection );
+ }
}
/*!
updateDesktopTitle();
updateCommandsStatus();
}
+
+/*!
+ Return index of the view ma
+*/
+int STD_Application::viewManagerId( const SUIT_ViewManager* theManager) const
+{
+ return myViewMgrs.indexOf(const_cast<SUIT_ViewManager*>(theManager));
+}
+
+/*!
+ \brief Abort active operations if there are any
+ \return \c false if some operation cannot be aborted
+*/
+bool STD_Application::abortAllOperations()
+{
+ return true;
+}
+
+/*!
+ \brief Gets the notification manager. Creates it if not exists.
+ \return \c notification manager instance
+*/
+QtxNotify* STD_Application::notifyMgr()
+{
+ if ( !myNotify )
+ {
+ myNotify = new QtxNotify(desktop());
+ myNotify->setWindow(desktop());
+
+ SUIT_ResourceMgr* aResMgr = resourceMgr();
+ if (aResMgr)
+ {
+ int anim = aResMgr->integerValue("notification", "animation", 0);
+ myNotify->setAnimationTime(anim);
+
+ double size = aResMgr->integerValue("notification", "size", 250);
+ myNotify->setNotificationSize(size);
+ }
+ }
+ return myNotify;
+}