OSDN Git Service

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