OSDN Git Service

Various refactorings involving NULL, ASSERT, TRUE and FALSE (7)
[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_nTopSubLinePushed(0)
45 {
46 }
47
48 void CGhostTextView::
49 ReAttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
50 {
51         if (pBuf == nullptr)
52         {
53                 pBuf = LocateTextBuffer ();
54                 // ...
55         }
56         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
57         CCrystalEditViewEx::ReAttachToBuffer(pBuf);
58 }
59
60 void CGhostTextView::
61 AttachToBuffer (CCrystalTextBuffer * pBuf /*= nullptr*/ )
62 {
63         if (pBuf == nullptr)
64         {
65                 pBuf = LocateTextBuffer ();
66                 // ...
67         }
68         m_pGhostTextBuffer = dynamic_cast<CGhostTextBuffer*> (pBuf);
69         CCrystalEditViewEx::AttachToBuffer(pBuf);
70 }
71
72 void CGhostTextView::
73 DetachFromBuffer ()
74 {
75         if (m_pGhostTextBuffer != nullptr)
76                 m_pGhostTextBuffer = nullptr;
77         CCrystalEditViewEx::DetachFromBuffer();
78 }
79
80 void CGhostTextView::popPosition(SCursorPushed Ssrc, CPoint & pt)
81 {
82         pt.x = Ssrc.x;
83         pt.y = m_pGhostTextBuffer->ComputeApparentLine(Ssrc.y, Ssrc.nToFirstReal);
84         // if the cursor was in a trailing ghost line, and this disappeared,
85         // got at the end of the last line
86         if (pt.y >= GetLineCount())
87         {
88                 pt.y = GetLineCount()-1;
89                 pt.x = GetLineLength(pt.y);
90         }
91 }
92
93 void CGhostTextView::pushPosition(SCursorPushed & Sdest, CPoint pt)
94 {
95         Sdest.x = pt.x;
96         Sdest.y = m_pGhostTextBuffer->ComputeRealLineAndGhostAdjustment(pt.y, Sdest.nToFirstReal);
97 }
98
99 void CGhostTextView::PopCursors ()
100 {
101         CPoint ptCursorLast = m_ptCursorLast;
102         popPosition(m_ptCursorPosPushed, ptCursorLast);
103
104         ASSERT_VALIDTEXTPOS (ptCursorLast);
105         SetCursorPos (ptCursorLast);
106
107         popPosition(m_ptSelStartPushed, m_ptSelStart);
108         ASSERT_VALIDTEXTPOS (m_ptSelStart);
109         popPosition(m_ptSelEndPushed, m_ptSelEnd);
110         ASSERT_VALIDTEXTPOS (m_ptSelEnd);
111         popPosition(m_ptAnchorPushed, m_ptAnchor);
112         ASSERT_VALIDTEXTPOS (m_ptAnchor);
113         // laoran 2003/09/03
114         // here is what we did before, maybe we have to do it, but test with pushed positions
115         // SetSelection (ptCursorLast, ptCursorLast);
116         // SetAnchor (ptCursorLast);
117
118         if (m_bDraggingText)
119         {
120                 popPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
121                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextBegin);
122                 popPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
123                 ASSERT_VALIDTEXTPOS(m_ptDraggedTextEnd);
124         }
125         if (m_bDropPosVisible)
126         {
127                 popPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
128                 ASSERT_VALIDTEXTPOS(m_ptSavedCaretPos);
129         }
130         if (m_bSelectionPushed)
131         {
132                 popPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
133                 ASSERT_VALIDTEXTPOS(m_ptSavedSelStart);
134                 popPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
135                 ASSERT_VALIDTEXTPOS(m_ptSavedSelEnd);
136         }
137
138         CPoint ptLastChange;
139         if (m_ptLastChangePushed.y == 0 && m_ptLastChangePushed.nToFirstReal > 0)
140                 ptLastChange = CPoint(-1,-1);
141         else 
142         {
143                 popPosition(m_ptLastChangePushed, ptLastChange);
144                 ASSERT_VALIDTEXTPOS(ptLastChange);
145         }
146         m_pGhostTextBuffer->RestoreLastChangePos(ptLastChange);
147
148         // restore the scrolling position
149         m_nTopSubLine = m_nTopSubLinePushed;
150         if (m_nTopSubLine >= GetSubLineCount())
151                 m_nTopSubLine = GetSubLineCount() - 1;
152         if (m_nTopSubLine < 0)
153                 m_nTopSubLine = 0;
154         int nDummy;
155         GetLineBySubLine( m_nTopSubLine, m_nTopLine, nDummy );
156     RecalcVertScrollBar(true);
157 }
158
159 void CGhostTextView::PushCursors ()
160 {
161         pushPosition(m_ptCursorPosPushed, m_ptCursorPos);
162         pushPosition(m_ptSelStartPushed, m_ptSelStart);
163         pushPosition(m_ptSelEndPushed, m_ptSelEnd);
164         pushPosition(m_ptAnchorPushed, m_ptAnchor);
165         if (m_bDraggingText)
166         {
167                 pushPosition(m_ptDraggedTextBeginPushed, m_ptDraggedTextBegin);
168                 pushPosition(m_ptDraggedTextEndPushed, m_ptDraggedTextEnd);
169         }
170         if (m_bDropPosVisible)
171         {
172                 pushPosition(m_ptSavedCaretPosPushed, m_ptSavedCaretPos);
173         }
174         if (m_bSelectionPushed)
175         {
176                 pushPosition(m_ptSavedSelStartPushed, m_ptSavedSelStart);
177                 pushPosition(m_ptSavedSelEndPushed, m_ptSavedSelEnd);
178         }
179
180         pushPosition(m_ptLastChangePushed, m_pGhostTextBuffer->GetLastChangePos());
181
182         // and top line positions
183         m_nTopSubLinePushed = m_nTopSubLine;
184 }
185
186
187
188
189 int CGhostTextView::ComputeRealLine (int nApparentLine) const
190 {
191         if (m_pGhostTextBuffer == nullptr)
192                 return 0;
193         return m_pGhostTextBuffer->ComputeRealLine(nApparentLine);
194 }
195
196 int CGhostTextView::ComputeApparentLine (int nRealLine) const
197 {
198         return m_pGhostTextBuffer->ComputeApparentLine(nRealLine);
199 }
200
201 void CGhostTextView::GetTextWithoutEmptys (int nStartLine, int nStartChar,
202                 int nEndLine, int nEndChar, CString &text,
203                 CRLFSTYLE nCrlfStyle /*= CRLF_STYLE_AUTOMATIC*/,
204                 bool bExcludeInvisibleLines /*= true*/)
205 {
206   if (m_pGhostTextBuffer != nullptr)
207     m_pGhostTextBuffer->GetTextWithoutEmptys (nStartLine, nStartChar, nEndLine, nEndChar, text, nCrlfStyle, bExcludeInvisibleLines);
208   else
209     text = _T ("");
210 }
211
212 void CGhostTextView::GetTextWithoutEmptysInColumnSelection (CString & text, bool bExcludeInvisibleLines /*= true*/)
213 {
214         if (m_pGhostTextBuffer == nullptr)
215         {
216                 text = _T ("");
217                 return;
218         }
219
220         PrepareSelBounds ();
221
222         CString sEol = m_pGhostTextBuffer->GetStringEol (CRLF_STYLE_DOS);
223
224         int nBufSize = 1;
225         for (int L = m_ptDrawSelStart.y; L <= m_ptDrawSelEnd.y; L++)
226                 nBufSize += GetLineLength (L) + sEol.GetLength ();
227         LPTSTR pszBuf = text.GetBuffer (nBufSize);
228
229         for (int I = m_ptDrawSelStart.y; I <= m_ptDrawSelEnd.y; I++)
230         {
231                 // exclude ghost lines
232                 if ((GetLineFlags(I) & LF_GHOST) || (bExcludeInvisibleLines && (GetLineFlags(I) & LF_INVISIBLE)))
233                         continue;
234
235                 int nSelLeft, nSelRight;
236                 GetColumnSelection (I, nSelLeft, nSelRight);
237                 memcpy (pszBuf, GetLineChars (I) + nSelLeft, sizeof (TCHAR) * (nSelRight - nSelLeft));
238                 pszBuf += (nSelRight - nSelLeft);
239                 memcpy (pszBuf, sEol, sizeof (TCHAR) * sEol.GetLength ());
240                 pszBuf += sEol.GetLength ();
241         }
242         pszBuf[0] = 0;
243         text.ReleaseBuffer ();
244         text.FreeExtra ();
245 }
246
247 HGLOBAL CGhostTextView::PrepareDragData ()
248 {
249         PrepareSelBounds ();
250         if (m_ptDrawSelStart == m_ptDrawSelEnd)
251                 return nullptr;
252
253         CString text;
254         GetTextWithoutEmptys (m_ptDrawSelStart.y, m_ptDrawSelStart.x, m_ptDrawSelEnd.y, m_ptDrawSelEnd.x, text);
255         int cchText = text.GetLength();
256         SIZE_T cbData = (cchText + 1) * sizeof(TCHAR);
257         HGLOBAL hData =::GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, cbData);
258         if (hData == nullptr)
259                 return nullptr;
260
261         LPTSTR pszData = (LPTSTR)::GlobalLock (hData);
262         if (pszData != nullptr)
263                 memcpy (pszData, text, cbData);
264         ::GlobalUnlock (hData);
265
266         m_ptDraggedTextBegin = m_ptDrawSelStart;
267         m_ptDraggedTextEnd = m_ptDrawSelEnd;
268         return hData;
269 }
270
271 /**
272  * @brief Draw selection margin. 
273  * @param [in] pdc         Pointer to draw context.
274  * @param [in] rect        The rectangle to draw.
275  * @param [in] nLineIndex  Index of line in view.
276  * @param [in] nLineNumber Line number to display. if -1, it's not displayed.
277  */
278 void CGhostTextView::DrawMargin (CDC * pdc, const CRect & rect, int nLineIndex, int nLineNumber)
279 {
280         int nRealLineNumber;
281         if (nLineIndex < 0 || GetLineFlags(nLineIndex) & LF_GHOST)
282                 nRealLineNumber = -1;
283         else
284                 nRealLineNumber = ComputeRealLine(nLineIndex) + 1;
285         CCrystalTextView::DrawMargin(pdc, rect, nLineIndex, nRealLineNumber);
286 }