1 // Copyright (C) 2015 OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19 // File : PyViewer_ViewWindow.cxx
20 // Author : Maxim GLIBIN, Open CASCADE S.A.S. (maxim.glibin@opencascade.com)
23 #include "PyViewer_ViewWindow.h"
25 #include "PyEditor_Editor.h"
26 #include "PyEditor_Settings.h"
27 #include "PyEditor_SettingsDlg.h"
29 #include <SUIT_Session.h>
30 #include <SUIT_ResourceMgr.h>
32 #include <QtxAction.h>
33 #include <QtxActionToolMgr.h>
34 #include <QtxMultiAction.h>
38 #include <QFileDialog>
39 #include <QMessageBox>
40 #include <QApplication>
44 \class PyViewer_ViewWindow
45 \brief Python view window.
50 \param theParent parent widget
52 PyViewer_ViewWindow::PyViewer_ViewWindow( SUIT_Desktop* theDesktop , PyViewer_Viewer* theModel ) :
53 SUIT_ViewWindow(theDesktop),
56 my_IsExternal = (theDesktop == NULL);
62 void PyViewer_ViewWindow::initLayout()
64 my_TextEditor = new PyEditor_Editor( my_IsExternal ,SUIT_Session::session()->resourceMgr(), this );
65 setCentralWidget( my_TextEditor );
69 setCurrentFile( QString() );
73 connect( my_TextEditor->document(), SIGNAL( modificationChanged( bool ) ),
74 this, SLOT( setWindowModified( bool ) ) );
76 statusBar()->showMessage( tr("STS_READY") );
83 PyViewer_ViewWindow::~PyViewer_ViewWindow()
85 my_CurrentFile.clear();
90 \return \c true if the application is external
92 bool PyViewer_ViewWindow::isExternal()
98 \brief Creates actions of Python view window.
100 void PyViewer_ViewWindow::createActions()
102 QtxActionToolMgr* aMgr = toolMgr();
105 // 1. File operations
106 // 1.1. Create New action
107 anAction = new QtxAction( tr( "MNU_PY_NEW" ), QIcon( ":/images/py_new.png" ),
108 tr( "MNU_PY_NEW" ), 0, this );
109 anAction->setStatusTip( tr( "DSC_PY_NEW" ) );
110 anAction->setShortcuts( QKeySequence::New );
111 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onNew() ) );
112 aMgr->registerAction( anAction, NewId );
114 // 1.2 Create Open action
115 anAction = new QtxAction( tr( "MNU_PY_OPEN" ), QIcon( ":/images/py_open.png" ),
116 tr( "MNU_PY_OPEN" ), 0, this );
117 anAction->setStatusTip( tr( "DSC_PY_OPEN" ) );
118 anAction->setShortcuts( QKeySequence::Open );
119 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onOpen() ) );
120 aMgr->registerAction( anAction, OpenId );
122 // 1.3. Create Save action
123 anAction = new QtxAction( tr( "MNU_PY_SAVE" ), QIcon( ":/images/py_save.png" ),
124 tr( "MNU_PY_SAVE" ), 0, this );
125 anAction->setStatusTip( tr( "DSC_PY_SAVE" ) );
126 anAction->setShortcuts( QKeySequence::Save );
127 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onSave() ) );
128 aMgr->registerAction( anAction, SaveId );
129 // Set default statement for Save action
130 anAction->setEnabled( my_TextEditor->document()->isModified() );
131 connect( my_TextEditor->document(), SIGNAL( modificationChanged( bool ) ),
132 anAction, SLOT( setEnabled( bool ) ) );
134 // 1.4. Create SaveAs action
135 anAction = new QtxAction( tr( "MNU_PY_SAVEAS" ), QIcon( ":/images/py_save_as.png" ),
136 tr( "MNU_PY_SAVEAS" ), 0, this );
137 anAction->setStatusTip( tr( "DSC_PY_SAVEAS" ) );
138 anAction->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_S );
139 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAs() ) );
140 aMgr->registerAction( anAction, SaveAsId );
142 // 1.5 Create multi-action for file operations
143 /*QtxMultiAction* aFileAction = new QtxMultiAction( this );
144 aFileAction->insertAction( aMgr->action( NewId ) );
145 aFileAction->insertAction( aMgr->action( OpenId ) );
146 aFileAction->insertAction( aMgr->action( SaveId ) );
147 aFileAction->insertAction( aMgr->action( SaveAsId ) );
148 aMgr->registerAction( aFileAction, FileOpId );*/
150 // 1.6. Create Close action
153 anAction = new QtxAction( tr( "MNU_PY_CLOSE" ), QIcon( ":/images/py_close.png" ),
154 tr( "MNU_PY_CLOSE" ), 0, this );
155 anAction->setStatusTip( tr( "DSC_PY_CLOSE" ) );
156 anAction->setShortcut( Qt::CTRL + Qt::Key_Q );
157 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( close() ) );
158 aMgr->registerAction( anAction, CloseId );
161 // 2. Edit operations
162 // 2.1. Create Undo action
163 anAction = new QtxAction( tr( "MNU_PY_UNDO" ), QIcon( ":/images/py_undo.png" ),
164 tr( "MNU_PY_UNDO" ), 0, this );
165 anAction->setStatusTip( tr( "DSC_PY_UNDO" ) );
166 anAction->setShortcuts( QKeySequence::Undo );
167 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( undo() ) );
168 aMgr->registerAction( anAction, UndoId );
169 // Set default statement for Undo action
170 anAction->setEnabled( my_TextEditor->document()->isUndoAvailable() );
171 connect( my_TextEditor->document(), SIGNAL( undoAvailable( bool ) ),
172 anAction, SLOT( setEnabled( bool ) ) );
174 // 2.2. Create Redo action
175 anAction = new QtxAction( tr( "MNU_PY_REDO" ), QIcon( ":/images/py_redo.png" ),
176 tr( "MNU_PY_REDO" ), 0, this );
177 anAction->setStatusTip( tr( "DSC_PY_REDO" ) );
178 anAction->setShortcuts( QKeySequence::Redo );
179 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( redo() ) );
180 aMgr->registerAction( anAction, RedoId );
181 // Set default statement for Redo action
182 anAction->setEnabled( my_TextEditor->document()->isRedoAvailable() );
183 connect( my_TextEditor->document(), SIGNAL( redoAvailable( bool ) ),
184 anAction, SLOT( setEnabled( bool ) ) );
186 // 2.3. Create Cut action
187 anAction = new QtxAction( tr( "MNU_PY_CUT" ), QIcon( ":/images/py_cut.png" ),
188 tr( "MNU_PY_CUT" ), 0, this );
189 anAction->setStatusTip( tr( "DSC_PY_CUT" ) );
190 anAction->setShortcuts( QKeySequence::Cut );
191 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( cut() ) );
192 aMgr->registerAction( anAction, CutId );
193 // Set default statement for Cut action
194 anAction->setEnabled( false );
195 connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ),
196 anAction, SLOT( setEnabled( bool ) ) );
198 // 2.4. Create Copy action
199 anAction = new QtxAction( tr( "MNU_PY_COPY" ), QIcon( ":/images/py_copy.png" ),
200 tr( "MNU_PY_COPY" ), 0, this );
201 anAction->setStatusTip( tr( "DSC_PY_COPY" ) );
202 anAction->setShortcuts( QKeySequence::Copy );
203 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( copy() ) );
204 aMgr->registerAction( anAction, CopyId );
205 // Set default statement for Copy action
206 anAction->setEnabled( false );
207 connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ),
208 anAction, SLOT( setEnabled( bool ) ) );
210 // 2.5. Create Paste action
211 anAction = new QtxAction( tr( "MNU_PY_PASTE" ), QIcon( ":/images/py_paste.png" ),
212 tr( "MNU_PY_PASTE" ), 0, this );
213 anAction->setStatusTip( tr( "DSC_PY_PASTE" ) );
214 anAction->setShortcuts( QKeySequence::Paste );
215 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( paste() ) );
216 aMgr->registerAction( anAction, PasteId );
218 // 2.6. Create Delete action
219 anAction = new QtxAction( tr( "MNU_PY_DELETE" ), QIcon( ":/images/py_delete.png" ),
220 tr( "MNU_PY_DELETE" ), 0, this );
221 anAction->setStatusTip( tr( "DSC_PY_DELETE" ) );
222 anAction->setShortcuts( QKeySequence::Delete );
223 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( deleteSelected() ) );
224 aMgr->registerAction( anAction, DeleteId );
225 // Set default statement for Delete action
226 anAction->setEnabled( false );
227 connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ),
228 anAction, SLOT( setEnabled( bool ) ) );
230 // 2.7. Create SelectAll action
231 anAction = new QtxAction( tr( "MNU_PY_SELECTALL" ), QIcon( ":/images/py_select_all.png" ),
232 tr( "MNU_PY_SELECTALL" ), 0, this );
233 anAction->setStatusTip( tr( "DSC_PY_SELECT_ALL" ) );
234 anAction->setShortcuts( QKeySequence::SelectAll );
235 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( selectAll() ) );
236 aMgr->registerAction( anAction, SelectAllId );
238 // 2.8. Create multi-action for edit operations
239 /*QtxMultiAction* anEditAction = new QtxMultiAction( this );
240 anEditAction->insertAction( aMgr->action( UndoId ) );
241 anEditAction->insertAction( aMgr->action( RedoId ) );
242 anEditAction->insertAction( aMgr->action( CutId ) );
243 anEditAction->insertAction( aMgr->action( CopyId ) );
244 anEditAction->insertAction( aMgr->action( PasteId ) );
245 anEditAction->insertAction( aMgr->action( DeleteId ) );
246 anEditAction->insertAction( aMgr->action( SelectAllId ) );
247 aMgr->registerAction( anEditAction, EditOpId );*/
249 // 3. Create Preference action
250 anAction = new QtxAction( tr( "MNU_PY_PREFERENCES" ), QIcon( ":/images/py_preferences.png" ),
251 tr( "MNU_PY_PREFERENCES" ), 0, this );
252 anAction->setStatusTip( tr( "DSC_PY_PREFERENCES" ) );
253 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onPreferences() ) );
254 aMgr->registerAction( anAction, PreferencesId );
256 // 4. Help operations
258 // 4.1. Create Help action
259 anAction = new QtxAction( tr( "MNU_PY_BROWSER" ), QIcon( ":/images/py_browser.png" ),
260 tr( "MNU_PY_BROWSER" ), 0, this );
261 anAction->setStatusTip( tr( "DSC_PY_BROWSER" ) );
262 connect( anAction, SIGNAL( triggered() ), this, SLOT( onBrowser() ) );
263 //aMgr->registerAction( anAction, BrowserId );
265 // 4.2. Create multi-action for help operations
266 /*QtxMultiAction* aHelpAction = new QtxMultiAction( this );
267 aHelpAction->insertAction( aMgr->action( BrowserId ) );
268 aMgr->registerAction( aHelpAction, HelpOpId );*/
272 \brief Create toolbar for the python view window.
274 void PyViewer_ViewWindow::createToolBar()
276 QtxActionToolMgr* aMgr = toolMgr();
277 int idTB = aMgr->createToolBar( tr("LBL_TOOLBAR_LABEL"), // title (language-dependent)
278 QString( "PyEditorOperations" ), // name (language-independent)
279 false ); // disable floatable toolbar
280 aMgr->append( NewId, idTB );
281 aMgr->append( OpenId, idTB );
282 aMgr->append( SaveId, idTB );
283 aMgr->append( SaveAsId, idTB );
285 aMgr->append( CloseId, idTB );
286 aMgr->append( aMgr->separator(), idTB );
287 aMgr->append( UndoId, idTB );
288 aMgr->append( RedoId, idTB );
289 aMgr->append( aMgr->separator(), idTB );
290 aMgr->append( CutId, idTB );
291 aMgr->append( CopyId, idTB );
292 aMgr->append( PasteId, idTB );
293 aMgr->append( DeleteId, idTB );
294 aMgr->append( SelectAllId, idTB );
295 aMgr->append( aMgr->separator(), idTB );
296 aMgr->append( PreferencesId, idTB );
297 aMgr->append( aMgr->separator(), idTB );
298 aMgr->append( BrowserId, idTB );
303 \brief Reimplemented class is to receive a window close request.
304 \param theEvent event
306 void PyViewer_ViewWindow::closeEvent( QCloseEvent* theEvent )
315 SLOT: Creates a new document
317 void PyViewer_ViewWindow::onNew()
321 my_TextEditor->clear();
322 setCurrentFile( QString() );
327 SLOT: Open an existing python file
329 void PyViewer_ViewWindow::onOpen()
333 QString aFilePath = QFileDialog::getOpenFileName(
334 this, tr( "TIT_DLG_OPEN" ), QDir::currentPath(), "Python Files (*.py)" );
336 if ( !aFilePath.isEmpty() )
337 loadFile( aFilePath );
342 SLOT: Save the current file
344 bool PyViewer_ViewWindow::onSave()
346 if ( my_CurrentFile.isEmpty() )
349 return saveFile( my_CurrentFile );
354 SLOT: Save the current file under a new name
356 bool PyViewer_ViewWindow::onSaveAs()
358 QString aFilePath = QFileDialog::getSaveFileName(
359 this, tr( "TIT_DLG_SAVEAS" ), QDir::currentPath(), "Python Files (*.py)" );
361 if ( !aFilePath.isEmpty() )
362 return saveFile( aFilePath );
368 SLOT: Open preferences dialog
370 void PyViewer_ViewWindow::onPreferences()
372 PyEditor_SettingsDlg* aPage = new PyEditor_SettingsDlg( my_TextEditor, this );
373 connect( aPage, SIGNAL( onHelpClicked() ),
374 this, SLOT( onHelp() ) );
380 \brief Set preferece values for view.
382 void PyViewer_ViewWindow::setPreferences()
384 my_TextEditor->settings()->readSettings();
385 my_TextEditor->updateStatement();
389 \brief Associates the theFilePath with the python view.
390 \param theFilePath file path
392 void PyViewer_ViewWindow::setCurrentFile( const QString &theFilePath )
394 my_CurrentFile = theFilePath;
395 my_TextEditor->document()->setModified( false );
399 setWindowModified( false );
401 QString aShownName = my_CurrentFile;
402 if ( my_CurrentFile.isEmpty() )
403 aShownName = "untitled.py";
404 setWindowFilePath( aShownName );
406 // Set window title with associated file path
407 QFileInfo anInfo( aShownName );
408 setWindowTitle( "Python Viewer - " + anInfo.fileName() + "[*]" );
413 \brief Checks whether the file is modified.
414 If it has the modifications then ask the user to save it.
415 \return true if the document is saved.
417 bool PyViewer_ViewWindow::whetherSave()
419 if ( my_TextEditor->document()->isModified() )
421 QMessageBox::StandardButton aReturn;
422 aReturn = QMessageBox::warning(
423 this, tr( "TIT_DLG_SAVE" ),tr( "WRN_PY_SAVE_FILE" ),
424 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel );
426 if ( aReturn == QMessageBox::Save )
428 else if ( aReturn == QMessageBox::Cancel )
436 \param theFilePath file path
438 void PyViewer_ViewWindow::loadFile( const QString &theFilePath )
440 QFile aFile( theFilePath );
441 if ( !aFile.open(QFile::ReadOnly | QFile::Text) )
443 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
444 tr( "WRN_PY_READ_FILE" ).arg( theFilePath ).arg( aFile.errorString() ) );
448 QTextStream anInput( &aFile );
449 QApplication::setOverrideCursor( Qt::WaitCursor );
450 my_TextEditor->setPlainText( anInput.readAll() );
451 QApplication::restoreOverrideCursor();
453 setCurrentFile( theFilePath );
456 statusBar()->showMessage( tr( "STS_F_LOADED" ), 2000 );
461 \param theFilePath file path
463 bool PyViewer_ViewWindow::saveFile( const QString &theFilePath )
465 QFile aFile( theFilePath );
466 if ( !aFile.open( QFile::WriteOnly | QFile::Text ) )
468 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
469 tr( "WRN_PY_WRITE_FILE" ).arg( theFilePath ).arg( aFile.errorString() ) );
473 QTextStream anOutput( &aFile );
474 QApplication::setOverrideCursor( Qt::WaitCursor );
475 anOutput << my_TextEditor->toPlainText();
476 QApplication::restoreOverrideCursor();
478 setCurrentFile( theFilePath );
482 statusBar()->showMessage( tr( "STS_F_SAVED" ), 2000 );
488 \brief Opens help browser with python view help information.
490 void PyViewer_ViewWindow::onBrowser()
492 QDir appDir = QApplication::applicationDirPath();
493 QStringList parameters;
494 parameters << QString( "--file=%1" ).arg( appDir.filePath( "pyeditor.html" ) );
495 QProcess::startDetached( "HelpBrowser", parameters );
499 Slot, called when user clicks "Help" button in "Preferences" dialog box.
501 void PyViewer_ViewWindow::onHelp()
504 SUIT_Application* app = SUIT_Session::session()->activeApplication();
506 app->onHelpContextModule( "GUI", "python_viewer_page.html", "custom_python_preferences" );