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>
37 #include <QFileDialog>
38 #include <QMessageBox>
39 #include <QApplication>
42 #include <QTextStream>
45 \class PyViewer_ViewWindow
46 \brief Python view window.
51 \param theParent parent widget
53 PyViewer_ViewWindow::PyViewer_ViewWindow( SUIT_Desktop* theDesktop , PyViewer_Viewer* theModel ) :
54 SUIT_ViewWindow(theDesktop),
57 my_IsExternal = (theDesktop == NULL);
63 void PyViewer_ViewWindow::initLayout()
65 my_TextEditor = new PyEditor_Editor( my_IsExternal ,SUIT_Session::session()->resourceMgr(), this );
66 setCentralWidget( my_TextEditor );
70 setCurrentFile( QString() );
74 connect( my_TextEditor->document(), SIGNAL( modificationChanged( bool ) ),
75 this, SLOT( setWindowModified( bool ) ) );
77 statusBar()->showMessage( tr("STS_READY") );
84 PyViewer_ViewWindow::~PyViewer_ViewWindow()
86 my_CurrentFile.clear();
91 \return \c true if the application is external
93 bool PyViewer_ViewWindow::isExternal()
99 \brief Creates actions of Python view window.
101 void PyViewer_ViewWindow::createActions()
103 QtxActionToolMgr* aMgr = toolMgr();
106 // 1. File operations
107 // 1.1. Create New action
108 anAction = new QtxAction( tr( "MNU_PY_NEW" ), QIcon( ":/images/py_new.png" ),
109 tr( "MNU_PY_NEW" ), 0, this );
110 anAction->setStatusTip( tr( "DSC_PY_NEW" ) );
111 anAction->setShortcuts( QKeySequence::New );
112 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onNew() ) );
113 aMgr->registerAction( anAction, NewId );
115 // 1.2 Create Open action
116 anAction = new QtxAction( tr( "MNU_PY_OPEN" ), QIcon( ":/images/py_open.png" ),
117 tr( "MNU_PY_OPEN" ), 0, this );
118 anAction->setStatusTip( tr( "DSC_PY_OPEN" ) );
119 anAction->setShortcuts( QKeySequence::Open );
120 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onOpen() ) );
121 aMgr->registerAction( anAction, OpenId );
123 // 1.3. Create Save action
124 anAction = new QtxAction( tr( "MNU_PY_SAVE" ), QIcon( ":/images/py_save.png" ),
125 tr( "MNU_PY_SAVE" ), 0, this );
126 anAction->setStatusTip( tr( "DSC_PY_SAVE" ) );
127 anAction->setShortcuts( QKeySequence::Save );
128 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onSave() ) );
129 aMgr->registerAction( anAction, SaveId );
130 // Set default statement for Save action
131 anAction->setEnabled( my_TextEditor->document()->isModified() );
132 connect( my_TextEditor->document(), SIGNAL( modificationChanged( bool ) ),
133 anAction, SLOT( setEnabled( bool ) ) );
135 // 1.4. Create SaveAs action
136 anAction = new QtxAction( tr( "MNU_PY_SAVEAS" ), QIcon( ":/images/py_save_as.png" ),
137 tr( "MNU_PY_SAVEAS" ), 0, this );
138 anAction->setStatusTip( tr( "DSC_PY_SAVEAS" ) );
139 anAction->setShortcut( Qt::CTRL + Qt::SHIFT + Qt::Key_S );
140 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAs() ) );
141 aMgr->registerAction( anAction, SaveAsId );
143 // 1.5 Create multi-action for file operations
144 /*QtxMultiAction* aFileAction = new QtxMultiAction( this );
145 aFileAction->insertAction( aMgr->action( NewId ) );
146 aFileAction->insertAction( aMgr->action( OpenId ) );
147 aFileAction->insertAction( aMgr->action( SaveId ) );
148 aFileAction->insertAction( aMgr->action( SaveAsId ) );
149 aMgr->registerAction( aFileAction, FileOpId );*/
151 // 1.6. Create Close action
154 anAction = new QtxAction( tr( "MNU_PY_CLOSE" ), QIcon( ":/images/py_close.png" ),
155 tr( "MNU_PY_CLOSE" ), 0, this );
156 anAction->setStatusTip( tr( "DSC_PY_CLOSE" ) );
157 anAction->setShortcut( Qt::CTRL + Qt::Key_Q );
158 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( close() ) );
159 aMgr->registerAction( anAction, CloseId );
162 // 2. Edit operations
163 // 2.1. Create Undo action
164 anAction = new QtxAction( tr( "MNU_PY_UNDO" ), QIcon( ":/images/py_undo.png" ),
165 tr( "MNU_PY_UNDO" ), 0, this );
166 anAction->setStatusTip( tr( "DSC_PY_UNDO" ) );
167 anAction->setShortcuts( QKeySequence::Undo );
168 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( undo() ) );
169 aMgr->registerAction( anAction, UndoId );
170 // Set default statement for Undo action
171 anAction->setEnabled( my_TextEditor->document()->isUndoAvailable() );
172 connect( my_TextEditor->document(), SIGNAL( undoAvailable( bool ) ),
173 anAction, SLOT( setEnabled( bool ) ) );
175 // 2.2. Create Redo action
176 anAction = new QtxAction( tr( "MNU_PY_REDO" ), QIcon( ":/images/py_redo.png" ),
177 tr( "MNU_PY_REDO" ), 0, this );
178 anAction->setStatusTip( tr( "DSC_PY_REDO" ) );
179 anAction->setShortcuts( QKeySequence::Redo );
180 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( redo() ) );
181 aMgr->registerAction( anAction, RedoId );
182 // Set default statement for Redo action
183 anAction->setEnabled( my_TextEditor->document()->isRedoAvailable() );
184 connect( my_TextEditor->document(), SIGNAL( redoAvailable( bool ) ),
185 anAction, SLOT( setEnabled( bool ) ) );
187 // 2.3. Create Cut action
188 anAction = new QtxAction( tr( "MNU_PY_CUT" ), QIcon( ":/images/py_cut.png" ),
189 tr( "MNU_PY_CUT" ), 0, this );
190 anAction->setStatusTip( tr( "DSC_PY_CUT" ) );
191 anAction->setShortcuts( QKeySequence::Cut );
192 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( cut() ) );
193 aMgr->registerAction( anAction, CutId );
194 // Set default statement for Cut action
195 anAction->setEnabled( false );
196 connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ),
197 anAction, SLOT( setEnabled( bool ) ) );
199 // 2.4. Create Copy action
200 anAction = new QtxAction( tr( "MNU_PY_COPY" ), QIcon( ":/images/py_copy.png" ),
201 tr( "MNU_PY_COPY" ), 0, this );
202 anAction->setStatusTip( tr( "DSC_PY_COPY" ) );
203 anAction->setShortcuts( QKeySequence::Copy );
204 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( copy() ) );
205 aMgr->registerAction( anAction, CopyId );
206 // Set default statement for Copy action
207 anAction->setEnabled( false );
208 connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ),
209 anAction, SLOT( setEnabled( bool ) ) );
211 // 2.5. Create Paste action
212 anAction = new QtxAction( tr( "MNU_PY_PASTE" ), QIcon( ":/images/py_paste.png" ),
213 tr( "MNU_PY_PASTE" ), 0, this );
214 anAction->setStatusTip( tr( "DSC_PY_PASTE" ) );
215 anAction->setShortcuts( QKeySequence::Paste );
216 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( paste() ) );
217 aMgr->registerAction( anAction, PasteId );
219 // 2.6. Create Delete action
220 anAction = new QtxAction( tr( "MNU_PY_DELETE" ), QIcon( ":/images/py_delete.png" ),
221 tr( "MNU_PY_DELETE" ), 0, this );
222 anAction->setStatusTip( tr( "DSC_PY_DELETE" ) );
223 anAction->setShortcuts( QKeySequence::Delete );
224 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( deleteSelected() ) );
225 aMgr->registerAction( anAction, DeleteId );
226 // Set default statement for Delete action
227 anAction->setEnabled( false );
228 connect( my_TextEditor, SIGNAL( copyAvailable( bool ) ),
229 anAction, SLOT( setEnabled( bool ) ) );
231 // 2.7. Create SelectAll action
232 anAction = new QtxAction( tr( "MNU_PY_SELECTALL" ), QIcon( ":/images/py_select_all.png" ),
233 tr( "MNU_PY_SELECTALL" ), 0, this );
234 anAction->setStatusTip( tr( "DSC_PY_SELECT_ALL" ) );
235 anAction->setShortcuts( QKeySequence::SelectAll );
236 connect( anAction, SIGNAL( triggered( bool ) ), my_TextEditor, SLOT( selectAll() ) );
237 aMgr->registerAction( anAction, SelectAllId );
239 // 2.8. Create multi-action for edit operations
240 /*QtxMultiAction* anEditAction = new QtxMultiAction( this );
241 anEditAction->insertAction( aMgr->action( UndoId ) );
242 anEditAction->insertAction( aMgr->action( RedoId ) );
243 anEditAction->insertAction( aMgr->action( CutId ) );
244 anEditAction->insertAction( aMgr->action( CopyId ) );
245 anEditAction->insertAction( aMgr->action( PasteId ) );
246 anEditAction->insertAction( aMgr->action( DeleteId ) );
247 anEditAction->insertAction( aMgr->action( SelectAllId ) );
248 aMgr->registerAction( anEditAction, EditOpId );*/
250 // 3. Create Preference action
251 anAction = new QtxAction( tr( "MNU_PY_PREFERENCES" ), QIcon( ":/images/py_preferences.png" ),
252 tr( "MNU_PY_PREFERENCES" ), 0, this );
253 anAction->setStatusTip( tr( "DSC_PY_PREFERENCES" ) );
254 connect( anAction, SIGNAL( triggered( bool ) ), this, SLOT( onPreferences() ) );
255 aMgr->registerAction( anAction, PreferencesId );
257 // 4. Help operations
259 // 4.1. Create Help action
260 anAction = new QtxAction( tr( "MNU_PY_BROWSER" ), QIcon( ":/images/py_browser.png" ),
261 tr( "MNU_PY_BROWSER" ), 0, this );
262 anAction->setStatusTip( tr( "DSC_PY_BROWSER" ) );
263 connect( anAction, SIGNAL( triggered() ), this, SLOT( onBrowser() ) );
264 //aMgr->registerAction( anAction, BrowserId );
266 // 4.2. Create multi-action for help operations
267 /*QtxMultiAction* aHelpAction = new QtxMultiAction( this );
268 aHelpAction->insertAction( aMgr->action( BrowserId ) );
269 aMgr->registerAction( aHelpAction, HelpOpId );*/
273 \brief Create toolbar for the python view window.
275 void PyViewer_ViewWindow::createToolBar()
277 QtxActionToolMgr* aMgr = toolMgr();
278 int idTB = aMgr->createToolBar( tr("LBL_TOOLBAR_LABEL"), // title (language-dependent)
279 QString( "PyEditorOperations" ), // name (language-independent)
280 false ); // disable floatable toolbar
281 aMgr->append( NewId, idTB );
282 aMgr->append( OpenId, idTB );
283 aMgr->append( SaveId, idTB );
284 aMgr->append( SaveAsId, idTB );
286 aMgr->append( CloseId, idTB );
287 aMgr->append( aMgr->separator(), idTB );
288 aMgr->append( UndoId, idTB );
289 aMgr->append( RedoId, idTB );
290 aMgr->append( aMgr->separator(), idTB );
291 aMgr->append( CutId, idTB );
292 aMgr->append( CopyId, idTB );
293 aMgr->append( PasteId, idTB );
294 aMgr->append( DeleteId, idTB );
295 aMgr->append( SelectAllId, idTB );
296 aMgr->append( aMgr->separator(), idTB );
297 aMgr->append( PreferencesId, idTB );
298 aMgr->append( aMgr->separator(), idTB );
299 aMgr->append( BrowserId, idTB );
304 \brief Reimplemented class is to receive a window close request.
305 \param theEvent event
307 void PyViewer_ViewWindow::closeEvent( QCloseEvent* theEvent )
316 SLOT: Creates a new document
318 void PyViewer_ViewWindow::onNew()
322 my_TextEditor->clear();
323 setCurrentFile( QString() );
328 SLOT: Open an existing python file
330 void PyViewer_ViewWindow::onOpen()
334 QString aFilePath = QFileDialog::getOpenFileName(
335 this, tr( "TIT_DLG_OPEN" ), QDir::currentPath(), "Python Files (*.py)" );
337 if ( !aFilePath.isEmpty() )
338 loadFile( aFilePath );
343 SLOT: Save the current file
345 bool PyViewer_ViewWindow::onSave()
347 if ( my_CurrentFile.isEmpty() )
350 return saveFile( my_CurrentFile );
355 SLOT: Save the current file under a new name
357 bool PyViewer_ViewWindow::onSaveAs()
359 QString aFilePath = QFileDialog::getSaveFileName(
360 this, tr( "TIT_DLG_SAVEAS" ), QDir::currentPath(), "Python Files (*.py)" );
362 if ( !aFilePath.isEmpty() )
363 return saveFile( aFilePath );
369 SLOT: Open preferences dialog
371 void PyViewer_ViewWindow::onPreferences()
373 PyEditor_SettingsDlg* aPage = new PyEditor_SettingsDlg( my_TextEditor, this );
374 connect( aPage, SIGNAL( onHelpClicked() ),
375 this, SLOT( onHelp() ) );
381 \brief Set preferece values for view.
383 void PyViewer_ViewWindow::setPreferences()
385 my_TextEditor->settings()->readSettings();
386 my_TextEditor->updateStatement();
390 \brief Associates the theFilePath with the python view.
391 \param theFilePath file path
393 void PyViewer_ViewWindow::setCurrentFile( const QString &theFilePath )
395 my_CurrentFile = theFilePath;
396 my_TextEditor->document()->setModified( false );
400 setWindowModified( false );
402 QString aShownName = my_CurrentFile;
403 if ( my_CurrentFile.isEmpty() )
404 aShownName = "untitled.py";
405 setWindowFilePath( aShownName );
407 // Set window title with associated file path
408 QFileInfo anInfo( aShownName );
409 setWindowTitle( "Python Viewer - " + anInfo.fileName() + "[*]" );
414 \brief Checks whether the file is modified.
415 If it has the modifications then ask the user to save it.
416 \return true if the document is saved.
418 bool PyViewer_ViewWindow::whetherSave()
420 if ( my_TextEditor->document()->isModified() )
422 QMessageBox::StandardButton aReturn;
423 aReturn = QMessageBox::warning(
424 this, tr( "TIT_DLG_SAVE" ),tr( "WRN_PY_SAVE_FILE" ),
425 QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel );
427 if ( aReturn == QMessageBox::Save )
429 else if ( aReturn == QMessageBox::Cancel )
437 \param theFilePath file path
439 void PyViewer_ViewWindow::loadFile( const QString &theFilePath )
441 QFile aFile( theFilePath );
442 if ( !aFile.open(QFile::ReadOnly | QFile::Text) )
444 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
445 tr( "WRN_PY_READ_FILE" ).arg( theFilePath ).arg( aFile.errorString() ) );
449 QTextStream anInput( &aFile );
450 QApplication::setOverrideCursor( Qt::WaitCursor );
451 my_TextEditor->setPlainText( anInput.readAll() );
452 QApplication::restoreOverrideCursor();
454 setCurrentFile( theFilePath );
457 statusBar()->showMessage( tr( "STS_F_LOADED" ), 2000 );
462 \param theFilePath file path
464 bool PyViewer_ViewWindow::saveFile( const QString &theFilePath )
466 QFile aFile( theFilePath );
467 if ( !aFile.open( QFile::WriteOnly | QFile::Text ) )
469 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
470 tr( "WRN_PY_WRITE_FILE" ).arg( theFilePath ).arg( aFile.errorString() ) );
474 QTextStream anOutput( &aFile );
475 QApplication::setOverrideCursor( Qt::WaitCursor );
476 anOutput << my_TextEditor->toPlainText();
477 QApplication::restoreOverrideCursor();
479 setCurrentFile( theFilePath );
483 statusBar()->showMessage( tr( "STS_F_SAVED" ), 2000 );
489 \brief Opens help browser with python view help information.
491 void PyViewer_ViewWindow::onBrowser()
493 QDir appDir = QApplication::applicationDirPath();
494 QStringList parameters;
495 parameters << QString( "--file=%1" ).arg( appDir.filePath( "pyeditor.html" ) );
496 QProcess::startDetached( "HelpBrowser", parameters );
500 Slot, called when user clicks "Help" button in "Preferences" dialog box.
502 void PyViewer_ViewWindow::onHelp()
505 SUIT_Application* app = SUIT_Session::session()->activeApplication();
507 app->onHelpContextModule( "GUI", "python_viewer_page.html", "custom_python_preferences" );