From eafed942b4187f551c3bf0fc9039458b83045c6a Mon Sep 17 00:00:00 2001 From: Pritpal Bedi Date: Tue, 24 Jul 2012 06:37:37 +0000 Subject: [PATCH] 2012-07-23 22:41 UTC-0800 Pritpal Bedi (bedipritpal@hotmail.com) * contrib/hbide/edit.prg * contrib/hbide/editor.prg * contrib/hbqt/qtgui/hbqt_hbqplaintextedit.cpp * contrib/hbqt/qtgui/hbqt_hbqplaintextedit.h % An exhaustive commit focused on selctions management, specially column selection. It also fixes the regression injected in last commit where I broke few here-and-theres. The changes are so exhaustive that I lost many to document, but following are the main points you should know: 1. + Tripple click selection of a line. Unlike other editors, HbIDE implements tripple-click like this: double-click selects a word; do-not move the cusor, click once, line is selected. Standard editors measure the time between clicks, HbIDE measure the position of click. This way user is not constrained to quickly inject the third click. However, double-click carries standard behavior. 2. + Shift+TAB now behaves as expected. It removes preceeding . can be configured via . Defaults to 3. 3. + TAB and Shift+TAB are also available in column selection. 4. + Ctrl+Left|Right, TAB/Shift+TAB and Backspace moves the selection cursor without affecting selected rows in column-selection mode when starting and ending columns are the same; which eventually becomes the multiline editing cursor. In practice there are lot many times when moving to another column without leaving the multi-line selection is needed. 5. + Enabled the physical cursor at all times, no matter in which selection mode the cursor is. Earlier it was disabled in column selection mode. 6. + TAB keys management is brought to PRG level instead of C++. This has made it possible to have them working under multi-line block editing mode ( extended column-selection mode). ;; A good amount of efforts have gone in this direction, and as I am into it deep, please forward your suggessions as to how the various behaviors should be. --- harbour/contrib/hbide/edit.prg | 153 ++- harbour/contrib/hbide/editor.prg | 4 +- .../hbqt/qtgui/hbqt_hbqplaintextedit.cpp | 927 +++++++++--------- .../hbqt/qtgui/hbqt_hbqplaintextedit.h | 6 +- 4 files changed, 589 insertions(+), 501 deletions(-) diff --git a/harbour/contrib/hbide/edit.prg b/harbour/contrib/hbide/edit.prg index 5962b4d61e..ff2216d1b0 100644 --- a/harbour/contrib/hbide/edit.prg +++ b/harbour/contrib/hbide/edit.prg @@ -250,6 +250,7 @@ CLASS IdeEdit INHERIT IdeObject METHOD highlightPage() METHOD reformatLine( nPos, nAdded, nDeleted ) + METHOD handleTab( key ) ENDCLASS @@ -560,7 +561,15 @@ METHOD IdeEdit:execKeyEvent( nMode, nEvent, p, p1 ) lCtrl := hb_bitAnd( kbm, Qt_ControlModifier ) == Qt_ControlModifier lShift := hb_bitAnd( kbm, Qt_ShiftModifier ) == Qt_ShiftModifier - IF ::oSC:execKey( Self, key, lAlt, lCtrl, lShift ) + SWITCH key /* On top of any user defined action be executed - QPlainTextEdit's default keys */ + CASE Qt_Key_Tab + CASE Qt_Key_Backtab + p:accept() + ::handleTab( key ) + RETURN .t. + ENDSWITCH + + IF ::oSC:execKey( Self, key, lAlt, lCtrl, lShift ) /* User Defined Actions */ RETURN .f. ENDIF @@ -631,13 +640,10 @@ METHOD IdeEdit:execKeyEvent( nMode, nEvent, p, p1 ) EXIT CASE QEvent_MouseButtonDblClick ::lCopyWhenDblClicked := .t. + ::clickFuncHelp() EXIT CASE 1001 /* Fired from hbqt_hbqplaintextedit.cpp */ SWITCH p - CASE QEvent_MouseButtonDblClick - ::lCopyWhenDblClicked := .f. /* not intuitive */ - ::clickFuncHelp() - EXIT CASE 21000 /* Sends Block Info { t,l,b,r,mode,state } hbGetBlockInfo() */ ::aSelectionInfo := p1 ::oDK:setButtonState( "SelectionMode", ::aSelectionInfo[ 5 ] > 1 ) @@ -977,7 +983,7 @@ METHOD IdeEdit:pasteBlockContents() NEXT EXIT ENDSWITCH - // + qCursor:endEditBlock() ::qEdit:ensureCursorVisible() @@ -985,8 +991,8 @@ METHOD IdeEdit:pasteBlockContents() /*----------------------------------------------------------------------*/ -METHOD IdeEdit:insertBlockContents( oKey ) - LOCAL nT, nL, nB, nR, nW, i, cLine, cKey, qCursor, aCord +METHOD IdeEdit:insertBlockContents( oKey ) /* Only called if block selection is on */ + LOCAL nT, nL, nB, nR, nW, i, cLine, cKey, qCursor, aCord, qCur IF ::lReadOnly RETURN Self @@ -999,6 +1005,7 @@ METHOD IdeEdit:insertBlockContents( oKey ) nW := nR - nL qCursor := ::qEdit:textCursor() + qCur := ::qEdit:textCursor() qCursor:beginEditBlock() IF nW == 0 @@ -1008,19 +1015,17 @@ METHOD IdeEdit:insertBlockContents( oKey ) hbide_qReplaceLine( qCursor, i, cLine ) NEXT - hbide_qPositionCursor( qCursor, nB, nR + 1 ) + hbide_qPositionCursor( qCursor, qCur:blockNumber(), nR + 1 ) ELSE FOR i := nT TO nB cLine := ::getLine( i + 1 ) cLine := pad( substr( cLine, 1, nL ), nL ) + replicate( cKey, nW ) + substr( cLine, nR + 1 ) - hbide_qReplaceLine( qCursor, i, cLine ) NEXT - hbide_qPositionCursor( qCursor, nB, nR ) + hbide_qPositionCursor( qCursor, qCur:blockNumber(), nR ) ENDIF - // - ::qEdit:setCursorWidth( 1 ) + ::qEdit:setTextCursor( qCursor ) qCursor:endEditBlock() @@ -1029,7 +1034,7 @@ METHOD IdeEdit:insertBlockContents( oKey ) /*----------------------------------------------------------------------*/ METHOD IdeEdit:cutBlockContents( k ) - LOCAL nT, nL, nB, nR, i, cLine, qCursor, nSelMode, aCord + LOCAL nT, nL, nB, nR, i, cLine, qCursor, nSelMode, aCord, qCur IF ::lReadOnly RETURN Self @@ -1045,6 +1050,7 @@ METHOD IdeEdit:cutBlockContents( k ) nSelMode := aCord[ 5 ] qCursor := ::qEdit:textCursor() + qCur := ::qEdit:textCursor() qCursor:beginEditBlock() IF k == Qt_Key_Backspace @@ -1054,7 +1060,7 @@ METHOD IdeEdit:cutBlockContents( k ) cLine := pad( substr( cLine, 1, nL - 1 ), nL - 1 ) + substr( cLine, nL + 1 ) hbide_qReplaceLine( qCursor, i, cLine ) NEXT - hbide_qPositionCursor( qCursor, nB, nR - 1 ) + hbide_qPositionCursor( qCursor, qCur:blockNumber(), nR - 1 ) ENDIF ELSE IF k == Qt_Key_Delete .OR. k == Qt_Key_X @@ -1064,8 +1070,8 @@ METHOD IdeEdit:cutBlockContents( k ) cLine := pad( substr( cLine, 1, nL ), nL ) + substr( cLine, nR + 1 ) hbide_qReplaceLine( qCursor, i, cLine ) NEXT - //hbide_qPositionCursor( qCursor, nT, nL ) - ::qEdit:hbSetSelectionInfo( { -1, -1, -1, -1, __selectionMode_column__ } ) + hbide_qPositionCursor( qCursor, qCur:blockNumber(), nL ) + ::qEdit:hbSetSelectionInfo( { nT, nL, nB, nL, __selectionMode_column__ } ) ELSEIF nSelMode == __selectionMode_stream__ hbide_qPositionCursor( qCursor, nT, nL ) @@ -1094,7 +1100,7 @@ METHOD IdeEdit:cutBlockContents( k ) /*----------------------------------------------------------------------*/ -METHOD IdeEdit:blockComment() +METHOD IdeEdit:blockComment() /* Toggles the block comments - always inserted at the begining of the line */ LOCAL nT, nL, nB, nR, nW, i, cLine, qCursor, aCord, nMode, a_ LOCAL cComment := "// " LOCAL nLen := Len( cComment ) @@ -1108,33 +1114,39 @@ METHOD IdeEdit:blockComment() nW := nR - nL IF nW >= 0 - nMode := aCord[ 5 ] - a_:= hbide_setQCursor( ::qEdit ) ; qCursor := a_[ 1 ] + nMode := aCord[ 5 ] + a_:= hbide_setQCursor( ::qEdit ) + qCursor := a_[ 1 ] FOR i := nT TO nB cLine := ::getLine( i + 1 ) - DO CASE - CASE nMode == __selectionMode_stream__ .OR. nMode == __selectionMode_line__ + SWITCH nMode + CASE __selectionMode_stream__ + CASE __selectionMode_line__ IF substr( cLine, 1, nLen ) == cComment cLine := substr( cLine, nLen + 1 ) ELSE cLine := cComment + cLine ENDIF - - CASE nMode == __selectionMode_column__ + EXIT + CASE __selectionMode_column__ IF substr( cLine, nL + 1, nLen ) == cComment cLine := pad( substr( cLine, 1, nL ), nL ) + substr( cLine, nL + nLen + 1 ) ELSE cLine := pad( substr( cLine, 1, nL ), nL ) + cComment + substr( cLine, nL + 1 ) ENDIF - - ENDCASE + EXIT + ENDSWITCH hbide_qReplaceLine( qCursor, i, cLine ) NEXT - +#if 1 hbide_setQCursor( ::qEdit, a_ ) +#else + hbide_qPositionCursor( qCursor, qCur:blockNumber(), nL ) + ::qEdit:hbSetSelectionInfo( { nT, nL, nB, nL, __selectionMode_column__ } ) +#endif ENDIF RETURN Self @@ -1186,6 +1198,62 @@ METHOD IdeEdit:streamComment() /*----------------------------------------------------------------------*/ +METHOD IdeEdit:handleTab( key ) + LOCAL nT, nL, nB, nR, i, cLine, qCursor, aCord, nMode, nCol, nRow + LOCAL cComment := space( ::nTabSpaces ) + LOCAL nLen := ::nTabSpaces + LOCAL nOff := iif( key == Qt_Key_Tab, nLen, -nLen ) + + HB_SYMBOL_UNUSED( key ) + IF ::lReadOnly + RETURN Self + ENDIF + + aCord := ::aSelectionInfo + hbide_normalizeRect( aCord, @nT, @nL, @nB, @nR ) + nMode := aCord[ 5 ] + + qCursor := ::qEdit:textCursor() + qCursor:beginEditBlock() + nCol := qCursor:columnNumber() + nRow := qCursor:blockNumber() + + SWITCH nMode + CASE __selectionMode_column__ + FOR i := nT TO nB + cLine := ::getLine( i + 1 ) + IF key == Qt_Key_Tab + cLine := substr( cLine, 1, nCol ) + cComment + substr( cLine, nCol + 1 ) + ELSE + cLine := substr( cLine, 1, nCol - 3 ) + substr( cLine, nCol + 1 ) + ENDIF + hbide_qReplaceLine( qCursor, i, cLine ) + NEXT + hbide_qPositionCursor( qCursor, nRow, max( 0, nCol + nOff ) ) + ::qEdit:hbSetSelectionInfo( { nT, max( 0, nL + nOff ), nB, max( 0, nR + nOff ), __selectionMode_column__ } ) + EXIT + CASE __selectionMode_stream__ + CASE __selectionMode_line__ + IF nL >= 0 /* Selection is marked */ + ::cutBlockContents( Qt_Key_Delete ) + ENDIF + cLine := ::getLine( nRow + 1 ) + IF key == Qt_Key_Tab + cLine := substr( cLine, 1, nCol ) + cComment + substr( cLine, nCol + 1 ) + ELSE + cLine := substr( cLine, 1, nCol - nLen ) + substr( cLine, nCol + 1 ) + ENDIF + hbide_qReplaceLine( qCursor, nRow, cLine ) + hbide_qPositionCursor( qCursor, nRow, max( 0, nCol + nOff ) ) + EXIT + ENDSWITCH + ::qEdit:setTextCursor( qCursor ) + qCursor:endEditBlock() + + RETURN .t. + +/*----------------------------------------------------------------------*/ + METHOD IdeEdit:blockIndent( nDirctn ) LOCAL nT, nL, nB, nR, nW, i, cLine, qCursor, aCord, a_, nMode, cLineSel @@ -1199,22 +1267,14 @@ METHOD IdeEdit:blockIndent( nDirctn ) IF nW >= 0 nMode := aCord[ 5 ] - a_:= hbide_setQCursor( ::qEdit ) ; qCursor := a_[ 1 ] + a_:= hbide_setQCursor( ::qEdit ) + qCursor := a_[ 1 ] FOR i := nT TO nB cLine := ::getLine( i + 1 ) - DO CASE - CASE nMode == __selectionMode_stream__ .OR. nMode == __selectionMode_line__ - IF nDirctn == -1 - IF left( cLine, 1 ) == " " - cLine := substr( cLine, 2 ) - ENDIF - ELSE - cLine := " " + cLine - ENDIF - - CASE nMode == __selectionMode_column__ + SWITCH nMode + CASE __selectionMode_column__ cLineSel := pad( substr( cLine, nL + 1, nW ), nW ) IF nDirctn == -1 IF left( cLineSel, 1 ) == " " @@ -1224,8 +1284,18 @@ METHOD IdeEdit:blockIndent( nDirctn ) cLineSel := " " + cLineSel ENDIF cLine := pad( substr( cLine, 1, nL ), nL ) + cLineSel + substr( cLine, nR + 1 ) - - ENDCASE + EXIT + CASE __selectionMode_stream__ + CASE __selectionMode_line__ + IF nDirctn == -1 + IF left( cLine, 1 ) == " " + cLine := substr( cLine, 2 ) + ENDIF + ELSE + cLine := " " + cLine + ENDIF + EXIT + ENDSWITCH hbide_qReplaceLine( qCursor, i, cLine ) NEXT @@ -2759,3 +2829,4 @@ STATIC FUNCTION hbide_normalizeRect( aCord, nT, nL, nB, nR ) RETURN NIL /*----------------------------------------------------------------------*/ + diff --git a/harbour/contrib/hbide/editor.prg b/harbour/contrib/hbide/editor.prg index 8e11314f2b..6b1367668c 100644 --- a/harbour/contrib/hbide/editor.prg +++ b/harbour/contrib/hbide/editor.prg @@ -300,6 +300,7 @@ METHOD IdeEditsManager:updateFieldsList( cAlias ) LOCAL aFlds IF ! empty( cAlias ) .AND. ! empty( aFlds := ::oBM:fetchFldsList( cAlias ) ) + asort( aFlds, , , {|e,f| lower( e ) < lower( f ) } ) ::qFldsStrList:clear() @@ -307,8 +308,8 @@ METHOD IdeEditsManager:updateFieldsList( cAlias ) ::qFldsModel:setStringList( ::qFldsStrList ) ::qCompleter:setModel( ::qFldsModel ) - RETURN .t. + RETURN .t. ELSE ::qCompleter:setModel( ::qCompModel ) @@ -2040,3 +2041,4 @@ STATIC FUNCTION hbide_qtDesigner() RETURN NIL /*----------------------------------------------------------------------*/ + diff --git a/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.cpp b/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.cpp index cbfc22e033..71c2e0ba14 100644 --- a/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.cpp +++ b/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.cpp @@ -80,9 +80,6 @@ HB_EXTERN_END #include -#define selectionState_off 0 -#define selectionState_on 1 - #define selectionMode_none 0 #define selectionMode_stream 1 #define selectionMode_column 2 @@ -92,6 +89,10 @@ HB_EXTERN_END #define selectionDisplay_qt 1 #define selectionDisplay_ide 2 +#define mouseMode_none 0 +#define mouseMode_select 1 +#define mouseMode_drag 2 + /*----------------------------------------------------------------------*/ HBQPlainTextEdit::HBQPlainTextEdit( QWidget * parent ) : QPlainTextEdit( parent ) @@ -111,7 +112,6 @@ HBQPlainTextEdit::HBQPlainTextEdit( QWidget * parent ) : QPlainTextEdit( parent columnEnds = -1; rowBegins = -1; rowEnds = -1; - selectionState = selectionState_off; selectionMode = selectionMode_stream; selectionDisplay = selectionDisplay_none; isColumnSelectionON = false; @@ -130,6 +130,9 @@ HBQPlainTextEdit::HBQPlainTextEdit( QWidget * parent ) : QPlainTextEdit( parent isCompletionTipsActive = true; isInDrag = false; dragStartPosition = QPoint(); + clickPos = QPoint(); + iClicks = 0; + mouseMode = mouseMode_none; #if 0 QTextFrameFormat format( this->document()->rootFrame()->frameFormat() ); @@ -307,7 +310,6 @@ void HBQPlainTextEdit::hbSetEventBlock( PHB_ITEM pBlock ) if( pBlock ) { block = hb_itemNew( pBlock ); - // hb_gcUnlock( block ); } } @@ -340,28 +342,7 @@ void HBQPlainTextEdit::hbSetProtoStyle( const QString & css ) bool HBQPlainTextEdit::event( QEvent *event ) { - if( event->type() == QEvent::KeyPress ) - { - QKeyEvent *keyEvent = ( QKeyEvent * ) event; - if( ( keyEvent->key() == Qt::Key_Tab ) && ( keyEvent->modifiers() & Qt::ControlModifier ) ) - { - return false; - } - else - { - if( ( keyEvent->key() == Qt::Key_Tab ) && !( keyEvent->modifiers() & Qt::ControlModifier & Qt::AltModifier & Qt::ShiftModifier ) ) - { - this->hbInsertTab( 0 ); - return true; - } - else if( ( keyEvent->key() == Qt::Key_Backtab ) && ( keyEvent->modifiers() & Qt::ShiftModifier ) ) - { - this->hbInsertTab( 1 ); - return true; - } - } - } - else if( event->type() == QEvent::ToolTip ) + if( event->type() == QEvent::ToolTip ) { event->ignore(); #if 0 @@ -374,7 +355,6 @@ bool HBQPlainTextEdit::event( QEvent *event ) #endif return false;//true; } - return QPlainTextEdit::event( event ); } @@ -434,7 +414,27 @@ bool HBQPlainTextEdit::isCursorInSelection() int col = c.columnNumber(); int row = c.blockNumber(); - return( col >= cb && col <= ce && row >= rb && row <= re ); + if( selectionMode == selectionMode_column ) + { + HB_TRACE( HB_TR_DEBUG, ( "isCursorInSelection( Modif %i %i %i %i RC %i %i Cur %i %i", rb, cb, re, ce, rowBegins, columnBegins, row, col ) ); + return( col >= cb && col <= ce && row >= rb && row <= re ); + } + else + { + if( row == rb ) + { + return( col >= cb ); + } + else if( row == re ) + { + return( col <= ce ); + } + else if( row >= rb && row <= re ) + { + return( true ); + } + } + return( false ); } /*----------------------------------------------------------------------*/ @@ -453,7 +453,7 @@ void HBQPlainTextEdit::hbPostSelectionInfo() hb_arraySetNI( p2, 3, rowEnds ); hb_arraySetNI( p2, 4, columnEnds ); hb_arraySetNI( p2, 5, selectionMode ); - hb_arraySetNI( p2, 6, selectionState ); + hb_arraySetNI( p2, 6, 0 ); hb_arraySetNI( p2, 7, 0 ); hb_vmEvalBlockV( block, 2, p1, p2 ); @@ -467,7 +467,6 @@ void HBQPlainTextEdit::hbPostSelectionInfo() void HBQPlainTextEdit::hbClearSelection() { - setCursorWidth( 1 ); rowBegins = -1; rowEnds = -1; columnBegins = -1; @@ -479,7 +478,6 @@ void HBQPlainTextEdit::hbClearSelection() void HBQPlainTextEdit::hbSelectAll() { - setCursorWidth( 1 ); rowBegins = 0; rowEnds = document()->blockCount(); columnBegins = 0; @@ -536,7 +534,6 @@ void HBQPlainTextEdit::hbSetSelectionMode( int mode, bool byApplication ) } setTextCursor( c ); } - setCursorWidth( 1 ); } else { @@ -544,7 +541,6 @@ void HBQPlainTextEdit::hbSetSelectionMode( int mode, bool byApplication ) { case selectionMode_stream: { - setCursorWidth( 1 ); selectionMode = selectionMode_stream; isStreamSelectionON = true; isColumnSelectionON = false; @@ -560,8 +556,6 @@ void HBQPlainTextEdit::hbSetSelectionMode( int mode, bool byApplication ) } case selectionMode_column: { - setCursorWidth( 0 ); - selectionMode = selectionMode_column; isStreamSelectionON = false; isColumnSelectionON = true; @@ -578,7 +572,6 @@ void HBQPlainTextEdit::hbSetSelectionMode( int mode, bool byApplication ) } case selectionMode_line: { - setCursorWidth( 1 ); selectionMode = selectionMode_line; isStreamSelectionON = false; isColumnSelectionON = false; @@ -603,7 +596,6 @@ void HBQPlainTextEdit::hbSetSelectionMode( int mode, bool byApplication ) { case selectionMode_stream: { - setCursorWidth( 1 ); if( columnBegins >= 0 ) { hbToStream(); @@ -615,7 +607,6 @@ void HBQPlainTextEdit::hbSetSelectionMode( int mode, bool byApplication ) } case selectionMode_column: { - setCursorWidth( 0 ); selectionMode = selectionMode_column; isColumnSelectionON = true; isLineSelectionON = false; @@ -768,13 +759,16 @@ void HBQPlainTextEdit::dropEvent( QDropEvent *event ) if( ( selectionMode == selectionMode_stream || selectionMode == selectionMode_line ) && row >= rowBegins && row <= rowEnds ) { setTextCursor( c ); + mouseMode = mouseMode_select; } else if( selectionMode == selectionMode_column && row >= rowBegins && row <= rowEnds && col >= columnBegins && col <= columnEnds ) { setTextCursor( c ); + mouseMode = mouseMode_select; } else { + mouseMode = mouseMode_none; hbCopy(); if( event->dropAction() != Qt::CopyAction ) { @@ -818,7 +812,6 @@ void HBQPlainTextEdit::dropEvent( QDropEvent *event ) { setTextCursor( c ); } - selectionState = 0; hbClearSelection(); hbPaste(); hbPostSelectionInfo(); @@ -887,79 +880,27 @@ void HBQPlainTextEdit::mouseDoubleClickEvent( QMouseEvent *event ) QTextCursor c( textCursor() ); if( c.hasSelection() ) { - rowBegins = c.blockNumber(); - rowEnds = rowBegins; - columnEnds = c.columnNumber(); - columnBegins = columnEnds - ( c.selectionEnd() - c.selectionStart() ); - selectionMode = selectionMode_stream; + rowBegins = c.blockNumber(); + rowEnds = rowBegins; + columnEnds = c.columnNumber(); + columnBegins = columnEnds - ( c.selectionEnd() - c.selectionStart() ); + selectionMode = selectionMode_stream; + mouseMode = mouseMode_select; c.clearSelection(); setTextCursor( c ); hbPostSelectionInfo(); + clickPos = event->pos(); + iClicks = 2; + repaint(); } - +#if 0 if( block ) { PHB_ITEM p1 = hb_itemPutNI( NULL, QEvent::MouseButtonDblClick ); hb_vmEvalBlockV( block, 1, p1 ); hb_itemRelease( p1 ); } -} - -/*----------------------------------------------------------------------*/ - -void HBQPlainTextEdit::mousePressEvent( QMouseEvent *event ) -{ - if( isSelectionByApplication ) - { - if( isColumnSelectionON ) - { - event->accept(); - } - else - { - QPlainTextEdit::mousePressEvent( event ); - } - return; - } - - if( event->modifiers() & Qt::ShiftModifier ) - { - QTextCursor c( textCursor() ); - rowBegins = c.blockNumber(); - columnBegins = c.columnNumber(); - - QPlainTextEdit::mousePressEvent( event ); - - c = textCursor(); - rowEnds = c.blockNumber(); - columnEnds = c.columnNumber(); - - selectionState = 1; - setCursorWidth( 1 ); - selectionMode = selectionMode_stream; - hbPostSelectionInfo(); - repaint(); - } - else - { - if( event->buttons() & Qt::LeftButton ) - { - setCursorWidth( 1 ); - - QTextCursor c( cursorForPosition( event->pos() ) ); - int row = c.blockNumber(); - int col = c.columnNumber(); - if( ( selectionMode == selectionMode_stream || selectionMode == selectionMode_line ) && row >= rowBegins && row <= rowEnds ) - { - dragStartPosition = event->pos(); - } - else if( selectionMode == selectionMode_column && row >= rowBegins && row <= rowEnds && col >= columnBegins && col <= columnEnds ) - { - dragStartPosition = event->pos(); - } - } - QPlainTextEdit::mousePressEvent( event ); - } +#endif } /*----------------------------------------------------------------------*/ @@ -990,21 +931,85 @@ void HBQPlainTextEdit::mouseReleaseEvent( QMouseEvent *event ) } else { - if( selectionState == 1 ) + QPlainTextEdit::mouseReleaseEvent( event ); + } +} + +/*----------------------------------------------------------------------*/ + +void HBQPlainTextEdit::mousePressEvent( QMouseEvent *event ) +{ + if( isSelectionByApplication ) + { + if( isColumnSelectionON ) { - selectionState = 0; - if( ! isSelectionPersistent ) - { - hbClearSelection(); - repaint(); - } + event->accept(); } else { - selectionState = 1; + QPlainTextEdit::mousePressEvent( event ); } - setCursorWidth( 1 ); + return; + } + else if( event->modifiers() & Qt::ShiftModifier ) + { + QTextCursor c( textCursor() ); + rowBegins = c.blockNumber(); + columnBegins = c.columnNumber(); + + QPlainTextEdit::mousePressEvent( event ); + + c = textCursor(); + rowEnds = c.blockNumber(); + columnEnds = c.columnNumber(); + c.clearSelection(); + setTextCursor( c ); + selectionMode = selectionMode_stream; hbPostSelectionInfo(); + repaint(); + } + else + { + if( event->buttons() & Qt::LeftButton ) + { + QTextCursor c( cursorForPosition( event->pos() ) ); + + if( iClicks == 2 ) /* Handle Tripple-click */ + { + iClicks = 0; + if( ( event->pos() - clickPos ).manhattanLength() < QApplication::startDragDistance() ) + { + selectionMode = selectionMode_stream; + c.movePosition( QTextCursor::EndOfLine ); + columnBegins = 0; + columnEnds = c.columnNumber(); + hbPostSelectionInfo(); + setTextCursor( c ); + event->accept(); + repaint(); + } + else + { + QPlainTextEdit::mousePressEvent( event ); + hbClearSelection(); + } + } + else + { + QPlainTextEdit::mousePressEvent( event ); + dragStartPosition = event->pos(); + if( mouseMode == mouseMode_select && isCursorInSelection() ) + { + mouseMode = mouseMode_drag; + } + else + { + mouseMode = mouseMode_none; + hbClearSelection(); + repaint(); + } + } + } } } @@ -1025,7 +1030,7 @@ void HBQPlainTextEdit::mouseMoveEvent( QMouseEvent *event ) } if( event->buttons() & Qt::LeftButton ) { - if( ( event->pos() - dragStartPosition ).manhattanLength() < QApplication::startDragDistance() ) + if( mouseMode == mouseMode_drag && ( event->pos() - dragStartPosition ).manhattanLength() < QApplication::startDragDistance() ) { QTextCursor c( cursorForPosition( event->pos() ) ); int row = c.blockNumber(); @@ -1052,26 +1057,17 @@ void HBQPlainTextEdit::mouseMoveEvent( QMouseEvent *event ) } } - if( selectionState == 1 ) - { - selectionState = 2; - hbClearSelection(); - } - if( columnBegins == -1 ) { - if( selectionMode == selectionMode_column ) - setCursorWidth( 0 ); - QTextCursor c( textCursor() ); - rowBegins = c.blockNumber(); columnBegins = c.columnNumber(); rowEnds = rowBegins; columnEnds = columnBegins; + mouseMode = mouseMode_select; QPlainTextEdit::mouseMoveEvent( event ); } - else + else if( mouseMode == mouseMode_select ) { if( selectionMode == selectionMode_column ) { @@ -1081,7 +1077,6 @@ void HBQPlainTextEdit::mouseMoveEvent( QMouseEvent *event ) } QPlainTextEdit::mouseMoveEvent( event ); QTextCursor c = textCursor(); - if( selectionMode != selectionMode_column ) { rowEnds = c.blockNumber(); @@ -1089,7 +1084,6 @@ void HBQPlainTextEdit::mouseMoveEvent( QMouseEvent *event ) } c.clearSelection(); setTextCursor( c ); -// repaint(); /* NOT REQUIRED : QPlainTextEdit::mouseMoveEvent( event ); */ } hbPostSelectionInfo(); } @@ -1103,16 +1097,334 @@ void HBQPlainTextEdit::keyReleaseEvent( QKeyEvent * event ) if( ( event->modifiers() & Qt::ControlModifier ) && event->text() == "" ) { - if( selectionState == 2 ) + hbPostSelectionInfo(); + } +} + +/*----------------------------------------------------------------------*/ + +void HBQPlainTextEdit::hbHandleKey( QKeyEvent * event, int k, int selMode, bool shift ) +{ + Q_UNUSED( selMode ); + Q_UNUSED( shift ); + + switch( k ) + { + case Qt::Key_Right: { - selectionState = 1; - emit selectionChanged(); + event->ignore(); + QTextCursor c( textCursor() ); + QTextCursor cc( textCursor() ); + cc.movePosition( QTextCursor::EndOfLine ); + if( columnEnds < cc.columnNumber() ) + { + c.movePosition( QTextCursor::Right ); + setTextCursor( c ); + } + columnEnds++; + break; + } + case Qt::Key_Left: + { + event->ignore(); + QTextCursor c( textCursor() ); + if( columnEnds >= 0 ) + { + if( columnEnds <= c.columnNumber() ) + { + c.movePosition( QTextCursor::Left ); + setTextCursor( c ); + } + columnEnds--; + } + break; + } + case Qt::Key_Home: + case Qt::Key_End: + { + QPlainTextEdit::keyPressEvent( event ); + columnEnds = textCursor().columnNumber(); + break; + } + case Qt::Key_Up: + case Qt::Key_PageUp: + case Qt::Key_Down: + case Qt::Key_PageDown: + { + QPlainTextEdit::keyPressEvent( event ); + rowEnds = textCursor().blockNumber(); + break; } } } /*----------------------------------------------------------------------*/ +bool HBQPlainTextEdit::hbKeyPressSelection( QKeyEvent * event ) +{ + int k; + bool ctrl, shift, isNavable; + + if( isSelectionByApplication ) + { + return hbKeyPressSelectionByApplication( event ); + } + k = event->key(); + ctrl = event->modifiers() & Qt::ControlModifier; + shift = event->modifiers() & Qt::ShiftModifier; + isNavable = isNavableKey( k ); + + if( ctrl && shift && ! isNavable ) + { + return false; + } + if( ctrl && event->text().isEmpty() && ! isNavable ) + { + return false; + } + if( ctrl && ( k == Qt::Key_C || k == Qt::Key_V || k == Qt::Key_X || + k == Qt::Key_A || k == Qt::Key_Z || k == Qt::Key_Y ) ) + { + event->ignore(); + return true; + } + + bool bClear = false; + + if( shift && isNavable ) + { + if( selectionMode == selectionMode_line ) + { + selectionMode = selectionMode_stream; + hbPostSelectionInfo(); + } + + isShiftPressed = true; + + event->accept(); + QTextCursor c( textCursor() ); + c.clearSelection(); + setTextCursor( c ); + + if( columnBegins == -1 || columnEnds == -1 || rowBegins == -1 || rowEnds == -1 ) + { + rowBegins = c.blockNumber(); + columnBegins = c.columnNumber(); + rowEnds = rowBegins; + columnEnds = columnBegins; + hbPostSelectionInfo(); + } + + /* Push key back to system without the shift modifier - it will position position the cursor as intended */ + QKeyEvent * ev = new QKeyEvent( event->type(), event->key(), ctrl ? Qt::ControlModifier : Qt::NoModifier, event->text() ); + keyPressEvent( ev ); + return true; + } + + if( isShiftPressed && isNavable ) + { + isShiftPressed = false; + + if( selectionMode == selectionMode_stream ) + { + QPlainTextEdit::keyPressEvent( event ); + rowEnds = textCursor().blockNumber(); + columnEnds = textCursor().columnNumber(); + } + else if( selectionMode == selectionMode_column ) + { + hbHandleKey( event, k, selectionMode_column, true ); + } + hbPostSelectionInfo(); + repaint(); /* A Must Here , otherwise selection will not be reflected */ + return true; + } + else if( ctrl && isNavable && selectionMode == selectionMode_column && columnBegins >= 0 && columnBegins == columnEnds ) + { + hbHandleKey( event, k, selectionMode_column, false ); + columnBegins = columnEnds; + hbPostSelectionInfo(); + repaint(); + return true; + } + else if( ! ctrl && k >= ' ' && k < 127 && columnBegins >= 0 && selectionMode == selectionMode_column ) + { + if( isCursorInSelection() ) + { + if( block ) + { + PHB_ITEM p1 = hb_itemPutNI( NULL, 21013 ); + PHB_ITEM p2 = hbqt_bindGetHbObject( NULL, ( void * ) event, "HB_QKEYEVENT", NULL, 0 ) ; + hb_vmEvalBlockV( block, 2, p1, p2 ); + hb_itemRelease( p1 ); + hb_itemRelease( p2 ); + + if( columnBegins == columnEnds ) + { + columnBegins++; + columnEnds++; + hbPostSelectionInfo(); + } + event->accept(); + repaint(); + return true; + } + } + else + { + bClear = true; + } + } + else if( ! ctrl && ( k == Qt::Key_Backspace || k == Qt::Key_Delete ) && columnBegins >= 0 ) + { + if( selectionMode == selectionMode_column ) + { + hbCut( k ); + if( k == Qt::Key_Backspace ) + { + columnBegins--; + columnEnds--; + } + else + { + columnEnds = columnBegins; + } + event->accept(); + hbPostSelectionInfo(); + repaint(); + return true; + } + else /* selectionMode == selectionMode_stream || selectionMode == selectionMode_line */ + { + hbCut( Qt::Key_Delete ); + repaint(); + hbPostSelectionInfo(); + if( k == Qt::Key_Delete ) + { + event->accept(); + return true; + } + } + } + else if( ! ctrl && k >= ' ' && k < 127 && columnBegins >= 0 && selectionMode == selectionMode_stream ) + { + hbCut( Qt::Key_Delete ); + hbClearSelection(); + } + else if( ! ctrl && k >= ' ' && k < 127 ) + { + bClear = true; + } + else if( isNavable ) + { + bClear = true; + } + + if( bClear ) + { + if( isSelectionPersistent ) + { + if( columnBegins >= 0 ) + { + if( columnEnds == columnBegins ) + { + hbClearSelection(); + } + hbPostSelectionInfo(); + } + } + else + { + if( columnBegins >= 0 ) + { + hbClearSelection(); + hbPostSelectionInfo(); + repaint(); + } + } + } + return false; +} + +/*----------------------------------------------------------------------*/ + +void HBQPlainTextEdit::keyPressEvent( QKeyEvent * event ) +{ + if( hbHandlePopup( event ) ) + { + return; + } + if( hbKeyPressSelection( event ) ) + { + return; + } + + QPlainTextEdit::keyPressEvent( event ); + + if( ! isCodeCompletionActive ) + { + if( c ){ + c->popup()->hide(); + } + return; + } + + if( ! c ) + { + return; + } + if( isTipActive ) + { + c->popup()->hide(); + return; + } + + if( ! isAliasCompleter ) + { + hbRefreshCompleter( hbTextAlias() ); + } + + if( ( event->modifiers() & ( Qt::ControlModifier | Qt::AltModifier ) ) ) + { + c->popup()->hide(); + return; + } + const bool ctrlOrShift = event->modifiers() & ( Qt::ControlModifier | Qt::ShiftModifier ); + if( ctrlOrShift && event->text().isEmpty() ) + { + return; + } + static QString eow( " ~!@#$%^&*()+{}|:\"<>?,./;'[]\\-=" ); /* end of word */ + bool hasModifier = ( event->modifiers() != Qt::NoModifier ) && !ctrlOrShift; + QString completionPrefix = hbTextUnderCursor( true ); + /*QString completionPrefix = hbTextUnderCursor( false );*/ + + if( hasModifier || + event->text().isEmpty() || + completionPrefix.length() < ( isAliasCompleter ? 0 : 1 ) || + eow.contains( event->text().right( 1 ) ) ) + { + c->popup()->hide(); + return; + } + + if( completionPrefix != c->completionPrefix() ) + { + c->setCompletionPrefix( completionPrefix ); + c->popup()->setCurrentIndex( c->completionModel()->index( 0, 0 ) ); + } + QRect cr = cursorRect(); + + c->popup()->setMaximumWidth( viewport()->width() ); + cr.setWidth( c->popup()->sizeHintForColumn( 0 ) + c->popup()->verticalScrollBar()->sizeHint().width() ); + cr.setTop( cr.top() + horzRulerHeight + 5 ); + cr.setBottom( cr.bottom() + horzRulerHeight + 5 ); + + c->complete( cr ); /* pop it up! */ +} + +/*----------------------------------------------------------------------*/ + bool HBQPlainTextEdit::hbKeyPressSelectionByApplication( QKeyEvent * event ) { bool shift = event->modifiers() & Qt::ShiftModifier; @@ -1208,343 +1520,42 @@ bool HBQPlainTextEdit::hbKeyPressSelectionByApplication( QKeyEvent * event ) /*----------------------------------------------------------------------*/ -bool HBQPlainTextEdit::hbKeyPressSelection( QKeyEvent * event ) -{ - int k; - bool ctrl, shift, isNavable; - - if( isSelectionByApplication ) { - return hbKeyPressSelectionByApplication( event ); - } - - k = event->key(); - ctrl = event->modifiers() & Qt::ControlModifier; - shift = event->modifiers() & Qt::ShiftModifier; - isNavable = isNavableKey( k ); - - if( ctrl && shift && ! isNavable ) { - return false; - } - if( ctrl && event->text().isEmpty() && ! isNavable ) { - return false; - } - if( ctrl && ( k == Qt::Key_C || k == Qt::Key_V || k == Qt::Key_X || - k == Qt::Key_A || k == Qt::Key_Z || k == Qt::Key_Y ) ) { - event->ignore(); - return true; - } - - bool bClear = false; - - if( shift && isNavable ) - { - if( selectionMode == selectionMode_line ) - { - selectionMode = selectionMode_stream; - selectionState = 0; - hbPostSelectionInfo(); - } - if( selectionState == 0 ) - { - hbClearSelection(); - } - - isShiftPressed = true; - - event->accept(); - QTextCursor c( textCursor() ); - c.clearSelection(); - setTextCursor( c ); - - if( columnBegins == -1 ) - { - if( selectionMode == selectionMode_column ) - { - setCursorWidth( 0 ); - } - selectionState = 2; - rowBegins = c.blockNumber(); - columnBegins = c.columnNumber(); - rowEnds = rowBegins; - columnEnds = columnBegins; - hbPostSelectionInfo(); - } - - QKeyEvent * ev = new QKeyEvent( event->type(), event->key(), ctrl ? Qt::ControlModifier : Qt::NoModifier, event->text() ); - keyPressEvent( ev ); - return true; - } - - if( isShiftPressed && isNavable ) - { - isShiftPressed = false; - - if( selectionMode == selectionMode_stream ) - { - QPlainTextEdit::keyPressEvent( event ); - rowEnds = textCursor().blockNumber(); - columnEnds = textCursor().columnNumber(); - } - else if( selectionMode == selectionMode_column ) - { - switch( k ) - { - case Qt::Key_Right: - { - QTextCursor c( textCursor() ); - c.movePosition( QTextCursor::EndOfLine ); - if( columnEnds < c.columnNumber() ) - { - QPlainTextEdit::keyPressEvent( event ); - ensureCursorVisible(); - } - else - { - event->ignore(); - } - columnEnds++; - break; - } - case Qt::Key_Left: - { - QTextCursor c( textCursor() ); - int col = c.columnNumber(); - if( col > 0 ) - { - QPlainTextEdit::keyPressEvent( event ); - columnEnds--; - } - else - { - event->ignore(); - } - break; - } - case Qt::Key_Home: - case Qt::Key_End: - { - QPlainTextEdit::keyPressEvent( event ); - columnEnds = textCursor().columnNumber(); - break; - } - case Qt::Key_Up: - case Qt::Key_PageUp: - case Qt::Key_Down: - case Qt::Key_PageDown: - { - QPlainTextEdit::keyPressEvent( event ); - rowEnds = textCursor().blockNumber(); - break; - } - } - } - hbPostSelectionInfo(); - repaint(); /* A Must Here , otherwise selection will not be reflected */ - return true; - } - else if( ! ctrl && k >= ' ' && k < 127 && columnBegins >= 0 && selectionMode == selectionMode_column ) - { - if( ( columnBegins == columnEnds && selectionState > 0 ) || isCursorInSelection() ) - { - if( block ) - { - PHB_ITEM p1 = hb_itemPutNI( NULL, 21013 ); - PHB_ITEM p2 = hbqt_bindGetHbObject( NULL, ( void * ) event, "HB_QKEYEVENT", NULL, 0 ) ; - hb_vmEvalBlockV( block, 2, p1, p2 ); - hb_itemRelease( p1 ); - hb_itemRelease( p2 ); - - if( columnBegins == columnEnds ) - { - columnBegins++; - columnEnds++; - hbPostSelectionInfo(); - } - event->accept(); - repaint(); - return true; - } - } - else - { - bClear = true; - } - } - else if( ! ctrl && ( k == Qt::Key_Backspace || k == Qt::Key_Delete ) && columnBegins >= 0 && selectionState > 0 ) - { - if( selectionMode == selectionMode_column ) - { - hbCut( k ); - if( k == Qt::Key_Backspace ) - { - columnBegins--; - columnEnds--; - } - else - { - columnEnds = columnBegins; - } - hbPostSelectionInfo(); - event->accept(); - repaint(); - return true; - } - else /* selectionMode == selectionMode_stream || selectionMode == selectionMode_line */ - { - hbCut( Qt::Key_Delete ); - repaint(); - selectionState = 0; - hbPostSelectionInfo(); - if( k == Qt::Key_Delete ) - { - event->accept(); - return true; - } - } - } - else if( ! ctrl && k >= ' ' && k < 127 && columnBegins >= 0 && selectionMode == selectionMode_stream ) - { - hbCut( Qt::Key_Delete ); - hbClearSelection(); - selectionState = 0; - } - else if( ! ctrl && k >= ' ' && k < 127 ) - { - bClear = true; - } - else if( isNavable ) - { - bClear = true; - } - - if( bClear ) - { - if( isSelectionPersistent ) - { - if( selectionState > 0 ) - { - setCursorWidth( 1 ); - selectionState = 0; - if( columnEnds == columnBegins ) - { - hbClearSelection(); - } - hbPostSelectionInfo(); - } - } - else - { - if( selectionState > 0 ) - { - setCursorWidth( 1 ); - selectionState = 0; - hbClearSelection(); - hbPostSelectionInfo(); - repaint(); - } - } - } - return false; -} - -/*----------------------------------------------------------------------*/ - -void HBQPlainTextEdit::keyPressEvent( QKeyEvent * event ) +bool HBQPlainTextEdit::hbHandlePopup( QKeyEvent * event ) { if( c && c->popup()->isVisible() ) { /* The following keys are forwarded by the completer to the widget */ switch( event->key() ) { - case Qt::Key_Enter : - case Qt::Key_Return : - case Qt::Key_Escape : - case Qt::Key_Tab : - case Qt::Key_Backtab : - event->ignore(); - return; /* let the completer do default behavior */ - case Qt::Key_Space: - if( block ) - { - PHB_ITEM p1 = hb_itemPutNI( NULL, 21001 ); - hb_vmEvalBlockV( block, 1, p1 ); - hb_itemRelease( p1 ); - hbRefreshCompleter(); /* Watch closely */ - } - break; - case Qt::Key_ParenLeft: - if( block ) - { - PHB_ITEM p1 = hb_itemPutNI( NULL, 21002 ); - hb_vmEvalBlockV( block, 1, p1 ); - hb_itemRelease( p1 ); - } - break; - default: - break; + case Qt::Key_Enter : + case Qt::Key_Return : + case Qt::Key_Escape : + case Qt::Key_Tab : + case Qt::Key_Backtab : + event->ignore(); + return true; /* let the completer do default behavior */ + case Qt::Key_Space: + if( block ) + { + PHB_ITEM p1 = hb_itemPutNI( NULL, 21001 ); + hb_vmEvalBlockV( block, 1, p1 ); + hb_itemRelease( p1 ); + hbRefreshCompleter(); /* Watch closely */ + } + break; + case Qt::Key_ParenLeft: + if( block ) + { + PHB_ITEM p1 = hb_itemPutNI( NULL, 21002 ); + hb_vmEvalBlockV( block, 1, p1 ); + hb_itemRelease( p1 ); + } + break; + default: + break; } } - - if( hbKeyPressSelection( event ) ) - { - return; - } - - QPlainTextEdit::keyPressEvent( event ); - - if( ! isCodeCompletionActive ){ - if( c ){ - c->popup()->hide(); - } - return; - } - - if( ! c ){ - return; - } - if( isTipActive ){ - c->popup()->hide(); - return; - } - - if( ! isAliasCompleter ){ - hbRefreshCompleter( hbTextAlias() ); - } - - if( ( event->modifiers() & ( Qt::ControlModifier | Qt::AltModifier ) ) ){ - c->popup()->hide(); - return; - } - const bool ctrlOrShift = event->modifiers() & ( Qt::ControlModifier | Qt::ShiftModifier ); - if( ctrlOrShift && event->text().isEmpty() ){ - return; - } - static QString eow( " ~!@#$%^&*()+{}|:\"<>?,./;'[]\\-=" ); /* end of word */ - bool hasModifier = ( event->modifiers() != Qt::NoModifier ) && !ctrlOrShift; - QString completionPrefix = hbTextUnderCursor( true ); - /*QString completionPrefix = hbTextUnderCursor( false );*/ - - if( hasModifier || - event->text().isEmpty() || - completionPrefix.length() < ( isAliasCompleter ? 0 : 1 ) || - eow.contains( event->text().right( 1 ) ) ) - { - c->popup()->hide(); - return; - } - - if( completionPrefix != c->completionPrefix() ) { - c->setCompletionPrefix( completionPrefix ); - c->popup()->setCurrentIndex( c->completionModel()->index( 0, 0 ) ); - } - QRect cr = cursorRect(); - - c->popup()->setMaximumWidth( viewport()->width() ); - cr.setWidth( c->popup()->sizeHintForColumn( 0 ) + c->popup()->verticalScrollBar()->sizeHint().width() ); - cr.setTop( cr.top() + horzRulerHeight + 5 ); - cr.setBottom( cr.bottom() + horzRulerHeight + 5 ); - - c->complete( cr ); /* pop it up! */ + return false; } /*----------------------------------------------------------------------*/ diff --git a/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.h b/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.h index 536dae22f5..a328697975 100644 --- a/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.h +++ b/harbour/contrib/hbqt/qtgui/hbqt_hbqplaintextedit.h @@ -153,7 +153,6 @@ private: int rowEnds; int columnBegins; int columnEnds; - int selectionState; int selectionMode; int selectionDisplay; bool isStreamSelectionON; @@ -177,6 +176,9 @@ private: bool isCompletionTipsActive; bool isInDrag; QPoint dragStartPosition; + QPoint clickPos; + int iClicks; + int mouseMode; protected: bool event( QEvent * event ); @@ -191,6 +193,8 @@ protected: void dragEnterEvent( QDragEnterEvent * event ); void dragMoveEvent( QDragMoveEvent * event ); void dropEvent( QDropEvent * event ); + void hbHandleKey( QKeyEvent * event, int k, int selMode, bool shift ); + bool hbHandlePopup( QKeyEvent * event ); public slots: QString hbTextAlias();