OSDN Git Service

crystaledit: Make almost the same code into a common function
[winmerge-jp/winmerge-jp.git] / Externals / crystaledit / editlib / dialogs / ceditreplacedlg.cpp
1 ////////////////////////////////////////////////////////////////////////////
2 //  File:       ceditreplacedlg.cpp
3 //  Version:    1.0.0.0
4 //  Created:    29-Dec-1998
5 //
6 //  Author:     Stcherbatchenko Andrei
7 //  E-mail:     windfall@gmx.de
8 //
9 //  Implementation of the CEditReplaceDlg dialog, a part of Crystal Edit -
10 //  syntax coloring text editor.
11 //
12 //  You are free to use or modify this code to the following restrictions:
13 //  - Acknowledge me somewhere in your about box, simple "Parts of code by.."
14 //  will be enough. If you can't (or don't want to), contact me personally.
15 //  - LEAVE THIS HEADER INTACT
16 ////////////////////////////////////////////////////////////////////////////
17
18 ////////////////////////////////////////////////////////////////////////////
19 //  19-Jul-99
20 //      Ferdinand Prantl:
21 //  +   FEATURE: regular expressions, go to line and things ...
22 //  +   FEATURE: some other things I've forgotten ...
23 //
24 //  ... it's being edited very rapidly so sorry for non-commented
25 //        and maybe "ugly" code ...
26 ////////////////////////////////////////////////////////////////////////////
27 /**
28  *  @file ceditreplacedlg.cpp
29  *
30  *  @brief Implementation of Replace-dialog.
31  */
32 // RCS ID line follows -- this is updated by CVS
33 // $Id$
34
35 #include "StdAfx.h"
36 #include "resource.h"
37 #include "ceditreplacedlg.h"
38 #include "ccrystaleditview.h"
39
40 #include "DDXHelper.h"
41
42 #ifdef _DEBUG
43 #define new DEBUG_NEW
44 #endif
45
46 #ifndef MB_DONT_DISPLAY_AGAIN
47 #define MB_DONT_DISPLAY_AGAIN           0x01000000L     // Additional style.
48 #endif
49
50 /////////////////////////////////////////////////////////////////////////////
51 // CEditReplaceDlg dialog
52
53
54 CEditReplaceDlg::CEditReplaceDlg (CCrystalEditView * pBuddy)
55 : CDialog (CEditReplaceDlg::IDD, nullptr)
56 , m_pBuddy(pBuddy)
57 , m_bMatchCase(false)
58 , m_bWholeWord(false)
59 , m_bRegExp(false)
60 , m_nScope(-1)
61 , m_bDontWrap(false)
62 , m_nDirection(1)
63 , m_bEnableScopeSelection(true)
64 , m_bFound(false)
65 , lastSearch({0})
66 {
67   ASSERT (pBuddy != nullptr);
68 }
69
70 void CEditReplaceDlg::
71 UpdateRegExp ()
72 {
73   if (m_bRegExp)
74     {
75       m_ctlWholeWord.EnableWindow (false);
76       m_bWholeWord = false;
77     }
78   else
79     {
80       m_ctlWholeWord.EnableWindow (true);
81     }
82 }
83
84 void CEditReplaceDlg::
85 DoDataExchange (CDataExchange * pDX)
86 {
87   CDialog::DoDataExchange (pDX);
88   //{{AFX_DATA_MAP(CEditReplaceDlg)
89   DDX_Control (pDX, IDC_EDIT_FINDTEXT, m_ctlFindText);
90   DDX_Control (pDX, IDC_EDIT_REPLACE_WITH, m_ctlReplText);
91   DDX_Control (pDX, IDC_EDIT_WHOLE_WORD, m_ctlWholeWord);
92   DDX_Check (pDX, IDC_EDIT_MATCH_CASE, m_bMatchCase);
93   DDX_Check (pDX, IDC_EDIT_WHOLE_WORD, m_bWholeWord);
94   DDX_Check (pDX, IDC_EDIT_REGEXP, m_bRegExp);
95   DDX_CBString (pDX, IDC_EDIT_FINDTEXT, m_sText);
96   DDX_CBString (pDX, IDC_EDIT_REPLACE_WITH, m_sNewText);
97   DDX_Radio (pDX, IDC_EDIT_SCOPE_SELECTION, m_nScope);
98   DDX_Check (pDX, IDC_EDIT_SCOPE_DONT_WRAP, m_bDontWrap);
99   //}}AFX_DATA_MAP
100   UpdateControls();
101 }
102
103 BEGIN_MESSAGE_MAP (CEditReplaceDlg, CDialog)
104 //{{AFX_MSG_MAP(CEditReplaceDlg)
105 ON_CBN_EDITCHANGE (IDC_EDIT_FINDTEXT, OnChangeEditText)
106 ON_CBN_SELCHANGE (IDC_EDIT_FINDTEXT, OnChangeSelected)
107 ON_BN_CLICKED (IDC_EDIT_REPLACE, OnEditReplace)
108 ON_BN_CLICKED (IDC_EDIT_REPLACE_ALL, OnEditReplaceAll)
109 ON_BN_CLICKED (IDC_EDIT_SKIP, OnEditSkip)
110 ON_BN_CLICKED (IDC_EDIT_FINDPREV, OnEditFindPrev)
111 ON_BN_CLICKED (IDC_EDIT_REGEXP, OnRegExp)
112 //}}AFX_MSG_MAP
113 END_MESSAGE_MAP ()
114
115 BOOL CEditReplaceDlg::PreTranslateMessage(MSG* pMsg)
116 {
117   if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
118     {
119       CButton *pSkip = (CButton*) GetDlgItem (IDC_EDIT_SKIP);
120       if (pSkip->GetButtonStyle () & BS_DEFPUSHBUTTON)
121         {
122           OnEditSkip ();
123         }
124       else
125         {
126           OnEditReplace ();
127         }
128       return true;
129     }
130   return CDialog::PreTranslateMessage(pMsg);
131 }
132
133 /////////////////////////////////////////////////////////////////////////////
134 // CEditReplaceDlg message handlers
135
136 void CEditReplaceDlg::OnChangeEditText ()
137 {
138   UpdateData();
139   UpdateControls();
140 }
141 void CEditReplaceDlg::OnChangeSelected ()
142 {
143   int sel = m_ctlFindText.GetCurSel();
144   if (sel != CB_ERR)
145   {
146     m_ctlFindText.GetLBText(sel, m_sText);
147     m_ctlFindText.SetWindowText(m_sText);
148   }
149   UpdateControls();
150 }
151
152 void CEditReplaceDlg::
153 OnCancel ()
154 {
155   VERIFY (UpdateData ());
156   CDialog::OnCancel ();
157   m_pBuddy->SetFocus();
158 }
159
160 BOOL CEditReplaceDlg::
161 OnInitDialog ()
162 {
163   LangTranslateDialog(m_hWnd);
164   CDialog::OnInitDialog ();
165
166   CMemComboBox::LoadSettings();
167   m_ctlReplText.m_sGroup = _T ("ReplaceText");
168   m_ctlReplText.OnSetfocus ();
169   GetDlgItem (IDC_EDIT_REPLACE_WITH)->GetWindowText (m_sNewText);
170   UpdateData (false);
171   m_ctlFindText.m_sGroup = _T ("FindText");
172   m_ctlFindText.OnSetfocus ();
173
174   GetDlgItem (IDC_EDIT_SCOPE_SELECTION)->EnableWindow (m_bEnableScopeSelection);
175   m_bFound = false;
176
177   return true;
178 }
179
180 LastSearchInfos * CEditReplaceDlg::
181 GetLastSearchInfos() 
182 {
183   return &lastSearch;
184 }
185
186 bool CEditReplaceDlg::
187 DoHighlightText ( bool bNotifyIfNotFound )
188 {
189   ASSERT (m_pBuddy != nullptr);
190   DWORD dwSearchFlags = 0;
191   if (m_bMatchCase)
192     dwSearchFlags |= FIND_MATCH_CASE;
193   if (m_bWholeWord)
194     dwSearchFlags |= FIND_WHOLE_WORD;
195   if (m_bRegExp)
196     dwSearchFlags |= FIND_REGEXP;
197   if (m_nDirection == 0)
198     dwSearchFlags |= FIND_DIRECTION_UP;
199
200   m_ptFoundAt = m_pBuddy->GetSearchPos (dwSearchFlags);
201
202   bool bFound;
203   if (m_nScope == 0)
204     {
205       //  Searching selection only
206       bFound = m_pBuddy->FindTextInBlock (m_sText, m_ptFoundAt, m_ptBlockBegin, m_ptBlockEnd,
207                                           dwSearchFlags, false, &m_ptFoundAt);
208     }
209   else if (m_bDontWrap)
210     {
211       //  Searching whole text, no wrap
212       bFound = m_pBuddy->FindText (m_sText, m_ptFoundAt, dwSearchFlags, false, &m_ptFoundAt);
213     }
214   else
215     {
216       //  Searching whole text, wrap
217       bFound = m_pBuddy->FindText (m_sText, m_ptFoundAt, dwSearchFlags, true, &m_ptFoundAt);
218     }
219
220   if (!bFound)
221     {
222       if ( bNotifyIfNotFound ) 
223       {
224         CString prompt, text(m_sText);
225         prompt.Format (LoadResString(IDS_EDIT_TEXT_NOT_FOUND).c_str(), (LPCTSTR)text);
226         AfxMessageBox (prompt, MB_ICONINFORMATION);
227       }
228       if (m_nScope == 0)
229         m_ptCurrentPos = m_ptBlockBegin;
230
231       return false;
232     }
233
234   m_pBuddy->HighlightText (m_ptFoundAt, m_pBuddy->m_nLastFindWhatLen);
235   return true;
236 }
237
238 bool CEditReplaceDlg::
239 DoReplaceText (LPCTSTR /*pszNewText*/, DWORD dwSearchFlags)
240 {
241   ASSERT (m_pBuddy != nullptr);
242   // m_pBuddy->m_nLastFindWhatLen
243
244   bool bFound;
245   if (m_nScope == 0)
246     {
247       //  Searching selection only
248       bFound = m_pBuddy->FindTextInBlock (m_sText, m_ptFoundAt, m_ptBlockBegin, m_ptBlockEnd,
249                                           dwSearchFlags, false, &m_ptFoundAt);
250     }
251   else if (m_bDontWrap)
252     {
253       //  Searching whole text, no wrap
254       bFound = m_pBuddy->FindText (m_sText, m_ptFoundAt, dwSearchFlags, false, &m_ptFoundAt);
255     }
256   else
257     {
258       //  Searching whole text, wrap
259       bFound = m_pBuddy->FindText (m_sText, m_ptFoundAt, dwSearchFlags, true, &m_ptFoundAt);
260     }
261
262   if (!bFound)
263     {
264       CString prompt, text(m_sText);
265       prompt.Format (LoadResString(IDS_EDIT_TEXT_NOT_FOUND).c_str(), (LPCTSTR)text);
266       AfxMessageBox (prompt, MB_ICONINFORMATION);
267       if (m_nScope == 0)
268         m_ptCurrentPos = m_ptBlockBegin;
269       return false;
270     }
271
272   m_pBuddy->HighlightText (m_ptFoundAt, m_pBuddy->m_nLastFindWhatLen);
273   return true;
274 }
275
276 void CEditReplaceDlg::
277 FindNextPrev (bool bNext)
278 {
279   if (!UpdateData ())
280     return;
281   
282   m_nDirection = bNext;
283   m_ctlFindText.FillCurrent();
284   m_ctlReplText.FillCurrent();
285   CMemComboBox::SaveSettings();
286   UpdateLastSearch ();
287
288   CButton *pSkip = (CButton*) GetDlgItem (IDC_EDIT_SKIP);
289   CButton *pRepl = (CButton*) GetDlgItem (IDC_EDIT_REPLACE);
290
291   if (!m_bFound)
292     {
293       m_bFound = DoHighlightText ( true );
294       if (m_bFound)
295         {
296           pSkip->SetButtonStyle (pSkip->GetButtonStyle () & ~BS_DEFPUSHBUTTON);
297           pRepl->SetButtonStyle (pRepl->GetButtonStyle () | BS_DEFPUSHBUTTON);
298           // pRepl->SetFocus ();
299         }
300       else
301         {
302           pRepl->SetButtonStyle (pRepl->GetButtonStyle () & ~BS_DEFPUSHBUTTON);
303           pSkip->SetButtonStyle (pSkip->GetButtonStyle () | BS_DEFPUSHBUTTON);
304           // pSkip->SetFocus ();
305         }
306       return;
307     }
308
309   if (!m_pBuddy->m_nLastFindWhatLen)
310     if (m_ptFoundAt.y + 1 < m_pBuddy->GetLineCount ())
311       {
312         m_ptFoundAt.x = 0;
313         m_ptFoundAt.y++;
314       }
315     else
316       {
317         m_bFound = false;
318         return;
319       }
320   else
321     m_ptFoundAt.x += 1;
322   m_bFound = DoHighlightText ( true );
323   if (m_bFound)
324     {
325       pSkip->SetButtonStyle (pSkip->GetButtonStyle () & ~BS_DEFPUSHBUTTON);
326       pRepl->SetButtonStyle (pRepl->GetButtonStyle () | BS_DEFPUSHBUTTON);
327       // pRepl->SetFocus ();
328     }
329   else
330     {
331       pRepl->SetButtonStyle (pRepl->GetButtonStyle () & ~BS_DEFPUSHBUTTON);
332       pSkip->SetButtonStyle (pSkip->GetButtonStyle () | BS_DEFPUSHBUTTON);
333       // pSkip->SetFocus ();
334     }
335 }
336
337 void CEditReplaceDlg::
338 OnEditSkip ()
339 {
340   FindNextPrev (true);
341 }
342
343 void CEditReplaceDlg::
344 OnEditFindPrev ()
345 {
346   FindNextPrev (false);
347 }
348
349 void CEditReplaceDlg::
350 OnEditReplace ()
351 {
352   if (!UpdateData ())
353     return;
354
355   m_ctlFindText.FillCurrent();
356   m_ctlReplText.FillCurrent();
357   CMemComboBox::SaveSettings();
358   UpdateLastSearch ();
359
360   if (!m_bFound)
361     {
362       m_bFound = DoHighlightText ( true );
363       CButton *pSkip = (CButton*) GetDlgItem (IDC_EDIT_SKIP);
364       CButton *pRepl = (CButton*) GetDlgItem (IDC_EDIT_REPLACE);
365       if (m_bFound)
366         {
367           pSkip->SetButtonStyle (pSkip->GetButtonStyle () & ~BS_DEFPUSHBUTTON);
368           pRepl->SetButtonStyle (pRepl->GetButtonStyle () | BS_DEFPUSHBUTTON);
369           // pRepl->SetFocus ();
370         }
371       else
372         {
373           pRepl->SetButtonStyle (pRepl->GetButtonStyle () & ~BS_DEFPUSHBUTTON);
374           pSkip->SetButtonStyle (pSkip->GetButtonStyle () | BS_DEFPUSHBUTTON);
375           // pSkip->SetFocus ();
376         }
377       return;
378     }
379   DWORD dwSearchFlags = 0;
380   if (m_bMatchCase)
381     dwSearchFlags |= FIND_MATCH_CASE;
382   if (m_bWholeWord)
383     dwSearchFlags |= FIND_WHOLE_WORD;
384   if (m_bRegExp)
385     dwSearchFlags |= FIND_REGEXP;
386   if (m_nDirection == 0)
387     dwSearchFlags |= FIND_DIRECTION_UP;
388
389   //  We have highlighted text
390   VERIFY (m_pBuddy->ReplaceSelection (m_sNewText, m_sNewText.GetLength(), dwSearchFlags));
391
392   //  Manually recalculate points
393   if (m_bEnableScopeSelection)
394     {
395       if (m_ptBlockBegin.y == m_ptFoundAt.y && m_ptBlockBegin.x > m_ptFoundAt.x)
396         {
397           m_ptBlockBegin.x -= m_pBuddy->m_nLastFindWhatLen;
398           m_ptBlockBegin.x += m_pBuddy->m_nLastReplaceLen;
399         }
400       if (m_ptBlockEnd.y == m_ptFoundAt.y && m_ptBlockEnd.x > m_ptFoundAt.x)
401         {
402           m_ptBlockEnd.x -= m_pBuddy->m_nLastFindWhatLen;
403           m_ptBlockEnd.x += m_pBuddy->m_nLastReplaceLen;
404         }
405     }
406   m_ptFoundAt = m_pBuddy->GetCursorPos ();
407   m_bFound = DoHighlightText ( true );
408
409   m_pBuddy->SaveLastSearch(&lastSearch);
410 }
411
412 void CEditReplaceDlg::
413 OnEditReplaceAll ()
414 {
415   if (!UpdateData ())
416     return;
417
418   m_ctlFindText.FillCurrent();
419   m_ctlReplText.FillCurrent();
420   CMemComboBox::SaveSettings();
421   UpdateLastSearch ();
422
423   int nNumReplaced = 0;
424   bool bWrapped = false;
425   CWaitCursor waitCursor;
426
427
428   if (!m_bFound)
429     {
430       m_ptFoundAt = m_ptCurrentPos;
431       m_bFound = DoHighlightText ( false );
432     }
433
434   CPoint m_ptFirstFound = m_ptFoundAt;
435   bool bGroupWithPrevious = false;
436
437   while (m_bFound)
438     {
439       DWORD dwSearchFlags = 0;
440       if (m_bMatchCase)
441         dwSearchFlags |= FIND_MATCH_CASE;
442       if (m_bWholeWord)
443         dwSearchFlags |= FIND_WHOLE_WORD;
444       if (m_bRegExp)
445         dwSearchFlags |= FIND_REGEXP;
446     
447       //  We have highlighted text
448       VERIFY (m_pBuddy->ReplaceSelection (m_sNewText, m_sNewText.GetLength(), dwSearchFlags, bGroupWithPrevious));
449
450       //  Manually recalculate points
451       if (m_bEnableScopeSelection)
452         {
453           if (m_ptBlockBegin.y == m_ptFoundAt.y && m_ptBlockBegin.x > m_ptFoundAt.x)
454             {
455               m_ptBlockBegin.x -= m_pBuddy->m_nLastFindWhatLen;
456               m_ptBlockBegin.x += m_pBuddy->m_nLastReplaceLen;
457             }
458           if (m_ptBlockEnd.y == m_ptFoundAt.y && m_ptBlockEnd.x > m_ptFoundAt.x)
459             {
460               m_ptBlockEnd.x -= m_pBuddy->m_nLastFindWhatLen;
461               m_ptBlockEnd.x += m_pBuddy->m_nLastReplaceLen;
462             }
463         }
464       // recalculate m_ptFirstFound
465       if (m_ptFirstFound.y == m_ptFoundAt.y && m_ptFirstFound.x > m_ptFoundAt.x)
466         {
467           m_ptFirstFound.x -= m_pBuddy->m_nLastFindWhatLen;
468           m_ptFirstFound.x += m_pBuddy->m_nLastReplaceLen;
469         }
470
471       // calculate the end of the current replacement
472       CPoint m_ptCurrentReplacedEnd = m_pBuddy->GetCursorPos ();
473
474       // m_ptFoundAt.x has two meanings:
475       // (1) One is the position of the word that was found.
476       // (2) The other is next position to search.
477       // The code below calculates the latter.
478       m_ptFoundAt = m_pBuddy->GetCursorPos ();
479       nNumReplaced++;
480
481       // find the next instance
482       m_bFound = DoHighlightText ( false );
483
484       // detect if we just wrapped at end of file
485       if (m_ptFoundAt.y < m_ptCurrentReplacedEnd.y || (m_ptFoundAt.y == m_ptCurrentReplacedEnd.y && m_ptFoundAt.x < m_ptCurrentReplacedEnd.x))
486         bWrapped = true;
487
488       // after wrapping, stop at m_ptFirstFound
489       // so we don't replace twice when replacement string includes replaced string 
490       // (like replace "here" with "there")
491       if (bWrapped)
492         if (m_ptFoundAt.y > m_ptFirstFound.y || (m_ptFoundAt.y == m_ptFirstFound.y && m_ptFoundAt.x >= m_ptFirstFound.x))
493           break;
494
495       bGroupWithPrevious = true;
496     }
497
498   // Let user know how many strings were replaced
499   CString strMessage;
500   CString strNumber;
501   strNumber.Format ( _T("%d"), nNumReplaced );
502   LPCTSTR lpsz = static_cast<LPCTSTR>(strNumber);
503   AfxFormatStrings (strMessage, LoadResString(IDS_NUM_REPLACED).c_str(), &lpsz, 1);
504
505   AfxMessageBox( strMessage, MB_ICONINFORMATION|MB_DONT_DISPLAY_AGAIN, IDS_NUM_REPLACED);
506
507   m_pBuddy->SaveLastSearch(&lastSearch);
508 }
509
510 void CEditReplaceDlg::
511 OnRegExp ()
512 {
513   UpdateData (true);
514   UpdateRegExp ();
515   UpdateData (false);
516 }
517
518 void CEditReplaceDlg::
519 UpdateControls()
520 {
521   GetDlgItem(IDC_EDIT_SKIP)->EnableWindow( !m_sText.IsEmpty() );
522   GetDlgItem(IDC_EDIT_REPLACE)->EnableWindow( !m_sText.IsEmpty() );
523   GetDlgItem(IDC_EDIT_REPLACE_ALL)->EnableWindow( !m_sText.IsEmpty() );
524   
525   UpdateRegExp();
526 }
527
528
529 //
530 // Last search functions
531 //
532 void CEditReplaceDlg::
533 SetLastSearch (LPCTSTR sText, bool bMatchCase, bool bWholeWord, bool bRegExp, int nScope, int nDirection)
534 {
535   lastSearch.m_bMatchCase = bMatchCase;
536   lastSearch.m_bWholeWord = bWholeWord;
537   lastSearch.m_bRegExp = bRegExp;
538   lastSearch.m_sText = sText;
539   lastSearch.m_bNoWrap = m_bDontWrap;
540   lastSearch.m_nDirection = nDirection;
541 }
542
543
544 void CEditReplaceDlg::
545 UpdateLastSearch ()
546 {
547   SetLastSearch (m_sText, m_bMatchCase, m_bWholeWord, m_bRegExp, m_nScope, m_nDirection);
548 }
549
550 void CEditReplaceDlg::
551 UseLastSearch () 
552 {
553   m_bMatchCase = lastSearch.m_bMatchCase;
554   m_bWholeWord = lastSearch.m_bWholeWord;
555   m_bRegExp = lastSearch.m_bRegExp;
556   m_sText = lastSearch.m_sText;
557   m_bDontWrap = lastSearch.m_bNoWrap;
558   m_nDirection = lastSearch.m_nDirection;
559 }
560
561 void CEditReplaceDlg::
562 SetScope(bool bWithSelection)
563 {
564   if (bWithSelection)
565     m_nScope = 0;
566   else
567     m_nScope = 1;
568 }