Salome HOME
A revision of documentation changes in the new version. Very minor corrections.
[modules/gui.git] / src / PyConsole / PyConsole_Console.cxx
1 // Copyright (C) 2007-2014  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // File   : PyConsole_Console.cxx
24 // Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
25 //
26 /*!
27   \class PyConsole_Console
28   \brief Python console widget.
29 */  
30
31 #include "PyConsole_Interp.h"   /// !!! WARNING !!! THIS INCLUDE MUST BE VERY FIRST !!!
32 #include "PyConsole_Console.h"
33 #include "PyConsole_EnhEditor.h"
34 #include "PyConsole_EnhInterp.h"
35
36 #include <Qtx.h>
37
38 #include <QAction>
39 #include <QApplication>
40 #include <QClipboard>
41 #include <QEvent>
42 #include <QMenu>
43 #include <QVBoxLayout>
44
45 /*!
46   \brief Constructor.
47
48   Creates new python console widget.
49   \param parent parent widget
50   \param interp python interpreter
51 */
52 PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* interp )
53 : QWidget( parent )
54 {
55   // create python interpreter
56   myInterp = interp;
57   if ( !myInterp )
58     myInterp = new PyConsole_Interp();
59   
60   // initialize Python interpretator
61   myInterp->initialize();
62   
63   // create editor console
64   QVBoxLayout* lay = new QVBoxLayout( this );
65   lay->setMargin( 0 );
66   myEditor = new PyConsole_Editor( myInterp, this );
67   char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
68   if (synchronous && atoi(synchronous))
69   {
70       myEditor->setIsSync(true);
71   }
72   myEditor->viewport()->installEventFilter( this );
73   lay->addWidget( myEditor );
74
75   createActions();
76 }
77
78 /**
79  * Protected constructor.
80  */
81 PyConsole_Console::PyConsole_Console( QWidget* parent, PyConsole_Interp* i,  PyConsole_Editor* e)
82   : QWidget (parent), myEditor(e), myInterp(i)
83 {}
84
85 /*!
86   \brief Destructor.
87
88   Does nothing for the moment.
89 */
90 PyConsole_Console::~PyConsole_Console()
91 {
92 }
93
94 /*!
95   \brief Execute python command in the interpreter.
96   \param command string with command and arguments
97 */
98 void PyConsole_Console::exec( const QString& command )
99 {
100   if ( myEditor )
101     myEditor->exec( command );
102 }
103
104 /*!
105   \brief Execute python command in the interpreter 
106          and wait until it is finished.
107   
108   Block execution of main application until the python command is executed.
109   \param command string with command and arguments
110 */
111 void PyConsole_Console::execAndWait( const QString& command )
112 {
113   if ( myEditor )
114     myEditor->execAndWait( command );
115 }
116
117 /*!
118   \brief Get synchronous mode flag value.
119   
120   \sa setIsSync()
121   \return True if python console works in synchronous mode
122 */
123 bool PyConsole_Console::isSync() const
124 {
125   return myEditor->isSync();
126 }
127
128 /*!
129   \brief Set synchronous mode flag value.
130
131   In synhronous mode the Python commands are executed in the GUI thread
132   and the GUI is blocked until the command is finished. In the asynchronous
133   mode each Python command is executed in the separate thread that does not
134   block the main GUI loop.
135
136   \param on synhronous mode flag
137 */
138 void PyConsole_Console::setIsSync( const bool on )
139 {
140   myEditor->setIsSync( on );
141 }
142
143 /*!
144   \brief Get suppress output flag value.
145   
146   \sa setIsSuppressOutput()
147   \return True if python console output is suppressed.
148 */
149 bool PyConsole_Console::isSuppressOutput() const
150 {
151   return myEditor->isSuppressOutput();
152 }
153
154 /*!
155   \brief Set suppress output flag value.
156
157   In case if suppress output flag is true, the python 
158   console output suppressed.
159
160   \param on suppress output flag
161 */
162 void PyConsole_Console::setIsSuppressOutput( const bool on )
163 {
164   myEditor->setIsSuppressOutput(on);
165 }
166
167 /*!
168   \brief Get 'show banner' flag value.
169   
170   \sa setIsShowBanner()
171   \return \c true if python console shows banner
172 */
173 bool PyConsole_Console::isShowBanner() const
174 {
175   return myEditor->isShowBanner();
176 }
177
178 /*!
179   \brief Set 'show banner' flag value.
180
181   The banner is shown in the top of the python console window.
182
183   \sa isShowBanner()
184   \param on 'show banner' flag
185 */
186 void PyConsole_Console::setIsShowBanner( const bool on )
187 {
188   myEditor->setIsShowBanner( on );
189 }
190
191 /*!
192   \brief Change the python console's font.
193   \param f new font
194 */
195 void PyConsole_Console::setFont( const QFont& f )
196 {
197   if( myEditor )
198     myEditor->setFont( f );
199 }
200
201 /*!
202   \brief Get python console font.
203   \return current python console's font
204 */
205 QFont PyConsole_Console::font() const
206 {
207   QFont res;
208   if( myEditor )
209     res = myEditor->font();
210   return res;
211 }
212
213 /*!
214   \brief Event handler.
215
216   Handles context menu request event.
217
218   \param o object
219   \param e event
220   \return True if the event is processed and further processing should be stopped
221 */
222 bool PyConsole_Console::eventFilter( QObject* o, QEvent* e )
223 {
224   if ( o == myEditor->viewport() && e->type() == QEvent::ContextMenu )
225   {
226     contextMenuRequest( (QContextMenuEvent*)e );
227     return true;
228   }
229   return QWidget::eventFilter( o, e );
230 }
231
232 /*!
233   \brief Create the context popup menu.
234
235   Fill in the popup menu with the commands.
236
237   \param menu context popup menu
238 */
239 void PyConsole_Console::contextMenuPopup( QMenu* menu )
240 {
241   if ( myEditor->isReadOnly() )
242     return;
243
244   menu->addAction( myActions[CopyId] );
245   menu->addAction( myActions[PasteId] );
246   menu->addAction( myActions[ClearId] );
247   menu->addSeparator();
248   menu->addAction( myActions[SelectAllId] );
249   menu->addSeparator();
250   menu->addAction( myActions[DumpCommandsId] );
251   if ( !myEditor->isLogging() )
252     menu->addAction( myActions[StartLogId] );
253   else
254     menu->addAction( myActions[StopLogId] );
255
256   Qtx::simplifySeparators( menu );
257
258   updateActions();
259 }
260
261 /*!
262   \brief Set actions to be visible in the context popup menu.
263   
264   Actions, which IDs are set in \a flags parameter, will be shown in the 
265   context popup menu. Other actions will not be shown.
266
267   \param flags ORed together actions flags
268 */
269 void PyConsole_Console::setMenuActions( const int flags )
270 {
271   myActions[CopyId]->setVisible( flags & CopyId );
272   myActions[PasteId]->setVisible( flags & PasteId );
273   myActions[ClearId]->setVisible( flags & ClearId );
274   myActions[SelectAllId]->setVisible( flags & SelectAllId );
275   myActions[DumpCommandsId]->setVisible( flags & DumpCommandsId );
276   myActions[StartLogId]->setVisible( flags & StartLogId );
277   myActions[StopLogId]->setVisible( flags & StopLogId );
278 }
279
280 /*!
281   \brief Get menu actions which are currently visible in the context popup menu.
282   \return ORed together actions flags
283   \sa setMenuActions()
284 */
285 int PyConsole_Console::menuActions() const
286 {
287   int ret = 0;
288   ret = ret | ( myActions[CopyId]->isVisible() ? CopyId : 0 );
289   ret = ret | ( myActions[PasteId]->isVisible() ? PasteId : 0 );
290   ret = ret | ( myActions[ClearId]->isVisible() ? ClearId : 0 );
291   ret = ret | ( myActions[SelectAllId]->isVisible() ? SelectAllId : 0 );
292   ret = ret | ( myActions[DumpCommandsId]->isVisible() ? DumpCommandsId : 0 );
293   ret = ret | ( myActions[StartLogId]->isVisible() ? StartLogId : 0 );
294   ret = ret | ( myActions[StopLogId]->isVisible() ? StopLogId : 0 );
295   return ret;
296 }
297
298 /*!
299   \brief Create menu actions.
300
301   Create context popup menu actions.
302 */
303 void PyConsole_Console::createActions()
304 {
305   QAction* a = new QAction( tr( "EDIT_COPY_CMD" ), this );
306   a->setStatusTip( tr( "EDIT_COPY_CMD" ) );
307   connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( copy() ) );
308   myActions.insert( CopyId, a );
309
310   a = new QAction( tr( "EDIT_PASTE_CMD" ), this );
311   a->setStatusTip( tr( "EDIT_PASTE_CMD" ) );
312   connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( paste() ) );
313   myActions.insert( PasteId, a );
314
315   a = new QAction( tr( "EDIT_CLEAR_CMD" ), this );
316   a->setStatusTip( tr( "EDIT_CLEAR_CMD" ) );
317   connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( clear() ) );
318   myActions.insert( ClearId, a );
319
320   a = new QAction( tr( "EDIT_SELECTALL_CMD" ), this );
321   a->setStatusTip( tr( "EDIT_SELECTALL_CMD" ) );
322   connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( selectAll() ) );
323   myActions.insert( SelectAllId, a );
324   
325   a = new QAction( tr( "EDIT_DUMPCOMMANDS_CMD" ), this );
326   a->setStatusTip( tr( "EDIT_DUMPCOMMANDS_CMD" ) );
327   connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( dump() ) );
328   myActions.insert( DumpCommandsId, a );
329
330   a = new QAction( tr( "EDIT_STARTLOG_CMD" ), this );
331   a->setStatusTip( tr( "EDIT_STARTLOG_CMD" ) );
332   connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( startLog() ) );
333   myActions.insert( StartLogId, a );
334
335   a = new QAction( tr( "EDIT_STOPLOG_CMD" ), this );
336   a->setStatusTip( tr( "EDIT_STOPLOG_CMD" ) );
337   connect( a, SIGNAL( triggered( bool ) ), myEditor, SLOT( stopLog() ) );
338   myActions.insert( StopLogId, a );
339 }
340
341 /*!
342   \brief Update menu actions.
343
344   Update context popup menu action state.
345 */
346 void PyConsole_Console::updateActions()
347 {
348   myActions[CopyId]->setEnabled( myEditor->textCursor().hasSelection() );
349   myActions[PasteId]->setEnabled( !myEditor->isReadOnly() && !QApplication::clipboard()->text().isEmpty() );
350   myActions[SelectAllId]->setEnabled( !myEditor->document()->isEmpty() );
351 }
352
353 /*!
354   \brief Start python trace logging
355   \param fileName the path to the log file
356 */
357 void PyConsole_Console::startLog( const QString& fileName )
358 {
359   myEditor->startLog( fileName );
360 }
361
362 /*!
363   \brief Stop python trace logging
364 */
365 void PyConsole_Console::stopLog()
366 {
367   myEditor->stopLog();
368 }
369
370 /**
371  * Similar to constructor of the base class but using enhanced objects.
372  * TODO: this should really be done in a factory to avoid code duplication.
373  * @param parent
374  * @param interp
375  */
376 PyConsole_EnhConsole::PyConsole_EnhConsole( QWidget* parent, PyConsole_EnhInterp* interp)
377   : PyConsole_Console(parent, interp, 0)
378 {
379   // create python interpreter
380   myInterp = interp;
381   if ( !myInterp )
382     myInterp = new PyConsole_EnhInterp();
383
384   // initialize Python interpretator
385   myInterp->initialize();
386
387   // create editor console
388   QVBoxLayout* lay = new QVBoxLayout( this );
389   lay->setMargin( 0 );
390   myEditor = new PyConsole_EnhEditor( static_cast<PyConsole_EnhInterp*>(myInterp), this );
391   char* synchronous = getenv("PYTHON_CONSOLE_SYNC");
392   if (synchronous && atoi(synchronous))
393   {
394       myEditor->setIsSync(true);
395   }
396   myEditor->viewport()->installEventFilter( this );
397   lay->addWidget( myEditor );
398
399   createActions();
400 }