1
// TortoiseGitMerge - a Diff/Patch program
3 // Copyright (C) 2003-2015 - 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"
30 #include "EncodingDlg.h"
31 #include "EditorConfigWrapper.h"
34 // We use three different kind of lines here:
35 // 1. The real lines of the original files.
36 // These are shown in the view margin and are not used elsewhere, they're only for user information.
38 // The lines actually shown on screen. All methods use screen lines as parameters/outputs if not explicitly specified otherwise.
40 // These are the lines of the diff data. If unmodified sections are collapsed, not all of those lines are shown.
42 // Basically view lines are the line data, while screen lines are shown lines.
49 #define MARGINWIDTH 20
50 #define HEADERHEIGHT 10
52 #define IDT_SCROLLTIMER 101
54 CBaseView
* CBaseView::m_pwndLeft
= NULL
;
55 CBaseView
* CBaseView::m_pwndRight
= NULL
;
56 CBaseView
* CBaseView::m_pwndBottom
= NULL
;
57 CLocatorBar
* CBaseView::m_pwndLocator
= NULL
;
58 CLineDiffBar
* CBaseView::m_pwndLineDiffBar
= NULL
;
59 CMFCStatusBar
* CBaseView::m_pwndStatusBar
= NULL
;
60 CMFCRibbonStatusBar
* CBaseView::m_pwndRibbonStatusBar
= NULL
;
61 CMainFrame
* CBaseView::m_pMainFrame
= NULL
;
62 CBaseView::Screen2View
CBaseView::m_Screen2View
;
63 const UINT
CBaseView::m_FindDialogMessage
= RegisterWindowMessage(FINDMSGSTRING
);
65 allviewstate
CBaseView::m_AllState
;
67 IMPLEMENT_DYNCREATE(CBaseView
, CView
)
69 CBaseView::CBaseView()
70 : m_pCacheBitmap(NULL
)
72 , m_pOtherViewData(NULL
)
77 , m_nLastScreenChars(-1)
78 , m_nMaxLineLength(-1)
84 , m_mouseInMargin(false)
86 , m_lineendings(EOL_AUTOLINE
)
88 , m_bReadonlyIsChangable(false)
91 , m_nSelViewBlockStart(-1)
92 , m_nSelViewBlockEnd(-1)
94 , m_bShowSelection(true)
95 , m_texttype(CFileTextLines::AUTOTYPE
)
97 , m_bOtherDiffChecked(false)
98 , m_bInlineWordDiff(true)
99 , m_bWhitespaceInlineDiffs(false)
101 , m_pFindDialog(NULL
)
103 , m_bMatchCase(false)
104 , m_bLimitToDiff(true)
105 , m_bWholeWord(false)
107 , m_pWorkingFile(NULL
)
108 , m_bInsertMode(true)
109 , m_bEditorConfigEnabled(false)
110 , m_bEditorConfigLoaded(2) // 2 = not evaluated
112 m_ptCaretViewPos
.x
= 0;
113 m_ptCaretViewPos
.y
= 0;
114 m_ptSelectionViewPosStart
= m_ptCaretViewPos
;
115 m_ptSelectionViewPosEnd
= m_ptSelectionViewPosStart
;
116 m_ptSelectionViewPosOrigin
= m_ptSelectionViewPosEnd
;
117 m_bViewWhitespace
= CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewWhitespaces"), 1);
118 m_bViewLinenumbers
= CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewLinenumbers"), 1);
119 m_bShowInlineDiff
= CRegDWORD(_T("Software\\TortoiseGitMerge\\DisplayBinDiff"), TRUE
);
120 m_nInlineDiffMaxLineLength
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineDiffMaxLineLength"), 3000);
121 m_InlineAddedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineAdded"), INLINEADDED_COLOR
);
122 m_InlineRemovedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineRemoved"), INLINEREMOVED_COLOR
);
123 m_ModifiedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\ColorModifiedB"), MODIFIED_COLOR
);
124 m_WhiteSpaceFg
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\Whitespace"), GetSysColor(COLOR_GRAYTEXT
));
125 m_sWordSeparators
= CRegString(_T("Software\\TortoiseGitMerge\\WordSeparators"), _T("[]();:.,{}!@#$%^&*-+=|/\\<>'`~\"?"));
126 m_bIconLFs
= CRegDWORD(_T("Software\\TortoiseGitMerge\\IconLFs"), 0);
127 m_nTabSize
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabSize"), 4);
128 m_nTabMode
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabMode"), TABMODE_NONE
);
129 m_bEditorConfigEnabled
= !!(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\EnableEditorConfig"), FALSE
);
130 std::fill_n(m_apFonts
, fontsCount
, (CFont
*)NULL
);
131 m_hConflictedIcon
= LoadIcon(IDI_CONFLICTEDLINE
);
132 m_hConflictedIgnoredIcon
= LoadIcon(IDI_CONFLICTEDIGNOREDLINE
);
133 m_hRemovedIcon
= LoadIcon(IDI_REMOVEDLINE
);
134 m_hAddedIcon
= LoadIcon(IDI_ADDEDLINE
);
135 m_hWhitespaceBlockIcon
= LoadIcon(IDI_WHITESPACELINE
);
136 m_hEqualIcon
= LoadIcon(IDI_EQUALLINE
);
137 m_hLineEndingCR
= LoadIcon(IDI_LINEENDINGCR
);
138 m_hLineEndingCRLF
= LoadIcon(IDI_LINEENDINGCRLF
);
139 m_hLineEndingLF
= LoadIcon(IDI_LINEENDINGLF
);
140 m_hEditedIcon
= LoadIcon(IDI_LINEEDITED
);
141 m_hMovedIcon
= LoadIcon(IDI_MOVEDLINE
);
142 m_hMarkedIcon
= LoadIcon(IDI_LINEMARKED
);
143 m_margincursor
= (HCURSOR
)LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDC_MARGINCURSOR
), IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
);
145 for (int i
=0; i
<1024; ++i
)
146 m_sConflictedText
+= _T("??");
147 m_sNoLineNr
.LoadString(IDS_EMPTYLINETT
);
151 SecureZeroMemory(&m_lfBaseFont
, sizeof(m_lfBaseFont
));
154 m_Eols
[EOL_LF
] = L
"\n"; // x0a
155 m_Eols
[EOL_CR
] = L
"\r"; // x0d
156 m_Eols
[EOL_CRLF
] = L
"\r\n"; // x0d x0a
157 m_Eols
[EOL_LFCR
] = L
"\n\r";
158 m_Eols
[EOL_VT
] = L
"\v"; // x0b
159 m_Eols
[EOL_FF
] = L
"\f"; // x0c
160 m_Eols
[EOL_NEL
] = L
"\x85";
161 m_Eols
[EOL_LS
] = L
"\x2028";
162 m_Eols
[EOL_PS
] = L
"\x2029";
163 m_Eols
[EOL_AUTOLINE
] = m_Eols
[m_lineendings
==EOL_AUTOLINE
166 m_SaveParams
.m_LineEndings
= EOL::EOL_AUTOLINE
;
167 m_SaveParams
.m_UnicodeType
= CFileTextLines::AUTOTYPE
;
170 CBaseView::~CBaseView()
174 DestroyIcon(m_hAddedIcon
);
175 DestroyIcon(m_hRemovedIcon
);
176 DestroyIcon(m_hConflictedIcon
);
177 DestroyIcon(m_hConflictedIgnoredIcon
);
178 DestroyIcon(m_hWhitespaceBlockIcon
);
179 DestroyIcon(m_hEqualIcon
);
180 DestroyIcon(m_hLineEndingCR
);
181 DestroyIcon(m_hLineEndingCRLF
);
182 DestroyIcon(m_hLineEndingLF
);
183 DestroyIcon(m_hEditedIcon
);
184 DestroyIcon(m_hMovedIcon
);
185 DestroyIcon(m_hMarkedIcon
);
186 DestroyCursor(m_margincursor
);
189 BEGIN_MESSAGE_MAP(CBaseView
, CView
)
202 ON_COMMAND(ID_NAVIGATE_NEXTDIFFERENCE
, OnMergeNextdifference
)
203 ON_COMMAND(ID_NAVIGATE_PREVIOUSDIFFERENCE
, OnMergePreviousdifference
)
204 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW
, 0, 0xFFFF, OnToolTipNotify
)
205 ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA
, 0, 0xFFFF, OnToolTipNotify
)
208 ON_COMMAND(ID_EDIT_COPY
, OnEditCopy
)
210 ON_COMMAND(ID_NAVIGATE_PREVIOUSCONFLICT
, OnMergePreviousconflict
)
211 ON_COMMAND(ID_NAVIGATE_NEXTCONFLICT
, OnMergeNextconflict
)
213 ON_COMMAND(ID_CARET_DOWN
, &CBaseView::OnCaretDown
)
214 ON_COMMAND(ID_CARET_LEFT
, &CBaseView::OnCaretLeft
)
215 ON_COMMAND(ID_CARET_RIGHT
, &CBaseView::OnCaretRight
)
216 ON_COMMAND(ID_CARET_UP
, &CBaseView::OnCaretUp
)
217 ON_COMMAND(ID_CARET_WORDLEFT
, &CBaseView::OnCaretWordleft
)
218 ON_COMMAND(ID_CARET_WORDRIGHT
, &CBaseView::OnCaretWordright
)
219 ON_COMMAND(ID_EDIT_CUT
, &CBaseView::OnEditCut
)
220 ON_COMMAND(ID_EDIT_PASTE
, &CBaseView::OnEditPaste
)
222 ON_WM_LBUTTONDBLCLK()
223 ON_COMMAND(ID_NAVIGATE_NEXTINLINEDIFF
, &CBaseView::OnNavigateNextinlinediff
)
224 ON_COMMAND(ID_NAVIGATE_PREVINLINEDIFF
, &CBaseView::OnNavigatePrevinlinediff
)
225 ON_COMMAND(ID_EDIT_SELECTALL
, &CBaseView::OnEditSelectall
)
226 ON_COMMAND(ID_EDIT_FIND
, OnEditFind
)
227 ON_REGISTERED_MESSAGE(m_FindDialogMessage
, OnFindDialogMessage
)
228 ON_COMMAND(ID_EDIT_FINDNEXT
, OnEditFindnext
)
229 ON_COMMAND(ID_EDIT_FINDPREV
, OnEditFindprev
)
230 ON_COMMAND(ID_EDIT_FINDNEXTSTART
, OnEditFindnextStart
)
231 ON_COMMAND(ID_EDIT_FINDPREVSTART
, OnEditFindprevStart
)
232 ON_COMMAND(ID_EDIT_GOTOLINE
, &CBaseView::OnEditGotoline
)
237 void CBaseView::DocumentUpdated()
243 m_nLastScreenChars
= -1;
244 m_nMaxLineLength
= -1;
248 m_bOtherDiffChecked
= false;
251 m_nTabSize
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabSize"), 4);
252 m_nTabMode
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabMode"), TABMODE_NONE
);
253 m_bViewLinenumbers
= CRegDWORD(_T("Software\\TortoiseGitMerge\\ViewLinenumbers"), 1);
254 m_InlineAddedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineAdded"), INLINEADDED_COLOR
);
255 m_InlineRemovedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineRemoved"), INLINEREMOVED_COLOR
);
256 m_ModifiedBk
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\ColorModifiedB"), MODIFIED_COLOR
);
257 m_WhiteSpaceFg
= CRegDWORD(_T("Software\\TortoiseGitMerge\\Colors\\Whitespace"), GetSysColor(COLOR_GRAYTEXT
));
258 m_bIconLFs
= CRegDWORD(_T("Software\\TortoiseGitMerge\\IconLFs"), 0);
259 m_nInlineDiffMaxLineLength
= CRegDWORD(_T("Software\\TortoiseGitMerge\\InlineDiffMaxLineLength"), 3000);
260 m_Eols
[EOL_AUTOLINE
] = m_Eols
[m_lineendings
==EOL_AUTOLINE
263 SetEditorConfigEnabled(m_bEditorConfigEnabled
);
265 ClearCurrentSelection();
270 void CBaseView::SetEditorConfigEnabled(bool bEditorConfigEnabled
)
272 m_bEditorConfigEnabled
= bEditorConfigEnabled
;
273 m_nTabSize
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabSize"), 4);
274 m_nTabMode
= (int)(DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\TabMode"), TABMODE_NONE
);
275 if (m_bEditorConfigEnabled
)
277 m_bEditorConfigLoaded
= FALSE
; // no editorconfig entries loaded
278 CEditorConfigWrapper ec
;
279 if (ec
.Load(m_sReflectedName
.IsEmpty() ? m_sFullFilePath
: m_sReflectedName
))
281 m_bEditorConfigLoaded
= TRUE
;
282 if (ec
.m_nTabWidth
!= nullptr)
283 m_nTabSize
= ec
.m_nTabWidth
;
284 if (ec
.m_bIndentStyle
!= nullptr)
285 m_nTabMode
= (m_nTabMode
& ~TABMODE_USESPACES
) | (ec
.m_bIndentStyle
? TABMODE_USESPACES
: TABMODE_NONE
);
290 static CString
GetTabModeString(int nTabMode
, int nTabSize
, bool bEditorConfig
)
293 if (nTabMode
& TABMODE_USESPACES
)
297 text
.AppendFormat(L
" %d", nTabSize
);
298 if (nTabMode
& TABMODE_SMARTINDENT
)
305 void CBaseView::UpdateStatusBar()
307 int nRemovedLines
= 0;
309 int nConflictedLines
= 0;
313 for (int i
=0; i
<m_pViewData
->GetCount(); i
++)
315 DiffStates state
= m_pViewData
->GetState(i
);
318 case DIFFSTATE_ADDED
:
319 case DIFFSTATE_IDENTICALADDED
:
320 case DIFFSTATE_THEIRSADDED
:
321 case DIFFSTATE_YOURSADDED
:
322 case DIFFSTATE_CONFLICTADDED
:
325 case DIFFSTATE_IDENTICALREMOVED
:
326 case DIFFSTATE_REMOVED
:
327 case DIFFSTATE_THEIRSREMOVED
:
328 case DIFFSTATE_YOURSREMOVED
:
331 case DIFFSTATE_CONFLICTED
:
332 case DIFFSTATE_CONFLICTED_IGNORED
:
344 sBarText
+= CFileTextLines::GetEncodingName(m_texttype
);
345 sBarText
+= sBarText
.IsEmpty() ? L
"" : L
" ";
346 sBarText
+= GetEolName(m_lineendings
);
347 sBarText
+= sBarText
.IsEmpty() ? L
"" : L
" ";
349 if (sBarText
.IsEmpty())
350 sBarText
+= _T(" / ");
355 sTemp
.Format(IDS_STATUSBAR_REMOVEDLINES
, nRemovedLines
);
356 if (!sBarText
.IsEmpty())
357 sBarText
+= _T(" / ");
362 sTemp
.Format(IDS_STATUSBAR_ADDEDLINES
, nAddedLines
);
363 if (!sBarText
.IsEmpty())
364 sBarText
+= _T(" / ");
367 if (nConflictedLines
)
369 sTemp
.Format(IDS_STATUSBAR_CONFLICTEDLINES
, nConflictedLines
);
370 if (!sBarText
.IsEmpty())
371 sBarText
+= _T(" / ");
374 if (m_pwndStatusBar
|| m_pwndRibbonStatusBar
)
381 if (m_nStatusBarID
== ID_INDICATOR_BOTTOMVIEW
)
383 sBarText
.Format(IDS_STATUSBAR_CONFLICTS
, nConflictedLines
);
385 if (m_nStatusBarID
== ID_INDICATOR_LEFTVIEW
)
387 sTemp
.LoadString(IDS_STATUSBAR_LEFTVIEW
);
388 sBarText
= sTemp
+sBarText
;
390 if (m_nStatusBarID
== ID_INDICATOR_RIGHTVIEW
)
392 sTemp
.LoadString(IDS_STATUSBAR_RIGHTVIEW
);
393 sBarText
= sTemp
+sBarText
;
395 int nIndex
= m_pwndStatusBar
->CommandToIndex(m_nStatusBarID
);
396 m_pwndStatusBar
->GetPaneInfo(nIndex
, nID
, nStyle
, cxWidth
);
397 //calculate the width of the text
398 CDC
* pDC
= m_pwndStatusBar
->GetDC();
401 CSize size
= pDC
->GetTextExtent(sBarText
);
402 m_pwndStatusBar
->SetPaneInfo(nIndex
, nID
, nStyle
, size
.cx
+2);
405 m_pwndStatusBar
->SetPaneText(nIndex
, sBarText
);
407 else if (m_pwndRibbonStatusBar
)
409 if (!IsViewGood(m_pwndBottom
))
410 m_pwndRibbonStatusBar
->RemoveElement(ID_INDICATOR_BOTTOMVIEW
);
411 if ((m_nStatusBarID
== ID_INDICATOR_BOTTOMVIEW
) && (IsViewGood(this)))
413 m_pwndRibbonStatusBar
->RemoveElement(ID_INDICATOR_BOTTOMVIEW
);
414 std::unique_ptr
<CMFCRibbonButtonsGroup
> apBtnGroupBottom(new CMFCRibbonButtonsGroup
);
415 apBtnGroupBottom
->SetID(ID_INDICATOR_BOTTOMVIEW
);
416 apBtnGroupBottom
->AddButton(new CMFCRibbonStatusBarPane(ID_SEPARATOR
, CString(MAKEINTRESOURCE(IDS_STATUSBAR_BOTTOMVIEW
)), TRUE
));
417 CMFCRibbonButton
* pButton
= new CMFCRibbonButton(ID_INDICATOR_BOTTOMVIEWCOMBOENCODING
, L
"");
418 m_pMainFrame
->FillEncodingButton(pButton
, ID_INDICATOR_BOTTOMENCODINGSTART
);
419 apBtnGroupBottom
->AddButton(pButton
);
420 pButton
= new CMFCRibbonButton(ID_INDICATOR_BOTTOMVIEWCOMBOEOL
, L
"");
421 m_pMainFrame
->FillEOLButton(pButton
, ID_INDICATOR_BOTTOMEOLSTART
);
422 apBtnGroupBottom
->AddButton(pButton
);
423 pButton
= new CMFCRibbonButton(ID_INDICATOR_BOTTOMVIEWCOMBOTABMODE
, L
"");
424 m_pMainFrame
->FillEOLButton(pButton
, ID_INDICATOR_BOTTOMTABMODESTART
);
425 apBtnGroupBottom
->AddButton(pButton
);
426 apBtnGroupBottom
->AddButton(new CMFCRibbonStatusBarPane(ID_INDICATOR_BOTTOMVIEW
, L
"", TRUE
));
427 m_pwndRibbonStatusBar
->AddExtendedElement(apBtnGroupBottom
.release(), L
"");
430 CMFCRibbonButtonsGroup
* pGroup
= DYNAMIC_DOWNCAST(CMFCRibbonButtonsGroup
, m_pwndRibbonStatusBar
->FindByID(m_nStatusBarID
));
433 CMFCRibbonStatusBarPane
* pPane
= DYNAMIC_DOWNCAST(CMFCRibbonStatusBarPane
, pGroup
->GetButton(4));
436 pPane
->SetText(sBarText
);
438 CMFCRibbonButton
* pButton
= DYNAMIC_DOWNCAST(CMFCRibbonButton
, pGroup
->GetButton(1));
441 pButton
->SetText(CFileTextLines::GetEncodingName(m_texttype
));
442 pButton
->SetDescription(CFileTextLines::GetEncodingName(m_texttype
));
444 pButton
= DYNAMIC_DOWNCAST(CMFCRibbonButton
, pGroup
->GetButton(2));
447 pButton
->SetText(GetEolName(m_lineendings
));
448 pButton
->SetDescription(GetEolName(m_lineendings
));
450 pButton
= DYNAMIC_DOWNCAST(CMFCRibbonButton
, pGroup
->GetButton(3));
453 pButton
->SetText(GetTabModeString(m_nTabMode
, m_nTabSize
, m_bEditorConfigEnabled
&& m_bEditorConfigLoaded
));
454 pButton
->SetDescription(GetTabModeString(m_nTabMode
, m_nTabSize
, m_bEditorConfigEnabled
&& m_bEditorConfigLoaded
));
457 m_pwndRibbonStatusBar
->RecalcLayout();
458 m_pwndRibbonStatusBar
->Invalidate();
463 BOOL
CBaseView::PreCreateWindow(CREATESTRUCT
& cs
)
465 if (!CView::PreCreateWindow(cs
))
468 cs
.dwExStyle
|= WS_EX_CLIENTEDGE
;
469 cs
.style
&= ~WS_BORDER
;
470 cs
.lpszClass
= AfxRegisterWndClass(CS_HREDRAW
|CS_VREDRAW
|CS_DBLCLKS
,
471 ::LoadCursor(NULL
, IDC_ARROW
), reinterpret_cast<HBRUSH
>(COLOR_WINDOW
+1), NULL
);
473 CWnd
*pParentWnd
= CWnd::FromHandlePermanent(cs
.hwndParent
);
474 if (pParentWnd
== NULL
|| ! pParentWnd
->IsKindOf(RUNTIME_CLASS(CSplitterWnd
)))
476 // View must always create its own scrollbars,
477 // if only it's not used within splitter
478 cs
.style
|= (WS_HSCROLL
| WS_VSCROLL
);
480 cs
.lpszClass
= AfxRegisterWndClass(CS_DBLCLKS
);
484 CFont
* CBaseView::GetFont(BOOL bItalic
/*= FALSE*/, BOOL bBold
/*= FALSE*/)
491 if (m_apFonts
[nIndex
] == NULL
)
493 m_apFonts
[nIndex
] = new CFont
;
494 m_lfBaseFont
.lfCharSet
= DEFAULT_CHARSET
;
495 m_lfBaseFont
.lfWeight
= bBold
? FW_BOLD
: FW_NORMAL
;
496 m_lfBaseFont
.lfItalic
= (BYTE
) bItalic
;
500 m_lfBaseFont
.lfHeight
= -MulDiv((DWORD
)CRegDWORD(_T("Software\\TortoiseGitMerge\\LogFontSize"), 10), GetDeviceCaps(pDC
->m_hDC
, LOGPIXELSY
), 72);
503 _tcsncpy_s(m_lfBaseFont
.lfFaceName
, (LPCTSTR
)(CString
)CRegString(_T("Software\\TortoiseGitMerge\\LogFontName"), _T("Courier New")), _countof(m_lfBaseFont
.lfFaceName
) - 1);
504 if (!m_apFonts
[nIndex
]->CreateFontIndirect(&m_lfBaseFont
))
506 delete m_apFonts
[nIndex
];
507 m_apFonts
[nIndex
] = NULL
;
508 return CView::GetFont();
511 return m_apFonts
[nIndex
];
514 void CBaseView::CalcLineCharDim()
519 CFont
*pOldFont
= pDC
->SelectObject(GetFont());
520 const CSize szCharExt
= pDC
->GetTextExtent(_T("X"));
521 pDC
->SelectObject(pOldFont
);
524 m_nLineHeight
= szCharExt
.cy
;
525 if (m_nLineHeight
<= 0)
527 m_nCharWidth
= szCharExt
.cx
;
528 if (m_nCharWidth
<= 0)
532 int CBaseView::GetScreenChars()
534 if (m_nScreenChars
== -1)
537 GetClientRect(&rect
);
538 m_nScreenChars
= (rect
.Width() - GetMarginWidth() - GetSystemMetrics(SM_CXVSCROLL
)) / GetCharWidth();
539 if (m_nScreenChars
< 0)
542 return m_nScreenChars
;
545 int CBaseView::GetAllMinScreenChars() const
547 int nChars
= INT_MAX
;
548 if (IsLeftViewGood())
549 nChars
= std::min
<int>(nChars
, m_pwndLeft
->GetScreenChars());
550 if (IsRightViewGood())
551 nChars
= std::min
<int>(nChars
, m_pwndRight
->GetScreenChars());
552 if (IsBottomViewGood())
553 nChars
= std::min
<int>(nChars
, m_pwndBottom
->GetScreenChars());
554 return (nChars
==INT_MAX
) ? 0 : nChars
;
557 int CBaseView::GetAllMaxLineLength() const
560 if (IsLeftViewGood())
561 nLength
= std::max
<int>(nLength
, m_pwndLeft
->GetMaxLineLength());
562 if (IsRightViewGood())
563 nLength
= std::max
<int>(nLength
, m_pwndRight
->GetMaxLineLength());
564 if (IsBottomViewGood())
565 nLength
= std::max
<int>(nLength
, m_pwndBottom
->GetMaxLineLength());
569 int CBaseView::GetLineHeight()
571 if (m_nLineHeight
== -1)
573 if (m_nLineHeight
<= 0)
575 return m_nLineHeight
;
578 int CBaseView::GetCharWidth()
580 if (m_nCharWidth
== -1)
582 if (m_nCharWidth
<= 0)
587 int CBaseView::GetMaxLineLength()
589 if (m_nMaxLineLength
== -1)
591 m_nMaxLineLength
= 0;
592 int nLineCount
= GetLineCount();
593 for (int i
=0; i
<nLineCount
; i
++)
595 int nActualLength
= GetLineLength(i
);
596 if (m_nMaxLineLength
< nActualLength
)
597 m_nMaxLineLength
= nActualLength
;
600 return m_nMaxLineLength
;
603 int CBaseView::GetLineLength(int index
)
605 if (m_pViewData
== NULL
)
607 if (m_pViewData
->GetCount() == 0)
609 if ((int)m_Screen2View
.size() <= index
)
611 int viewLine
= GetViewLineForScreen(index
);
612 if (m_pMainFrame
->m_bWrapLines
)
614 int nLineLength
= GetLineChars(index
).GetLength();
615 ASSERT(nLineLength
>= 0);
618 int nLineLength
= m_pViewData
->GetLine(viewLine
).GetLength();
619 ASSERT(nLineLength
>= 0);
623 int CBaseView::GetViewLineLength(int nViewLine
) const
625 if (m_pViewData
== NULL
)
627 if (m_pViewData
->GetCount() <= nViewLine
)
629 int nLineLength
= m_pViewData
->GetLine(nViewLine
).GetLength();
630 ASSERT(nLineLength
>= 0);
634 int CBaseView::GetLineCount() const
636 if (m_pViewData
== NULL
)
638 int nLineCount
= (int)m_Screen2View
.size();
639 ASSERT(nLineCount
>= 0);
643 int CBaseView::GetSubLineOffset(int index
)
645 return m_Screen2View
.GetSubLineOffset(index
);
648 CString
CBaseView::GetViewLineChars(int nViewLine
) const
650 if (m_pViewData
== NULL
)
652 if (m_pViewData
->GetCount() <= nViewLine
)
654 return m_pViewData
->GetLine(nViewLine
);
657 CString
CBaseView::GetLineChars(int index
)
659 if (m_pViewData
== NULL
)
661 if (m_pViewData
->GetCount() == 0)
663 if ((int)m_Screen2View
.size() <= index
)
665 int viewLine
= GetViewLineForScreen(index
);
666 if (m_pMainFrame
->m_bWrapLines
)
668 int subLine
= GetSubLineOffset(index
);
671 if (subLine
< CountMultiLines(viewLine
))
673 return m_ScreenedViewLine
[viewLine
].SubLines
[subLine
];
678 return m_pViewData
->GetLine(viewLine
);
681 void CBaseView::CheckOtherView()
683 if (m_bOtherDiffChecked
)
685 // find out what the 'other' file is
686 m_pOtherViewData
= NULL
;
688 if (this == m_pwndLeft
&& IsRightViewGood())
690 m_pOtherViewData
= m_pwndRight
->m_pViewData
;
691 m_pOtherView
= m_pwndRight
;
694 if (this == m_pwndRight
&& IsLeftViewGood())
696 m_pOtherViewData
= m_pwndLeft
->m_pViewData
;
697 m_pOtherView
= m_pwndLeft
;
700 m_bOtherDiffChecked
= true;
704 void CBaseView::GetWhitespaceBlock(CViewData
*viewData
, int nLineIndex
, int & nStartBlock
, int & nEndBlock
)
706 enum { MAX_WHITESPACEBLOCK_SIZE
= 8 };
709 DiffStates origstate
= viewData
->GetState(nLineIndex
);
711 // Go back and forward at most MAX_WHITESPACEBLOCK_SIZE lines to see where this block ends
712 nStartBlock
= nLineIndex
;
713 nEndBlock
= nLineIndex
;
714 while ((nStartBlock
> 0) && (nStartBlock
> (nLineIndex
- MAX_WHITESPACEBLOCK_SIZE
)))
716 DiffStates state
= viewData
->GetState(nStartBlock
- 1);
717 if ((origstate
== DIFFSTATE_EMPTY
) && (state
!= DIFFSTATE_NORMAL
))
719 if ((origstate
== state
) || (state
== DIFFSTATE_EMPTY
))
724 while ((nEndBlock
< (viewData
->GetCount() - 1)) && (nEndBlock
< (nLineIndex
+ MAX_WHITESPACEBLOCK_SIZE
)))
726 DiffStates state
= viewData
->GetState(nEndBlock
+ 1);
727 if ((origstate
== DIFFSTATE_EMPTY
) && (state
!= DIFFSTATE_NORMAL
))
729 if ((origstate
== state
) || (state
== DIFFSTATE_EMPTY
))
736 CString
CBaseView::GetWhitespaceString(CViewData
*viewData
, int nStartBlock
, int nEndBlock
)
738 enum { MAX_WHITESPACEBLOCK_SIZE
= 8 };
741 for (int i
= nStartBlock
; i
<= nEndBlock
; ++i
)
742 len
+= viewData
->GetLine(i
).GetLength()+2;
745 // do not check for whitespace blocks if the line is too long, because
746 // reserving a lot of memory here takes too much time (performance hog)
747 if (len
> MAX_WHITESPACEBLOCK_SIZE
*256)
749 block
.Preallocate(len
+1);
750 for (int i
= nStartBlock
; i
<= nEndBlock
; ++i
)
752 block
+= viewData
->GetLine(i
);
753 block
+= m_Eols
[viewData
->GetLineEnding(i
)];
758 bool CBaseView::IsBlockWhitespaceOnly(int nLineIndex
, bool& bIdentical
, int& blockstart
, int& blockend
)
760 if (m_pViewData
== NULL
)
764 if (!m_pOtherViewData
)
766 int viewLine
= GetViewLineForScreen(nLineIndex
);
768 (m_pViewData
->GetState(viewLine
) == DIFFSTATE_NORMAL
) &&
769 (m_pOtherViewData
->GetLine(viewLine
) == m_pViewData
->GetLine(viewLine
))
775 // first check whether the line itself only has whitespace changes
776 CString mine
= m_pViewData
->GetLine(viewLine
);
777 CString other
= m_pOtherViewData
->GetLine(min(viewLine
, m_pOtherViewData
->GetCount() - 1));
778 if (mine
.IsEmpty() && other
.IsEmpty())
789 FilterWhitespaces(mine
, other
);
793 int nStartBlock2
, nEndBlock2
;
794 GetWhitespaceBlock(m_pViewData
, viewLine
, blockstart
, blockend
);
795 GetWhitespaceBlock(m_pOtherViewData
, min(viewLine
, m_pOtherViewData
->GetCount() - 1), nStartBlock2
, nEndBlock2
);
796 mine
= GetWhitespaceString(m_pViewData
, blockstart
, blockend
);
801 other
= GetWhitespaceString(m_pOtherViewData
, nStartBlock2
, nEndBlock2
);
802 bIdentical
= mine
== other
;
803 FilterWhitespaces(mine
, other
);
806 return (!mine
.IsEmpty()) && (mine
== other
);
809 bool CBaseView::IsViewLineHidden(int nViewLine
)
811 return IsViewLineHidden(m_pViewData
, nViewLine
);
814 bool CBaseView::IsViewLineHidden(CViewData
* pViewData
, int nViewLine
)
816 return m_pMainFrame
->m_bCollapsed
&& (pViewData
->GetHideState(nViewLine
)!=HIDESTATE_SHOWN
);
819 int CBaseView::GetLineNumber(int index
) const
821 if (m_pViewData
== NULL
)
823 int viewLine
= GetViewLineForScreen(index
);
824 if (m_pViewData
->GetLineNumber(viewLine
)==DIFF_EMPTYLINENUMBER
)
826 return m_pViewData
->GetLineNumber(viewLine
);
829 int CBaseView::GetScreenLines()
831 if (m_nScreenLines
== -1)
834 GetClientRect(&rect
);
835 int scrollBarHeight
= 0;
836 SCROLLBARINFO sbi
= { sizeof(sbi
) };
837 if (GetScrollBarInfo(OBJID_HSCROLL
, &sbi
))
839 // only use the scroll bar size if the info is correct and the scrollbar is visible
840 // if anything isn't proper, assume the scrollbar has a size of zero
841 // and calculate the screen lines without it.
842 if (!(sbi
.rgstate
[0] & STATE_SYSTEM_INVISIBLE
) && !(sbi
.rgstate
[0] & STATE_SYSTEM_UNAVAILABLE
))
844 scrollBarHeight
= sbi
.rcScrollBar
.bottom
- sbi
.rcScrollBar
.top
;
845 m_nScreenLines
= (rect
.Height() - HEADERHEIGHT
- scrollBarHeight
) / GetLineHeight();
846 if (m_nScreenLines
< 0)
848 return m_nScreenLines
;
851 // if the scroll bar is not visible, unavailable or there was an error,
852 // assume the scroll bar height is zero and return the screen lines here.
853 // Of course, that means the cache (using the member variable) won't work
854 // and we fetch the scroll bar info every time. But in this case the overhead is necessary.
855 return (rect
.Height() - HEADERHEIGHT
) / GetLineHeight();
857 return m_nScreenLines
;
860 int CBaseView::GetAllMinScreenLines() const
862 int nLines
= INT_MAX
;
863 if (IsLeftViewGood())
864 nLines
= m_pwndLeft
->GetScreenLines();
865 if (IsRightViewGood())
866 nLines
= std::min
<int>(nLines
, m_pwndRight
->GetScreenLines());
867 if (IsBottomViewGood())
868 nLines
= std::min
<int>(nLines
, m_pwndBottom
->GetScreenLines());
869 return (nLines
== INT_MAX
) || (nLines
< 0) ? 0 : nLines
;
872 int CBaseView::GetAllLineCount() const
875 if (IsLeftViewGood())
876 nLines
= m_pwndLeft
->GetLineCount();
877 if (IsRightViewGood())
878 nLines
= std::max
<int>(nLines
, m_pwndRight
->GetLineCount());
879 if (IsBottomViewGood())
880 nLines
= std::max
<int>(nLines
, m_pwndBottom
->GetLineCount());
884 void CBaseView::RecalcAllVertScrollBars(BOOL bPositionOnly
/*= FALSE*/)
886 if (IsLeftViewGood())
887 m_pwndLeft
->RecalcVertScrollBar(bPositionOnly
);
888 if (IsRightViewGood())
889 m_pwndRight
->RecalcVertScrollBar(bPositionOnly
);
890 if (IsBottomViewGood())
891 m_pwndBottom
->RecalcVertScrollBar(bPositionOnly
);
894 void CBaseView::RecalcVertScrollBar(BOOL bPositionOnly
/*= FALSE*/)
897 si
.cbSize
= sizeof(si
);
901 si
.nPos
= m_nTopLine
;
905 EnableScrollBarCtrl(SB_VERT
, TRUE
);
906 if (GetAllMinScreenLines() >= GetAllLineCount() && m_nTopLine
> 0)
911 si
.fMask
= SIF_DISABLENOSCROLL
| SIF_PAGE
| SIF_POS
| SIF_RANGE
;
913 si
.nMax
= GetAllLineCount();
914 si
.nPage
= GetAllMinScreenLines();
915 si
.nPos
= m_nTopLine
;
917 VERIFY(SetScrollInfo(SB_VERT
, &si
));
920 void CBaseView::OnVScroll(UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
)
922 CView::OnVScroll(nSBCode
, nPos
, pScrollBar
);
924 m_pwndLeft
->OnDoVScroll(nSBCode
, nPos
, pScrollBar
, this);
926 m_pwndRight
->OnDoVScroll(nSBCode
, nPos
, pScrollBar
, this);
928 m_pwndBottom
->OnDoVScroll(nSBCode
, nPos
, pScrollBar
, this);
930 m_pwndLocator
->Invalidate();
933 void CBaseView::OnDoVScroll(UINT nSBCode
, UINT
/*nPos*/, CScrollBar
* /*pScrollBar*/, CBaseView
* master
)
935 // Note we cannot use nPos because of its 16-bit nature
937 si
.cbSize
= sizeof(si
);
939 VERIFY(master
->GetScrollInfo(SB_VERT
, &si
));
941 int nPageLines
= GetScreenLines();
942 int nLineCount
= GetLineCount();
946 static LONG textwidth
= 0;
947 static CString
sFormat(MAKEINTRESOURCE(IDS_VIEWSCROLLTIPTEXT
));
954 nNewTopLine
= nLineCount
- nPageLines
+ 1;
957 nNewTopLine
= m_nTopLine
- 1;
960 nNewTopLine
= m_nTopLine
+ 1;
963 nNewTopLine
= m_nTopLine
- si
.nPage
+ 1;
966 nNewTopLine
= m_nTopLine
+ si
.nPage
- 1;
968 case SB_THUMBPOSITION
:
969 m_ScrollTool
.Clear();
970 nNewTopLine
= si
.nTrackPos
;
974 nNewTopLine
= si
.nTrackPos
;
975 if (GetFocus() == this)
978 GetClientRect(&thumbrect
);
979 ClientToScreen(&thumbrect
);
982 thumbpoint
.x
= thumbrect
.right
;
983 thumbpoint
.y
= thumbrect
.top
+ ((thumbrect
.bottom
-thumbrect
.top
)*si
.nTrackPos
)/(si
.nMax
-si
.nMin
);
984 m_ScrollTool
.Init(&thumbpoint
);
987 CString sTemp
= sFormat
;
988 sTemp
.Format(sFormat
, m_nDigits
, 10*m_nDigits
-1);
989 textwidth
= m_ScrollTool
.GetTextWidth(sTemp
);
991 thumbpoint
.x
-= textwidth
;
992 int line
= GetLineNumber(nNewTopLine
);
994 m_ScrollTool
.SetText(&thumbpoint
, sFormat
, m_nDigits
, GetLineNumber(nNewTopLine
)+1);
996 m_ScrollTool
.SetText(&thumbpoint
, m_sNoLineNr
);
1003 if (nNewTopLine
< 0)
1005 if (nNewTopLine
>= nLineCount
)
1006 nNewTopLine
= nLineCount
- 1;
1007 ScrollToLine(nNewTopLine
);
1010 void CBaseView::RecalcAllHorzScrollBars(BOOL bPositionOnly
/*= FALSE*/)
1012 if (IsLeftViewGood())
1013 m_pwndLeft
->RecalcHorzScrollBar(bPositionOnly
);
1014 if (IsRightViewGood())
1015 m_pwndRight
->RecalcHorzScrollBar(bPositionOnly
);
1016 if (IsBottomViewGood())
1017 m_pwndBottom
->RecalcHorzScrollBar(bPositionOnly
);
1020 void CBaseView::RecalcHorzScrollBar(BOOL bPositionOnly
/*= FALSE*/)
1023 si
.cbSize
= sizeof(si
);
1027 si
.nPos
= m_nOffsetChar
;
1031 EnableScrollBarCtrl(SB_HORZ
, !m_pMainFrame
->m_bWrapLines
);
1032 if (!m_pMainFrame
->m_bWrapLines
)
1034 int minScreenChars
= GetAllMinScreenChars();
1035 int maxLineLength
= GetAllMaxLineLength();
1036 if (minScreenChars
>= maxLineLength
&& m_nOffsetChar
> 0)
1041 si
.fMask
= SIF_DISABLENOSCROLL
| SIF_PAGE
| SIF_POS
| SIF_RANGE
;
1043 si
.nMax
= m_pMainFrame
->m_bWrapLines
? minScreenChars
: maxLineLength
;
1044 si
.nMax
+= GetMarginWidth()/GetCharWidth();
1045 si
.nPage
= GetScreenChars();
1046 si
.nPos
= m_nOffsetChar
;
1049 VERIFY(SetScrollInfo(SB_HORZ
, &si
));
1052 void CBaseView::OnHScroll(UINT nSBCode
, UINT nPos
, CScrollBar
* pScrollBar
)
1054 CView::OnHScroll(nSBCode
, nPos
, pScrollBar
);
1056 m_pwndLeft
->OnDoHScroll(nSBCode
, nPos
, pScrollBar
, this);
1058 m_pwndRight
->OnDoHScroll(nSBCode
, nPos
, pScrollBar
, this);
1060 m_pwndBottom
->OnDoHScroll(nSBCode
, nPos
, pScrollBar
, this);
1062 m_pwndLocator
->Invalidate();
1065 void CBaseView::OnDoHScroll(UINT nSBCode
, UINT
/*nPos*/, CScrollBar
* /*pScrollBar*/, CBaseView
* master
)
1068 si
.cbSize
= sizeof(si
);
1070 VERIFY(master
->GetScrollInfo(SB_HORZ
, &si
));
1072 int nPageChars
= GetScreenChars();
1073 int nMaxLineLength
= GetMaxLineLength();
1082 nNewOffset
= nMaxLineLength
- nPageChars
+ 1;
1085 nNewOffset
= m_nOffsetChar
- 1;
1088 nNewOffset
= m_nOffsetChar
+ 1;
1091 nNewOffset
= m_nOffsetChar
- si
.nPage
+ 1;
1094 nNewOffset
= m_nOffsetChar
+ si
.nPage
- 1;
1096 case SB_THUMBPOSITION
:
1098 nNewOffset
= si
.nTrackPos
;
1104 if (nNewOffset
>= nMaxLineLength
)
1105 nNewOffset
= nMaxLineLength
- 1;
1108 ScrollToChar(nNewOffset
, TRUE
);
1111 void CBaseView::ScrollToChar(int nNewOffsetChar
, BOOL bTrackScrollBar
/*= TRUE*/)
1113 if (m_nOffsetChar
!= nNewOffsetChar
)
1115 int nScrollChars
= m_nOffsetChar
- nNewOffsetChar
;
1116 m_nOffsetChar
= nNewOffsetChar
;
1118 GetClientRect(&rcScroll
);
1119 rcScroll
.left
+= GetMarginWidth();
1120 rcScroll
.top
+= GetLineHeight()+HEADERHEIGHT
;
1121 ScrollWindow(nScrollChars
* GetCharWidth(), 0, &rcScroll
, &rcScroll
);
1122 // update the view header
1125 rcScroll
.bottom
= GetLineHeight()+HEADERHEIGHT
;
1126 InvalidateRect(&rcScroll
, FALSE
);
1128 if (bTrackScrollBar
)
1129 RecalcHorzScrollBar(TRUE
);
1131 if (m_pwndLineDiffBar
)
1132 m_pwndLineDiffBar
->Invalidate();
1136 void CBaseView::ScrollAllToChar(int nNewOffsetChar
, BOOL bTrackScrollBar
/* = TRUE */)
1139 m_pwndLeft
->ScrollToChar(nNewOffsetChar
, bTrackScrollBar
);
1141 m_pwndRight
->ScrollToChar(nNewOffsetChar
, bTrackScrollBar
);
1143 m_pwndBottom
->ScrollToChar(nNewOffsetChar
, bTrackScrollBar
);
1146 void CBaseView::ScrollAllSide(int delta
)
1148 int nNewOffset
= m_nOffsetChar
;
1149 nNewOffset
+= delta
;
1150 int nMaxLineLength
= GetMaxLineLength();
1151 if (nNewOffset
>= nMaxLineLength
)
1152 nNewOffset
= nMaxLineLength
- 1;
1155 ScrollAllToChar(nNewOffset
, TRUE
);
1156 if (m_pwndLineDiffBar
)
1157 m_pwndLineDiffBar
->Invalidate();
1161 void CBaseView::ScrollSide(int delta
)
1163 int nNewOffset
= m_nOffsetChar
;
1164 nNewOffset
+= delta
;
1165 int nMaxLineLength
= GetMaxLineLength();
1166 if (nNewOffset
>= nMaxLineLength
)
1167 nNewOffset
= nMaxLineLength
- 1;
1170 ScrollToChar(nNewOffset
, TRUE
);
1171 if (m_pwndLineDiffBar
)
1172 m_pwndLineDiffBar
->Invalidate();
1176 void CBaseView::ScrollVertical(short zDelta
)
1178 const int nLineCount
= GetLineCount();
1179 int nTopLine
= m_nTopLine
;
1180 nTopLine
-= (zDelta
/30);
1183 if (nTopLine
>= nLineCount
)
1184 nTopLine
= nLineCount
- 1;
1185 ScrollToLine(nTopLine
, TRUE
);
1188 void CBaseView::ScrollToLine(int nNewTopLine
, BOOL bTrackScrollBar
/*= TRUE*/)
1190 if (m_nTopLine
!= nNewTopLine
)
1192 if (nNewTopLine
< 0)
1195 int nScrollLines
= m_nTopLine
- nNewTopLine
;
1197 m_nTopLine
= nNewTopLine
;
1199 GetClientRect(&rcScroll
);
1200 rcScroll
.top
+= GetLineHeight()+HEADERHEIGHT
;
1201 ScrollWindow(0, nScrollLines
* GetLineHeight(), &rcScroll
, &rcScroll
);
1203 if (bTrackScrollBar
)
1204 RecalcVertScrollBar(TRUE
);
1210 void CBaseView::DrawMargin(CDC
*pdc
, const CRect
&rect
, int nLineIndex
)
1212 pdc
->FillSolidRect(rect
, ::GetSysColor(COLOR_SCROLLBAR
));
1214 if ((nLineIndex
>= 0)&&(m_pViewData
)&&(m_pViewData
->GetCount()))
1216 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1218 ASSERT(nViewLine
<(int)m_ScreenedViewLine
.size());
1219 TScreenedViewLine::EIcon eIcon
= m_ScreenedViewLine
[nViewLine
].eIcon
;
1220 if (eIcon
==TScreenedViewLine::ICN_UNKNOWN
)
1222 DiffStates state
= m_pViewData
->GetState(nViewLine
);
1225 case DIFFSTATE_ADDED
:
1226 case DIFFSTATE_THEIRSADDED
:
1227 case DIFFSTATE_YOURSADDED
:
1228 case DIFFSTATE_IDENTICALADDED
:
1229 case DIFFSTATE_CONFLICTADDED
:
1230 eIcon
= TScreenedViewLine::ICN_ADD
;
1232 case DIFFSTATE_REMOVED
:
1233 case DIFFSTATE_THEIRSREMOVED
:
1234 case DIFFSTATE_YOURSREMOVED
:
1235 case DIFFSTATE_IDENTICALREMOVED
:
1236 eIcon
= TScreenedViewLine::ICN_REMOVED
;
1238 case DIFFSTATE_CONFLICTED
:
1239 eIcon
= TScreenedViewLine::ICN_CONFLICT
;
1241 case DIFFSTATE_CONFLICTED_IGNORED
:
1242 eIcon
= TScreenedViewLine::ICN_CONFLICTIGNORED
;
1244 case DIFFSTATE_EDITED
:
1245 eIcon
= TScreenedViewLine::ICN_EDIT
;
1250 bool bIdentical
= false;
1251 int blockstart
= -1;
1253 if ((state
!= DIFFSTATE_EDITED
)&&(IsBlockWhitespaceOnly(nLineIndex
, bIdentical
, blockstart
, blockend
)))
1256 eIcon
= TScreenedViewLine::ICN_SAME
;
1258 eIcon
= TScreenedViewLine::ICN_WHITESPACEDIFF
;
1259 if (((blockstart
>= 0) && (blockend
>= 0)) && (blockstart
< blockend
))
1261 if (nViewLine
> blockstart
)
1262 Invalidate(); // redraw the upper icons since they're now changing
1263 while (blockstart
<= blockend
)
1264 m_ScreenedViewLine
[blockstart
++].eIcon
= eIcon
;
1267 if (m_pViewData
->GetMovedIndex(nViewLine
) >= 0)
1268 eIcon
= TScreenedViewLine::ICN_MOVED
;
1269 if (m_pViewData
->GetMarked(nViewLine
))
1270 eIcon
= TScreenedViewLine::ICN_MARKED
;
1271 m_ScreenedViewLine
[nViewLine
].eIcon
= eIcon
;
1275 case TScreenedViewLine::ICN_UNKNOWN
:
1276 case TScreenedViewLine::ICN_NONE
:
1278 case TScreenedViewLine::ICN_SAME
:
1279 icon
= m_hEqualIcon
;
1281 case TScreenedViewLine::ICN_EDIT
:
1282 icon
= m_hEditedIcon
;
1284 case TScreenedViewLine::ICN_WHITESPACEDIFF
:
1285 icon
= m_hWhitespaceBlockIcon
;
1287 case TScreenedViewLine::ICN_ADD
:
1288 icon
= m_hAddedIcon
;
1290 case TScreenedViewLine::ICN_CONFLICT
:
1291 icon
= m_hConflictedIcon
;
1293 case TScreenedViewLine::ICN_CONFLICTIGNORED
:
1294 icon
= m_hConflictedIgnoredIcon
;
1296 case TScreenedViewLine::ICN_REMOVED
:
1297 icon
= m_hRemovedIcon
;
1299 case TScreenedViewLine::ICN_MOVED
:
1300 icon
= m_hMovedIcon
;
1302 case TScreenedViewLine::ICN_MARKED
:
1303 icon
= m_hMarkedIcon
;
1310 ::DrawIconEx(pdc
->m_hDC
, rect
.left
+ 2, rect
.top
+ (rect
.Height()-16)/2, icon
, 16, 16, NULL
, NULL
, DI_NORMAL
);
1312 if ((m_bViewLinenumbers
)&&(m_nDigits
))
1314 int nSubLine
= GetSubLineOffset(nLineIndex
);
1315 bool bIsFirstSubline
= (nSubLine
== 0) || (nSubLine
== -1);
1316 CString sLinenumber
;
1317 if (bIsFirstSubline
)
1319 CString sLinenumberFormat
;
1320 int nLineNumber
= GetLineNumber(nLineIndex
);
1321 if (IsViewLineHidden(GetViewLineForScreen(nLineIndex
)))
1323 // TODO: do not show if there is no number hidden
1324 // TODO: show number if there is only one
1325 sLinenumberFormat
.Format(_T("%%%ds"), m_nDigits
);
1326 sLinenumber
.Format(sLinenumberFormat
, (m_nDigits
>1) ? _T("↕⁞") : _T("⁞")); // alternative …
1328 else if (nLineNumber
>= 0)
1330 sLinenumberFormat
.Format(_T("%%%dd"), m_nDigits
);
1331 sLinenumber
.Format(sLinenumberFormat
, nLineNumber
+1);
1333 else if (m_pMainFrame
->m_bWrapLines
)
1335 sLinenumberFormat
.Format(_T("%%%ds"), m_nDigits
);
1336 sLinenumber
.Format(sLinenumberFormat
, _T("·"));
1338 if (!sLinenumber
.IsEmpty())
1340 pdc
->SetBkColor(::GetSysColor(COLOR_SCROLLBAR
));
1341 pdc
->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT
));
1343 pdc
->SelectObject(GetFont());
1344 pdc
->ExtTextOut(rect
.left
+ 18, rect
.top
, ETO_CLIPPED
, &rect
, sLinenumber
, NULL
);
1351 int CBaseView::GetMarginWidth()
1353 if ((m_bViewLinenumbers
)&&(m_pViewData
)&&(m_pViewData
->GetCount()))
1357 int nLength
= (int)m_pViewData
->GetCount();
1358 // find out how many digits are needed to show the highest line number
1360 sMax
.Format(_T("%d"), nLength
);
1361 m_nDigits
= sMax
.GetLength();
1363 int nWidth
= GetCharWidth();
1364 return (MARGINWIDTH
+ (m_nDigits
* nWidth
) + 2);
1369 void CBaseView::DrawHeader(CDC
*pdc
, const CRect
&rect
)
1371 CRect
textrect(rect
.left
, rect
.top
, rect
.Width(), GetLineHeight()+HEADERHEIGHT
);
1372 COLORREF crBk
, crFg
;
1373 if (IsBottomViewGood())
1375 CDiffColors::GetInstance().GetColors(DIFFSTATE_NORMAL
, crBk
, crFg
);
1376 crBk
= ::GetSysColor(COLOR_SCROLLBAR
);
1380 DiffStates state
= DIFFSTATE_REMOVED
;
1381 if (this == m_pwndRight
)
1383 state
= DIFFSTATE_ADDED
;
1385 CDiffColors::GetInstance().GetColors(state
, crBk
, crFg
);
1387 pdc
->SetBkColor(crBk
);
1388 pdc
->FillSolidRect(textrect
, crBk
);
1390 pdc
->SetTextColor(crFg
);
1392 pdc
->SelectObject(GetFont(FALSE
, TRUE
));
1397 sViewTitle
= _T("* ") + m_sWindowName
;
1401 sViewTitle
= m_sWindowName
;
1403 int nStringLength
= (GetCharWidth()*m_sWindowName
.GetLength());
1404 if (nStringLength
> rect
.Width())
1406 int offset
= std::min
<int>(m_nOffsetChar
, (nStringLength
-rect
.Width())/GetCharWidth()+1);
1407 sViewTitle
= m_sWindowName
.Mid(offset
);
1409 pdc
->ExtTextOut(std::max
<int>(rect
.left
+ (rect
.Width()-nStringLength
)/2, 1),
1410 rect
.top
+(HEADERHEIGHT
/2), ETO_CLIPPED
, textrect
, sViewTitle
, NULL
);
1411 if (this->GetFocus() == this)
1412 pdc
->DrawEdge(textrect
, EDGE_BUMP
, BF_RECT
);
1414 pdc
->DrawEdge(textrect
, EDGE_ETCHED
, BF_RECT
);
1417 void CBaseView::OnDraw(CDC
* pDC
)
1420 GetClientRect(rcClient
);
1422 int nLineCount
= GetLineCount();
1423 int nLineHeight
= GetLineHeight();
1426 VERIFY(cacheDC
.CreateCompatibleDC(pDC
));
1427 if (m_pCacheBitmap
== NULL
)
1429 m_pCacheBitmap
= new CBitmap
;
1430 VERIFY(m_pCacheBitmap
->CreateCompatibleBitmap(pDC
, rcClient
.Width(), nLineHeight
));
1432 CBitmap
*pOldBitmap
= cacheDC
.SelectObject(m_pCacheBitmap
);
1434 DrawHeader(pDC
, rcClient
);
1438 rcLine
.top
+= nLineHeight
+HEADERHEIGHT
;
1439 rcLine
.bottom
= rcLine
.top
+ nLineHeight
;
1440 CRect
rcCacheMargin(0, 0, GetMarginWidth(), nLineHeight
);
1441 CRect
rcCacheLine(GetMarginWidth(), 0, rcLine
.Width(), nLineHeight
);
1443 int nCurrentLine
= m_nTopLine
;
1444 bool bBeyondFileLineCached
= false;
1445 while (rcLine
.top
< rcClient
.bottom
)
1447 if (nCurrentLine
< nLineCount
)
1449 DrawMargin(&cacheDC
, rcCacheMargin
, nCurrentLine
);
1450 DrawSingleLine(&cacheDC
, rcCacheLine
, nCurrentLine
);
1451 bBeyondFileLineCached
= false;
1453 else if (!bBeyondFileLineCached
)
1455 DrawMargin(&cacheDC
, rcCacheMargin
, -1);
1456 DrawSingleLine(&cacheDC
, rcCacheLine
, -1);
1457 bBeyondFileLineCached
= true;
1460 VERIFY(pDC
->BitBlt(rcLine
.left
, rcLine
.top
, rcLine
.Width(), rcLine
.Height(), &cacheDC
, 0, 0, SRCCOPY
));
1463 rcLine
.OffsetRect(0, nLineHeight
);
1466 cacheDC
.SelectObject(pOldBitmap
);
1470 bool CBaseView::IsStateConflicted(DiffStates state
)
1474 case DIFFSTATE_CONFLICTED
:
1475 case DIFFSTATE_CONFLICTED_IGNORED
:
1476 case DIFFSTATE_CONFLICTEMPTY
:
1477 case DIFFSTATE_CONFLICTADDED
:
1483 bool CBaseView::IsStateEmpty(DiffStates state
)
1487 case DIFFSTATE_CONFLICTEMPTY
:
1488 case DIFFSTATE_UNKNOWN
:
1489 case DIFFSTATE_EMPTY
:
1495 bool CBaseView::IsStateRemoved(DiffStates state
)
1499 case DIFFSTATE_REMOVED
:
1500 case DIFFSTATE_THEIRSREMOVED
:
1501 case DIFFSTATE_YOURSREMOVED
:
1502 case DIFFSTATE_IDENTICALREMOVED
:
1508 DiffStates
CBaseView::ResolveState(DiffStates state
)
1510 if (IsStateConflicted(state
))
1512 if (state
== DIFFSTATE_CONFLICTEMPTY
)
1513 return DIFFSTATE_CONFLICTRESOLVEDEMPTY
;
1515 return DIFFSTATE_CONFLICTRESOLVED
;
1521 bool CBaseView::IsLineEmpty(int nLineIndex
)
1523 if (m_pViewData
== 0)
1525 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1526 return IsViewLineEmpty(nViewLine
);
1529 bool CBaseView::IsViewLineEmpty(int nViewLine
)
1531 if (m_pViewData
== 0)
1533 const DiffStates state
= m_pViewData
->GetState(nViewLine
);
1534 return IsStateEmpty(state
);
1537 bool CBaseView::IsLineRemoved(int nLineIndex
)
1539 if (m_pViewData
== 0)
1541 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1542 return IsViewLineRemoved(nViewLine
);
1545 bool CBaseView::IsViewLineRemoved(int nViewLine
)
1547 if (m_pViewData
== 0)
1549 const DiffStates state
= m_pViewData
->GetState(nViewLine
);
1550 return IsStateRemoved(state
);
1553 bool CBaseView::IsViewLineConflicted(int nLineIndex
)
1555 if (m_pViewData
== 0)
1557 const DiffStates state
= m_pViewData
->GetState(nLineIndex
);
1558 return IsStateConflicted(state
);
1561 COLORREF
CBaseView::InlineDiffColor(int nLineIndex
)
1563 return IsLineRemoved(nLineIndex
) ? m_InlineRemovedBk
: m_InlineAddedBk
;
1566 COLORREF
CBaseView::InlineViewLineDiffColor(int nViewLine
)
1568 return IsViewLineRemoved(nViewLine
) ? m_InlineRemovedBk
: m_InlineAddedBk
;
1571 void CBaseView::DrawLineEnding(CDC
*pDC
, const CRect
&rc
, int nLineIndex
, const CPoint
& origin
)
1573 if (origin
.x
< (rc
.left
- GetCharWidth() +1))
1575 if (!(m_bViewWhitespace
&& m_pViewData
&& (nLineIndex
>= 0) && (nLineIndex
< GetLineCount())))
1577 int viewLine
= GetViewLineForScreen(nLineIndex
);
1578 EOL ending
= m_pViewData
->GetLineEnding(viewLine
);
1581 HICON hEndingIcon
= NULL
;
1584 case EOL_CR
: hEndingIcon
= m_hLineEndingCR
; break;
1585 case EOL_CRLF
: hEndingIcon
= m_hLineEndingCRLF
; break;
1586 case EOL_LF
: hEndingIcon
= m_hLineEndingLF
; break;
1589 // If EOL style has changed, color end-of-line markers as inline differences.
1591 m_bShowInlineDiff
&& m_pOtherViewData
&&
1592 (viewLine
< m_pOtherViewData
->GetCount()) &&
1593 (ending
!= EOL_NOENDING
) &&
1594 (ending
!= m_pOtherViewData
->GetLineEnding(viewLine
) &&
1595 (m_pOtherViewData
->GetLineEnding(viewLine
) != EOL_NOENDING
))
1598 pDC
->FillSolidRect(origin
.x
, origin
.y
, rc
.Height(), rc
.Height(), InlineDiffColor(nLineIndex
));
1601 DrawIconEx(pDC
->GetSafeHdc(), origin
.x
, origin
.y
, hEndingIcon
, rc
.Height(), rc
.Height(), NULL
, NULL
, DI_NORMAL
);
1605 CPen
pen(PS_SOLID
, 0, m_WhiteSpaceFg
);
1606 CPen
* oldpen
= pDC
->SelectObject(&pen
);
1607 int yMiddle
= origin
.y
+ rc
.Height()/2;
1608 int xMiddle
= origin
.x
+GetCharWidth()/2;
1609 bool bMultiline
= false;
1610 if (((int)m_Screen2View
.size() > nLineIndex
+1) && (GetViewLineForScreen(nLineIndex
+1) == viewLine
))
1612 if (GetLineLength(nLineIndex
+1))
1616 pDC
->MoveTo(origin
.x
, yMiddle
-2);
1617 pDC
->LineTo(origin
.x
+GetCharWidth()-1, yMiddle
-2);
1618 pDC
->LineTo(origin
.x
+GetCharWidth()-1, yMiddle
+2);
1619 pDC
->LineTo(origin
.x
, yMiddle
+2);
1621 else if (GetLineLength(nLineIndex
) == 0)
1624 else if ((nLineIndex
> 0) && (GetViewLineForScreen(nLineIndex
-1) == viewLine
) && (GetLineLength(nLineIndex
) == 0))
1633 // arrow from top to middle+2, then left
1634 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, rc
.top
+1);
1635 pDC
->LineTo(origin
.x
+GetCharWidth()-1, yMiddle
);
1637 // arrow from right to left
1638 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, yMiddle
);
1639 pDC
->LineTo(origin
.x
, yMiddle
);
1640 pDC
->LineTo(origin
.x
+4, yMiddle
+4);
1641 pDC
->MoveTo(origin
.x
, yMiddle
);
1642 pDC
->LineTo(origin
.x
+4, yMiddle
-4);
1645 // from right-upper to left then down
1646 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, yMiddle
-2);
1647 pDC
->LineTo(xMiddle
, yMiddle
-2);
1648 pDC
->LineTo(xMiddle
, rc
.bottom
-1);
1649 pDC
->LineTo(xMiddle
+4, rc
.bottom
-5);
1650 pDC
->MoveTo(xMiddle
, rc
.bottom
-1);
1651 pDC
->LineTo(xMiddle
-4, rc
.bottom
-5);
1654 // arrow from top to bottom
1655 pDC
->MoveTo(xMiddle
, rc
.top
);
1656 pDC
->LineTo(xMiddle
, rc
.bottom
-1);
1657 pDC
->LineTo(xMiddle
+4, rc
.bottom
-5);
1658 pDC
->MoveTo(xMiddle
, rc
.bottom
-1);
1659 pDC
->LineTo(xMiddle
-4, rc
.bottom
-5);
1661 case EOL_FF
: // Form Feed, U+000C
1662 case EOL_NEL
: // Next Line, U+0085
1663 case EOL_LS
: // Line Separator, U+2028
1664 case EOL_PS
: // Paragraph Separator, U+2029
1665 // draw a horizontal line at the bottom of this line
1666 pDC
->FillSolidRect(rc
.left
, rc
.bottom
-1, rc
.right
, rc
.bottom
, GetSysColor(COLOR_WINDOWTEXT
));
1667 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, rc
.bottom
-GetCharWidth()-2);
1668 pDC
->LineTo(origin
.x
, rc
.bottom
-2);
1669 pDC
->LineTo(origin
.x
+5, rc
.bottom
-2);
1670 pDC
->MoveTo(origin
.x
, rc
.bottom
-2);
1671 pDC
->LineTo(origin
.x
+1, rc
.bottom
-6);
1673 default: // other EOLs
1674 // arrow from top right to bottom left
1675 pDC
->MoveTo(origin
.x
+GetCharWidth()-1, rc
.bottom
-GetCharWidth());
1676 pDC
->LineTo(origin
.x
, rc
.bottom
-1);
1677 pDC
->LineTo(origin
.x
+5, rc
.bottom
-2);
1678 pDC
->MoveTo(origin
.x
, rc
.bottom
-1);
1679 pDC
->LineTo(origin
.x
+1, rc
.bottom
-6);
1685 pDC
->SelectObject(oldpen
);
1689 void CBaseView::DrawBlockLine(CDC
*pDC
, const CRect
&rc
, int nLineIndex
)
1691 if (!m_bShowSelection
)
1696 if (!GetViewSelection(nSelBlockStart
, nSelBlockEnd
))
1699 const int THICKNESS
= 2;
1700 COLORREF rectcol
= GetSysColor(m_bFocused
? COLOR_WINDOWTEXT
: COLOR_GRAYTEXT
);
1702 int nViewLineIndex
= GetViewLineForScreen(nLineIndex
);
1703 int nSubLine
= GetSubLineOffset(nLineIndex
);
1704 bool bFirstLineOfViewLine
= (nSubLine
==0 || nSubLine
==-1);
1705 if ((nViewLineIndex
== nSelBlockStart
) && bFirstLineOfViewLine
)
1707 pDC
->FillSolidRect(rc
.left
, rc
.top
, rc
.Width(), THICKNESS
, rectcol
);
1710 bool bLastLineOfViewLine
= (nLineIndex
+1 == m_Screen2View
.size()) || (GetViewLineForScreen(nLineIndex
) != GetViewLineForScreen(nLineIndex
+1));
1711 if ((nViewLineIndex
== nSelBlockEnd
) && bLastLineOfViewLine
)
1713 pDC
->FillSolidRect(rc
.left
, rc
.bottom
- THICKNESS
, rc
.Width(), THICKNESS
, rectcol
);
1717 void CBaseView::DrawTextLine(
1718 CDC
* pDC
, const CRect
&rc
, int nLineIndex
, POINT
& coords
)
1720 ASSERT(nLineIndex
< GetLineCount());
1721 int nViewLine
= GetViewLineForScreen(nLineIndex
);
1722 ASSERT(m_pViewData
&& (nViewLine
< m_pViewData
->GetCount()));
1724 LineColors lineCols
= GetLineColors(nViewLine
);
1726 CString sViewLine
= GetViewLineChars(nViewLine
);
1728 if (m_bShowSelection
&& HasTextSelection())
1730 // has this line selection ?
1731 if ((m_ptSelectionViewPosStart
.y
<= nViewLine
) && (nViewLine
<= m_ptSelectionViewPosEnd
.y
))
1733 int nViewLineLength
= sViewLine
.GetLength();
1735 // first suppose the whole line is selected
1736 int selectedStart
= 0;
1737 int selectedEnd
= nViewLineLength
;
1739 // the view line is partially selected
1740 if (m_ptSelectionViewPosStart
.y
== nViewLine
)
1742 selectedStart
= m_ptSelectionViewPosStart
.x
;
1745 if (m_ptSelectionViewPosEnd
.y
== nViewLine
)
1747 selectedEnd
= m_ptSelectionViewPosEnd
.x
;
1749 // apply selection coloring
1750 // First enforce start and end point
1751 lineCols
.SplitBlock(selectedStart
);
1752 lineCols
.SplitBlock(selectedEnd
);
1753 // change color of affected parts
1754 long intenseColorScale
= m_bFocused
? 70 : 30;
1755 std::map
<int, linecolors_t
>::iterator it
= lineCols
.lower_bound(selectedStart
);
1756 for ( ; it
!= lineCols
.end() && it
->first
< selectedEnd
; ++it
)
1758 COLORREF crBk
= CAppUtils::IntenseColor(intenseColorScale
, it
->second
.background
);
1759 if (it
->second
.shot
== it
->second
.background
)
1761 it
->second
.shot
= crBk
;
1763 it
->second
.background
= crBk
;
1764 it
->second
.text
= CAppUtils::IntenseColor(intenseColorScale
, it
->second
.text
);
1769 // TODO: remove duplicate from selection and mark
1770 if (!m_sMarkedWord
.IsEmpty())
1772 int nMarkLength
= m_sMarkedWord
.GetLength();
1773 //int nViewLineLength = sViewLine.GetLength();
1774 const TCHAR
* text
= sViewLine
;
1775 const TCHAR
* findText
= text
;
1776 while ((findText
= _tcsstr(findText
, (LPCTSTR
)m_sMarkedWord
))!=0)
1778 int nMarkStart
= static_cast<int>(findText
- text
);
1779 int nMarkEnd
= nMarkStart
+ nMarkLength
;
1780 findText
+= nMarkLength
;
1781 ECharGroup eLeft
= GetCharGroup(sViewLine
, nMarkStart
- 1);
1782 ECharGroup eStart
= GetCharGroup(sViewLine
, nMarkStart
);
1783 if (eLeft
== eStart
)
1785 ECharGroup eRight
= GetCharGroup(sViewLine
, nMarkEnd
);
1786 ECharGroup eEnd
= GetCharGroup(sViewLine
, nMarkEnd
- 1);
1790 // First enforce start and end point
1791 lineCols
.SplitBlock(nMarkStart
);
1792 lineCols
.SplitBlock(nMarkEnd
);
1793 // change color of affected parts
1794 const long int nIntenseColorScale
= 200;
1795 std::map
<int, linecolors_t
>::iterator it
= lineCols
.lower_bound(nMarkStart
);
1796 for ( ; it
!= lineCols
.end() && it
->first
< nMarkEnd
; ++it
)
1798 COLORREF crBk
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.background
);
1799 if (it
->second
.shot
== it
->second
.background
)
1801 it
->second
.shot
= crBk
;
1803 it
->second
.background
= crBk
;
1804 it
->second
.text
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.text
);
1808 if (!m_sFindText
.IsEmpty())
1812 int nStringPos
= nMarkStart
;
1813 CString searchLine
= sViewLine
;
1815 searchLine
.MakeLower();
1816 while (StringFound(searchLine
, SearchNext
, nMarkStart
, nMarkEnd
)!=0)
1818 // First enforce start and end point
1819 lineCols
.SplitBlock(nMarkStart
+nStringPos
);
1820 lineCols
.SplitBlock(nMarkEnd
+nStringPos
);
1821 // change color of affected parts
1822 const long int nIntenseColorScale
= 30;
1823 std::map
<int, linecolors_t
>::iterator it
= lineCols
.lower_bound(nMarkStart
+nStringPos
);
1824 for ( ; it
!= lineCols
.end() && it
->first
< nMarkEnd
; ++it
)
1826 COLORREF crBk
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.background
);
1827 if (it
->second
.shot
== it
->second
.background
)
1829 it
->second
.shot
= crBk
;
1831 it
->second
.background
= crBk
;
1832 it
->second
.text
= CAppUtils::IntenseColor(nIntenseColorScale
, it
->second
.text
);
1834 searchLine
= searchLine
.Mid(nMarkEnd
);
1835 nStringPos
= nMarkEnd
;
1841 // @ this point we may cache data for next line which may be same in wrapped mode
1843 int nTextOffset
= 0;
1844 int nSubline
= GetSubLineOffset(nLineIndex
);
1845 for (int n
=0; n
<nSubline
; n
++)
1847 CString sLine
= m_ScreenedViewLine
[nViewLine
].SubLines
[n
];
1848 nTextOffset
+= sLine
.GetLength();
1851 CString sLine
= GetLineChars(nLineIndex
);
1852 int nLineLength
= sLine
.GetLength();
1853 CString sLineExp
= ExpandChars(sLine
);
1854 LPCTSTR textExp
= sLineExp
;
1855 //int nLineLengthExp = sLineExp.GetLength();
1857 int nLeft
= coords
.x
;
1858 for (std::map
<int, linecolors_t
>::const_iterator itStart
= lineCols
.begin(); itStart
!= lineCols
.end(); ++itStart
)
1860 std::map
<int, linecolors_t
>::const_iterator itEnd
= itStart
;
1862 int nStart
= std::max
<int>(0, itStart
->first
- nTextOffset
);
1863 int nEnd
= nLineLength
;
1864 if (itEnd
!= lineCols
.end())
1866 nEnd
= std::min
<int>(nEnd
, itEnd
->first
- nTextOffset
);
1868 int nBlockLength
= nEnd
- nStart
;
1869 if (nBlockLength
> 0 && nEnd
>=0)
1871 pDC
->SetBkColor(itStart
->second
.background
);
1872 pDC
->SetTextColor(itStart
->second
.text
);
1873 int nEndExp
= CountExpandedChars(sLine
, nEnd
);
1874 int nTextLength
= nEndExp
- nStartExp
;
1875 LPCTSTR p_zBlockText
= textExp
+ nStartExp
;
1877 GetTextExtentPoint32(pDC
->GetSafeHdc(), p_zBlockText
, nTextLength
, &Size
); // falls time-2-tme
1878 int nRight
= nLeft
+ Size
.cx
;
1879 if ((nRight
> rc
.left
) && (nLeft
< rc
.right
))
1881 // note: ExtTextOut has a limit for the length of the string. That limit is supposed
1882 // to be 8192, but that's not really true: I found that the limit (at least on my machine and a few others)
1883 // is 4094 (4095 doesn't work anymore).
1884 // So we limit the length here to that 4094 chars.
1885 // In case we're scrolled to the right, there's no need to draw the string
1886 // from way outside our window, so we also offset the drawing to the start of the window.
1887 // This reduces the string length as well.
1889 int leftcoord
= nLeft
;
1892 int fit
= nTextLength
;
1893 std::unique_ptr
<int> posBuffer(new int[fit
]);
1894 GetTextExtentExPoint(pDC
->GetSafeHdc(), p_zBlockText
, nTextLength
, INT_MAX
, &fit
, posBuffer
.get(), &Size
);
1895 int lower
= 0, upper
= fit
- 1;
1898 int middle
= (upper
+ lower
+ 1) / 2;
1899 int width
= posBuffer
.get()[middle
];
1900 if (rc
.left
- nLeft
< width
)
1904 } while (lower
< upper
);
1907 nTextLength
-= offset
;
1908 leftcoord
+= lower
> 0 ? posBuffer
.get()[lower
- 1] : 0;
1911 pDC
->ExtTextOut(leftcoord
, coords
.y
, ETO_CLIPPED
, &rc
, p_zBlockText
+offset
, min(nTextLength
, 4094), NULL
);
1912 if ((itStart
->second
.shot
!= itStart
->second
.background
) && (itStart
->first
== nStart
+ nTextOffset
))
1914 pDC
->FillSolidRect(nLeft
-1, rc
.top
, 1, rc
.Height(), itStart
->second
.shot
);
1919 nStartExp
= nEndExp
;
1924 void CBaseView::DrawSingleLine(CDC
*pDC
, const CRect
&rc
, int nLineIndex
)
1926 if (nLineIndex
>= GetLineCount())
1928 ASSERT(nLineIndex
>= -1);
1930 if ((nLineIndex
== -1) || !m_pViewData
)
1932 // Draw line beyond the text
1933 COLORREF crBkgnd
, crText
;
1934 CDiffColors::GetInstance().GetColors(DIFFSTATE_UNKNOWN
, crBkgnd
, crText
);
1935 pDC
->FillSolidRect(rc
, crBkgnd
);
1939 int viewLine
= GetViewLineForScreen(nLineIndex
);
1940 if (m_pMainFrame
->m_bCollapsed
)
1942 if (m_pViewData
->GetHideState(viewLine
) == HIDESTATE_MARKER
)
1944 COLORREF crBkgnd
, crText
;
1945 CDiffColors::GetInstance().GetColors(DIFFSTATE_UNKNOWN
, crBkgnd
, crText
);
1946 pDC
->FillSolidRect(rc
, crBkgnd
);
1948 const int THICKNESS
= 2;
1949 COLORREF rectcol
= GetSysColor(COLOR_WINDOWTEXT
);
1950 pDC
->FillSolidRect(rc
.left
, rc
.top
+ (rc
.Height()/2), rc
.Width(), THICKNESS
, rectcol
);
1951 pDC
->SetTextColor(GetSysColor(COLOR_GRAYTEXT
));
1952 pDC
->SetBkColor(crBkgnd
);
1954 pDC
->DrawText(_T("{...}"), &rect
, DT_NOPREFIX
|DT_SINGLELINE
|DT_CENTER
);
1959 DiffStates diffState
= m_pViewData
->GetState(viewLine
);
1960 COLORREF crBkgnd
, crText
;
1961 CDiffColors::GetInstance().GetColors(diffState
, crBkgnd
, crText
);
1963 if (diffState
== DIFFSTATE_CONFLICTED
)
1965 // conflicted lines are shown without 'text' on them
1967 pDC
->FillSolidRect(rc
, crBkgnd
);
1968 // now draw some faint text patterns
1969 pDC
->SetTextColor(CAppUtils::IntenseColor(130, crBkgnd
));
1970 pDC
->DrawText(m_sConflictedText
, rect
, DT_LEFT
|DT_NOPREFIX
|DT_SINGLELINE
);
1971 DrawBlockLine(pDC
, rc
, nLineIndex
);
1975 CPoint
origin(rc
.left
- m_nOffsetChar
* GetCharWidth(), rc
.top
);
1976 CString sLine
= GetLineChars(nLineIndex
);
1977 if (sLine
.IsEmpty())
1979 pDC
->FillSolidRect(rc
, crBkgnd
);
1980 DrawBlockLine(pDC
, rc
, nLineIndex
);
1981 DrawLineEnding(pDC
, rc
, nLineIndex
, origin
);
1989 pDC
->SelectObject(GetFont(FALSE
, FALSE
));
1991 DrawTextLine(pDC
, rc
, nLineIndex
, origin
);
1993 // draw white space after the end of line
1995 if (origin
.x
> frect
.left
)
1996 frect
.left
= origin
.x
;
1997 if (frect
.right
> frect
.left
)
1998 pDC
->FillSolidRect(frect
, crBkgnd
);
2000 // draw the whitespace chars
2001 LPCTSTR pszChars
= (LPCWSTR
)sLine
;
2002 if (m_bViewWhitespace
)
2006 LPCTSTR pLastSpace
= pszChars
;
2007 int y
= rc
.top
+ (rc
.bottom
-rc
.top
)/2;
2008 xpos
-= m_nOffsetChar
* GetCharWidth();
2010 CPen
pen(PS_SOLID
, 0, m_WhiteSpaceFg
);
2011 CPen
pen2(PS_SOLID
, 2, m_WhiteSpaceFg
);
2018 xpos
+= pDC
->GetTextExtent(pLastSpace
, (int)(pszChars
- pLastSpace
)).cx
;
2019 pLastSpace
= pszChars
+ 1;
2021 int nSpaces
= GetTabSize() - nChars
% GetTabSize();
2022 if (xpos
+ nSpaces
* GetCharWidth() > 0)
2024 int xposreal
= max(xpos
, 0);
2025 if ((xposreal
> 0) || (nSpaces
> 0))
2027 CPen
* oldPen
= pDC
->SelectObject(&pen
);
2028 pDC
->MoveTo(xposreal
+ rc
.left
, y
);
2029 pDC
->LineTo((xpos
+ nSpaces
* GetCharWidth()) + rc
.left
- 2, y
);
2030 pDC
->LineTo((xpos
+ nSpaces
* GetCharWidth()) + rc
.left
- 6, y
- 4);
2031 pDC
->MoveTo((xpos
+ nSpaces
* GetCharWidth()) + rc
.left
- 2, y
);
2032 pDC
->LineTo((xpos
+ nSpaces
* GetCharWidth()) + rc
.left
- 6, y
+ 4);
2033 pDC
->SelectObject(oldPen
);
2036 xpos
+= nSpaces
* GetCharWidth();
2042 xpos
+= pDC
->GetTextExtent(pLastSpace
, (int)(pszChars
- pLastSpace
)).cx
;
2043 pLastSpace
= pszChars
+ 1;
2047 CPen
* oldPen
= pDC
->SelectObject(&pen2
);
2048 pDC
->MoveTo(xpos
+ rc
.left
+ GetCharWidth()/2-1, y
);
2049 pDC
->LineTo(xpos
+ rc
.left
+ GetCharWidth()/2+1, y
);
2050 pDC
->SelectObject(oldPen
);
2052 xpos
+= GetCharWidth();
2063 DrawBlockLine(pDC
, rc
, nLineIndex
);
2064 if (origin
.x
>= rc
.left
)
2065 DrawLineEnding(pDC
, rc
, nLineIndex
, origin
);
2068 void CBaseView::ExpandChars(const CString
&sLine
, int nOffset
, int nCount
, CString
&line
)
2076 int nTabSize
= GetTabSize();
2078 int nActualOffset
= CountExpandedChars(sLine
, nOffset
);
2080 LPCTSTR pszChars
= (LPCWSTR
)sLine
;
2081 pszChars
+= nOffset
;
2082 int nLength
= nCount
;
2085 for (int i
=0; i
<nLength
; i
++)
2087 if (pszChars
[i
] == _T('\t'))
2091 LPTSTR pszBuf
= line
.GetBuffer(nLength
+ nTabCount
* (nTabSize
- 1) + 1);
2093 if (nTabCount
> 0 || m_bViewWhitespace
)
2095 for (int i
=0; i
<nLength
; i
++)
2097 if (pszChars
[i
] == _T('\t'))
2099 int nSpaces
= nTabSize
- (nActualOffset
+ nCurPos
) % nTabSize
;
2102 pszBuf
[nCurPos
++] = _T(' ');
2108 pszBuf
[nCurPos
] = pszChars
[i
];
2115 memcpy(pszBuf
, pszChars
, sizeof(TCHAR
) * nLength
);
2118 pszBuf
[nCurPos
] = 0;
2119 line
.ReleaseBuffer();
2122 CString
CBaseView::ExpandChars(const CString
&sLine
, int nOffset
)
2125 int nLength
= sLine
.GetLength();
2126 ExpandChars(sLine
, nOffset
, nLength
, sRet
);
2130 int CBaseView::CountExpandedChars(const CString
&sLine
, int nLength
)
2132 int nTabSize
= GetTabSize();
2134 int nActualOffset
= 0;
2135 for (int i
=0; i
<nLength
; i
++)
2137 if (sLine
[i
] == _T('\t'))
2138 nActualOffset
+= (nTabSize
- nActualOffset
% nTabSize
);
2142 return nActualOffset
;
2145 void CBaseView::ScrollAllToLine(int nNewTopLine
, BOOL bTrackScrollBar
)
2148 m_pwndLeft
->ScrollToLine(nNewTopLine
, bTrackScrollBar
);
2150 m_pwndRight
->ScrollToLine(nNewTopLine
, bTrackScrollBar
);
2152 m_pwndBottom
->ScrollToLine(nNewTopLine
, bTrackScrollBar
);
2154 m_pwndLocator
->Invalidate();
2157 void CBaseView::GoToLine(int nNewLine
, BOOL bAll
)
2159 //almost the same as ScrollAllToLine, but try to put the line in the
2160 //middle of the view, not on top
2161 int nNewTopLine
= nNewLine
- GetScreenLines()/2;
2162 if (nNewTopLine
< 0)
2164 if (nNewTopLine
>= (int)m_Screen2View
.size())
2165 nNewTopLine
= (int)m_Screen2View
.size()-1;
2167 ScrollAllToLine(nNewTopLine
);
2169 ScrollToLine(nNewTopLine
);
2172 BOOL
CBaseView::OnEraseBkgnd(CDC
* /*pDC*/)
2177 int CBaseView::OnCreate(LPCREATESTRUCT lpCreateStruct
)
2179 if (CView::OnCreate(lpCreateStruct
) == -1)
2182 SecureZeroMemory(&m_lfBaseFont
, sizeof(m_lfBaseFont
));
2183 //lstrcpy(m_lfBaseFont.lfFaceName, _T("Courier New"));
2184 //lstrcpy(m_lfBaseFont.lfFaceName, _T("FixedSys"));
2185 m_lfBaseFont
.lfHeight
= 0;
2186 m_lfBaseFont
.lfWeight
= FW_NORMAL
;
2187 m_lfBaseFont
.lfItalic
= FALSE
;
2188 m_lfBaseFont
.lfCharSet
= DEFAULT_CHARSET
;
2189 m_lfBaseFont
.lfOutPrecision
= OUT_DEFAULT_PRECIS
;
2190 m_lfBaseFont
.lfClipPrecision
= CLIP_DEFAULT_PRECIS
;
2191 m_lfBaseFont
.lfQuality
= DEFAULT_QUALITY
;
2192 m_lfBaseFont
.lfPitchAndFamily
= DEFAULT_PITCH
;
2197 void CBaseView::OnDestroy()
2199 if ((m_pFindDialog
)&&(!m_pFindDialog
->IsTerminating()))
2201 m_pFindDialog
->SendMessage(WM_CLOSE
);
2209 void CBaseView::OnSize(UINT nType
, int cx
, int cy
)
2211 CView::OnSize(nType
, cx
, cy
);
2214 m_nScreenLines
= -1;
2215 m_nScreenChars
= -1;
2216 if (m_nLastScreenChars
!= GetScreenChars())
2218 BuildAllScreen2ViewVector();
2219 m_nLastScreenChars
= m_nScreenChars
;
2220 if (m_pMainFrame
&& m_pMainFrame
->m_bWrapLines
)
2222 // if we're in wrap mode, the line wrapping most likely changed
2223 // and that means we have to redraw the whole window, not just the
2229 // make sure the view header is redrawn
2231 GetClientRect(&rcScroll
);
2232 rcScroll
.bottom
= GetLineHeight()+HEADERHEIGHT
;
2233 InvalidateRect(&rcScroll
, FALSE
);
2238 // make sure the view header is redrawn
2240 GetClientRect(&rcScroll
);
2241 rcScroll
.bottom
= GetLineHeight()+HEADERHEIGHT
;
2242 InvalidateRect(&rcScroll
, FALSE
);
2245 RecalcVertScrollBar();
2246 RecalcHorzScrollBar();
2251 BOOL
CBaseView::OnMouseWheel(UINT nFlags
, short zDelta
, CPoint pt
)
2254 m_pwndLeft
->OnDoMouseWheel(nFlags
, zDelta
, pt
);
2256 m_pwndRight
->OnDoMouseWheel(nFlags
, zDelta
, pt
);
2258 m_pwndBottom
->OnDoMouseWheel(nFlags
, zDelta
, pt
);
2260 m_pwndLocator
->Invalidate();
2261 return CView::OnMouseWheel(nFlags
, zDelta
, pt
);
2264 void CBaseView::OnMouseHWheel(UINT nFlags
, short zDelta
, CPoint pt
)
2267 m_pwndLeft
->OnDoMouseHWheel(nFlags
, zDelta
, pt
);
2269 m_pwndRight
->OnDoMouseHWheel(nFlags
, zDelta
, pt
);
2271 m_pwndBottom
->OnDoMouseHWheel(nFlags
, zDelta
, pt
);
2273 m_pwndLocator
->Invalidate();
2276 void CBaseView::OnDoMouseWheel(UINT
/*nFlags*/, short zDelta
, CPoint
/*pt*/)
2278 bool bControl
= !!(GetKeyState(VK_CONTROL
)&0x8000);
2279 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
2281 if (bControl
|| bShift
)
2283 if (m_pMainFrame
->m_bWrapLines
)
2285 // Ctrl-Wheel scrolls sideways
2286 ScrollSide(-zDelta
/30);
2290 ScrollVertical(zDelta
);
2294 void CBaseView::OnDoMouseHWheel(UINT
/*nFlags*/, short zDelta
, CPoint
/*pt*/)
2296 bool bControl
= !!(GetKeyState(VK_CONTROL
)&0x8000);
2297 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
2299 if (bControl
|| bShift
)
2301 ScrollVertical(zDelta
);
2305 if (m_pMainFrame
->m_bWrapLines
)
2307 // Ctrl-Wheel scrolls sideways
2308 ScrollSide(-zDelta
/30);
2312 BOOL
CBaseView::OnSetCursor(CWnd
* pWnd
, UINT nHitTest
, UINT message
)
2314 if (nHitTest
== HTCLIENT
)
2316 if ((m_pViewData
)&&(m_pMainFrame
->m_bCollapsed
))
2318 if (m_nMouseLine
< (int)m_Screen2View
.size())
2320 if (m_nMouseLine
>= 0)
2322 int viewLine
= GetViewLineForScreen(m_nMouseLine
);
2323 if (viewLine
< m_pViewData
->GetCount())
2325 if (m_pViewData
->GetHideState(viewLine
) == HIDESTATE_MARKER
)
2327 ::SetCursor(::LoadCursor(NULL
, IDC_HAND
));
2334 if (m_mouseInMargin
)
2336 ::SetCursor(m_margincursor
);
2339 if (m_nMouseLine
>= 0)
2341 ::SetCursor(::LoadCursor(NULL
, IDC_IBEAM
)); // Set To Edit Cursor
2345 ::SetCursor(::LoadCursor(NULL
, IDC_ARROW
)); // Set To Arrow Cursor
2348 return CView::OnSetCursor(pWnd
, nHitTest
, message
);
2351 void CBaseView::OnKillFocus(CWnd
* pNewWnd
)
2353 CView::OnKillFocus(pNewWnd
);
2359 void CBaseView::OnSetFocus(CWnd
* pOldWnd
)
2361 CView::OnSetFocus(pOldWnd
);
2367 int CBaseView::GetLineFromPoint(CPoint point
)
2369 ScreenToClient(&point
);
2370 return (((point
.y
- HEADERHEIGHT
) / GetLineHeight()) + m_nTopLine
);
2373 void CBaseView::OnContextMenu(CPoint point
, DiffStates state
)
2375 if (!this->IsWindowVisible())
2379 if (!popup
.CreatePopupMenu())
2382 AddContextItems(popup
, state
);
2386 int nEncodingCommandBase
= POPUPCOMMAND__LAST
;
2387 int nEolCommandBase
= nEncodingCommandBase
+_countof(uctArray
);
2391 TWhitecharsProperties oWhites
= GetWhitecharsProperties();
2392 temp
.LoadString(IDS_EDIT_TAB2SPACE
);
2393 popup
.AppendMenu((MF_STRING
| oWhites
.HasTabsToConvert
) ? MF_ENABLED
: (MF_DISABLED
|MF_GRAYED
), POPUPCOMMAND_TABTOSPACES
, temp
);
2394 temp
.LoadString(IDS_EDIT_SPACE2TAB
);
2395 popup
.AppendMenu((MF_STRING
| oWhites
.HasSpacesToConvert
) ? MF_ENABLED
: (MF_DISABLED
|MF_GRAYED
), POPUPCOMMAND_SPACESTOTABS
, temp
);
2396 temp
.LoadString(IDS_EDIT_TRIM
);
2397 popup
.AppendMenu((MF_STRING
| oWhites
.HasTrailWhiteChars
) ? MF_ENABLED
: (MF_DISABLED
|MF_GRAYED
), POPUPCOMMAND_REMOVETRAILWHITES
, temp
);
2400 if (!popupEols
.CreatePopupMenu())
2403 EOL eEolType
= GetLineEndings(oWhites
.HasMixedEols
);
2404 for (int i
= 1; i
< _countof(eolArray
); i
++)
2406 temp
= GetEolName(eolArray
[i
]);
2407 bool bChecked
= (eEolType
== eolArray
[i
]);
2408 popupEols
.AppendMenu(MF_STRING
| MF_ENABLED
| (bChecked
? MF_CHECKED
: 0), nEolCommandBase
+i
, temp
);
2411 temp
.LoadString(IDS_VIEWCONTEXTMENU_EOL
);
2412 popup
.AppendMenuW(MF_POPUP
| MF_ENABLED
, (UINT_PTR
)popupEols
.GetSafeHmenu(), temp
);
2414 // add encoding submenu
2415 if (!popupUnicode
.CreatePopupMenu())
2417 for (int i
= 0; i
< _countof(uctArray
); i
++)
2419 temp
= CFileTextLines::GetEncodingName(uctArray
[i
]);
2420 bool bChecked
= (m_texttype
== uctArray
[i
]);
2421 popupUnicode
.AppendMenu(MF_STRING
| MF_ENABLED
| (bChecked
? MF_CHECKED
: 0), nEncodingCommandBase
+i
, temp
);
2423 temp
.LoadString(IDS_VIEWCONTEXTMENU_ENCODING
);
2424 popup
.AppendMenuW(MF_POPUP
| MF_ENABLED
, (UINT_PTR
)popupUnicode
.GetSafeHmenu(), temp
);
2428 CompensateForKeyboard(point
);
2430 int cmd
= popup
.TrackPopupMenu(TPM_RETURNCMD
| TPM_LEFTALIGN
| TPM_NONOTIFY
| TPM_RIGHTBUTTON
, point
.x
, point
.y
, this, 0);
2432 if ((cmd
>=nEncodingCommandBase
) && (cmd
<nEncodingCommandBase
+(int)_countof(uctArray
)))
2434 SetTextType(uctArray
[cmd
-nEncodingCommandBase
]);
2436 if ((cmd
>=nEolCommandBase
) && (cmd
<nEolCommandBase
+(int)_countof(eolArray
)))
2438 ReplaceLineEndings(eolArray
[cmd
-nEolCommandBase
]);
2443 // 2-pane view commands; target is right view
2444 case POPUPCOMMAND_USELEFTBLOCK
:
2445 m_pwndRight
->UseLeftBlock();
2447 case POPUPCOMMAND_USELEFTFILE
:
2448 m_pwndRight
->UseLeftFile();
2450 case POPUPCOMMAND_USEBOTHLEFTFIRST
:
2451 m_pwndRight
->UseBothLeftFirst();
2453 case POPUPCOMMAND_USEBOTHRIGHTFIRST
:
2454 m_pwndRight
->UseBothRightFirst();
2456 case POPUPCOMMAND_MARKBLOCK
:
2457 m_pwndRight
->MarkBlock(true);
2459 case POPUPCOMMAND_UNMARKBLOCK
:
2460 m_pwndRight
->MarkBlock(false);
2462 case POPUPCOMMAND_LEAVEONLYMARKEDBLOCKS
:
2463 m_pwndRight
->LeaveOnlyMarkedBlocks();
2465 // 2-pane view multiedit commands; target is left view
2466 case POPUPCOMMAND_PREPENDFROMRIGHT
:
2467 if (!m_pwndLeft
->IsReadonly())
2468 m_pwndLeft
->UseBothRightFirst();
2470 case POPUPCOMMAND_REPLACEBYRIGHT
:
2471 if (!m_pwndLeft
->IsReadonly())
2472 m_pwndLeft
->UseRightBlock();
2474 case POPUPCOMMAND_APPENDFROMRIGHT
:
2475 if (!m_pwndLeft
->IsReadonly())
2476 m_pwndLeft
->UseBothLeftFirst();
2478 case POPUPCOMMAND_USERIGHTFILE
:
2479 m_pwndLeft
->UseRightFile();
2481 // 3-pane view commands; target is bottom view
2482 case POPUPCOMMAND_USEYOURANDTHEIRBLOCK
:
2483 m_pwndBottom
->UseBothRightFirst();
2485 case POPUPCOMMAND_USETHEIRANDYOURBLOCK
:
2486 m_pwndBottom
->UseBothLeftFirst();
2488 case POPUPCOMMAND_USEYOURBLOCK
:
2489 m_pwndBottom
->UseRightBlock();
2491 case POPUPCOMMAND_USEYOURFILE
:
2492 m_pwndBottom
->UseRightFile();
2494 case POPUPCOMMAND_USETHEIRBLOCK
:
2495 m_pwndBottom
->UseLeftBlock();
2497 case POPUPCOMMAND_USETHEIRFILE
:
2498 m_pwndBottom
->UseLeftFile();
2500 // copy, cut and paste commands
2510 // white chars manipulations
2511 case POPUPCOMMAND_TABTOSPACES
:
2512 ConvertTabToSpaces();
2514 case POPUPCOMMAND_SPACESTOTABS
:
2517 case POPUPCOMMAND_REMOVETRAILWHITES
:
2518 RemoveTrailWhiteChars();
2523 SaveUndoStep(); // all except copy, cut paste save undo step, but this should not be harmful as step is empty already and thus not saved
2527 void CBaseView::OnContextMenu(CWnd
* /*pWnd*/, CPoint point
)
2532 int nViewBlockStart
= -1;
2533 int nViewBlockEnd
= -1;
2534 GetViewSelection(nViewBlockStart
, nViewBlockEnd
);
2535 if ((point
.x
>= 0) && (point
.y
>= 0))
2537 int nLine
= GetLineFromPoint(point
)-1;
2538 if ((nLine
>= 0) && (nLine
< m_Screen2View
.size()))
2540 int nViewLine
= GetViewLineForScreen(nLine
);
2541 if (((nViewLine
< nViewBlockStart
) || (nViewBlockEnd
< nViewLine
)))
2543 ClearSelection(); // Clear text-copy selection
2545 nViewBlockStart
= nViewLine
;
2546 nViewBlockEnd
= nViewLine
;
2547 DiffStates state
= m_pViewData
->GetState(nViewLine
);
2548 while (nViewBlockStart
> 0)
2550 const DiffStates lineState
= m_pViewData
->GetState(nViewBlockStart
-1);
2551 if (!LinesInOneChange(-1, state
, lineState
))
2556 while (nViewBlockEnd
< (m_pViewData
->GetCount()-1))
2558 const DiffStates lineState
= m_pViewData
->GetState(nViewBlockEnd
+1);
2559 if (!LinesInOneChange(1, state
, lineState
))
2564 SetupAllViewSelection(nViewBlockStart
, nViewBlockEnd
);
2565 UpdateCaretPosition(point
);
2570 // FixSelection(); fix selection range
2571 /*if (m_nSelBlockEnd >= m_pViewData->GetCount())
2572 m_nSelBlockEnd = m_pViewData->GetCount()-1;//*/
2574 DiffStates state
= DIFFSTATE_UNKNOWN
;
2575 if (GetViewSelection(nViewBlockStart
, nViewBlockEnd
))
2577 // find a more 'relevant' state in the selection
2578 for (int i
=nViewBlockStart
; i
<=nViewBlockEnd
; ++i
)
2580 state
= m_pViewData
->GetState(i
);
2581 if ((state
!= DIFFSTATE_NORMAL
) && (state
!= DIFFSTATE_UNKNOWN
))
2585 OnContextMenu(point
, state
);
2588 void CBaseView::RefreshViews()
2592 m_pwndLeft
->UpdateStatusBar();
2593 m_pwndLeft
->Invalidate();
2597 m_pwndRight
->UpdateStatusBar();
2598 m_pwndRight
->Invalidate();
2602 m_pwndBottom
->UpdateStatusBar();
2603 m_pwndBottom
->Invalidate();
2606 m_pwndLocator
->Invalidate();
2609 void CBaseView::GoToFirstDifference()
2611 SetCaretToFirstViewLine();
2612 SelectNextBlock(1, false, false);
2615 void CBaseView::GoToFirstConflict()
2617 SetCaretToFirstViewLine();
2618 SelectNextBlock(1, true, false);
2621 void CBaseView::HighlightLines(int nStart
, int nEnd
/* = -1 */)
2624 SetupAllSelection(nStart
, max(nStart
, nEnd
));
2626 UpdateCaretPosition(SetupPoint(0, nStart
));
2630 void CBaseView::HighlightViewLines(int nStart
, int nEnd
/* = -1 */)
2633 SetupAllViewSelection(nStart
, max(nStart
, nEnd
));
2635 UpdateCaretViewPosition(SetupPoint(0, nStart
));
2639 void CBaseView::SetupAllViewSelection(int start
, int end
)
2641 SetupViewSelection(m_pwndBottom
, start
, end
);
2642 SetupViewSelection(m_pwndLeft
, start
, end
);
2643 SetupViewSelection(m_pwndRight
, start
, end
);
2646 void CBaseView::SetupAllSelection(int start
, int end
)
2648 SetupAllViewSelection(GetViewLineForScreen(start
), GetViewLineForScreen(end
));
2651 //void CBaseView::SetupSelection(CBaseView* view, int start, int end) { }
2653 void CBaseView::SetupSelection(int start
, int end
)
2655 SetupViewSelection(GetViewLineForScreen(start
), GetViewLineForScreen(end
));
2658 void CBaseView::SetupViewSelection(CBaseView
* view
, int start
, int end
)
2660 if (!IsViewGood(view
))
2662 view
->SetupViewSelection(start
, end
);
2665 void CBaseView::SetupViewSelection(int start
, int end
)
2667 // clear text selection before setting line selection ?
2668 m_nSelViewBlockStart
= start
;
2669 m_nSelViewBlockEnd
= end
;
2674 void CBaseView::OnMergePreviousconflict()
2676 SelectNextBlock(-1, true);
2679 void CBaseView::OnMergeNextconflict()
2681 SelectNextBlock(1, true);
2684 void CBaseView::OnMergeNextdifference()
2686 SelectNextBlock(1, false);
2689 void CBaseView::OnMergePreviousdifference()
2691 SelectNextBlock(-1, false);
2694 bool CBaseView::HasNextConflict()
2696 return SelectNextBlock(1, true, true, true);
2699 bool CBaseView::HasPrevConflict()
2701 return SelectNextBlock(-1, true, true, true);
2704 bool CBaseView::HasNextDiff()
2706 return SelectNextBlock(1, false, true, true);
2709 bool CBaseView::HasPrevDiff()
2711 return SelectNextBlock(-1, false, true, true);
2714 bool CBaseView::LinesInOneChange(int direction
,
2715 DiffStates initialLineState
, DiffStates currentLineState
)
2717 // Checks whether all the adjacent lines starting from the initial line
2718 // and up to the current line form the single change
2720 // First of all, if the two lines have identical states, they surely
2721 // belong to one change.
2722 if (initialLineState
== currentLineState
)
2725 // Either we move down and initial line state is "added" or "removed" and
2726 // current line state is "empty"...
2729 if (currentLineState
== DIFFSTATE_EMPTY
)
2731 if (initialLineState
== DIFFSTATE_ADDED
|| initialLineState
== DIFFSTATE_REMOVED
)
2734 if (initialLineState
== DIFFSTATE_CONFLICTADDED
&& currentLineState
== DIFFSTATE_CONFLICTEMPTY
)
2737 // ...or we move up and initial line state is "empty" and current line
2738 // state is "added" or "removed".
2741 if (initialLineState
== DIFFSTATE_EMPTY
)
2743 if (currentLineState
== DIFFSTATE_ADDED
|| currentLineState
== DIFFSTATE_REMOVED
)
2746 if (initialLineState
== DIFFSTATE_CONFLICTEMPTY
&& currentLineState
== DIFFSTATE_CONFLICTADDED
)
2752 bool CBaseView::SelectNextBlock(int nDirection
, bool bConflict
, bool bSkipEndOfCurrentBlock
/* = true */, bool dryrun
/* = false */)
2757 const int linesCount
= (int)m_Screen2View
.size();
2761 int nCenterPos
= GetCaretPosition().y
;
2764 nLimit
= linesCount
;
2766 if (nCenterPos
>= linesCount
)
2767 nCenterPos
= linesCount
-1;
2769 if (bSkipEndOfCurrentBlock
)
2771 // Find end of current block
2772 const DiffStates state
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2773 while (nCenterPos
!= nLimit
)
2775 const DiffStates lineState
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2776 if (!LinesInOneChange(nDirection
, state
, lineState
))
2778 nCenterPos
+= nDirection
;
2782 // Find next diff/conflict block
2783 while (nCenterPos
!= nLimit
)
2785 DiffStates linestate
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2787 (linestate
!= DIFFSTATE_NORMAL
) &&
2788 (linestate
!= DIFFSTATE_UNKNOWN
))
2793 ((linestate
== DIFFSTATE_CONFLICTADDED
) ||
2794 (linestate
== DIFFSTATE_CONFLICTED_IGNORED
) ||
2795 (linestate
== DIFFSTATE_CONFLICTED
) ||
2796 (linestate
== DIFFSTATE_CONFLICTEMPTY
)))
2801 nCenterPos
+= nDirection
;
2803 if (nCenterPos
== nLimit
)
2806 return (nCenterPos
!= nLimit
);
2808 // Find end of new block
2809 DiffStates state
= m_pViewData
->GetState(GetViewLineForScreen(nCenterPos
));
2810 int nBlockEnd
= nCenterPos
;
2811 const int maxAllowedLine
= nLimit
-nDirection
;
2812 while (nBlockEnd
!= maxAllowedLine
)
2814 const int lineIndex
= nBlockEnd
+ nDirection
;
2815 if (lineIndex
>= linesCount
)
2817 DiffStates lineState
= m_pViewData
->GetState(GetViewLineForScreen(lineIndex
));
2818 if (!LinesInOneChange(nDirection
, state
, lineState
))
2820 nBlockEnd
+= nDirection
;
2823 int nTopPos
= nCenterPos
- (GetScreenLines()/2);
2827 POINT ptCaretPos
= {0, nCenterPos
};
2828 SetCaretPosition(ptCaretPos
);
2831 SetupAllSelection(nCenterPos
, nBlockEnd
);
2833 SetupAllSelection(nBlockEnd
, nCenterPos
);
2835 ScrollAllToLine(nTopPos
, FALSE
);
2836 RecalcAllVertScrollBars(TRUE
);
2837 SetCaretToLineStart();
2838 EnsureCaretVisible();
2839 OnNavigateNextinlinediff();
2841 UpdateViewsCaretPosition();
2843 ShowDiffLines(nCenterPos
);
2847 BOOL
CBaseView::OnToolTipNotify(UINT
/*id*/, NMHDR
*pNMHDR
, LRESULT
*pResult
)
2849 if (pNMHDR
->idFrom
!= (UINT_PTR
)m_hWnd
)
2853 strTipText
= m_sWindowName
+ _T("\r\n") + m_sFullFilePath
;
2855 DWORD pos
= GetMessagePos();
2856 CPoint
point(GET_X_LPARAM(pos
), GET_Y_LPARAM(pos
));
2857 ScreenToClient(&point
);
2858 const int nLine
= GetButtonEventLineIndex(point
);
2862 int nViewLine
= GetViewLineForScreen(nLine
);
2863 if((m_pViewData
)&&(nViewLine
< m_pViewData
->GetCount()))
2865 auto movedIndex
= m_pViewData
->GetMovedIndex(nViewLine
);
2866 if (movedIndex
>= 0)
2868 if (m_pViewData
->IsMovedFrom(nViewLine
))
2870 strTipText
.Format(IDS_MOVED_TO_TT
, movedIndex
+1);
2874 strTipText
.Format(IDS_MOVED_FROM_TT
, movedIndex
+1);
2882 if (strTipText
.IsEmpty())
2885 // need to handle both ANSI and UNICODE versions of the message
2886 if (pNMHDR
->code
== TTN_NEEDTEXTA
)
2888 TOOLTIPTEXTA
* pTTTA
= (TOOLTIPTEXTA
*)pNMHDR
;
2889 pTTTA
->lpszText
= m_szTip
;
2890 WideCharToMultiByte(CP_ACP
, 0, strTipText
, -1, m_szTip
, strTipText
.GetLength()+1, 0, 0);
2894 TOOLTIPTEXTW
* pTTTW
= (TOOLTIPTEXTW
*)pNMHDR
;
2895 lstrcpyn(m_wszTip
, strTipText
, min(strTipText
.GetLength() + 1, _countof(m_wszTip
) - 1));
2896 pTTTW
->lpszText
= m_wszTip
;
2899 return TRUE
; // message was handled
2902 INT_PTR
CBaseView::OnToolHitTest(CPoint point
, TOOLINFO
* pTI
) const
2905 GetClientRect(rcClient
);
2906 CRect
textrect(rcClient
.left
, rcClient
.top
, rcClient
.Width(), m_nLineHeight
+HEADERHEIGHT
);
2907 int marginwidth
= MARGINWIDTH
;
2908 if ((m_bViewLinenumbers
)&&(m_pViewData
)&&(m_pViewData
->GetCount())&&(m_nDigits
> 0))
2910 marginwidth
= (MARGINWIDTH
+ (m_nDigits
* m_nCharWidth
) + 2);
2912 CRect
borderrect(rcClient
.left
, rcClient
.top
+m_nLineHeight
+HEADERHEIGHT
, marginwidth
, rcClient
.bottom
);
2914 if (textrect
.PtInRect(point
) || borderrect
.PtInRect(point
))
2916 // inside the header part of the view (showing the filename)
2917 pTI
->hwnd
= this->m_hWnd
;
2918 this->GetClientRect(&pTI
->rect
);
2919 pTI
->uFlags
|= TTF_ALWAYSTIP
| TTF_IDISHWND
;
2920 pTI
->uId
= (UINT_PTR
)m_hWnd
;
2921 pTI
->lpszText
= LPSTR_TEXTCALLBACK
;
2923 // we want multi line tooltips
2924 CToolTipCtrl
* pToolTip
= AfxGetModuleThreadState()->m_pToolTip
;
2925 if (pToolTip
->GetSafeHwnd() != NULL
)
2927 pToolTip
->SetMaxTipWidth(INT_MAX
);
2930 return (textrect
.PtInRect(point
) ? 1 : 2);
2936 void CBaseView::OnKeyDown(UINT nChar
, UINT nRepCnt
, UINT nFlags
)
2938 bool bControl
= !!(GetKeyState(VK_CONTROL
)&0x8000);
2939 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
2946 if (this==m_pwndLeft
)
2948 if (IsViewGood(m_pwndRight
))
2950 m_pwndRight
->SetFocus();
2952 else if (IsViewGood(m_pwndBottom
))
2954 m_pwndBottom
->SetFocus();
2957 else if (this==m_pwndRight
)
2959 if (IsViewGood(m_pwndBottom
))
2961 m_pwndBottom
->SetFocus();
2963 else if (IsViewGood(m_pwndLeft
))
2965 m_pwndLeft
->SetFocus();
2968 else if (this==m_pwndBottom
)
2970 if (IsViewGood(m_pwndLeft
))
2972 m_pwndLeft
->SetFocus();
2974 else if (IsViewGood(m_pwndRight
))
2976 m_pwndRight
->SetFocus();
2983 POINT ptCaretPos
= GetCaretPosition();
2984 ptCaretPos
.y
-= GetScreenLines();
2985 ptCaretPos
.y
= max(ptCaretPos
.y
, 0);
2986 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
2987 SetCaretPosition(ptCaretPos
);
2988 OnCaretMove(MOVELEFT
, bShift
);
2989 ShowDiffLines(ptCaretPos
.y
);
2994 POINT ptCaretPos
= GetCaretPosition();
2995 ptCaretPos
.y
+= GetScreenLines();
2996 if (ptCaretPos
.y
>= GetLineCount())
2997 ptCaretPos
.y
= GetLineCount()-1;
2998 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
2999 SetCaretPosition(ptCaretPos
);
3000 OnCaretMove(MOVERIGHT
, bShift
);
3001 ShowDiffLines(ptCaretPos
.y
);
3009 SetCaretToViewStart();
3010 m_nCaretGoalPos
= 0;
3012 AdjustSelection(MOVELEFT
);
3019 POINT ptCaretPos
= GetCaretPosition();
3020 CString sLine
= GetLineChars(ptCaretPos
.y
);
3022 while (pos
< sLine
.GetLength())
3024 if (sLine
[pos
] != ' ' && sLine
[pos
] != '\t')
3028 if (ptCaretPos
.x
== pos
)
3030 SetCaretToLineStart();
3031 m_nCaretGoalPos
= 0;
3032 OnCaretMove(MOVERIGHT
, bShift
);
3038 SetCaretAndGoalPosition(ptCaretPos
);
3039 OnCaretMove(MOVELEFT
, bShift
);
3048 ScrollAllToLine(GetLineCount()-GetAllMinScreenLines());
3050 ptCaretPos
.y
= GetLineCount()-1;
3051 ptCaretPos
.x
= GetLineLength(ptCaretPos
.y
);
3052 SetCaretAndGoalPosition(ptCaretPos
);
3054 AdjustSelection(MOVERIGHT
);
3060 POINT ptCaretPos
= GetCaretPosition();
3061 ptCaretPos
.x
= GetLineLength(ptCaretPos
.y
);
3062 if ((GetSubLineOffset(ptCaretPos
.y
) != -1) && (GetSubLineOffset(ptCaretPos
.y
) != CountMultiLines(GetViewLineForScreen(ptCaretPos
.y
))-1)) // not last screen line of view line
3066 SetCaretAndGoalPosition(ptCaretPos
);
3067 OnCaretMove(MOVERIGHT
, bShift
);
3074 if (! HasTextSelection())
3076 POINT ptCaretPos
= GetCaretPosition();
3077 if (ptCaretPos
.y
== 0 && ptCaretPos
.x
== 0)
3079 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
3081 MoveCaretWordLeft();
3084 while (MoveCaretLeft() && IsViewLineEmpty(GetCaretViewPosition().y
))
3088 m_ptSelectionViewPosStart
= GetCaretViewPosition();
3090 RemoveSelectedText();
3096 if (! HasTextSelection())
3100 m_ptSelectionViewPosStart
= GetCaretViewPosition();
3101 MoveCaretWordRight();
3102 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
3106 if (! MoveCaretRight())
3108 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
3110 m_ptSelectionViewPosStart
= GetCaretViewPosition();
3113 RemoveSelectedText();
3117 m_bInsertMode
= !m_bInsertMode
;
3121 CView::OnKeyDown(nChar
, nRepCnt
, nFlags
);
3124 void CBaseView::OnLButtonDown(UINT nFlags
, CPoint point
)
3126 const int nClickedLine
= GetButtonEventLineIndex(point
);
3127 if ((nClickedLine
>= m_nTopLine
)&&(nClickedLine
< GetLineCount()))
3130 ptCaretPos
.y
= nClickedLine
;
3131 int xpos2
= CalcColFromPoint(point
.x
, nClickedLine
);
3132 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, xpos2
);
3133 SetCaretAndGoalPosition(ptCaretPos
);
3135 if (nFlags
& MK_SHIFT
)
3136 AdjustSelection(MOVERIGHT
);
3140 SetupAllSelection(ptCaretPos
.y
, ptCaretPos
.y
);
3141 if (point
.x
< GetMarginWidth())
3143 // select the whole line
3144 m_ptSelectionViewPosStart
= m_ptSelectionViewPosEnd
= GetCaretViewPosition();
3145 m_ptSelectionViewPosEnd
.x
= GetViewLineLength(m_ptSelectionViewPosEnd
.y
);
3149 UpdateViewsCaretPosition();
3153 CView::OnLButtonDown(nFlags
, point
);
3156 CBaseView::ECharGroup
CBaseView::GetCharGroup(wchar_t zChar
) const
3158 if (zChar
== ' ' || zChar
== '\t' )
3160 return CHG_WHITESPACE
;
3166 if (m_sWordSeparators
.Find(zChar
) >= 0)
3168 return CHG_WORDSEPARATOR
;
3170 return CHG_WORDLETTER
;
3173 void CBaseView::OnLButtonDblClk(UINT nFlags
, CPoint point
)
3175 if (m_pViewData
== 0) {
3176 CView::OnLButtonDblClk(nFlags
, point
);
3180 const int nClickedLine
= GetButtonEventLineIndex(point
);
3181 if ( nClickedLine
< 0)
3183 int nViewLine
= GetViewLineForScreen(nClickedLine
);
3184 if (point
.x
< GetMarginWidth()) // only if double clicked on the margin
3186 if((nViewLine
< m_pViewData
->GetCount())) // a double click on moved line scrolls to corresponding line
3188 if (m_pViewData
->GetMovedIndex(nViewLine
)>=0)
3190 int movedindex
= m_pViewData
->GetMovedIndex(nViewLine
);
3191 int screenLine
= FindViewLineNumber(movedindex
);
3192 int nTop
= screenLine
- GetScreenLines()/2;
3195 ScrollAllToLine(nTop
);
3196 // find and select the whole moved block
3197 int startSel
= movedindex
;
3198 int endSel
= movedindex
;
3199 while ((startSel
> 0) && (m_pOtherViewData
->GetMovedIndex(startSel
) >= 0))
3202 while ((endSel
< GetLineCount()) && (m_pOtherViewData
->GetMovedIndex(endSel
) >= 0))
3205 m_pOtherView
->SetupSelection(startSel
, endSel
);
3206 return CView::OnLButtonDblClk(nFlags
, point
);
3210 if ((m_pMainFrame
->m_bCollapsed
)&&(m_pViewData
->GetHideState(nViewLine
) == HIDESTATE_MARKER
))
3212 // a double click on a marker expands the hidden text
3214 while ((i
< m_pViewData
->GetCount())&&(m_pViewData
->GetHideState(i
) != HIDESTATE_SHOWN
))
3216 if ((m_pwndLeft
)&&(m_pwndLeft
->m_pViewData
))
3217 m_pwndLeft
->m_pViewData
->SetLineHideState(i
, HIDESTATE_SHOWN
);
3218 if ((m_pwndRight
)&&(m_pwndRight
->m_pViewData
))
3219 m_pwndRight
->m_pViewData
->SetLineHideState(i
, HIDESTATE_SHOWN
);
3220 if ((m_pwndBottom
)&&(m_pwndBottom
->m_pViewData
))
3221 m_pwndBottom
->m_pViewData
->SetLineHideState(i
, HIDESTATE_SHOWN
);
3224 BuildAllScreen2ViewVector();
3226 m_pwndLeft
->Invalidate();
3228 m_pwndRight
->Invalidate();
3230 m_pwndBottom
->Invalidate();
3235 ptCaretPos
.y
= nClickedLine
;
3236 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth());
3237 SetCaretPosition(ptCaretPos
);
3240 POINT ptViewCarret
= GetCaretViewPosition();
3241 nViewLine
= ptViewCarret
.y
;
3242 if (nViewLine
>= GetViewCount())
3244 const CString
&sLine
= GetViewLine(nViewLine
);
3245 int nLineLength
= sLine
.GetLength();
3246 int nBasePos
= ptViewCarret
.x
;
3247 // get target char group
3248 ECharGroup eLeft
= CHG_UNKNOWN
;
3251 eLeft
= GetCharGroup(sLine
[nBasePos
-1]);
3253 ECharGroup eRight
= CHG_UNKNOWN
;
3254 if (nBasePos
< nLineLength
)
3256 eRight
= GetCharGroup(sLine
[nBasePos
]);
3258 ECharGroup eTarget
= max(eRight
, eLeft
);
3260 int nLeft
= nBasePos
;
3261 while (nLeft
> 0 && GetCharGroup(sLine
[nLeft
-1]) == eTarget
)
3266 int nRight
= nBasePos
;
3267 while (nRight
< nLineLength
&& GetCharGroup(sLine
[nRight
]) == eTarget
)
3272 m_ptSelectionViewPosStart
.x
= nLeft
;
3273 m_ptSelectionViewPosStart
.y
= nViewLine
;
3274 m_ptSelectionViewPosEnd
.x
= nRight
;
3275 m_ptSelectionViewPosEnd
.y
= nViewLine
;
3276 m_ptSelectionViewPosOrigin
= m_ptSelectionViewPosStart
;
3277 SetupAllViewSelection(nViewLine
, nViewLine
);
3279 ptCaretPos
= ConvertViewPosToScreen(m_ptSelectionViewPosEnd
);
3280 UpdateViewsCaretPosition();
3284 m_sPreviousMarkedWord
= m_sMarkedWord
; // store marked word to recall in case of triple click
3285 int nMarkWidth
= max(nRight
- nLeft
, 0);
3286 m_sMarkedWord
= sLine
.Mid(m_ptSelectionViewPosStart
.x
, nMarkWidth
).Trim();
3287 if (m_sMarkedWord
.Compare(m_sPreviousMarkedWord
) == 0)
3289 m_sMarkedWord
.Empty();
3293 m_pwndLeft
->SetMarkedWord(m_sMarkedWord
);
3295 m_pwndRight
->SetMarkedWord(m_sMarkedWord
);
3297 m_pwndBottom
->SetMarkedWord(m_sMarkedWord
);
3301 m_pwndLocator
->Invalidate();
3304 CView::OnLButtonDblClk(nFlags
, point
);
3307 void CBaseView::OnLButtonTrippleClick( UINT
/*nFlags*/, CPoint point
)
3309 const int nClickedLine
= GetButtonEventLineIndex(point
);
3310 if (((point
.y
- HEADERHEIGHT
) / GetLineHeight()) <= 0)
3312 if (!m_sConvertedFilePath
.IsEmpty() && (GetKeyState(VK_CONTROL
)&0x8000))
3314 PCIDLIST_ABSOLUTE __unaligned pidl
= ILCreateFromPath((LPCTSTR
)m_sConvertedFilePath
);
3317 SHOpenFolderAndSelectItems(pidl
,0,0,0);
3318 CoTaskMemFree((LPVOID
)pidl
);
3324 ptCaretPos
.y
= nClickedLine
;
3325 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth());
3326 SetCaretAndGoalPosition(ptCaretPos
);
3327 m_sMarkedWord
= m_sPreviousMarkedWord
; // recall previous Marked word
3329 m_pwndLeft
->SetMarkedWord(m_sMarkedWord
);
3331 m_pwndRight
->SetMarkedWord(m_sMarkedWord
);
3333 m_pwndBottom
->SetMarkedWord(m_sMarkedWord
);
3335 m_ptSelectionViewPosStart
.x
= 0;
3336 m_ptSelectionViewPosStart
.y
= nClickedLine
;
3337 m_ptSelectionViewPosEnd
.x
= GetLineLength(nClickedLine
);
3338 m_ptSelectionViewPosEnd
.y
= nClickedLine
;
3339 SetupSelection(m_ptSelectionViewPosStart
.y
, m_ptSelectionViewPosEnd
.y
);
3340 UpdateViewsCaretPosition();
3343 m_pwndLocator
->Invalidate();
3346 void CBaseView::OnEditCopy()
3348 CString sCopyData
= GetSelectedText();
3350 if (!sCopyData
.IsEmpty())
3352 CStringUtils::WriteAsciiStringToClipboard(sCopyData
, m_hWnd
);
3356 void CBaseView::OnMouseMove(UINT nFlags
, CPoint point
)
3358 if (m_pMainFrame
->m_nMoveMovesToIgnore
> 0)
3360 --m_pMainFrame
->m_nMoveMovesToIgnore
;
3361 CView::OnMouseMove(nFlags
, point
);
3364 int nMouseLine
= GetButtonEventLineIndex(point
);
3365 if (nMouseLine
< -1)
3367 m_mouseInMargin
= point
.x
< GetMarginWidth();
3369 ShowDiffLines(nMouseLine
);
3371 KillTimer(IDT_SCROLLTIMER
);
3372 if (nFlags
& MK_LBUTTON
)
3374 int saveMouseLine
= nMouseLine
>= 0 ? nMouseLine
: 0;
3375 saveMouseLine
= saveMouseLine
< GetLineCount() ? saveMouseLine
: GetLineCount() - 1;
3376 if (saveMouseLine
< 0)
3378 int col
= CalcColFromPoint(point
.x
, saveMouseLine
);
3379 int charIndex
= CalculateCharIndex(saveMouseLine
, col
);
3380 if (HasSelection() &&
3381 ((nMouseLine
>= m_nTopLine
)&&(nMouseLine
< GetLineCount())))
3383 POINT ptCaretPos
= {charIndex
, nMouseLine
};
3384 SetCaretAndGoalPosition(ptCaretPos
);
3385 AdjustSelection(MOVERIGHT
);
3389 if (nMouseLine
< m_nTopLine
)
3391 ScrollAllToLine(m_nTopLine
-1, TRUE
);
3392 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3394 if (nMouseLine
>= m_nTopLine
+ GetScreenLines() - 2)
3396 ScrollAllToLine(m_nTopLine
+1, TRUE
);
3397 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3399 if (!m_pMainFrame
->m_bWrapLines
&& ((m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth()) <= m_nOffsetChar
))
3402 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3404 if (!m_pMainFrame
->m_bWrapLines
&& (charIndex
>= (GetScreenChars()+m_nOffsetChar
-4)))
3407 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3413 CView::OnMouseMove(nFlags
, point
);
3416 void CBaseView::OnLButtonUp(UINT nFlags
, CPoint point
)
3420 KillTimer(IDT_SCROLLTIMER
);
3422 __super::OnLButtonUp(nFlags
, point
);
3425 void CBaseView::OnTimer(UINT_PTR nIDEvent
)
3427 if (nIDEvent
== IDT_SCROLLTIMER
)
3430 GetCursorPos(&point
);
3431 ScreenToClient(&point
);
3432 int nMouseLine
= GetButtonEventLineIndex(point
);
3433 if (nMouseLine
< -1)
3437 if (GetKeyState(VK_LBUTTON
)&0x8000)
3439 int saveMouseLine
= nMouseLine
>= 0 ? nMouseLine
: 0;
3440 saveMouseLine
= saveMouseLine
< GetLineCount() ? saveMouseLine
: GetLineCount() - 1;
3441 int charIndex
= CalculateCharIndex(saveMouseLine
, m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth());
3442 if (nMouseLine
< m_nTopLine
)
3444 ScrollAllToLine(m_nTopLine
-1, TRUE
);
3445 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3447 if (nMouseLine
>= m_nTopLine
+ GetScreenLines() - 2)
3449 ScrollAllToLine(m_nTopLine
+1, TRUE
);
3450 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3452 if (!m_pMainFrame
->m_bWrapLines
&& ((m_nOffsetChar
+ (point
.x
- GetMarginWidth()) / GetCharWidth()) <= m_nOffsetChar
))
3455 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3457 if (!m_pMainFrame
->m_bWrapLines
&& (charIndex
>= (GetScreenChars()+m_nOffsetChar
-4)))
3460 SetTimer(IDT_SCROLLTIMER
, 20, NULL
);
3466 CView::OnTimer(nIDEvent
);
3469 void CBaseView::ShowDiffLines(int nLine
)
3471 if ((nLine
< m_nTopLine
)||(nLine
>= GetLineCount()))
3473 m_pwndLineDiffBar
->ShowLines(nLine
);
3475 m_nMouseLine
= nLine
;
3479 if ((!m_pwndRight
)||(!m_pwndLeft
))
3481 if(m_pMainFrame
->m_bOneWay
)
3484 nLine
= (nLine
> (int)m_pwndRight
->m_Screen2View
.size() ? -1 : nLine
);
3485 nLine
= (nLine
> (int)m_pwndLeft
->m_Screen2View
.size() ? -1 : nLine
);
3490 if (nLine
!= m_nMouseLine
)
3492 if (nLine
>= GetLineCount())
3494 m_nMouseLine
= nLine
;
3495 m_pwndLineDiffBar
->ShowLines(nLine
);
3497 m_pMainFrame
->m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
3500 const viewdata
& CBaseView::GetEmptyLineData()
3502 static const viewdata
emptyLine(_T(""), DIFFSTATE_EMPTY
, -1, EOL_NOENDING
, HIDESTATE_SHOWN
);
3506 void CBaseView::InsertViewEmptyLines(int nFirstView
, int nCount
)
3508 for (int i
= 0; i
< nCount
; i
++)
3510 InsertViewData(nFirstView
, GetEmptyLineData());
3515 void CBaseView::UpdateCaret()
3517 POINT ptCaretPos
= GetCaretPosition();
3518 ptCaretPos
.y
= std::max
<int>(std::min
<int>(ptCaretPos
.y
, GetLineCount()-1), 0);
3519 ptCaretPos
.x
= std::max
<int>(std::min
<int>(ptCaretPos
.x
, GetLineLength(ptCaretPos
.y
)), 0);
3520 SetCaretPosition(ptCaretPos
);
3522 int nCaretOffset
= CalculateActualOffset(ptCaretPos
);
3525 ptCaretPos
.y
>= m_nTopLine
&&
3526 ptCaretPos
.y
< (m_nTopLine
+GetScreenLines()) &&
3527 nCaretOffset
>= m_nOffsetChar
&&
3528 nCaretOffset
< (m_nOffsetChar
+GetScreenChars()))
3530 POINT pt1
= TextToClient(ptCaretPos
);
3532 CreateSolidCaret(2, GetLineHeight());
3535 POINT pt
= { ptCaretPos
.x
+ 1, ptCaretPos
.y
};
3536 POINT pt2
= TextToClient(pt
);
3537 int width
= max(GetCharWidth(), pt2
.x
- pt1
.x
);
3538 CreateSolidCaret(width
, GetLineHeight());
3549 POINT
CBaseView::ConvertScreenPosToView(const POINT
& pt
)
3554 int nSubLine
= GetSubLineOffset(pt
.y
);
3557 for (int nScreenLine
= pt
.y
-1; nScreenLine
>= pt
.y
-nSubLine
; nScreenLine
--)
3559 ptViewPos
.x
+= GetLineChars(nScreenLine
).GetLength();
3563 ptViewPos
.y
= GetViewLineForScreen(pt
.y
);
3567 POINT
CBaseView::ConvertViewPosToScreen(const POINT
& pt
)
3570 int nViewLineLenLeft
= GetViewLineLength(pt
.y
);
3571 ptPos
.x
= min(nViewLineLenLeft
, pt
.x
);
3572 ptPos
.y
= FindScreenLineForViewLine(pt
.y
);
3573 if (GetViewLineForScreen(ptPos
.y
) != pt
.y
)
3577 else if (GetSubLineOffset(ptPos
.y
) >= 0) // sublined
3579 int nSubLineLength
= GetLineChars(ptPos
.y
).GetLength();
3580 while (nSubLineLength
< ptPos
.x
)
3582 ptPos
.x
-= nSubLineLength
;
3583 nViewLineLenLeft
-= nSubLineLength
;
3585 nSubLineLength
= GetLineChars(ptPos
.y
).GetLength();
3587 // last pos of non last sub-line go to start of next screen line
3588 // Note: while this works correctly, it's not what a user might expect:
3589 // cursor-right when the caret is before the last char of a wrapped line
3590 // now moves the caret to the next line. But users expect the caret to
3591 // move to the right of the last char instead, and with another cursor-right
3592 // keystroke to move the caret to the next line.
3593 // Basically, this would require to handle two caret positions for the same
3594 // logical position in the line string (one on the last position of the first line,
3595 // one on the first position of the new line. For non-wrapped lines this works
3596 // because there's an 'invisible' newline char at the end of the first line.
3597 if (nSubLineLength
== ptPos
.x
&& nViewLineLenLeft
> nSubLineLength
)
3608 void CBaseView::EnsureCaretVisible()
3610 POINT ptCaretPos
= GetCaretPosition();
3611 int nCaretOffset
= CalculateActualOffset(ptCaretPos
);
3613 if (ptCaretPos
.y
< m_nTopLine
)
3614 ScrollAllToLine(ptCaretPos
.y
);
3615 int screnLines
= GetScreenLines();
3618 if (ptCaretPos
.y
>= (m_nTopLine
+screnLines
)-1)
3619 ScrollAllToLine(ptCaretPos
.y
-screnLines
+2);
3620 if (nCaretOffset
< m_nOffsetChar
)
3621 ScrollAllToChar(nCaretOffset
);
3622 if (nCaretOffset
> (m_nOffsetChar
+GetScreenChars()-1))
3623 ScrollAllToChar(nCaretOffset
-GetScreenChars()+1);
3627 int CBaseView::CalculateActualOffset(const POINT
& point
)
3629 int nLineIndex
= point
.y
;
3630 int nCharIndex
= point
.x
;
3631 ASSERT(nCharIndex
>= 0);
3632 CString sLine
= GetLineChars(nLineIndex
);
3633 int nLineLength
= sLine
.GetLength();
3634 return CountExpandedChars(sLine
, min(nCharIndex
, nLineLength
));
3637 int CBaseView::CalculateCharIndex(int nLineIndex
, int nActualOffset
)
3639 int nLength
= GetLineLength(nLineIndex
);
3640 int nSubLine
= GetSubLineOffset(nLineIndex
);
3643 int nViewLine
= GetViewLineForScreen(nLineIndex
);
3644 if ((nViewLine
>=0)&&(nViewLine
< (int)m_ScreenedViewLine
.size()))
3646 int nMultilineCount
= CountMultiLines(nViewLine
);
3647 if ((nMultilineCount
>0) && (nSubLine
<nMultilineCount
-1))
3653 CString Line
= GetLineChars(nLineIndex
);
3656 int nTabSize
= GetTabSize();
3657 while (nOffset
< nActualOffset
&& nIndex
< nLength
)
3659 if (Line
.GetAt(nIndex
) == _T('\t'))
3660 nOffset
+= (nTabSize
- nOffset
% nTabSize
);
3669 * @param xpos X coordinate in CBaseView
3670 * @param lineIndex logical line index (e.g. wrap/collapse)
3672 int CBaseView::CalcColFromPoint(int xpos
, int lineIndex
)
3678 CString text
= ExpandChars(GetLineChars(lineIndex
), 0);
3679 int fit
= text
.GetLength();
3680 std::unique_ptr
<int> posBuffer(new int[fit
]);
3681 pDC
->SelectObject(GetFont()); // is this right font ?
3683 GetTextExtentExPoint(pDC
->GetSafeHdc(), text
, fit
, INT_MAX
, &fit
, posBuffer
.get(), &size
);
3685 int lower
= -1, upper
= fit
- 1;
3686 int xcheck
= xpos
- GetMarginWidth() + m_nOffsetChar
* GetCharWidth();
3689 int middle
= (upper
+ lower
+ 1) / 2;
3690 int width
= posBuffer
.get()[middle
];
3695 } while (lower
< upper
);
3698 if (lower
< fit
- 1)
3700 int charWidth
= posBuffer
.get()[lower
] - (lower
> 0 ? posBuffer
.get()[lower
- 1] : 0);
3701 if (posBuffer
.get()[lower
] - xcheck
<= charWidth
/ 2)
3707 xpos2
= (xpos
- GetMarginWidth()) / GetCharWidth() + m_nOffsetChar
;
3708 if ((xpos
% GetCharWidth()) >= (GetCharWidth()/2))
3714 POINT
CBaseView::TextToClient(const POINT
& point
)
3717 int nOffsetScreenLine
= max(0, (point
.y
- m_nTopLine
));
3718 pt
.y
= nOffsetScreenLine
* GetLineHeight();
3719 pt
.x
= CalculateActualOffset(point
);
3721 int nLeft
= GetMarginWidth() - m_nOffsetChar
* GetCharWidth();
3722 CDC
* pDC
= GetDC();
3725 pDC
->SelectObject(GetFont()); // is this right font ?
3726 int nScreenLine
= nOffsetScreenLine
+ m_nTopLine
;
3727 CString sLine
= GetLineChars(nScreenLine
);
3728 ExpandChars(sLine
, 0, std::min
<int>(pt
.x
, sLine
.GetLength()), sLine
);
3729 nLeft
+= pDC
->GetTextExtent(sLine
, pt
.x
).cx
;
3732 nLeft
+= pt
.x
* GetCharWidth();
3736 pt
.y
= (pt
.y
+ GetLineHeight() + HEADERHEIGHT
);
3740 void CBaseView::OnChar(UINT nChar
, UINT nRepCnt
, UINT nFlags
)
3742 CView::OnChar(nChar
, nRepCnt
, nFlags
);
3744 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
3745 bool bSkipSelectionClear
= false;
3750 if ((::GetKeyState(VK_LBUTTON
) & 0x8000) != 0 ||
3751 (::GetKeyState(VK_RBUTTON
) & 0x8000) != 0)
3756 if (!m_pViewData
) // no data - nothing to do
3759 if (nChar
== VK_F16
)
3761 // generated by a ctrl+backspace - ignore.
3763 else if (nChar
==VK_TAB
&& HasTextLineSelection())
3765 // change indentation for selected lines
3768 RemoveIndentationForSelectedBlock();
3772 AddIndentationForSelectedBlock();
3774 bSkipSelectionClear
= true;
3776 else if ((nChar
> 31)||(nChar
== VK_TAB
))
3779 RemoveSelectedText();
3780 POINT ptCaretViewPos
= GetCaretViewPosition();
3781 int nViewLine
= ptCaretViewPos
.y
;
3782 if ((nViewLine
==0)&&(GetViewCount()==0))
3783 OnChar(VK_RETURN
, 0, 0);
3785 viewdata lineData
= GetViewData(nViewLine
);
3786 if (nChar
== VK_TAB
)
3788 int indentChars
= GetIndentCharsForLine(ptCaretViewPos
.x
, nViewLine
);
3789 if (indentChars
> 0)
3791 lineData
.sLine
.Insert(ptCaretViewPos
.x
, CString(_T(' '), indentChars
));
3792 charCount
= indentChars
;
3795 lineData
.sLine
.Insert(ptCaretViewPos
.x
, _T('\t'));
3800 lineData
.sLine
.Insert(ptCaretViewPos
.x
, (wchar_t)nChar
);
3803 if (lineData
.sLine
.GetLength() > ptCaretViewPos
.x
)
3804 lineData
.sLine
.SetAt(ptCaretViewPos
.x
, (wchar_t)nChar
);
3806 lineData
.sLine
.Insert(ptCaretViewPos
.x
, (wchar_t)nChar
);
3809 if (IsStateEmpty(lineData
.state
))
3811 // if not last line set EOL
3812 for (int nCheckViewLine
= nViewLine
+1; nCheckViewLine
< GetViewCount(); nCheckViewLine
++)
3814 if (!IsViewLineEmpty(nCheckViewLine
))
3816 lineData
.ending
= m_lineendings
;
3820 // make sure previous (non empty) line have EOL set
3821 for (int nCheckViewLine
= nViewLine
-1; nCheckViewLine
> 0; nCheckViewLine
--)
3823 if (!IsViewLineEmpty(nCheckViewLine
))
3825 if (GetViewLineEnding(nCheckViewLine
) == EOL_NOENDING
)
3827 SetViewLineEnding(nCheckViewLine
, m_lineendings
);
3833 lineData
.state
= DIFFSTATE_EDITED
;
3834 bool bNeedRenumber
= false;
3835 if (lineData
.linenumber
== -1)
3837 lineData
.linenumber
= 0;
3838 bNeedRenumber
= true;
3840 SetViewData(nViewLine
, lineData
);
3843 BuildAllScreen2ViewVector(nViewLine
);
3846 UpdateViewLineNumbers();
3848 for (int i
= 0; i
< charCount
; ++i
)
3852 else if (nChar
== 10)
3854 int nViewLine
= GetViewLineForScreen(GetCaretPosition().y
);
3855 EOL eol
= m_pViewData
->GetLineEnding(nViewLine
);
3856 EOL newEOL
= EOL_CRLF
;
3869 if (eol
==EOL_NOENDING
|| eol
==newEOL
)
3870 // don't allow to change enter on empty line, or last text line (lines with EOL_NOENDING)
3871 // to add EOL on newly edited empty line hit enter
3872 // don't store into UNDO if no change happened
3873 // and don't mark file as modified
3875 AddUndoViewLine(nViewLine
);
3876 m_pViewData
->SetLineEnding(nViewLine
, newEOL
);
3877 m_pViewData
->SetState(nViewLine
, DIFFSTATE_EDITED
);
3880 else if (nChar
== VK_RETURN
)
3882 // insert a new, fresh and empty line below the cursor
3883 RemoveSelectedText();
3885 CUndo::GetInstance().BeginGrouping();
3887 POINT ptCaretViewPos
= GetCaretViewPosition();
3888 int nViewLine
= ptCaretViewPos
.y
;
3889 int nLeft
= ptCaretViewPos
.x
;
3890 CString sLine
= GetViewLineChars(nViewLine
);
3891 CString sLineLeft
= sLine
.Left(nLeft
);
3892 CString sLineRight
= sLine
.Right(sLine
.GetLength() - nLeft
);
3893 EOL eOriginalEnding
= EOL_AUTOLINE
;
3894 if (m_pViewData
->GetCount() > nViewLine
)
3895 eOriginalEnding
= GetViewLineEnding(nViewLine
);
3897 if (!sLineRight
.IsEmpty() || (eOriginalEnding
!=m_lineendings
))
3899 viewdata
newFirstLine(sLineLeft
, DIFFSTATE_EDITED
, 1, m_lineendings
, HIDESTATE_SHOWN
);
3900 SetViewData(nViewLine
, newFirstLine
);
3903 int nInsertLine
= (m_pViewData
->GetCount()==0) ? 0 : nViewLine
+ 1;
3904 viewdata
newLastLine(sLineRight
, DIFFSTATE_EDITED
, 1, eOriginalEnding
, HIDESTATE_SHOWN
);
3905 InsertViewData(nInsertLine
, newLastLine
);
3909 // adds new line everywhere except me
3910 if (IsViewGood(m_pwndLeft
) && m_pwndLeft
!=this)
3912 m_pwndLeft
->InsertViewEmptyLines(nInsertLine
, 1);
3914 if (IsViewGood(m_pwndRight
) && m_pwndRight
!=this)
3916 m_pwndRight
->InsertViewEmptyLines(nInsertLine
, 1);
3918 if (IsViewGood(m_pwndBottom
) && m_pwndBottom
!=this)
3920 m_pwndBottom
->InsertViewEmptyLines(nInsertLine
, 1);
3924 UpdateViewLineNumbers();
3926 CUndo::GetInstance().EndGrouping();
3928 BuildAllScreen2ViewVector();
3929 // move the cursor to the new line
3930 ptCaretViewPos
= SetupPoint(0, nViewLine
+1);
3931 SetCaretAndGoalViewPosition(ptCaretViewPos
);
3934 return; // Unknown control character -- ignore it.
3935 if (!bSkipSelectionClear
)
3937 EnsureCaretVisible();
3942 void CBaseView::AddUndoViewLine(int nViewLine
, bool bAddEmptyLine
)
3945 m_AllState
.left
.AddViewLineFromView(m_pwndLeft
, nViewLine
, bAddEmptyLine
);
3946 m_AllState
.right
.AddViewLineFromView(m_pwndRight
, nViewLine
, bAddEmptyLine
);
3947 m_AllState
.bottom
.AddViewLineFromView(m_pwndBottom
, nViewLine
, bAddEmptyLine
);
3950 RecalcAllVertScrollBars();
3954 void CBaseView::AddEmptyViewLine(int nViewLineIndex
)
3956 if (m_pViewData
== NULL
)
3958 int viewLine
= nViewLineIndex
;
3959 EOL ending
= m_pViewData
->GetLineEnding(viewLine
);
3960 if (ending
== EOL_NOENDING
)
3962 ending
= m_lineendings
;
3964 viewdata
newLine(_T(""), DIFFSTATE_EDITED
, -1, ending
, HIDESTATE_SHOWN
);
3965 if (IsTarget()) // TODO: once more wievs will writable this is not correct anymore
3967 CString sPartLine
= GetViewLineChars(nViewLineIndex
);
3968 int nPosx
= GetCaretPosition().x
; // should be view pos ?
3969 m_pViewData
->SetLine(viewLine
, sPartLine
.Left(nPosx
));
3970 sPartLine
= sPartLine
.Mid(nPosx
);
3971 newLine
.sLine
= sPartLine
;
3973 m_pViewData
->InsertData(viewLine
+1, newLine
);
3974 BuildAllScreen2ViewVector();
3977 void CBaseView::RemoveSelectedText()
3979 if (m_pViewData
== NULL
)
3981 if (!HasTextSelection())
3984 // fix selection if starts or ends on empty line
3985 SetCaretViewPosition(m_ptSelectionViewPosEnd
);
3986 while (IsViewLineEmpty(GetCaretViewPosition().y
) && MoveCaretRight())
3989 m_ptSelectionViewPosEnd
= GetCaretViewPosition();
3990 SetCaretViewPosition(m_ptSelectionViewPosStart
);
3991 while (IsViewLineEmpty(GetCaretViewPosition().y
) && MoveCaretRight())
3994 m_ptSelectionViewPosStart
= GetCaretViewPosition();
3995 if (!HasTextSelection())
4001 // We want to undo the insertion in a single step.
4003 CUndo::GetInstance().BeginGrouping();
4005 // combine first and last line
4006 viewdata oFirstLine
= GetViewData(m_ptSelectionViewPosStart
.y
);
4007 viewdata oLastLine
= GetViewData(m_ptSelectionViewPosEnd
.y
);
4008 oFirstLine
.sLine
= oFirstLine
.sLine
.Left(m_ptSelectionViewPosStart
.x
) + oLastLine
.sLine
.Mid(m_ptSelectionViewPosEnd
.x
);
4009 oFirstLine
.ending
= oLastLine
.ending
;
4010 oFirstLine
.state
= DIFFSTATE_EDITED
;
4011 SetViewData(m_ptSelectionViewPosStart
.y
, oFirstLine
);
4013 // clean up middle lines if any
4014 if (m_ptSelectionViewPosStart
.y
!= m_ptSelectionViewPosEnd
.y
)
4016 viewdata oEmptyLine
= GetEmptyLineData();
4017 for (int nViewLine
= m_ptSelectionViewPosStart
.y
+1; nViewLine
<= m_ptSelectionViewPosEnd
.y
; nViewLine
++)
4019 SetViewData(nViewLine
, oEmptyLine
);
4023 if (CleanEmptyLines())
4025 BuildAllScreen2ViewVector(); // schedule full rebuild
4028 UpdateViewLineNumbers();
4031 SetModified(); //TODO set modified only if real data was changed
4033 CUndo::GetInstance().EndGrouping();
4035 BuildAllScreen2ViewVector(m_ptSelectionViewPosStart
.y
, m_ptSelectionViewPosEnd
.y
);
4036 SetCaretViewPosition(m_ptSelectionViewPosStart
);
4040 EnsureCaretVisible();
4044 void CBaseView::PasteText()
4046 if (!OpenClipboard())
4049 CString sClipboardText
;
4050 HGLOBAL hglb
= GetClipboardData(CF_TEXT
);
4053 LPCSTR lpstr
= (LPCSTR
)GlobalLock(hglb
);
4054 sClipboardText
= CString(lpstr
);
4057 hglb
= GetClipboardData(CF_UNICODETEXT
);
4060 LPCTSTR lpstr
= (LPCTSTR
)GlobalLock(hglb
);
4061 sClipboardText
= lpstr
;
4066 if (sClipboardText
.IsEmpty())
4069 sClipboardText
.Replace(_T("\r\n"), _T("\r"));
4070 sClipboardText
.Replace('\n', '\r');
4072 InsertText(sClipboardText
);
4075 void CBaseView::OnCaretDown()
4077 POINT ptCaretPos
= GetCaretPosition();
4078 int nLine
= ptCaretPos
.y
;
4079 int nNextLine
= nLine
+ 1;
4080 if (nNextLine
>= GetLineCount()) // already at last line
4085 POINT ptCaretViewPos
= GetCaretViewPosition();
4086 int nViewLine
= ptCaretViewPos
.y
;
4087 int nNextViewLine
= GetViewLineForScreen(nNextLine
);
4088 if (!((nNextViewLine
== nViewLine
) && (GetSubLineOffset(nNextLine
)<CountMultiLines(nNextViewLine
)))) // not on same view line
4090 // find next suitable screen line
4091 while ((nNextViewLine
== nViewLine
) || IsViewLineHidden(nNextViewLine
))
4094 if (nNextLine
>= GetLineCount())
4098 nNextViewLine
= GetViewLineForScreen(nNextLine
);
4101 ptCaretPos
.y
= nNextLine
;
4102 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
4103 SetCaretPosition(ptCaretPos
);
4104 OnCaretMove(MOVELEFT
);
4105 ShowDiffLines(ptCaretPos
.y
);
4108 bool CBaseView::MoveCaretLeft()
4110 POINT ptCaretViewPos
= GetCaretViewPosition();
4112 //int nViewLine = ptCaretViewPos.y;
4113 if (ptCaretViewPos
.x
== 0)
4115 int nPrevLine
= GetCaretPosition().y
;
4123 nPrevViewLine
= GetViewLineForScreen(nPrevLine
);
4124 } while ((GetSubLineOffset(nPrevLine
) >= CountMultiLines(nPrevViewLine
)) || IsViewLineHidden(nPrevViewLine
));
4125 ptCaretViewPos
= ConvertScreenPosToView(SetupPoint(GetLineLength(nPrevLine
), nPrevLine
));
4126 ShowDiffLines(nPrevLine
);
4131 SetCaretAndGoalViewPosition(ptCaretViewPos
);
4135 bool CBaseView::MoveCaretRight()
4137 POINT ptCaretViewPos
= GetCaretViewPosition();
4139 int nViewLine
= ptCaretViewPos
.y
;
4140 int nViewLineLen
= GetViewLineLength(nViewLine
);
4141 if (ptCaretViewPos
.x
>= nViewLineLen
)
4143 int nNextLine
= GetCaretPosition().y
;
4147 if (nNextLine
>= GetLineCount())
4151 nNextViewLine
= GetViewLineForScreen(nNextLine
);
4152 } while (nNextViewLine
== nViewLine
|| IsViewLineHidden(nNextViewLine
));
4153 ptCaretViewPos
.y
= nNextViewLine
;
4154 ptCaretViewPos
.x
= 0;
4155 ShowDiffLines(nNextLine
);
4160 SetCaretAndGoalViewPosition(ptCaretViewPos
);
4164 void CBaseView::UpdateGoalPos()
4166 m_nCaretGoalPos
= CalculateActualOffset(GetCaretPosition());
4169 void CBaseView::OnCaretLeft()
4172 OnCaretMove(MOVELEFT
);
4175 void CBaseView::OnCaretRight()
4178 OnCaretMove(MOVERIGHT
);
4181 void CBaseView::OnCaretUp()
4183 POINT ptCaretPos
= GetCaretPosition();
4184 int nLine
= ptCaretPos
.y
;
4185 if (nLine
<= 0) // already at first line
4189 int nPrevLine
= nLine
- 1;
4191 POINT ptCaretViewPos
= GetCaretViewPosition();
4192 int nViewLine
= ptCaretViewPos
.y
;
4193 int nPrevViewLine
= GetViewLineForScreen(nPrevLine
);
4194 if (nPrevViewLine
!= nViewLine
) // not on same view line
4196 // find previous suitable screen line
4197 while ((GetSubLineOffset(nPrevLine
) >= CountMultiLines(nPrevViewLine
)) || IsViewLineHidden(nPrevViewLine
))
4204 nPrevViewLine
= GetViewLineForScreen(nPrevLine
);
4207 ptCaretPos
.y
= nPrevLine
;
4208 ptCaretPos
.x
= CalculateCharIndex(ptCaretPos
.y
, m_nCaretGoalPos
);
4209 SetCaretPosition(ptCaretPos
);
4210 OnCaretMove(MOVELEFT
);
4211 ShowDiffLines(ptCaretPos
.y
);
4214 bool CBaseView::IsWordSeparator(const wchar_t ch
) const
4216 switch (GetCharGroup(ch
))
4219 case CHG_WHITESPACE
:
4220 case CHG_WORDSEPARATOR
:
4226 bool CBaseView::IsCaretAtWordBoundary()
4228 POINT ptViewCaret
= GetCaretViewPosition();
4229 CString line
= GetViewLineChars(ptViewCaret
.y
);
4231 return false; // no boundary at the empty lines
4232 if (ptViewCaret
.x
== 0)
4233 return !IsWordSeparator(line
.GetAt(ptViewCaret
.x
));
4234 if (ptViewCaret
.x
>= GetViewLineLength(ptViewCaret
.y
))
4235 return !IsWordSeparator(line
.GetAt(ptViewCaret
.x
- 1));
4237 IsWordSeparator(line
.GetAt(ptViewCaret
.x
)) !=
4238 IsWordSeparator(line
.GetAt(ptViewCaret
.x
- 1));
4241 void CBaseView::UpdateViewsCaretPosition()
4243 POINT ptCaretPos
= GetCaretPosition();
4244 if (m_pwndBottom
&& m_pwndBottom
!=this)
4245 m_pwndBottom
->UpdateCaretPosition(ptCaretPos
);
4246 if (m_pwndLeft
&& m_pwndLeft
!=this)
4247 m_pwndLeft
->UpdateCaretPosition(ptCaretPos
);
4248 if (m_pwndRight
&& m_pwndRight
!=this)
4249 m_pwndRight
->UpdateCaretPosition(ptCaretPos
);
4252 void CBaseView::OnCaretWordleft()
4254 MoveCaretWordLeft();
4255 OnCaretMove(MOVELEFT
);
4258 void CBaseView::OnCaretWordright()
4260 MoveCaretWordRight();
4261 OnCaretMove(MOVERIGHT
);
4264 void CBaseView::MoveCaretWordLeft()
4266 while (MoveCaretLeft() && !IsCaretAtWordBoundary())
4271 void CBaseView::MoveCaretWordRight()
4273 while (MoveCaretRight() && !IsCaretAtWordBoundary())
4278 void CBaseView::ClearCurrentSelection()
4280 m_ptSelectionViewPosStart
= GetCaretViewPosition();
4281 m_ptSelectionViewPosEnd
= m_ptSelectionViewPosStart
;
4282 m_ptSelectionViewPosOrigin
= m_ptSelectionViewPosStart
;
4283 m_nSelViewBlockStart
= -1;
4284 m_nSelViewBlockEnd
= -1;
4288 void CBaseView::ClearSelection()
4291 m_pwndLeft
->ClearCurrentSelection();
4293 m_pwndRight
->ClearCurrentSelection();
4295 m_pwndBottom
->ClearCurrentSelection();
4298 void CBaseView::AdjustSelection(bool bMoveLeft
)
4300 POINT ptCaretViewPos
= GetCaretViewPosition();
4301 if (ArePointsSame(m_ptSelectionViewPosOrigin
, SetupPoint(-1, -1)))
4303 // select all have been used recently update origin
4304 m_ptSelectionViewPosOrigin
= bMoveLeft
? m_ptSelectionViewPosEnd
: m_ptSelectionViewPosStart
;
4306 if ((ptCaretViewPos
.y
< m_ptSelectionViewPosOrigin
.y
) ||
4307 (ptCaretViewPos
.y
== m_ptSelectionViewPosOrigin
.y
&& ptCaretViewPos
.x
<= m_ptSelectionViewPosOrigin
.x
))
4309 m_ptSelectionViewPosStart
= ptCaretViewPos
;
4310 m_ptSelectionViewPosEnd
= m_ptSelectionViewPosOrigin
;
4314 m_ptSelectionViewPosStart
= m_ptSelectionViewPosOrigin
;
4315 m_ptSelectionViewPosEnd
= ptCaretViewPos
;
4318 SetupAllViewSelection(m_ptSelectionViewPosStart
.y
, m_ptSelectionViewPosEnd
.y
);
4323 void CBaseView::OnEditCut()
4328 RemoveSelectedText();
4332 void CBaseView::OnEditPaste()
4336 CUndo::GetInstance().BeginGrouping();
4337 RemoveSelectedText();
4339 CUndo::GetInstance().EndGrouping();
4343 void CBaseView::DeleteFonts()
4345 for (int i
=0; i
<fontsCount
; i
++)
4347 if (m_apFonts
[i
] != NULL
)
4349 m_apFonts
[i
]->DeleteObject();
4350 delete m_apFonts
[i
];
4351 m_apFonts
[i
] = NULL
;
4356 void CBaseView::OnCaretMove(bool bMoveLeft
)
4358 bool bShift
= !!(GetKeyState(VK_SHIFT
)&0x8000);
4359 OnCaretMove(bMoveLeft
, bShift
);
4362 void CBaseView::OnCaretMove(bool bMoveLeft
, bool isShiftPressed
)
4365 AdjustSelection(bMoveLeft
);
4368 EnsureCaretVisible();
4372 void CBaseView::AddContextItems(CIconMenu
& popup
, DiffStates
/*state*/)
4374 AddCutCopyAndPaste(popup
);
4377 void CBaseView::AddCutCopyAndPaste(CIconMenu
& popup
)
4379 popup
.AppendMenu(MF_SEPARATOR
, NULL
);
4381 temp
.LoadString(IDS_EDIT_COPY
);
4382 popup
.AppendMenu(MF_STRING
| (HasTextSelection() ? MF_ENABLED
: MF_DISABLED
|MF_GRAYED
), ID_EDIT_COPY
, temp
);
4385 temp
.LoadString(IDS_EDIT_CUT
);
4386 popup
.AppendMenu(MF_STRING
| (HasTextSelection() ? MF_ENABLED
: MF_DISABLED
|MF_GRAYED
), ID_EDIT_CUT
, temp
);
4387 temp
.LoadString(IDS_EDIT_PASTE
);
4388 popup
.AppendMenu(MF_STRING
| (CAppUtils::HasClipboardFormat(CF_UNICODETEXT
)||CAppUtils::HasClipboardFormat(CF_TEXT
) ? MF_ENABLED
: MF_DISABLED
|MF_GRAYED
), ID_EDIT_PASTE
, temp
);
4389 popup
.AppendMenu(MF_SEPARATOR
, NULL
);
4393 void CBaseView::CompensateForKeyboard(CPoint
& point
)
4395 // if the context menu is invoked through the keyboard, we have to use
4396 // a calculated position on where to anchor the menu on
4397 if (ArePointsSame(point
, SetupPoint(-1, -1)))
4400 GetWindowRect(&rect
);
4401 point
= rect
.CenterPoint();
4405 HICON
CBaseView::LoadIcon(WORD iconId
)
4407 HANDLE icon
= ::LoadImage( AfxGetResourceHandle(), MAKEINTRESOURCE(iconId
),
4408 IMAGE_ICON
, 16, 16, LR_DEFAULTCOLOR
);
4412 void CBaseView::ReleaseBitmap()
4414 if (m_pCacheBitmap
!= NULL
)
4416 m_pCacheBitmap
->DeleteObject();
4417 delete m_pCacheBitmap
;
4418 m_pCacheBitmap
= NULL
;
4422 void CBaseView::BuildMarkedWordArray()
4424 int lineCount
= GetLineCount();
4425 m_arMarkedWordLines
.clear();
4426 m_arMarkedWordLines
.reserve(lineCount
);
4427 bool bDoit
= !m_sMarkedWord
.IsEmpty();
4428 for (int i
= 0; i
< lineCount
; ++i
)
4432 CString line
= GetLineChars(i
);
4434 if (!line
.IsEmpty())
4437 int nMarkStart
= -1;
4438 while ((nMarkStart
= line
.Find(m_sMarkedWord
, ++nMarkStart
)) >= 0)
4440 int nMarkEnd
= nMarkStart
+ m_sMarkedWord
.GetLength();
4441 ECharGroup eLeft
= GetCharGroup(line
, nMarkStart
- 1);
4442 ECharGroup eStart
= GetCharGroup(line
, nMarkStart
);
4443 if (eLeft
!= eStart
)
4445 ECharGroup eRight
= GetCharGroup(line
, nMarkEnd
);
4446 ECharGroup eEnd
= GetCharGroup(line
, nMarkEnd
- 1);
4454 m_arMarkedWordLines
.push_back(found
);
4457 m_arMarkedWordLines
.push_back(0);
4460 m_arMarkedWordLines
.push_back(0);
4464 void CBaseView::BuildFindStringArray()
4466 int lineCount
= GetLineCount();
4467 m_arFindStringLines
.clear();
4468 m_arFindStringLines
.reserve(lineCount
);
4469 bool bDoit
= !m_sFindText
.IsEmpty();
4472 for (int i
= 0; i
< lineCount
; ++i
)
4476 CString line
= GetLineChars(i
);
4478 if (!line
.IsEmpty())
4480 switch (m_pViewData
->GetState(GetViewLineForScreen(i
)))
4482 case DIFFSTATE_EMPTY
:
4483 m_arFindStringLines
.push_back(0);
4485 case DIFFSTATE_UNKNOWN
:
4486 case DIFFSTATE_NORMAL
:
4489 m_arFindStringLines
.push_back(0);
4492 case DIFFSTATE_REMOVED
:
4493 case DIFFSTATE_REMOVEDWHITESPACE
:
4494 case DIFFSTATE_ADDED
:
4495 case DIFFSTATE_ADDEDWHITESPACE
:
4496 case DIFFSTATE_WHITESPACE
:
4497 case DIFFSTATE_WHITESPACE_DIFF
:
4498 case DIFFSTATE_CONFLICTED
:
4499 case DIFFSTATE_CONFLICTED_IGNORED
:
4500 case DIFFSTATE_CONFLICTADDED
:
4501 case DIFFSTATE_CONFLICTEMPTY
:
4502 case DIFFSTATE_CONFLICTRESOLVED
:
4503 case DIFFSTATE_IDENTICALREMOVED
:
4504 case DIFFSTATE_IDENTICALADDED
:
4505 case DIFFSTATE_THEIRSREMOVED
:
4506 case DIFFSTATE_THEIRSADDED
:
4507 case DIFFSTATE_YOURSREMOVED
:
4508 case DIFFSTATE_YOURSADDED
:
4509 case DIFFSTATE_EDITED
:
4512 line
= line
.MakeLower();
4516 while (StringFound(line
, SearchNext
, s
, e
))
4522 m_arFindStringLines
.push_back(match
);
4526 m_arFindStringLines
.push_back(0);
4530 m_arFindStringLines
.push_back(0);
4533 m_arFindStringLines
.push_back(0);
4538 bool CBaseView::GetInlineDiffPositions(int nViewLine
, std::vector
<inlineDiffPos
>& positions
)
4540 if (!m_bShowInlineDiff
)
4542 if ((m_pwndBottom
!= NULL
) && !(m_pwndBottom
->IsHidden()))
4545 if (m_pViewData
== nullptr || m_pViewData
->GetCount() <= nViewLine
)
4547 const CString
&sLine
= m_pViewData
->GetLine(nViewLine
);
4548 if (sLine
.IsEmpty())
4552 if (!m_pOtherViewData
)
4555 const CString
&sDiffLine
= m_pOtherViewData
->GetLine(nViewLine
);
4556 if (sDiffLine
.IsEmpty())
4559 svn_diff_t
* diff
= NULL
;
4560 auto pLine1
= (this == m_pwndLeft
) ? &sLine
: &sDiffLine
;
4561 auto pLine2
= (this == m_pwndLeft
) ? &sDiffLine
: &sLine
;
4562 m_svnlinediff
.Diff(&diff
, *pLine1
, pLine1
->GetLength(), *pLine2
, pLine2
->GetLength(), m_bInlineWordDiff
);
4563 if (!diff
|| !SVNLineDiff::ShowInlineDiff(diff
))
4566 size_t lineoffset
= 0;
4567 size_t position
= 0;
4570 if (this == m_pwndRight
)
4572 apr_off_t nTmp
= diff
->modified_length
;
4573 diff
->modified_length
= diff
->original_length
;
4574 diff
->original_length
= nTmp
;
4576 nTmp
= diff
->modified_start
;
4577 diff
->modified_start
= diff
->original_start
;
4578 diff
->original_start
= nTmp
;
4580 apr_off_t len
= diff
->original_length
;
4581 size_t oldpos
= position
;
4583 for (apr_off_t i
= 0; i
< len
; ++i
)
4585 position
+= (this == m_pwndRight
) ? m_svnlinediff
.m_line2tokens
[lineoffset
].size() : m_svnlinediff
.m_line1tokens
[lineoffset
].size();
4589 if (diff
->type
== svn_diff__type_diff_modified
)
4594 positions
.push_back(p
);
4600 return !positions
.empty();
4603 void CBaseView::OnNavigateNextinlinediff()
4606 if (GetNextInlineDiff(nX
))
4608 POINT ptCaretViewPos
= GetCaretViewPosition();
4609 ptCaretViewPos
.x
= nX
;
4610 SetCaretAndGoalViewPosition(ptCaretViewPos
);
4611 m_ptSelectionViewPosOrigin
= ptCaretViewPos
;
4612 EnsureCaretVisible();
4616 void CBaseView::OnNavigatePrevinlinediff()
4619 if (GetPrevInlineDiff(nX
))
4621 POINT ptCaretViewPos
= GetCaretViewPosition();
4622 ptCaretViewPos
.x
= nX
;
4623 SetCaretAndGoalViewPosition(ptCaretViewPos
);
4624 m_ptSelectionViewPosOrigin
= ptCaretViewPos
;
4625 EnsureCaretVisible();
4629 bool CBaseView::HasNextInlineDiff()
4632 return GetNextInlineDiff(nPos
);
4635 bool CBaseView::GetNextInlineDiff(int & nPos
)
4637 POINT ptCaretViewPos
= GetCaretViewPosition();
4638 std::vector
<inlineDiffPos
> positions
;
4639 if (GetInlineDiffPositions(ptCaretViewPos
.y
, positions
))
4641 for (auto it
= positions
.cbegin(); it
!= positions
.cend(); ++it
)
4643 if (it
->start
> ptCaretViewPos
.x
)
4645 nPos
= (LONG
)it
->start
;
4648 if (it
->end
> ptCaretViewPos
.x
)
4650 nPos
= (LONG
)it
->end
;
4658 bool CBaseView::HasPrevInlineDiff()
4661 return GetPrevInlineDiff(nPos
);
4664 bool CBaseView::GetPrevInlineDiff(int & nPos
)
4666 POINT ptCaretViewPos
= GetCaretViewPosition();
4667 std::vector
<inlineDiffPos
> positions
;
4668 if (GetInlineDiffPositions(ptCaretViewPos
.y
, positions
))
4670 for (auto it
= positions
.crbegin(); it
!= positions
.crend(); ++it
)
4672 if ( it
->end
< ptCaretViewPos
.x
)
4674 nPos
= (LONG
)it
->end
;
4677 if ( it
->start
< ptCaretViewPos
.x
)
4679 nPos
= (LONG
)it
->start
;
4687 CBaseView
* CBaseView::GetFirstGoodView()
4689 if (IsViewGood(m_pwndLeft
))
4691 if (IsViewGood(m_pwndRight
))
4693 if (IsViewGood(m_pwndBottom
))
4694 return m_pwndBottom
;
4698 void CBaseView::BuildAllScreen2ViewVector()
4700 CBaseView
* p_pwndView
= GetFirstGoodView();
4703 m_Screen2View
.ScheduleFullRebuild(p_pwndView
->m_pViewData
);
4707 void CBaseView::BuildAllScreen2ViewVector(int nViewLine
)
4709 BuildAllScreen2ViewVector(nViewLine
, nViewLine
);
4712 void CBaseView::BuildAllScreen2ViewVector(int nFirstViewLine
, int nLastViewLine
)
4714 CBaseView
* p_pwndView
= GetFirstGoodView();
4717 m_Screen2View
.ScheduleRangeRebuild(p_pwndView
->m_pViewData
, nFirstViewLine
, nLastViewLine
);
4721 void CBaseView::UpdateViewLineNumbers()
4723 int nLineNumber
= 0;
4724 int nViewLineCount
= GetViewCount();
4725 for (int nViewLine
= 0; nViewLine
< nViewLineCount
; nViewLine
++)
4727 int oldLine
= (int)GetViewLineNumber(nViewLine
);
4729 SetViewLineNumber(nViewLine
, nLineNumber
++);
4734 int CBaseView::CleanEmptyLines()
4736 int nRemovedCount
= 0;
4737 int nViewLineCount
= GetViewCount();
4738 bool bCheckLeft
= IsViewGood(m_pwndLeft
);
4739 bool bCheckRight
= IsViewGood(m_pwndRight
);
4740 bool bCheckBottom
= IsViewGood(m_pwndBottom
);
4741 for (int nViewLine
= 0; nViewLine
< nViewLineCount
; )
4743 bool bAllEmpty
= true;
4744 bAllEmpty
&= !bCheckLeft
|| IsStateEmpty(m_pwndLeft
->GetViewState(nViewLine
));
4745 bAllEmpty
&= !bCheckRight
|| IsStateEmpty(m_pwndRight
->GetViewState(nViewLine
));
4746 bAllEmpty
&= !bCheckBottom
|| IsStateEmpty(m_pwndBottom
->GetViewState(nViewLine
));
4751 m_pwndLeft
->RemoveViewData(nViewLine
);
4755 m_pwndRight
->RemoveViewData(nViewLine
);
4759 m_pwndBottom
->RemoveViewData(nViewLine
);
4761 if (CUndo::GetInstance().IsGrouping()) // if use group undo -> ensure back adding goes in right (reversed) order
4771 return nRemovedCount
;
4774 int CBaseView::FindScreenLineForViewLine( int viewLine
)
4776 return m_Screen2View
.FindScreenLineForViewLine(viewLine
);
4779 int CBaseView::CountMultiLines( int nViewLine
)
4781 if (m_ScreenedViewLine
.empty())
4782 return 0; // in case the view is completely empty
4784 ASSERT(nViewLine
< (int)m_ScreenedViewLine
.size());
4786 if (m_ScreenedViewLine
[nViewLine
].bSublinesSet
)
4788 return (int)m_ScreenedViewLine
[nViewLine
].SubLines
.size();
4791 CString multiline
= CStringUtils::WordWrap(m_pViewData
->GetLine(nViewLine
), GetScreenChars()-1, false, true, GetTabSize()); // GetMultiLine(nLine);
4793 TScreenedViewLine oScreenedLine
;
4797 while ((pos
= multiline
.Find('\n', pos
)) >= 0)
4799 oScreenedLine
.SubLines
.push_back(multiline
.Mid(prevpos
, pos
-prevpos
)); // WordWrap could return vector/list of lines instead of string
4803 oScreenedLine
.SubLines
.push_back(multiline
.Mid(prevpos
));
4804 oScreenedLine
.bSublinesSet
= true;
4805 m_ScreenedViewLine
[nViewLine
] = oScreenedLine
;
4807 return CountMultiLines(nViewLine
);
4810 /// prepare inline diff cache
4811 LineColors
& CBaseView::GetLineColors(int nViewLine
)
4813 ASSERT(nViewLine
< (int)m_ScreenedViewLine
.size());
4815 if (m_bWhitespaceInlineDiffs
)
4817 if (m_ScreenedViewLine
[nViewLine
].bLineColorsSetWhiteSpace
)
4818 return m_ScreenedViewLine
[nViewLine
].lineColorsWhiteSpace
;
4822 if (m_ScreenedViewLine
[nViewLine
].bLineColorsSet
)
4823 return m_ScreenedViewLine
[nViewLine
].lineColors
;
4826 LineColors oLineColors
;
4827 // set main line color
4828 COLORREF crBkgnd
, crText
;
4829 DiffStates diffState
= m_pViewData
->GetState(nViewLine
);
4830 CDiffColors::GetInstance().GetColors(diffState
, crBkgnd
, crText
);
4831 oLineColors
.SetColor(0, crText
, crBkgnd
);
4834 if (!m_bShowInlineDiff
)
4837 if ((diffState
== DIFFSTATE_NORMAL
)&&(!m_bWhitespaceInlineDiffs
))
4840 CString sLine
= GetViewLineChars(nViewLine
);
4841 if (sLine
.IsEmpty())
4846 CString sDiffLine
= m_pOtherView
->GetViewLineChars(nViewLine
);
4847 if (sDiffLine
.IsEmpty())
4850 svn_diff_t
* diff
= NULL
;
4851 if (sLine
.GetLength() > (int)m_nInlineDiffMaxLineLength
)
4853 auto pLine1
= (this == m_pwndLeft
) ? &sLine
: &sDiffLine
;
4854 auto pLine2
= (this == m_pwndLeft
) ? &sDiffLine
: &sLine
;
4855 m_svnlinediff
.Diff(&diff
, *pLine1
, pLine1
->GetLength(), *pLine2
, pLine2
->GetLength(), m_bInlineWordDiff
);
4856 if (!diff
|| !SVNLineDiff::ShowInlineDiff(diff
) || !diff
->next
)
4860 int nTextStartOffset
= 0;
4861 std::map
<int, COLORREF
> removedPositions
;
4864 if (this == m_pwndRight
)
4866 apr_off_t nTmp
= diff
->modified_length
;
4867 diff
->modified_length
= diff
->original_length
;
4868 diff
->original_length
= nTmp
;
4870 nTmp
= diff
->modified_start
;
4871 diff
->modified_start
= diff
->original_start
;
4872 diff
->original_start
= nTmp
;
4874 apr_off_t len
= diff
->original_length
;
4876 size_t nTextLength
= 0;
4877 for (int i
= 0; i
< len
; ++i
)
4879 nTextLength
+= (this == m_pwndRight
) ? m_svnlinediff
.m_line2tokens
[lineoffset
].size() : m_svnlinediff
.m_line1tokens
[lineoffset
].size();
4882 bool bInlineDiff
= (diff
->type
== svn_diff__type_diff_modified
);
4884 CDiffColors::GetInstance().GetColors(diffState
, crBkgnd
, crText
);
4885 if ((m_bShowInlineDiff
)&&(bInlineDiff
))
4887 crBkgnd
= InlineViewLineDiffColor(nViewLine
);
4891 crBkgnd
= m_ModifiedBk
;
4894 if (len
< diff
->modified_length
)
4896 removedPositions
[nTextStartOffset
] = m_InlineRemovedBk
;
4898 oLineColors
.SetColor(nTextStartOffset
, crText
, crBkgnd
);
4900 nTextStartOffset
+= (int)nTextLength
;
4903 for (std::map
<int, COLORREF
>::const_iterator it
= removedPositions
.begin(); it
!= removedPositions
.end(); ++it
)
4905 oLineColors
.AddShotColor(it
->first
, it
->second
);
4907 } while (false); // error catch
4909 if (!m_bWhitespaceInlineDiffs
)
4911 m_ScreenedViewLine
[nViewLine
].lineColors
= oLineColors
;
4912 m_ScreenedViewLine
[nViewLine
].bLineColorsSet
= true;
4916 m_ScreenedViewLine
[nViewLine
].lineColorsWhiteSpace
= oLineColors
;
4917 m_ScreenedViewLine
[nViewLine
].bLineColorsSetWhiteSpace
= true;
4920 return GetLineColors(nViewLine
);
4923 void CBaseView::OnEditSelectall()
4925 if (m_pViewData
== nullptr)
4927 int nLastViewLine
= m_pViewData
->GetCount()-1;
4928 if (nLastViewLine
< 0)
4930 SetupAllViewSelection(0, nLastViewLine
);
4932 CString sLine
= GetViewLineChars(nLastViewLine
);
4933 m_ptSelectionViewPosStart
= SetupPoint(0, 0);
4934 m_ptSelectionViewPosEnd
= SetupPoint(sLine
.GetLength(), nLastViewLine
);
4935 m_ptSelectionViewPosOrigin
= SetupPoint(-1, -1);
4940 void CBaseView::FilterWhitespaces(CString
& first
, CString
& second
)
4942 FilterWhitespaces(first
);
4943 FilterWhitespaces(second
);
4946 void CBaseView::FilterWhitespaces(CString
& line
)
4954 int CBaseView::GetButtonEventLineIndex(const POINT
& point
)
4956 const int nLineFromTop
= (point
.y
- HEADERHEIGHT
) / GetLineHeight();
4957 int nEventLine
= nLineFromTop
+ m_nTopLine
;
4958 nEventLine
--; //we need the index
4963 BOOL
CBaseView::PreTranslateMessage(MSG
* pMsg
)
4965 if (RelayTrippleClick(pMsg
))
4967 return CView::PreTranslateMessage(pMsg
);
4971 void CBaseView::ResetUndoStep()
4976 void CBaseView::SaveUndoStep()
4978 if (!m_AllState
.IsEmpty())
4980 CUndo::GetInstance().AddState(m_AllState
, GetCaretViewPosition());
4985 void CBaseView::InsertViewData( int index
, const CString
& sLine
, DiffStates state
, int linenumber
, EOL ending
, HIDESTATE hide
, int movedline
)
4987 m_pState
->addedlines
.push_back(index
);
4988 m_pViewData
->InsertData(index
, sLine
, state
, linenumber
, ending
, hide
, movedline
);
4991 void CBaseView::InsertViewData( int index
, const viewdata
& data
)
4993 m_pState
->addedlines
.push_back(index
);
4994 m_pViewData
->InsertData(index
, data
);
4997 void CBaseView::RemoveViewData( int index
)
4999 m_pState
->removedlines
[index
] = m_pViewData
->GetData(index
);
5000 m_pViewData
->RemoveData(index
);
5003 void CBaseView::SetViewData( int index
, const viewdata
& data
)
5005 m_pState
->replacedlines
[index
] = m_pViewData
->GetData(index
);
5006 m_pViewData
->SetData(index
, data
);
5009 void CBaseView::SetViewState( int index
, DiffStates state
)
5011 m_pState
->linestates
[index
] = m_pViewData
->GetState(index
);
5012 m_pViewData
->SetState(index
, state
);
5015 void CBaseView::SetViewLine( int index
, const CString
& sLine
)
5017 m_pState
->difflines
[index
] = m_pViewData
->GetLine(index
);
5018 m_pViewData
->SetLine(index
, sLine
);
5021 void CBaseView::SetViewLineNumber( int index
, int linenumber
)
5023 int oldLineNumber
= m_pViewData
->GetLineNumber(index
);
5024 if (oldLineNumber
!= linenumber
) {
5025 m_pState
->linelines
[index
] = oldLineNumber
;
5026 m_pViewData
->SetLineNumber(index
, linenumber
);
5030 void CBaseView::SetViewLineEnding( int index
, EOL ending
)
5032 m_pState
->linesEOL
[index
] = m_pViewData
->GetLineEnding(index
);
5033 m_pViewData
->SetLineEnding(index
, ending
);
5036 void CBaseView::SetViewMarked( int index
, bool marked
)
5038 m_pState
->markedlines
[index
] = m_pViewData
->GetMarked(index
);
5039 m_pViewData
->SetMarked(index
, marked
);
5043 BOOL
CBaseView::GetViewSelection( int& start
, int& end
) const
5047 start
= m_nSelViewBlockStart
;
5048 end
= m_nSelViewBlockEnd
;
5054 int CBaseView::Screen2View::GetViewLineForScreen( int screenLine
)
5056 RebuildIfNecessary();
5057 if ((size() <= screenLine
) || (screenLine
< 0))
5059 return m_Screen2View
[screenLine
].nViewLine
;
5062 int CBaseView::Screen2View::size()
5064 RebuildIfNecessary();
5065 return (int)m_Screen2View
.size();
5068 int CBaseView::Screen2View::GetSubLineOffset( int screenLine
)
5070 RebuildIfNecessary();
5071 if (size() <= screenLine
)
5073 return m_Screen2View
[screenLine
].nViewSubLine
;
5076 CBaseView::TScreenLineInfo
CBaseView::Screen2View::GetScreenLineInfo( int screenLine
)
5078 RebuildIfNecessary();
5079 return m_Screen2View
[screenLine
];
5083 doing partial rebuild, whole screen2view vector is built, but uses ScreenedViewLine cache to do it faster
5085 void CBaseView::Screen2View::RebuildIfNecessary()
5088 return; // rebuild not necessary
5090 FixScreenedCacheSize(m_pwndLeft
);
5091 FixScreenedCacheSize(m_pwndRight
);
5092 FixScreenedCacheSize(m_pwndBottom
);
5095 for (auto it
= m_RebuildRanges
.cbegin(); it
!= m_RebuildRanges
.cend(); ++it
)
5097 ResetScreenedViewLineCache(m_pwndLeft
, *it
);
5098 ResetScreenedViewLineCache(m_pwndRight
, *it
);
5099 ResetScreenedViewLineCache(m_pwndBottom
, *it
);
5104 ResetScreenedViewLineCache(m_pwndLeft
);
5105 ResetScreenedViewLineCache(m_pwndRight
);
5106 ResetScreenedViewLineCache(m_pwndBottom
);
5108 m_RebuildRanges
.clear();
5111 size_t OldSize
= m_Screen2View
.size();
5112 m_Screen2View
.clear();
5113 m_Screen2View
.reserve(OldSize
); // guess same size
5114 for (int i
= 0; i
< m_pViewData
->GetCount(); ++i
)
5116 if (m_pMainFrame
->m_bCollapsed
)
5118 while ((i
< m_pViewData
->GetCount())&&(m_pViewData
->GetHideState(i
) == HIDESTATE_HIDDEN
))
5120 if (!(i
< m_pViewData
->GetCount()))
5123 TScreenLineInfo oLineInfo
;
5124 oLineInfo
.nViewLine
= i
;
5125 oLineInfo
.nViewSubLine
= -1; // no wrap
5126 if (m_pMainFrame
->m_bWrapLines
&& !IsViewLineHidden(m_pViewData
, i
))
5129 if (IsLeftViewGood())
5130 nMaxLines
= std::max
<int>(nMaxLines
, m_pwndLeft
->CountMultiLines(i
));
5131 if (IsRightViewGood())
5132 nMaxLines
= std::max
<int>(nMaxLines
, m_pwndRight
->CountMultiLines(i
));
5133 if (IsBottomViewGood())
5134 nMaxLines
= std::max
<int>(nMaxLines
, m_pwndBottom
->CountMultiLines(i
));
5135 for (int l
= 0; l
< (nMaxLines
-1); ++l
)
5137 oLineInfo
.nViewSubLine
++;
5138 m_Screen2View
.push_back(oLineInfo
);
5140 oLineInfo
.nViewSubLine
++;
5142 m_Screen2View
.push_back(oLineInfo
);
5146 if (IsLeftViewGood())
5147 m_pwndLeft
->BuildMarkedWordArray();
5148 if (IsRightViewGood())
5149 m_pwndRight
->BuildMarkedWordArray();
5150 if (IsBottomViewGood())
5151 m_pwndBottom
->BuildMarkedWordArray();
5153 RecalcAllVertScrollBars();
5154 RecalcAllHorzScrollBars();
5157 int CBaseView::Screen2View::FindScreenLineForViewLine( int viewLine
)
5159 RebuildIfNecessary();
5161 int nScreenLineCount
= (int)m_Screen2View
.size();
5164 if (nScreenLineCount
>16)
5166 // for enough long data search for last screen
5167 // with viewline less than one we are looking for
5168 // use approximate method (based on) binary search using asymmetric start point
5169 // in form 2**n (determined as MSB of length) to go around division and rounding;
5170 // this effectively looks for bit values from MSB to LSB
5173 //GetMostSignificantBitValue
5174 // note _BitScanReverse(&nTestBit, nScreenLineCount); can be used instead
5175 nTestBit
= nScreenLineCount
;
5176 nTestBit
|= nTestBit
>>1;
5177 nTestBit
|= nTestBit
>>2;
5178 nTestBit
|= nTestBit
>>4;
5179 nTestBit
|= nTestBit
>>8;
5180 nTestBit
|= nTestBit
>>16;
5181 nTestBit
^= (nTestBit
>>1);
5185 int nTestPos
= nPos
| nTestBit
;
5186 if (nTestPos
< nScreenLineCount
&& m_Screen2View
[nTestPos
].nViewLine
< viewLine
)
5193 while (nPos
< nScreenLineCount
&& m_Screen2View
[nPos
].nViewLine
< viewLine
)
5201 void CBaseView::Screen2View::ScheduleFullRebuild(CViewData
* pViewData
) {
5204 m_pViewData
= pViewData
;
5207 void CBaseView::Screen2View::ScheduleRangeRebuild(CViewData
* pViewData
, int nFirstViewLine
, int nLastViewLine
)
5212 m_pViewData
= pViewData
;
5214 TRebuildRange Range
;
5215 Range
.FirstViewLine
=nFirstViewLine
;
5216 Range
.LastViewLine
=nLastViewLine
;
5217 m_RebuildRanges
.push_back(Range
);
5220 bool CBaseView::Screen2View::FixScreenedCacheSize(CBaseView
* pwndView
)
5222 if (!IsViewGood(pwndView
))
5226 const int nOldSize
= (int)pwndView
->m_ScreenedViewLine
.size();
5227 const int nViewCount
= std::max
<int>(pwndView
->GetViewCount(), 0);
5228 if (nOldSize
== nViewCount
)
5232 pwndView
->m_ScreenedViewLine
.resize(nViewCount
);
5236 bool CBaseView::Screen2View::ResetScreenedViewLineCache(CBaseView
* pwndView
) const
5238 if (!IsViewGood(pwndView
))
5242 TRebuildRange Range
={0, pwndView
->GetViewCount()-1};
5243 ResetScreenedViewLineCache(pwndView
, Range
);
5247 bool CBaseView::Screen2View::ResetScreenedViewLineCache(CBaseView
* pwndView
, const TRebuildRange
& Range
) const
5249 if (!IsViewGood(pwndView
))
5253 if (Range
.LastViewLine
== -1)
5257 ASSERT(Range
.FirstViewLine
>= 0);
5258 ASSERT(Range
.LastViewLine
< pwndView
->GetViewCount());
5259 for (int i
= Range
.FirstViewLine
; i
<= Range
.LastViewLine
; i
++)
5261 pwndView
->m_ScreenedViewLine
[i
].Clear();
5266 void CBaseView::WrapChanged()
5268 m_nMaxLineLength
= -1;
5272 void CBaseView::OnEditFind()
5277 m_pFindDialog
= new CFindDlg(this);
5278 m_pFindDialog
->Create(this);
5280 m_pFindDialog
->SetFindString(HasTextSelection() ? GetSelectedText() : L
"");
5281 m_pFindDialog
->SetReadonly(m_bReadonly
);
5284 LRESULT
CBaseView::OnFindDialogMessage(WPARAM wParam
, LPARAM
/*lParam*/)
5286 ASSERT(m_pFindDialog
!= NULL
);
5288 if (m_pFindDialog
->IsTerminating())
5290 // invalidate the handle identifying the dialog box.
5291 m_pFindDialog
= NULL
;
5295 if(m_pFindDialog
->FindNext())
5297 //read data from dialog
5298 m_sFindText
= m_pFindDialog
->GetFindString();
5299 m_bMatchCase
= (m_pFindDialog
->MatchCase() == TRUE
);
5300 m_bLimitToDiff
= m_pFindDialog
->LimitToDiffs();
5301 m_bWholeWord
= m_pFindDialog
->WholeWord();
5304 m_sFindText
= m_sFindText
.MakeLower();
5306 BuildFindStringArray();
5307 if ((CFindDlg::FindType
)wParam
== CFindDlg::FindType::Find
)
5309 if (m_pFindDialog
->SearchUp())
5314 else if ((CFindDlg::FindType
)wParam
== CFindDlg::FindType::Count
)
5317 for (size_t i
= 0; i
< m_arFindStringLines
.size(); ++i
)
5318 count
+= m_arFindStringLines
[i
];
5320 format
.LoadString(IDS_FIND_COUNT
);
5322 matches
.Format(format
, count
);
5323 m_pFindDialog
->SetStatusText(matches
);
5325 else if ((CFindDlg::FindType
)wParam
== CFindDlg::FindType::Replace
)
5329 bool bFound
= false;
5330 if (m_pFindDialog
->SearchUp())
5331 bFound
= Search(SearchPrevious
, true, true, false);
5333 bFound
= Search(SearchNext
, true, true, false);
5336 CString sReplaceText
= m_pFindDialog
->GetReplaceString();
5337 CUndo::GetInstance().BeginGrouping();
5338 RemoveSelectedText();
5339 InsertText(sReplaceText
);
5340 CUndo::GetInstance().EndGrouping();
5344 else if ((CFindDlg::FindType
)wParam
== CFindDlg::FindType::ReplaceAll
)
5348 bool bFound
= false;
5349 int replaceCount
= 0;
5350 POINT lastPoint
= m_ptSelectionViewPosStart
;
5351 m_ptSelectionViewPosStart
.x
= m_ptSelectionViewPosStart
.y
= 0;
5352 CUndo::GetInstance().BeginGrouping();
5355 bFound
= Search(SearchNext
, true, false, true);
5358 CString sReplaceText
= m_pFindDialog
->GetReplaceString();
5359 RemoveSelectedText();
5360 InsertText(sReplaceText
);
5364 CUndo::GetInstance().EndGrouping();
5365 if (replaceCount
== 0)
5366 m_ptSelectionViewPosStart
= lastPoint
;
5368 message
.Format(IDS_FIND_REPLACED
, replaceCount
);
5370 m_pFindDialog
->SetStatusText(message
, RGB(0, 0, 0));
5378 void CBaseView::OnEditFindnextStart()
5380 if (m_pViewData
== nullptr)
5382 if (HasTextSelection())
5384 m_sFindText
= GetSelectedText();
5385 m_bMatchCase
= false;
5386 m_bLimitToDiff
= false;
5387 m_bWholeWord
= false;
5388 m_sFindText
= m_sFindText
.MakeLower();
5390 BuildFindStringArray();
5395 m_sFindText
.Empty();
5396 BuildFindStringArray();
5400 void CBaseView::OnEditFindprevStart()
5402 if (m_pViewData
== nullptr)
5404 if (HasTextSelection())
5406 m_sFindText
= GetSelectedText();
5407 m_bMatchCase
= false;
5408 m_bLimitToDiff
= false;
5409 m_bWholeWord
= false;
5410 m_sFindText
= m_sFindText
.MakeLower();
5412 BuildFindStringArray();
5417 m_sFindText
.Empty();
5418 BuildFindStringArray();
5422 bool CBaseView::StringFound(const CString
& str
, SearchDirection srchDir
, int& start
, int& end
) const
5424 if (srchDir
== SearchPrevious
)
5427 int laststart2
= -1;
5430 laststart2
= laststart
;
5431 laststart
= str
.Find(m_sFindText
, laststart
+ 1);
5432 } while (laststart
>= 0 && laststart
< start
);
5436 start
= str
.Find(m_sFindText
, start
);
5437 end
= start
+ m_sFindText
.GetLength();
5438 bool bStringFound
= (start
>= 0);
5439 if (bStringFound
&& m_bWholeWord
)
5442 bStringFound
= IsWordSeparator(str
.Mid(start
-1,1).GetAt(0));
5446 if (str
.GetLength() > end
)
5447 bStringFound
= IsWordSeparator(str
.Mid(end
, 1).GetAt(0));
5450 return bStringFound
;
5453 void CBaseView::OnEditFindprev()
5455 Search(SearchPrevious
, false, true, false);
5458 void CBaseView::OnEditFindnext()
5460 Search(SearchNext
, false, true, false);
5463 bool CBaseView::Search(SearchDirection srchDir
, bool useStart
, bool flashIfNotFound
, bool stopEof
)
5465 if (m_sFindText
.IsEmpty())
5470 POINT start
= useStart
? m_ptSelectionViewPosStart
: m_ptSelectionViewPosEnd
;
5472 end
.y
= m_pViewData
->GetCount()-1;
5476 if (srchDir
==SearchNext
)
5477 end
.x
= GetViewLineLength(end
.y
);
5480 end
.x
= m_ptSelectionViewPosStart
.x
;
5484 if (!HasTextSelection())
5486 start
.y
= m_ptCaretViewPos
.y
;
5487 if (srchDir
==SearchNext
)
5488 start
.x
= m_ptCaretViewPos
.x
;
5492 end
.x
= m_ptCaretViewPos
.x
;
5495 CString sSelectedText
;
5497 for (int nViewLine
=start
.y
; ;srchDir
==SearchNext
? nViewLine
++ : nViewLine
--)
5503 nViewLine
= m_pViewData
->GetCount()-1;
5504 startline
= start
.y
;
5505 if (flashIfNotFound
)
5508 m_pFindDialog
->SetStatusText(CString(MAKEINTRESOURCE(IDS_FIND_TOPREACHED
)), RGB(63, 127, 47));
5509 m_pMainFrame
->FlashWindowEx(FLASHW_ALL
, 2, 100);
5512 if (nViewLine
> end
.y
)
5517 startline
= start
.y
;
5518 if (flashIfNotFound
)
5521 m_pFindDialog
->SetStatusText(CString(MAKEINTRESOURCE(IDS_FIND_BOTTOMREACHED
)), RGB(63, 127, 47));
5522 m_pMainFrame
->FlashWindowEx(FLASHW_ALL
, 2, 100);
5525 switch (m_pViewData
->GetState(nViewLine
))
5527 case DIFFSTATE_EMPTY
:
5529 case DIFFSTATE_UNKNOWN
:
5530 case DIFFSTATE_NORMAL
:
5533 case DIFFSTATE_REMOVED
:
5534 case DIFFSTATE_REMOVEDWHITESPACE
:
5535 case DIFFSTATE_ADDED
:
5536 case DIFFSTATE_ADDEDWHITESPACE
:
5537 case DIFFSTATE_WHITESPACE
:
5538 case DIFFSTATE_WHITESPACE_DIFF
:
5539 case DIFFSTATE_CONFLICTED
:
5540 case DIFFSTATE_CONFLICTED_IGNORED
:
5541 case DIFFSTATE_CONFLICTADDED
:
5542 case DIFFSTATE_CONFLICTEMPTY
:
5543 case DIFFSTATE_CONFLICTRESOLVED
:
5544 case DIFFSTATE_IDENTICALREMOVED
:
5545 case DIFFSTATE_IDENTICALADDED
:
5546 case DIFFSTATE_THEIRSREMOVED
:
5547 case DIFFSTATE_THEIRSADDED
:
5548 case DIFFSTATE_YOURSREMOVED
:
5549 case DIFFSTATE_YOURSADDED
:
5550 case DIFFSTATE_EDITED
:
5552 sSelectedText
= GetViewLineChars(nViewLine
);
5553 if (nViewLine
== start
.y
&& startline
< 0)
5554 sSelectedText
= srchDir
== SearchNext
? sSelectedText
.Mid(start
.x
) : sSelectedText
.Left(end
.x
);
5556 sSelectedText
= sSelectedText
.MakeLower();
5557 int startfound
= srchDir
== SearchNext
? 0 : sSelectedText
.GetLength();
5559 if (StringFound(sSelectedText
, srchDir
, startfound
, endfound
))
5561 HighlightViewLines(nViewLine
, nViewLine
);
5562 m_ptSelectionViewPosStart
.x
= startfound
;
5563 m_ptSelectionViewPosEnd
.x
= endfound
;
5564 if (nViewLine
== start
.y
&& startline
< 0)
5566 m_ptSelectionViewPosStart
.x
+= start
.x
;
5567 m_ptSelectionViewPosEnd
.x
+= start
.x
;
5569 m_ptSelectionViewPosEnd
.x
= m_ptSelectionViewPosStart
.x
+ m_sFindText
.GetLength();
5570 m_ptSelectionViewPosStart
.y
= nViewLine
;
5571 m_ptSelectionViewPosEnd
.y
= nViewLine
;
5572 m_ptCaretViewPos
= m_ptSelectionViewPosStart
;
5573 UpdateViewsCaretPosition();
5574 EnsureCaretVisible();
5584 if (nViewLine
== startline
)
5586 if (flashIfNotFound
)
5589 message
.Format(IDS_FIND_NOTFOUND
, m_sFindText
);
5591 m_pFindDialog
->SetStatusText(message
, RGB(255, 0, 0));
5592 ::MessageBeep(0xFFFFFFFF);
5593 m_pMainFrame
->FlashWindowEx(FLASHW_ALL
, 3, 100);
5599 m_pMainFrame
->m_nMoveMovesToIgnore
= MOVESTOIGNORE
;
5603 CString
CBaseView::GetSelectedText() const
5605 CString sSelectedText
;
5606 POINT start
= m_ptSelectionViewPosStart
;
5607 POINT end
= m_ptSelectionViewPosEnd
;
5608 if (!HasTextSelection())
5610 if (!HasSelection())
5611 return sSelectedText
;
5612 start
.y
= m_nSelViewBlockStart
;
5614 end
.y
= m_nSelViewBlockEnd
;
5615 end
.x
= GetViewLineLength(m_nSelViewBlockEnd
);
5617 if (m_pViewData
== nullptr)
5618 return sSelectedText
;
5619 // first store the selected lines in one CString
5620 for (int nViewLine
=start
.y
; nViewLine
<=end
.y
; nViewLine
++)
5622 switch (m_pViewData
->GetState(nViewLine
))
5624 case DIFFSTATE_EMPTY
:
5626 case DIFFSTATE_UNKNOWN
:
5627 case DIFFSTATE_NORMAL
:
5628 case DIFFSTATE_REMOVED
:
5629 case DIFFSTATE_REMOVEDWHITESPACE
:
5630 case DIFFSTATE_ADDED
:
5631 case DIFFSTATE_ADDEDWHITESPACE
:
5632 case DIFFSTATE_WHITESPACE
:
5633 case DIFFSTATE_WHITESPACE_DIFF
:
5634 case DIFFSTATE_CONFLICTED
:
5635 case DIFFSTATE_CONFLICTED_IGNORED
:
5636 case DIFFSTATE_CONFLICTADDED
:
5637 case DIFFSTATE_CONFLICTEMPTY
:
5638 case DIFFSTATE_CONFLICTRESOLVED
:
5639 case DIFFSTATE_IDENTICALREMOVED
:
5640 case DIFFSTATE_IDENTICALADDED
:
5641 case DIFFSTATE_THEIRSREMOVED
:
5642 case DIFFSTATE_THEIRSADDED
:
5643 case DIFFSTATE_YOURSREMOVED
:
5644 case DIFFSTATE_YOURSADDED
:
5645 case DIFFSTATE_EDITED
:
5646 sSelectedText
+= GetViewLineChars(nViewLine
);
5647 sSelectedText
+= _T("\r\n");
5651 // remove the non-selected chars from the first line, last line and last \r\n
5652 int nLeftCut
= start
.x
;
5653 int nRightCut
= GetViewLineChars(end
.y
).GetLength() - end
.x
+ 2;
5654 sSelectedText
= sSelectedText
.Mid(nLeftCut
, sSelectedText
.GetLength()-nLeftCut
-nRightCut
);
5655 return sSelectedText
;
5658 void CBaseView::CheckModifications(bool& hasMods
, bool& hasConflicts
, bool& hasWhitespaceMods
)
5661 hasConflicts
= false;
5662 hasWhitespaceMods
= false;
5666 for (int i
=0; i
<m_pViewData
->GetCount(); i
++)
5668 DiffStates state
= m_pViewData
->GetState(i
);
5671 case DIFFSTATE_ADDED
:
5672 case DIFFSTATE_IDENTICALADDED
:
5673 case DIFFSTATE_THEIRSADDED
:
5674 case DIFFSTATE_YOURSADDED
:
5675 case DIFFSTATE_CONFLICTADDED
:
5676 case DIFFSTATE_IDENTICALREMOVED
:
5677 case DIFFSTATE_REMOVED
:
5678 case DIFFSTATE_THEIRSREMOVED
:
5679 case DIFFSTATE_YOURSREMOVED
:
5680 case DIFFSTATE_EMPTY
:
5683 case DIFFSTATE_CONFLICTED
:
5684 case DIFFSTATE_CONFLICTED_IGNORED
:
5685 hasConflicts
= true;
5687 case DIFFSTATE_REMOVEDWHITESPACE
:
5688 case DIFFSTATE_ADDEDWHITESPACE
:
5689 case DIFFSTATE_WHITESPACE
:
5690 case DIFFSTATE_WHITESPACE_DIFF
:
5691 hasWhitespaceMods
= true;
5698 void CBaseView::OnEditGotoline()
5700 if (m_pViewData
== NULL
)
5702 // find the last and first line number
5703 int nViewLineCount
= m_pViewData
->GetCount();
5705 int nLastLineNumber
= DIFF_EMPTYLINENUMBER
;
5706 for (int nViewLine
=nViewLineCount
-1; nViewLine
>=0; --nViewLine
)
5708 nLastLineNumber
= m_pViewData
->GetLineNumber(nViewLine
);
5709 if (nLastLineNumber
!=DIFF_EMPTYLINENUMBER
)
5714 if (nLastLineNumber
==DIFF_EMPTYLINENUMBER
|| nLastLineNumber
==0) // not numbered line foud or last one is first
5719 int nFirstLineNumber
=1; // first is always 1
5722 sText
.Format(IDS_GOTOLINE
, nFirstLineNumber
, nLastLineNumber
);
5724 CGotoLineDlg
dlg(this);
5725 dlg
.SetLabel(sText
);
5726 dlg
.SetLimits(nFirstLineNumber
, nLastLineNumber
);
5727 if (dlg
.DoModal() == IDOK
)
5729 for (int nViewLine
= 0; nViewLine
< nViewLineCount
; ++nViewLine
)
5731 if ((m_pViewData
->GetLineNumber(nViewLine
)+1) == dlg
.GetLineNumber())
5733 HighlightViewLines(nViewLine
, nViewLine
);
5740 void CBaseView::OnToggleReadonly()
5742 if (IsReadonlyChangable()) {
5743 SetWritable(IsReadonly());
5747 int CBaseView::SaveFile(int nFlags
)
5750 if (m_pViewData
!=NULL
&& m_pWorkingFile
!=NULL
)
5752 CFileTextLines file
;
5753 m_SaveParams
.m_LineEndings
= m_lineendings
;
5754 m_SaveParams
.m_UnicodeType
= m_texttype
;
5755 file
.SetSaveParams(m_SaveParams
);
5757 for (int i
=0; i
<m_pViewData
->GetCount(); i
++)
5759 //only copy non-removed lines
5760 DiffStates state
= m_pViewData
->GetState(i
);
5763 case DIFFSTATE_CONFLICTED
:
5764 case DIFFSTATE_CONFLICTED_IGNORED
:
5771 } while((last
<m_pViewData
->GetCount()) && ((m_pViewData
->GetState(last
)==DIFFSTATE_CONFLICTED
)||(m_pViewData
->GetState(last
)==DIFFSTATE_CONFLICTED_IGNORED
)));
5772 file
.Add(_T("<<<<<<< .mine"), EOL_NOENDING
);
5773 for (int j
=first
; j
<last
; j
++)
5775 file
.Add(m_pwndRight
->m_pViewData
->GetLine(j
), m_pwndRight
->m_pViewData
->GetLineEnding(j
));
5777 file
.Add(_T("======="), EOL_NOENDING
);
5778 for (int j
=first
; j
<last
; j
++)
5780 file
.Add(m_pwndLeft
->m_pViewData
->GetLine(j
), m_pwndLeft
->m_pViewData
->GetLineEnding(j
));
5782 file
.Add(_T(">>>>>>> .theirs"), EOL_NOENDING
);
5786 case DIFFSTATE_EMPTY
:
5788 case DIFFSTATE_CONFLICTEMPTY
:
5789 case DIFFSTATE_IDENTICALREMOVED
:
5790 case DIFFSTATE_REMOVED
:
5791 case DIFFSTATE_THEIRSREMOVED
:
5792 case DIFFSTATE_YOURSREMOVED
:
5793 case DIFFSTATE_CONFLICTRESOLVEDEMPTY
:
5794 if ((nFlags
&SAVE_REMOVEDLINES
) == 0)
5796 // do not save removed lines
5800 file
.Add(m_pViewData
->GetLine(i
), m_pViewData
->GetLineEnding(i
));
5804 CString filename
= m_pWorkingFile
->GetFilename();
5805 if (m_pWorkingFile
->IsReadonly())
5806 if (!CCommonAppUtils::FileOpenSave(filename
, NULL
, IDS_SAVEASTITLE
, IDS_COMMONFILEFILTER
, false, m_hWnd
))
5808 if (!file
.Save(filename
))
5810 ::MessageBox(m_hWnd
, file
.GetErrorString(), _T("TortoiseGitMerge"), MB_ICONERROR
);
5813 m_pWorkingFile
->SetFileName(filename
);
5814 m_pWorkingFile
->StoreFileAttributes();
5815 // m_dlgFilePatches.SetFileStatusAsPatched(sFilePath);
5817 CUndo::GetInstance().MarkAsOriginalState(
5819 this == m_pwndRight
,
5820 this == m_pwndBottom
);
5821 if (file
.GetCount() == 1 && file
.GetAt(0).IsEmpty() && file
.GetLineEnding(0) == EOL_NOENDING
)
5823 return file
.GetCount();
5829 int CBaseView::SaveFileTo(CString sFileName
, int nFlags
)
5833 m_pWorkingFile
->SetFileName(sFileName
);
5834 return SaveFile(nFlags
);
5840 EOL
CBaseView::GetLineEndings()
5842 return GetLineEndings(GetWhitecharsProperties().HasMixedEols
);
5845 EOL
CBaseView::GetLineEndings(bool bHasMixedEols
)
5849 return EOL_AUTOLINE
; // mixed eols - hack value
5851 if (m_lineendings
== EOL_AUTOLINE
)
5855 return m_lineendings
;
5858 void CBaseView::ReplaceLineEndings(EOL eEol
)
5860 if (eEol
== EOL_AUTOLINE
)
5865 m_lineendings
= eEol
;
5866 // replace all set EOLs
5867 // TODO store line endings and lineendings in undo
5868 //CUndo::BeginGrouping();
5869 for (int i
= 0; i
< GetViewCount(); ++i
)
5875 EOL eLineEol
= GetViewLineEnding(i
);
5876 if (eLineEol
== EOL_AUTOLINE
|| eLineEol
== EOL_NOENDING
|| eLineEol
== m_lineendings
)
5880 SetViewLineEnding(i
, eEol
);
5882 //CUndo::EndGrouping();
5883 //CUndo::saveundostep;
5888 void CBaseView::SetLineEndingStyle(EOL eEol
)
5890 m_lineendings
= eEol
;
5893 void CBaseView::SetTextType(CFileTextLines::UnicodeType eTextType
)
5895 if (m_texttype
== eTextType
)
5899 m_texttype
= eTextType
;
5904 void CBaseView::AskUserForNewLineEndingsAndTextType(int nTextId
)
5907 return; // nothing to be changed in read-only view
5909 dlg
.view
.LoadString(nTextId
);
5910 dlg
.texttype
= m_texttype
;
5911 dlg
.lineendings
= GetLineEndings();
5912 if (dlg
.DoModal() != IDOK
)
5914 SetTextType(dlg
.texttype
);
5915 ReplaceLineEndings(dlg
.lineendings
);
5919 Replaces lines from source view to this
5921 void CBaseView::UseViewBlock(CBaseView
* pwndView
, int nFirstViewLine
, int nLastViewLine
, std::function
<bool(int)> fnSkip
)
5923 if (!IsViewGood(pwndView
))
5927 CUndo::GetInstance().BeginGrouping();
5929 for (int viewLine
= nFirstViewLine
; viewLine
<= nLastViewLine
; viewLine
++)
5931 bool skip
= fnSkip(viewLine
);
5934 if (GetViewMarked(viewLine
))
5935 SetViewMarked(viewLine
, false);
5938 viewdata line
= pwndView
->GetViewData(viewLine
);
5939 if (line
.ending
!= EOL_NOENDING
)
5940 line
.ending
= m_lineendings
;
5943 case DIFFSTATE_CONFLICTEMPTY
:
5944 case DIFFSTATE_UNKNOWN
:
5945 line
.state
= DIFFSTATE_EMPTY
;
5946 case DIFFSTATE_EMPTY
:
5948 case DIFFSTATE_ADDED
:
5949 case DIFFSTATE_CONFLICTADDED
:
5950 case DIFFSTATE_CONFLICTED
:
5951 case DIFFSTATE_CONFLICTED_IGNORED
:
5952 case DIFFSTATE_IDENTICALADDED
:
5953 case DIFFSTATE_THEIRSADDED
:
5954 case DIFFSTATE_YOURSADDED
:
5955 case DIFFSTATE_IDENTICALREMOVED
:
5956 case DIFFSTATE_REMOVED
:
5957 case DIFFSTATE_THEIRSREMOVED
:
5958 case DIFFSTATE_YOURSREMOVED
:
5959 pwndView
->SetViewState(viewLine
, DIFFSTATE_NORMAL
);
5960 line
.state
= DIFFSTATE_NORMAL
;
5961 case DIFFSTATE_NORMAL
:
5966 bool marked
= GetViewMarked(viewLine
);
5967 SetViewData(viewLine
, line
);
5969 SetViewMarked(viewLine
, false);
5970 if ((m_texttype
== UnicodeType::ASCII
) && (pwndView
->GetTextType() != UnicodeType::ASCII
))
5972 // if this view is in ASCII and the other is not, we have to make sure that
5973 // the text we copy from the other view can actually be saved in ASCII encoding.
5974 // if not, we have to change this views encoding to the same encoding as the other view
5975 BOOL useDefault
= FALSE
;
5976 WideCharToMultiByte(CP_ACP
, WC_NO_BEST_FIT_CHARS
, line
.sLine
, -1, NULL
, 0, 0, &useDefault
);
5977 if (useDefault
) // a default char is required, so the char can not be saved as ASCII
5978 SetTextType(pwndView
->GetTextType());
5981 // normal lines is mostly same but may differ in EOL so any copied line change view state to modified
5982 // TODO: check if copied line is same as original one set modified only when differ
5986 int nRemovedLines
= CleanEmptyLines();
5989 // make sure all non empty line have EOL set but last
5990 // wrong can be last copied line(have eol, but no line under),
5991 // or old last line (line before copied block missing eol, but have line under)
5992 // we'll check all lines to be sure
5993 int nLine
= GetViewCount();
5994 // check last line have no EOL set
5997 if (!IsViewLineEmpty(nLine
))
5999 if (GetViewLineEnding(nLine
) != EOL_NOENDING
)
6001 // we added non last line into empty block on the end (or should we remove eol from this one ?)
6002 // so next line is empty
6003 ASSERT(IsViewLineEmpty(nLine
+1));
6004 // and we can turn it to normal empty line
6005 SetViewData(nLine
+1, viewdata(CString(), DIFFSTATE_ADDED
, 1, EOL_NOENDING
, HIDESTATE_SHOWN
));
6010 // check all (nonlast) line have EOL set
6013 if (!IsViewLineEmpty(nLine
))
6015 if (GetViewLineEnding(nLine
) == EOL_NOENDING
)
6017 SetViewLineEnding(nLine
, m_lineendings
);
6018 // in theory there should be only one line needing fix, but most of time we get over all anyway
6024 UpdateViewLineNumbers();
6027 CUndo::GetInstance().EndGrouping();
6029 if (nRemovedLines
!=0)
6031 // some lines are gone update selection
6033 SetupAllViewSelection(nFirstViewLine
, nLastViewLine
- nRemovedLines
);
6035 BuildAllScreen2ViewVector();
6036 pwndView
->Invalidate();
6040 void CBaseView::MarkBlock(bool marked
, int nFirstViewLine
, int nLastViewLine
)
6044 CUndo::GetInstance().BeginGrouping();
6046 for (int viewLine
= nFirstViewLine
; viewLine
<= nLastViewLine
; viewLine
++)
6047 SetViewMarked(viewLine
, marked
);
6051 CUndo::GetInstance().EndGrouping();
6053 BuildAllScreen2ViewVector();
6058 void CBaseView::LeaveOnlyMarkedBlocks(CBaseView
*pwndView
)
6060 auto fn
= [this](int viewLine
) -> bool { return GetViewMarked(viewLine
) || GetViewState(viewLine
) == DIFFSTATE_EDITED
; };
6061 UseViewBlock(pwndView
, 0, GetViewCount() - 1, fn
);
6064 void CBaseView::UseViewFileOfMarked(CBaseView
*pwndView
)
6066 auto fn
= [this](int viewLine
) -> bool { return !GetViewMarked(viewLine
) || GetViewState(viewLine
) == DIFFSTATE_EDITED
; };
6067 UseViewBlock(pwndView
, 0, GetViewCount() - 1, fn
);
6070 void CBaseView::UseViewFileExceptEdited(CBaseView
*pwndView
)
6072 auto fn
= [this](int viewLine
) -> bool { return GetViewState(viewLine
) == DIFFSTATE_EDITED
; };
6073 UseViewBlock(pwndView
, 0, GetViewCount() - 1, fn
);
6076 int CBaseView::GetIndentCharsForLine(int x
, int y
)
6078 const int maxGuessLine
= 100;
6080 CString line
= GetViewLine(y
);
6081 if (m_nTabMode
& TABMODE_SMARTINDENT
)
6083 // detect left char and right char
6084 TCHAR lc
= x
> 0 ? line
[x
- 1] : '\0';
6085 TCHAR rc
= x
< line
.GetLength() ? line
[x
] : '\0';
6086 if (lc
== ' ' && rc
!= '\t' || rc
== ' ' && lc
!= '\t')
6088 if (lc
== '\t' && rc
!= ' ' || rc
== '\t' && lc
!= ' ')
6090 if (lc
== ' ' && rc
== '\t' || rc
== ' ' && lc
== '\t')
6091 nTabMode
= m_nTabMode
& TABMODE_USESPACES
;
6093 // detect lines nearby
6094 for (int i
= y
- 1, j
= y
+ 1; nTabMode
== -1; --i
, ++j
)
6096 bool above
= i
> 0 && i
>= y
- maxGuessLine
;
6097 bool below
= j
< GetViewCount() && j
<= y
+ maxGuessLine
;
6098 if (!(above
|| below
))
6100 TCHAR ac
= above
? GetViewLine(i
)[0] : '\0';
6101 TCHAR bc
= below
? GetViewLine(j
)[0] : '\0';
6102 if (ac
== ' ' && bc
!= '\t' || bc
== ' ' && ac
!= '\t')
6104 else if (ac
== '\t' && bc
!= ' ' || bc
== '\t' && ac
!= ' ')
6106 else if (ac
== ' ' && bc
== '\t' || bc
== ' ' && ac
== '\t')
6107 nTabMode
= m_nTabMode
& TABMODE_USESPACES
;
6111 nTabMode
= m_nTabMode
& TABMODE_USESPACES
;
6116 x
= CountExpandedChars(line
, x
);
6117 return (m_nTabSize
- (x
% m_nTabSize
));
6124 void CBaseView::AddIndentationForSelectedBlock()
6126 bool bModified
= false;
6127 for (int nViewLine
= m_ptSelectionViewPosStart
.y
; nViewLine
<= m_ptSelectionViewPosEnd
.y
; nViewLine
++)
6129 // skip the line if no character is selected in the last selected line
6130 if (nViewLine
== m_ptSelectionViewPosEnd
.y
&& m_ptSelectionViewPosEnd
.x
== 0)
6135 if (IsLineEmpty(nViewLine
))
6139 const CString
&sLine
= GetViewLine(nViewLine
);
6140 CString sTemp
= sLine
;
6141 if (sTemp
.Trim().IsEmpty())
6143 // skip empty and whitechar only lines
6146 // add tab to line start (alternatively m_nTabSize spaces can be used)
6148 int indentChars
= GetIndentCharsForLine(0, nViewLine
);
6149 tabStr
= indentChars
> 0 ? CString(_T(' '), indentChars
) : _T("\t");
6150 SetViewLine(nViewLine
, tabStr
+ sLine
);
6157 BuildAllScreen2ViewVector();
6161 void CBaseView::RemoveIndentationForSelectedBlock()
6163 bool bModified
= false;
6164 for (int nViewLine
= m_ptSelectionViewPosStart
.y
; nViewLine
<= m_ptSelectionViewPosEnd
.y
; nViewLine
++)
6166 // skip the line if no character is selected in the last selected line
6167 if (nViewLine
== m_ptSelectionViewPosEnd
.y
&& m_ptSelectionViewPosEnd
.x
== 0)
6172 if (IsLineEmpty(nViewLine
))
6176 CString sLine
= GetViewLine(nViewLine
);
6177 // remove up to n spaces from line start
6178 // and one tab (if less then n spaces was removed)
6180 while (nPos
<m_nTabSize
)
6182 switch (sLine
[nPos
])
6194 sLine
.Delete(0, nPos
);
6195 SetViewLine(nViewLine
, sLine
);
6203 BuildAllScreen2ViewVector();
6208 there are two possible versions
6209 - convert tabs to spaces only in front of text (implemented)
6210 - convert all tabs to spaces
6212 void CBaseView::ConvertTabToSpaces()
6214 bool bModified
= false;
6215 for (int nViewLine
= 0; nViewLine
< GetViewCount(); nViewLine
++)
6217 if (IsLineEmpty(nViewLine
))
6221 const CString
&sLine
= GetViewLine(nViewLine
);
6222 bool bTabToConvertFound
= false;
6225 while (nPosIn
<sLine
.GetLength())
6227 switch (sLine
[nPosIn
])
6235 bTabToConvertFound
= true;
6236 nPosOut
= (nPosOut
+m_nTabSize
) - nPosOut
%m_nTabSize
;
6241 if (bTabToConvertFound
)
6243 CString sLineNew
= sLine
;
6244 sLineNew
.Delete(0, nPosIn
);
6245 sLineNew
= CString(' ', nPosOut
) + sLineNew
;
6246 SetViewLine(nViewLine
, sLineNew
);
6254 BuildAllScreen2ViewVector();
6259 there are two possible version
6260 - convert spaces to tabs only in front of text (implemented)
6261 - convert all spaces to tabs
6263 void CBaseView::Tabularize()
6265 bool bModified
= false;
6266 for (int nViewLine
= 0; nViewLine
< GetViewCount(); nViewLine
++)
6268 if (IsLineEmpty(nViewLine
))
6272 const CString
&sLine
= GetViewLine(nViewLine
);
6274 int nTabCount
= 0; // total tabs to be used
6275 int nSpaceCount
= 0; // number of spaces in tab size run
6277 while (nPos
<sLine
.GetLength())
6279 switch (sLine
[nPos
++])
6283 if (++nSpaceCount
< m_nTabSize
)
6297 CString sLineNew
= sLine
;
6298 sLineNew
.Delete(0, nDel
);
6299 sLineNew
= CString('\t', nTabCount
) + sLineNew
;
6300 if (sLine
!=sLineNew
)
6302 SetViewLine(nViewLine
, sLineNew
);
6311 BuildAllScreen2ViewVector();
6315 void CBaseView::RemoveTrailWhiteChars()
6317 bool bModified
= false;
6318 for (int nViewLine
= 0; nViewLine
< GetViewCount(); nViewLine
++)
6320 if (IsLineEmpty(nViewLine
))
6324 const CString
&sLine
= GetViewLine(nViewLine
);
6325 CString sLineNew
= sLine
;
6326 sLineNew
.TrimRight();
6327 if (sLine
.GetLength()!=sLineNew
.GetLength())
6329 SetViewLine(nViewLine
, sLineNew
);
6337 BuildAllScreen2ViewVector();
6341 CBaseView::TWhitecharsProperties
CBaseView::GetWhitecharsProperties()
6343 if (GetViewCount()>10000)
6345 // 10k lines is enough to check
6346 TWhitecharsProperties oRet
= {true, true, true, true};
6349 TWhitecharsProperties oRet
= {};
6350 for (int nViewLine
= 0; nViewLine
< GetViewCount(); nViewLine
++)
6352 if (IsLineEmpty(nViewLine
))
6356 const CString
&sLine
= GetViewLine(nViewLine
);
6357 if (sLine
.IsEmpty())
6361 // check leading whites for convertible tabs and spaces
6363 int nSpaceCount
= 0; // number of spaces in tab size run
6364 while (nPos
<sLine
.GetLength() && (!oRet
.HasSpacesToConvert
|| !oRet
.HasTabsToConvert
))
6366 switch (sLine
[nPos
++])
6369 if (++nSpaceCount
>= m_nTabSize
)
6371 oRet
.HasSpacesToConvert
= true;
6375 oRet
.HasTabsToConvert
= true;
6378 oRet
.HasSpacesToConvert
= true;
6385 // check trailing whites for removable chars
6386 switch (sLine
[sLine
.GetLength()-1])
6390 oRet
.HasTrailWhiteChars
= true;
6394 EOL eLineEol
= GetViewLineEnding(nViewLine
);
6395 if (!oRet
.HasMixedEols
&& (eLineEol
!= m_lineendings
) && (eLineEol
!= EOL_AUTOLINE
) && (eLineEol
!= EOL_NOENDING
))
6397 oRet
.HasMixedEols
= true;
6403 void CBaseView::InsertText(const CString
& sText
)
6407 POINT ptCaretViewPos
= GetCaretViewPosition();
6408 int nLeft
= ptCaretViewPos
.x
;
6409 int nViewLine
= ptCaretViewPos
.y
;
6411 if ((nViewLine
== 0) && (GetViewCount() == 0))
6412 OnChar(VK_RETURN
, 0, 0);
6414 std::vector
<CString
> lines
;
6417 while ((nEolPos
= sText
.Find('\r', nEolPos
)) >= 0)
6419 CString sLine
= sText
.Mid(nStart
, nEolPos
- nStart
);
6420 lines
.push_back(sLine
);
6424 CString sLine
= sText
.Mid(nStart
);
6425 lines
.push_back(sLine
);
6427 int nLinesToPaste
= (int)lines
.size();
6428 if (nLinesToPaste
> 1)
6432 // We want to undo the multiline insertion in a single step.
6433 CUndo::GetInstance().BeginGrouping();
6435 sLine
= GetViewLineChars(nViewLine
);
6436 CString sLineLeft
= sLine
.Left(nLeft
);
6437 CString sLineRight
= sLine
.Right(sLine
.GetLength() - nLeft
);
6438 EOL eOriginalEnding
= GetViewLineEnding(nViewLine
);
6439 viewdata
newLine(L
"", DIFFSTATE_EDITED
, 1, m_lineendings
, HIDESTATE_SHOWN
);
6440 if (!lines
[0].IsEmpty() || !sLineRight
.IsEmpty() || (eOriginalEnding
!= m_lineendings
))
6442 newLine
.sLine
= sLineLeft
+ lines
[0];
6443 SetViewData(nViewLine
, newLine
);
6446 int nInsertLine
= nViewLine
;
6447 for (int i
= 1; i
< nLinesToPaste
- 1; i
++)
6449 newLine
.sLine
= lines
[i
];
6450 InsertViewData(++nInsertLine
, newLine
);
6452 newLine
.sLine
= lines
[nLinesToPaste
- 1] + sLineRight
;
6453 newLine
.ending
= eOriginalEnding
;
6454 InsertViewData(++nInsertLine
, newLine
);
6459 // adds new lines everywhere except me
6460 if (IsViewGood(m_pwndLeft
) && m_pwndLeft
!= this)
6462 m_pwndLeft
->InsertViewEmptyLines(nViewLine
+ 1, nLinesToPaste
- 1);
6464 if (IsViewGood(m_pwndRight
) && m_pwndRight
!= this)
6466 m_pwndRight
->InsertViewEmptyLines(nViewLine
+ 1, nLinesToPaste
- 1);
6468 if (IsViewGood(m_pwndBottom
) && m_pwndBottom
!= this)
6470 m_pwndBottom
->InsertViewEmptyLines(nViewLine
+ 1, nLinesToPaste
- 1);
6474 UpdateViewLineNumbers();
6475 CUndo::GetInstance().EndGrouping();
6477 ptCaretViewPos
= SetupPoint(lines
[nLinesToPaste
- 1].GetLength(), nInsertLine
);
6481 // single line text - just insert it
6482 sLine
= GetViewLineChars(nViewLine
);
6483 sLine
.Insert(nLeft
, sText
);
6484 ptCaretViewPos
= SetupPoint(nLeft
+ sText
.GetLength(), nViewLine
);
6485 SetViewLine(nViewLine
, sLine
);
6486 SetViewState(nViewLine
, DIFFSTATE_EDITED
);
6492 BuildAllScreen2ViewVector();
6493 UpdateCaretViewPosition(ptCaretViewPos
);