OSDN Git Service

Fix the issue where the Apache Tika plugin becomes enabled again when reopening the...
[winmerge-jp/winmerge-jp.git] / Src / GhostTextView.cpp
1 ////////////////////////////////////////////////////////////////////////////
2 //  File:       GhostTextView.h
3 //  Version:    1.0.0.0
4 //  Created:    31-Jul-2003
5 //
6 /////////////////////////////////////////////////////////////////////////////
7 //    WinMerge:  an interactive diff/merge utility
8 //    Copyright (C) 1997-2000  Thingamahoochie Software
9 //    Author: Dean Grimm
10 //    SPDX-License-Identifier: GPL-2.0-or-later
11 /////////////////////////////////////////////////////////////////////////////
12
13
14 #include "stdafx.h"
15 #include "GhostTextView.h"
16 #include "GhostTextBuffer.h"
17
18 #ifdef _DEBUG
19 #define new DEBUG_NEW
20 #endif
21
22
23 IMPLEMENT_DYNCREATE (CGhostTextView, CCrystalEditViewEx)
24
25 /** 
26  * @brief Constructor, initializes members.
27  */
28 CGhostTextView::CGhostTextView()
29 : m_pGhostTextBuffer(nullptr)
30 , m_ptCursorPosPushed{}
31 , m_ptSelStartPushed{}
32 , m_ptSelEndPushed{}
33 , m_ptAnchorPushed{}
34 , m_ptDraggedTextBeginPushed{}
35 , m_ptDraggedTextEndPushed{}
36 , m_ptSavedCaretPosPushed{}
37 , m_ptSavedSelStartPushed{}
38 , m_ptSavedSelEndPushed{}
39 , m_ptLastChangePushed{}
40 , m_nTopSubLinePushed(0)
41 , m_nOffsetCharPushed(0)
42 {
43 }
44
45 void CGhostTextView::
46 ReAttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
47 {
48         if (pBuf == nullptr)
49         {
50                 pBuf = LocateTextBuffer ();
51                 // ...
52         }
53         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
54         CCrystalEditViewEx::ReAttachToBuffer(pBuf);
55 }
56
57 void CGhostTextView::
58 AttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
59 {
60         if (pBuf == nullptr)
61         {
62                 pBuf = LocateTextBuffer ();
63                 // ...
64         }
65         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
66         CCrystalEditViewEx::AttachToBuffer(pBuf);
67 }
68
69 void CGhostTextView::
70 DetachFromBuffer ()
71 {
72         m_pGhostTextBuffer = nullptr;
73         CCrystalEditViewEx::DetachFromBuffer();
74 }
75
76 void CGhostTextView::popPosition(SCursorPushed Ssrc, CEPoint & pt)
77 {
78         pt.x = Ssrc.x;
79         pt.y = m_pGhostTextBuffer->ComputeApparentLine(Ssrc.y, Ssrc.nToFirstReal);
80         // if the cursor was in a trailing ghost line, and this disappeared,
81         // got at the end of the last line
82         if (pt.y >= GetLineCount())
83         {
84                 pt.y = GetLineCount()-1;
85                 pt.x = GetLineLength(pt.y);
86         }
87         if (pt.y < 0)
88                 pt.y = 0;
89 }
90
91 void CGhostTextView::pushPosition(SCursorPushed & Sdest, CEPoint pt)
92 {
93         Sdest.x = pt.x;
94         if (m_pGhostTextBuffer)
95                 Sdest.y = m_pGhostTextBuffer->ComputeRealLineAndGhostAdjustment(pt.y, Sdest.nToFirstReal);
96         else
97                 Sdest.y = pt.y;
98 }
99
100 void CGhostTextView::PopCursors ()
101 {
102         CEPoint ptCursorLast = m_ptCursorLast;
103         popPosition(m_ptCursorPosPushed, ptCursorLast);
104
105         ASSERT_VALIDTEXTPOS (ptCursorLast);
106         SetCursorPos (ptCursorLast);
107
108         popPosition(m_ptSelStartPushed, m_ptSelStart);
109         ASSERT_VALIDTEXTPOS (m_ptSelStart);
110         popPosition(m_ptSelEndPushed, m_ptSelEnd);
111         ASSERT_VALIDTEXTPOS (m_ptSelEnd);
112         popPosition(m_ptAnchorPushed, m_ptAnchor);
113         ASSERT_VALIDTEXTPOS (m_ptAnchor);
114         // laoran 2003/09/03
115         // here is what we did before, maybe we have to do it, but test with pushed positions
116         // SetSelection (ptCursorLast, ptCursorLast);
117         // SetAnchor (ptCursorLast);
118
119         if (m_bDraggingText)
120         {
121                 popPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
122                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextBegin);
123                 popPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
124                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextEnd);
125         }
126         if (m_bDropPosVisible)
127         {
128                 popPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
129                 ASSERT_VALIDTEXTPOS(m_ptSavedCaretPos);
130         }
131         if (m_bSelectionPushed)
132         {
133                 popPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
134                 ASSERT_VALIDTEXTPOS(m_ptSavedSelStart);
135                 popPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
136                 ASSERT_VALIDTEXTPOS(m_ptSavedSelEnd);
137         }
138
139         CEPoint ptLastChange;
140         if (m_ptLastChangePushed.y == 0 && m_ptLastChangePushed.nToFirstReal > 0)
141                 ptLastChange = CEPoint(-1,-1);
142         else 
143         {
144                 popPosition(m_ptLastChangePushed, ptLastChange);
145                 ASSERT_VALIDTEXTPOS(ptLastChange);
146         }
147         m_pGhostTextBuffer->RestoreLastChangePos(ptLastChange);
148
149         // restore the scrolling position
150         m_nTopSubLine = m_nTopSubLinePushed;
151         if (m_nTopSubLine >= GetSubLineCount())
152                 m_nTopSubLine = GetSubLineCount() - 1;
153         if (m_nTopSubLine < 0)
154                 m_nTopSubLine = 0;
155         int nDummy;
156         GetLineBySubLine( m_nTopSubLine, m_nTopLine, nDummy );
157         const int nMaxLineLength = GetMaxLineLength(m_nTopLine, GetScreenLines());
158         m_nOffsetChar = (m_nOffsetCharPushed < nMaxLineLength) ? m_nOffsetCharPushed : nMaxLineLength;
159     RecalcVertScrollBar(true);
160     InvalidateHorzScrollBar();
161 }
162
163 void CGhostTextView::PushCursors ()
164 {
165         pushPosition(m_ptCursorPosPushed, m_ptCursorPos);
166         pushPosition(m_ptSelStartPushed, m_ptSelStart);
167         pushPosition(m_ptSelEndPushed, m_ptSelEnd);
168         pushPosition(m_ptAnchorPushed, m_ptAnchor);
169         if (m_bDraggingText)
170         {
171                 pushPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
172                 pushPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
173         }
174         if (m_bDropPosVisible)
175         {
176                 pushPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
177         }
178         if (m_bSelectionPushed)
179         {
180                 pushPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
181                 pushPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
182         }
183
184         pushPosition(m_ptLastChangePushed, m_pGhostTextBuffer ? m_pGhostTextBuffer->GetLastChangePos() : CEPoint{0, 0});
185
186         // and top line positions
187         m_nTopSubLinePushed = m_nTopSubLine;
188         m_nOffsetCharPushed = m_nOffsetChar;
189 }
190
191
192
193
194 int CGhostTextView::ComputeRealLine (int nApparentLine) const
195 {
196         if (m_pGhostTextBuffer == nullptr)
197                 return 0;
198         return m_pGhostTextBuffer->ComputeRealLine(nApparentLine);
199 }
200
201 int CGhostTextView::ComputeApparentLine (int nRealLine) const
202 {
203         return m_pGhostTextBuffer->ComputeApparentLine(nRealLine);
204 }
205
206 void CGhostTextView::GetTextWithoutEmptys (int nStartLine, int nStartChar,
207                 int nEndLine, int nEndChar, CString &text,
208                 CRLFSTYLE nCrlfStyle /*= CRLFSTYLE::AUTOMATIC*/,
209                 bool bExcludeInvisibleLines /*= true*/)
210 {
211         if (m_pGhostTextBuffer != nullptr)
212         {
213                 String sText;
214                 m_pGhostTextBuffer->GetTextWithoutEmptys(nStartLine, nStartChar, nEndLine, nEndChar, sText, nCrlfStyle, bExcludeInvisibleLines);
215                 text.SetString(sText.c_str(), static_cast<int>(sText.length())); // TODO: Use String instead of CString
216         }
217         else
218                 text.Empty();
219 }
220
221 void CGhostTextView::GetTextWithoutEmptysInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/)
222 {
223         if (m_pGhostTextBuffer == nullptr)
224         {
225                 text.Empty();
226                 return;
227         }
228
229         PrepareSelBounds ();
230
231         CString sEol = m_pGhostTextBuffer->GetStringEol (CRLFSTYLE::DOS);
232
233         int nBufSize = 1;
234         for (int L = m_ptDrawSelStart.y; L <= m_ptDrawSelEnd.y; L++)
235                 nBufSize += GetLineLength (L) + sEol.GetLength ();
236         tchar_t* pszBuf = text.GetBuffer (nBufSize);
237
238         for (int I = m_ptDrawSelStart.y; I <= m_ptDrawSelEnd.y; I++)
239         {
240                 // exclude ghost lines
241                 if ((GetLineFlags(I) & LF_GHOST) || (bExcludeInvisibleLines && (GetLineFlags(I) & LF_INVISIBLE)))
242                         continue;
243
244                 int nSelLeft, nSelRight;
245                 GetColumnSelection (I, nSelLeft, nSelRight);
246                 memcpy (pszBuf, GetLineChars (I) + nSelLeft, sizeof (tchar_t) * (nSelRight - nSelLeft));
247                 pszBuf += (nSelRight - nSelLeft);
248                 memcpy (pszBuf, sEol, sizeof (tchar_t) * sEol.GetLength ());
249                 pszBuf += sEol.GetLength ();
250         }
251         pszBuf[0] = 0;
252         text.ReleaseBuffer ();
253         text.FreeExtra ();
254 }
255
256 HGLOBAL CGhostTextView::PrepareDragData ()
257 {
258         PrepareSelBounds ();
259         if (m_ptDrawSelStart == m_ptDrawSelEnd)
260                 return nullptr;
261
262         CString text;
263         GetTextWithoutEmptys (m_ptDrawSelStart.y, m_ptDrawSelStart.x, m_ptDrawSelEnd.y, m_ptDrawSelEnd.x, text);
264         int cchText = text.GetLength();
265         SIZE_T cbData = (cchText + 1) * sizeof(tchar_t);
266         HGLOBAL hData =::GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, cbData);
267         if (hData == nullptr)
268                 return nullptr;
269
270         tchar_t* pszData = (tchar_t*)::GlobalLock (hData);
271         if (pszData != nullptr)
272                 memcpy (pszData, text, cbData);
273         ::GlobalUnlock (hData);
274
275         m_ptDraggedTextBegin = m_ptDrawSelStart;
276         m_ptDraggedTextEnd = m_ptDrawSelEnd;
277         return hData;
278 }
279
280 /**
281  * @brief Draw selection margin. 
282  * @param [in] pdc         Pointer to draw context.
283  * @param [in] rect        The rectangle to draw.
284  * @param [in] nLineIndex  Index of line in view.
285  * @param [in] nLineNumber Line number to display. if -1, it's not displayed.
286  */
287 void CGhostTextView::DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
288 {
289         int nRealLineNumber;
290         if (nLineIndex < 0 || GetLineFlags(nLineIndex) & LF_GHOST)
291                 nRealLineNumber = -1;
292         else
293                 nRealLineNumber = ComputeRealLine(nLineIndex) + 1;
294         CCrystalTextView::DrawMargin(rect, nLineIndex, nRealLineNumber);
295 }