1 // Copyright (C) 2015-2016 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_Widget.h"
26 #include "PyEditor_SettingsDlg.h"
28 #include "SUIT_Session.h"
29 #include "SUIT_ResourceMgr.h"
31 #include "QtxAction.h"
32 #include "QtxActionToolMgr.h"
34 #include <QApplication>
35 #include <QCloseEvent>
36 #include <QFileDialog>
37 #include <QMessageBox>
38 #include <QTextStream>
39 #include <QVBoxLayout>
42 \class PyViewer_ViewWindow
43 \brief Python view window.
48 \param desktop SALOME desktop window
50 PyViewer_ViewWindow::PyViewer_ViewWindow( SUIT_Desktop* desktop ) :
51 SUIT_ViewWindow( desktop )
53 // Create central widget.
54 myEditor = new PyEditor_Widget( this );
55 setCentralWidget( myEditor );
58 SUIT_ResourceMgr* resMgr = SUIT_Session::session()->resourceMgr();
62 action = new QtxAction( tr( "TTP_NEW" ),
63 resMgr->loadPixmap( "PyViewer", tr( "ICON_NEW" ) ),
64 tr( "ACT_NEW" ), 0, this );
65 action->setStatusTip( tr( "DSC_NEW" ) );
66 action->setShortcut( QKeySequence::New );
67 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onNew() ) );
68 toolMgr()->registerAction( action, NewId );
71 action = new QtxAction( tr( "TTP_OPEN" ),
72 resMgr->loadPixmap( "PyViewer", tr( "ICON_OPEN" ) ),
73 tr( "ACT_OPEN" ), 0, this );
74 action->setStatusTip( tr( "DSC_OPEN" ) );
75 action->setShortcut( QKeySequence::Open );
76 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onOpen() ) );
77 toolMgr()->registerAction( action, OpenId );
80 action = new QtxAction( tr( "TTP_SAVE" ),
81 resMgr->loadPixmap( "PyViewer", tr( "ICON_SAVE" ) ),
82 tr( "ACT_SAVE" ), 0, this );
83 action->setStatusTip( tr( "DSC_SAVE" ) );
84 action->setShortcut( QKeySequence::Save );
85 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSave() ) );
86 action->setEnabled( false );
87 connect( myEditor, SIGNAL( modificationChanged( bool ) ),
88 action, SLOT( setEnabled( bool ) ) );
89 toolMgr()->registerAction( action, SaveId );
92 action = new QtxAction( tr( "TTP_SAVEAS" ),
93 resMgr->loadPixmap( "PyViewer", tr( "ICON_SAVEAS" ) ),
94 tr( "ACT_SAVEAS" ), 0, this );
95 action->setStatusTip( tr( "DSC_SAVEAS" ) );
96 action->setShortcut( QKeySequence::SaveAs );
97 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAs() ) );
98 toolMgr()->registerAction( action, SaveAsId );
101 action = new QtxAction( tr( "TTP_UNDO" ),
102 resMgr->loadPixmap( "PyViewer", tr( "ICON_UNDO" ) ),
103 tr( "ACT_UNDO" ), 0, this );
104 action->setStatusTip( tr( "DSC_UNDO" ) );
105 action->setShortcut( QKeySequence::Undo );
106 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( undo() ) );
107 action->setEnabled( false );
108 connect( myEditor, SIGNAL( undoAvailable( bool ) ),
109 action, SLOT( setEnabled( bool ) ) );
110 toolMgr()->registerAction( action, UndoId );
113 action = new QtxAction( tr( "TTP_REDO" ),
114 resMgr->loadPixmap( "PyViewer", tr( "ICON_REDO" ) ),
115 tr( "ACT_REDO" ), 0, this );
116 action->setStatusTip( tr( "DSC_REDO" ) );
117 action->setShortcut( QKeySequence::Redo );
118 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( redo() ) );
119 action->setEnabled( false );
120 connect( myEditor, SIGNAL( redoAvailable( bool ) ),
121 action, SLOT( setEnabled( bool ) ) );
122 toolMgr()->registerAction( action, RedoId );
125 action = new QtxAction( tr( "TTP_CUT" ),
126 resMgr->loadPixmap( "PyViewer", tr( "ICON_CUT" ) ),
127 tr( "ACT_CUT" ), 0, this );
128 action->setStatusTip( tr( "DSC_CUT" ) );
129 action->setShortcut( QKeySequence::Cut );
130 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( cut() ) );
131 action->setEnabled( false );
132 connect( myEditor, SIGNAL( copyAvailable( bool ) ),
133 action, SLOT( setEnabled( bool ) ) );
134 toolMgr()->registerAction( action, CutId );
137 action = new QtxAction( tr( "TTP_COPY" ),
138 resMgr->loadPixmap( "PyViewer", tr( "ICON_COPY" ) ),
139 tr( "ACT_COPY" ), 0, this );
140 action->setStatusTip( tr( "DSC_COPY" ) );
141 action->setShortcut( QKeySequence::Copy );
142 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( copy() ) );
143 action->setEnabled( false );
144 connect( myEditor, SIGNAL( copyAvailable( bool ) ),
145 action, SLOT( setEnabled( bool ) ) );
146 toolMgr()->registerAction( action, CopyId );
149 action = new QtxAction( tr( "TTP_PASTE" ),
150 resMgr->loadPixmap( "PyViewer", tr( "ICON_PASTE" ) ),
151 tr( "ACT_PASTE" ), 0, this );
152 action->setStatusTip( tr( "DSC_PASTE" ) );
153 action->setShortcut( QKeySequence::Paste );
154 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( paste() ) );
155 toolMgr()->registerAction( action, PasteId );
158 action = new QtxAction( tr( "TTP_DELETE" ),
159 resMgr->loadPixmap( "PyViewer", tr( "ICON_DELETE" ) ),
160 tr( "ACT_DELETE" ), 0, this );
161 action->setStatusTip( tr( "DSC_DELETE" ) );
162 action->setShortcut( QKeySequence::Delete );
163 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( deleteSelected() ) );
164 action->setEnabled( false );
165 connect( myEditor, SIGNAL( copyAvailable( bool ) ),
166 action, SLOT( setEnabled( bool ) ) );
167 toolMgr()->registerAction( action, DeleteId );
170 action = new QtxAction( tr( "TTP_SELECT_ALL" ),
171 resMgr->loadPixmap( "PyViewer", tr( "ICON_SELECT_ALL" ) ),
172 tr( "ACT_SELECT_ALL" ), 0, this );
173 action->setStatusTip( tr( "DSC_SELECT_ALL" ) );
174 action->setShortcut( QKeySequence::SelectAll );
175 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( selectAll() ) );
176 toolMgr()->registerAction( action, SelectAllId );
179 action = new QtxAction( tr( "TTP_FIND" ),
180 resMgr->loadPixmap( "PyViewer", tr( "ICON_FIND" ) ),
181 tr( "ACT_FIND" ), 0, this );
182 action->setStatusTip( tr( "DSC_FIND" ) );
183 action->setShortcut( QKeySequence::Find );
184 action->setShortcutContext( Qt::WidgetShortcut );
185 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( find() ) );
186 toolMgr()->registerAction( action, FindId );
189 action = new QtxAction( tr( "TTP_REPLACE" ),
190 resMgr->loadPixmap( "PyViewer", tr( "ICON_REPLACE" ) ),
191 tr( "ACT_REPLACE" ), 0, this );
192 action->setStatusTip( tr( "DSC_REPLACE" ) );
193 action->setShortcuts( QList<QKeySequence>() << QKeySequence( "Ctrl+H" ) << QKeySequence( QKeySequence::Replace ) );
194 action->setShortcutContext( Qt::WidgetShortcut );
195 connect( action, SIGNAL( triggered( bool ) ), myEditor, SLOT( replace() ) );
196 toolMgr()->registerAction( action, ReplaceId );
199 action = new QtxAction( tr( "TTP_PREFERENCES" ),
200 resMgr->loadPixmap( "PyViewer", tr( "ICON_PREFERENCES" ) ),
201 tr( "ACT_PREFERENCES" ), 0, this );
202 action->setStatusTip( tr( "DSC_PREFERENCES" ) );
203 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onPreferences() ) );
204 toolMgr()->registerAction( action, PreferencesId );
207 action = new QtxAction( tr( "TTP_HELP" ),
208 resMgr->loadPixmap( "PyViewer", tr( "ICON_HELP" ) ),
209 tr( "ACT_HELP" ), 0, this );
210 action->setStatusTip( tr( "DSC_HELP" ) );
211 connect( action, SIGNAL( triggered() ), this, SLOT( onHelp() ) );
212 toolMgr()->registerAction( action, HelpId );
215 int idTB = toolMgr()->createToolBar( tr("TOOLBAR_LABEL"), QString( "PythonEditor" ), false );
216 toolMgr()->append( NewId, idTB );
217 toolMgr()->append( OpenId, idTB );
218 toolMgr()->append( SaveId, idTB );
219 toolMgr()->append( SaveAsId, idTB );
220 toolMgr()->append( toolMgr()->separator(), idTB );
221 toolMgr()->append( UndoId, idTB );
222 toolMgr()->append( RedoId, idTB );
223 toolMgr()->append( toolMgr()->separator(), idTB );
224 toolMgr()->append( CutId, idTB );
225 toolMgr()->append( CopyId, idTB );
226 toolMgr()->append( PasteId, idTB );
227 toolMgr()->append( DeleteId, idTB );
228 toolMgr()->append( SelectAllId, idTB );
229 toolMgr()->append( toolMgr()->separator(), idTB );
230 toolMgr()->append( FindId, idTB );
231 toolMgr()->append( ReplaceId, idTB );
232 toolMgr()->append( toolMgr()->separator(), idTB );
233 toolMgr()->append( PreferencesId, idTB );
234 toolMgr()->append( toolMgr()->separator(), idTB );
235 toolMgr()->append( HelpId, idTB );
238 setCurrentFile( QString() );
244 PyViewer_ViewWindow::~PyViewer_ViewWindow()
249 \brief Manage window close request.
250 \param event close event
252 void PyViewer_ViewWindow::closeEvent( QCloseEvent* event )
261 SLOT: Create new document
263 void PyViewer_ViewWindow::onNew()
268 setCurrentFile( QString() );
273 SLOT: Open existing Python file
275 void PyViewer_ViewWindow::onOpen()
279 QString filter = tr( "TIT_PY_FILES" );
281 QString aFilePath = QFileDialog::getOpenFileName( this,
282 tr( "TIT_DLG_OPEN" ),
286 if ( !aFilePath.isEmpty() )
287 loadFile( aFilePath );
292 SLOT: Save current document
294 bool PyViewer_ViewWindow::onSave()
296 if ( myURL.isEmpty() )
299 return saveFile( myURL );
304 SLOT: Save current document under a new name
306 bool PyViewer_ViewWindow::onSaveAs()
308 QString filter = tr( "TIT_PY_FILES" );
310 QString url = myURL.isEmpty() ? defaultName() : myURL;
311 QString aFilePath = QFileDialog::getSaveFileName( this,
312 tr( "TIT_DLG_SAVE" ),
316 if ( !aFilePath.isEmpty() )
317 return saveFile( aFilePath );
323 SLOT: Open preferences dialog
325 void PyViewer_ViewWindow::onPreferences()
327 PyEditor_SettingsDlg dlg( myEditor->editor(), true, this );
328 connect( &dlg, SIGNAL( help() ), this, SLOT( onHelp() ) );
333 \brief Associate \a filePath with the current document
334 \param filePath document's file path
336 void PyViewer_ViewWindow::setCurrentFile( const QString& filePath )
339 myEditor->setModified( false );
343 \brief Check whether the file is modified.
344 If it has the modifications then ask the user to save it.
345 \return true if the document is saved.
347 bool PyViewer_ViewWindow::whetherSave()
349 if ( myEditor->isModified() )
351 QMessageBox::StandardButton answer = QMessageBox::warning( this,
352 tr( "NAME_PYEDITOR" ),
353 tr( "WRN_SAVE_FILE" ),
355 QMessageBox::Discard |
356 QMessageBox::Cancel );
359 case QMessageBox::Save:
361 case QMessageBox::Cancel:
372 \param filePath file path
374 void PyViewer_ViewWindow::loadFile( const QString& filePath )
376 QFile aFile( filePath );
377 if ( !aFile.open(QFile::ReadOnly | QFile::Text) )
379 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
380 tr( "WRN_READ_FILE" ).arg( filePath ).arg( aFile.errorString() ) );
384 QTextStream anInput( &aFile );
385 QApplication::setOverrideCursor( Qt::WaitCursor );
386 myEditor->setText( anInput.readAll() );
387 QApplication::restoreOverrideCursor();
389 setCurrentFile( filePath );
396 \param theFilePath file path
398 bool PyViewer_ViewWindow::saveFile( const QString& filePath )
400 QFile aFile( filePath );
401 if ( !aFile.open( QFile::WriteOnly | QFile::Text ) )
403 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
404 tr( "WRN_WRITE_FILE" ).arg( filePath ).arg( aFile.errorString() ) );
408 QTextStream anOutput( &aFile );
409 QApplication::setOverrideCursor( Qt::WaitCursor );
410 anOutput << myEditor->text();
411 QApplication::restoreOverrideCursor();
413 setCurrentFile( filePath );
420 Slot, called when user clicks "Help" button in "Preferences" dialog box.
422 void PyViewer_ViewWindow::onHelp()
424 SUIT_Application* app = SUIT_Session::session()->activeApplication();
426 QString page = "python_viewer_page.html";
427 if ( qobject_cast<QWidget*>( sender() ) )
428 page += "#custom_python_preferences";
429 app->onHelpContextModule( "GUI", page );
434 Get default name for Python file
437 QString PyViewer_ViewWindow::defaultName() const
439 return tr( "NONAME" );