1 // TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2003-2013 - TortoiseSVN
4 // Copyright (C) 2011-2012 Sven Strickroth <email@cs-ware.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "TortoiseMerge.h"
26 #include "DiffColors.h"
27 #include "StringUtils.h"
29 #include "GotoLineDlg.h"
32 // We use three different kind of lines here:
33 // 1. The real lines of the original files.
34 // These are shown in the view margin and are not used elsewhere, they're only for user information.
36 // The lines actually shown on screen. All methods use screen lines as parameters/outputs if not explicitly specified otherwise.
38 // These are the lines of the diff data. If unmodified sections are collapsed, not all of those lines are shown.
40 // Basically view lines are the line data, while screen lines are shown lines.
47 #define MARGINWIDTH 20
48 #define HEADERHEIGHT 10
50 #define IDT_SCROLLTIMER 101
52 CBaseView
* CBaseView::m_pwndLeft
= NULL
;
53 CBaseView
* CBaseView::m_pwndRight
= NULL
;
54 CBaseView
* CBaseView::m_pwndBottom
= NULL
;
55 CLocatorBar
* CBaseView::m_pwndLocator
= NULL
;
56 CLineDiffBar
* CBaseView::m_pwndLineDiffBar
= NULL
;
57 CMFCStatusBar
* CBaseView::m_pwndStatusBar
= NULL
;
58 CMainFrame
* CBaseView::m_pMainFrame
= NULL
;
59 CBaseView::Screen2View
CBaseView::m_Screen2View
;
60 const UINT
CBaseView::m_FindDialogMessage
= RegisterWindowMessage(FINDMSGSTRING
);
62 allviewstate
CBaseView::m_AllState
;
64 IMPLEMENT_DYNCREATE(CBaseView
, CView
)
66 CBaseView::CBaseView()
67 : m_pCacheBitmap(NULL
)
69 , m_pOtherViewData(NULL
)
74 , m_nLastScreenChars(-1)
75 , m_nMaxLineLength(-1)
81 , m_mouseInMargin(false)
83 , lineendings(EOL_AUTOLINE
)
85 , m_bReadonlyIsChangable(false)
88 , m_nSelViewBlockStart(-1)
89 , m_nSelViewBlockEnd(-1)
91 , m_bShowSelection(true)
92 , texttype(CFileTextLines::AUTOTYPE
)
94 , m_bOtherDiffChecked(false)
95 , m_bInlineWordDiff(true)
96 , m_bWhitespaceInlineDiffs(false)
100 , m_bMatchCase(false)
101 , m_bLimitToDiff(true)
102 , m_bWholeWord(false)
104 , m_pWorkingFile(NULL
)
106 m_ptCaretViewPos
.x
= 0;
107 m_ptCaretViewPos
.y
= 0;
108 m_ptSelectionViewPosStart
= m_ptCaretViewPos
;
109 m_ptSelectionViewPosEnd
= m_ptSelectionViewPosStart
;
110 m_ptSelectionViewPosOrigin
= m_ptSelectionViewPosEnd
;
111 m_bViewWhitespace
= CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
112 m_bViewLinenumbers
= CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewLinenumbers"), 1);
113 m_bShowInlineDiff
= CRegDWORD(_T("Software\\TortoiseGitMerge\\DisplayBinDiff"), TRUE
);
114 m_nInlineDiffMaxLineLength
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineDiffMaxLineLength"), 3000);
115 m_InlineAddedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineAdded"), INLINEADDED_COLOR
);
116 m_InlineRemovedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineRemoved"), INLINEREMOVED_COLOR
);
117 m_ModifiedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\ColorModifiedB"), MODIFIED_COLOR
);
118 m_WhiteSpaceFg
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\Whitespace"), GetSysColor(COLOR_GRAYTEXT
));
119 m_sWordSeparators
= CRegString(_T("Software\\TortoiseGitMerge\\WordSeparators"), _T("[]();:.,{}!@#$%^&*-+=|/\\<>'`~\""));
120 m_bIconLFs
= CRegDWORD(_T("Software\\TortoiseGitMerge\\IconLFs"), 0);
121 m_nTabSize
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabSize"), 4);
122 std::fill_n(m_apFonts
, fontsCount
, (CFont
*)NULL
);
123 m_hConflictedIcon
= LoadIcon(IDI_CONFLICTEDLINE
);
124 m_hConflictedIgnoredIcon
= LoadIcon(IDI_CONFLICTEDIGNOREDLINE
);
125 m_hRemovedIcon
= LoadIcon(IDI_REMOVEDLINE
);
126 m_hAddedIcon
= LoadIcon(IDI_ADDEDLINE
);
127 m_hWhitespaceBlockIcon
= LoadIcon(IDI_WHITESPACELINE
);
128 m_hEqualIcon
= LoadIcon(IDI_EQUALLINE
);
129 m_hLineEndingCR
= LoadIcon(IDI_LINEENDINGCR
);
130 m_hLineEndingCRLF
= LoadIcon(IDI_LINEENDINGCRLF
);
131 m_hLineEndingLF
= LoadIcon(IDI_LINEENDINGLF
);
132 m_hEditedIcon
= LoadIcon(IDI_LINEEDITED
);
133 m_hMovedIcon
= LoadIcon(IDI_MOVEDLINE
);
134 m_margincursor
= (HCURSOR
)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDC_MARGINCURSOR
), IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
);
136 for (int i
=0; i
<1024; ++i
)
137 m_sConflictedText
+= _T("??");
138 m_sNoLineNr
.LoadString(IDS_EMPTYLINETT
);
142 SecureZeroMemory(&m_lfBaseFont
, sizeof(m_lfBaseFont
));
146 CBaseView::~CBaseView()
150 DestroyIcon(m_hAddedIcon
);
151 DestroyIcon(m_hRemovedIcon
);
152 DestroyIcon(m_hConflictedIcon
);
153 DestroyIcon(m_hConflictedIgnoredIcon
);
154 DestroyIcon(m_hWhitespaceBlockIcon
);
155 DestroyIcon(m_hEqualIcon
);
156 DestroyIcon(m_hLineEndingCR
);
157 DestroyIcon(m_hLineEndingCRLF
);
158 DestroyIcon(m_hLineEndingLF
);
159 DestroyIcon(m_hEditedIcon
);
160 DestroyIcon(m_hMovedIcon
);
161 DestroyCursor(m_margincursor
);
164 BEGIN_MESSAGE_MAP(CBaseView
, CView
)
177 ON_COMMAND(ID_NAVIGATE_NEXTDIFFERENCE
, OnMergeNextdifference
)
178 ON_COMMAND(ID_NAVIGATE_PREVIOUSDIFFERENCE
, OnMergePreviousdifference
)
179 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW
, 0, 0xFFFF, OnToolTipNotify
)
180 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA
, 0, 0xFFFF, OnToolTipNotify
)
183 ON_COMMAND(ID_EDIT_COPY
, OnEditCopy
)
185 ON_COMMAND(ID_NAVIGATE_PREVIOUSCONFLICT
, OnMergePreviousconflict
)
186 ON_COMMAND(ID_NAVIGATE_NEXTCONFLICT
, OnMergeNextconflict
)
188 ON_COMMAND(ID_CARET_DOWN
, &CBaseView::OnCaretDown
)
189 ON_COMMAND(ID_CARET_LEFT
, &CBaseView::OnCaretLeft
)
190 ON_COMMAND(ID_CARET_RIGHT
, &CBaseView::OnCaretRight
)
191 ON_COMMAND(ID_CARET_UP
, &CBaseView::OnCaretUp
)
192 ON_COMMAND(ID_CARET_WORDLEFT
, &CBaseView::OnCaretWordleft
)
193 ON_COMMAND(ID_CARET_WORDRIGHT
, &CBaseView::OnCaretWordright
)
194 ON_COMMAND(ID_EDIT_CUT
, &CBaseView::OnEditCut
)
195 ON_COMMAND(ID_EDIT_PASTE
, &CBaseView::OnEditPaste
)
197 ON_WM_LBUTTONDBLCLK()
198 ON_COMMAND(ID_NAVIGATE_NEXTINLINEDIFF
, &CBaseView::OnNavigateNextinlinediff
)
199 ON_COMMAND(ID_NAVIGATE_PREVINLINEDIFF
, &CBaseView::OnNavigatePrevinlinediff
)
200 ON_COMMAND(ID_EDIT_SELECTALL
, &CBaseView::OnEditSelectall
)
201 ON_COMMAND(ID_EDIT_FIND
, OnEditFind
)
202 ON_REGISTERED_MESSAGE(m_FindDialogMessage
, OnFindDialogMessage
)
203 ON_COMMAND(ID_EDIT_FINDNEXT
, OnEditFindnext
)
204 ON_COMMAND(ID_EDIT_FINDPREV
, OnEditFindprev
)
205 ON_COMMAND(ID_EDIT_FINDNEXTSTART
, OnEditFindnextStart
)
206 ON_COMMAND(ID_EDIT_FINDPREVSTART
, OnEditFindprevStart
)
207 ON_COMMAND(ID_EDIT_GOTOLINE
, &CBaseView::OnEditGotoline
)
212 void CBaseView::DocumentUpdated()
218 m_nLastScreenChars
= -1;
219 m_nMaxLineLength
= -1;
223 m_bOtherDiffChecked
= false;
226 m_nTabSize
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabSize"), 4);
227 m_bViewLinenumbers
= CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewLinenumbers"), 1);
228 m_InlineAddedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineAdded"), INLINEADDED_COLOR
);
229 m_InlineRemovedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineRemoved"), INLINEREMOVED_COLOR
);
230 m_ModifiedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\ColorModifiedB"), MODIFIED_COLOR
);
231 m_WhiteSpaceFg
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\Whitespace"), GetSysColor(COLOR_GRAYTEXT
));
232 m_bIconLFs
= CRegDWORD(_T("Software\\TortoiseGitMerge\\IconLFs"), 0);
233 m_nInlineDiffMaxLineLength
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineDiffMaxLineLength"), 3000);
235 ClearCurrentSelection();
240 void CBaseView::UpdateStatusBar()
242 int nRemovedLines
= 0;
244 int nConflictedLines
= 0;
248 for (int i
=0; i
<m_pViewData
->GetCount(); i
++)
250 DiffStates state
= m_pViewData
->GetState(i
);
253 case DIFFSTATE_ADDED
:
254 case DIFFSTATE_IDENTICALADDED
:
255 case DIFFSTATE_MOVED_TO
:
256 case DIFFSTATE_THEIRSADDED
:
257 case DIFFSTATE_YOURSADDED
:
258 case DIFFSTATE_CONFLICTADDED
:
261 case DIFFSTATE_IDENTICALREMOVED
:
262 case DIFFSTATE_REMOVED
:
263 case DIFFSTATE_MOVED_FROM
:
264 case DIFFSTATE_THEIRSREMOVED
:
265 case DIFFSTATE_YOURSREMOVED
:
268 case DIFFSTATE_CONFLICTED
:
269 case DIFFSTATE_CONFLICTED_IGNORED
:
281 case CFileTextLines::ASCII
:
282 sBarText
= _T("ASCII ");
284 case CFileTextLines::BINARY
:
285 sBarText
= _T("BINARY ");
287 case CFileTextLines::UTF16_LE
:
288 sBarText
= _T("UTF-16LE ");
290 case CFileTextLines::UTF16_BE
:
291 sBarText
= _T("UTF-16BE ");
293 case CFileTextLines::UTF32_LE
:
294 sBarText
= _T("UTF-32LE ");
296 case CFileTextLines::UTF32_BE
:
297 sBarText
= _T("UTF-32BE ");
299 case CFileTextLines::UTF8
:
300 sBarText
= _T("UTF8 ");
302 case CFileTextLines::UTF8BOM
:
303 sBarText
= _T("UTF8 BOM ");
310 sBarText
+= _T("LF ");
313 sBarText
+= _T("CRLF ");
316 sBarText
+= _T("LFCR ");
319 sBarText
+= _T("CR ");
322 sBarText
+= _T("VT ");
325 sBarText
+= _T("FF ");
328 sBarText
+= _T("NEL ");
331 sBarText
+= _T("LS ");
334 sBarText
+= _T("PS ");
338 sBarText
+= _T("AEOL ");
343 if (sBarText
.IsEmpty())
344 sBarText
+= _T(" / ");
348 sTemp
.Format(IDS_STATUSBAR_REMOVEDLINES
, nRemovedLines
);
349 if (!sBarText
.IsEmpty())
350 sBarText
+= _T(" / ");
355 sTemp
.Format(IDS_STATUSBAR_ADDEDLINES
, nAddedLines
);
356 if (!sBarText
.IsEmpty())
357 sBarText
+= _T(" / ");
360 if (nConflictedLines
)
362 sTemp
.Format(IDS_STATUSBAR_CONFLICTEDLINES
, nConflictedLines
);
363 if (!sBarText
.IsEmpty())
364 sBarText
+= _T(" / ");
372 int nIndex
= m_pwndStatusBar
->CommandToIndex(m_nStatusBarID
);
373 if (m_nStatusBarID
== ID_INDICATOR_BOTTOMVIEW
)
375 sBarText
.Format(IDS_STATUSBAR_CONFLICTS
, nConflictedLines
);
377 if (m_nStatusBarID
== ID_INDICATOR_LEFTVIEW
)
379 sTemp
.LoadString(IDS_STATUSBAR_LEFTVIEW
);
380 sBarText
= sTemp
+sBarText
;
382 if (m_nStatusBarID
== ID_INDICATOR_RIGHTVIEW
)
384 sTemp
.LoadString(IDS_STATUSBAR_RIGHTVIEW
);
385 sBarText
= sTemp
+sBarText
;
387 m_pwndStatusBar
->GetPaneInfo(nIndex
, nID
, nStyle
, cxWidth
);
388 //calculate the width of the text
389 CDC
* pDC
= m_pwndStatusBar
->GetDC();
392 CSize size
= pDC
->GetTextExtent(sBarText
);
393 m_pwndStatusBar
->SetPaneInfo(nIndex
, nID
, nStyle
, size
.cx
+2);
396 m_pwndStatusBar
->SetPaneText(nIndex
, sBarText
);
400 BOOL
CBaseView::PreCreateWindow(CREATESTRUCT
& cs
)
402 if (!CView::PreCreateWindow(cs
))
405 cs
.dwExStyle
|= WS_EX_CLIENTEDGE
;
406 cs
.style
&= ~WS_BORDER
;
407 cs
.lpszClass
= AfxRegisterWndClass(CS_HREDRAW
|CS_VREDRAW
|CS_DBLCLKS
,
408 ::LoadCursor(NULL
, IDC_ARROW
), reinterpret_cast<HBRUSH
>(COLOR_WINDOW
+1), NULL
);
410 CWnd
*pParentWnd
= CWnd::FromHandlePermanent(cs
.hwndParent
);
411 if (pParentWnd
== NULL
|| ! pParentWnd
->IsKindOf(RUNTIME_CLASS(CSplitterWnd
)))
413 // View must always create its own scrollbars,
414 // if only it's not used within splitter
415 cs
.style
|= (WS_HSCROLL
| WS_VSCROLL
);
417 cs
.lpszClass
= AfxRegisterWndClass(CS_DBLCLKS
);
421 CFont
* CBaseView::GetFont(BOOL bItalic
/*= FALSE*/, BOOL bBold
/*= FALSE*/)
428 if (m_apFonts
[nIndex
] == NULL
)
430 m_apFonts
[nIndex
] = new CFont
;
431 m_lfBaseFont
.lfCharSet
= DEFAULT_CHARSET
;
432 m_lfBaseFont
.lfWeight
= bBold
? FW_BOLD
: FW_NORMAL
;
433 m_lfBaseFont
.lfItalic
= (BYTE
) bItalic
;
437 m_lfBaseFont
.lfHeight
= -MulDiv((DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\LogFontSize"), 10), GetDeviceCaps(pDC
->m_hDC
, LOGPIXELSY
), 72);
440 _tcsncpy_s(m_lfBaseFont
.lfFaceName
, (LPCTSTR
)(CString
)CRegString(_T("Software\\TortoiseGitMerge\\LogFontName"), _T("Courier New")), 32);
441 if (!m_apFonts
[nIndex
]->CreateFontIndirect(&m_lfBaseFont
))
443 delete m_apFonts
[nIndex
];
444 m_apFonts
[nIndex
] = NULL
;
445 return CView::GetFont();
448 return m_apFonts
[nIndex
];
451 void CBaseView::CalcLineCharDim()
456 CFont
*pOldFont
= pDC
->SelectObject(GetFont());
457 const CSize szCharExt
= pDC
->GetTextExtent(_T("X"));
458 pDC
->SelectObject(pOldFont
);
461 m_nLineHeight
= szCharExt
.cy
;
462 if (m_nLineHeight
<= 0)
464 m_nCharWidth
= szCharExt
.cx
;
465 if (m_nCharWidth
<= 0)
469 int CBaseView::GetScreenChars()
471 if (m_nScreenChars
== -1)
474 GetClientRect(&rect
);
475 m_nScreenChars
= (rect
.Width() - GetMarginWidth() - GetSystemMetrics(SM_CXVSCROLL
)) / GetCharWidth();
476 if (m_nScreenChars
< 0)
479 return m_nScreenChars
;
482 int CBaseView::GetAllMinScreenChars() const
484 int nChars
= INT_MAX
;
485 if (IsLeftViewGood())
486 nChars
= std::min
<int>(nChars
, m_pwndLeft
->GetScreenChars());
487 if (IsRightViewGood())
488 nChars
= std::min
<int>(nChars
, m_pwndRight
->GetScreenChars());
489 if (IsBottomViewGood())
490 nChars
= std::min
<int>(nChars
, m_pwndBottom
->GetScreenChars());
491 return (nChars
==INT_MAX
) ? 0 : nChars
;
494 int CBaseView::GetAllMaxLineLength() const
497 if (IsLeftViewGood())
498 nLength
= std::max
<int>(nLength
, m_pwndLeft
->GetMaxLineLength());
499 if (IsRightViewGood())
500 nLength
= std::max
<int>(nLength
, m_pwndRight
->GetMaxLineLength());
501 if (IsBottomViewGood())
502 nLength
= std::max
<int>(nLength
, m_pwndBottom
->GetMaxLineLength());
506 int CBaseView::GetLineHeight()
508 if (m_nLineHeight
== -1)
510 if (m_nLineHeight
<= 0)
512 return m_nLineHeight
;
515 int CBaseView::GetCharWidth()
517 if (m_nCharWidth
== -1)
519 if (m_nCharWidth
<= 0)
524 int CBaseView::GetMaxLineLength()
526 if (m_nMaxLineLength
== -1)
528 m_nMaxLineLength
= 0;
529 int nLineCount
= GetLineCount();
530 for (int i
=0; i
<nLineCount
; i
++)
532 int nActualLength
= GetLineLength(i
);
533 if (m_nMaxLineLength
< nActualLength
)
534 m_nMaxLineLength
= nActualLength
;
537 return m_nMaxLineLength
;
540 int CBaseView::GetLineLength(int index
)
542 if (m_pViewData
== NULL
)
544 if (m_pViewData
->GetCount() == 0)
546 if ((int)m_Screen2View
.size() <= index
)
548 int viewLine
= GetViewLineForScreen(index
);
549 if (m_pMainFrame
->m_bWrapLines
)
551 int nLineLength
= GetLineChars(index
).GetLength();
552 ASSERT(nLineLength
>= 0);
555 int nLineLength
= m_pViewData
->GetLine(viewLine
).GetLength();
556 ASSERT(nLineLength
>= 0);
560 int CBaseView::GetViewLineLength(int nViewLine
) const
562 if (m_pViewData
== NULL
)
564 if (m_pViewData
->GetCount() <= nViewLine
)
566 int nLineLength
= m_pViewData
->GetLine(nViewLine
).GetLength();
567 ASSERT(nLineLength
>= 0);
571 int CBaseView::GetLineCount() const
573 if (m_pViewData
== NULL
)
575 int nLineCount
= (int)m_Screen2View
.size();
576 ASSERT(nLineCount
>= 0);
580 int CBaseView::GetSubLineOffset(int index
)
582 return m_Screen2View
.GetSubLineOffset(index
);
585 CString
CBaseView::GetViewLineChars(int nViewLine
) const
587 if (m_pViewData
== NULL
)
589 if (m_pViewData
->GetCount() <= nViewLine
)
591 return m_pViewData
->GetLine(nViewLine
);
594 CString
CBaseView::GetLineChars(int index
)
596 if (m_pViewData
== NULL
)
598 if (m_pViewData
->GetCount() == 0)
600 if ((int)m_Screen2View
.size() <= index
)
602 int viewLine
= GetViewLineForScreen(index
);
603 if (m_pMainFrame
->m_bWrapLines
)
605 int subLine
= GetSubLineOffset(index
);
608 if (subLine
< CountMultiLines(viewLine
))
610 return m_ScreenedViewLine
[viewLine
].SubLines
[subLine
];
615 return m_pViewData
->GetLine(viewLine
);
618 void CBaseView::CheckOtherView()
620 if (m_bOtherDiffChecked
)
622 // find out what the 'other' file is
623 m_pOtherViewData
= NULL
;
625 if (this == m_pwndLeft
&& IsRightViewGood())
627 m_pOtherViewData
= m_pwndRight
->m_pViewData
;
628 m_pOtherView
= m_pwndRight
;
631 if (this == m_pwndRight
&& IsLeftViewGood())
633 m_pOtherViewData
= m_pwndLeft
->m_pViewData
;
634 m_pOtherView
= m_pwndLeft
;
637 m_bOtherDiffChecked
= true;
641 void CBaseView::GetWhitespaceBlock(CViewData
*viewData
, int nLineIndex
, int & nStartBlock
, int & nEndBlock
)
643 enum { MAX_WHITESPACEBLOCK_SIZE
= 8 };
646 DiffStates origstate
= viewData
->GetState(nLineIndex
);
648 // Go back and forward at most MAX_WHITESPACEBLOCK_SIZE lines to see where this block ends
649 nStartBlock
= nLineIndex
;
650 nEndBlock
= nLineIndex
;
651 while ((nStartBlock
> 0) && (nStartBlock
> (nLineIndex
- MAX_WHITESPACEBLOCK_SIZE
)))
653 DiffStates state
= viewData
->GetState(nStartBlock
- 1);
654 if ((origstate
== DIFFSTATE_EMPTY
) && (state
!= DIFFSTATE_NORMAL
))
656 if ((origstate
== state
) || (state
== DIFFSTATE_EMPTY
))
661 while ((nEndBlock
< (viewData
->GetCount() - 1)) && (nEndBlock
< (nLineIndex
+ MAX_WHITESPACEBLOCK_SIZE
)))
663 DiffStates state
= viewData
->GetState(nEndBlock
+ 1);
664 if ((origstate
== DIFFSTATE_EMPTY
) && (state
!= DIFFSTATE_NORMAL
))
666 if ((origstate
== state
) || (state
== DIFFSTATE_EMPTY
))
673 CString
CBaseView::GetWhitespaceString(CViewData
*viewData
, int nStartBlock
, int nEndBlock
)
675 enum { MAX_WHITESPACEBLOCK_SIZE
= 8 };
677 for (int i
= nStartBlock
; i
<= nEndBlock
; ++i
)
678 len
+= viewData
->GetLine(i
).GetLength();
681 // do not check for whitespace blocks if the line is too long, because
682 // reserving a lot of memory here takes too much time (performance hog)
683 if (len
> MAX_WHITESPACEBLOCK_SIZE
*256)
685 block
.Preallocate(len
+1);
686 for (int i
= nStartBlock
; i
<= nEndBlock
; ++i
)
687 block
+= viewData
->GetLine(i
);
691 bool CBaseView::IsBlockWhitespaceOnly(int nLineIndex
, bool& bIdentical
)
693 if (m_pViewData
== NULL
)
697 if (!m_pOtherViewData
)
699 int viewLine
= GetViewLineForScreen(nLineIndex
);
701 (m_pViewData
->GetState(viewLine
) == DIFFSTATE_NORMAL
) &&
702 (m_pOtherViewData
->GetLine(viewLine
) == m_pViewData
->GetLine(viewLine
))
708 // first check whether the line itself only has whitespace changes
709 CString mine
= m_pViewData
->GetLine(viewLine
);
710 CString other
= m_pOtherViewData
->GetLine(min(viewLine
, m_pOtherViewData
->GetCount() - 1));
711 if (mine
.IsEmpty() && other
.IsEmpty())
722 FilterWhitespaces(mine
, other
);
726 int nStartBlock1
, nEndBlock1
;
727 int nStartBlock2
, nEndBlock2
;
728 GetWhitespaceBlock(m_pViewData
, viewLine
, nStartBlock1
, nEndBlock1
);
729 GetWhitespaceBlock(m_pOtherViewData
, min(viewLine
, m_pOtherViewData
->GetCount() - 1), nStartBlock2
, nEndBlock2
);
730 mine
= GetWhitespaceString(m_pViewData
, nStartBlock1
, nEndBlock1
);
735 other
= GetWhitespaceString(m_pOtherViewData
, nStartBlock2
, nEndBlock2
);
736 bIdentical
= mine
== other
;
737 FilterWhitespaces(mine
, other
);
740 return (!mine
.IsEmpty()) && (mine
== other
);
743 bool CBaseView::IsViewLineHidden(int nViewLine
)
745 return IsViewLineHidden(m_pViewData
, nViewLine
);
748 bool CBaseView::IsViewLineHidden(CViewData
* pViewData
, int nViewLine
)
750 return m_pMainFrame
->m_bCollapsed
&& (pViewData
->GetHideState(nViewLine
)!=HIDESTATE_SHOWN
);
753 int CBaseView::GetLineNumber(int index
) const
755 if (m_pViewData
== NULL
)
757 int viewLine
= GetViewLineForScreen(index
);
758 if (m_pViewData
->GetLineNumber(viewLine
)==DIFF_EMPTYLINENUMBER
)
760 return m_pViewData
->GetLineNumber(viewLine
);
763 int CBaseView::GetScreenLines()
765 if (m_nScreenLines
== -1)
768 sbi
.cbSize
= sizeof(sbi
);
769 int scrollBarHeight
= 0;
770 if (GetScrollBarInfo(OBJID_HSCROLL
, &sbi
))
771 scrollBarHeight
= sbi
.rcScrollBar
.bottom
- sbi
.rcScrollBar
.top
;
772 if ((sbi
.rgstate
[0] & STATE_SYSTEM_INVISIBLE
)||(sbi
.rgstate
[0] & STATE_SYSTEM_UNAVAILABLE
))
775 GetClientRect(&rect
);
776 m_nScreenLines
= (rect
.Height() - HEADERHEIGHT
- scrollBarHeight
) / GetLineHeight();
777 if (m_nScreenLines
< 0)
780 return m_nScreenLines
;
783 int CBaseView::GetAllMinScreenLines() const
785 int nLines
= INT_MAX
;
786 if (IsLeftViewGood())
787 nLines
= m_pwndLeft
->GetScreenLines();
788 if (IsRightViewGood())
789 nLines
= std::min
<int>(nLines
, m_pwndRight
->GetScreenLines());
790 if (IsBottomViewGood())
791 nLines
= std::min
<int>(nLines
, m_pwndBottom
->GetScreenLines());
792 return (nLines
==INT_MAX
) ? 0 : nLines
;
795 int CBaseView::GetAllLineCount() const
798 if (IsLeftViewGood())
799 nLines
= m_pwndLeft
->GetLineCount();
800 if (IsRightViewGood())
801 nLines
= std::max
<int>(nLines
, m_pwndRight
->GetLineCount());
802 if (IsBottomViewGood())
803 nLines
= std::max
<int>(nLines
, m_pwndBottom
->GetLineCount());
807 void CBaseView::RecalcAllVertScrollBars(BOOL bPositionOnly
/*= FALSE*/)
809 if (IsLeftViewGood())
810 m_pwndLeft
->RecalcVertScrollBar(bPositionOnly
);
811 if (IsRightViewGood())
812 m_pwndRight
->RecalcVertScrollBar(bPositionOnly
);
813 if (IsBottomViewGood())
814 m_pwndBottom
->RecalcVertScrollBar(bPositionOnly
);
817 void CBaseView::RecalcVertScrollBar(BOOL bPositionOnly
/*= FALSE*/)
820 si
.cbSize
= sizeof(si
);
824 si
.nPos
= m_nTopLine
;
828 EnableScrollBarCtrl(SB_VERT
, TRUE
);
829 if (GetAllMinScreenLines() >= GetAllLineCount() && m_nTopLine
> 0)
834 si
.fMask
= SIF_DISABLENOSCROLL
| SIF_PAGE
| SIF_POS
| SIF_RANGE
;
836 si
.nMax
= GetAllLineCount();
837 si
.nPage
= GetAllMinScreenLines();
838 si
.nPos
= m_nTopLine
;
840 VERIFY(SetScrollInfo(SB_VERT
, &si
));
843 void CBaseView::OnVScroll(UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
)
845 CView::OnVScroll(nSBCode
, nPos
, pScrollBar
);
847 m_pwndLeft
->OnDoVScroll(nSBCode
, nPos
, pScrollBar
, this);
849 m_pwndRight
->OnDoVScroll(nSBCode
, nPos
, pScrollBar
, this);
851 m_pwndBottom
->OnDoVScroll(nSBCode
, nPos
, pScrollBar
, this);
853 m_pwndLocator
->Invalidate();
856 void CBaseView::OnDoVScroll(UINT nSBCode
, UINT
/*nPos*/, CScrollBar
* /*pScrollBar*/, CBaseView
* master
)
858 // Note we cannot use nPos because of its 16-bit nature
860 si
.cbSize
= sizeof(si
);
862 VERIFY(master
->GetScrollInfo(SB_VERT
, &si
));
864 int nPageLines
= GetScreenLines();
865 int nLineCount
= GetLineCount();
869 static LONG textwidth
= 0;
870 static CString
sFormat(MAKEINTRESOURCE(IDS_VIEWSCROLLTIPTEXT
));
877 nNewTopLine
= nLineCount
- nPageLines
+ 1;
880 nNewTopLine
= m_nTopLine
- 1;
883 nNewTopLine
= m_nTopLine
+ 1;
886 nNewTopLine
= m_nTopLine
- si
.nPage
+ 1;
889 nNewTopLine
= m_nTopLine
+ si
.nPage
- 1;
891 case SB_THUMBPOSITION
:
892 m_ScrollTool
.Clear();
893 nNewTopLine
= si
.nTrackPos
;
897 nNewTopLine
= si
.nTrackPos
;
898 if (GetFocus() == this)
901 GetClientRect(&thumbrect
);
902 ClientToScreen(&thumbrect
);
905 thumbpoint
.x
= thumbrect
.right
;
906 thumbpoint
.y
= thumbrect
.top
+ ((thumbrect
.bottom
-thumbrect
.top
)*si
.nTrackPos
)/(si
.nMax
-si
.nMin
);
907 m_ScrollTool
.Init(&thumbpoint
);
910 CString sTemp
= sFormat
;
911 sTemp
.Format(sFormat
, m_nDigits
, 10*m_nDigits
-1);
912 textwidth
= m_ScrollTool
.GetTextWidth(sTemp
);
914 thumbpoint
.x
-= textwidth
;
915 int line
= GetLineNumber(nNewTopLine
);
917 m_ScrollTool
.SetText(&thumbpoint
, sFormat
, m_nDigits
, GetLineNumber(nNewTopLine
)+1);
919 m_ScrollTool
.SetText(&thumbpoint
, m_sNoLineNr
);
928 if (nNewTopLine
>= nLineCount
)
929 nNewTopLine
= nLineCount
- 1;
930 ScrollToLine(nNewTopLine
);
933 void CBaseView::RecalcAllHorzScrollBars(BOOL bPositionOnly
/*= FALSE*/)
935 if (IsLeftViewGood())
936 m_pwndLeft
->RecalcHorzScrollBar(bPositionOnly
);
937 if (IsRightViewGood())
938 m_pwndRight
->RecalcHorzScrollBar(bPositionOnly
);
939 if (IsBottomViewGood())
940 m_pwndBottom
->RecalcHorzScrollBar(bPositionOnly
);
943 void CBaseView::RecalcHorzScrollBar(BOOL bPositionOnly
/*= FALSE*/)
946 si
.cbSize
= sizeof(si
);
950 si
.nPos
= m_nOffsetChar
;
954 EnableScrollBarCtrl(SB_HORZ
, !m_pMainFrame
->m_bWrapLines
);
955 if (!m_pMainFrame
->m_bWrapLines
)
957 int minScreenChars
= GetAllMinScreenChars();
958 int maxLineLength
= GetAllMaxLineLength();
959 if (minScreenChars
>= maxLineLength
&& m_nOffsetChar
> 0)
964 si
.fMask
= SIF_DISABLENOSCROLL
| SIF_PAGE
| SIF_POS
| SIF_RANGE
;
966 si
.nMax
= m_pMainFrame
->m_bWrapLines
? minScreenChars
: maxLineLength
;
967 si
.nMax
+= GetMarginWidth()/GetCharWidth();
968 si
.nPage
= minScreenChars
;
969 si
.nPos
= m_nOffsetChar
;
972 VERIFY(SetScrollInfo(SB_HORZ
, &si
));
975 void CBaseView::OnHScroll(UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
)
977 CView::OnHScroll(nSBCode
, nPos
, pScrollBar
);
979 m_pwndLeft
->OnDoHScroll(nSBCode
, nPos
, pScrollBar
, this);
981 m_pwndRight
->OnDoHScroll(nSBCode
, nPos
, pScrollBar
, this);
983 m_pwndBottom
->OnDoHScroll(nSBCode
, nPos
, pScrollBar
, this);
985 m_pwndLocator
->Invalidate();
988 void CBaseView::OnDoHScroll(UINT nSBCode
, UINT
/*nPos*/, CScrollBar
* /*pScrollBar*/, CBaseView
* master
)
991 si
.cbSize
= sizeof(si
);
993 VERIFY(master
->GetScrollInfo(SB_HORZ
, &si
));
995 int nPageChars
= GetScreenChars();
996 int nMaxLineLength
= GetMaxLineLength();
1005 nNewOffset
= nMaxLineLength
- nPageChars
+ 1;
1008 nNewOffset
= m_nOffsetChar
- 1;
1011 nNewOffset
= m_nOffsetChar
+ 1;
1014 nNewOffset
= m_nOffsetChar
- si
.nPage
+ 1;
1017 nNewOffset
= m_nOffsetChar
+ si
.nPage
- 1;
1019 case SB_THUMBPOSITION
:
1021 nNewOffset
= si
.nTrackPos
;
1027 if (nNewOffset
>= nMaxLineLength
)
1028 nNewOffset
= nMaxLineLength
- 1;
1031 ScrollToChar(nNewOffset
, TRUE
);
1034 void CBaseView::ScrollToChar(int nNewOffsetChar
, BOOL bTrackScrollBar
/*= TRUE*/)
1036 if (m_nOffsetChar
!= nNewOffsetChar
)
1038 int nScrollChars
= m_nOffsetChar
- nNewOffsetChar
;
1039 m_nOffsetChar
= nNewOffsetChar
;
1041 GetClientRect(&rcScroll
);
1042 rcScroll
.left
+= GetMarginWidth();
1043 rcScroll
.top
+= GetLineHeight()+HEADERHEIGHT
;
1044 ScrollWindow(nScrollChars
* GetCharWidth(), 0, &rcScroll
, &rcScroll
);
1045 // update the view header
1048 rcScroll
.bottom
= GetLineHeight()+HEADERHEIGHT
;
1049 InvalidateRect(&rcScroll
, FALSE
);
1051 if (bTrackScrollBar
)
1052 RecalcHorzScrollBar(TRUE
);
1054 if (m_pwndLineDiffBar
)
1055 m_pwndLineDiffBar
->Invalidate();
1059 void CBaseView::ScrollAllToChar(int nNewOffsetChar
, BOOL bTrackScrollBar
/* = TRUE */)
1062 m_pwndLeft
->ScrollToChar(nNewOffsetChar
, bTrackScrollBar
);
1064 m_pwndRight
->ScrollToChar(nNewOffsetChar
, bTrackScrollBar
);
1066 m_pwndBottom
->ScrollToChar(nNewOffsetChar
, bTrackScrollBar
);
1069 void CBaseView::ScrollAllSide(int delta
)
1071 int nNewOffset
= m_nOffsetChar
;
1072 nNewOffset
+= delta
;
1073 int nMaxLineLength
= GetMaxLineLength();
1074 if (nNewOffset
>= nMaxLineLength
)
1075 nNewOffset
= nMaxLineLength
- 1;
1078 ScrollAllToChar(nNewOffset
, TRUE
);
1079 if (m_pwndLineDiffBar
)
1080 m_pwndLineDiffBar
->Invalidate();
1084 void CBaseView::ScrollSide(int delta
)
1086 int nNewOffset
= m_nOffsetChar
;
1087 nNewOffset
+= delta
;
1088 int nMaxLineLength
= GetMaxLineLength();
1089 if (nNewOffset
>= nMaxLineLength
)
1090 nNewOffset
= nMaxLineLength
- 1;
1093 ScrollToChar(nNewOffset
, TRUE
);
1094 if (m_pwndLineDiffBar
)
1095 m_pwndLineDiffBar
->Invalidate();
1099 void CBaseView::ScrollVertical(short zDelta
)
1101 const int nLineCount
= GetLineCount();
1102 int nTopLine
= m_nTopLine
;
1103 nTopLine
-= (zDelta
/30);
1106 if (nTopLine
>= nLineCount
)
1107 nTopLine
= nLineCount
- 1;
1108 ScrollToLine(nTopLine
, TRUE
);
1111 void CBaseView::ScrollToLine(int nNewTopLine
, BOOL bTrackScrollBar
/*= TRUE*/)
1113 if (m_nTopLine
!= nNewTopLine
)
1115 if (nNewTopLine
< 0)
1118 int nScrollLines
= m_nTopLine
- nNewTopLine
;
1120 m_nTopLine
= nNewTopLine
;
1122 GetClientRect(&rcScroll
);
1123 rcScroll
.top
+= GetLineHeight()+HEADERHEIGHT
;
1124 ScrollWindow(0, nScrollLines
* GetLineHeight(), &rcScroll
, &rcScroll
);
1126 if (bTrackScrollBar
)
1127 RecalcVertScrollBar(TRUE
);
1133 void CBaseView::DrawMargin(CDC
*pdc
, const CRect
&rect
, int nLineIndex
)
1135 pdc
->FillSolidRect(rect
, ::GetSysColor(COLOR_SCROLLBAR
));
1137 if ((nLineIndex
>= 0)&&(m_pViewData
)&&(m_pViewData
->GetCount()))
1139 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1141 ASSERT(nViewLine
<(int)m_ScreenedViewLine
.size());
1142 TScreenedViewLine::EIcon eIcon
= m_ScreenedViewLine
[nViewLine
].eIcon
;
1143 if (eIcon
==TScreenedViewLine::ICN_UNKNOWN
)
1145 DiffStates state
= m_pViewData
->GetState(nViewLine
);
1148 case DIFFSTATE_ADDED
:
1149 case DIFFSTATE_THEIRSADDED
:
1150 case DIFFSTATE_YOURSADDED
:
1151 case DIFFSTATE_IDENTICALADDED
:
1152 case DIFFSTATE_CONFLICTADDED
:
1153 eIcon
= TScreenedViewLine::ICN_ADD
;
1155 case DIFFSTATE_REMOVED
:
1156 case DIFFSTATE_THEIRSREMOVED
:
1157 case DIFFSTATE_YOURSREMOVED
:
1158 case DIFFSTATE_IDENTICALREMOVED
:
1159 eIcon
= TScreenedViewLine::ICN_REMOVED
;
1161 case DIFFSTATE_CONFLICTED
:
1162 eIcon
= TScreenedViewLine::ICN_CONFLICT
;
1164 case DIFFSTATE_CONFLICTED_IGNORED
:
1165 eIcon
= TScreenedViewLine::ICN_CONFLICTIGNORED
;
1167 case DIFFSTATE_EDITED
:
1168 eIcon
= TScreenedViewLine::ICN_EDIT
;
1170 case DIFFSTATE_MOVED_TO
:
1171 case DIFFSTATE_MOVED_FROM
:
1172 eIcon
= TScreenedViewLine::ICN_MOVED
;
1177 bool bIdentical
= false;
1178 if ((state
!= DIFFSTATE_EDITED
)&&(IsBlockWhitespaceOnly(nLineIndex
, bIdentical
)))
1181 eIcon
= TScreenedViewLine::ICN_SAME
;
1183 eIcon
= TScreenedViewLine::ICN_WHITESPACEDIFF
;
1185 m_ScreenedViewLine
[nViewLine
].eIcon
= eIcon
;
1189 case TScreenedViewLine::ICN_UNKNOWN
:
1190 case TScreenedViewLine::ICN_NONE
:
1192 case TScreenedViewLine::ICN_SAME
:
1193 icon
= m_hEqualIcon
;
1195 case TScreenedViewLine::ICN_EDIT
:
1196 icon
= m_hEditedIcon
;
1198 case TScreenedViewLine::ICN_WHITESPACEDIFF
:
1199 icon
= m_hWhitespaceBlockIcon
;
1201 case TScreenedViewLine::ICN_ADD
:
1202 icon
= m_hAddedIcon
;
1204 case TScreenedViewLine::ICN_CONFLICT
:
1205 icon
= m_hConflictedIcon
;
1207 case TScreenedViewLine::ICN_CONFLICTIGNORED
:
1208 icon
= m_hConflictedIgnoredIcon
;
1210 case TScreenedViewLine::ICN_REMOVED
:
1211 icon
= m_hRemovedIcon
;
1213 case TScreenedViewLine::ICN_MOVED
:
1214 icon
= m_hMovedIcon
;
1221 ::DrawIconEx(pdc
->m_hDC
, rect
.left
+ 2, rect
.top
+ (rect
.Height()-16)/2, icon
, 16, 16, NULL
, NULL
, DI_NORMAL
);
1223 if ((m_bViewLinenumbers
)&&(m_nDigits
))
1225 int nSubLine
= GetSubLineOffset(nLineIndex
);
1226 bool bIsFirstSubline
= (nSubLine
== 0) || (nSubLine
== -1);
1227 CString sLinenumber
;
1228 if (bIsFirstSubline
)
1230 CString sLinenumberFormat
;
1231 int nLineNumber
= GetLineNumber(nLineIndex
);
1232 if (IsViewLineHidden(GetViewLineForScreen(nLineIndex
)))
1234 // TODO: do not show if there is no number hidden
1235 // TODO: show number if there is only one
1236 sLinenumberFormat
.Format(_T("%%%ds"), m_nDigits
);
1237 sLinenumber
.Format(sLinenumberFormat
, (m_nDigits
>1) ? _T("↕⁞") : _T("⁞")); // alternative …
1239 else if (nLineNumber
>= 0)
1241 sLinenumberFormat
.Format(_T("%%%dd"), m_nDigits
);
1242 sLinenumber
.Format(sLinenumberFormat
, nLineNumber
+1);
1244 else if (m_pMainFrame
->m_bWrapLines
)
1246 sLinenumberFormat
.Format(_T("%%%ds"), m_nDigits
);
1247 sLinenumber
.Format(sLinenumberFormat
, _T("·"));
1249 if (!sLinenumber
.IsEmpty())
1251 pdc
->SetBkColor(::GetSysColor(COLOR_SCROLLBAR
));
1252 pdc
->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT
));
1254 pdc
->SelectObject(GetFont());
1255 pdc
->ExtTextOut(rect
.left
+ 18, rect
.top
, ETO_CLIPPED
, &rect
, sLinenumber
, NULL
);
1262 int CBaseView::GetMarginWidth()
1264 if ((m_bViewLinenumbers
)&&(m_pViewData
)&&(m_pViewData
->GetCount()))
1268 int nLength
= (int)m_pViewData
->GetCount();
1269 // find out how many digits are needed to show the highest line number
1271 sMax
.Format(_T("%d"), nLength
);
1272 m_nDigits
= sMax
.GetLength();
1274 int nWidth
= GetCharWidth();
1275 return (MARGINWIDTH
+ (m_nDigits
* nWidth
) + 2);
1280 void CBaseView::DrawHeader(CDC
*pdc
, const CRect
&rect
)
1282 CRect
textrect(rect
.left
, rect
.top
, rect
.Width(), GetLineHeight()+HEADERHEIGHT
);
1283 COLORREF crBk
, crFg
;
1284 if (IsBottomViewGood())
1286 CDiffColors::GetInstance().GetColors(DIFFSTATE_NORMAL
, crBk
, crFg
);
1287 crBk
= ::GetSysColor(COLOR_SCROLLBAR
);
1291 DiffStates state
= DIFFSTATE_REMOVED
;
1292 if (this == m_pwndRight
)
1294 state
= DIFFSTATE_ADDED
;
1296 CDiffColors::GetInstance().GetColors(state
, crBk
, crFg
);
1298 pdc
->SetBkColor(crBk
);
1299 pdc
->FillSolidRect(textrect
, crBk
);
1301 pdc
->SetTextColor(crFg
);
1303 pdc
->SelectObject(GetFont(FALSE
, TRUE
));
1308 sViewTitle
= _T("* ") + m_sWindowName
;
1312 sViewTitle
= m_sWindowName
;
1314 int nStringLength
= (GetCharWidth()*m_sWindowName
.GetLength());
1315 if (nStringLength
> rect
.Width())
1317 int offset
= std::min
<int>(m_nOffsetChar
, (nStringLength
-rect
.Width())/GetCharWidth()+1);
1318 sViewTitle
= m_sWindowName
.Mid(offset
);
1320 pdc
->ExtTextOut(std::max
<int>(rect
.left
+ (rect
.Width()-nStringLength
)/2, 1),
1321 rect
.top
+(HEADERHEIGHT
/2), ETO_CLIPPED
, textrect
, sViewTitle
, NULL
);
1322 if (this->GetFocus() == this)
1323 pdc
->DrawEdge(textrect
, EDGE_BUMP
, BF_RECT
);
1325 pdc
->DrawEdge(textrect
, EDGE_ETCHED
, BF_RECT
);
1328 void CBaseView::OnDraw(CDC
* pDC
)
1331 GetClientRect(rcClient
);
1333 int nLineCount
= GetLineCount();
1334 int nLineHeight
= GetLineHeight();
1337 VERIFY(cacheDC
.CreateCompatibleDC(pDC
));
1338 if (m_pCacheBitmap
== NULL
)
1340 m_pCacheBitmap
= new CBitmap
;
1341 VERIFY(m_pCacheBitmap
->CreateCompatibleBitmap(pDC
, rcClient
.Width(), nLineHeight
));
1343 CBitmap
*pOldBitmap
= cacheDC
.SelectObject(m_pCacheBitmap
);
1345 DrawHeader(pDC
, rcClient
);
1349 rcLine
.top
+= nLineHeight
+HEADERHEIGHT
;
1350 rcLine
.bottom
= rcLine
.top
+ nLineHeight
;
1351 CRect
rcCacheMargin(0, 0, GetMarginWidth(), nLineHeight
);
1352 CRect
rcCacheLine(GetMarginWidth(), 0, rcLine
.Width(), nLineHeight
);
1354 int nCurrentLine
= m_nTopLine
;
1355 bool bBeyondFileLineCached
= false;
1356 while (rcLine
.top
< rcClient
.bottom
)
1358 if (nCurrentLine
< nLineCount
)
1360 DrawMargin(&cacheDC
, rcCacheMargin
, nCurrentLine
);
1361 DrawSingleLine(&cacheDC
, rcCacheLine
, nCurrentLine
);
1362 bBeyondFileLineCached
= false;
1364 else if (!bBeyondFileLineCached
)
1366 DrawMargin(&cacheDC
, rcCacheMargin
, -1);
1367 DrawSingleLine(&cacheDC
, rcCacheLine
, -1);
1368 bBeyondFileLineCached
= true;
1371 VERIFY(pDC
->BitBlt(rcLine
.left
, rcLine
.top
, rcLine
.Width(), rcLine
.Height(), &cacheDC
, 0, 0, SRCCOPY
));
1374 rcLine
.OffsetRect(0, nLineHeight
);
1377 cacheDC
.SelectObject(pOldBitmap
);
1381 bool CBaseView::IsStateConflicted(DiffStates state
)
1385 case DIFFSTATE_CONFLICTED
:
1386 case DIFFSTATE_CONFLICTED_IGNORED
:
1387 case DIFFSTATE_CONFLICTEMPTY
:
1388 case DIFFSTATE_CONFLICTADDED
:
1394 bool CBaseView::IsStateEmpty(DiffStates state
)
1398 case DIFFSTATE_CONFLICTEMPTY
:
1399 case DIFFSTATE_UNKNOWN
:
1400 case DIFFSTATE_EMPTY
:
1406 bool CBaseView::IsStateRemoved(DiffStates state
)
1410 case DIFFSTATE_REMOVED
:
1411 case DIFFSTATE_MOVED_FROM
:
1412 case DIFFSTATE_THEIRSREMOVED
:
1413 case DIFFSTATE_YOURSREMOVED
:
1414 case DIFFSTATE_IDENTICALREMOVED
:
1420 DiffStates
CBaseView::ResolveState(DiffStates state
)
1422 if (IsStateConflicted(state
))
1424 if (state
== DIFFSTATE_CONFLICTEMPTY
)
1425 return DIFFSTATE_CONFLICTRESOLVEDEMPTY
;
1427 return DIFFSTATE_CONFLICTRESOLVED
;
1433 bool CBaseView::IsLineEmpty(int nLineIndex
)
1435 if (m_pViewData
== 0)
1437 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1438 return IsViewLineEmpty(nViewLine
);
1441 bool CBaseView::IsViewLineEmpty(int nViewLine
)
1443 if (m_pViewData
== 0)
1445 const DiffStates state
= m_pViewData
->GetState(nViewLine
);
1446 return IsStateEmpty(state
);
1449 bool CBaseView::IsLineRemoved(int nLineIndex
)
1451 if (m_pViewData
== 0)
1453 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1454 return IsViewLineRemoved(nViewLine
);
1457 bool CBaseView::IsViewLineRemoved(int nViewLine
)
1459 if (m_pViewData
== 0)
1461 const DiffStates state
= m_pViewData
->GetState(nViewLine
);
1462 return IsStateRemoved(state
);
1465 bool CBaseView::IsViewLineConflicted(int nLineIndex
)
1467 if (m_pViewData
== 0)
1469 const DiffStates state
= m_pViewData
->GetState(nLineIndex
);
1470 return IsStateConflicted(state
);
1473 COLORREF
CBaseView::InlineDiffColor(int nLineIndex
)
1475 return IsLineRemoved(nLineIndex
) ? m_InlineRemovedBk
: m_InlineAddedBk
;
1478 COLORREF
CBaseView::InlineViewLineDiffColor(int nViewLine
)
1480 return IsViewLineRemoved(nViewLine
) ? m_InlineRemovedBk
: m_InlineAddedBk
;
1483 void CBaseView::DrawLineEnding(CDC
*pDC
, const CRect
&rc
, int nLineIndex
, const CPoint
& origin
)
1485 if (!(m_bViewWhitespace
&& m_pViewData
&& (nLineIndex
>= 0) && (nLineIndex
< GetLineCount())))
1487 int viewLine
= GetViewLineForScreen(nLineIndex
);
1488 EOL ending
= m_pViewData
->GetLineEnding(viewLine
);
1491 HICON hEndingIcon
= NULL
;
1494 case EOL_CR
: hEndingIcon
= m_hLineEndingCR
; break;
1495 case EOL_CRLF
: hEndingIcon
= m_hLineEndingCRLF
; break;
1496 case EOL_LF
: hEndingIcon
= m_hLineEndingLF
; break;
1499 if (origin
.x
< (rc
.left
-GetCharWidth()))
1501 // If EOL style has changed, color end-of-line markers as inline differences.
1503 m_bShowInlineDiff
&& m_pOtherViewData
&&
1504 (viewLine
< m_pOtherViewData
->GetCount()) &&
1505 (ending
!= EOL_NOENDING
) &&
1506 (ending
!= m_pOtherViewData
->GetLineEnding(viewLine
) &&
1507 (m_pOtherViewData
->GetLineEnding(viewLine
) != EOL_NOENDING
))
1510 pDC
->FillSolidRect(origin
.x
, origin
.y
, rc
.Height(), rc
.Height(), InlineDiffColor(nLineIndex
));
1513 DrawIconEx(pDC
->GetSafeHdc(), origin
.x
, origin
.y
, hEndingIcon
, rc
.Height(), rc
.Height(), NULL
, NULL
, DI_NORMAL
);
1517 CPen
pen(PS_SOLID
, 0, m_WhiteSpaceFg
);
1518 CPen
* oldpen
= pDC
->SelectObject(&pen
);
1519 int yMiddle
= origin
.y
+ rc
.Height()/2;
1520 int xMiddle
= origin
.x
+GetCharWidth()/2;
1521 bool bMultiline
= false;
1522 if (((int)m_Screen2View
.size() > nLineIndex
+1) && (GetViewLineForScreen(nLineIndex
+1) == viewLine
))
1524 if (GetLineLength(nLineIndex
+1))
1528 pDC
->MoveTo(origin
.x
, yMiddle
-2);
1529 pDC
->LineTo(origin
.x
+GetCharWidth()-1, yMiddle
-2);
1530 pDC
->LineTo(origin
.x
+GetCharWidth()-1, yMiddle
+2);
1531 pDC
->LineTo(origin
.x
, yMiddle
+2);
1533 else if (GetLineLength(nLineIndex
) == 0)
1536 else if ((nLineIndex
> 0) && (GetViewLineForScreen(nLineIndex
-1) == viewLine
) && (GetLineLength(nLineIndex
) == 0))
1545 // arrow from top to middle+2, then left
1546 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, rc
.top
+1);
1547 pDC
->LineTo(origin
.x
+GetCharWidth()-1, yMiddle
);
1549 // arrow from right to left
1550 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, yMiddle
);
1551 pDC
->LineTo(origin
.x
, yMiddle
);
1552 pDC
->LineTo(origin
.x
+4, yMiddle
+4);
1553 pDC
->MoveTo(origin
.x
, yMiddle
);
1554 pDC
->LineTo(origin
.x
+4, yMiddle
-4);
1557 // from right-upper to left then down
1558 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, yMiddle
-2);
1559 pDC
->LineTo(xMiddle
, yMiddle
-2);
1560 pDC
->LineTo(xMiddle
, rc
.bottom
-1);
1561 pDC
->LineTo(xMiddle
+4, rc
.bottom
-5);
1562 pDC
->MoveTo(xMiddle
, rc
.bottom
-1);
1563 pDC
->LineTo(xMiddle
-4, rc
.bottom
-5);
1566 // arrow from top to bottom
1567 pDC
->MoveTo(xMiddle
, rc
.top
);
1568 pDC
->LineTo(xMiddle
, rc
.bottom
-1);
1569 pDC
->LineTo(xMiddle
+4, rc
.bottom
-5);
1570 pDC
->MoveTo(xMiddle
, rc
.bottom
-1);
1571 pDC
->LineTo(xMiddle
-4, rc
.bottom
-5);
1573 case EOL_FF
: // Form Feed, U+000C
1574 case EOL_NEL
: // Next Line, U+0085
1575 case EOL_LS
: // Line Separator, U+2028
1576 case EOL_PS
: // Paragraph Separator, U+2029
1577 // draw a horizontal line at the bottom of this line
1578 pDC
->FillSolidRect(rc
.left
, rc
.bottom
-1, rc
.right
, rc
.bottom
, GetSysColor(COLOR_WINDOWTEXT
));
1579 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, rc
.bottom
-GetCharWidth()-2);
1580 pDC
->LineTo(origin
.x
, rc
.bottom
-2);
1581 pDC
->LineTo(origin
.x
+5, rc
.bottom
-2);
1582 pDC
->MoveTo(origin
.x
, rc
.bottom
-2);
1583 pDC
->LineTo(origin
.x
+1, rc
.bottom
-6);
1585 default: // other EOLs
1586 // arrow from top right to bottom left
1587 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, rc
.bottom
-GetCharWidth());
1588 pDC
->LineTo(origin
.x
, rc
.bottom
-1);
1589 pDC
->LineTo(origin
.x
+5, rc
.bottom
-2);
1590 pDC
->MoveTo(origin
.x
, rc
.bottom
-1);
1591 pDC
->LineTo(origin
.x
+1, rc
.bottom
-6);
1597 pDC
->SelectObject(oldpen
);
1601 void CBaseView::DrawBlockLine(CDC
*pDC
, const CRect
&rc
, int nLineIndex
)
1603 if (!m_bShowSelection
)
1608 if (!GetViewSelection(nSelBlockStart
, nSelBlockEnd
))
1611 const int THICKNESS
= 2;
1612 COLORREF rectcol
= GetSysColor(m_bFocused
? COLOR_WINDOWTEXT
: COLOR_GRAYTEXT
);
1614 int nViewLineIndex
= GetViewLineForScreen(nLineIndex
);
1615 int nSubLine
= GetSubLineOffset(nLineIndex
);
1616 bool bFirstLineOfViewLine
= (nSubLine
==0 || nSubLine
==-1);
1617 if ((nViewLineIndex
== nSelBlockStart
) && bFirstLineOfViewLine
)
1619 pDC
->FillSolidRect(rc
.left
, rc
.top
, rc
.Width(), THICKNESS
, rectcol
);
1622 bool bLastLineOfViewLine
= (nLineIndex
+1 == m_Screen2View
.size()) || (GetViewLineForScreen(nLineIndex
) != GetViewLineForScreen(nLineIndex
+1));
1623 if ((nViewLineIndex
== nSelBlockEnd
) && bLastLineOfViewLine
)
1625 pDC
->FillSolidRect(rc
.left
, rc
.bottom
- THICKNESS
, rc
.Width(), THICKNESS
, rectcol
);
1629 void CBaseView::DrawTextLine(
1630 CDC
* pDC
, const CRect
&rc
, int nLineIndex
, POINT
& coords
)
1632 ASSERT(nLineIndex
< GetLineCount());
1633 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1634 ASSERT(m_pViewData
&& (nViewLine
< m_pViewData
->GetCount()));
1636 LineColors lineCols
= GetLineColors(nViewLine
);
1638 CString sViewLine
= GetViewLineChars(nViewLine
);
1640 if (m_bShowSelection
&& HasTextSelection())
1642 // has this line selection ?
1643 if ((m_ptSelectionViewPosStart
.y
<= nViewLine
) && (nViewLine
<= m_ptSelectionViewPosEnd
.y
))
1645 int nViewLineLength
= sViewLine
.GetLength();
1647 // first suppose the whole line is selected
1648 int selectedStart
= 0;
1649 int selectedEnd
= nViewLineLength
;
1651 // the view line is partially selected
1652 if (m_ptSelectionViewPosStart
.y
== nViewLine
)
1654 selectedStart
= m_ptSelectionViewPosStart
.x
;
1657 if (m_ptSelectionViewPosEnd
.y
== nViewLine
)
1659 selectedEnd
= m_ptSelectionViewPosEnd
.x
;
1661 // apply selection coloring
1662 // First enforce start and end point
1663 lineCols
.SplitBlock(selectedStart
);
1664 lineCols
.SplitBlock(selectedEnd
);
1665 // change color of affected parts
1666 long intenseColorScale
= m_bFocused
? 70 : 30;
1667 std::map
<int, linecolors_t
>::iterator it
= lineCols
.lower_bound(selectedStart
);
1668 for ( ; it
!= lineCols
.end() && it
->first
< selectedEnd
; ++it
)
1670 COLORREF crBk
= CAppUtils::IntenseColor(intenseColorScale
, it
->second
.background
);
1671 if (it
->second
.shot
== it
->second
.background
)
1673 it
->second
.shot
= crBk
;
1675 it
->second
.background
= crBk
;
1676 it
->second
.text
= CAppUtils::IntenseColor(intenseColorScale
, it
->second
.text
);
1681 // TODO: remove duplicate from selection and mark
1682 if (!m_sMarkedWord
.IsEmpty())
1684 int nMarkLength
= m_sMarkedWord
.GetLength();
1685 //int nViewLineLength = sViewLine.GetLength();
1686 const TCHAR
* text
= sViewLine
;
1687 const TCHAR
* findText
= text
;
1688 while ((findText
= _tcsstr(findText
, (LPCTSTR
)m_sMarkedWord
))!=0)
1690 int nMarkStart
= static_cast<int>(findText
- text
);
1691 int nMarkEnd
= nMarkStart
+ nMarkLength
;
1692 // First enforce start and end point
1693 lineCols
.SplitBlock(nMarkStart
);
1694 lineCols
.SplitBlock(nMarkEnd
);
1695 // change color of affected parts
1696 const long int nIntenseColorScale
= 200;
1697 std::map
<int, linecolors_t
>::iterator it
= lineCols
.lower_bound(nMarkStart
);
1698 for ( ; it
!= lineCols
.end() && it
->first
< nMarkEnd
; ++it
)
1700 COLORREF crBk
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.background
);
1701 if (it
->second
.shot
== it
->second
.background
)
1703 it
->second
.shot
= crBk
;
1705 it
->second
.background
= crBk
;
1706 it
->second
.text
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.text
);
1708 findText
+= nMarkLength
;
1711 if (!m_sFindText
.IsEmpty())
1715 int nStringPos
= nMarkStart
;
1716 CString searchLine
= sViewLine
;
1718 searchLine
.MakeLower();
1719 while (StringFound(searchLine
, SearchNext
, nMarkStart
, nMarkEnd
)!=0)
1721 // First enforce start and end point
1722 lineCols
.SplitBlock(nMarkStart
+nStringPos
);
1723 lineCols
.SplitBlock(nMarkEnd
+nStringPos
);
1724 // change color of affected parts
1725 const long int nIntenseColorScale
= 30;
1726 std::map
<int, linecolors_t
>::iterator it
= lineCols
.lower_bound(nMarkStart
+nStringPos
);
1727 for ( ; it
!= lineCols
.end() && it
->first
< nMarkEnd
; ++it
)
1729 COLORREF crBk
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.background
);
1730 if (it
->second
.shot
== it
->second
.background
)
1732 it
->second
.shot
= crBk
;
1734 it
->second
.background
= crBk
;
1735 it
->second
.text
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.text
);
1737 searchLine
= searchLine
.Mid(nMarkEnd
);
1738 nStringPos
= nMarkEnd
;
1742 // @ this point we may cache data for next line which may be same in wrapped mode
1744 int nTextOffset
= 0;
1745 int nSubline
= GetSubLineOffset(nLineIndex
);
1746 for (int n
=0; n
<nSubline
; n
++)
1748 CString sLine
= m_ScreenedViewLine
[nViewLine
].SubLines
[n
];
1749 nTextOffset
+= sLine
.GetLength();
1752 CString sLine
= GetLineChars(nLineIndex
);
1753 int nLineLength
= sLine
.GetLength();
1754 CString sLineExp
= ExpandChars(sLine
);
1755 LPCTSTR textExp
= sLineExp
;
1756 //int nLineLengthExp = sLineExp.GetLength();
1758 int nLeft
= coords
.x
;
1759 for (std::map
<int, linecolors_t
>::const_iterator itStart
= lineCols
.begin(); itStart
!= lineCols
.end(); ++itStart
)
1761 std::map
<int, linecolors_t
>::const_iterator itEnd
= itStart
;
1763 int nStart
= std::max
<int>(0, itStart
->first
- nTextOffset
);
1764 int nEnd
= nLineLength
;
1765 if (itEnd
!= lineCols
.end())
1767 nEnd
= std::min
<int>(nEnd
, itEnd
->first
- nTextOffset
);
1769 int nBlockLength
= nEnd
- nStart
;
1770 if (nBlockLength
> 0 && nEnd
>=0)
1772 pDC
->SetBkColor(itStart
->second
.background
);
1773 pDC
->SetTextColor(itStart
->second
.text
);
1774 int nEndExp
= CountExpandedChars(sLine
, nEnd
);
1775 int nTextLength
= nEndExp
- nStartExp
;
1776 LPCTSTR p_zBlockText
= textExp
+ nStartExp
;
1778 GetTextExtentPoint32(pDC
->GetSafeHdc(), p_zBlockText
, nTextLength
, &Size
); // falls time-2-tme
1779 int nRight
= nLeft
+ Size
.cx
;
1780 if ((nRight
> rc
.left
) && (nLeft
< rc
.right
))
1782 // note: ExtTextOut has a limit for the length of the string. That limit is supposed
1783 // to be 8192, but that's not really true: I found that the limit (at least on my machine and a few others)
1784 // is 4094 (4095 doesn't work anymore).
1785 // So we limit the length here to that 4094 chars.
1786 // In case we're scrolled to the right, there's no need to draw the string
1787 // from way outside our window, so we also offset the drawing to the start of the window.
1788 // This reduces the string length as well.
1790 int leftcoord
= nLeft
;
1793 offset
= (-nLeft
/GetCharWidth());
1794 nTextLength
-= offset
;
1795 leftcoord
= nLeft
% GetCharWidth();
1798 pDC
->ExtTextOut(leftcoord
, coords
.y
, ETO_CLIPPED
, &rc
, p_zBlockText
+offset
, min(nTextLength
, 4094), NULL
);
1799 if ((itStart
->second
.shot
!= itStart
->second
.background
) && (itStart
->first
== nStart
+ nTextOffset
))
1801 pDC
->FillSolidRect(nLeft
-1, rc
.top
, 1, rc
.Height(), itStart
->second
.shot
);
1806 nStartExp
= nEndExp
;
1811 void CBaseView::DrawSingleLine(CDC
*pDC
, const CRect
&rc
, int nLineIndex
)
1813 if (nLineIndex
>= GetLineCount())
1815 ASSERT(nLineIndex
>= -1);
1817 if ((nLineIndex
== -1) || !m_pViewData
)
1819 // Draw line beyond the text
1820 COLORREF crBkgnd
, crText
;
1821 CDiffColors::GetInstance().GetColors(DIFFSTATE_UNKNOWN
, crBkgnd
, crText
);
1822 pDC
->FillSolidRect(rc
, crBkgnd
);
1826 int viewLine
= GetViewLineForScreen(nLineIndex
);
1827 if (m_pMainFrame
->m_bCollapsed
)
1829 if (m_pViewData
->GetHideState(viewLine
) == HIDESTATE_MARKER
)
1831 COLORREF crBkgnd
, crText
;
1832 CDiffColors::GetInstance().GetColors(DIFFSTATE_UNKNOWN
, crBkgnd
, crText
);
1833 pDC
->FillSolidRect(rc
, crBkgnd
);
1835 const int THICKNESS
= 2;
1836 COLORREF rectcol
= GetSysColor(COLOR_WINDOWTEXT
);
1837 pDC
->FillSolidRect(rc
.left
, rc
.top
+ (rc
.Height()/2), rc
.Width(), THICKNESS
, rectcol
);
1838 pDC
->SetTextColor(GetSysColor(COLOR_GRAYTEXT
));
1839 pDC
->SetBkColor(crBkgnd
);
1841 pDC
->DrawText(_T("{...}"), &rect
, DT_NOPREFIX
|DT_SINGLELINE
|DT_CENTER
);
1846 DiffStates diffState
= m_pViewData
->GetState(viewLine
);
1847 COLORREF crBkgnd
, crText
;
1848 CDiffColors::GetInstance().GetColors(diffState
, crBkgnd
, crText
);
1850 if (diffState
== DIFFSTATE_CONFLICTED
)
1852 // conflicted lines are shown without 'text' on them
1854 pDC
->FillSolidRect(rc
, crBkgnd
);
1855 // now draw some faint text patterns
1856 pDC
->SetTextColor(CAppUtils::IntenseColor(130, crBkgnd
));
1857 pDC
->DrawText(m_sConflictedText
, rect
, DT_LEFT
|DT_NOPREFIX
|DT_SINGLELINE
);
1858 DrawBlockLine(pDC
, rc
, nLineIndex
);
1862 CPoint
origin(rc
.left
- m_nOffsetChar
* GetCharWidth(), rc
.top
);
1863 CString sLine
= GetLineChars(nLineIndex
);
1864 if (sLine
.IsEmpty())
1866 pDC
->FillSolidRect(rc
, crBkgnd
);
1867 DrawBlockLine(pDC
, rc
, nLineIndex
);
1868 DrawLineEnding(pDC
, rc
, nLineIndex
, origin
);
1876 pDC
->SelectObject(GetFont(FALSE
, FALSE
));
1878 DrawTextLine(pDC
, rc
, nLineIndex
, origin
);
1880 // draw white space after the end of line
1882 if (origin
.x
> frect
.left
)
1883 frect
.left
= origin
.x
;
1884 if (frect
.right
> frect
.left
)
1885 pDC
->FillSolidRect(frect
, crBkgnd
);
1887 // draw the whitespace chars
1888 LPCTSTR pszChars
= (LPCWSTR
)sLine
;
1889 if (m_bViewWhitespace
)
1892 int y
= rc
.top
+ (rc
.bottom
-rc
.top
)/2;
1894 int nActualOffset
= 0;
1895 while ((nActualOffset
< m_nOffsetChar
) && (*pszChars
))
1897 if (*pszChars
== _T('\t'))
1898 nActualOffset
+= (GetTabSize() - nActualOffset
% GetTabSize());
1903 if (nActualOffset
> m_nOffsetChar
)
1906 CPen
pen(PS_SOLID
, 0, m_WhiteSpaceFg
);
1907 CPen
pen2(PS_SOLID
, 2, m_WhiteSpaceFg
);
1915 CPen
* oldPen
= pDC
->SelectObject(&pen
);
1916 int nSpaces
= GetTabSize() - (m_nOffsetChar
+ xpos
) % GetTabSize();
1917 pDC
->MoveTo(xpos
* GetCharWidth() + rc
.left
, y
);
1918 pDC
->LineTo((xpos
+ nSpaces
) * GetCharWidth() + rc
.left
-2, y
);
1919 pDC
->LineTo((xpos
+ nSpaces
) * GetCharWidth() + rc
.left
-6, y
-4);
1920 pDC
->MoveTo((xpos
+ nSpaces
) * GetCharWidth() + rc
.left
-2, y
);
1921 pDC
->LineTo((xpos
+ nSpaces
) * GetCharWidth() + rc
.left
-6, y
+4);
1923 pDC
->SelectObject(oldPen
);
1929 CPen
* oldPen
= pDC
->SelectObject(&pen2
);
1930 pDC
->MoveTo(xpos
* GetCharWidth() + rc
.left
+ GetCharWidth()/2-1, y
);
1931 pDC
->LineTo(xpos
* GetCharWidth() + rc
.left
+ GetCharWidth()/2+1, y
);
1933 pDC
->SelectObject(oldPen
);
1943 DrawBlockLine(pDC
, rc
, nLineIndex
);
1944 if (origin
.x
>= rc
.left
)
1945 DrawLineEnding(pDC
, rc
, nLineIndex
, origin
);
1948 void CBaseView::ExpandChars(const CString
&sLine
, int nOffset
, int nCount
, CString
&line
)
1956 int nTabSize
= GetTabSize();
1958 int nActualOffset
= CountExpandedChars(sLine
, nOffset
);
1960 LPCTSTR pszChars
= (LPCWSTR
)sLine
;
1961 pszChars
+= nOffset
;
1962 int nLength
= nCount
;
1965 for (int i
=0; i
<nLength
; i
++)
1967 if (pszChars
[i
] == _T('\t'))
1971 LPTSTR pszBuf
= line
.GetBuffer(nLength
+ nTabCount
* (nTabSize
- 1) + 1);
1973 if (nTabCount
> 0 || m_bViewWhitespace
)
1975 for (int i
=0; i
<nLength
; i
++)
1977 if (pszChars
[i
] == _T('\t'))
1979 int nSpaces
= nTabSize
- (nActualOffset
+ nCurPos
) % nTabSize
;
1982 pszBuf
[nCurPos
++] = _T(' ');
1988 pszBuf
[nCurPos
] = pszChars
[i
];
1995 memcpy(pszBuf
, pszChars
, sizeof(TCHAR
) * nLength
);
1998 pszBuf
[nCurPos
] = 0;
1999 line
.ReleaseBuffer();
2002 CString
CBaseView::ExpandChars(const CString
&sLine
, int nOffset
)
2005 int nLength
= sLine
.GetLength();
2006 ExpandChars(sLine
, nOffset
, nLength
, sRet
);
2010 int CBaseView::CountExpandedChars(const CString
&sLine
, int nLength
)
2012 int nTabSize
= GetTabSize();
2014 int nActualOffset
= 0;
2015 for (int i
=0; i
<nLength
; i
++)
2017 if (sLine
[i
] == _T('\t'))
2018 nActualOffset
+= (nTabSize
- nActualOffset
% nTabSize
);
2022 return nActualOffset
;
2025 void CBaseView::ScrollAllToLine(int nNewTopLine
, BOOL bTrackScrollBar
)
2028 m_pwndLeft
->ScrollToLine(nNewTopLine
, bTrackScrollBar
);
2030 m_pwndRight
->ScrollToLine(nNewTopLine
, bTrackScrollBar
);
2032 m_pwndBottom
->ScrollToLine(nNewTopLine
, bTrackScrollBar
);
2034 m_pwndLocator
->Invalidate();
2037 void CBaseView::GoToLine(int nNewLine
, BOOL bAll
)
2039 //almost the same as ScrollAllToLine, but try to put the line in the
2040 //middle of the view, not on top
2041 int nNewTopLine
= nNewLine
- GetScreenLines()/2;
2042 if (nNewTopLine
< 0)
2044 if (nNewTopLine
>= (int)m_Screen2View
.size())
2045 nNewTopLine
= (int)m_Screen2View
.size()-1;
2047 ScrollAllToLine(nNewTopLine
);
2049 ScrollToLine(nNewTopLine
);
2052 BOOL
CBaseView::OnEraseBkgnd(CDC
* /*pDC*/)
2057 int CBaseView::OnCreate(LPCREATESTRUCT lpCreateStruct
)
2059 if (CView::OnCreate(lpCreateStruct
) == -1)
2062 memset(&m_lfBaseFont
, 0, sizeof(m_lfBaseFont
));
2063 //lstrcpy(m_lfBaseFont.lfFaceName, _T("Courier New"));
2064 //lstrcpy(m_lfBaseFont.lfFaceName, _T("FixedSys"));
2065 m_lfBaseFont
.lfHeight
= 0;
2066 m_lfBaseFont
.lfWeight
= FW_NORMAL
;
2067 m_lfBaseFont
.lfItalic
= FALSE
;
2068 m_lfBaseFont
.lfCharSet
= DEFAULT_CHARSET
;
2069 m_lfBaseFont
.lfOutPrecision
= OUT_DEFAULT_PRECIS
;
2070 m_lfBaseFont
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2071 m_lfBaseFont
.lfQuality
= DEFAULT_QUALITY
;
2072 m_lfBaseFont
.lfPitchAndFamily
= DEFAULT_PITCH
;
2077 void CBaseView::OnDestroy()
2079 if ((m_pFindDialog
)&&(!m_pFindDialog
->IsTerminating()))
2081 m_pFindDialog
->SendMessage(WM_CLOSE
);
2089 void CBaseView::OnSize(UINT nType
, int cx
, int cy
)
2091 CView::OnSize(nType
, cx
, cy
);
2094 m_nScreenLines
= -1;
2095 m_nScreenChars
= -1;
2096 if (m_nLastScreenChars
!= GetScreenChars())
2098 BuildAllScreen2ViewVector();
2099 m_nLastScreenChars
= m_nScreenChars
;
2100 if (m_pMainFrame
&& m_pMainFrame
->m_bWrapLines
)
2102 // if we're in wrap mode, the line wrapping most likely changed
2103 // and that means we have to redraw the whole window, not just the
2109 // make sure the view header is redrawn
2111 GetClientRect(&rcScroll
);
2112 rcScroll
.bottom
= GetLineHeight()+HEADERHEIGHT
;
2113 InvalidateRect(&rcScroll
, FALSE
);
2118 // make sure the view header is redrawn
2120 GetClientRect(&rcScroll
);
2121 rcScroll
.bottom
= GetLineHeight()+HEADERHEIGHT
;
2122 InvalidateRect(&rcScroll
, FALSE
);
2125 RecalcVertScrollBar();
2126 RecalcHorzScrollBar();
2131 BOOL
CBaseView::OnMouseWheel(UINT nFlags
, short zDelta
, CPoint pt
)
2134 m_pwndLeft
->OnDoMouseWheel(nFlags
, zDelta
, pt
);
2136 m_pwndRight
->OnDoMouseWheel(nFlags
, zDelta
, pt
);
2138 m_pwndBottom
->OnDoMouseWheel(nFlags
, zDelta
, pt
);
2140 m_pwndLocator
->Invalidate();
2141 return CView::OnMouseWheel(nFlags
, zDelta
, pt
);
2144 void CBaseView::OnMouseHWheel(UINT nFlags
, short zDelta
, CPoint pt
)
2147 m_pwndLeft
->OnDoMouseHWheel(nFlags
, zDelta
, pt
);
2149 m_pwndRight
->OnDoMouseHWheel(nFlags
, zDelta
, pt
);
2151 m_pwndBottom
->OnDoMouseHWheel(nFlags
, zDelta
, pt
);
2153 m_pwndLocator
->Invalidate();
2156 void CBaseView::OnDoMouseWheel(UINT
/*nFlags*/, short zDelta
, CPoint
/*pt*/)
2158 bool bControl
= !!(GetKeyState(VK_CONTROL
)&0x8000);
2159 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
2161 if (bControl
|| bShift
)
2163 if (m_pMainFrame
->m_bWrapLines
)
2165 // Ctrl-Wheel scrolls sideways
2166 ScrollSide(-zDelta
/30);
2170 ScrollVertical(zDelta
);
2174 void CBaseView::OnDoMouseHWheel(UINT
/*nFlags*/, short zDelta
, CPoint
/*pt*/)
2176 bool bControl
= !!(GetKeyState(VK_CONTROL
)&0x8000);
2177 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
2179 if (bControl
|| bShift
)
2181 ScrollVertical(zDelta
);
2185 if (m_pMainFrame
->m_bWrapLines
)
2187 // Ctrl-Wheel scrolls sideways
2188 ScrollSide(-zDelta
/30);
2192 BOOL
CBaseView::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
2194 if (nHitTest
== HTCLIENT
)
2196 if ((m_pViewData
)&&(m_pMainFrame
->m_bCollapsed
))
2198 if (m_nMouseLine
< (int)m_Screen2View
.size())
2200 if (m_nMouseLine
>= 0)
2202 int viewLine
= GetViewLineForScreen(m_nMouseLine
);
2203 if (viewLine
< m_pViewData
->GetCount())
2205 if (m_pViewData
->GetHideState(viewLine
) == HIDESTATE_MARKER
)
2207 ::SetCursor(::LoadCursor(NULL
, MAKEINTRESOURCE(IDC_HAND
)));
2214 if (m_mouseInMargin
)
2216 ::SetCursor(m_margincursor
);
2219 if (m_nMouseLine
>= 0)
2221 ::SetCursor(::LoadCursor(NULL
, MAKEINTRESOURCE(IDC_IBEAM
))); // Set To Edit Cursor
2225 ::SetCursor(::LoadCursor(NULL
, MAKEINTRESOURCE(IDC_ARROW
))); // Set To Arrow Cursor
2228 return CView::OnSetCursor(pWnd
, nHitTest
, message
);
2231 void CBaseView::OnKillFocus(CWnd
* pNewWnd
)
2233 CView::OnKillFocus(pNewWnd
);
2239 void CBaseView::OnSetFocus(CWnd
* pOldWnd
)
2241 CView::OnSetFocus(pOldWnd
);
2247 int CBaseView::GetLineFromPoint(CPoint point
)
2249 ScreenToClient(&point
);
2250 return (((point
.y
- HEADERHEIGHT
) / GetLineHeight()) + m_nTopLine
);
2253 void CBaseView::OnContextMenu(CPoint point
, DiffStates state
)
2255 if (!this->IsWindowVisible())
2259 if (!popup
.CreatePopupMenu())
2262 AddContextItems(popup
, state
);
2264 CompensateForKeyboard(point
);
2266 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
| TPM_RIGHTBUTTON
, point
.x
, point
.y
, this, 0);
2270 // 2-pane view commands; target is right view
2271 case POPUPCOMMAND_USELEFTBLOCK
:
2272 m_pwndRight
->UseLeftBlock();
2274 case POPUPCOMMAND_USELEFTFILE
:
2275 m_pwndRight
->UseLeftFile();
2277 case POPUPCOMMAND_USEBOTHLEFTFIRST
:
2278 m_pwndRight
->UseBothLeftFirst();
2280 case POPUPCOMMAND_USEBOTHRIGHTFIRST
:
2281 m_pwndRight
->UseBothRightFirst();
2283 // 3-pane view commands; target is bottom view
2284 case POPUPCOMMAND_USEYOURANDTHEIRBLOCK
:
2285 m_pwndBottom
->UseBothRightFirst();
2287 case POPUPCOMMAND_USETHEIRANDYOURBLOCK
:
2288 m_pwndBottom
->UseBothLeftFirst();
2290 case POPUPCOMMAND_USEYOURBLOCK
:
2291 m_pwndBottom
->UseRightBlock();
2293 case POPUPCOMMAND_USEYOURFILE
:
2294 m_pwndBottom
->UseRightFile();
2296 case POPUPCOMMAND_USETHEIRBLOCK
:
2297 m_pwndBottom
->UseLeftBlock();
2299 case POPUPCOMMAND_USETHEIRFILE
:
2300 m_pwndBottom
->UseLeftFile();
2302 // copy, cut and paste commands
2315 SaveUndoStep(); // all except copy, cut paste save undo step, but this should not be harmful as step is empty already and thus not saved
2319 void CBaseView::OnContextMenu(CWnd
* /*pWnd*/, CPoint point
)
2324 int nViewBlockStart
= -1;
2325 int nViewBlockEnd
= -1;
2326 GetViewSelection(nViewBlockStart
, nViewBlockEnd
);
2327 if ((point
.x
>= 0) && (point
.y
>= 0))
2329 int nLine
= GetLineFromPoint(point
)-1;
2330 if ((nLine
>= 0) && (nLine
< m_Screen2View
.size()))
2332 int nViewLine
= GetViewLineForScreen(nLine
);
2333 if (((nViewLine
< nViewBlockStart
) || (nViewBlockEnd
< nViewLine
)))
2335 ClearSelection(); // Clear text-copy selection
2337 nViewBlockStart
= nViewLine
;
2338 nViewBlockEnd
= nViewLine
;
2339 DiffStates state
= m_pViewData
->GetState(nViewLine
);
2340 while (nViewBlockStart
> 0)
2342 const DiffStates lineState
= m_pViewData
->GetState(nViewBlockStart
-1);
2343 if (!LinesInOneChange(-1, state
, lineState
))
2348 while (nViewBlockEnd
< (m_pViewData
->GetCount()-1))
2350 const DiffStates lineState
= m_pViewData
->GetState(nViewBlockEnd
+1);
2351 if (!LinesInOneChange(1, state
, lineState
))
2356 SetupAllViewSelection(nViewBlockStart
, nViewBlockEnd
);
2357 UpdateCaretPosition(point
);
2362 // FixSelection(); fix selection range
2363 /*if (m_nSelBlockEnd >= m_pViewData->GetCount())
2364 m_nSelBlockEnd = m_pViewData->GetCount()-1;//*/
2366 DiffStates state
= DIFFSTATE_UNKNOWN
;
2367 if (GetViewSelection(nViewBlockStart
, nViewBlockEnd
))
2369 // find a more 'relevant' state in the selection
2370 for (int i
=nViewBlockStart
; i
<=nViewBlockEnd
; ++i
)
2372 state
= m_pViewData
->GetState(i
);
2373 if ((state
!= DIFFSTATE_NORMAL
) && (state
!= DIFFSTATE_UNKNOWN
))
2377 OnContextMenu(point
, state
);
2380 void CBaseView::RefreshViews()
2384 m_pwndLeft
->UpdateStatusBar();
2385 m_pwndLeft
->Invalidate();
2389 m_pwndRight
->UpdateStatusBar();
2390 m_pwndRight
->Invalidate();
2394 m_pwndBottom
->UpdateStatusBar();
2395 m_pwndBottom
->Invalidate();
2398 m_pwndLocator
->Invalidate();
2401 void CBaseView::GoToFirstDifference()
2403 SetCaretToFirstViewLine();
2404 SelectNextBlock(1, false, false);
2407 void CBaseView::GoToFirstConflict()
2409 SetCaretToFirstViewLine();
2410 SelectNextBlock(1, true, false);
2413 void CBaseView::HighlightLines(int nStart
, int nEnd
/* = -1 */)
2416 SetupAllSelection(nStart
, max(nStart
, nEnd
));
2418 UpdateCaretPosition(SetupPoint(0, nStart
));
2422 void CBaseView::HighlightViewLines(int nStart
, int nEnd
/* = -1 */)
2425 SetupAllViewSelection(nStart
, max(nStart
, nEnd
));
2427 UpdateCaretViewPosition(SetupPoint(0, nStart
));
2431 void CBaseView::SetupAllViewSelection(int start
, int end
)
2433 SetupViewSelection(m_pwndBottom
, start
, end
);
2434 SetupViewSelection(m_pwndLeft
, start
, end
);
2435 SetupViewSelection(m_pwndRight
, start
, end
);
2438 void CBaseView::SetupAllSelection(int start
, int end
)
2440 SetupAllViewSelection(GetViewLineForScreen(start
), GetViewLineForScreen(end
));
2443 //void CBaseView::SetupSelection(CBaseView* view, int start, int end) { }
2445 void CBaseView::SetupSelection(int start
, int end
)
2447 SetupViewSelection(GetViewLineForScreen(start
), GetViewLineForScreen(end
));
2450 void CBaseView::SetupViewSelection(CBaseView
* view
, int start
, int end
)
2452 if (!IsViewGood(view
))
2454 view
->SetupViewSelection(start
, end
);
2457 void CBaseView::SetupViewSelection(int start
, int end
)
2459 // clear text selection before setting line selection ?
2460 m_nSelViewBlockStart
= start
;
2461 m_nSelViewBlockEnd
= end
;
2466 void CBaseView::OnMergePreviousconflict()
2468 SelectNextBlock(-1, true);
2471 void CBaseView::OnMergeNextconflict()
2473 SelectNextBlock(1, true);
2476 void CBaseView::OnMergeNextdifference()
2478 SelectNextBlock(1, false);
2481 void CBaseView::OnMergePreviousdifference()
2483 SelectNextBlock(-1, false);
2486 bool CBaseView::HasNextConflict()
2488 return SelectNextBlock(1, true, true, true);
2491 bool CBaseView::HasPrevConflict()
2493 return SelectNextBlock(-1, true, true, true);
2496 bool CBaseView::HasNextDiff()
2498 return SelectNextBlock(1, false, true, true);
2501 bool CBaseView::HasPrevDiff()
2503 return SelectNextBlock(-1, false, true, true);
2506 bool CBaseView::LinesInOneChange(int direction
,
2507 DiffStates initialLineState
, DiffStates currentLineState
)
2509 // Checks whether all the adjacent lines starting from the initial line
2510 // and up to the current line form the single change
2512 // Do not distinguish between moved and added/removed lines
2513 if (initialLineState
== DIFFSTATE_MOVED_TO
)
2514 initialLineState
= DIFFSTATE_ADDED
;
2515 if (initialLineState
== DIFFSTATE_MOVED_FROM
)
2516 initialLineState
= DIFFSTATE_REMOVED
;
2517 if (currentLineState
== DIFFSTATE_MOVED_TO
)
2518 currentLineState
= DIFFSTATE_ADDED
;
2519 if (currentLineState
== DIFFSTATE_MOVED_FROM
)
2520 currentLineState
= DIFFSTATE_REMOVED
;
2522 // First of all, if the two lines have identical states, they surely
2523 // belong to one change.
2524 if (initialLineState
== currentLineState
)
2527 // Either we move down and initial line state is "added" or "removed" and
2528 // current line state is "empty"...
2531 if (currentLineState
== DIFFSTATE_EMPTY
)
2533 if (initialLineState
== DIFFSTATE_ADDED
|| initialLineState
== DIFFSTATE_REMOVED
)
2536 if (initialLineState
== DIFFSTATE_CONFLICTADDED
&& currentLineState
== DIFFSTATE_CONFLICTEMPTY
)
2539 // ...or we move up and initial line state is "empty" and current line
2540 // state is "added" or "removed".
2543 if (initialLineState
== DIFFSTATE_EMPTY
)
2545 if (currentLineState
== DIFFSTATE_ADDED
|| currentLineState
== DIFFSTATE_REMOVED
)
2548 if (initialLineState
== DIFFSTATE_CONFLICTEMPTY
&& currentLineState
== DIFFSTATE_CONFLICTADDED
)
2554 bool CBaseView::SelectNextBlock(int nDirection
, bool bConflict
, bool bSkipEndOfCurrentBlock
/* = true */, bool dryrun
/* = false */)
2559 const int linesCount
= (int)m_Screen2View
.size();
2563 int nCenterPos
= GetCaretPosition().y
;
2566 nLimit
= linesCount
;
2568 if (nCenterPos
>= linesCount
)
2569 nCenterPos
= linesCount
-1;
2571 if (bSkipEndOfCurrentBlock
)
2573 // Find end of current block
2574 const DiffStates state
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2575 while (nCenterPos
!= nLimit
)
2577 const DiffStates lineState
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2578 if (!LinesInOneChange(nDirection
, state
, lineState
))
2580 nCenterPos
+= nDirection
;
2584 // Find next diff/conflict block
2585 while (nCenterPos
!= nLimit
)
2587 DiffStates linestate
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2589 (linestate
!= DIFFSTATE_NORMAL
) &&
2590 (linestate
!= DIFFSTATE_UNKNOWN
))
2595 ((linestate
== DIFFSTATE_CONFLICTADDED
) ||
2596 (linestate
== DIFFSTATE_CONFLICTED_IGNORED
) ||
2597 (linestate
== DIFFSTATE_CONFLICTED
) ||
2598 (linestate
== DIFFSTATE_CONFLICTEMPTY
)))
2603 nCenterPos
+= nDirection
;
2605 if (nCenterPos
== nLimit
)
2608 return (nCenterPos
!= nLimit
);
2610 // Find end of new block
2611 DiffStates state
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2612 int nBlockEnd
= nCenterPos
;
2613 const int maxAllowedLine
= nLimit
-nDirection
;
2614 while (nBlockEnd
!= maxAllowedLine
)
2616 const int lineIndex
= nBlockEnd
+ nDirection
;
2617 if (lineIndex
>= linesCount
)
2619 DiffStates lineState
= m_pViewData
->GetState(GetViewLineForScreen(lineIndex
));
2620 if (!LinesInOneChange(nDirection
, state
, lineState
))
2622 nBlockEnd
+= nDirection
;
2625 int nTopPos
= nCenterPos
- (GetScreenLines()/2);
2629 POINT ptCaretPos
= {0, nCenterPos
};
2630 SetCaretPosition(ptCaretPos
);
2633 SetupAllSelection(nCenterPos
, nBlockEnd
);
2635 SetupAllSelection(nBlockEnd
, nCenterPos
);
2637 ScrollAllToLine(nTopPos
, FALSE
);
2638 RecalcAllVertScrollBars(TRUE
);
2639 SetCaretToLineStart();
2640 EnsureCaretVisible();
2641 OnNavigateNextinlinediff();
2643 UpdateViewsCaretPosition();
2645 ShowDiffLines(nCenterPos
);
2649 BOOL
CBaseView::OnToolTipNotify(UINT
/*id*/, NMHDR
*pNMHDR
, LRESULT
*pResult
)
2651 if (pNMHDR
->idFrom
!= (UINT
)m_hWnd
)
2655 strTipText
= m_sWindowName
+ _T("\r\n") + m_sFullFilePath
;
2657 DWORD pos
= GetMessagePos();
2658 CPoint
point(GET_X_LPARAM(pos
), GET_Y_LPARAM(pos
));
2659 ScreenToClient(&point
);
2660 const int nLine
= GetButtonEventLineIndex(point
);
2664 int nViewLine
= GetViewLineForScreen(nLine
);
2665 if((m_pViewData
)&&(nViewLine
< m_pViewData
->GetCount()))
2667 if (m_pViewData
->GetState(nViewLine
)==DIFFSTATE_MOVED_FROM
)
2669 strTipText
.Format(IDS_MOVED_TO_TT
, m_pViewData
->GetMovedIndex(nViewLine
)+1);
2671 if (m_pViewData
->GetState(nViewLine
)==DIFFSTATE_MOVED_TO
)
2673 strTipText
.Format(IDS_MOVED_FROM_TT
, m_pViewData
->GetMovedIndex(nViewLine
)+1);
2680 if (strTipText
.IsEmpty())
2683 // need to handle both ANSI and UNICODE versions of the message
2684 if (pNMHDR
->code
== TTN_NEEDTEXTA
)
2686 TOOLTIPTEXTA
* pTTTA
= (TOOLTIPTEXTA
*)pNMHDR
;
2687 pTTTA
->lpszText
= m_szTip
;
2688 WideCharToMultiByte(CP_ACP
, 0, strTipText
, -1, m_szTip
, strTipText
.GetLength()+1, 0, 0);
2692 TOOLTIPTEXTW
* pTTTW
= (TOOLTIPTEXTW
*)pNMHDR
;
2693 lstrcpyn(m_wszTip
, strTipText
, strTipText
.GetLength()+1);
2694 pTTTW
->lpszText
= m_wszTip
;
2697 return TRUE
; // message was handled
2700 INT_PTR
CBaseView::OnToolHitTest(CPoint point
, TOOLINFO
* pTI
) const
2703 GetClientRect(rcClient
);
2704 CRect
textrect(rcClient
.left
, rcClient
.top
, rcClient
.Width(), m_nLineHeight
+HEADERHEIGHT
);
2705 int marginwidth
= MARGINWIDTH
;
2706 if ((m_bViewLinenumbers
)&&(m_pViewData
)&&(m_pViewData
->GetCount())&&(m_nDigits
> 0))
2708 marginwidth
= (MARGINWIDTH
+ (m_nDigits
* m_nCharWidth
) + 2);
2710 CRect
borderrect(rcClient
.left
, rcClient
.top
+m_nLineHeight
+HEADERHEIGHT
, marginwidth
, rcClient
.bottom
);
2712 if (textrect
.PtInRect(point
) || borderrect
.PtInRect(point
))
2714 // inside the header part of the view (showing the filename)
2715 pTI
->hwnd
= this->m_hWnd
;
2716 this->GetClientRect(&pTI
->rect
);
2717 pTI
->uFlags
|= TTF_ALWAYSTIP
| TTF_IDISHWND
;
2718 pTI
->uId
= (UINT
)m_hWnd
;
2719 pTI
->lpszText
= LPSTR_TEXTCALLBACK
;
2721 // we want multi line tooltips
2722 CToolTipCtrl
* pToolTip
= AfxGetModuleThreadState()->m_pToolTip
;
2723 if (pToolTip
->GetSafeHwnd() != NULL
)
2725 pToolTip
->SetMaxTipWidth(INT_MAX
);
2728 return (textrect
.PtInRect(point
) ? 1 : 2);
2734 void CBaseView::OnKeyDown(UINT nChar
, UINT nRepCnt
, UINT nFlags
)
2736 bool bControl
= !!(GetKeyState(VK_CONTROL
)&0x8000);
2737 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
2742 if ((nChar
== '\t') && bControl
)
2744 if (this==m_pwndLeft
)
2746 if (IsViewGood(m_pwndRight
))
2748 m_pwndRight
->SetFocus();
2750 else if (IsViewGood(m_pwndBottom
))
2752 m_pwndBottom
->SetFocus();
2755 else if (this==m_pwndRight
)
2757 if (IsViewGood(m_pwndBottom
))
2759 m_pwndBottom
->SetFocus();
2761 else if (IsViewGood(m_pwndLeft
))
2763 m_pwndLeft
->SetFocus();
2766 else if (this==m_pwndBottom
)
2768 if (IsViewGood(m_pwndLeft
))
2770 m_pwndLeft
->SetFocus();
2772 else if (IsViewGood(m_pwndRight
))
2774 m_pwndRight
->SetFocus();
2781 POINT ptCaretPos
= GetCaretPosition();
2782 ptCaretPos
.y
-= GetScreenLines();
2783 ptCaretPos
.y
= max(ptCaretPos
.y
, 0);
2784 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
2785 SetCaretPosition(ptCaretPos
);
2786 OnCaretMove(MOVELEFT
, bShift
);
2787 ShowDiffLines(ptCaretPos
.y
);
2792 POINT ptCaretPos
= GetCaretPosition();
2793 ptCaretPos
.y
+= GetScreenLines();
2794 if (ptCaretPos
.y
>= GetLineCount())
2795 ptCaretPos
.y
= GetLineCount()-1;
2796 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
2797 SetCaretPosition(ptCaretPos
);
2798 OnCaretMove(MOVERIGHT
, bShift
);
2799 ShowDiffLines(ptCaretPos
.y
);
2807 SetCaretToViewStart();
2808 m_nCaretGoalPos
= 0;
2810 AdjustSelection(MOVELEFT
);
2817 SetCaretToLineStart();
2818 m_nCaretGoalPos
= 0;
2819 OnCaretMove(MOVERIGHT
, bShift
);
2828 ScrollAllToLine(GetLineCount()-GetAllMinScreenLines());
2830 ptCaretPos
.y
= GetLineCount()-1;
2831 ptCaretPos
.x
= GetLineLength(ptCaretPos
.y
);
2832 SetCaretAndGoalPosition(ptCaretPos
);
2834 AdjustSelection(MOVERIGHT
);
2840 POINT ptCaretPos
= GetCaretPosition();
2841 ptCaretPos
.x
= GetLineLength(ptCaretPos
.y
);
2842 if ((GetSubLineOffset(ptCaretPos
.y
) != -1) && (GetSubLineOffset(ptCaretPos
.y
) != CountMultiLines(GetViewLineForScreen(ptCaretPos
.y
))-1)) // not last screen line of view line
2846 SetCaretAndGoalPosition(ptCaretPos
);
2847 OnCaretMove(bShift
);
2854 if (! HasTextSelection())
2856 POINT ptCaretPos
= GetCaretPosition();
2857 if (ptCaretPos
.y
== 0 && ptCaretPos
.x
== 0)
2859 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
2861 MoveCaretWordLeft();
2864 while (MoveCaretLeft() && IsViewLineEmpty(GetCaretViewPosition().y
))
2868 m_ptSelectionViewPosStart
= GetCaretViewPosition();
2870 RemoveSelectedText();
2876 if (! HasTextSelection())
2880 m_ptSelectionViewPosStart
= GetCaretViewPosition();
2881 MoveCaretWordRight();
2882 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
2886 if (! MoveCaretRight())
2888 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
2890 m_ptSelectionViewPosStart
= GetCaretViewPosition();
2893 RemoveSelectedText();
2897 CView::OnKeyDown(nChar
, nRepCnt
, nFlags
);
2900 void CBaseView::OnLButtonDown(UINT nFlags
, CPoint point
)
2902 const int nClickedLine
= GetButtonEventLineIndex(point
);
2903 if ((nClickedLine
>= m_nTopLine
)&&(nClickedLine
< GetLineCount()))
2906 ptCaretPos
.y
= nClickedLine
;
2907 LONG xpos
= point
.x
- GetMarginWidth();
2908 LONG xpos2
= xpos
/ GetCharWidth();
2909 xpos2
+= m_nOffsetChar
;
2910 if ((xpos
% GetCharWidth()) >= (GetCharWidth()/2))
2912 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, xpos2
);
2913 SetCaretAndGoalPosition(ptCaretPos
);
2915 if (nFlags
& MK_SHIFT
)
2916 AdjustSelection(MOVERIGHT
);
2920 SetupAllSelection(ptCaretPos
.y
, ptCaretPos
.y
);
2921 if (point
.x
< GetMarginWidth())
2923 // select the whole line
2924 m_ptSelectionViewPosStart
= m_ptSelectionViewPosEnd
= GetCaretViewPosition();
2925 m_ptSelectionViewPosEnd
.x
= GetViewLineLength(m_ptSelectionViewPosEnd
.y
);
2929 UpdateViewsCaretPosition();
2933 CView::OnLButtonDown(nFlags
, point
);
2936 enum ECharGroup
{ // ordered by priority low-to-hi
2938 CHG_CONTROL
, // x00-x08, x0a-x1f
2939 CHG_WHITESPACE
, // space tab
2940 CHG_PUNCTUATION
, // 0x21-2f, x3a-x40, x5b-x60, x7b-x7f .,:;!?(){}[]/\<> ...
2941 CHG_WORDLETTER
, // alpha num _ (others)
2944 ECharGroup
GetCharGroup(wchar_t zChar
)
2946 if (zChar
== ' ' || zChar
== '\t' )
2948 return CHG_WHITESPACE
;
2954 if ((zChar
>= 0x21 && zChar
<= 0x2f)
2955 || (zChar
>= 0x3a && zChar
<= 0x40)
2956 || (zChar
>= 0x5b && zChar
<= 0x5e)
2958 || (zChar
>= 0x7b && zChar
<= 0x7f))
2960 return CHG_PUNCTUATION
;
2962 return CHG_WORDLETTER
;
2965 void CBaseView::OnLButtonDblClk(UINT nFlags
, CPoint point
)
2967 if (m_pViewData
== 0) {
2968 CView::OnLButtonDblClk(nFlags
, point
);
2972 const int nClickedLine
= GetButtonEventLineIndex(point
);
2973 if ( nClickedLine
< 0)
2975 int nViewLine
= GetViewLineForScreen(nClickedLine
);
2976 if (point
.x
< GetMarginWidth()) // only if double clicked on the margin
2978 if((nViewLine
< m_pViewData
->GetCount())) // a double click on moved line scrolls to corresponding line
2980 if((m_pViewData
->GetState(nViewLine
)==DIFFSTATE_MOVED_FROM
)||
2981 (m_pViewData
->GetState(nViewLine
)==DIFFSTATE_MOVED_TO
))
2983 int movedindex
= m_pViewData
->GetMovedIndex(nViewLine
);
2984 int screenLine
= FindViewLineNumber(movedindex
);
2985 int nTop
= screenLine
- GetScreenLines()/2;
2988 ScrollAllToLine(nTop
);
2989 // find and select the whole moved block
2990 int startSel
= movedindex
;
2991 int endSel
= movedindex
;
2992 while ((startSel
> 0) && ((m_pOtherViewData
->GetState(startSel
) == DIFFSTATE_MOVED_FROM
) || (m_pOtherViewData
->GetState(startSel
) == DIFFSTATE_MOVED_TO
)))
2995 while ((endSel
< GetLineCount()) && ((m_pOtherViewData
->GetState(endSel
) == DIFFSTATE_MOVED_FROM
) || (m_pOtherViewData
->GetState(endSel
) == DIFFSTATE_MOVED_TO
)))
2998 m_pOtherView
->SetupSelection(startSel
, endSel
);
2999 return CView::OnLButtonDblClk(nFlags
, point
);
3003 if ((m_pMainFrame
->m_bCollapsed
)&&(m_pViewData
->GetHideState(nViewLine
) == HIDESTATE_MARKER
))
3005 // a double click on a marker expands the hidden text
3007 while ((i
< m_pViewData
->GetCount())&&(m_pViewData
->GetHideState(i
) != HIDESTATE_SHOWN
))
3009 if ((m_pwndLeft
)&&(m_pwndLeft
->m_pViewData
))
3010 m_pwndLeft
->m_pViewData
->SetLineHideState(i
, HIDESTATE_SHOWN
);
3011 if ((m_pwndRight
)&&(m_pwndRight
->m_pViewData
))
3012 m_pwndRight
->m_pViewData
->SetLineHideState(i
, HIDESTATE_SHOWN
);
3013 if ((m_pwndBottom
)&&(m_pwndBottom
->m_pViewData
))
3014 m_pwndBottom
->m_pViewData
->SetLineHideState(i
, HIDESTATE_SHOWN
);
3017 BuildAllScreen2ViewVector();
3019 m_pwndLeft
->Invalidate();
3021 m_pwndRight
->Invalidate();
3023 m_pwndBottom
->Invalidate();
3028 ptCaretPos
.y
= nClickedLine
;
3029 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth());
3030 SetCaretPosition(ptCaretPos
);
3033 POINT ptViewCarret
= GetCaretViewPosition();
3034 nViewLine
= ptViewCarret
.y
;
3035 if (nViewLine
>= GetViewCount())
3037 CString sLine
= GetViewLine(nViewLine
);
3038 int nLineLength
= sLine
.GetLength();
3039 int nBasePos
= ptViewCarret
.x
;
3040 // get target char group
3041 ECharGroup eLeft
= CHG_UNKNOWN
;
3044 eLeft
= GetCharGroup(sLine
[nBasePos
-1]);
3046 ECharGroup eRight
= CHG_UNKNOWN
;
3047 if (nBasePos
< nLineLength
)
3049 eRight
= GetCharGroup(sLine
[nBasePos
]);
3051 ECharGroup eTarget
= max(eRight
, eLeft
);
3053 int nLeft
= nBasePos
;
3054 while (nLeft
> 0 && GetCharGroup(sLine
[nLeft
-1]) == eTarget
)
3059 int nRight
= nBasePos
;
3060 while (nRight
< nLineLength
&& GetCharGroup(sLine
[nRight
]) == eTarget
)
3065 m_ptSelectionViewPosStart
.x
= nLeft
;
3066 m_ptSelectionViewPosStart
.y
= nViewLine
;
3067 m_ptSelectionViewPosEnd
.x
= nRight
;
3068 m_ptSelectionViewPosEnd
.y
= nViewLine
;
3069 m_ptSelectionViewPosOrigin
= m_ptSelectionViewPosStart
;
3070 SetupAllViewSelection(nViewLine
, nViewLine
);
3072 ptCaretPos
= ConvertViewPosToScreen(m_ptSelectionViewPosEnd
);
3073 UpdateViewsCaretPosition();
3077 m_sPreviousMarkedWord
= m_sMarkedWord
; // store marked word to recall in case of triple click
3078 int nMarkWidth
= max(nRight
- nLeft
, 0);
3079 m_sMarkedWord
= sLine
.Mid(m_ptSelectionViewPosStart
.x
, nMarkWidth
).Trim();
3080 if (m_sMarkedWord
.Compare(m_sPreviousMarkedWord
) == 0)
3082 m_sMarkedWord
.Empty();
3086 m_pwndLeft
->SetMarkedWord(m_sMarkedWord
);
3088 m_pwndRight
->SetMarkedWord(m_sMarkedWord
);
3090 m_pwndBottom
->SetMarkedWord(m_sMarkedWord
);
3094 m_pwndLocator
->Invalidate();
3097 CView::OnLButtonDblClk(nFlags
, point
);
3100 void CBaseView::OnLButtonTrippleClick( UINT
/*nFlags*/, CPoint point
)
3102 const int nClickedLine
= GetButtonEventLineIndex(point
);
3103 if (((point
.y
- HEADERHEIGHT
) / GetLineHeight()) <= 0)
3105 if (!m_sConvertedFilePath
.IsEmpty() && (GetKeyState(VK_CONTROL
)&0x8000))
3107 PCIDLIST_ABSOLUTE __unaligned pidl
= ILCreateFromPath((LPCTSTR
)m_sConvertedFilePath
);
3110 SHOpenFolderAndSelectItems(pidl
,0,0,0);
3111 CoTaskMemFree((LPVOID
)pidl
);
3117 ptCaretPos
.y
= nClickedLine
;
3118 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth());
3119 SetCaretAndGoalPosition(ptCaretPos
);
3120 m_sMarkedWord
= m_sPreviousMarkedWord
; // recall previous Marked word
3122 m_pwndLeft
->SetMarkedWord(m_sMarkedWord
);
3124 m_pwndRight
->SetMarkedWord(m_sMarkedWord
);
3126 m_pwndBottom
->SetMarkedWord(m_sMarkedWord
);
3128 m_ptSelectionViewPosStart
.x
= 0;
3129 m_ptSelectionViewPosStart
.y
= nClickedLine
;
3130 m_ptSelectionViewPosEnd
.x
= GetLineLength(nClickedLine
);
3131 m_ptSelectionViewPosEnd
.y
= nClickedLine
;
3132 SetupSelection(m_ptSelectionViewPosStart
.y
, m_ptSelectionViewPosEnd
.y
);
3133 UpdateViewsCaretPosition();
3136 m_pwndLocator
->Invalidate();
3139 void CBaseView::OnEditCopy()
3141 CString sCopyData
= GetSelectedText();
3143 if (!sCopyData
.IsEmpty())
3145 CStringUtils::WriteAsciiStringToClipboard(sCopyData
, m_hWnd
);
3149 void CBaseView::OnMouseMove(UINT nFlags
, CPoint point
)
3151 if (m_pMainFrame
->m_nMoveMovesToIgnore
> 0)
3153 --m_pMainFrame
->m_nMoveMovesToIgnore
;
3154 CView::OnMouseMove(nFlags
, point
);
3157 int nMouseLine
= GetButtonEventLineIndex(point
);
3158 if (nMouseLine
< -1)
3160 m_mouseInMargin
= point
.x
< GetMarginWidth();
3162 ShowDiffLines(nMouseLine
);
3164 KillTimer(IDT_SCROLLTIMER
);
3165 if (nFlags
& MK_LBUTTON
)
3167 int saveMouseLine
= nMouseLine
>= 0 ? nMouseLine
: 0;
3168 saveMouseLine
= saveMouseLine
< GetLineCount() ? saveMouseLine
: GetLineCount() - 1;
3169 if (saveMouseLine
< 0)
3171 int charIndex
= CalculateCharIndex(saveMouseLine
, m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth());
3172 if (HasSelection() &&
3173 ((nMouseLine
>= m_nTopLine
)&&(nMouseLine
< GetLineCount())))
3175 POINT ptCaretPos
= {charIndex
, nMouseLine
};
3176 SetCaretAndGoalPosition(ptCaretPos
);
3177 AdjustSelection(MOVERIGHT
);
3181 if (nMouseLine
< m_nTopLine
)
3183 ScrollAllToLine(m_nTopLine
-1, TRUE
);
3184 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3186 if (nMouseLine
>= m_nTopLine
+ GetScreenLines() - 2)
3188 ScrollAllToLine(m_nTopLine
+1, TRUE
);
3189 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3191 if (!m_pMainFrame
->m_bWrapLines
&& ((m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth()) <= m_nOffsetChar
))
3194 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3196 if (!m_pMainFrame
->m_bWrapLines
&& (charIndex
>= (GetScreenChars()+m_nOffsetChar
-4)))
3199 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3205 CView::OnMouseMove(nFlags
, point
);
3208 void CBaseView::OnLButtonUp(UINT nFlags
, CPoint point
)
3212 KillTimer(IDT_SCROLLTIMER
);
3214 __super::OnLButtonUp(nFlags
, point
);
3217 void CBaseView::OnTimer(UINT_PTR nIDEvent
)
3219 if (nIDEvent
== IDT_SCROLLTIMER
)
3222 GetCursorPos(&point
);
3223 ScreenToClient(&point
);
3224 int nMouseLine
= GetButtonEventLineIndex(point
);
3225 if (nMouseLine
< -1)
3229 if (GetKeyState(VK_LBUTTON
)&0x8000)
3231 int saveMouseLine
= nMouseLine
>= 0 ? nMouseLine
: 0;
3232 saveMouseLine
= saveMouseLine
< GetLineCount() ? saveMouseLine
: GetLineCount() - 1;
3233 int charIndex
= CalculateCharIndex(saveMouseLine
, m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth());
3234 if (nMouseLine
< m_nTopLine
)
3236 ScrollAllToLine(m_nTopLine
-1, TRUE
);
3237 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3239 if (nMouseLine
>= m_nTopLine
+ GetScreenLines() - 2)
3241 ScrollAllToLine(m_nTopLine
+1, TRUE
);
3242 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3244 if (!m_pMainFrame
->m_bWrapLines
&& ((m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth()) <= m_nOffsetChar
))
3247 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3249 if (!m_pMainFrame
->m_bWrapLines
&& (charIndex
>= (GetScreenChars()+m_nOffsetChar
-4)))
3252 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3258 CView::OnTimer(nIDEvent
);
3261 void CBaseView::ShowDiffLines(int nLine
)
3263 if ((nLine
< m_nTopLine
)||(nLine
>= GetLineCount()))
3265 m_pwndLineDiffBar
->ShowLines(nLine
);
3267 m_nMouseLine
= nLine
;
3271 if ((!m_pwndRight
)||(!m_pwndLeft
))
3273 if(m_pMainFrame
->m_bOneWay
)
3276 nLine
= (nLine
> (int)m_pwndRight
->m_Screen2View
.size() ? -1 : nLine
);
3277 nLine
= (nLine
> (int)m_pwndLeft
->m_Screen2View
.size() ? -1 : nLine
);
3282 if (nLine
!= m_nMouseLine
)
3284 if (nLine
>= GetLineCount())
3286 m_nMouseLine
= nLine
;
3287 m_pwndLineDiffBar
->ShowLines(nLine
);
3289 m_pMainFrame
->m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
3292 const viewdata
& CBaseView::GetEmptyLineData()
3294 static const viewdata
emptyLine(_T(""), DIFFSTATE_EMPTY
, -1, EOL_NOENDING
, HIDESTATE_SHOWN
, -1);
3298 void CBaseView::InsertViewEmptyLines(int nFirstView
, int nCount
)
3300 for (int i
= 0; i
< nCount
; i
++)
3302 InsertViewData(nFirstView
, GetEmptyLineData());
3307 void CBaseView::UpdateCaret()
3309 POINT ptCaretPos
= GetCaretPosition();
3310 ptCaretPos
.y
= std::max
<int>(std::min
<int>(ptCaretPos
.y
, GetLineCount()-1), 0);
3311 ptCaretPos
.x
= std::max
<int>(std::min
<int>(ptCaretPos
.x
, GetLineLength(ptCaretPos
.y
)), 0);
3312 SetCaretPosition(ptCaretPos
);
3314 int nCaretOffset
= CalculateActualOffset(ptCaretPos
);
3317 ptCaretPos
.y
>= m_nTopLine
&&
3318 ptCaretPos
.y
< (m_nTopLine
+GetScreenLines()) &&
3319 nCaretOffset
>= m_nOffsetChar
&&
3320 nCaretOffset
< (m_nOffsetChar
+GetScreenChars()))
3322 CreateSolidCaret(2, GetLineHeight());
3323 SetCaretPos(TextToClient(ptCaretPos
));
3332 POINT
CBaseView::ConvertScreenPosToView(const POINT
& pt
)
3337 int nSubLine
= GetSubLineOffset(pt
.y
);
3340 for (int nScreenLine
= pt
.y
-1; nScreenLine
>= pt
.y
-nSubLine
; nScreenLine
--)
3342 ptViewPos
.x
+= GetLineChars(nScreenLine
).GetLength();
3346 ptViewPos
.y
= GetViewLineForScreen(pt
.y
);
3350 POINT
CBaseView::ConvertViewPosToScreen(const POINT
& pt
)
3353 int nViewLineLenLeft
= GetViewLineLength(pt
.y
);
3354 ptPos
.x
= min(nViewLineLenLeft
, pt
.x
);
3355 ptPos
.y
= FindScreenLineForViewLine(pt
.y
);
3356 if (GetViewLineForScreen(ptPos
.y
) != pt
.y
)
3360 else if (GetSubLineOffset(ptPos
.y
) >= 0) // sublined
3362 int nSubLineLength
= GetLineChars(ptPos
.y
).GetLength();
3363 while (nSubLineLength
< ptPos
.x
)
3365 ptPos
.x
-= nSubLineLength
;
3366 nViewLineLenLeft
-= nSubLineLength
;
3368 nSubLineLength
= GetLineChars(ptPos
.y
).GetLength();
3370 // last pos of non last sub-line go to start of next screen line
3371 // Note: while this works correctly, it's not what a user might expect:
3372 // cursor-right when the caret is before the last char of a wrapped line
3373 // now moves the caret to the next line. But users expect the caret to
3374 // move to the right of the last char instead, and with another cursor-right
3375 // keystroke to move the caret to the next line.
3376 // Basically, this would require to handle two caret positions for the same
3377 // logical position in the line string (one on the last position of the first line,
3378 // one on the first position of the new line. For non-wrapped lines this works
3379 // because there's an 'invisible' newline char at the end of the first line.
3380 if (nSubLineLength
== ptPos
.x
&& nViewLineLenLeft
> nSubLineLength
)
3391 void CBaseView::EnsureCaretVisible()
3393 POINT ptCaretPos
= GetCaretPosition();
3394 int nCaretOffset
= CalculateActualOffset(ptCaretPos
);
3396 if (ptCaretPos
.y
< m_nTopLine
)
3397 ScrollAllToLine(ptCaretPos
.y
);
3398 int screnLines
= GetScreenLines();
3401 if (ptCaretPos
.y
>= (m_nTopLine
+screnLines
)-1)
3402 ScrollAllToLine(ptCaretPos
.y
-screnLines
+2);
3403 if (nCaretOffset
< m_nOffsetChar
)
3404 ScrollAllToChar(nCaretOffset
);
3405 if (nCaretOffset
> (m_nOffsetChar
+GetScreenChars()-1))
3406 ScrollAllToChar(nCaretOffset
-GetScreenChars()+1);
3410 int CBaseView::CalculateActualOffset(const POINT
& point
)
3412 int nLineIndex
= point
.y
;
3413 int nCharIndex
= point
.x
;
3414 ASSERT(nCharIndex
>= 0);
3415 CString sLine
= GetLineChars(nLineIndex
);
3416 int nLineLength
= sLine
.GetLength();
3417 return CountExpandedChars(sLine
, min(nCharIndex
, nLineLength
));
3420 int CBaseView::CalculateCharIndex(int nLineIndex
, int nActualOffset
)
3422 int nLength
= GetLineLength(nLineIndex
);
3423 int nSubLine
= GetSubLineOffset(nLineIndex
);
3426 int nViewLine
= GetViewLineForScreen(nLineIndex
);
3427 if ((nViewLine
>=0)&&(nViewLine
< (int)m_ScreenedViewLine
.size()))
3429 int nMultilineCount
= CountMultiLines(nViewLine
);
3430 if ((nMultilineCount
>0) && (nSubLine
<nMultilineCount
-1))
3436 CString Line
= GetLineChars(nLineIndex
);
3439 int nTabSize
= GetTabSize();
3440 while (nOffset
< nActualOffset
&& nIndex
< nLength
)
3442 if (Line
.GetAt(nIndex
) == _T('\t'))
3443 nOffset
+= (nTabSize
- nOffset
% nTabSize
);
3451 POINT
CBaseView::TextToClient(const POINT
& point
)
3454 int nOffsetScreenLine
= max(0, (point
.y
- m_nTopLine
));
3455 pt
.y
= nOffsetScreenLine
* GetLineHeight();
3456 pt
.x
= CalculateActualOffset(point
);
3458 int nLeft
= GetMarginWidth() - m_nOffsetChar
* GetCharWidth();
3459 CDC
* pDC
= GetDC();
3462 pDC
->SelectObject(GetFont()); // is this right font ?
3463 int nScreenLine
= nOffsetScreenLine
+ m_nTopLine
;
3464 CString sLine
= GetLineChars(nScreenLine
);
3465 ExpandChars(sLine
, 0, std::min
<int>(pt
.x
, sLine
.GetLength()), sLine
);
3466 nLeft
+= pDC
->GetTextExtent(sLine
, pt
.x
).cx
;
3469 nLeft
+= pt
.x
* GetCharWidth();
3473 pt
.y
= (pt
.y
+ GetLineHeight() + HEADERHEIGHT
);
3477 void CBaseView::OnChar(UINT nChar
, UINT nRepCnt
, UINT nFlags
)
3479 CView::OnChar(nChar
, nRepCnt
, nFlags
);
3484 if ((::GetKeyState(VK_LBUTTON
) & 0x8000) != 0 ||
3485 (::GetKeyState(VK_RBUTTON
) & 0x8000) != 0)
3490 if (!m_pViewData
) // no data - nothing to do
3493 if (nChar
== VK_F16
)
3495 // generated by a ctrl+backspace - ignore.
3497 else if ((nChar
> 31)||(nChar
== VK_TAB
))
3500 RemoveSelectedText();
3501 POINT ptCaretViewPos
= GetCaretViewPosition();
3502 int nViewLine
= ptCaretViewPos
.y
;
3503 if ((nViewLine
==0)&&(GetViewCount()==0))
3504 OnChar(VK_RETURN
, 0, 0);
3505 viewdata lineData
= GetViewData(nViewLine
);
3506 lineData
.sLine
.Insert(ptCaretViewPos
.x
, (wchar_t)nChar
);
3507 if (IsStateEmpty(lineData
.state
))
3509 // if not last line set EOL
3510 for (int nCheckViewLine
= nViewLine
+1; nCheckViewLine
< GetViewCount(); nCheckViewLine
++)
3512 if (!IsViewLineEmpty(nCheckViewLine
))
3514 lineData
.ending
= lineendings
;
3518 // make sure previous (non empty) line have EOL set
3519 for (int nCheckViewLine
= nViewLine
-1; nCheckViewLine
> 0; nCheckViewLine
--)
3521 if (!IsViewLineEmpty(nCheckViewLine
))
3523 if (GetViewLineEnding(nCheckViewLine
) == EOL_NOENDING
)
3525 SetViewLineEnding(nCheckViewLine
, lineendings
);
3531 lineData
.state
= DIFFSTATE_EDITED
;
3532 bool bNeedRenumber
= false;
3533 if (lineData
.linenumber
== -1)
3535 lineData
.linenumber
= 0;
3536 bNeedRenumber
= true;
3538 SetViewData(nViewLine
, lineData
);
3540 BuildAllScreen2ViewVector(nViewLine
);
3543 UpdateViewLineNumbers();
3548 else if (nChar
== 10)
3550 int nViewLine
= GetViewLineForScreen(GetCaretPosition().y
);
3551 EOL eol
= m_pViewData
->GetLineEnding(nViewLine
);
3552 EOL newEOL
= EOL_CRLF
;
3565 if (eol
==EOL_NOENDING
|| eol
==newEOL
)
3566 // don't allow to change enter on empty line, or last text line (lines with EOL_NOENDING)
3567 // to add EOL on newly edited empty line hit enter
3568 // don't store into UNDO if no change happened
3569 // and don't mark file as modified
3571 AddUndoViewLine(nViewLine
);
3572 m_pViewData
->SetLineEnding(nViewLine
, newEOL
);
3573 m_pViewData
->SetState(nViewLine
, DIFFSTATE_EDITED
);
3576 else if (nChar
== VK_RETURN
)
3578 // insert a new, fresh and empty line below the cursor
3579 RemoveSelectedText();
3581 CUndo::GetInstance().BeginGrouping();
3583 POINT ptCaretViewPos
= GetCaretViewPosition();
3584 int nViewLine
= ptCaretViewPos
.y
;
3585 int nLeft
= ptCaretViewPos
.x
;
3586 CString sLine
= GetViewLineChars(nViewLine
);
3587 CString sLineLeft
= sLine
.Left(nLeft
);
3588 CString sLineRight
= sLine
.Right(sLine
.GetLength() - nLeft
);
3589 EOL eOriginalEnding
= EOL_AUTOLINE
;
3590 if (m_pViewData
->GetCount() > nViewLine
)
3591 eOriginalEnding
= GetViewLineEnding(nViewLine
);
3593 if (!sLineRight
.IsEmpty() || (eOriginalEnding
!=lineendings
))
3595 viewdata
newFirstLine(sLineLeft
, DIFFSTATE_EDITED
, 1, lineendings
, HIDESTATE_SHOWN
, -1);
3596 SetViewData(nViewLine
, newFirstLine
);
3599 int nInsertLine
= (m_pViewData
->GetCount()==0) ? 0 : nViewLine
+ 1;
3600 viewdata
newLastLine(sLineRight
, DIFFSTATE_EDITED
, 1, eOriginalEnding
, HIDESTATE_SHOWN
, -1);
3601 InsertViewData(nInsertLine
, newLastLine
);
3604 // adds new line everywhere except me
3605 if (IsViewGood(m_pwndLeft
) && m_pwndLeft
!=this)
3607 m_pwndLeft
->InsertViewEmptyLines(nInsertLine
, 1);
3609 if (IsViewGood(m_pwndRight
) && m_pwndRight
!=this)
3611 m_pwndRight
->InsertViewEmptyLines(nInsertLine
, 1);
3613 if (IsViewGood(m_pwndBottom
) && m_pwndBottom
!=this)
3615 m_pwndBottom
->InsertViewEmptyLines(nInsertLine
, 1);
3619 UpdateViewLineNumbers();
3621 CUndo::GetInstance().EndGrouping();
3623 BuildAllScreen2ViewVector();
3624 // move the cursor to the new line
3625 ptCaretViewPos
= SetupPoint(0, nViewLine
+1);
3626 SetCaretAndGoalViewPosition(ptCaretViewPos
);
3629 return; // Unknown control character -- ignore it.
3631 EnsureCaretVisible();
3637 void CBaseView::AddUndoViewLine(int nViewLine
, bool bAddEmptyLine
)
3640 m_AllState
.left
.AddViewLineFromView(m_pwndLeft
, nViewLine
, bAddEmptyLine
);
3641 m_AllState
.right
.AddViewLineFromView(m_pwndRight
, nViewLine
, bAddEmptyLine
);
3642 m_AllState
.bottom
.AddViewLineFromView(m_pwndBottom
, nViewLine
, bAddEmptyLine
);
3644 RecalcAllVertScrollBars();
3648 void CBaseView::AddEmptyViewLine(int nViewLineIndex
)
3650 if (m_pViewData
== NULL
)
3652 int viewLine
= nViewLineIndex
;
3653 EOL ending
= m_pViewData
->GetLineEnding(viewLine
);
3654 if (ending
== EOL_NOENDING
)
3656 ending
= lineendings
;
3658 viewdata
newLine(_T(""), DIFFSTATE_EDITED
, -1, ending
, HIDESTATE_SHOWN
, -1);
3659 if (IsTarget()) // TODO: once more wievs will writable this is not correct anymore
3661 CString sPartLine
= GetViewLineChars(nViewLineIndex
);
3662 int nPosx
= GetCaretPosition().x
; // should be view pos ?
3663 m_pViewData
->SetLine(viewLine
, sPartLine
.Left(nPosx
));
3664 sPartLine
= sPartLine
.Mid(nPosx
);
3665 newLine
.sLine
= sPartLine
;
3667 m_pViewData
->InsertData(viewLine
+1, newLine
);
3668 BuildAllScreen2ViewVector();
3671 void CBaseView::RemoveSelectedText()
3673 if (m_pViewData
== NULL
)
3675 if (!HasTextSelection())
3678 // fix selection if starts or ends on empty line
3679 SetCaretViewPosition(m_ptSelectionViewPosEnd
);
3680 while (IsViewLineEmpty(GetCaretViewPosition().y
) && MoveCaretRight())
3683 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
3684 SetCaretViewPosition(m_ptSelectionViewPosStart
);
3685 while (IsViewLineEmpty(GetCaretViewPosition().y
) && MoveCaretRight())
3688 m_ptSelectionViewPosStart
= GetCaretViewPosition();
3689 if (!HasTextSelection())
3695 // We want to undo the insertion in a single step.
3697 CUndo::GetInstance().BeginGrouping();
3699 // combine first and last line
3700 viewdata oFirstLine
= GetViewData(m_ptSelectionViewPosStart
.y
);
3701 viewdata oLastLine
= GetViewData(m_ptSelectionViewPosEnd
.y
);
3702 oFirstLine
.sLine
= oFirstLine
.sLine
.Left(m_ptSelectionViewPosStart
.x
) + oLastLine
.sLine
.Mid(m_ptSelectionViewPosEnd
.x
);
3703 oFirstLine
.ending
= oLastLine
.ending
;
3704 oFirstLine
.state
= DIFFSTATE_EDITED
;
3705 SetViewData(m_ptSelectionViewPosStart
.y
, oFirstLine
);
3707 // clean up middle lines if any
3708 if (m_ptSelectionViewPosStart
.y
!= m_ptSelectionViewPosEnd
.y
)
3710 viewdata oEmptyLine
= GetEmptyLineData();
3711 for (int nViewLine
= m_ptSelectionViewPosStart
.y
+1; nViewLine
<= m_ptSelectionViewPosEnd
.y
; nViewLine
++)
3713 SetViewData(nViewLine
, oEmptyLine
);
3717 if (CleanEmptyLines())
3719 BuildAllScreen2ViewVector(); // schedule full rebuild
3722 UpdateViewLineNumbers();
3726 CUndo::GetInstance().EndGrouping();
3729 BuildAllScreen2ViewVector(m_ptSelectionViewPosStart
.y
, m_ptSelectionViewPosEnd
.y
);
3730 SetCaretViewPosition(m_ptSelectionViewPosStart
);
3734 EnsureCaretVisible();
3738 void CBaseView::PasteText()
3740 if (!OpenClipboard())
3743 CString sClipboardText
;
3744 HGLOBAL hglb
= GetClipboardData(CF_TEXT
);
3747 LPCSTR lpstr
= (LPCSTR
)GlobalLock(hglb
);
3748 sClipboardText
= CString(lpstr
);
3751 hglb
= GetClipboardData(CF_UNICODETEXT
);
3754 LPCTSTR lpstr
= (LPCTSTR
)GlobalLock(hglb
);
3755 sClipboardText
= lpstr
;
3760 if (sClipboardText
.IsEmpty())
3763 sClipboardText
.Replace(_T("\r\n"), _T("\r"));
3764 sClipboardText
.Replace('\n', '\r');
3768 POINT ptCaretViewPos
= GetCaretViewPosition();
3769 int nLeft
= ptCaretViewPos
.x
;
3770 int nViewLine
= ptCaretViewPos
.y
;
3772 if ((nViewLine
==0)&&(GetViewCount()==0))
3773 OnChar(VK_RETURN
, 0, 0);
3775 std::vector
<CString
> lines
;
3778 while ((nEolPos
= sClipboardText
.Find('\r', nEolPos
))>=0)
3780 CString sLine
= sClipboardText
.Mid(nStart
, nEolPos
-nStart
);
3781 lines
.push_back(sLine
);
3785 CString sLine
= sClipboardText
.Mid(nStart
);
3786 lines
.push_back(sLine
);
3788 int nLinesToPaste
= (int)lines
.size();
3789 if (nLinesToPaste
> 1)
3793 // We want to undo the multiline insertion in a single step.
3794 CUndo::GetInstance().BeginGrouping();
3796 sLine
= GetViewLineChars(nViewLine
);
3797 CString sLineLeft
= sLine
.Left(nLeft
);
3798 CString sLineRight
= sLine
.Right(sLine
.GetLength() - nLeft
);
3799 EOL eOriginalEnding
= GetViewLineEnding(nViewLine
);
3800 viewdata
newLine(_T(""), DIFFSTATE_EDITED
, 1, lineendings
, HIDESTATE_SHOWN
, -1);
3801 if (!lines
[0].IsEmpty() || !sLineRight
.IsEmpty() || (eOriginalEnding
!=lineendings
))
3803 newLine
.sLine
= sLineLeft
+ lines
[0];
3804 SetViewData(nViewLine
, newLine
);
3807 int nInsertLine
= nViewLine
;
3808 for (int i
= 1; i
< nLinesToPaste
-1; i
++)
3810 newLine
.sLine
= lines
[i
];
3811 InsertViewData(++nInsertLine
, newLine
);
3813 newLine
.sLine
= lines
[nLinesToPaste
-1] + sLineRight
;
3814 newLine
.ending
= eOriginalEnding
;
3815 InsertViewData(++nInsertLine
, newLine
);
3819 // adds new lines everywhere except me
3820 if (IsViewGood(m_pwndLeft
) && m_pwndLeft
!=this)
3822 m_pwndLeft
->InsertViewEmptyLines(nViewLine
+1, nLinesToPaste
-1);
3824 if (IsViewGood(m_pwndRight
) && m_pwndRight
!=this)
3826 m_pwndRight
->InsertViewEmptyLines(nViewLine
+1, nLinesToPaste
-1);
3828 if (IsViewGood(m_pwndBottom
) && m_pwndBottom
!=this)
3830 m_pwndBottom
->InsertViewEmptyLines(nViewLine
+1, nLinesToPaste
-1);
3834 UpdateViewLineNumbers();
3835 CUndo::GetInstance().EndGrouping();
3837 ptCaretViewPos
= SetupPoint(lines
[nLinesToPaste
-1].GetLength(), nInsertLine
);
3841 // single line text - just insert it
3842 sLine
= GetViewLineChars(nViewLine
);
3843 sLine
.Insert(nLeft
, sClipboardText
);
3844 ptCaretViewPos
= SetupPoint(nLeft
+ sClipboardText
.GetLength(), nViewLine
);
3845 SetViewLine(nViewLine
, sLine
);
3846 SetViewState(nViewLine
, DIFFSTATE_EDITED
);
3852 BuildAllScreen2ViewVector();
3853 UpdateCaretViewPosition(ptCaretViewPos
);
3856 void CBaseView::OnCaretDown()
3858 POINT ptCaretPos
= GetCaretPosition();
3859 int nLine
= ptCaretPos
.y
;
3860 int nNextLine
= nLine
+ 1;
3861 if (nNextLine
>= GetLineCount()) // already at last line
3866 POINT ptCaretViewPos
= GetCaretViewPosition();
3867 int nViewLine
= ptCaretViewPos
.y
;
3868 int nNextViewLine
= GetViewLineForScreen(nNextLine
);
3869 if (!((nNextViewLine
== nViewLine
) && (GetSubLineOffset(nNextLine
)<CountMultiLines(nNextViewLine
)))) // not on same view line
3871 // find next suitable screen line
3872 while ((nNextViewLine
== nViewLine
) || IsViewLineHidden(nNextViewLine
))
3875 if (nNextLine
>= GetLineCount())
3879 nNextViewLine
= GetViewLineForScreen(nNextLine
);
3882 ptCaretPos
.y
= nNextLine
;
3883 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
3884 SetCaretPosition(ptCaretPos
);
3885 OnCaretMove(MOVELEFT
);
3886 ShowDiffLines(ptCaretPos
.y
);
3889 bool CBaseView::MoveCaretLeft()
3891 POINT ptCaretViewPos
= GetCaretViewPosition();
3893 //int nViewLine = ptCaretViewPos.y;
3894 if (ptCaretViewPos
.x
== 0)
3896 int nPrevLine
= GetCaretPosition().y
;
3904 nPrevViewLine
= GetViewLineForScreen(nPrevLine
);
3905 } while ((GetSubLineOffset(nPrevLine
) >= CountMultiLines(nPrevViewLine
)) || IsViewLineHidden(nPrevViewLine
));
3906 ptCaretViewPos
= ConvertScreenPosToView(SetupPoint(GetLineLength(nPrevLine
), nPrevLine
));
3907 ShowDiffLines(nPrevLine
);
3912 SetCaretAndGoalViewPosition(ptCaretViewPos
);
3916 bool CBaseView::MoveCaretRight()
3918 POINT ptCaretViewPos
= GetCaretViewPosition();
3920 int nViewLine
= ptCaretViewPos
.y
;
3921 int nViewLineLen
= GetViewLineLength(nViewLine
);
3922 if (ptCaretViewPos
.x
>= nViewLineLen
)
3924 int nNextLine
= GetCaretPosition().y
;
3928 if (nNextLine
>= GetLineCount())
3932 nNextViewLine
= GetViewLineForScreen(nNextLine
);
3933 } while (nNextViewLine
== nViewLine
|| IsViewLineHidden(nNextViewLine
));
3934 ptCaretViewPos
.y
= nNextViewLine
;
3935 ptCaretViewPos
.x
= 0;
3936 ShowDiffLines(nNextLine
);
3941 SetCaretAndGoalViewPosition(ptCaretViewPos
);
3945 void CBaseView::UpdateGoalPos()
3947 m_nCaretGoalPos
= CalculateActualOffset(GetCaretPosition());
3950 void CBaseView::OnCaretLeft()
3953 OnCaretMove(MOVELEFT
);
3956 void CBaseView::OnCaretRight()
3959 OnCaretMove(MOVERIGHT
);
3962 void CBaseView::OnCaretUp()
3964 POINT ptCaretPos
= GetCaretPosition();
3965 int nLine
= ptCaretPos
.y
;
3966 if (nLine
<= 0) // already at first line
3970 int nPrevLine
= nLine
- 1;
3972 POINT ptCaretViewPos
= GetCaretViewPosition();
3973 int nViewLine
= ptCaretViewPos
.y
;
3974 int nPrevViewLine
= GetViewLineForScreen(nPrevLine
);
3975 if (nPrevViewLine
!= nViewLine
) // not on same view line
3977 // find previous suitable screen line
3978 while ((GetSubLineOffset(nPrevLine
) >= CountMultiLines(nPrevViewLine
)) || IsViewLineHidden(nPrevViewLine
))
3985 nPrevViewLine
= GetViewLineForScreen(nPrevLine
);
3988 ptCaretPos
.y
= nPrevLine
;
3989 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
3990 SetCaretPosition(ptCaretPos
);
3991 OnCaretMove(MOVELEFT
);
3992 ShowDiffLines(ptCaretPos
.y
);
3995 bool CBaseView::IsWordSeparator(const wchar_t ch
) const
3997 return ch
== ' ' || ch
== '\t' || (m_sWordSeparators
.Find(ch
) >= 0);
4000 bool CBaseView::IsCaretAtWordBoundary()
4002 POINT ptViewCaret
= GetCaretViewPosition();
4003 CString line
= GetViewLineChars(ptViewCaret
.y
);
4005 return false; // no boundary at the empty lines
4006 if (ptViewCaret
.x
== 0)
4007 return !IsWordSeparator(line
.GetAt(ptViewCaret
.x
));
4008 if (ptViewCaret
.x
>= GetViewLineLength(ptViewCaret
.y
))
4009 return !IsWordSeparator(line
.GetAt(ptViewCaret
.x
- 1));
4011 IsWordSeparator(line
.GetAt(ptViewCaret
.x
)) !=
4012 IsWordSeparator(line
.GetAt(ptViewCaret
.x
- 1));
4015 void CBaseView::UpdateViewsCaretPosition()
4017 POINT ptCaretPos
= GetCaretPosition();
4018 if (m_pwndBottom
&& m_pwndBottom
!=this)
4019 m_pwndBottom
->UpdateCaretPosition(ptCaretPos
);
4020 if (m_pwndLeft
&& m_pwndLeft
!=this)
4021 m_pwndLeft
->UpdateCaretPosition(ptCaretPos
);
4022 if (m_pwndRight
&& m_pwndRight
!=this)
4023 m_pwndRight
->UpdateCaretPosition(ptCaretPos
);
4026 void CBaseView::OnCaretWordleft()
4028 MoveCaretWordLeft();
4029 OnCaretMove(MOVELEFT
);
4032 void CBaseView::OnCaretWordright()
4034 MoveCaretWordRight();
4035 OnCaretMove(MOVERIGHT
);
4038 void CBaseView::MoveCaretWordLeft()
4040 while (MoveCaretLeft() && !IsCaretAtWordBoundary())
4045 void CBaseView::MoveCaretWordRight()
4047 while (MoveCaretRight() && !IsCaretAtWordBoundary())
4052 void CBaseView::ClearCurrentSelection()
4054 m_ptSelectionViewPosStart
= GetCaretViewPosition();
4055 m_ptSelectionViewPosEnd
= m_ptSelectionViewPosStart
;
4056 m_ptSelectionViewPosOrigin
= m_ptSelectionViewPosStart
;
4057 m_nSelViewBlockStart
= -1;
4058 m_nSelViewBlockEnd
= -1;
4062 void CBaseView::ClearSelection()
4065 m_pwndLeft
->ClearCurrentSelection();
4067 m_pwndRight
->ClearCurrentSelection();
4069 m_pwndBottom
->ClearCurrentSelection();
4072 void CBaseView::AdjustSelection(bool bMoveLeft
)
4074 POINT ptCaretViewPos
= GetCaretViewPosition();
4075 if (ArePointsSame(m_ptSelectionViewPosOrigin
, SetupPoint(-1, -1)))
4077 // select all have been used recently update origin
4078 m_ptSelectionViewPosOrigin
= bMoveLeft
? m_ptSelectionViewPosEnd
: m_ptSelectionViewPosStart
;
4080 if ((ptCaretViewPos
.y
< m_ptSelectionViewPosOrigin
.y
) ||
4081 (ptCaretViewPos
.y
== m_ptSelectionViewPosOrigin
.y
&& ptCaretViewPos
.x
<= m_ptSelectionViewPosOrigin
.x
))
4083 m_ptSelectionViewPosStart
= ptCaretViewPos
;
4084 m_ptSelectionViewPosEnd
= m_ptSelectionViewPosOrigin
;
4088 m_ptSelectionViewPosStart
= m_ptSelectionViewPosOrigin
;
4089 m_ptSelectionViewPosEnd
= ptCaretViewPos
;
4092 SetupAllViewSelection(m_ptSelectionViewPosStart
.y
, m_ptSelectionViewPosEnd
.y
);
4097 void CBaseView::OnEditCut()
4102 RemoveSelectedText();
4106 void CBaseView::OnEditPaste()
4110 CUndo::GetInstance().BeginGrouping();
4111 RemoveSelectedText();
4113 CUndo::GetInstance().EndGrouping();
4117 void CBaseView::DeleteFonts()
4119 for (int i
=0; i
<fontsCount
; i
++)
4121 if (m_apFonts
[i
] != NULL
)
4123 m_apFonts
[i
]->DeleteObject();
4124 delete m_apFonts
[i
];
4125 m_apFonts
[i
] = NULL
;
4130 void CBaseView::OnCaretMove(bool bMoveLeft
)
4132 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
4133 OnCaretMove(bMoveLeft
, bShift
);
4136 void CBaseView::OnCaretMove(bool bMoveLeft
, bool isShiftPressed
)
4139 AdjustSelection(bMoveLeft
);
4142 EnsureCaretVisible();
4146 void CBaseView::AddContextItems(CIconMenu
& popup
, DiffStates
/*state*/)
4148 AddCutCopyAndPaste(popup
);
4151 void CBaseView::AddCutCopyAndPaste(CIconMenu
& popup
)
4153 popup
.AppendMenu(MF_SEPARATOR
, NULL
);
4155 temp
.LoadString(IDS_EDIT_COPY
);
4156 popup
.AppendMenu(MF_STRING
| (HasTextSelection() ? MF_ENABLED
: MF_DISABLED
|MF_GRAYED
), ID_EDIT_COPY
, temp
);
4159 temp
.LoadString(IDS_EDIT_CUT
);
4160 popup
.AppendMenu(MF_STRING
| (HasTextSelection() ? MF_ENABLED
: MF_DISABLED
|MF_GRAYED
), ID_EDIT_CUT
, temp
);
4161 temp
.LoadString(IDS_EDIT_PASTE
);
4162 popup
.AppendMenu(MF_STRING
| (CAppUtils::HasClipboardFormat(CF_UNICODETEXT
)||CAppUtils::HasClipboardFormat(CF_TEXT
) ? MF_ENABLED
: MF_DISABLED
|MF_GRAYED
), ID_EDIT_PASTE
, temp
);
4166 void CBaseView::CompensateForKeyboard(CPoint
& point
)
4168 // if the context menu is invoked through the keyboard, we have to use
4169 // a calculated position on where to anchor the menu on
4170 if (ArePointsSame(point
, SetupPoint(-1, -1)))
4173 GetWindowRect(&rect
);
4174 point
= rect
.CenterPoint();
4178 HICON
CBaseView::LoadIcon(WORD iconId
)
4180 HANDLE icon
= ::LoadImage( AfxGetResourceHandle(), MAKEINTRESOURCE(iconId
),
4181 IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
4185 void CBaseView::ReleaseBitmap()
4187 if (m_pCacheBitmap
!= NULL
)
4189 m_pCacheBitmap
->DeleteObject();
4190 delete m_pCacheBitmap
;
4191 m_pCacheBitmap
= NULL
;
4195 void CBaseView::BuildMarkedWordArray()
4197 int lineCount
= GetLineCount();
4198 m_arMarkedWordLines
.clear();
4199 m_arMarkedWordLines
.reserve(lineCount
);
4200 bool bDoit
= !m_sMarkedWord
.IsEmpty();
4201 for (int i
= 0; i
< lineCount
; ++i
)
4205 CString line
= GetLineChars(i
);
4207 if (!line
.IsEmpty())
4209 m_arMarkedWordLines
.push_back(line
.Find(m_sMarkedWord
) != -1);
4212 m_arMarkedWordLines
.push_back(0);
4215 m_arMarkedWordLines
.push_back(0);
4219 void CBaseView::BuildFindStringArray()
4221 int lineCount
= GetLineCount();
4222 m_arFindStringLines
.clear();
4223 m_arFindStringLines
.reserve(lineCount
);
4224 bool bDoit
= !m_sFindText
.IsEmpty();
4227 for (int i
= 0; i
< lineCount
; ++i
)
4231 CString line
= GetLineChars(i
);
4233 if (!line
.IsEmpty())
4235 line
= line
.MakeLower();
4236 m_arFindStringLines
.push_back(StringFound(line
, SearchNext
, s
, e
));
4239 m_arFindStringLines
.push_back(0);
4242 m_arFindStringLines
.push_back(0);
4247 bool CBaseView::GetInlineDiffPositions(int nViewLine
, std::vector
<inlineDiffPos
>& positions
)
4249 if (!m_bShowInlineDiff
)
4251 if ((m_pwndBottom
!= NULL
) && !(m_pwndBottom
->IsHidden()))
4254 CString sLine
= GetViewLineChars(nViewLine
);
4255 if (sLine
.IsEmpty())
4259 if (!m_pOtherViewData
)
4262 CString sDiffLine
= m_pOtherViewData
->GetLine(nViewLine
);
4263 if (sDiffLine
.IsEmpty())
4266 CString sLineExp
= ExpandChars(sLine
);
4267 CString sDiffLineExp
= ExpandChars(sDiffLine
);
4268 svn_diff_t
* diff
= NULL
;
4269 m_svnlinediff
.Diff(&diff
, sLineExp
, sLineExp
.GetLength(), sDiffLineExp
, sDiffLineExp
.GetLength(), m_bInlineWordDiff
);
4270 if (!diff
|| !SVNLineDiff::ShowInlineDiff(diff
))
4273 size_t lineoffset
= 0;
4274 size_t position
= 0;
4277 apr_off_t len
= diff
->original_length
;
4278 size_t oldpos
= position
;
4280 for (apr_off_t i
= 0; i
< len
; ++i
)
4282 position
+= m_svnlinediff
.m_line1tokens
[lineoffset
].size();
4286 if (diff
->type
== svn_diff__type_diff_modified
)
4291 positions
.push_back(p
);
4297 return !positions
.empty();
4300 void CBaseView::OnNavigateNextinlinediff()
4303 if (GetNextInlineDiff(nX
))
4305 POINT ptCaretViewPos
= GetCaretViewPosition();
4306 ptCaretViewPos
.x
= nX
;
4307 SetCaretAndGoalViewPosition(ptCaretViewPos
);
4308 m_ptSelectionViewPosOrigin
= ptCaretViewPos
;
4309 EnsureCaretVisible();
4313 void CBaseView::OnNavigatePrevinlinediff()
4316 if (GetPrevInlineDiff(nX
))
4318 POINT ptCaretViewPos
= GetCaretViewPosition();
4319 ptCaretViewPos
.x
= nX
;
4320 SetCaretAndGoalViewPosition(ptCaretViewPos
);
4321 m_ptSelectionViewPosOrigin
= ptCaretViewPos
;
4322 EnsureCaretVisible();
4326 bool CBaseView::HasNextInlineDiff()
4329 return GetNextInlineDiff(nPos
);
4332 bool CBaseView::GetNextInlineDiff(int & nPos
)
4334 POINT ptCaretViewPos
= GetCaretViewPosition();
4335 std::vector
<inlineDiffPos
> positions
;
4336 if (GetInlineDiffPositions(ptCaretViewPos
.y
, positions
))
4338 for (auto it
= positions
.cbegin(); it
!= positions
.cend(); ++it
)
4340 if (it
->start
> ptCaretViewPos
.x
)
4342 nPos
= (LONG
)it
->start
;
4345 if (it
->end
> ptCaretViewPos
.x
)
4347 nPos
= (LONG
)it
->end
;
4355 bool CBaseView::HasPrevInlineDiff()
4358 return GetPrevInlineDiff(nPos
);
4361 bool CBaseView::GetPrevInlineDiff(int & nPos
)
4363 POINT ptCaretViewPos
= GetCaretViewPosition();
4364 std::vector
<inlineDiffPos
> positions
;
4365 if (GetInlineDiffPositions(ptCaretViewPos
.y
, positions
))
4367 for (auto it
= positions
.crbegin(); it
!= positions
.crend(); ++it
)
4369 if ( it
->end
< ptCaretViewPos
.x
)
4371 nPos
= (LONG
)it
->end
;
4374 if ( it
->start
< ptCaretViewPos
.x
)
4376 nPos
= (LONG
)it
->start
;
4384 CBaseView
* CBaseView::GetFirstGoodView()
4386 if (IsViewGood(m_pwndLeft
))
4388 if (IsViewGood(m_pwndRight
))
4390 if (IsViewGood(m_pwndBottom
))
4391 return m_pwndBottom
;
4395 void CBaseView::BuildAllScreen2ViewVector()
4397 CBaseView
* p_pwndView
= GetFirstGoodView();
4400 m_Screen2View
.ScheduleFullRebuild(p_pwndView
->m_pViewData
);
4404 void CBaseView::BuildAllScreen2ViewVector(int nViewLine
)
4406 BuildAllScreen2ViewVector(nViewLine
, nViewLine
);
4409 void CBaseView::BuildAllScreen2ViewVector(int nFirstViewLine
, int nLastViewLine
)
4411 CBaseView
* p_pwndView
= GetFirstGoodView();
4414 m_Screen2View
.ScheduleRangeRebuild(p_pwndView
->m_pViewData
, nFirstViewLine
, nLastViewLine
);
4418 void CBaseView::UpdateViewLineNumbers()
4420 int nLineNumber
= 0;
4421 int nViewLineCount
= GetViewCount();
4422 for (int nViewLine
= 0; nViewLine
< nViewLineCount
; nViewLine
++)
4424 int oldLine
= (int)GetViewLineNumber(nViewLine
);
4426 SetViewLineNumber(nViewLine
, nLineNumber
++);
4431 int CBaseView::CleanEmptyLines()
4433 int nRemovedCount
= 0;
4434 int nViewLineCount
= GetViewCount();
4435 bool bCheckLeft
= IsViewGood(m_pwndLeft
);
4436 bool bCheckRight
= IsViewGood(m_pwndRight
);
4437 bool bCheckBottom
= IsViewGood(m_pwndBottom
);
4438 for (int nViewLine
= 0; nViewLine
< nViewLineCount
; )
4440 bool bAllEmpty
= true;
4441 bAllEmpty
&= !bCheckLeft
|| IsStateEmpty(m_pwndLeft
->GetViewState(nViewLine
));
4442 bAllEmpty
&= !bCheckRight
|| IsStateEmpty(m_pwndRight
->GetViewState(nViewLine
));
4443 bAllEmpty
&= !bCheckBottom
|| IsStateEmpty(m_pwndBottom
->GetViewState(nViewLine
));
4448 m_pwndLeft
->RemoveViewData(nViewLine
);
4452 m_pwndRight
->RemoveViewData(nViewLine
);
4456 m_pwndBottom
->RemoveViewData(nViewLine
);
4458 if (CUndo::GetInstance().IsGrouping()) // if use group undo -> ensure back adding goes in right (reversed) order
4468 return nRemovedCount
;
4471 int CBaseView::FindScreenLineForViewLine( int viewLine
)
4473 return m_Screen2View
.FindScreenLineForViewLine(viewLine
);
4476 int CBaseView::CountMultiLines( int nViewLine
)
4478 if (m_ScreenedViewLine
.empty())
4479 return 0; // in case the view is completely empty
4481 ASSERT(nViewLine
< (int)m_ScreenedViewLine
.size());
4483 if (m_ScreenedViewLine
[nViewLine
].bSublinesSet
)
4485 return (int)m_ScreenedViewLine
[nViewLine
].SubLines
.size();
4488 CString multiline
= CStringUtils::WordWrap(m_pViewData
->GetLine(nViewLine
), GetScreenChars()-1, false, true, GetTabSize()); // GetMultiLine(nLine);
4490 TScreenedViewLine oScreenedLine
;
4494 while ((pos
= multiline
.Find('\n', pos
)) >= 0)
4496 oScreenedLine
.SubLines
.push_back(multiline
.Mid(prevpos
, pos
-prevpos
)); // WordWrap could return vector/list of lines instead of string
4500 oScreenedLine
.SubLines
.push_back(multiline
.Mid(prevpos
));
4501 oScreenedLine
.bSublinesSet
= true;
4502 m_ScreenedViewLine
[nViewLine
] = oScreenedLine
;
4504 return CountMultiLines(nViewLine
);
4507 /// prepare inline diff cache
4508 LineColors
& CBaseView::GetLineColors(int nViewLine
)
4510 ASSERT(nViewLine
< (int)m_ScreenedViewLine
.size());
4512 if (m_bWhitespaceInlineDiffs
)
4514 if (m_ScreenedViewLine
[nViewLine
].bLineColorsSetWhiteSpace
)
4515 return m_ScreenedViewLine
[nViewLine
].lineColorsWhiteSpace
;
4519 if (m_ScreenedViewLine
[nViewLine
].bLineColorsSet
)
4520 return m_ScreenedViewLine
[nViewLine
].lineColors
;
4523 LineColors oLineColors
;
4524 // set main line color
4525 COLORREF crBkgnd
, crText
;
4526 DiffStates diffState
= m_pViewData
->GetState(nViewLine
);
4527 CDiffColors::GetInstance().GetColors(diffState
, crBkgnd
, crText
);
4528 oLineColors
.SetColor(0, crText
, crBkgnd
);
4531 if (!m_bShowInlineDiff
)
4534 if ((diffState
== DIFFSTATE_NORMAL
)&&(!m_bWhitespaceInlineDiffs
))
4537 CString sLine
= GetViewLineChars(nViewLine
);
4538 if (sLine
.IsEmpty())
4543 CString sDiffLine
= m_pOtherView
->GetViewLineChars(nViewLine
);
4544 if (sDiffLine
.IsEmpty())
4547 svn_diff_t
* diff
= NULL
;
4548 if (sLine
.GetLength() > (int)m_nInlineDiffMaxLineLength
)
4550 m_svnlinediff
.Diff(&diff
, sLine
, sLine
.GetLength(), sDiffLine
, sDiffLine
.GetLength(), m_bInlineWordDiff
);
4551 if (!diff
|| !SVNLineDiff::ShowInlineDiff(diff
) || !diff
->next
)
4555 int nTextStartOffset
= 0;
4556 std::map
<int, COLORREF
> removedPositions
;
4559 apr_off_t len
= diff
->original_length
;
4562 for (int i
= 0; i
< len
; ++i
)
4564 s
+= m_svnlinediff
.m_line1tokens
[lineoffset
].c_str();
4567 bool bInlineDiff
= (diff
->type
== svn_diff__type_diff_modified
);
4568 int nTextLength
= s
.GetLength();
4570 CDiffColors::GetInstance().GetColors(diffState
, crBkgnd
, crText
);
4571 if ((m_bShowInlineDiff
)&&(bInlineDiff
))
4573 crBkgnd
= InlineViewLineDiffColor(nViewLine
);
4577 crBkgnd
= m_ModifiedBk
;
4580 if (len
< diff
->modified_length
)
4582 removedPositions
[nTextStartOffset
] = m_InlineRemovedBk
;
4584 oLineColors
.SetColor(nTextStartOffset
, crText
, crBkgnd
);
4586 nTextStartOffset
+= nTextLength
;
4589 for (std::map
<int, COLORREF
>::const_iterator it
= removedPositions
.begin(); it
!= removedPositions
.end(); ++it
)
4591 oLineColors
.AddShotColor(it
->first
, it
->second
);
4593 } while (false); // error catch
4595 if (!m_bWhitespaceInlineDiffs
)
4597 m_ScreenedViewLine
[nViewLine
].lineColors
= oLineColors
;
4598 m_ScreenedViewLine
[nViewLine
].bLineColorsSet
= true;
4602 m_ScreenedViewLine
[nViewLine
].lineColorsWhiteSpace
= oLineColors
;
4603 m_ScreenedViewLine
[nViewLine
].bLineColorsSetWhiteSpace
= true;
4606 return GetLineColors(nViewLine
);
4609 void CBaseView::OnEditSelectall()
4611 if (m_pViewData
== nullptr)
4613 int nLastViewLine
= m_pViewData
->GetCount()-1;
4614 if (nLastViewLine
< 0)
4616 SetupAllViewSelection(0, nLastViewLine
);
4618 CString sLine
= GetViewLineChars(nLastViewLine
);
4619 m_ptSelectionViewPosStart
= SetupPoint(0, 0);
4620 m_ptSelectionViewPosEnd
= SetupPoint(sLine
.GetLength(), nLastViewLine
);
4621 m_ptSelectionViewPosOrigin
= SetupPoint(-1, -1);
4626 void CBaseView::FilterWhitespaces(CString
& first
, CString
& second
)
4628 FilterWhitespaces(first
);
4629 FilterWhitespaces(second
);
4632 void CBaseView::FilterWhitespaces(CString
& line
)
4640 int CBaseView::GetButtonEventLineIndex(const POINT
& point
)
4642 const int nLineFromTop
= (point
.y
- HEADERHEIGHT
) / GetLineHeight();
4643 int nEventLine
= nLineFromTop
+ m_nTopLine
;
4644 nEventLine
--; //we need the index
4649 BOOL
CBaseView::PreTranslateMessage(MSG
* pMsg
)
4651 if (RelayTrippleClick(pMsg
))
4653 return CView::PreTranslateMessage(pMsg
);
4657 void CBaseView::ResetUndoStep()
4662 void CBaseView::SaveUndoStep()
4664 if (!m_AllState
.IsEmpty())
4666 CUndo::GetInstance().AddState(m_AllState
, GetCaretViewPosition());
4671 void CBaseView::InsertViewData( int index
, const CString
& sLine
, DiffStates state
, int linenumber
, EOL ending
, HIDESTATE hide
, int movedline
)
4673 m_pState
->addedlines
.push_back(index
);
4674 m_pViewData
->InsertData(index
, sLine
, state
, linenumber
, ending
, hide
, movedline
);
4677 void CBaseView::InsertViewData( int index
, const viewdata
& data
)
4679 m_pState
->addedlines
.push_back(index
);
4680 m_pViewData
->InsertData(index
, data
);
4683 void CBaseView::RemoveViewData( int index
)
4685 m_pState
->removedlines
[index
] = m_pViewData
->GetData(index
);
4686 m_pViewData
->RemoveData(index
);
4689 void CBaseView::SetViewData( int index
, const viewdata
& data
)
4691 m_pState
->replacedlines
[index
] = m_pViewData
->GetData(index
);
4692 m_pViewData
->SetData(index
, data
);
4695 void CBaseView::SetViewState( int index
, DiffStates state
)
4697 m_pState
->linestates
[index
] = m_pViewData
->GetState(index
);
4698 m_pViewData
->SetState(index
, state
);
4701 void CBaseView::SetViewLine( int index
, const CString
& sLine
)
4703 m_pState
->difflines
[index
] = m_pViewData
->GetLine(index
);
4704 m_pViewData
->SetLine(index
, sLine
);
4707 void CBaseView::SetViewLineNumber( int index
, int linenumber
)
4709 int oldLineNumber
= m_pViewData
->GetLineNumber(index
);
4710 if (oldLineNumber
!= linenumber
) {
4711 m_pState
->linelines
[index
] = oldLineNumber
;
4712 m_pViewData
->SetLineNumber(index
, linenumber
);
4716 void CBaseView::SetViewLineEnding( int index
, EOL ending
)
4718 m_pState
->linesEOL
[index
] = m_pViewData
->GetLineEnding(index
);
4719 m_pViewData
->SetLineEnding(index
, ending
);
4723 BOOL
CBaseView::GetViewSelection( int& start
, int& end
) const
4727 start
= m_nSelViewBlockStart
;
4728 end
= m_nSelViewBlockEnd
;
4734 int CBaseView::Screen2View::GetViewLineForScreen( int screenLine
)
4736 RebuildIfNecessary();
4737 if (size() <= screenLine
)
4739 return m_Screen2View
[screenLine
].nViewLine
;
4742 int CBaseView::Screen2View::size()
4744 RebuildIfNecessary();
4745 return (int)m_Screen2View
.size();
4748 int CBaseView::Screen2View::GetSubLineOffset( int screenLine
)
4750 RebuildIfNecessary();
4751 if (size() <= screenLine
)
4753 return m_Screen2View
[screenLine
].nViewSubLine
;
4756 CBaseView::TScreenLineInfo
CBaseView::Screen2View::GetScreenLineInfo( int screenLine
)
4758 RebuildIfNecessary();
4759 return m_Screen2View
[screenLine
];
4763 doing partial rebuild, whole screen2view vector is built, but uses ScreenedViewLine cache to do it faster
4765 void CBaseView::Screen2View::RebuildIfNecessary()
4768 return; // rebuild not necessary
4770 FixScreenedCacheSize(m_pwndLeft
);
4771 FixScreenedCacheSize(m_pwndRight
);
4772 FixScreenedCacheSize(m_pwndBottom
);
4775 for (auto it
= m_RebuildRanges
.cbegin(); it
!= m_RebuildRanges
.cend(); ++it
)
4777 ResetScreenedViewLineCache(m_pwndLeft
, *it
);
4778 ResetScreenedViewLineCache(m_pwndRight
, *it
);
4779 ResetScreenedViewLineCache(m_pwndBottom
, *it
);
4784 ResetScreenedViewLineCache(m_pwndLeft
);
4785 ResetScreenedViewLineCache(m_pwndRight
);
4786 ResetScreenedViewLineCache(m_pwndBottom
);
4788 m_RebuildRanges
.clear();
4791 size_t OldSize
= m_Screen2View
.size();
4792 m_Screen2View
.clear();
4793 m_Screen2View
.reserve(OldSize
); // guess same size
4794 for (int i
= 0; i
< m_pViewData
->GetCount(); ++i
)
4796 if (m_pMainFrame
->m_bCollapsed
)
4798 while ((i
< m_pViewData
->GetCount())&&(m_pViewData
->GetHideState(i
) == HIDESTATE_HIDDEN
))
4800 if (!(i
< m_pViewData
->GetCount()))
4803 TScreenLineInfo oLineInfo
;
4804 oLineInfo
.nViewLine
= i
;
4805 oLineInfo
.nViewSubLine
= -1; // no wrap
4806 if (m_pMainFrame
->m_bWrapLines
&& !IsViewLineHidden(m_pViewData
, i
))
4809 if (IsLeftViewGood())
4810 nMaxLines
= std::max
<int>(nMaxLines
, m_pwndLeft
->CountMultiLines(i
));
4811 if (IsRightViewGood())
4812 nMaxLines
= std::max
<int>(nMaxLines
, m_pwndRight
->CountMultiLines(i
));
4813 if (IsBottomViewGood())
4814 nMaxLines
= std::max
<int>(nMaxLines
, m_pwndBottom
->CountMultiLines(i
));
4815 for (int l
= 0; l
< (nMaxLines
-1); ++l
)
4817 oLineInfo
.nViewSubLine
++;
4818 m_Screen2View
.push_back(oLineInfo
);
4820 oLineInfo
.nViewSubLine
++;
4822 m_Screen2View
.push_back(oLineInfo
);
4826 if (IsLeftViewGood())
4827 m_pwndLeft
->BuildMarkedWordArray();
4828 if (IsRightViewGood())
4829 m_pwndRight
->BuildMarkedWordArray();
4830 if (IsBottomViewGood())
4831 m_pwndBottom
->BuildMarkedWordArray();
4833 RecalcAllVertScrollBars();
4834 RecalcAllHorzScrollBars();
4837 int CBaseView::Screen2View::FindScreenLineForViewLine( int viewLine
)
4839 RebuildIfNecessary();
4841 int nScreenLineCount
= (int)m_Screen2View
.size();
4844 if (nScreenLineCount
>16)
4846 // for enough long data search for last screen
4847 // with viewline less than one we are looking for
4848 // use approximate method (based on) binary search using asymmetric start point
4849 // in form 2**n (determined as MSB of length) to go around division and rounding;
4850 // this effectively looks for bit values from MSB to LSB
4853 //GetMostSignificantBitValue
4854 // note _BitScanReverse(&nTestBit, nScreenLineCount); can be used instead
4855 nTestBit
= nScreenLineCount
;
4856 nTestBit
|= nTestBit
>>1;
4857 nTestBit
|= nTestBit
>>2;
4858 nTestBit
|= nTestBit
>>4;
4859 nTestBit
|= nTestBit
>>8;
4860 nTestBit
|= nTestBit
>>16;
4861 nTestBit
^= (nTestBit
>>1);
4865 int nTestPos
= nPos
| nTestBit
;
4866 if (nTestPos
< nScreenLineCount
&& m_Screen2View
[nTestPos
].nViewLine
< viewLine
)
4873 while (nPos
< nScreenLineCount
&& m_Screen2View
[nPos
].nViewLine
< viewLine
)
4881 void CBaseView::Screen2View::ScheduleFullRebuild(CViewData
* pViewData
) {
4884 m_pViewData
= pViewData
;
4887 void CBaseView::Screen2View::ScheduleRangeRebuild(CViewData
* pViewData
, int nFirstViewLine
, int nLastViewLine
)
4892 m_pViewData
= pViewData
;
4894 TRebuildRange Range
;
4895 Range
.FirstViewLine
=nFirstViewLine
;
4896 Range
.LastViewLine
=nLastViewLine
;
4897 m_RebuildRanges
.push_back(Range
);
4900 bool CBaseView::Screen2View::FixScreenedCacheSize(CBaseView
* pwndView
)
4902 if (!IsViewGood(pwndView
))
4906 const int nOldSize
= (int)pwndView
->m_ScreenedViewLine
.size();
4907 const int nViewCount
= std::max
<int>(pwndView
->GetViewCount(), 0);
4908 if (nOldSize
== nViewCount
)
4912 pwndView
->m_ScreenedViewLine
.resize(nViewCount
);
4916 bool CBaseView::Screen2View::ResetScreenedViewLineCache(CBaseView
* pwndView
)
4918 if (!IsViewGood(pwndView
))
4922 TRebuildRange Range
={0, pwndView
->GetViewCount()-1};
4923 ResetScreenedViewLineCache(pwndView
, Range
);
4927 bool CBaseView::Screen2View::ResetScreenedViewLineCache(CBaseView
* pwndView
, const TRebuildRange
& Range
)
4929 if (!IsViewGood(pwndView
))
4933 if (Range
.LastViewLine
== -1)
4937 ASSERT(Range
.FirstViewLine
>= 0);
4938 ASSERT(Range
.LastViewLine
< pwndView
->GetViewCount());
4939 for (int i
= Range
.FirstViewLine
; i
<= Range
.LastViewLine
; i
++)
4941 pwndView
->m_ScreenedViewLine
[i
].Clear();
4946 void CBaseView::WrapChanged()
4948 m_nMaxLineLength
= -1;
4952 void CBaseView::OnEditFind()
4957 m_pFindDialog
= new CFindDlg(this);
4958 m_pFindDialog
->Create(this);
4960 m_pFindDialog
->SetFindString(HasTextSelection() ? GetSelectedText() : L
"");
4963 LRESULT
CBaseView::OnFindDialogMessage(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
4965 ASSERT(m_pFindDialog
!= NULL
);
4967 if (m_pFindDialog
->IsTerminating())
4969 // invalidate the handle identifying the dialog box.
4970 m_pFindDialog
= NULL
;
4974 if(m_pFindDialog
->FindNext())
4976 //read data from dialog
4977 m_sFindText
= m_pFindDialog
->GetFindString();
4978 m_bMatchCase
= (m_pFindDialog
->MatchCase() == TRUE
);
4979 m_bLimitToDiff
= m_pFindDialog
->LimitToDiffs();
4980 m_bWholeWord
= m_pFindDialog
->WholeWord();
4983 m_sFindText
= m_sFindText
.MakeLower();
4985 BuildFindStringArray();
4992 void CBaseView::OnEditFindnextStart()
4994 if (m_pViewData
== nullptr)
4996 if (HasTextSelection())
4998 m_sFindText
= GetSelectedText();
4999 m_bMatchCase
= false;
5000 m_bLimitToDiff
= false;
5001 m_bWholeWord
= false;
5002 m_sFindText
= m_sFindText
.MakeLower();
5004 BuildFindStringArray();
5009 m_sFindText
.Empty();
5010 BuildFindStringArray();
5014 void CBaseView::OnEditFindprevStart()
5016 if (m_pViewData
== nullptr)
5018 if (HasTextSelection())
5020 m_sFindText
= GetSelectedText();
5021 m_bMatchCase
= false;
5022 m_bLimitToDiff
= false;
5023 m_bWholeWord
= false;
5024 m_sFindText
= m_sFindText
.MakeLower();
5026 BuildFindStringArray();
5031 m_sFindText
.Empty();
5032 BuildFindStringArray();
5036 bool CBaseView::StringFound(const CString
& str
, SearchDirection srchDir
, int& start
, int& end
) const
5038 start
= str
.Find(m_sFindText
);
5039 if ((srchDir
==SearchPrevious
)&&(start
>=0))
5041 int laststart
= start
;
5045 laststart
= str
.Find(m_sFindText
, laststart
+1);
5046 } while (laststart
>= 0);
5048 end
= start
+ m_sFindText
.GetLength();
5049 bool bStringFound
= (start
>= 0);
5050 if (bStringFound
&& m_bWholeWord
)
5053 bStringFound
= IsWordSeparator(str
.Mid(start
-1,1).GetAt(0));
5057 if (str
.GetLength() > end
)
5058 bStringFound
= IsWordSeparator(str
.Mid(end
, 1).GetAt(0));
5061 return bStringFound
;
5064 void CBaseView::OnEditFindprev()
5066 Search(SearchPrevious
);
5069 void CBaseView::OnEditFindnext()
5074 void CBaseView::Search(SearchDirection srchDir
)
5076 if (m_sFindText
.IsEmpty())
5081 POINT start
= m_ptSelectionViewPosEnd
;
5083 end
.y
= m_pViewData
->GetCount()-1;
5087 if (srchDir
==SearchNext
)
5088 end
.x
= GetViewLineLength(end
.y
);
5091 end
.x
= m_ptSelectionViewPosStart
.x
;
5095 if (!HasTextSelection())
5097 start
.y
= m_ptCaretViewPos
.y
;
5098 if (srchDir
==SearchNext
)
5099 start
.x
= m_ptCaretViewPos
.x
;
5103 end
.x
= m_ptCaretViewPos
.x
;
5106 CString sSelectedText
;
5108 for (int nViewLine
=start
.y
; ;srchDir
==SearchNext
? nViewLine
++ : nViewLine
--)
5112 nViewLine
= m_pViewData
->GetCount()-1;
5113 startline
= start
.y
;
5115 if (nViewLine
> end
.y
)
5118 startline
= start
.y
;
5122 if (nViewLine
== startline
)
5125 switch (m_pViewData
->GetState(nViewLine
))
5127 case DIFFSTATE_EMPTY
:
5129 case DIFFSTATE_UNKNOWN
:
5130 case DIFFSTATE_NORMAL
:
5133 case DIFFSTATE_REMOVED
:
5134 case DIFFSTATE_REMOVEDWHITESPACE
:
5135 case DIFFSTATE_ADDED
:
5136 case DIFFSTATE_ADDEDWHITESPACE
:
5137 case DIFFSTATE_WHITESPACE
:
5138 case DIFFSTATE_WHITESPACE_DIFF
:
5139 case DIFFSTATE_CONFLICTED
:
5140 case DIFFSTATE_CONFLICTED_IGNORED
:
5141 case DIFFSTATE_CONFLICTADDED
:
5142 case DIFFSTATE_CONFLICTEMPTY
:
5143 case DIFFSTATE_CONFLICTRESOLVED
:
5144 case DIFFSTATE_IDENTICALREMOVED
:
5145 case DIFFSTATE_IDENTICALADDED
:
5146 case DIFFSTATE_THEIRSREMOVED
:
5147 case DIFFSTATE_THEIRSADDED
:
5148 case DIFFSTATE_MOVED_FROM
:
5149 case DIFFSTATE_MOVED_TO
:
5150 case DIFFSTATE_YOURSREMOVED
:
5151 case DIFFSTATE_YOURSADDED
:
5152 case DIFFSTATE_EDITED
:
5154 sSelectedText
= GetViewLineChars(nViewLine
);
5155 if (nViewLine
==start
.y
)
5156 sSelectedText
= srchDir
==SearchNext
? sSelectedText
.Mid(start
.x
) : sSelectedText
.Left(start
.x
);
5158 sSelectedText
= sSelectedText
.MakeLower();
5159 int startfound
= -1;
5161 if (StringFound(sSelectedText
, srchDir
, startfound
, endfound
))
5163 HighlightViewLines(nViewLine
, nViewLine
);
5164 m_ptSelectionViewPosStart
.x
= startfound
;
5165 m_ptSelectionViewPosEnd
.x
= endfound
;
5166 if (nViewLine
==start
.y
)
5168 m_ptSelectionViewPosStart
.x
+= start
.x
;
5169 m_ptSelectionViewPosEnd
.x
+= start
.x
;
5171 m_ptSelectionViewPosEnd
.x
= m_ptSelectionViewPosStart
.x
+ m_sFindText
.GetLength();
5172 m_ptSelectionViewPosStart
.y
= nViewLine
;
5173 m_ptSelectionViewPosEnd
.y
= nViewLine
;
5174 m_ptCaretViewPos
= m_ptSelectionViewPosStart
;
5175 UpdateViewsCaretPosition();
5176 EnsureCaretVisible();
5184 m_pMainFrame
->m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
5187 CString
CBaseView::GetSelectedText() const
5189 CString sSelectedText
;
5190 POINT start
= m_ptSelectionViewPosStart
;
5191 POINT end
= m_ptSelectionViewPosEnd
;
5192 if (!HasTextSelection())
5194 if (!HasSelection())
5195 return sSelectedText
;
5196 start
.y
= m_nSelViewBlockStart
;
5198 end
.y
= m_nSelViewBlockEnd
;
5199 end
.x
= GetViewLineLength(m_nSelViewBlockEnd
);
5201 // first store the selected lines in one CString
5202 for (int nViewLine
=start
.y
; nViewLine
<=end
.y
; nViewLine
++)
5204 switch (m_pViewData
->GetState(nViewLine
))
5206 case DIFFSTATE_EMPTY
:
5208 case DIFFSTATE_UNKNOWN
:
5209 case DIFFSTATE_NORMAL
:
5210 case DIFFSTATE_REMOVED
:
5211 case DIFFSTATE_REMOVEDWHITESPACE
:
5212 case DIFFSTATE_ADDED
:
5213 case DIFFSTATE_ADDEDWHITESPACE
:
5214 case DIFFSTATE_WHITESPACE
:
5215 case DIFFSTATE_WHITESPACE_DIFF
:
5216 case DIFFSTATE_CONFLICTED
:
5217 case DIFFSTATE_CONFLICTED_IGNORED
:
5218 case DIFFSTATE_CONFLICTADDED
:
5219 case DIFFSTATE_CONFLICTEMPTY
:
5220 case DIFFSTATE_CONFLICTRESOLVED
:
5221 case DIFFSTATE_IDENTICALREMOVED
:
5222 case DIFFSTATE_IDENTICALADDED
:
5223 case DIFFSTATE_THEIRSREMOVED
:
5224 case DIFFSTATE_THEIRSADDED
:
5225 case DIFFSTATE_MOVED_FROM
:
5226 case DIFFSTATE_MOVED_TO
:
5227 case DIFFSTATE_YOURSREMOVED
:
5228 case DIFFSTATE_YOURSADDED
:
5229 case DIFFSTATE_EDITED
:
5230 sSelectedText
+= GetViewLineChars(nViewLine
);
5231 sSelectedText
+= _T("\r\n");
5235 // remove the non-selected chars from the first line, last line and last \r\n
5236 int nLeftCut
= start
.x
;
5237 int nRightCut
= GetViewLineChars(end
.y
).GetLength() - end
.x
+ 2;
5238 sSelectedText
= sSelectedText
.Mid(nLeftCut
, sSelectedText
.GetLength()-nLeftCut
-nRightCut
);
5239 return sSelectedText
;
5242 void CBaseView::OnEditGotoline()
5244 if (m_pViewData
== NULL
)
5246 // find the last and first line number
5247 int nViewLineCount
= m_pViewData
->GetCount();
5249 int nLastLineNumber
= DIFF_EMPTYLINENUMBER
;
5250 for (int nViewLine
=nViewLineCount
-1; nViewLine
>=0; --nViewLine
)
5252 nLastLineNumber
= m_pViewData
->GetLineNumber(nViewLine
);
5253 if (nLastLineNumber
!=DIFF_EMPTYLINENUMBER
)
5258 if (nLastLineNumber
==DIFF_EMPTYLINENUMBER
|| nLastLineNumber
==0) // not numbered line foud or last one is first
5263 int nFirstLineNumber
=1; // first is always 1
5266 sText
.Format(IDS_GOTOLINE
, nFirstLineNumber
, nLastLineNumber
);
5268 CGotoLineDlg
dlg(this);
5269 dlg
.SetLabel(sText
);
5270 dlg
.SetLimits(nFirstLineNumber
, nLastLineNumber
);
5271 if (dlg
.DoModal() == IDOK
)
5273 for (int nViewLine
= 0; nViewLine
< nViewLineCount
; ++nViewLine
)
5275 if ((m_pViewData
->GetLineNumber(nViewLine
)+1) == dlg
.GetLineNumber())
5277 HighlightViewLines(nViewLine
, nViewLine
);
5284 void CBaseView::OnToggleReadonly()
5286 if (IsReadonlyChangable()) {
5287 SetWritable(IsReadonly());
5291 int CBaseView::SaveFile(int nFlags
)
5294 if (m_pViewData
!=NULL
&& m_pWorkingFile
!=NULL
)
5296 CFileTextLines file
;
5297 //file.SetSaveParams(m_SaveParams);
5299 for (int i
=0; i
<m_pViewData
->GetCount(); i
++)
5301 //only copy non-removed lines
5302 DiffStates state
= m_pViewData
->GetState(i
);
5305 case DIFFSTATE_CONFLICTED
:
5306 case DIFFSTATE_CONFLICTED_IGNORED
:
5313 } while((last
<m_pViewData
->GetCount()) && ((m_pViewData
->GetState(last
)==DIFFSTATE_CONFLICTED
)||(m_pViewData
->GetState(last
)==DIFFSTATE_CONFLICTED_IGNORED
)));
5314 file
.Add(_T("<<<<<<< .mine"), EOL_NOENDING
);
5315 for (int j
=first
; j
<last
; j
++)
5317 file
.Add(m_pwndRight
->m_pViewData
->GetLine(j
), m_pwndRight
->m_pViewData
->GetLineEnding(j
));
5319 file
.Add(_T("======="), EOL_NOENDING
);
5320 for (int j
=first
; j
<last
; j
++)
5322 file
.Add(m_pwndLeft
->m_pViewData
->GetLine(j
), m_pwndLeft
->m_pViewData
->GetLineEnding(j
));
5324 file
.Add(_T(">>>>>>> .theirs"), EOL_NOENDING
);
5328 case DIFFSTATE_EMPTY
:
5330 case DIFFSTATE_CONFLICTEMPTY
:
5331 case DIFFSTATE_IDENTICALREMOVED
:
5332 case DIFFSTATE_REMOVED
:
5333 case DIFFSTATE_THEIRSREMOVED
:
5334 case DIFFSTATE_YOURSREMOVED
:
5335 case DIFFSTATE_CONFLICTRESOLVEDEMPTY
:
5336 if ((nFlags
&SAVE_REMOVED
) == 0)
5338 // do not save removed lines
5342 file
.Add(m_pViewData
->GetLine(i
), m_pViewData
->GetLineEnding(i
));
5346 CString filename
= m_pWorkingFile
->GetFilename();
5347 if (m_pWorkingFile
->IsReadonly())
5348 if (!CCommonAppUtils::FileOpenSave(filename
, NULL
, IDS_SAVEASTITLE
, IDS_COMMONFILEFILTER
, false, m_hWnd
))
5350 if (!file
.Save(filename
))
5352 ::MessageBox(m_hWnd
, file
.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR
);
5355 m_pWorkingFile
->SetFileName(filename
);
5356 m_pWorkingFile
->StoreFileAttributes();
5357 // m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
5359 CUndo::GetInstance().MarkAsOriginalState();
5360 if (file
.GetCount() == 1 && file
.GetAt(0).IsEmpty() && file
.GetLineEnding(0) == EOL_NOENDING
)
5362 return file
.GetCount();
5368 int CBaseView::SaveFileTo(CString sFileName
, int nFlags
)
5372 m_pWorkingFile
->SetFileName(sFileName
);
5373 return SaveFile(nFlags
);