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 : PyEditor_Window.cxx
20 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
23 #include "PyEditor_Window.h"
24 #include "PyEditor_Editor.h"
25 #include "PyEditor_Settings.h"
26 #include "PyEditor_SettingsDlg.h"
29 #include <QApplication>
30 #include <QFileDialog>
32 #include <QMessageBox>
34 #include <QTextStream>
38 \class PyEditor_Window
39 \brief Python view window.
44 \param parent parent widget
46 PyEditor_Window::PyEditor_Window( QWidget* parent ) :
49 Q_INIT_RESOURCE( PyEditor );
51 // Create editor and set it as a central widget.
52 myTextEditor = new PyEditor_Editor( this );
53 setCentralWidget( myTextEditor );
59 action = new QAction( QIcon( ":/images/py_new.png" ),
60 tr( "ACT_NEW" ), this );
61 action->setToolTip( tr( "TTP_NEW" ) );
62 action->setStatusTip( tr( "DSC_NEW" ) );
63 action->setShortcut( QKeySequence::New );
64 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onNew() ) );
65 myActions[ NewId ] = action;
68 action = new QAction( QIcon( ":/images/py_open.png" ),
69 tr( "ACT_OPEN" ), this );
70 action->setToolTip( tr( "TTP_OPEN" ) );
71 action->setStatusTip( tr( "DSC_OPEN" ) );
72 action->setShortcut( QKeySequence::Open );
73 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onOpen() ) );
74 myActions[ OpenId ] = action;
77 action = new QAction( QIcon( ":/images/py_save.png" ),
78 tr( "ACT_SAVE" ), this );
79 action->setToolTip( tr( "TTP_SAVE" ) );
80 action->setStatusTip( tr( "DSC_SAVE" ) );
81 action->setShortcut( QKeySequence::Save );
82 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSave() ) );
83 action->setEnabled( false );
84 connect( myTextEditor->document(), SIGNAL( modificationChanged( bool ) ),
85 action, SLOT( setEnabled( bool ) ) );
86 myActions[ SaveId ] = action;
89 action = new QAction( QIcon( ":/images/py_save_as.png" ),
90 tr( "ACT_SAVEAS" ), this );
91 action->setToolTip( tr( "TTP_SAVEAS" ) );
92 action->setStatusTip( tr( "DSC_SAVEAS" ) );
93 action->setShortcut( QKeySequence::SaveAs );
94 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onSaveAs() ) );
95 myActions[ SaveAsId ] = action;
98 action = new QAction( QIcon( ":/images/py_exit.png" ),
99 tr( "ACT_EXIT" ), this );
100 action->setToolTip( tr( "TTP_EXIT" ) );
101 action->setStatusTip( tr( "DSC_EXIT" ) );
102 action->setShortcut( QKeySequence::Quit );
103 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( close() ) );
104 myActions[ ExitId ] = action;
107 action = new QAction( QIcon( ":/images/py_undo.png" ),
108 tr( "ACT_UNDO" ), this );
109 action->setToolTip( tr( "TTP_UNDO" ) );
110 action->setStatusTip( tr( "DSC_UNDO" ) );
111 action->setShortcut( QKeySequence::Undo );
112 connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( undo() ) );
113 action->setEnabled( false );
114 connect( myTextEditor->document(), SIGNAL( undoAvailable( bool ) ),
115 action, SLOT( setEnabled( bool ) ) );
116 myActions[ UndoId ] = action;
119 action = new QAction( QIcon( ":/images/py_redo.png" ),
120 tr( "ACT_REDO" ), this );
121 action->setToolTip( tr( "TTP_REDO" ) );
122 action->setStatusTip( tr( "DSC_REDO" ) );
123 action->setShortcut( QKeySequence::Redo );
124 connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( redo() ) );
125 action->setEnabled( false );
126 connect( myTextEditor->document(), SIGNAL( redoAvailable( bool ) ),
127 action, SLOT( setEnabled( bool ) ) );
128 myActions[ RedoId ] = action;
131 action = new QAction( QIcon( ":/images/py_cut.png" ),
132 tr( "ACT_CUT" ), this );
133 action->setToolTip( tr( "TTP_CUT" ) );
134 action->setStatusTip( tr( "DSC_CUT" ) );
135 action->setShortcut( QKeySequence::Cut );
136 connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( cut() ) );
137 action->setEnabled( false );
138 connect( myTextEditor, SIGNAL( copyAvailable( bool ) ),
139 action, SLOT( setEnabled( bool ) ) );
140 myActions[ CutId ] = action;
143 action = new QAction( QIcon( ":/images/py_copy.png" ),
144 tr( "ACT_COPY" ), this );
145 action->setToolTip( tr( "TTP_COPY" ) );
146 action->setStatusTip( tr( "DSC_COPY" ) );
147 action->setShortcut( QKeySequence::Copy );
148 connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( copy() ) );
149 action->setEnabled( false );
150 connect( myTextEditor, SIGNAL( copyAvailable( bool ) ),
151 action, SLOT( setEnabled( bool ) ) );
152 myActions[ CopyId ] = action;
155 action = new QAction( QIcon( ":/images/py_paste.png" ),
156 tr( "ACT_PASTE" ), this );
157 action->setToolTip( tr( "TTP_PASTE" ) );
158 action->setStatusTip( tr( "DSC_PASTE" ) );
159 action->setShortcut( QKeySequence::Paste );
160 connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( paste() ) );
161 myActions[ PasteId ] = action;
164 action = new QAction( QIcon( ":/images/py_delete.png" ),
165 tr( "ACT_DELETE" ), this );
166 action->setToolTip( tr( "TTP_DELETE" ) );
167 action->setStatusTip( tr( "DSC_DELETE" ) );
168 action->setShortcut( QKeySequence::Delete );
169 connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( deleteSelected() ) );
170 action->setEnabled( false );
171 connect( myTextEditor, SIGNAL( copyAvailable( bool ) ),
172 action, SLOT( setEnabled( bool ) ) );
173 myActions[ DeleteId ] = action;
176 action = new QAction( QIcon( ":/images/py_select_all.png" ),
177 tr( "ACT_SELECT_ALL" ), this );
178 action->setToolTip( tr( "TTP_SELECT_ALL" ) );
179 action->setStatusTip( tr( "DSC_SELECT_ALL" ) );
180 action->setShortcut( QKeySequence::SelectAll );
181 connect( action, SIGNAL( triggered( bool ) ), myTextEditor, SLOT( selectAll() ) );
182 myActions[ SelectAllId ] = action;
185 action = new QAction( QIcon( ":/images/py_preferences.png" ),
186 tr( "ACT_PREFERENCES" ), this );
187 action->setToolTip( tr( "TTP_PREFERENCES" ) );
188 action->setStatusTip( tr( "DSC_PREFERENCES" ) );
189 connect( action, SIGNAL( triggered( bool ) ), this, SLOT( onPreferences() ) );
190 myActions[ PreferencesId ] = action;
193 action = new QAction( QIcon( ":/images/py_help.png" ),
194 tr( "ACT_HELP" ), this );
195 action->setToolTip( tr( "TTP_HELP" ) );
196 action->setStatusTip( tr( "DSC_HELP" ) );
197 connect( action, SIGNAL( triggered() ), this, SLOT( onHelp() ) );
198 myActions[ HelpId ] = action;
201 QMenu* menu = menuBar()->addMenu( tr( "MNU_FILE" ) );
202 menu->addAction( myActions[ NewId ] );
203 menu->addAction( myActions[ OpenId ] );
204 menu->addSeparator();
205 menu->addAction( myActions[ SaveId ] );
206 menu->addAction( myActions[ SaveAsId ] );
207 menu->addSeparator();
208 menu->addAction( myActions[ ExitId ] );
210 menu = menuBar()->addMenu( tr( "MNU_EDIT" ) );
211 menu->addAction( myActions[ UndoId ] );
212 menu->addAction( myActions[ RedoId ] );
213 menu->addSeparator();
214 menu->addAction( myActions[ CutId ] );
215 menu->addAction( myActions[ CopyId ] );
216 menu->addAction( myActions[ PasteId ] );
217 menu->addAction( myActions[ DeleteId ] );
218 menu->addSeparator();
219 menu->addAction( myActions[ SelectAllId ] );
220 menu->addSeparator();
221 menu->addAction( myActions[ PreferencesId ] );
223 menu = menuBar()->addMenu( tr( "MNU_HELP" ) );
224 menu->addAction( myActions[ HelpId ] );
227 QToolBar* toolbar = addToolBar( tr( "TOOLBAR_LABEL" ) );
228 toolbar->setObjectName("PythonEditor");
229 toolbar->addAction( myActions[ NewId ] );
230 toolbar->addAction( myActions[ OpenId ] );
231 toolbar->addAction( myActions[ SaveId ] );
232 toolbar->addAction( myActions[ SaveAsId ] );
233 toolbar->addSeparator();
234 toolbar->addAction( myActions[ ExitId ] );
235 toolbar->addSeparator();
236 toolbar->addAction( myActions[ UndoId ] );
237 toolbar->addAction( myActions[ RedoId ] );
238 toolbar->addSeparator();
239 toolbar->addAction( myActions[ CutId ] );
240 toolbar->addAction( myActions[ CopyId ] );
241 toolbar->addAction( myActions[ PasteId ] );
242 toolbar->addAction( myActions[ DeleteId ] );
243 toolbar->addAction( myActions[ SelectAllId ] );
244 toolbar->addSeparator();
245 toolbar->addAction( myActions[ PreferencesId ] );
246 toolbar->addSeparator();
247 toolbar->addAction( myActions[ HelpId ] );
250 setCurrentFile( QString() );
252 // Additional set-up for main window.
253 connect( myTextEditor->document(), SIGNAL( modificationChanged( bool ) ),
254 this, SLOT( setWindowModified( bool ) ) );
256 // Initialize status bar.
257 statusBar()->showMessage( tr( "STS_READY" ) );
263 PyEditor_Window::~PyEditor_Window()
268 \brief Manage window close request.
269 \param event close event
271 void PyEditor_Window::closeEvent( QCloseEvent* event )
280 SLOT: Create new document
282 void PyEditor_Window::onNew()
286 myTextEditor->clear();
287 setCurrentFile( QString() );
292 SLOT: Open existing Python file
294 void PyEditor_Window::onOpen()
298 QString filter = tr( "TIT_PY_FILES" );
300 QString aFilePath = QFileDialog::getOpenFileName( this,
301 tr( "TIT_DLG_OPEN" ),
305 if ( !aFilePath.isEmpty() )
306 loadFile( aFilePath );
311 SLOT: Save current document
313 bool PyEditor_Window::onSave()
315 if ( myURL.isEmpty() )
318 return saveFile( myURL );
323 SLOT: Save current document under a new name
325 bool PyEditor_Window::onSaveAs()
327 QString filter = tr( "TIT_PY_FILES" );
329 QString url = myURL.isEmpty() ? defaultName() : myURL;
330 QString aFilePath = QFileDialog::getSaveFileName( this,
331 tr( "TIT_DLG_SAVE" ),
335 if ( !aFilePath.isEmpty() )
336 return saveFile( aFilePath );
342 SLOT: Open preferences dialog
344 void PyEditor_Window::onPreferences()
346 PyEditor_SettingsDlg dlg( myTextEditor, true, this );
347 connect( &dlg, SIGNAL( help() ), this, SLOT( onHelp() ) );
352 \brief Associate \a filePath with the current document
353 \param filePath document's file path
355 void PyEditor_Window::setCurrentFile( const QString& filePath )
358 myTextEditor->document()->setModified( false );
360 setWindowModified( false );
362 setWindowFilePath( myURL.isEmpty() ? defaultName() : myURL );
366 \brief Check whether the file is modified.
367 If it has the modifications then ask the user to save it.
368 \return true if the document is saved.
370 bool PyEditor_Window::whetherSave()
372 if ( myTextEditor->document()->isModified() )
374 QMessageBox::StandardButton answer = QMessageBox::warning( this,
375 tr( "NAME_PYEDITOR" ),
376 tr( "WRN_SAVE_FILE" ),
378 QMessageBox::Discard |
379 QMessageBox::Cancel );
382 case QMessageBox::Save:
384 case QMessageBox::Cancel:
395 \param filePath file path
397 void PyEditor_Window::loadFile( const QString& filePath )
399 QFile aFile( filePath );
400 if ( !aFile.open(QFile::ReadOnly | QFile::Text) )
402 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
403 tr( "WRN_READ_FILE" ).arg( filePath ).arg( aFile.errorString() ) );
407 QTextStream anInput( &aFile );
408 QApplication::setOverrideCursor( Qt::WaitCursor );
409 myTextEditor->setPlainText( anInput.readAll() );
410 QApplication::restoreOverrideCursor();
412 setCurrentFile( filePath );
415 statusBar()->showMessage( tr( "STS_F_LOADED" ), 2000 );
420 \param filePath file path
422 bool PyEditor_Window::saveFile( const QString& filePath )
424 QFile aFile( filePath );
425 if ( !aFile.open( QFile::WriteOnly | QFile::Text ) )
427 QMessageBox::warning( this, tr( "NAME_PYEDITOR" ),
428 tr( "WRN_WRITE_FILE" ).arg( filePath ).arg( aFile.errorString() ) );
432 QTextStream anOutput( &aFile );
433 QApplication::setOverrideCursor( Qt::WaitCursor );
434 anOutput << myTextEditor->toPlainText();
435 QApplication::restoreOverrideCursor();
437 setCurrentFile( filePath );
440 statusBar()->showMessage( tr( "STS_F_SAVED" ), 2000 );
446 Slot, called when user clicks "Help" button in "Preferences" dialog box.
448 void PyEditor_Window::onHelp()
450 QWidget* w = qobject_cast<QWidget*>( sender() );
452 QFile file(":/about.txt");
453 file.open(QFile::ReadOnly | QFile::Text);
454 QTextStream stream( &file );
455 QString about = stream.readAll();
457 QMessageBox::about( w, tr( "NAME_PYEDITOR" ), about );
461 Get default name for Python file
464 QString PyEditor_Window::defaultName() const
466 return tr( "NONAME" );