OSDN Git Service

Fix crash in Test
[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 //
11 //    This program is free software; you can redistribute it and/or modify
12 //    it under the terms of the GNU General Public License as published by
13 //    the Free Software Foundation; either version 2 of the License, or
14 //    (at your option) any later version.
15 //
16 //    This program is distributed in the hope that it will be useful,
17 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
18 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 //    GNU General Public License for more details.
20 //
21 //    You should have received a copy of the GNU General Public License
22 //    along with this program; if not, write to the Free Software
23 //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 /////////////////////////////////////////////////////////////////////////////
26
27
28 #include "stdafx.h"
29 #include "GhostTextView.h"
30 #include "GhostTextBuffer.h"
31
32 #ifdef _DEBUG
33 #define new DEBUG_NEW
34 #endif
35
36
37 IMPLEMENT_DYNCREATE (CGhostTextView, CCrystalEditViewEx)
38
39 /** 
40  * @brief Constructor, initializes members.
41  */
42 CGhostTextView::CGhostTextView()
43 : m_pGhostTextBuffer(nullptr)
44 , m_ptCursorPosPushed{}
45 , m_ptSelStartPushed{}
46 , m_ptSelEndPushed{}
47 , m_ptAnchorPushed{}
48 , m_ptDraggedTextBeginPushed{}
49 , m_ptDraggedTextEndPushed{}
50 , m_ptSavedCaretPosPushed{}
51 , m_ptSavedSelStartPushed{}
52 , m_ptSavedSelEndPushed{}
53 , m_ptLastChangePushed{}
54 , m_nTopSubLinePushed(0)
55 {
56 }
57
58 void CGhostTextView::
59 ReAttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
60 {
61         if (pBuf == nullptr)
62         {
63                 pBuf = LocateTextBuffer ();
64                 // ...
65         }
66         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
67         CCrystalEditViewEx::ReAttachToBuffer(pBuf);
68 }
69
70 void CGhostTextView::
71 AttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
72 {
73         if (pBuf == nullptr)
74         {
75                 pBuf = LocateTextBuffer ();
76                 // ...
77         }
78         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
79         CCrystalEditViewEx::AttachToBuffer(pBuf);
80 }
81
82 void CGhostTextView::
83 DetachFromBuffer ()
84 {
85         m_pGhostTextBuffer = nullptr;
86         CCrystalEditViewEx::DetachFromBuffer();
87 }
88
89 void CGhostTextView::popPosition(SCursorPushed Ssrc, CPoint & pt)
90 {
91         pt.x = Ssrc.x;
92         pt.y = m_pGhostTextBuffer->ComputeApparentLine(Ssrc.y, Ssrc.nToFirstReal);
93         // if the cursor was in a trailing ghost line, and this disappeared,
94         // got at the end of the last line
95         if (pt.y >= GetLineCount())
96         {
97                 pt.y = GetLineCount()-1;
98                 pt.x = GetLineLength(pt.y);
99         }
100         if (pt.y < 0)
101                 pt.y = 0;
102 }
103
104 void CGhostTextView::pushPosition(SCursorPushed & Sdest, CPoint pt)
105 {
106         Sdest.x = pt.x;
107         if (m_pGhostTextBuffer)
108                 Sdest.y = m_pGhostTextBuffer->ComputeRealLineAndGhostAdjustment(pt.y, Sdest.nToFirstReal);
109         else
110                 Sdest.y = pt.y;
111 }
112
113 void CGhostTextView::PopCursors ()
114 {
115         CPoint ptCursorLast = m_ptCursorLast;
116         popPosition(m_ptCursorPosPushed, ptCursorLast);
117
118         ASSERT_VALIDTEXTPOS (ptCursorLast);
119         SetCursorPos (ptCursorLast);
120
121         popPosition(m_ptSelStartPushed, m_ptSelStart);
122         ASSERT_VALIDTEXTPOS (m_ptSelStart);
123         popPosition(m_ptSelEndPushed, m_ptSelEnd);
124         ASSERT_VALIDTEXTPOS (m_ptSelEnd);
125         popPosition(m_ptAnchorPushed, m_ptAnchor);
126         ASSERT_VALIDTEXTPOS (m_ptAnchor);
127         // laoran 2003/09/03
128         // here is what we did before, maybe we have to do it, but test with pushed positions
129         // SetSelection (ptCursorLast, ptCursorLast);
130         // SetAnchor (ptCursorLast);
131
132         if (m_bDraggingText)
133         {
134                 popPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
135                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextBegin);
136                 popPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
137                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextEnd);
138         }
139         if (m_bDropPosVisible)
140         {
141                 popPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
142                 ASSERT_VALIDTEXTPOS(m_ptSavedCaretPos);
143         }
144         if (m_bSelectionPushed)
145         {
146                 popPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
147                 ASSERT_VALIDTEXTPOS(m_ptSavedSelStart);
148                 popPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
149                 ASSERT_VALIDTEXTPOS(m_ptSavedSelEnd);
150         }
151
152         CPoint ptLastChange;
153         if (m_ptLastChangePushed.y == 0 && m_ptLastChangePushed.nToFirstReal > 0)
154                 ptLastChange = CPoint(-1,-1);
155         else 
156         {
157                 popPosition(m_ptLastChangePushed, ptLastChange);
158                 ASSERT_VALIDTEXTPOS(ptLastChange);
159         }
160         m_pGhostTextBuffer->RestoreLastChangePos(ptLastChange);
161
162         // restore the scrolling position
163         m_nTopSubLine = m_nTopSubLinePushed;
164         if (m_nTopSubLine >= GetSubLineCount())
165                 m_nTopSubLine = GetSubLineCount() - 1;
166         if (m_nTopSubLine < 0)
167                 m_nTopSubLine = 0;
168         int nDummy;
169         GetLineBySubLine( m_nTopSubLine, m_nTopLine, nDummy );
170     RecalcVertScrollBar(true);
171     RecalcHorzScrollBar();
172 }
173
174 void CGhostTextView::PushCursors ()
175 {
176         pushPosition(m_ptCursorPosPushed, m_ptCursorPos);
177         pushPosition(m_ptSelStartPushed, m_ptSelStart);
178         pushPosition(m_ptSelEndPushed, m_ptSelEnd);
179         pushPosition(m_ptAnchorPushed, m_ptAnchor);
180         if (m_bDraggingText)
181         {
182                 pushPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
183                 pushPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
184         }
185         if (m_bDropPosVisible)
186         {
187                 pushPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
188         }
189         if (m_bSelectionPushed)
190         {
191                 pushPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
192                 pushPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
193         }
194
195         pushPosition(m_ptLastChangePushed, m_pGhostTextBuffer ? m_pGhostTextBuffer->GetLastChangePos() : CPoint{0, 0});
196
197         // and top line positions
198         m_nTopSubLinePushed = m_nTopSubLine;
199 }
200
201
202
203
204 int CGhostTextView::ComputeRealLine (int nApparentLine) const
205 {
206         if (m_pGhostTextBuffer == nullptr)
207                 return 0;
208         return m_pGhostTextBuffer->ComputeRealLine(nApparentLine);
209 }
210
211 int CGhostTextView::ComputeApparentLine (int nRealLine) const
212 {
213         return m_pGhostTextBuffer->ComputeApparentLine(nRealLine);
214 }
215
216 void CGhostTextView::GetTextWithoutEmptys (int nStartLine, int nStartChar,
217                 int nEndLine, int nEndChar, CString &text,
218                 CRLFSTYLE nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/,
219                 bool bExcludeInvisibleLines /*= true*/)
220 {
221   if (m_pGhostTextBuffer != nullptr)
222     m_pGhostTextBuffer->GetTextWithoutEmptys (nStartLine, nStartChar, nEndLine, nEndChar, text, nCrlfStyle, bExcludeInvisibleLines);
223   else
224     text = _T ("");
225 }
226
227 void CGhostTextView::GetTextWithoutEmptysInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/)
228 {
229         if (m_pGhostTextBuffer == nullptr)
230         {
231                 text = _T ("");
232                 return;
233         }
234
235         PrepareSelBounds ();
236
237         CString sEol = m_pGhostTextBuffer->GetStringEol (CRLF_STYLE_DOS);
238
239         int nBufSize = 1;
240         for (int L = m_ptDrawSelStart.y; L <= m_ptDrawSelEnd.y; L++)
241                 nBufSize += GetLineLength (L) + sEol.GetLength ();
242         LPTSTR pszBuf = text.GetBuffer (nBufSize);
243
244         for (int I = m_ptDrawSelStart.y; I <= m_ptDrawSelEnd.y; I++)
245         {
246                 // exclude ghost lines
247                 if ((GetLineFlags(I) & LF_GHOST) || (bExcludeInvisibleLines && (GetLineFlags(I) & LF_INVISIBLE)))
248                         continue;
249
250                 int nSelLeft, nSelRight;
251                 GetColumnSelection (I, nSelLeft, nSelRight);
252                 memcpy (pszBuf, GetLineChars (I) + nSelLeft, sizeof (TCHAR) * (nSelRight - nSelLeft));
253                 pszBuf += (nSelRight - nSelLeft);
254                 memcpy (pszBuf, sEol, sizeof (TCHAR) * sEol.GetLength ());
255                 pszBuf += sEol.GetLength ();
256         }
257         pszBuf[0] = 0;
258         text.ReleaseBuffer ();
259         text.FreeExtra ();
260 }
261
262 HGLOBAL CGhostTextView::PrepareDragData ()
263 {
264         PrepareSelBounds ();
265         if (m_ptDrawSelStart == m_ptDrawSelEnd)
266                 return nullptr;
267
268         CString text;
269         GetTextWithoutEmptys (m_ptDrawSelStart.y, m_ptDrawSelStart.x, m_ptDrawSelEnd.y, m_ptDrawSelEnd.x, text);
270         int cchText = text.GetLength();
271         SIZE_T cbData = (cchText + 1) * sizeof(TCHAR);
272         HGLOBAL hData =::GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, cbData);
273         if (hData == nullptr)
274                 return nullptr;
275
276         LPTSTR pszData = (LPTSTR)::GlobalLock (hData);
277         if (pszData != nullptr)
278                 memcpy (pszData, text, cbData);
279         ::GlobalUnlock (hData);
280
281         m_ptDraggedTextBegin = m_ptDrawSelStart;
282         m_ptDraggedTextEnd = m_ptDrawSelEnd;
283         return hData;
284 }
285
286 /**
287  * @brief Draw selection margin. 
288  * @param [in] pdc         Pointer to draw context.
289  * @param [in] rect        The rectangle to draw.
290  * @param [in] nLineIndex  Index of line in view.
291  * @param [in] nLineNumber Line number to display. if -1, it's not displayed.
292  */
293 void CGhostTextView::DrawMargin (const CRect & rect, int nLineIndex, int nLineNumber)
294 {
295         int nRealLineNumber;
296         if (nLineIndex < 0 || GetLineFlags(nLineIndex) & LF_GHOST)
297                 nRealLineNumber = -1;
298         else
299                 nRealLineNumber = ComputeRealLine(nLineIndex) + 1;
300         CCrystalTextView::DrawMargin(rect, nLineIndex, nRealLineNumber);
301 }