]> SALOME platform Git repositories - modules/gui.git/blob - src/PythonConsole/PythonConsole_PyEditor.cxx
Salome HOME
*** empty log message ***
[modules/gui.git] / src / PythonConsole / PythonConsole_PyEditor.cxx
1 //  SALOME SALOMEGUI : implementation of desktop and GUI kernel
2 //
3 //  Copyright (C) 2003  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. 
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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : PythonConsole_PyEditor.cxx
25 //  Author : Nicolas REJNERI
26 //  Module : SALOME
27
28 #include <PythonConsole_PyEditor.h> // this include must be first (see PyInterp_base.h)!
29
30 #include <PyInterp_Dispatcher.h>
31
32 #include <SUIT_Tools.h>
33
34 #include <qmap.h>
35 #include <qclipboard.h>
36 #include <qdragobject.h>
37 #include <qapplication.h>
38
39 using namespace std;
40
41 enum { IdCopy, IdPaste, IdClear, IdSelectAll };
42
43 static QString READY_PROMPT = ">>> ";
44 static QString DOTS_PROMPT  = "... ";
45 #define PROMPT_SIZE _currentPrompt.length()
46
47 class ExecCommand : public PyInterp_LockRequest
48 {
49 public:
50   ExecCommand(PyInterp_base* theInterp, const char* theCommand, PythonConsole_PyEditor* theListener)
51 : PyInterp_LockRequest( theInterp, theListener ), myCommand(theCommand), myState( PyInterp_Event::OK )
52   {}
53
54 protected:
55   virtual void execute(){
56     if(myCommand != ""){
57 //      if(MYDEBUG) MESSAGE("*** ExecCommand::execute() started");
58       int ret = getInterp()->run( myCommand.latin1() );
59 //      if(MYDEBUG) MESSAGE("ExecCommand::execute() - myInterp = "<<getInterp()<<"; myCommand = '"<<myCommand.latin1()<<"' - "<<ret);
60       if(ret < 0)
61         myState = PyInterp_Event::ERROR;
62       else if(ret > 0)
63         myState = PyInterp_Event::INCOMPLETE;
64       myError  = getInterp()->getverr().c_str();
65       myOutput = getInterp()->getvout().c_str();
66 //      if(MYDEBUG) MESSAGE("*** ExecCommand::execute() finished");
67     }else{
68       myError = "";
69       myOutput = "";
70     }
71   }
72
73   virtual QEvent* createEvent() const
74   {
75     return new PyInterp_Event( myState, (PyInterp_Request*)this );    
76   }
77
78 public:
79   QString myError;
80   QString myOutput;
81
82 private:
83   QString myCommand;
84   int myState;
85 };
86
87
88 /*!
89     Constructor
90 */
91 PythonConsole_PyEditor::PythonConsole_PyEditor(PyInterp_base* theInterp, QWidget *theParent, const char* theName): 
92   QTextEdit(theParent,theName),
93   myInterp( 0 )
94 {
95   QString fntSet( "" );
96   QFont aFont = SUIT_Tools::stringToFont( fntSet );
97   setFont(aFont);
98   setTextFormat(QTextEdit::PlainText);
99   setUndoRedoEnabled( false );
100
101   _currentPrompt = READY_PROMPT;
102   setWordWrap(NoWrap);
103
104   connect(this,SIGNAL(returnPressed()),this,SLOT(handleReturn()) );
105
106   // san - This is necessary for troubleless initialization
107   onPyInterpChanged( theInterp );
108 }
109
110 /*!
111     Destructor
112 */
113 PythonConsole_PyEditor::~PythonConsole_PyEditor()
114 {
115 //  if(MYDEBUG) MESSAGE("PythonConsole_PyEditor::~PythonConsole_PyEditor()");
116 }
117
118 /*!
119     Called to insert a string s 
120 */
121 void PythonConsole_PyEditor::setText(QString s)
122 {
123   int para=paragraphs()-1;
124   int col=paragraphLength(para);
125   insertAt(s,para,col);
126   int n = paragraphs()-1;  
127   setCursorPosition( n, paragraphLength(n)); 
128 }
129
130 /*!
131     Called when an handleReturn
132 */
133 void PythonConsole_PyEditor::handleReturn()
134 {
135   int para=paragraphs()-2;
136   _buf.append(text(para).remove(0,PROMPT_SIZE));
137   _buf.truncate( _buf.length() - 1 );
138   setReadOnly( true );
139   viewport()->setCursor( waitCursor );
140   
141   // Post a request to execute Python command
142   // Editor will be informed via a custom event that execution has been completed
143   PyInterp_Dispatcher::Get()->Exec( new ExecCommand( myInterp, _buf.latin1(), this ) );
144 }
145
146 /*
147    Processes drop event: paste dragged text
148 */
149 void PythonConsole_PyEditor::contentsDropEvent( QDropEvent* event )
150 {
151   event->acceptAction();
152   QString text;
153   if ( QTextDrag::decode( event, text ) ) {
154     int par, col;
155     int endLine = paragraphs() -1;
156     col = charAt( event->pos(), &par );
157     
158     if ( col >= 0 && par >= 0 ) {
159       if ( par != endLine || col < PROMPT_SIZE ) {
160         par = endLine;
161         col = paragraphLength( endLine );
162       }
163       setCursorPosition( par, col );
164       insertAt( text, par, col );
165       removeSelection();
166     }
167   }
168 }
169
170 /*
171    Processes middle button release event - paste clipboard's contents
172 */
173 void PythonConsole_PyEditor::contentsMouseReleaseEvent( QMouseEvent* event )
174 {
175   if ( event->button() == LeftButton ) {
176     QTextEdit::contentsMouseReleaseEvent(event);
177     copy();
178   }
179   if ( event->button() == MidButton ) {
180     if (QApplication::clipboard()->supportsSelection()) {
181       int par, col;
182       int endLine = paragraphs() -1;
183       col = charAt( event->pos(), &par );
184       if ( col >= 0 && par >= 0 ) {
185         if ( par != endLine || col < PROMPT_SIZE )
186           setCursorPosition( endLine, paragraphLength( endLine ) );
187         else
188           setCursorPosition( par, col );
189         QApplication::clipboard()->setSelectionMode(TRUE);
190         paste();
191         QApplication::clipboard()->setSelectionMode(FALSE);
192       }
193     }
194   }
195   else {
196     QTextEdit::contentsMouseReleaseEvent(event);
197   }
198 }
199
200 /*
201    Processes own popup menu
202 */
203 void PythonConsole_PyEditor::mousePressEvent (QMouseEvent* event)
204 {
205   if ( event->button() == RightButton ) {
206     QPopupMenu *popup = new QPopupMenu( this );
207     QMap<int, int> idMap;
208
209     int para1, col1, para2, col2;
210     getSelection(&para1, &col1, &para2, &col2);
211     bool allSelected = hasSelectedText() &&
212       para1 == 0 && para2 == paragraphs()-1 && col1 == 0 && para2 == paragraphLength(para2);
213     int id;
214     id = popup->insertItem( tr( "EDIT_COPY_CMD" ) );
215     idMap.insert(IdCopy, id);
216     id = popup->insertItem( tr( "EDIT_PASTE_CMD" ) );
217     idMap.insert(IdPaste, id);
218     id = popup->insertItem( tr( "EDIT_CLEAR_CMD" ) );
219     idMap.insert(IdClear, id);
220     popup->insertSeparator();
221     id = popup->insertItem( tr( "EDIT_SELECTALL_CMD" ) );
222     idMap.insert(IdSelectAll, id);
223     popup->setItemEnabled( idMap[ IdCopy ],  hasSelectedText() );
224     popup->setItemEnabled( idMap[ IdPaste ],
225                           !isReadOnly() && (bool)QApplication::clipboard()->text().length() );
226     popup->setItemEnabled( idMap[ IdSelectAll ],
227                           (bool)text().length() && !allSelected );
228     
229     int r = popup->exec( event->globalPos() );
230     delete popup;
231     
232     if ( r == idMap[ IdCopy ] ) {
233       copy();
234     }
235     else if ( r == idMap[ IdPaste ] ) {
236       paste();
237     }
238     else if ( r == idMap[ IdClear ] ) {
239       clear();
240       setText(myBanner);
241       _currentPrompt = READY_PROMPT;
242       setText(_currentPrompt);
243     }
244     else if ( r == idMap[ IdSelectAll ] ) {
245       selectAll();
246     }
247   }
248   else {
249     QTextEdit::mousePressEvent(event);
250   }
251 }
252
253 /*!
254    Checks, is the string a command line or not.
255 */
256
257 bool PythonConsole_PyEditor::isCommand( const QString& str) const
258 {
259   // prompt may be '>>> ' or for '... '
260   return ( str.find( READY_PROMPT ) == 0 || str.find( DOTS_PROMPT ) == 0 );
261 }
262
263
264 /*!
265     Called when a keyPress event
266 */
267 void PythonConsole_PyEditor::keyPressEvent( QKeyEvent* e )
268 {
269   // get cursor position
270   int curLine, curCol;
271   getCursorPosition(&curLine, &curCol);
272
273   // get last edited line
274   int endLine = paragraphs() -1;
275
276   // get pressed key code
277   int aKey = e->key();
278
279   // check if <Ctrl> is pressed
280   bool ctrlPressed = e->state() & ControlButton;
281   // check if <Shift> is pressed
282   bool shftPressed = e->state() & ShiftButton;
283
284   // process <Ctrl>+<C> key-bindings
285   if ( aKey == Key_C && ctrlPressed ) {
286     _buf.truncate(0);
287     setText("\n");
288     _currentPrompt = READY_PROMPT;
289     setText(_currentPrompt);
290     return;
291   }
292
293   // check for printed key
294   aKey = ( aKey < Key_Space || aKey > Key_ydiaeresis ) ? aKey : 0;
295
296   switch ( aKey ) {
297   case 0 :
298     // any printed key
299     {
300       if ( curLine < endLine || curCol < PROMPT_SIZE )
301         moveCursor( QTextEdit::MoveEnd, false );
302       QTextEdit::keyPressEvent( e );
303       break;
304     }
305   case Key_Return:
306   case Key_Enter:
307     // <Enter> key
308     {
309       moveCursor( QTextEdit::MoveEnd, false );
310       QTextEdit::keyPressEvent( e );
311       break;
312     }
313   case Key_Up:
314     // <Up> arrow key: process as follows:
315     // - without <Ctrl>, <Shift> modifiers: previous command in history
316     // - with <Ctrl> modifier key pressed:  move cursor one row up without selection
317     // - with <Shift> modifier key pressed: move cursor one row up with selection
318     // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row up
319     {
320       if ( ctrlPressed && shftPressed ) {
321         scrollBy( 0, -QFontMetrics( font() ).lineSpacing() );
322       }
323       else if ( shftPressed ) {
324         if ( curLine > 0 )
325           moveCursor( QTextEdit::MoveUp, true );
326       }
327       else if ( ctrlPressed ) {
328         moveCursor( QTextEdit::MoveUp, false );
329       }
330       else { 
331         QString histLine = _currentPrompt;
332         if ( ! _isInHistory ) {
333           _isInHistory = true;
334           _currentCommand = text( endLine ).remove( 0, PROMPT_SIZE );
335           _currentCommand.truncate( _currentCommand.length() - 1 );
336         }
337         QString previousCommand = myInterp->getPrevious();
338         if ( previousCommand.compare( BEGIN_HISTORY_PY ) != 0 )
339   {
340     removeParagraph( endLine );
341           histLine.append( previousCommand );
342     append( histLine );
343         }
344         moveCursor( QTextEdit::MoveEnd, false );
345       }
346       break;
347     }
348   case Key_Down:
349     // <Down> arrow key: process as follows:
350     // - without <Ctrl>, <Shift> modifiers: next command in history
351     // - with <Ctrl> modifier key pressed:  move cursor one row down without selection
352     // - with <Shift> modifier key pressed: move cursor one row down with selection
353     // - with <Ctrl>+<Shift> modifier keys pressed: scroll one row down
354     {
355       if ( ctrlPressed && shftPressed ) {
356         scrollBy( 0, QFontMetrics( font() ).lineSpacing() );
357       }
358       else if ( shftPressed ) {
359         if ( curLine < endLine )
360           moveCursor( QTextEdit::MoveDown, true );
361       }
362       else if ( ctrlPressed ) {
363         moveCursor( QTextEdit::MoveDown, false );
364       }
365       else { 
366         QString histLine = _currentPrompt;
367         QString nextCommand = myInterp->getNext();
368         if ( nextCommand.compare( TOP_HISTORY_PY ) != 0 ) {
369           removeParagraph( endLine );
370           histLine.append( nextCommand );
371           append( histLine );
372         }
373         else {
374           if (_isInHistory) {
375             _isInHistory = false;
376             removeParagraph( endLine );
377             histLine.append( _currentCommand );
378             append( histLine );
379           }
380         }
381         moveCursor( QTextEdit::MoveEnd, false );
382       }
383       break;
384     }
385   case Key_Left:
386     // <Left> arrow key: process as follows:
387     // - without <Ctrl>, <Shift> modifiers: move one symbol left (taking into account prompt)
388     // - with <Ctrl> modifier key pressed:  move one word left (taking into account prompt)
389     // - with <Shift> modifier key pressed: move one symbol left with selection
390     // - with <Ctrl>+<Shift> modifier keys pressed: move one word left with selection
391     {
392       if ( !shftPressed && isCommand( text( curLine ) ) && curCol <= PROMPT_SIZE ) {
393         setCursorPosition( curLine-1, 0 );
394         moveCursor( QTextEdit::MoveLineEnd, false );
395       }
396       else {
397         QTextEdit::keyPressEvent( e );
398       }
399       break;
400     }
401   case Key_Right:
402     // <Right> arrow key: process as follows:
403     // - without <Ctrl>, <Shift> modifiers: move one symbol right (taking into account prompt)
404     // - with <Ctrl> modifier key pressed:  move one word right (taking into account prompt)
405     // - with <Shift> modifier key pressed: move one symbol right with selection
406     // - with <Ctrl>+<Shift> modifier keys pressed: move one word right with selection
407     {
408       if ( !shftPressed ) {
409         if ( curCol < paragraphLength( curLine ) ) {
410           if ( isCommand( text( curLine ) ) && curCol < PROMPT_SIZE ) {
411             setCursorPosition( curLine, PROMPT_SIZE );
412             break;
413           }
414         }
415         else {
416           if ( curLine < endLine && isCommand( text( curLine+1 ) ) ) {
417             setCursorPosition( curLine+1, PROMPT_SIZE );
418             break;
419           }
420         }
421       }
422       QTextEdit::keyPressEvent( e );
423       break;
424     }
425   case Key_PageUp:
426     // <PageUp> key: process as follows:
427     // - without <Ctrl>, <Shift> modifiers: first command in history
428     // - with <Ctrl> modifier key pressed:  move cursor one page up without selection
429     // - with <Shift> modifier key pressed: move cursor one page up with selection
430     // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page up
431     {
432       if ( ctrlPressed && shftPressed ) {
433         scrollBy( 0, -visibleHeight() );
434       }
435       else if ( shftPressed ) {
436         if ( curLine > 0 )
437           moveCursor( QTextEdit::MovePgUp, true );
438       }
439       else if ( ctrlPressed ) {
440         moveCursor( QTextEdit::MovePgUp, false );
441       }
442       else { 
443         QString histLine = _currentPrompt;
444         if ( ! _isInHistory ) {
445           _isInHistory = true;
446           _currentCommand = text( endLine ).remove( 0, PROMPT_SIZE );
447           _currentCommand.truncate( _currentCommand.length() - 1 );
448         }
449         QString firstCommand = myInterp->getPrevious();
450         QString pcmd;
451         while ( ( pcmd = QString( myInterp->getPrevious() ) ).compare( BEGIN_HISTORY_PY ) != 0 )
452           firstCommand = pcmd;
453         if ( firstCommand.compare( BEGIN_HISTORY_PY ) != 0 ) {
454           removeParagraph( endLine );
455           histLine.append( firstCommand );
456           insertParagraph( histLine, -1 );
457         }
458         moveCursor( QTextEdit::MoveEnd, false );
459       }
460       break;
461     }
462   case Key_PageDown:
463     // <PageDown> key: process as follows:
464     // - without <Ctrl>, <Shift> modifiers: last command in history
465     // - with <Ctrl> modifier key pressed:  move cursor one page down without selection
466     // - with <Shift> modifier key pressed: move cursor one page down with selection
467     // - with <Ctrl>+<Shift> modifier keys pressed: scroll one page down
468     {
469       if ( ctrlPressed && shftPressed ) {
470         scrollBy( 0, visibleHeight() );
471       }
472       else if ( shftPressed ) {
473         if ( curLine < endLine )
474           moveCursor( QTextEdit::MovePgDown, true );
475       }
476       else if ( ctrlPressed ) {
477         moveCursor( QTextEdit::MovePgDown, false );
478       }
479       else { 
480         if ( _isInHistory ) {
481           QString histLine = _currentPrompt;
482           while ( QString( myInterp->getNext() ).compare( TOP_HISTORY_PY ) != 0 );
483           _isInHistory = false;
484           removeParagraph( endLine );
485           histLine.append( _currentCommand );
486           insertParagraph( histLine, -1 );
487         }
488         moveCursor( QTextEdit::MoveEnd, false );
489       }
490       break;
491     }
492   case Key_Home: 
493     // <Home> key: process as follows:
494     // - without <Ctrl>, <Shift> modifiers: move cursor to the beginning of the current line without selection
495     // - with <Ctrl> modifier key pressed:  move cursor to the very first symbol without selection
496     // - with <Shift> modifier key pressed: move cursor to the beginning of the current line with selection
497     // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very first symbol with selection
498     {
499       if ( ctrlPressed ) { 
500         moveCursor( QTextEdit::MoveHome, shftPressed );
501       }
502       else {
503         if ( isCommand( text( curLine ) ) ) {
504           int ps1, ps2, cs1, cs2;
505           bool hasSelection = hasSelectedText();
506           if ( hasSelection )
507             getSelection( &ps1, &cs1, &ps2, &cs2 );
508           removeSelection();
509           horizontalScrollBar()->setValue( horizontalScrollBar()->minValue() );
510           if ( curCol > PROMPT_SIZE && shftPressed ) 
511             setSelection( curLine, PROMPT_SIZE, curLine, ( hasSelection && ps1 == ps2 && ps1 == curLine && cs2 > PROMPT_SIZE ) ? cs2 : curCol );
512           setCursorPosition( curLine, PROMPT_SIZE );
513         }
514         else {
515           moveCursor( QTextEdit::MoveLineStart, shftPressed );
516         }
517       }
518       break;
519     }
520   case Key_End:
521     // <End> key: process as follows:
522     // - without <Ctrl>, <Shift> modifiers: move cursor to the end of the current line without selection
523     // - with <Ctrl> modifier key pressed:  move cursor to the very last symbol without selection
524     // - with <Shift> modifier key pressed: move cursor to the end of the current line with selection
525     // - with <Ctrl>+<Shift> modifier keys pressed: move cursor to the very last symbol with selection
526     {
527       if ( ctrlPressed ) { 
528         moveCursor( QTextEdit::MoveEnd, shftPressed );
529       }
530       else {
531         moveCursor( QTextEdit::MoveLineEnd, shftPressed );
532       }
533       break;
534     }  
535   case Key_Backspace :
536     // <Backspace> key: process as follows
537     // - without any modifiers : delete symbol before the cursor / selection (taking into account prompt)
538     // - with <Ctrl> modifier key pressed: delete previous word
539     // works only for last (command) line
540     {
541       if ( curLine == endLine && ( curCol > PROMPT_SIZE || curCol >= PROMPT_SIZE && hasSelectedText() ) ) {
542         if ( ctrlPressed && !hasSelectedText() ) {
543           QString txt = text( curLine );
544           int ind = curCol-1;
545           while ( ind > 0 && txt[ ind ] == ' ' ) ind--;
546           ind = txt.findRev( ' ', ind ) + 1;
547           if ( ind > PROMPT_SIZE-1 ) {
548             setSelection( curLine, ind, curLine, curCol );
549             removeSelectedText();
550           }
551           else {
552             QTextEdit::keyPressEvent( e );
553           }
554         }
555         else {
556           QTextEdit::keyPressEvent( e );
557         }
558       }
559       break;
560     }
561   case Key_Delete :
562     // <Delete> key: process as follows
563     // - without any modifiers : delete symbol after the cursor / selection (taking into account prompt)
564     // - with <Ctrl> modifier key pressed: delete next word
565     // works only for last (command) line
566     {
567       if ( curLine == endLine && curCol > PROMPT_SIZE-1 ) {
568         if ( ctrlPressed && !hasSelectedText() ) {
569           QString txt = text( curLine );
570           int ind = curCol;
571           while ( ind < txt.length()-1 && txt[ ind ] == ' ' ) ind++;
572           ind = txt.find( ' ', ind );
573           while ( ind < txt.length()-1 && txt[ ind ] == ' ' ) ind++;
574           if ( ind > PROMPT_SIZE-1 ) {
575             setSelection( curLine, curCol, curLine, ind );
576             removeSelectedText();
577           }
578           else {
579             QTextEdit::keyPressEvent( e );
580           }
581         }
582         else {
583           QTextEdit::keyPressEvent( e );
584         }
585       }
586       break;
587     }
588   case Key_Insert :
589     // <Insert> key: process as follows
590     // - with <Ctrl> modifier key pressed:  copy()
591     // - with <Shift> modifier key pressed: paste() to the command line
592     {
593       if ( ctrlPressed ) {
594         copy();
595       }
596       else if ( shftPressed ) {
597         if ( curLine != endLine || curCol < PROMPT_SIZE )
598           moveCursor( QTextEdit::MoveEnd, false );
599         paste();
600       }
601       else
602         QTextEdit::keyPressEvent( e );
603       break;
604     }
605   }
606 }
607
608 /*!
609     Handles notifications coming from Python dispatcher
610 */
611 void PythonConsole_PyEditor::customEvent(QCustomEvent* e)
612 {
613   switch( e->type() ) {
614   case PyInterp_Event::OK:
615   case PyInterp_Event::ERROR:
616     {
617       PyInterp_Event* pe = dynamic_cast<PyInterp_Event*>( e );
618       if ( pe ){
619         ExecCommand* ec = dynamic_cast<ExecCommand*>( pe->GetRequest() );
620         if ( ec ){
621           // The next line has appeared dangerous in case if
622           // Python command execution has produced very large output.
623           // A more clever approach is needed...
624           setText(ec->myOutput);
625           setText(ec->myError);
626         }
627       }
628       _buf.truncate(0);
629       _currentPrompt = READY_PROMPT;
630       setText(_currentPrompt);
631       viewport()->unsetCursor();
632       break;
633     }
634   case PyInterp_Event::INCOMPLETE:
635     {
636       _buf.append("\n");
637       _currentPrompt = DOTS_PROMPT;
638       setText(_currentPrompt);
639       viewport()->unsetCursor();
640       break;
641     }
642   default:
643     QTextEdit::customEvent( e );
644   }
645
646   setReadOnly( false );
647   _isInHistory = false;
648 }
649
650 /*!
651    Handles Python interpreter change
652 */
653 void PythonConsole_PyEditor::onPyInterpChanged( PyInterp_base* interp )
654 {
655   if ( myInterp != interp 
656        // Force read-only state and wait cursor when myInterp is NULL
657       || !myInterp ){
658     myInterp = interp;
659     if ( myInterp ){
660       myBanner = myInterp->getbanner().c_str();
661       setText(myBanner);
662       _buf.truncate(0);
663       setReadOnly( false );
664       _isInHistory = false;
665       setText(_currentPrompt);
666       viewport()->unsetCursor();
667     }
668     else {
669       clear();
670       setReadOnly( true );
671       viewport()->setCursor( waitCursor );
672     }
673   }
674 }
675
676 QPopupMenu* PythonConsole_PyEditor::createPopupMenu( const QPoint& pos )
677 {
678   QPopupMenu* popup = QTextEdit::createPopupMenu( pos );
679
680   QValueList<int> ids;
681   for ( int i = 0; popup && i < popup->count(); i++ )
682   {
683     if ( !popup->isItemEnabled( popup->idAt( i ) ) )
684       ids.append( popup->idAt( i ) );
685   }
686
687   for ( QValueList<int>::const_iterator it = ids.begin(); it != ids.end(); ++it )
688     popup->removeItem( *it );
689
690   SUIT_Tools::simplifySeparators( popup );
691
692   return popup;
693 }