]>
git.saurik.com Git - wxWidgets.git/blob - utils/wxPython/modules/lseditor/tdefs.cpp
1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Contrib. demo
4 // Author: Aleksandras Gluchovas
8 // Copyright: (c) Aleksandars Gluchovas
9 // Licence: GNU General Public License
10 /////////////////////////////////////////////////////////////////////////////
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU General Public License for more details.
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 /////////////////////////////////////////////////////////////////////////////
28 // For compilers that support precompilation, includes "wx/wx.h".
29 #include "wx/wxprec.h"
40 #include "wx/textdlg.h"
41 #include "wx/clipbrd.h"
42 #include "wx/dataobj.h"
51 /***** Implementation for class TBlock *****/
53 void TBlock::RecalcBlockProperties()
56 char* end
= mBuf
+ mTextLen
;
61 if ( is_eol_char( *cur
) ) ++mRowCount
;
67 /***** Implementation for class TTextIterator *****/
69 string
TTextIterator::mSeparators
= ",.()[]\t\\+-*/|=<>:;\t\n~?!%";
71 bool TTextIterator::IsSeparator( char ch
)
73 size_t sz
= mSeparators
.size();
75 for( size_t i
= 0; i
!= sz
; ++i
)
77 if ( mSeparators
[i
] == ch
) return TRUE
;
82 char* TTextIterator::GetClosestPos()
84 char* end
= GetBlockEnd();
85 char* cur
= mpCurRowStart
;
88 while( cur
< end
&& col
< mPos
.mCol
&& !is_eol_char(*cur
) )
90 if ( !is_DOS_eol_char( *cur
) ) ++col
;
94 if ( is_DOS_eol_char( *cur
) ) ++cur
;
99 char* TTextIterator::GotoClosestPos()
101 char* end
= GetBlockEnd();
102 char* cur
= mpCurRowStart
;
105 while( cur
< end
&& col
< mPos
.mCol
&& !is_eol_char(*cur
) )
107 if ( !is_DOS_eol_char( *cur
) ) ++col
;
113 if ( is_DOS_eol_char( *cur
) ) ++cur
;
118 TTextIterator::TTextIterator()
123 bool TTextIterator::IsLastLine()
125 TBlockIteratorT nextBlk
= mBlockIter
;
128 if ( nextBlk
!= mEndOfListIter
) return FALSE
;
130 char* cur
= mpCurRowStart
;
131 char* end
= GetBlockEnd();
133 while( cur
< end
&& !is_eol_char( *cur
) ) ++cur
;
135 if ( cur
== end
) return TRUE
;
139 return ( cur
== end
);
142 char TTextIterator::GetChar()
144 char* cur
= GetClosestPos();
146 if ( is_DOS_eol_char( *cur
) )
153 bool TTextIterator::IsEol()
155 return is_eol_char( GetChar() ) || mIsEof
;
158 bool TTextIterator::IsEof()
163 int TTextIterator::GetDistFromEol()
168 void TTextIterator::NextChar()
170 char* cur
= GotoClosestPos();
172 if ( cur
+ 1 >= GetBlockEnd() )
174 TBlockIteratorT nextBlk
= mBlockIter
;
177 if ( nextBlk
== mEndOfListIter
)
179 if ( cur
!= GetBlockEnd() )
189 mBlockIter
= nextBlk
;
191 mFirstRowInBlock
= mPos
.mRow
;
192 mActualRow
= mPos
.mRow
;
193 mpCurRowStart
= (*mBlockIter
).mBuf
;
195 mIsEof
= ( (*mBlockIter
).mTextLen
== 0 );
199 if ( is_eol_char( *cur
) )
204 mActualRow
= mPos
.mRow
;
205 mpCurRowStart
= cur
+ 1;
211 mIsEof
= (mpCurRowStart
+ mPos
.mCol
) == GetBlockEnd();
214 void TTextIterator::PreviousChar()
216 char* cur
= GotoClosestPos();
218 if ( cur
== (*mBlockIter
).mBuf
)
220 TBlockIteratorT prevBlk
= mBlockIter
;
223 if ( prevBlk
== mEndOfListIter
)
231 mBlockIter
= prevBlk
;
233 cur
= GetBlockEnd() - 1;
237 char* start
= (*mBlockIter
).mBuf
;
239 while( cur
!= start
&& !is_eol_char( *cur
) ) --cur
; // goto start of line
241 if ( is_eol_char( *cur
) ) ++cur
;
243 mPos
.mCol
= (size_t)(eolPos
- cur
);
246 mFirstRowInBlock
= mPos
.mRow
;
247 mActualRow
= mPos
.mRow
;
253 // FIXME FIXME:: this is more then messy .... !
255 if ( is_eol_char( *(cur
-1) ) )
263 char* start
= (*mBlockIter
).mBuf
;
265 while( cur
!= start
&& !is_eol_char( *cur
) ) --cur
; // goto start of line
267 if ( is_eol_char( *cur
) ) ++cur
;
269 mPos
.mCol
= (size_t)(eolPos
- cur
);
272 if ( eolPos
!= cur
&& is_DOS_eol_char( *(eolPos
-1) ) ) --mPos
.mCol
;
274 mActualRow
= mPos
.mRow
;
279 if ( is_DOS_eol_char( *(cur
-1) ) )
283 if ( cur
!= (*mBlockIter
).mBuf
&& is_eol_char( *(cur
-1) ) )
301 mIsEof
= (mpCurRowStart
+ mPos
.mCol
) == GetBlockEnd();
304 void TTextIterator::NextWord()
308 // skip non-white space ahead
310 bool wasSeparator
= IsSeparator( GetChar() );
319 wasSeparator
!= IsSeparator(ch
) )
326 // skip all white stpace if any
331 if ( ch
!= ' ' && ch
!= '\t' && !is_eol_char(ch
) )
339 void TTextIterator::PreviousWord()
345 // skip all white stpace if any
350 if ( ch
!= ' ' && ch
!= '\t' && !is_eol_char(ch
) )
357 bool wasSeparator
= IsSeparator( GetChar() );
367 wasSeparator
!= IsSeparator(ch
)
378 void TTextIterator::ToEndOfLine()
386 if ( is_eol_char( ch
) ) break;
392 void TTextIterator::ToStartOfLine()
397 mPos
.mRow
= mActualRow
;
400 size_t TTextIterator::GetLineLen()
402 char* cur
= mpCurRowStart
;
403 char* end
= GetBlockEnd();
407 while( cur
< end
&& !is_eol_char( *cur
) )
409 if ( !is_DOS_eol_char( *cur
) ) ++len
;
416 TPosition
TTextIterator::GetPosition()
421 bool TTextIterator::IsInLastBlock()
423 TBlockIteratorT next
= mBlockIter
;
426 return next
== mEndOfListIter
;
429 bool TTextIterator::DetectUnixText()
431 char* cur
= GetBlockStart();
432 char* end
= GetBlockEnd();
434 bool isUnixText
= IS_UNIX_TEXT_BY_DEFAULT
;
438 if ( is_DOS_eol_char( *cur
) ) return FALSE
;
440 if ( is_eol_char( *cur
) ) return TRUE
;
448 /***** Implementation for class TCppJavaHighlightListener *****/
450 void TCppJavaHighlightListener::OnTextChanged( wxTextEditorModel
* pModel
,
451 size_t atRow
, size_t nRows
,
452 TEXT_CHANGE_TYPE ct
)
458 int state = GetStateAtRow( atRow );
460 if ( ct == CT_INSERTED )
462 RemoveCommentTags( atRow, atRow + nRows + 1 );
463 GenerateTagsForRange( atRows, atRows + nRows + 1 );
466 if ( ct == CT_DELETED )
468 RemoveCommentTags( atRow, atRow + 1 );
469 GenerateTagsForRange( atRows, atRows + 1 );
474 /***** Implementation for class wxTextEditorModel *****/
476 /*** protected methods ***/
478 size_t wxTextEditorModel::GetLineCountInRange( char* from
, char* till
)
482 while( from
!= till
)
484 if ( is_eol_char( *from
) ) ++nLines
;
492 void wxTextEditorModel::DoInsertText( const TPosition
& pos
,
493 char* text
, size_t len
,
494 TRange
& actualRange
)
496 // FOR NOW:: very dummy imp.
498 char* end
= text
+ len
;
500 TTextIterator iter
= CreateIterator( pos
);
502 TBlock
& blk
= (*iter
.mBlockIter
);
506 char* insertPos
= iter
.GotoClosestPos();
507 actualRange
.mFrom
= iter
.GetPosition();
509 if ( is_eol_char( *insertPos
) &&
510 insertPos
!= iter
.GetBlockStart() &&
511 is_DOS_eol_char( *(insertPos
-1) )
515 size_t sizeAfter
= (size_t)(iter
.GetBlockEnd() - insertPos
);
517 size_t nLines
= GetLineCountInRange( text
, text
+ len
);
519 if ( blk
.mTextLen
+ len
< FILLED_BLOCK_LEN
)
521 memmove( insertPos
+ len
, insertPos
, sizeAfter
);
523 memcpy( insertPos
, text
, len
);
528 blk
.RecalcBlockProperties();
530 if ( iter
.IsInLastBlock() )
532 ++blk
.mRowCount
; // last block have always the-last-row-to-spare -
533 // the "nature" of most text editors
535 char* endPos
= insertPos
+ len
;
540 // OLD STUFF:: slow & buggy
542 while( !iter.IsEof() )
544 if ( iter.GetClosestPos() == endPos )
546 actualRange.mTill = iter.GetPosition();
556 actualRange.mTill = iter.GetPosition();
557 ++actualRange.mTill.mCol;
559 //T_ASSERT( found ); // DBG::
563 actualRange
.mTill
= actualRange
.mFrom
;
564 actualRange
.mTill
.mRow
+= nLines
;
568 actualRange
.mTill
.mCol
= actualRange
.mFrom
.mCol
+ (len
);
573 while( cur
!= insertPos
&& !is_eol_char( *cur
) )
577 if ( is_eol_char( *cur
) ) ++cur
;
579 actualRange
.mTill
.mCol
= (int)(end
- cur
);
582 NotifyTextChanged( pos
.mRow
, nLines
, CT_INSERTED
);
589 sprintf( buf
, "%d", FILLED_BLOCK_LEN
);
590 string msg
= "Sorry!!! Currently editor is limited to files less then ";
592 msg
+= " bytes\n(the requested text length is " +
593 sprintf( buf
, "%d", blk
.mTextLen
+ len
);
595 msg
+= " bytes)\n Please, close this file without making any changes.";
599 GetActiveView()->SetFocus();
601 //T_ASSERT(0); // DBG:: for now
605 void wxTextEditorModel::DoDeleteRange( const TPosition
& from
, const TPosition
& till
,
609 // FOR NOW:: very dummy imp.
611 TTextIterator iterFrom
= CreateIterator( from
);
612 TTextIterator iterTill
= CreateIterator( till
);
614 if ( iterFrom
.mBlockIter
== iterTill
.mBlockIter
)
616 char* fromPos
= iterFrom
.GotoClosestPos();
617 char* tillPos
= iterTill
.GotoClosestPos();
618 char* blockStart
= (*iterFrom
.mBlockIter
).mBuf
;
620 if ( is_eol_char( *fromPos
) &&
621 fromPos
!= blockStart
&&
622 is_DOS_eol_char( *(fromPos
-1) )
626 if ( is_eol_char( *tillPos
) &&
627 tillPos
!= blockStart
&&
628 is_DOS_eol_char( *(tillPos
-1) )
632 size_t len
= (size_t)( tillPos
-fromPos
);
634 size_t nLines
= GetLineCountInRange( fromPos
, fromPos
+ len
);
636 size_t sizeAfter
= (size_t)(iterFrom
.GetBlockEnd() - tillPos
);
638 memmove( fromPos
, tillPos
, sizeAfter
);
640 (*iterFrom
.mBlockIter
).mTextLen
-= len
;
642 (*iterFrom
.mBlockIter
).RecalcBlockProperties();
644 if ( iterFrom
.IsInLastBlock() )
646 ++(*iterFrom
.mBlockIter
).mRowCount
; // last block have always the-last-row-to-spare -
647 // the "nature" of most text editors
649 actualRange
.mFrom
= iterFrom
.GetPosition();
650 actualRange
.mTill
= iterTill
.GetPosition();
652 NotifyTextChanged( from
.mRow
, nLines
, CT_DELETED
);
655 T_ASSERT(0); // DBG:: for now
658 void wxTextEditorModel::GetTextFromRange( const TPosition
& from
, const TPosition
& till
,
659 char** text
, size_t& textLen
662 TTextIterator iterFrom
= CreateIterator( from
);
663 TTextIterator iterTill
= CreateIterator( till
);
665 if ( iterFrom
.mBlockIter
== iterTill
.mBlockIter
)
667 char* blockStart
= (*iterFrom
.mBlockIter
).mBuf
;
669 char* fromPos
= iterFrom
.GetClosestPos();
670 char* tillPos
= iterTill
.GetClosestPos();
672 if ( is_eol_char( *fromPos
) &&
673 fromPos
!= blockStart
&&
674 is_DOS_eol_char( *(fromPos
-1) )
678 if ( is_eol_char( *tillPos
) &&
679 tillPos
!= blockStart
&&
680 is_DOS_eol_char( *(tillPos
-1) )
684 textLen
= (size_t)( tillPos
-fromPos
);
686 *text
= AllocCharacters( textLen
);
688 memcpy( *text
, fromPos
, textLen
);
691 T_ASSERT(0); // DBG:: for now
694 void wxTextEditorModel::LoadTextFromFile( const wxString
& fname
)
696 T_ASSERT( wxFile::Exists( fname
) );
702 char* buf
= AllocCharacters( fl
.Length() );
704 fl
.Read( buf
, fl
.Length() );
707 DoInsertText( TPosition( 0,0 ), buf
, fl
.Length(), result
);
709 FreeCharacters( buf
);
711 TTextIterator iter
= CreateIterator( TPosition( 0,0 ) );
713 mIsUnixText
= iter
.DetectUnixText();
720 void wxTextEditorModel::SaveTextToFile( const wxString
& fname
)
722 wxFile
fl( fname
, wxFile::write
);
727 GetTextFromRange( TPosition(0,0), TPosition( GetTotalRowCount()+1,0 ), &text
, len
);
729 fl
.Write( text
, len
);
732 FreeCharacters( text
);
735 void wxTextEditorModel::NotifyTextChanged( size_t atRow
, size_t nRows
, TEXT_CHANGE_TYPE ct
)
739 MergeChange( atRow
, mRowsPerPage
);
741 MergeChange( atRow
, 1 );
743 // reposition bookmarsk
747 if ( ct
== CT_INSERTED
)
749 size_t curPin
= FindNextPinFrom( atRow
+ 1 );
751 while( curPin
!= NPOS
)
753 mPins
[curPin
]->mRow
+= nRows
;
757 if ( curPin
== mPins
.size() ) break;
761 if ( ct
== CT_DELETED
)
763 size_t curPin
= FindNextPinFrom( atRow
+ 1 );
764 size_t fromPin
= curPin
;
765 size_t tillRow
= atRow
+ nRows
;
767 while( curPin
!= NPOS
&& mPins
[curPin
]->mRow
< tillRow
)
771 if ( curPin
== mPins
.size() ) break;
774 if ( fromPin
!= NPOS
&& nRows
!= 0 )
776 mPins
.erase( &mPins
[fromPin
], &mPins
[curPin
] );
778 while( curPin
< mPins
.size() )
780 mPins
[curPin
]->mRow
-= nRows
;
788 // send notificaitons
790 for( size_t i
= 0; i
!= mChangeListeners
.size(); ++i
)
792 mChangeListeners
[i
]->OnTextChanged( this, atRow
, nRows
, ct
);
795 void wxTextEditorModel::NotifyTextChanged( TPosition from
, TPosition till
, TEXT_CHANGE_TYPE ct
)
797 ArrangePositions( from
, till
);
799 NotifyTextChanged( from
.mRow
, till
.mRow
- from
.mRow
+ 1, ct
);
802 void wxTextEditorModel::DoExecuteNewCommand( TCommand
& cmd
)
804 if ( cmd
.mType
== TCMD_INSERT
)
806 cmd
.mPrePos
= mCursorPos
;
807 DoInsertText( cmd
.mRange
.mFrom
, cmd
.mData
, cmd
.mDataLen
, cmd
.mRange
);
810 if ( cmd
.mType
== TCMD_DELETE
)
812 cmd
.mPrePos
= mCursorPos
;
813 DoDeleteRange( cmd
.mRange
.mFrom
, cmd
.mRange
.mTill
, cmd
.mRange
);
817 void wxTextEditorModel::DoReexecuteCommand( TCommand
& cmd
)
819 NotifyTextChanged( mCursorPos
.mRow
, 1, CT_MODIFIED
); // indicate update of current cursor position
821 if ( cmd
.mType
== TCMD_INSERT
)
823 DoInsertText( cmd
.mRange
.mFrom
, cmd
.mData
, cmd
.mDataLen
, cmd
.mRange
);
824 mCursorPos
= cmd
.mPostPos
;
827 if ( cmd
.mType
== TCMD_DELETE
)
829 DoDeleteRange( cmd
.mRange
.mFrom
, cmd
.mRange
.mTill
, cmd
.mRange
);
830 mCursorPos
= cmd
.mPostPos
;
833 NotifyTextChanged( mCursorPos
.mRow
, 1, CT_MODIFIED
); // indicate update of current cursor position
836 void wxTextEditorModel::DoUnexecuteCommand( TCommand
& cmd
)
838 NotifyTextChanged( mCursorPos
.mRow
, 1, CT_MODIFIED
); // indicate update of current cursor position
840 if ( cmd
.mType
== TCMD_INSERT
)
842 DoDeleteRange( cmd
.mRange
.mFrom
, cmd
.mRange
.mTill
, cmd
.mRange
);
843 mCursorPos
= cmd
.mPrePos
;
846 if ( cmd
.mType
== TCMD_DELETE
)
848 DoInsertText( cmd
.mRange
.mFrom
, cmd
.mData
, cmd
.mDataLen
, cmd
.mRange
);
849 mCursorPos
= cmd
.mPrePos
;
852 NotifyTextChanged( mCursorPos
.mRow
, 1, CT_MODIFIED
); // indicate update of current cursor position
855 void wxTextEditorModel::UndoImpl()
859 DoUnexecuteCommand( *mCommands
[mCurCommand
] );
862 void wxTextEditorModel::RedoImpl()
864 DoReexecuteCommand( *mCommands
[mCurCommand
] );
869 void wxTextEditorModel::ExecuteCommand( TCommand
* pCmd
)
871 if ( mCurCommand
< mCheckPointCmdNo
)
873 // new command is executed before the checkpoint,
874 // and every thing is sliced - invalidate it
876 mCheckPointDestroyed
= TRUE
;
878 // slice undo-able commands ahead in the queue,
879 // they wont ever be reexecuted
881 while( mCommands
.size() > mCurCommand
)
883 delete mCommands
.back();
885 mCommands
.pop_back();
888 mCommands
.push_back( pCmd
);
890 DoExecuteNewCommand( *pCmd
);
894 bool wxTextEditorModel::CanPrependCommand( TCommand
* pCmd
)
896 if ( mCommands
.size() != mCurCommand
||
897 mCommands
.size() == 0 )
901 TCommand
& prevCmd
= *mCommands
.back();
903 if ( !(prevCmd
.mRange
.mTill
== pCmd
->mRange
.mFrom
) )
907 char prevCh
= prevCmd
.mData
[ prevCmd
.mDataLen
- 1];
908 char curCh
= pCmd
->mData
[0];
910 if ( prevCh
== curCh
) return TRUE
;
912 if ( prevCh
== ' ' || curCh
== ' ') return FALSE
;
914 if ( TTextIterator::IsSeparator(prevCh
) !=
915 TTextIterator::IsSeparator(curCh
) )
922 void wxTextEditorModel::PrependCommand( TCommand
* pCmd
)
924 if ( mCheckPointCmdNo
== mCurCommand
)
926 mCheckPointDestroyed
= TRUE
;
928 TCommand
& prevCmd
= *mCommands
.back();
930 DoExecuteNewCommand( *pCmd
);
932 TCommand
* pComb
= new TCommand();
934 pComb
->mType
= TCMD_INSERT
;
935 pComb
->mDataLen
= prevCmd
.mDataLen
+ pCmd
->mDataLen
;
937 pComb
->mData
= AllocCharacters( pComb
->mDataLen
);
938 pComb
->mRange
.mFrom
= prevCmd
.mRange
.mFrom
;
939 pComb
->mRange
.mTill
= pCmd
->mRange
.mTill
;
940 pComb
->mPrePos
= prevCmd
.mPrePos
;
941 pComb
->mPostPos
= pCmd
->mPostPos
;
943 memcpy( pComb
->mData
, prevCmd
.mData
, prevCmd
.mDataLen
);
944 memcpy( pComb
->mData
+ prevCmd
.mDataLen
, pCmd
->mData
, pCmd
->mDataLen
);
946 FreeCharacters( prevCmd
.mData
);
947 FreeCharacters( pCmd
->mData
);
952 mCommands
[ mCommands
.size() - 1 ] = pComb
;
955 void wxTextEditorModel::SetPostPos( const TPosition
& pos
)
957 mCommands
[mCurCommand
-1]->mPostPos
= pos
;
960 bool wxTextEditorModel::SelectionIsEmpty()
962 return mSelectionStart
== mSelectionEnd
;
965 void wxTextEditorModel::StartBatch()
970 void wxTextEditorModel::FinishBatch()
975 void wxTextEditorModel::DeleteRange( const TPosition
& from
, const TPosition
& till
)
977 TCommand
* pCmd
= new TCommand();
979 pCmd
->mType
= TCMD_DELETE
;
981 pCmd
->mRange
.mFrom
= from
;
982 pCmd
->mRange
.mTill
= till
;
983 pCmd
->mPrePos
= mCursorPos
;
985 GetTextFromRange( from
, till
, &pCmd
->mData
, pCmd
->mDataLen
);
987 ExecuteCommand( pCmd
);
990 void wxTextEditorModel::InsertText( const TPosition
& pos
, const char* text
, size_t len
)
992 TCommand
* pCmd
= new TCommand();
994 pCmd
->mType
= TCMD_INSERT
;
996 pCmd
->mRange
.mFrom
= pos
;
998 pCmd
->mData
= AllocCharacters( len
, text
),
999 pCmd
->mDataLen
= len
;
1000 pCmd
->mPrePos
= mCursorPos
;
1002 ExecuteCommand( pCmd
);
1005 void wxTextEditorModel::DeleteSelection()
1007 DeleteRange( mSelectionStart
, mSelectionEnd
);
1012 bool wxTextEditorModel::IsLastLine( const TPosition
& pos
)
1017 TTextIterator
wxTextEditorModel::CreateIterator( const TPosition
& pos
)
1021 TBlockIteratorT bIter
= mBlocks
.begin();
1023 TTextIterator tIter
;
1025 while( bIter
!= mBlocks
.end() )
1027 TBlockIteratorT nextBlk
= bIter
;
1030 if ( nextBlk
== mBlocks
.end() ||
1031 ( pos
.mRow
>= curRow
&&
1032 pos
.mRow
<= curRow
+ (*bIter
).mRowCount
)
1035 tIter
.mFirstRowInBlock
= curRow
;
1037 char* cur
= (*bIter
).mBuf
;
1038 char* end
= cur
+ (*bIter
).mTextLen
;
1040 // slightly optimized
1042 if ( curRow
< pos
.mRow
)
1046 if ( is_eol_char( *cur
) )
1050 if ( !(curRow
< pos
.mRow
) )
1061 tIter
.mActualRow
= curRow
;
1062 tIter
.mpCurRowStart
= cur
;
1065 // FOR NOW:: positioning past the end of file is not supported
1066 tIter
.mPos
.mRow
= curRow
;
1068 tIter
.mBlockIter
= bIter
;
1069 tIter
.mEndOfListIter
= mBlocks
.end();
1075 curRow
+= (*bIter
).mRowCount
;
1083 void wxTextEditorModel::ArrangePositions( TPosition
& upper
, TPosition
& lower
)
1085 if ( upper
> lower
)
1087 TPosition
tmp( lower
);
1093 void wxTextEditorModel::ArrangePositions( size_t& upper
, size_t& lower
)
1095 if ( upper
> lower
)
1103 void wxTextEditorModel::MergeChange( size_t fromRow
, size_t nRows
)
1105 if ( mTextChanged
== FALSE
)
1107 mChangedFromRow
= fromRow
;
1108 mChangedTillRow
= fromRow
+ nRows
;
1109 mTextChanged
= TRUE
;
1113 if ( mChangedFromRow
> fromRow
)
1115 mChangedFromRow
= fromRow
;
1117 if ( mChangedTillRow
< fromRow
+ nRows
)
1119 mChangedTillRow
= fromRow
+ nRows
;
1123 void wxTextEditorModel::TrackSelection()
1125 if ( !mIsSelectionEditMode
) return;
1127 if ( mPrevCursorPos
== mSelectionStart
)
1129 mSelectionStart
= mCursorPos
;
1131 mSelectionEnd
= mCursorPos
;
1133 ArrangePositions( mSelectionStart
, mSelectionEnd
);
1135 NotifyTextChanged( mSelectionStart
, mPrevSelectionStart
, CT_MODIFIED
);
1136 NotifyTextChanged( mSelectionEnd
, mPrevSelectionEnd
, CT_MODIFIED
);
1139 void wxTextEditorModel::CheckSelection()
1141 ArrangePositions( mSelectionStart
, mSelectionEnd
);
1143 if ( mIsSelectionEditMode
&& SelectionIsEmpty() )
1145 mSelectionStart
= mCursorPos
;
1146 mSelectionEnd
= mCursorPos
;
1149 if ( !mIsSelectionEditMode
&& !SelectionIsEmpty() )
1154 mPrevSelectionStart
= mSelectionStart
;
1155 mPrevSelectionEnd
= mSelectionEnd
;
1156 mPrevCursorPos
= mCursorPos
;
1159 void wxTextEditorModel::ResetSelection()
1161 if ( SelectionIsEmpty() ) return;
1163 MergeChange( mSelectionStart
.mRow
,
1164 mSelectionEnd
.mRow
- mSelectionStart
.mRow
+ 1 );
1166 NotifyTextChanged( mSelectionStart
, mSelectionEnd
, CT_MODIFIED
);
1168 mSelectionStart
= TPosition(0,0);
1169 mSelectionEnd
= TPosition(0,0);
1173 void wxTextEditorModel::ClearUndoBuffer()
1175 for( size_t i
= 0; i
!= mCommands
.size(); ++i
)
1177 TCommand
& cmd
= *mCommands
[i
];
1179 if ( cmd
.mData
) delete [] cmd
.mData
;
1184 mCommands
.erase( mCommands
.begin(), mCommands
.end() );
1189 void wxTextEditorModel::GetAllText( char** text
, size_t& textLen
)
1191 GetTextFromRange( TPosition(0,0), TPosition( GetTotalRowCount()+1, 0 ),
1196 void wxTextEditorModel::DeleteAllText()
1200 DeleteRange( TPosition(0,0), TPosition( GetTotalRowCount()+1, 0 ) );
1203 void wxTextEditorModel::SetSelectionEditMode( bool editIsOn
)
1205 mIsSelectionEditMode
= editIsOn
;
1208 size_t wxTextEditorModel::GetTotalRowCount()
1212 for( TBlockIteratorT i
= mBlocks
.begin(); i
!= mBlocks
.end(); ++i
)
1214 nRows
+= (*i
).mRowCount
;
1219 void wxTextEditorModel::GetSelection( char** text
, size_t& textLen
)
1221 GetTextFromRange( GetStartOfSelection(), GetEndOfSelection(), text
, textLen
);
1224 void wxTextEditorModel::NotifyView()
1226 mpActiveView
->OnModelChanged();
1229 void wxTextEditorModel::NotifyAllViews()
1231 for( size_t i
= 0; i
!= mViews
.size(); ++i
)
1233 mViews
[i
]->OnModelChanged();
1236 void wxTextEditorModel::PrepreForCommand()
1239 mChangedFromRow
= 0;
1240 mChangedTillRow
= 0;
1243 size_t wxTextEditorModel::TextToScrColumn( const TPosition
& pos
)
1247 mpActiveView
->TextPosToScreenPos( pos
, spos
);
1249 return spos
.mCol
+ mpActiveView
->GetPagePos().mCol
;
1252 size_t wxTextEditorModel::ScrToTextColumn( TPosition pos
)
1256 pos
.mCol
-= mpActiveView
->GetPagePos().mCol
;
1257 pos
.mRow
-= mpActiveView
->GetPagePos().mRow
;
1259 mpActiveView
->ScreenPosToTextPos( pos
, tpos
);
1264 void wxTextEditorModel::DoMoveCursor( int rows
, int cols
)
1266 mCursorPos
.mCol
= TextToScrColumn( mCursorPos
);
1268 mCursorPos
.mRow
+= rows
;
1269 mCursorPos
.mCol
+= cols
;
1271 mCursorPos
.mCol
= ScrToTextColumn( mCursorPos
);
1274 /*** public interface ***/
1276 wxTextEditorModel::wxTextEditorModel()
1279 mpActiveView( NULL
),
1281 mIsSelectionEditMode( FALSE
),
1283 mTextChanged( FALSE
),
1286 mInsertMode ( TRUE
),
1287 mAutoIndentMode ( TRUE
),
1288 mSmartIndentMode( TRUE
),
1289 mWasChanged ( FALSE
),
1290 mIsReadOnly ( FALSE
),
1291 mIsUnixText ( IS_UNIX_TEXT_BY_DEFAULT
)
1293 // at least one block should be present
1294 // (otherwise text-iterators wont work)
1296 mBlocks
.push_back( TBlock() );
1299 wxTextEditorModel::~wxTextEditorModel()
1304 char* wxTextEditorModel::AllocCharacters( size_t n
)
1309 char* wxTextEditorModel::AllocCharacters( size_t n
, const char* srcBuf
)
1311 char* destBuf
= AllocCharacters( n
);
1313 memcpy( destBuf
, srcBuf
, n
);
1318 void wxTextEditorModel::FreeCharacters( char* buf
)
1323 void wxTextEditorModel::OnInsertChar( char ch
)
1325 if ( ch
== 27 ) return; // hack
1327 if ( is_DOS_eol_char( ch
) ) ch
= '\n';
1332 TCommand
* pCmd
= new TCommand();
1334 pCmd
->mType
= TCMD_INSERT
;
1336 if ( ch
== '\n' && !mIsUnixText
)
1338 // DOS text with CR-LF pair
1339 pCmd
->mData
= AllocCharacters( 2 );
1341 pCmd
->mData
[0] = (char)13;
1342 pCmd
->mData
[1] = (char)10;
1346 pCmd
->mData
= AllocCharacters( 1 );
1348 pCmd
->mData
[0] = ch
;
1352 if ( !SelectionIsEmpty() )
1354 mCursorPos
= mSelectionStart
;
1358 pCmd
->mRange
.mFrom
= mCursorPos
;
1360 if ( mInsertMode
== FALSE
)
1362 TPosition
nextPos( mCursorPos
.mRow
, mCursorPos
.mCol
+ 1 );
1363 DeleteRange( mCursorPos
, nextPos
);
1365 SetPostPos( mCursorPos
);
1368 TTextIterator iter
= CreateIterator( mCursorPos
);
1370 size_t lineLen
= iter
.GetLineLen();
1372 bool indentAdded
= FALSE
;
1374 if ( mCursorPos
.mCol
> lineLen
)
1377 wxString
s( ' ', mCursorPos
.mCol
- lineLen
);
1378 InsertText( TPosition( mCursorPos
.mRow
, lineLen
), s
.c_str(), s
.length() );
1380 SetPostPos( mCursorPos
);
1385 if ( CanPrependCommand( pCmd
) || indentAdded
)
1387 PrependCommand( pCmd
);
1389 ExecuteCommand( pCmd
);
1393 if ( is_eol_char( ch
) )
1395 mCursorPos
.mCol
= 0;
1398 SetPostPos( mCursorPos
);
1400 if ( mAutoIndentMode
)
1402 iter
.ToStartOfLine();
1405 while( !iter
.IsEol() )
1407 char ch
= iter
.GetChar();
1409 if ( ch
== '\t' || ch
== ' ' )
1418 if ( indent
.length() )
1420 // auto-indent is always prepended to the command which
1423 mCursorPos
= TPosition( mCursorPos
.mRow
, 0 );
1426 TCommand
* pICmd
= new TCommand();
1427 pICmd
->mType
= TCMD_INSERT
;
1428 pICmd
->mData
= AllocCharacters( indent
.length() );
1429 pICmd
->mDataLen
= indent
.length();
1430 memcpy( pICmd
->mData
, indent
, indent
.length() );
1432 pICmd
->mRange
.mFrom
= TPosition( mCursorPos
.mRow
, 0 );
1434 PrependCommand( pICmd
);
1436 SetPostPos( mCursorPos
);
1438 mCursorPos
.mCol
= indent
.length();
1443 SetPostPos( mCursorPos
);
1450 void wxTextEditorModel::OnDelete()
1455 if ( !SelectionIsEmpty() )
1457 TPosition startPos
= mSelectionStart
;
1459 mCursorPos
= startPos
;
1463 TTextIterator iter
= CreateIterator( mCursorPos
);
1465 if ( iter
.GetLineLen() == mCursorPos
.mCol
&& !iter
.IsLastLine() )
1467 TPosition
nextPos( mCursorPos
.mRow
+1, 0 );
1468 DeleteRange( mCursorPos
, nextPos
);
1469 NotifyTextChanged( mCursorPos
.mRow
, 2, CT_DELETED
);
1473 TPosition
nextPos( mCursorPos
.mRow
, mCursorPos
.mCol
+ 1 );
1474 DeleteRange( mCursorPos
, nextPos
);
1478 SetPostPos( mCursorPos
);
1485 void wxTextEditorModel::OnDeleteBack()
1490 if ( !SelectionIsEmpty() )
1492 mCursorPos
= mSelectionStart
;
1496 if ( !(mCursorPos
== TPosition(0,0)) )
1500 if ( mCursorPos
.mCol
== 0 )
1502 TTextIterator iter
= CreateIterator( mCursorPos
);
1503 iter
.PreviousChar();
1505 prevPos
= iter
.GetPosition();
1508 prevPos
= TPosition( mCursorPos
.mRow
, mCursorPos
.mCol
- 1 );
1510 DeleteRange( prevPos
, mCursorPos
);
1512 mCursorPos
= prevPos
;
1515 SetPostPos( mCursorPos
);
1523 void wxTextEditorModel::OnDeleteLine()
1530 TTextIterator iter
= CreateIterator( mCursorPos
);
1532 iter
.ToStartOfLine();
1534 TPosition from
= iter
.GetPosition();
1538 if ( iter
.IsLastLine() == FALSE
)
1540 iter
.NextChar(); // delete eol-char also, if it's not the last line
1542 TPosition till
= iter
.GetPosition();
1544 DeleteRange( from
, till
);
1545 SetPostPos( mCursorPos
);
1552 void wxTextEditorModel::OnShiftSelectionIndent( bool left
)
1554 if ( SelectionIsEmpty() ) return;
1559 for( size_t row
= mSelectionStart
.mRow
; row
!= mSelectionEnd
.mRow
; ++row
)
1561 TTextIterator iter
= CreateIterator( TPosition( row
, 0 ) );
1567 while( !iter
.IsEol() && !iter
.IsEof() )
1569 char ch
= iter
.GetChar();
1571 if ( pos
== mTabSize
) break;
1573 if ( ch
!= ' ' && ch
!= '\t' ) break;
1577 if ( ch
== '\t' ) break;
1584 if ( n
) DeleteRange( TPosition( row
,0 ), TPosition( row
, n
) );
1590 InsertText( TPosition( row
, 0 ), &txt
, sizeof(char) );
1598 void wxTextEditorModel::OnPaste()
1600 // FIXME:: "wxLogQueryInterface(..)" linking problems with MSDev4.0
1602 #ifdef __HACK_MY_MSDEV40__
1604 bool alreadyOpen
=wxClipboardOpen();
1610 char* data
= (char*)::wxGetClipboardData( wxDF_TEXT
);
1614 if ( data
== NULL
) return;
1619 if ( !SelectionIsEmpty() )
1621 mCursorPos
= GetStartOfSelection();
1625 InsertText( mCursorPos
, data
, strlen( data
) );
1630 if ( !wxTheClipboard
->Open() ) return;
1632 wxTextDataObject data
;
1633 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1635 wxTheClipboard
->Close();
1639 wxTheClipboard
->GetData(&data
);
1641 string txt
= data
.GetText();
1643 wxTheClipboard
->Close();
1650 InsertText( mCursorPos
, txt
.c_str(), txt
.length() );
1654 mCursorPos
= mCommands
.back()->mRange
.mTill
;
1655 SetPostPos( mCursorPos
);
1661 void wxTextEditorModel::OnCut()
1669 SetPostPos( mCursorPos
);
1676 void wxTextEditorModel::OnCopy()
1678 if ( !SelectionIsEmpty() )
1683 #ifndef __HACK_MY_MSDEV40__
1685 if ( !wxTheClipboard
->Open() ) return;
1687 GetTextFromRange( mSelectionStart
, mSelectionEnd
, &text
, len
);
1689 wxString
s( text
, len
);
1691 wxTheClipboard
->AddData( new wxTextDataObject(s
) );
1692 wxTheClipboard
->Close();
1694 FreeCharacters( text
);
1696 bool alreadyOpen
=wxClipboardOpen();
1700 if (!wxEmptyClipboard())
1707 GetTextFromRange( mSelectionStart
, mSelectionEnd
, &text
, len
);
1709 wxString
s( text
, len
);
1711 bool success
= ::wxEmptyClipboard();
1713 success
= wxSetClipboardData( wxDF_TEXT
, (wxObject
*)s
.c_str(), 0,0 );
1715 FreeCharacters( text
);
1723 bool wxTextEditorModel::CanCopy()
1725 return !SelectionIsEmpty();
1728 bool wxTextEditorModel::CanPaste()
1730 if ( mIsReadOnly
) return FALSE
;
1732 #ifndef __HACK_MY_MSDEV40__
1734 if ( !wxTheClipboard
->Open() ) return FALSE
;
1736 if ( !wxTheClipboard
->IsSupported(wxDF_TEXT
) )
1739 wxTheClipboard
->Close();
1745 bool success
= ::wxClipboardOpen();
1747 bool alreadyOpen
=wxClipboardOpen();
1753 char* data
= (char*)::wxGetClipboardData( wxDF_TEXT
);
1757 if ( data
!= NULL
&& strlen(data
) != 0 )
1772 bool wxTextEditorModel::CanUndo()
1774 return !( mCommands
.size() == 0 ||
1778 bool wxTextEditorModel::CanRedo()
1780 return mCurCommand
!= mCommands
.size();
1783 void wxTextEditorModel::OnUndo()
1785 if ( !CanUndo() ) return;
1798 void wxTextEditorModel::OnRedo()
1800 if ( !CanRedo() ) return;
1813 void wxTextEditorModel::OnMoveLeft()
1818 if ( mCursorPos
.mCol
== 0 )
1820 if ( mCursorPos
.mRow
!= 0 )
1824 TTextIterator iter
= CreateIterator( mCursorPos
);
1828 mCursorPos
.mCol
= iter
.GetPosition().mCol
;
1838 void wxTextEditorModel::OnMoveRight()
1849 void wxTextEditorModel::OnMoveUp()
1854 if ( mCursorPos
.mRow
!= 0 )
1856 DoMoveCursor( -1,0 );
1862 void wxTextEditorModel::OnMoveDown()
1867 if ( mCursorPos
.mRow
+ 1 < GetTotalRowCount() )
1869 DoMoveCursor( 1,0 );
1875 void wxTextEditorModel::OnWordRight()
1880 TTextIterator iter
= CreateIterator( mCursorPos
);
1884 mCursorPos
= iter
.GetPosition();
1890 void wxTextEditorModel::OnWordLeft()
1895 TTextIterator iter
= CreateIterator( mCursorPos
);
1897 iter
.PreviousWord();
1899 mCursorPos
= iter
.GetPosition();
1905 void wxTextEditorModel::OnMoveToPosition( const TPosition
& pos
)
1916 void wxTextEditorModel::OnEndOfLine()
1921 TTextIterator iter
= CreateIterator( mCursorPos
);
1924 mCursorPos
= iter
.GetPosition();
1930 void wxTextEditorModel::OnStartOfLine()
1935 int prevCol
= mCursorPos
.mCol
;
1937 TTextIterator iter
= CreateIterator( mCursorPos
);
1938 iter
.ToStartOfLine();
1940 // bypass leading white-space at the begining of the line
1942 while( !iter
.IsEol() )
1944 char ch
= iter
.GetChar();
1946 if ( ch
!= ' ' && ch
!= '\t' ) break;
1953 mCursorPos
= iter
.GetPosition();
1955 if ( mCursorPos
.mCol
== prevCol
)
1957 mCursorPos
.mCol
= 0;
1963 void wxTextEditorModel::OnPageUp()
1968 if ( mCursorPos
.mRow
< mRowsPerPage
)
1970 mCursorPos
.mRow
= 0;
1972 DoMoveCursor( -mRowsPerPage
,0 );
1974 mpActiveView
->ScrollView( -(int)mRowsPerPage
, 0 );
1980 void wxTextEditorModel::OnPageDown()
1985 if ( mCursorPos
.mRow
+ mRowsPerPage
>= GetTotalRowCount() )
1987 if ( GetTotalRowCount() != 0 )
1989 mCursorPos
.mRow
= GetTotalRowCount() - 1;
1991 mCursorPos
.mRow
= 0;
1994 DoMoveCursor( mRowsPerPage
,0 );
1996 mpActiveView
->ScrollView( mRowsPerPage
, 0 );
2002 void wxTextEditorModel::OnSlideUp()
2006 if ( mpActiveView
->GetPagePos().mRow
+ mRowsPerPage
- 1 == mCursorPos
.mRow
)
2008 if ( mCursorPos
.mRow
== 0 )
2012 DoMoveCursor( -1,0 );
2015 mpActiveView
->ScrollView( -1, 0 );
2020 void wxTextEditorModel::OnSlideDown()
2024 if ( mCursorPos
.mRow
== mpActiveView
->GetPagePos().mRow
)
2026 if ( mCursorPos
.mRow
+ 1 >= GetTotalRowCount() )
2030 DoMoveCursor( 1,0 );
2033 mpActiveView
->ScrollView( 1, 0 );
2038 void wxTextEditorModel::OnStartOfText()
2043 mCursorPos
.mRow
= mCursorPos
.mCol
= 0;
2049 void wxTextEditorModel::OnEndOfText()
2054 mCursorPos
.mRow
= GetTotalRowCount() - 1;
2056 TTextIterator iter
= CreateIterator( mCursorPos
);
2060 mCursorPos
= iter
.GetPosition();
2066 void wxTextEditorModel::OnSelectWord()
2070 TTextIterator iter1
= CreateIterator( mCursorPos
);
2071 iter1
.GotoClosestPos();
2073 if ( mCursorPos
== iter1
.GetPosition() )
2075 TTextIterator iter2
= iter1
;
2077 // find the left-edge of the word
2079 bool wasSeparator
= TTextIterator::IsSeparator( iter1
.GetChar() );
2081 while( !iter1
.IsEol() )
2083 char ch
= iter1
.GetChar();
2087 wasSeparator
!= TTextIterator::IsSeparator( iter1
.GetChar() )
2094 iter1
.PreviousChar();
2097 // find the left-edge of the word
2099 while( !iter2
.IsEol() )
2101 char ch
= iter2
.GetChar();
2105 wasSeparator
!= TTextIterator::IsSeparator( iter2
.GetChar() )
2112 if ( !(iter1
.GetPosition() == iter2
.GetPosition()) )
2114 mSelectionStart
= iter1
.GetPosition();
2115 mSelectionEnd
= iter2
.GetPosition();
2116 mCursorPos
= iter2
.GetPosition();
2118 NotifyTextChanged( mSelectionStart
.mRow
, 1, CT_MODIFIED
);
2125 void wxTextEditorModel::OnSelectAll()
2131 mSelectionStart
= TPosition(0,0);
2132 mSelectionEnd
= TPosition( GetTotalRowCount(), 1024 ); // FOR NOW:: hack
2134 mCursorPos
= mSelectionStart
;
2136 NotifyTextChanged( mSelectionStart
.mRow
, mSelectionEnd
.mRow
, CT_MODIFIED
);
2141 void wxTextEditorModel::OnToggleBookmark()
2143 size_t curRow
= GetCursor().mRow
;
2145 if ( GetPinAt( curRow
, TBookmarkPin::GetPinTypeCode() ) != NULL
)
2147 RemovePinAt( curRow
, TBookmarkPin::GetPinTypeCode() );
2149 AddPin( new TBookmarkPin( curRow
) );
2151 MergeChange( curRow
, 1 );
2156 void wxTextEditorModel::OnNextBookmark()
2158 size_t pinNo
= FindNextPinFrom( mCursorPos
.mRow
+ 1 );
2160 while( pinNo
!= NPOS
)
2162 TPinBase
& pin
= *mPins
[pinNo
];
2164 if ( pin
.mTypeCode
== BOOKMARK_PIN_TC
)
2166 OnGotoLine( pin
.mRow
, 0 );
2170 if ( pinNo
== mPins
.size() ) break;
2176 void wxTextEditorModel::OnPreviousBookmark()
2178 if ( mCursorPos
.mRow
== 0 ) return;
2180 size_t pinNo
= FindPreviousPinFrom( mCursorPos
.mRow
- 1 );
2182 while( pinNo
!= NPOS
)
2184 TPinBase
& pin
= *mPins
[pinNo
];
2186 if ( pin
.mTypeCode
== BOOKMARK_PIN_TC
)
2188 OnGotoLine( pin
.mRow
, 0 );
2192 if ( pinNo
== 0 ) break;
2198 bool wxTextEditorModel::OnFind()
2200 if ( !SelectionIsEmpty() )
2202 if ( GetStartOfSelection().mRow
== GetEndOfSelection().mRow
)
2204 char* buf
= NULL
; size_t len
= 0;
2206 GetSelection( &buf
, len
);
2208 mLastFindExpr
= string( buf
, 0, len
);
2214 wxFindTextDialog
dlg( GetActiveView(), mLastFindExpr
);
2215 //dlg.SetExpr( mLastFindExpr );
2217 if( dlg
.ShowModal() == wxID_OK
)
2219 mLastFindExpr
= dlg
.GetExpr();
2221 GetActiveView()->SetFocus();
2223 return OnFindNext();
2226 GetActiveView()->SetFocus();
2231 bool wxTextEditorModel::OnFindNext()
2235 string
& val
= mLastFindExpr
;
2236 size_t len
= val
.length();
2241 wxMessageBox( "Secarch string not found!" );
2243 GetActiveView()->SetFocus();
2250 TTextIterator iter
= CreateIterator( mCursorPos
);
2252 while( !iter
.IsEof() )
2254 char ch
= iter
.GetChar();
2258 size_t startCol
= iter
.mPos
.mCol
;
2260 ch
= iter
.GetChar();
2263 while( i
< len
&& !iter
.IsEof() && ch
== val
[i
] )
2267 ch
= iter
.GetChar();
2272 if ( !SelectionIsEmpty() )
2276 SetStartOfSelection( TPosition( iter
.mPos
.mRow
, startCol
) );
2277 SetEndOfSelection( iter
.mPos
);
2279 MergeChange( iter
.mPos
.mRow
, 1 );
2281 mCursorPos
= iter
.mPos
;
2283 OnGotoLine( iter
.mPos
.mRow
, iter
.mPos
.mCol
);
2292 MergeChange( mCursorPos
.mRow
, 2 );
2293 wxMessageBox( "Secarch string not found!" );
2295 GetActiveView()->SetFocus();
2300 bool wxTextEditorModel::OnFindPrevious()
2306 void wxTextEditorModel::OnGotoLine( int line
, int col
)
2308 if ( mpActiveView
== NULL
) return;
2310 TPosition pagePos
= mpActiveView
->GetPagePos();
2312 if ( line
>= pagePos
.mRow
&&
2313 line
< pagePos
.mRow
+ mRowsPerPage
)
2315 mCursorPos
.mRow
= (size_t)line
;
2316 mCursorPos
.mCol
= (size_t)col
;
2320 mCursorPos
.mCol
= 0;
2329 size_t third
= mRowsPerPage
/ 3;
2336 newTop
= line
- third
;
2339 mpActiveView
->ScrollView( (int)newTop
- (int)pagePos
.mRow
, -(int)pagePos
.mCol
);
2341 mCursorPos
.mRow
= line
;
2342 mCursorPos
.mCol
= col
;
2346 mCursorPos
.mCol
= 0;
2353 void wxTextEditorModel::OnGotoLine()
2355 wxTextEntryDialog
* dlg
=
2356 new wxTextEntryDialog( mpActiveView
, "Line number:", "Goto line", "" );
2360 while( dlg
->ShowModal() == wxID_OK
&& nTries
)
2365 sscanf( dlg
->GetValue(), "%d", &i
);
2369 wxMessageBox( "Please enter a number" );
2376 OnGotoLine( (size_t)(i
-1), 0 );
2382 GetActiveView()->SetFocus();
2386 bool wxTextEditorModel::IsReadOnly()
2391 bool wxTextEditorModel::IsModified()
2393 return mCurCommand
!= 0;
2396 bool wxTextEditorModel::IsInsertMode()
2401 void wxTextEditorModel::SetCheckpoint()
2403 mCheckPointDestroyed
= FALSE
;
2404 mCheckPointCmdNo
= mCurCommand
;
2407 bool wxTextEditorModel::CheckpointModified()
2409 if ( mCheckPointDestroyed
) return TRUE
;
2411 return mCheckPointCmdNo
!= mCurCommand
;
2414 TPosition
wxTextEditorModel::GetStartOfSelection()
2416 ArrangePositions( mSelectionStart
, mSelectionEnd
);
2418 return mSelectionStart
;
2421 TPosition
wxTextEditorModel::GetEndOfSelection()
2423 ArrangePositions( mSelectionStart
, mSelectionEnd
);
2425 return mSelectionEnd
;
2428 TPosition
wxTextEditorModel::GetCursor()
2433 void wxTextEditorModel::SetStartOfSelection( const TPosition
& pos
)
2435 mSelectionStart
= pos
;
2438 void wxTextEditorModel::SetEndOfSelection( const TPosition
& pos
)
2440 mSelectionEnd
= pos
;
2443 void wxTextEditorModel::SetCursor( const TPosition
& pos
)
2448 void wxTextEditorModel::AddView( wxTextEditorView
* pView
)
2450 mViews
.push_back( pView
);
2451 pView
->SetModel( this );
2454 void wxTextEditorModel::RemoveView( wxTextEditorView
* pView
)
2456 for( size_t i
= 0; i
!= mViews
.size(); ++i
)
2458 if ( mViews
[i
] == pView
)
2460 mViews
.erase( & mViews
[i
] );
2465 void wxTextEditorModel::SetActiveView( wxTextEditorView
* pView
)
2467 mpActiveView
= pView
;
2470 wxTextEditorView
* wxTextEditorModel::GetActiveView()
2472 return mpActiveView
;
2475 void wxTextEditorModel::SetRowsPerPage( size_t n
)
2480 void wxTextEditorModel::AddPin( TPinBase
* pPin
)
2482 // FIXME:: binary search should be used
2484 size_t beforePin
= FindNextPinFrom( pPin
->mRow
);
2486 if ( beforePin
!= NPOS
)
2488 // pins in the same row are ordered in the
2489 // descending order of their type-codes
2491 while( beforePin
< mPins
.size() &&
2492 mPins
[beforePin
]->mRow
== pPin
->mRow
&&
2493 mPins
[beforePin
]->mTypeCode
< pPin
->mTypeCode
)
2497 if ( beforePin
< mPins
.size() )
2499 mPins
.insert( &mPins
[beforePin
], pPin
);
2501 mPins
.push_back( pPin
);
2504 mPins
.push_back( pPin
);
2507 PinListT
& wxTextEditorModel::GetPins()
2512 size_t wxTextEditorModel::FindFirstPinInRange( size_t fromRow
, size_t tillRow
)
2514 // FIXME:: pefrom binary search instead
2516 for( size_t i
= 0; i
!= mPins
.size(); ++i
)
2518 TPinBase
& pin
= *mPins
[i
];
2520 if ( pin
.mRow
>= tillRow
) return NPOS
;
2522 if ( pin
.mRow
>= fromRow
)
2530 size_t wxTextEditorModel::FindNextPinFrom( size_t fromRow
)
2532 // FIXME:: pefrom binary search instead
2534 for( size_t i
= 0; i
!= mPins
.size(); ++i
)
2536 TPinBase
& pin
= *mPins
[i
];
2538 if ( pin
.mRow
>= fromRow
)
2547 size_t wxTextEditorModel::FindPreviousPinFrom( size_t fromRow
)
2549 // FIXME:: pefrom binary search instead
2551 if ( mPins
.size() == 0 ) return NPOS
;
2553 size_t i
= mPins
.size() - 1;
2557 TPinBase
& pin
= *mPins
[i
];
2559 if ( pin
.mRow
<= fromRow
)
2563 if ( i
== 0 ) break;
2571 size_t wxTextEditorModel::GetPinNoAt( size_t row
, int pinTypeCode
)
2573 size_t curPin
= FindNextPinFrom( row
);
2575 while( curPin
!= NPOS
)
2577 TPinBase
& pin
= *mPins
[curPin
];
2579 if ( pin
.mRow
> row
) return NPOS
;
2581 if ( pin
.mTypeCode
== pinTypeCode
) return curPin
;
2585 if ( curPin
== mPins
.size() ) return NPOS
;
2591 TPinBase
* wxTextEditorModel::GetPinAt( size_t row
, int pinTypeCode
)
2593 size_t pinNo
= GetPinNoAt( row
, pinTypeCode
);
2595 return ( pinNo
== NPOS
) ? NULL
: mPins
[pinNo
];
2598 void wxTextEditorModel::RemovePinAt( size_t row
, int pinTypeCode
)
2600 size_t pinNo
= GetPinNoAt( row
, pinTypeCode
);
2602 if ( pinNo
!= NPOS
)
2604 mPins
.erase( &mPins
[pinNo
] );
2607 void wxTextEditorModel::AddChangeListener( TTextChangeListenerBase
* pListener
)
2609 mChangeListeners
.push_back( pListener
);
2612 /***** Implementation for class wxTextEditorView *****/
2614 BEGIN_EVENT_TABLE( wxTextEditorView
, wxScrolledWindow
)
2616 EVT_SIZE ( wxTextEditorView::OnSize
)
2617 #if (( wxVERSION_NUMBER < 2100 ) || (( wxVERSION_NUMBER == 2100 ) && (wxBETA_NUMBER <= 4)))
2618 EVT_SCROLL( wxTextEditorView::OnScroll
)
2620 EVT_SCROLLWIN( wxTextEditorView::OnScroll
)
2622 EVT_PAINT ( wxTextEditorView::OnPaint
)
2624 EVT_LEFT_DOWN ( wxTextEditorView::OnLButtonDown
)
2625 EVT_LEFT_UP ( wxTextEditorView::OnLButtonUp
)
2626 EVT_MOTION ( wxTextEditorView::OnMotion
)
2627 EVT_LEFT_DCLICK( wxTextEditorView::OnDblClick
)
2629 EVT_SET_FOCUS ( wxTextEditorView::OnSetFocus
)
2630 EVT_KILL_FOCUS ( wxTextEditorView::OnKillFocus
)
2632 EVT_CHAR( wxTextEditorView::OnChar
)
2633 EVT_KEY_DOWN( wxTextEditorView::OnKeyDown
)
2635 EVT_ERASE_BACKGROUND( wxTextEditorView::OnEraseBackground
)
2640 TCursorTimer
* wxTextEditorView::mpTimer
= new TCursorTimer();
2642 wxTextEditorView::wxTextEditorView( wxWindow
* parent
,
2644 wxTextEditorModel
* pModel
,
2648 : wxScrolledWindow( parent
, id
, wxPoint(32768,32768), wxSize(0,0),
2649 wxHSCROLL
| wxVSCROLL
| wndStyle
2652 mDragStarted( FALSE
),
2653 mpDraggedText( NULL
),
2654 mAdjustScrollPending( FALSE
),
2658 mScrollingOn( TRUE
),
2660 mOwnsModel ( ownsModel
),
2662 mLastRowsTotal( (size_t)(-1) )
2668 SetSourcePainter( new SourcePainter() );
2670 mCashedIter
.mPos
= TPosition( (size_t)(-1), 0 );
2673 AddPinPainter( new TBookmarkPainter() );
2676 wxTextEditorView::~wxTextEditorView()
2678 if ( mpTimer
->GetView() == this &&
2679 mCursorOn
&& !mLTMode
)
2681 mpTimer
->SetView( NULL
);
2682 mpTimer
->HideCursor( TRUE
);
2685 if ( mOwnsModel
&& mpModel
)
2690 void wxTextEditorView::SetTextDefaults()
2697 mCharDim
.x
= -1; // not detected yet
2700 mNormalTextCol
= *wxBLACK
;
2701 mIndentifierTextCol
= *wxBLUE
;
2702 mReservedWordTextCol
= *wxRED
;
2703 mCommentTextCol
= wxColour( 0,128,128 );
2705 mNormalBkCol
= wxColour(255,255,255);//*wxWHITE;//wxColour( 128,220,128 );
2706 mSelectionFgCol
= wxColour(255,255,255);//*wxWHITE;
2707 mSelectionBkCol
= wxColour( 0,0,128 );
2709 mNormalBkBrush
= wxBrush( mNormalBkCol
, wxSOLID
);
2710 mSelectedBkBrush
= wxBrush( mSelectionBkCol
, wxSOLID
);
2712 #if defined(__WXMSW__) || defined(__WINDOWS__)
2713 mFont
.SetFaceName("Fixedsys");
2715 mFont
.SetWeight(40);
2716 mFont
.SetPointSize( 11);
2718 //mFont.SetFamily( wxSWISS );
2719 mFont
= wxSystemSettings::GetSystemFont(wxSYS_OEM_FIXED_FONT
);
2723 #if defined(__WXMSW__) || defined(__WINDOWS__)
2724 mFont
.RealizeResource();
2727 // reduce flicker un wxGtk
2728 SetBackgroundColour( mNormalBkCol
);
2731 void wxTextEditorView::SetColours( const wxColour
& normalBkCol
,
2732 const wxColour
& selectedBkCol
,
2733 const wxColour
& selectedTextCol
)
2735 mNormalBkCol
= normalBkCol
;
2736 mSelectionFgCol
= selectedTextCol
;
2737 mSelectionBkCol
= selectedBkCol
;
2739 mNormalBkBrush
= wxBrush( mNormalBkCol
, wxSOLID
);
2740 mSelectedBkBrush
= wxBrush( mSelectionBkCol
, wxSOLID
);
2743 void wxTextEditorView::SetHeighlightingColours( const wxColour
& normalTextCol
,
2744 const wxColour
& identifierTextCol
,
2745 const wxColour
& reservedWordTextCol
,
2746 const wxColour
& commentTextCol
)
2748 mNormalTextCol
= normalTextCol
;
2749 mIndentifierTextCol
= identifierTextCol
;
2750 mReservedWordTextCol
= reservedWordTextCol
;
2751 mCommentTextCol
= commentTextCol
;
2754 void wxTextEditorView::SetMargins( int top
, int left
, int bottom
, int right
)
2757 mRightMargin
= right
;
2759 mBottomMargin
= bottom
;
2762 void wxTextEditorView::RecalcPagingInfo()
2764 bool firstRefresh
= mCharDim
.x
== -1;
2768 ObtainFontProperties();
2771 GetClientSize( &w
, &h
);
2773 w
-= mLeftMargin
+ mRightMargin
;
2774 h
-= mTopMargin
+ mBottomMargin
;
2776 mColsPerPage
= ( ( w
/ mCharDim
.x
) +
2777 ( ( w
% mCharDim
.x
) ? 0 : 0 ) );
2780 mRowsPerPage
= ( ( h
/ mCharDim
.y
) +
2781 ( ( h
% mCharDim
.y
) ? 0 : 0 ) );
2783 if ( mpModel
->GetActiveView() == this )
2785 mpModel
->SetRowsPerPage( mRowsPerPage
);
2789 // scrolling should not happen at DC-level
2790 EnableScrolling( FALSE
, FALSE
);
2794 SetScrollbars( mCharDim
.x
, mCharDim
.y
,
2796 mpModel
->GetTotalRowCount(),
2806 #if (( wxVERSION_NUMBER < 2100 ) || (( wxVERSION_NUMBER == 2100 ) && (wxBETA_NUMBER <= 4)))
2807 // this changed in ver 2.1
2808 void wxTextEditorView::OnScroll( wxScrollEvent
& event
)
2810 void wxTextEditorView::OnScroll( wxScrollWinEvent
& event
)
2813 if ( !mScrollingOn
) return;
2815 // overriden implementation of wxScrolledWindow::OnScroll,
2816 // to reduce flicker on wxGtk, by using wxClientDC
2817 // instead of Refresh()
2819 int orient
= event
.GetOrientation();
2821 int nScrollInc
= CalcScrollInc(event
);
2822 if (nScrollInc
== 0) return;
2824 if (orient
== wxHORIZONTAL
)
2826 int newPos
= m_xScrollPosition
+ nScrollInc
;
2827 SetScrollPos(wxHORIZONTAL
, newPos
, TRUE
);
2831 int newPos
= m_yScrollPosition
+ nScrollInc
;
2832 SetScrollPos(wxVERTICAL
, newPos
, TRUE
);
2835 if (orient
== wxHORIZONTAL
)
2837 m_xScrollPosition
+= nScrollInc
;
2841 m_yScrollPosition
+= nScrollInc
;
2845 ViewStart( &x
, &y
);
2852 if ( mAdjustScrollPending
)
2854 mLastRowsTotal
= mpModel
->GetTotalRowCount();
2855 SetScrollbars( mCharDim
.x
, mCharDim
.y
,
2856 mMaxColumns
, // FOR NOW:: maximal line-length not calculated
2863 mLastViewStart
= mPagePos
;
2865 mAdjustScrollPending
= FALSE
;
2870 wxClientDC
dc( this );
2872 mFullRefreshPending
= TRUE
;
2874 PaintRows( mPagePos
.mRow
, mPagePos
.mRow
+ mRowsPerPage
, dc
);
2877 void wxTextEditorView::OnPaint( wxPaintEvent
& event
)
2879 //wxScrolledWindow::OnPaint( event );
2880 if ( mCharDim
.x
== -1 ) ObtainFontProperties();
2882 wxPaintDC
dc( this );
2884 mFullRefreshPending
= TRUE
;
2886 PaintRows( mPagePos
.mRow
, mPagePos
.mRow
+ mRowsPerPage
, dc
);
2889 void wxTextEditorView::OnSize( wxSizeEvent
& event
)
2898 void wxTextEditorView::OnEraseBackground( wxEraseEvent
& event
)
2903 GetClientSize( &w
, &h
);
2905 wxPaintDC
dc( this );
2907 dc
.SetPen( *wxTRANSPARENT_PEN
);
2908 dc
.SetBrush( *wxWHITE_BRUSH
);
2909 dc
.DrawRectangle( 0,0, w
,h
);
2913 void wxTextEditorView::OnLButtonDown( wxMouseEvent
& event
)
2915 if ( mDragStarted
) return;
2917 mDragStarted
= TRUE
;
2920 PixelsToTextPos( event
.m_x
, event
.m_y
, textPos
);
2922 mpModel
->SetSelectionEditMode( FALSE
);
2924 mpModel
->OnMoveToPosition( textPos
);
2926 mpModel
->SetSelectionEditMode( TRUE
);
2933 void wxTextEditorView::OnLButtonUp( wxMouseEvent
& event
)
2937 OnMotion( event
); // simulate last motion event
2939 mpModel
->SetSelectionEditMode( FALSE
);
2942 mDragStarted
= FALSE
;
2946 void wxTextEditorView::OnMotion( wxMouseEvent
& event
)
2952 if ( event
.m_y
< 0 && mpModel
->GetCursor().mRow
== 0 )
2956 PixelsToTextPos( event
.m_x
, event
.m_y
, textPos
);
2958 mpModel
->OnMoveToPosition( textPos
);
2962 void wxTextEditorView::OnDblClick( wxMouseEvent
& event
)
2965 mpModel
->OnSelectWord();
2968 void wxTextEditorView::OnSetFocus( wxFocusEvent
& event
)
2970 if ( !mLTMode
&& mCursorOn
)
2972 mpTimer
->SetView( this );
2973 mpTimer
->ShowCursor( TRUE
);
2977 void wxTextEditorView::OnKillFocus( wxFocusEvent
& event
)
2979 if ( !mLTMode
&& mCursorOn
)
2981 mpTimer
->HideCursor( TRUE
);
2982 mpTimer
->SetView( NULL
);
2986 void wxTextEditorView::HoldCursor( bool hold
)
2988 if ( mLTMode
|| !mCursorOn
) return;
2992 if ( wxWindow::FindFocus() != this )
2994 mpTimer
->HideCursor();
2995 mpTimer
->SetView( NULL
);
3000 mpTimer
->SetView( this );
3001 mpTimer
->ShowCursor();
3005 void wxTextEditorView::OnKeyDown( wxKeyEvent
& event
)
3007 // FOR NOW:: hard-coded key-bindings
3009 mpModel
->SetSelectionEditMode( event
.ShiftDown() );
3011 if ( event
.ControlDown() )
3013 if ( event
.m_keyCode
== WXK_LEFT
)
3015 mpModel
->OnWordLeft();
3017 if ( event
.m_keyCode
== WXK_RIGHT
)
3019 mpModel
->OnWordRight();
3021 if ( event
.m_keyCode
== WXK_UP
)
3023 mpModel
->OnSlideUp();
3025 if ( event
.m_keyCode
== WXK_DOWN
)
3027 mpModel
->OnSlideDown();
3029 if ( event
.m_keyCode
== WXK_HOME
)
3031 mpModel
->OnStartOfText();
3033 if ( event
.m_keyCode
== WXK_END
)
3035 mpModel
->OnEndOfText();
3037 if ( event
.m_keyCode
== WXK_INSERT
)
3045 if ( event.m_keyCode == WXK_NEXT )
3049 if ( event.m_keyCode == WXK_PRIOR )
3056 if ( event
.m_keyCode
== WXK_LEFT
)
3058 mpModel
->OnMoveLeft();
3060 if ( event
.m_keyCode
== WXK_RIGHT
)
3062 mpModel
->OnMoveRight();
3064 if ( event
.m_keyCode
== WXK_UP
)
3066 mpModel
->OnMoveUp();
3068 if ( event
.m_keyCode
== WXK_DOWN
)
3070 mpModel
->OnMoveDown();
3072 if ( event
.m_keyCode
== WXK_HOME
)
3074 mpModel
->OnStartOfLine();
3076 if ( event
.m_keyCode
== WXK_END
)
3078 mpModel
->OnEndOfLine();
3080 if ( event
.m_keyCode
== WXK_NEXT
)
3082 mpModel
->OnPageDown();
3084 if ( event
.m_keyCode
== WXK_PRIOR
)
3086 mpModel
->OnPageUp();
3088 if ( event
.m_keyCode
== WXK_DELETE
)
3090 mpModel
->OnDelete();
3092 if ( event
.m_keyCode
== WXK_INSERT
&& event
.ShiftDown() )
3100 void wxTextEditorView::OnChar( wxKeyEvent
& event
)
3102 if ( event
.ControlDown() )
3104 if ( event
.m_keyCode
== 'y' )
3106 mpModel
->OnDeleteLine();
3108 if ( event
.m_keyCode
== 'v' )
3112 if ( event
.m_keyCode
== 'c' )
3116 if ( event
.m_keyCode
== 'z' )
3120 if ( event
.m_keyCode
== 'a' )
3127 if ( event
.AltDown() )
3129 if ( event
.m_keyCode
== WXK_BACK
)
3136 if ( event
.m_keyCode
== WXK_BACK
)
3138 mpModel
->OnDeleteBack();
3140 if ( event
.m_keyCode
== WXK_TAB
&& event
.ShiftDown() )
3142 mpModel
->OnShiftSelectionIndent( TRUE
);
3145 if ( !mpModel
->SelectionIsEmpty() && event
.m_keyCode
== WXK_TAB
)
3147 mpModel
->OnShiftSelectionIndent( FALSE
);
3149 mpModel
->OnInsertChar( event
.m_keyCode
);
3153 void wxTextEditorView::SetModel( wxTextEditorModel
* pModel
)
3156 mSelectionStart
= pModel
->GetStartOfSelection();
3157 mSelectionEnd
= pModel
->GetEndOfSelection();
3158 mCursorPos
= pModel
->GetCursor();
3161 void wxTextEditorView::SetSourcePainter( SourcePainter
* pPainter
)
3163 mpPainter
= pPainter
;
3166 void wxTextEditorView::AddPinPainter( TPinPainterBase
* pPainter
)
3168 mPinPainters
.push_back( pPainter
);
3171 void wxTextEditorView::SetDefaultFont( const wxFont
& font
)
3175 #if defined(__WXMSW__) || defined(__WINDOWS__)
3176 mFont
.RealizeResource();
3185 void wxTextEditorView::SetRowsPerPage( size_t n
)
3187 mpModel
->SetRowsPerPage( n
);
3194 void wxTextEditorView::SetMaxColumns( size_t n
)
3202 wxFont
& wxTextEditorView::GetDefaultFont()
3207 void wxTextEditorView::SetLineTrackingMode( bool on
, const wxColour
& col
)
3212 if ( mpTimer
->GetView() == this )
3214 mpTimer
->HideCursor();
3217 void wxTextEditorView::EnableCursor( bool enable
)
3222 void wxTextEditorView::EnableScrollbars( bool enable
)
3224 mScrollingOn
= enable
;
3227 bool wxTextEditorView::IsActiveView()
3229 return this == mpModel
->GetActiveView();
3232 void wxTextEditorView::PositionCursor()
3234 if ( !IsActiveView() ||
3235 mLTMode
|| !mCursorOn
) return;
3237 mpTimer
->HideCursor();
3239 TextPosToScreenPos( mpModel
->GetCursor(), mCursorScrPos
);
3241 mpTimer
->ShowCursor();
3244 void wxTextEditorView::PixelsToScrPos( int x
, int y
, int& scrRow
, int& scrCol
)
3249 //if ( x < 0 ) x = 0; // FOR NOW:: horizontal auto-scroll disabled
3251 scrCol
= x
/ mCharDim
.x
;
3252 scrRow
= y
/ mCharDim
.y
;
3255 void wxTextEditorView::PixelsToTextPos( int x
, int y
, TPosition
& textPos
)
3257 int scrRow
= 0, scrCol
= 0;
3258 PixelsToScrPos( x
, y
, scrRow
, scrCol
);
3260 if ( scrRow
+ (int)mPagePos
.mRow
< 0 )
3262 scrRow
= -(int)mPagePos
.mRow
;
3264 if ( scrCol
+ (int)mPagePos
.mCol
< 0 )
3266 scrCol
= -(int)mPagePos
.mCol
;
3268 ScreenPosToTextPos( TPosition( scrRow
, scrCol
), textPos
);
3271 void wxTextEditorView::ScreenPosToPixels( const TPosition
& scrPos
, int& x
, int& y
)
3273 x
= mLeftMargin
+ scrPos
.mCol
* mCharDim
.x
;
3274 y
= mTopMargin
+ scrPos
.mRow
* mCharDim
.y
;
3277 void wxTextEditorView::TextPosToScreenPos( const TPosition
& txtPos
, TPosition
& scrPos
)
3281 if ( txtPos
.mRow
!= mCashedIter
.mPos
.mRow
)
3283 iter
= mpModel
->CreateIterator( txtPos
);
3289 iter
.mPos
.mCol
= txtPos
.mCol
;
3292 iter
.ToStartOfLine();
3297 while( !iter
.IsEol() && txtCol
< txtPos
.mCol
)
3299 if ( iter
.GetChar() == '\t' )
3301 size_t spacing
= ( (scrCol
/ mpModel
->mTabSize
) + 1 ) * mpModel
->mTabSize
- scrCol
;
3312 TPosition actualPos
= iter
.GetPosition();
3314 scrCol
+= txtPos
.mCol
- txtCol
;
3316 scrPos
.mRow
= actualPos
.mRow
- mPagePos
.mRow
;
3317 scrPos
.mCol
= scrCol
- mPagePos
.mCol
;
3320 void wxTextEditorView::ScreenPosToTextPos( const TPosition
& scrPos
, TPosition
& txtPos
)
3322 TPosition
absScrPos( scrPos
.mRow
+ mPagePos
.mRow
, scrPos
.mCol
+ mPagePos
.mCol
);
3324 TTextIterator iter
= mpModel
->CreateIterator( TPosition( absScrPos
.mRow
, 0 ) );
3329 // iterate over all possible on-screen positions, and find one which matches "absScrPos"
3331 while( !iter
.IsEol() && scrCol
< absScrPos
.mCol
)
3333 if ( iter
.GetChar() == '\t' )
3335 size_t spacing
= ( (scrCol
/ mpModel
->mTabSize
) + 1 ) * mpModel
->mTabSize
- scrCol
;
3346 TPosition actualPos
= iter
.GetPosition();
3348 if ( scrCol
== absScrPos
.mCol
)
3354 if ( scrCol
< absScrPos
.mCol
)
3356 // the absScrPos points past the eol
3359 txtPos
.mCol
+= absScrPos
.mCol
- scrCol
;
3362 if ( scrCol
> absScrPos
.mCol
)
3364 // there should have been a '\t' char, which made us jump too far forward
3371 bool wxTextEditorView::IsClipboardCmd( wxKeyEvent
& key
)
3373 if ( key
.ControlDown() && key
.m_keyCode
== WXK_CONTROL
)
3377 if ( key
.ShiftDown() && key
.m_keyCode
== WXK_SHIFT
)
3381 if ( key
.ControlDown() )
3383 return ( key
.m_keyCode
== 'C' ||
3384 key
.m_keyCode
== 'c' ||
3385 key
.m_keyCode
== WXK_INSERT
);
3391 void wxTextEditorView::ObtainFontProperties()
3393 wxClientDC
dc(this);
3394 dc
.SetFont( mFont
);
3398 dc
.GetTextExtent( "X", &w
, &h
);
3404 void wxTextEditorView::SyncViewPortPosition()
3407 TPosition pos
= mpModel
->GetCursor();
3409 TextPosToScreenPos( pos
, pos
);
3410 pos
.mRow
+= mPagePos
.mRow
;
3411 pos
.mCol
+= mPagePos
.mCol
;
3413 if ( pos
.mRow
< mPagePos
.mRow
)
3415 mPagePos
.mRow
= pos
.mRow
;
3416 mFullRefreshPending
= TRUE
;
3419 if ( pos
.mRow
>= mPagePos
.mRow
+ mRowsPerPage
&& mRowsPerPage
!= 0 )
3421 mPagePos
.mRow
= pos
.mRow
- mRowsPerPage
+ 1;
3422 mFullRefreshPending
= TRUE
;
3425 if ( pos
.mCol
< mPagePos
.mCol
)
3427 mPagePos
.mCol
= pos
.mCol
;
3428 mFullRefreshPending
= TRUE
;
3431 if ( pos
.mCol
>= mPagePos
.mCol
+ mColsPerPage
)
3433 mPagePos
.mCol
= pos
.mCol
- mColsPerPage
+ 1;
3434 mFullRefreshPending
= TRUE
;
3438 void wxTextEditorView::SyncScrollbars()
3440 if ( !mScrollingOn
) return;
3442 size_t nRows
= mpModel
->GetTotalRowCount();
3444 #if !defined(__WINDOWS__)
3446 if ( mLastViewStart
== mPagePos
)
3448 if ( mLastRowsTotal
!= nRows
)
3450 mAdjustScrollPending
= TRUE
;
3455 if ( mLastViewStart
== mPagePos
&&
3456 mLastRowsTotal
== nRows
)
3460 SetScrollbars( mCharDim
.x
, mCharDim
.y
,
3468 mLastViewStart
= mPagePos
;
3469 mLastRowsTotal
= nRows
;
3472 void wxTextEditorView::ScrollView( int rows
, int cols
)
3474 int pageRow
= (int)mPagePos
.mRow
;
3475 int pageCol
= (int)mPagePos
.mCol
;
3477 if ( pageRow
+ rows
< 0 )
3480 if ( pageRow
+ rows
> (int)mpModel
->GetTotalRowCount() )
3482 pageRow
= mpModel
->GetTotalRowCount();
3484 pageRow
= pageRow
+ rows
;
3486 mPagePos
.mRow
= (size_t)pageRow
;
3488 if ( pageCol
+ cols
< 0 )
3492 pageCol
= pageCol
+ cols
;
3494 mPagePos
.mCol
= pageCol
;
3496 mFullRefreshPending
= TRUE
;
3499 void wxTextEditorView::OnModelChanged()
3501 // invalidate pre-cached iterator
3502 mCashedIter
.mPos
= TPosition( (size_t)(-1), 0 );
3504 SyncViewPortPosition();
3506 if ( mLTMode
) mFullRefreshPending
= TRUE
;
3508 if ( mpModel
->mTextChanged
&& !mFullRefreshPending
)
3510 wxClientDC
dc( this );
3511 PaintRows( mpModel
->mChangedFromRow
, mpModel
->mChangedTillRow
, dc
);
3514 if ( mFullRefreshPending
)
3516 wxClientDC
dc( this );
3517 PaintRows( mPagePos
.mRow
, mPagePos
.mRow
+ mRowsPerPage
, dc
);
3520 if ( IsActiveView() )
3527 void wxTextEditorView::Activate()
3529 mpModel
->SetStartOfSelection( mSelectionStart
);
3530 mpModel
->SetEndOfSelection( mSelectionEnd
);
3531 mpModel
->SetCursor( mCursorPos
);
3533 mpModel
->SetRowsPerPage( mRowsPerPage
);
3535 if ( !mLTMode
&& mCursorOn
)
3537 mpTimer
->SetView( this );
3538 mpTimer
->ShowCursor();
3541 mpModel
->SetActiveView( this );
3544 void wxTextEditorView::Deactivate()
3546 mSelectionStart
= mpModel
->GetStartOfSelection();
3547 mSelectionEnd
= mpModel
->GetEndOfSelection();
3548 mCursorPos
= mpModel
->GetCursor();
3550 if ( mpTimer
->GetView() == this &&
3551 !mLTMode
&& mCursorOn
)
3553 mpTimer
->HideCursor( TRUE
);
3556 /*** protected methods ***/
3558 char* wxTextEditorView::mpLineBuffer
= NULL
;
3559 size_t wxTextEditorView::mpLineBufferLen
= 0;
3561 char* wxTextEditorView::GetLineBuffer( size_t len
)
3563 if ( mpLineBuffer
== NULL
|| mpLineBufferLen
< len
)
3565 if ( !mpLineBuffer
) mpModel
->FreeCharacters( mpLineBuffer
);
3567 mpLineBuffer
= mpModel
->AllocCharacters( len
);
3569 mpLineBufferLen
= len
;
3572 return mpLineBuffer
;
3575 TPinPainterBase
* wxTextEditorView::FindPainterForPin( TPinBase
& pin
)
3577 int pinTc
= pin
.mTypeCode
;
3579 for( size_t i
= 0; i
!= mPinPainters
.size(); ++i
)
3581 if ( mPinPainters
[i
]->mPinTypeCode
== pinTc
)
3583 return mPinPainters
[i
];
3588 void wxTextEditorView::PaintDecorations( size_t fromRow
,
3590 wxDC
& dc
, TTextIterator
& iter
)
3592 int dcY
= ( fromRow
- mPagePos
.mRow
) * mCharDim
.y
+ mTopMargin
;
3594 size_t curPin
= mpModel
->FindFirstPinInRange( fromRow
, tillRow
);
3596 PinListT
& pins
= mpModel
->GetPins();
3597 TPinPainterBase
* pPainter
= NULL
;
3599 size_t prevRow
= fromRow
;
3603 wxSize
dim( mLeftMargin
, mCharDim
.y
);
3605 while( curPin
!= NPOS
)
3607 TPinBase
& pin
= *pins
[curPin
];
3609 if ( pPainter
== NULL
||
3610 pPainter
->mPinTypeCode
!= pin
.mTypeCode
)
3612 pPainter
= FindPainterForPin( pin
);
3615 // only pins which have their painters can be "visualized"
3620 pos
.y
= ( pin
.mRow
- mPagePos
.mRow
)* mCharDim
.y
+ mTopMargin
;
3622 if ( prevRow
< pin
.mRow
)
3626 dc
.SetBrush( mNormalBkBrush
);
3627 dc
.SetPen( *wxTRANSPARENT_PEN
);
3628 dc
.DrawRectangle( 0, prevY
,
3630 mCharDim
.y
* ( pin
.mRow
- prevRow
) + 1 );
3633 pPainter
->DrawPin( &pin
, *this, dc
, pos
, dim
);
3635 prevRow
= pin
.mRow
+ 1;
3636 prevY
= pos
.y
+ mCharDim
.y
;
3641 if ( curPin
>= pins
.size() ||
3642 pins
[curPin
]->mRow
>= tillRow
)
3647 // fill the reminder
3649 if ( prevRow
< tillRow
)
3651 dc
.SetBrush( mNormalBkBrush
);
3652 dc
.SetPen( *wxTRANSPARENT_PEN
);
3653 dc
.DrawRectangle( 0, prevY
,
3655 mCharDim
.y
* ( tillRow
- prevRow
) + 1 );
3658 dc
.SetPen( *wxTRANSPARENT_PEN
);
3661 void wxTextEditorView::PaintRows( size_t fromRow
, size_t tillRow
, wxDC
& dc
)
3663 // NOTE:: raws are painted from "fromRow" but not including "tillRow" - [fromRow,tillRow)
3665 dc
.SetPen( *wxTRANSPARENT_PEN
);
3667 // how much on-screen columns are visable?
3669 size_t fromScrCol
= mPagePos
.mCol
;
3670 size_t tillScrCol
= fromScrCol
+ mColsPerPage
;
3672 TPosition selStart
= mpModel
->GetStartOfSelection();
3673 TPosition selEnd
= mpModel
->GetEndOfSelection();
3675 bool selectionIsEmpty
= ( selStart
== selEnd
);
3680 wxBrush
mLTBrush( mLTColour
, wxSOLID
);
3682 // clip given row-region to the current page
3684 if ( ( fromRow
>= mPagePos
.mRow
+ mRowsPerPage
) ||
3685 ( tillRow
<= mPagePos
.mRow
)
3690 if ( fromRow
< mPagePos
.mRow
) fromRow
= mPagePos
.mRow
;
3691 if ( tillRow
> mPagePos
.mRow
+ mRowsPerPage
) tillRow
= mPagePos
.mRow
+ mRowsPerPage
;
3693 if ( fromRow
>= tillRow
) return;
3695 // now start the renderng
3697 if ( mpTimer
->GetView() == this && mCursorOn
&& !mLTMode
)
3700 mpTimer
->SetIsShown( FALSE
);
3703 dc
.SetFont( mFont
);
3704 dc
.SetBackgroundMode( wxSOLID
);
3706 TTextIterator iter
= mpModel
->CreateIterator( TPosition( fromRow
, 0 ) );
3708 PaintDecorations( fromRow
, tillRow
, dc
, iter
);
3710 size_t cursorRow
= mpModel
->GetCursor().mRow
;
3712 size_t curRow
= fromRow
;
3713 for( ; curRow
!= tillRow
; ++curRow
)
3715 // place text into line-buffer
3717 iter
.ToStartOfLine();
3718 size_t lineLen
= iter
.GetLineLen();
3720 char* lineBuf
= GetLineBuffer( lineLen
+ 1 );
3724 while( !iter
.IsEof() && !iter
.IsEol() )
3726 lineBuf
[i
++] = iter
.GetChar();
3730 iter
.NextChar(); // skip eol
3732 // obtain "highlights"
3734 mpPainter
->SetState( FALSE
, FALSE
);
3735 mpPainter
->Init( FALSE
);
3736 mpPainter
->ProcessSource( lineBuf
, lineLen
);
3737 IntListT
& blocks
= mpPainter
->GetBlocks();
3741 int dcY
= ( curRow
- mPagePos
.mRow
) * mCharDim
.y
+ mTopMargin
;
3747 size_t curBlkCol
= 0;
3750 size_t chunkTxtStart
= 0;
3751 size_t chunkScrStart
= 0;
3753 // pre-detect occurance of selection
3755 bool lineHasSelection
= ( selStart
.mRow
== curRow
) ||
3756 ( selEnd
.mRow
== curRow
);
3758 bool isInSelection
= ( selStart
.mRow
<= curRow
) &&
3759 ( selEnd
.mRow
>= curRow
);
3761 if ( isInSelection
&& selStart
.mRow
== curRow
&&
3762 selStart
.mCol
!= 0 )
3764 isInSelection
= FALSE
;
3766 if ( selStart
== selEnd
)
3768 lineHasSelection
= FALSE
;
3769 isInSelection
= FALSE
;
3774 // loop though the text in this row
3778 TPosition
curPos( curRow
, txtCol
);
3780 // first check if we can finish the current chunk
3782 bool finishChunk
= FALSE
;
3784 if ( curBlk
< blocks
.size() &&
3785 curBlkCol
+ get_src_block_len( blocks
[curBlk
] ) == txtCol
)
3787 curBlkCol
+= get_src_block_len( blocks
[curBlk
] );
3792 if ( ( !selectionIsEmpty
&& ( curPos
== selStart
|| curPos
== selEnd
) )
3793 || lineBuf
[txtCol
] == '\t'
3794 || txtCol
== lineLen
)
3798 if ( finishChunk
&& chunkLen
!= -1 )
3800 // is any part of the chunk visable?
3802 size_t chunkScrEnd
= chunkScrStart
+ chunkLen
;
3804 if ( ( // if hits from one side or is inside
3805 ( chunkScrStart
>= fromScrCol
&&
3806 chunkScrStart
< tillScrCol
) ||
3807 ( chunkScrEnd
>= fromScrCol
&&
3808 chunkScrEnd
< tillScrCol
) ) ||
3810 // if overlaps the whole range
3811 ( chunkScrStart
< fromScrCol
&&
3812 chunkScrEnd
>= tillScrCol
)
3816 // render chunk data to the given DC
3818 dc
.SetTextForeground( curFgCol
);
3819 dc
.SetTextBackground( curBkCol
);
3823 if ( chunkScrStart
< fromScrCol
)
3825 size_t diff
= fromScrCol
- chunkScrStart
;
3827 chunkTxtStart
+= diff
;
3828 chunkScrStart
+= diff
;
3833 if ( chunkScrEnd
> tillScrCol
)
3835 size_t diff
= chunkScrEnd
- tillScrCol
;
3837 chunkScrEnd
-= diff
;
3842 char tmp
= lineBuf
[chunkTxtStart
+ chunkLen
];
3844 lineBuf
[chunkTxtStart
+ chunkLen
] = '\0';
3846 // use member-variable, reuse heap-buffer between outputs
3847 mFragment
= lineBuf
+ chunkTxtStart
;
3849 lineBuf
[chunkTxtStart
+ chunkLen
] = tmp
;
3853 int dcX
= (chunkScrStart
- fromScrCol
) * mCharDim
.x
+ mLeftMargin
;
3855 dc
.DrawText( mFragment
, dcX
, dcY
);
3860 } // end of "if ( finishChunk )"
3862 if ( txtCol
== lineLen
)
3865 if ( chunkLen
== -1 )
3867 // prepare the new chunk
3869 if ( curBlk
< blocks
.size() )
3871 switch( get_src_block_rank( blocks
[curBlk
] ) )
3873 case RANK_BLACK
: curFgCol
= mNormalTextCol
; break;
3874 case RANK_BLUE
: curFgCol
= mIndentifierTextCol
; break;
3875 case RANK_RED
: curFgCol
= mReservedWordTextCol
; break;
3876 case RANK_GREEN
: curFgCol
= mCommentTextCol
; break;
3881 // track occurence of selection
3883 if ( lineHasSelection
)
3885 isInSelection
= TRUE
;
3887 if ( selEnd
.mRow
== curRow
&&
3888 selEnd
.mCol
<= txtCol
)
3890 isInSelection
= FALSE
;
3892 if ( selStart
.mRow
== curRow
&&
3893 selStart
.mCol
> txtCol
)
3895 isInSelection
= FALSE
;
3898 if ( isInSelection
)
3900 curFgCol
= mSelectionFgCol
;
3901 curBkCol
= mSelectionBkCol
;
3905 if ( mLTMode
&& curRow
== cursorRow
)
3907 curBkCol
= mLTColour
;
3909 curBkCol
= mNormalBkCol
;
3912 chunkScrStart
= scrCol
;
3913 chunkTxtStart
= txtCol
;
3918 ch
= lineBuf
[txtCol
];
3922 // tab's are treated specially (for simplicity and speed)
3924 int dcX
= (chunkScrStart
- fromScrCol
) * mCharDim
.x
+ mLeftMargin
;
3926 if ( !isInSelection
)
3928 if ( mLTMode
&& curRow
== cursorRow
)
3930 dc
.SetBrush( mLTBrush
);
3932 dc
.SetBrush( mNormalBkBrush
);
3934 else dc
.SetBrush( mSelectedBkBrush
);
3936 // *** "the rule of TAB..." ***
3938 size_t spacing
= ( (scrCol
/ mpModel
->mTabSize
) + 1 ) * mpModel
->mTabSize
- scrCol
;
3940 int width
= spacing
* mCharDim
.x
+ 1;
3942 if ( dcX
< mLeftMargin
)
3944 width
-= mLeftMargin
- dcX
;
3951 dc
.DrawRectangle( dcX
, dcY
, width
, mCharDim
.y
+ 1 );
3956 // move chunk-start forward, after the occurance of '\t'
3962 // increase on-screen/in-text positions
3971 // fill the reminding white-space after eol
3973 if ( scrCol
< tillScrCol
&&
3975 ( isInSelection
&& curRow
== selEnd
.mRow
) )
3978 if ( scrCol
< fromScrCol
) scrCol
= fromScrCol
;
3980 int dcX
= ( scrCol
- fromScrCol
) * mCharDim
.x
+ mLeftMargin
;
3982 if ( mLTMode
&& curRow
== cursorRow
)
3984 dc
.SetBrush ( mLTBrush
);
3986 dc
.SetBrush( mNormalBkBrush
);
3988 dc
.DrawRectangle( dcX
, dcY
,
3989 mCharDim
.x
* ( tillScrCol
- scrCol
) + 1,
3993 // render selection which is located past the eol
3995 if ( ( lineHasSelection
|| isInSelection
) &&
3996 !( selEnd
.mRow
== curRow
&& selEnd
.mCol
<= txtCol
)
3999 // determine start of selection on-screen
4001 size_t scrSelStart
= scrCol
+ ( selStart
.mCol
- txtCol
);
4003 if ( isInSelection
)
4005 scrSelStart
= scrCol
;
4007 size_t scrSelEnd
= tillScrCol
;
4009 if ( selEnd
.mRow
== curRow
)
4011 scrSelEnd
= scrCol
+ ( selEnd
.mCol
- txtCol
);
4015 if ( scrSelStart
< fromScrCol
) scrSelStart
= fromScrCol
;
4016 if ( scrSelEnd
> tillScrCol
) scrSelEnd
= tillScrCol
;
4020 if ( scrSelEnd
> scrSelStart
)
4022 int dcX
= ( scrSelStart
- fromScrCol
) * mCharDim
.x
+ mLeftMargin
;
4024 dc
.SetBrush( mSelectedBkBrush
);
4025 dc
.DrawRectangle( dcX
, dcY
,
4026 mCharDim
.x
* ( scrSelEnd
- scrSelStart
) + 1,
4037 } // end of "for(...)"
4039 if ( curRow
< tillRow
)
4041 dc
.SetBrush( mNormalBkBrush
);
4043 int dcY
= mTopMargin
+ (curRow
- mPagePos
.mRow
)*mCharDim
.y
;
4044 int dcX
= mLeftMargin
;
4046 dc
.DrawRectangle( dcX
, dcY
, mColsPerPage
*mCharDim
.x
+ 1,
4047 ( tillRow
- curRow
) * mCharDim
.y
+ 1
4051 if ( mFullRefreshPending
)
4053 dc
.SetBrush( mNormalBkBrush
);
4055 // fill in "corners" which are never reached by characters
4058 GetClientSize( &w
, &h
);
4060 dc
.SetBrush( mNormalBkBrush
);
4062 int dcX
= tillScrCol
*mCharDim
.x
+ mLeftMargin
;
4064 dc
.DrawRectangle( dcX
, mTopMargin
, w
- dcX
+ 1, h
);
4066 int dcY
= mTopMargin
+ mRowsPerPage
*mCharDim
.y
;
4068 dc
.DrawRectangle( 0, dcY
, w
, h
- dcY
+ 2 );
4072 // any past-the-eof lines left at the bottom?
4075 mFullRefreshPending
= FALSE
;
4077 if ( mpTimer
->GetView() == this && mCursorOn
&& !mLTMode
)
4081 } // end of PaintRows(..)
4083 /***** Implementation for class TBookmarkPainter *****/
4085 TBookmarkPainter::TBookmarkPainter()
4087 : TPinPainterBase( BOOKMARK_PIN_TC
),
4088 mBkBrush( wxColour( 0,255,255 ), wxSOLID
)
4092 void TBookmarkPainter::DrawPin( TPinBase
* pPin
, wxTextEditorView
& view
, wxDC
& dc
,
4093 const wxPoint
& pos
, const wxSize
& dim
)
4095 dc
.SetPen( *wxBLACK_PEN
);
4096 dc
.SetBrush( mBkBrush
);
4097 dc
.DrawRoundedRectangle( pos
.x
+2, pos
.y
, dim
.x
-4, dim
.y
, 4 );
4100 /***** Implementation for class TBreakpointPainter *****/
4102 TBreakpointPainter::TBreakpointPainter()
4104 : TPinPainterBase( BRKPOINT_PIN_TC
),
4105 mBkBrush( wxColour( 196,0,0 ), wxSOLID
)
4109 void TBreakpointPainter::DrawPin( TPinBase
* pPin
, wxTextEditorView
& view
, wxDC
& dc
,
4110 const wxPoint
& pos
, const wxSize
& dim
)
4112 dc
.SetPen( *wxBLACK_PEN
);
4113 dc
.SetBrush( mBkBrush
);
4114 dc
.DrawRoundedRectangle( pos
.x
+6, pos
.y
+2, dim
.x
-12, dim
.y
-4, 30 );
4117 /***** Implementation for class TCursorTimer *****/
4119 TCursorTimer::TCursorTimer()
4121 : mIsLocked( FALSE
),
4123 mBlinkInterval( 500 ),
4124 mBrush( wxColour(0,0,0), wxSOLID
),
4125 mMissOneTick( FALSE
)
4129 void TCursorTimer::Notify()
4131 if ( mIsLocked
) return;
4135 // this trick is used because it's not
4136 // possible to restart the timer under wxGtk
4138 mMissOneTick
= FALSE
;
4147 mIsShown
= !mIsShown
;
4152 void TCursorTimer::SetView( wxTextEditorView
* pView
)
4157 wxTextEditorView
* TCursorTimer::GetView()
4163 void TCursorTimer::HideCursor( bool forceHide
)
4176 void TCursorTimer::ShowCursor( bool forceShow
)
4186 mMissOneTick
= TRUE
;
4193 Start( mBlinkInterval
);
4198 void TCursorTimer::Lock()
4200 // while( mIsLocked );
4205 void TCursorTimer::Unlock()
4210 void TCursorTimer::SetIsShown( bool isShown
)
4215 /*** protected methods ***/
4217 void TCursorTimer::DrawCursor()
4219 if ( mpView
== NULL
) return;
4221 wxClientDC
dc( mpView
);
4225 mpView
->ScreenPosToPixels( mpView
->mCursorScrPos
, x
, y
);
4227 dc
.SetLogicalFunction( wxINVERT
);
4228 dc
.SetBrush( mBrush
);
4230 dc
.SetPen( *wxTRANSPARENT_PEN
);
4231 dc
.DrawRectangle( x
,y
, 3, mpView
->mCharDim
.y
+ 1 );
4232 dc
.SetBackgroundMode( wxSOLID
);