CPatch: New memory management
[TortoiseGit.git] / src / Utils / ACEdit.cpp
blobaff40939317e351bc06cc71ed5f197a8dfe9c40e
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (c) 2003 by Andreas Kapust <info@akinstaller.de>; <http://www.codeproject.com/Articles/2607/AutoComplete-without-IAutoComplete>
4 // Copyright (C) 2009, 2012-2013, 2015-2016, 2018 - TortoiseGit
6 // Licensed under: The Code Project Open License (CPOL); <http://www.codeproject.com/info/cpol10.aspx>
8 // ACEdit.cpp: Implementierungsdatei
9 //
11 #include "stdafx.h"
12 #include "ACEdit.h"
13 #include <io.h>
14 #include "StringUtils.h"
16 #ifdef _DEBUG
17 #define new DEBUG_NEW
18 #undef THIS_FILE
19 static char THIS_FILE[] = __FILE__;
20 #endif
22 #define _EDIT_ 1
23 #define _COMBOBOX_ 2
25 /////////////////////////////////////////////////////////////////////////////
26 // CACEdit
28 CACEdit::CACEdit()
30 m_iMode = _MODE_STANDARD_;
31 m_iType = -1;
32 m_pEdit = nullptr;
33 m_CursorMode = false;
34 m_PrefixChar = L'\0';
35 m_szDrive[0] = L'\0';
36 m_szDir[0] = L'\0';
37 m_szFname[0] = L'\0';
38 m_szExt[0] = L'\0';
41 /*********************************************************************/
43 CACEdit::~CACEdit()
45 DestroyWindow();
48 /*********************************************************************/
50 BEGIN_MESSAGE_MAP(CACEdit, CWnd)
51 //{{AFX_MSG_MAP(CACEdit)
52 ON_CONTROL_REFLECT(EN_KILLFOCUS, OnKillfocus)
53 ON_CONTROL_REFLECT(CBN_KILLFOCUS, OnKillfocus)
54 ON_WM_KEYDOWN()
55 ON_CONTROL_REFLECT(EN_CHANGE, OnChange)
56 ON_CONTROL_REFLECT(CBN_EDITCHANGE, OnChange)
57 ON_CONTROL_REFLECT(CBN_DROPDOWN, OnCloseList)
58 //}}AFX_MSG_MAP
59 ON_MESSAGE(ENAC_UPDATE,OnUpdateFromList)
60 END_MESSAGE_MAP()
62 /*********************************************************************/
64 void CACEdit::SetMode(int iMode)
66 if(m_iType == -1)
67 Init();
69 m_iMode = iMode;
72 ** Vers. 1.1
73 ** NEW: _MODE_CURSOR_O_LIST_
75 if(iMode == _MODE_CURSOR_O_LIST_)
76 m_iMode |= _MODE_STANDARD_;
78 if(iMode & _MODE_FILESYSTEM_)
79 m_SeparationStr = L'\\';
81 // Vers. 1.2
82 if(iMode & _MODE_FIND_ALL_)
84 m_Liste.m_lMode |= _MODE_FIND_ALL_;
88 /*********************************************************************/
90 void CACEdit::Init()
92 CString szClassName = AfxRegisterWndClass(CS_CLASSDC|CS_SAVEBITS|CS_HREDRAW|CS_VREDRAW,
93 0,(HBRUSH) (COLOR_WINDOW), 0);
94 CRect rcWnd,rcWnd1;
95 GetWindowRect(rcWnd);
97 VERIFY(m_Liste.CreateEx(WS_EX_TOOLWINDOW,
98 szClassName, nullptr,
99 WS_THICKFRAME | WS_CHILD | WS_BORDER |
100 WS_CLIPSIBLINGS | WS_OVERLAPPED,
101 CRect(rcWnd.left, rcWnd.top +20, rcWnd.left+ 200, rcWnd.top+200),
102 GetDesktopWindow(),
103 0x3E8, nullptr));
105 CString m_ClassName;
106 ::GetClassName(GetSafeHwnd(), CStrBuf(m_ClassName, 32), 32);
108 if (m_ClassName.Compare(L"Edit") == 0)
109 m_iType = _EDIT_;
110 else
112 if (m_ClassName.Compare(L"ComboBox") == 0)
114 m_iType = _COMBOBOX_;
116 m_pEdit = (CEdit*)GetWindow(GW_CHILD);
117 VERIFY(m_pEdit);
118 ::GetClassName(m_pEdit->GetSafeHwnd(), CStrBuf(m_ClassName, 32), 32);
119 VERIFY(m_ClassName.Compare(L"Edit") == 0);
123 if(m_iType == -1)
125 ASSERT(0);
126 return;
129 m_Liste.Init(this);
132 /*********************************************************************/
134 void CACEdit::AddSearchStrings(LPCTSTR Strings[])
136 int i = 0;
137 LPCTSTR str;
138 if(m_iType == -1) {ASSERT(0); return;}
140 m_Liste.RemoveAll();
144 str = Strings[i];
145 if(str)
147 m_Liste.AddSearchString(str);
150 i++;
152 while(str);
154 m_Liste.SortSearchList();
157 /*********************************************************************/
159 void CACEdit::AddSearchString(LPCTSTR lpszString)
161 if(m_iType == -1) {ASSERT(0); return;}
163 m_Liste.AddSearchString(lpszString);
166 /*********************************************************************/
168 void CACEdit::RemoveSearchAll()
170 if(m_iType == -1) {ASSERT(0); return;}
172 m_Liste.RemoveAll();
175 /*********************************************************************/
177 void CACEdit::OnKillfocus()
179 if(m_Liste.GetSafeHwnd()) // fix Vers 1.1
180 m_Liste.ShowWindow(false);
183 /*********************************************************************/
185 void CACEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
187 if(!HandleKey(nChar,false))
188 CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
191 /*********************************************************************/
193 bool CACEdit::HandleKey(UINT nChar, bool m_bFromChild)
195 if (nChar == VK_ESCAPE || nChar == VK_RETURN && !m_Liste.IsWindowVisible())
197 m_Liste.ShowWindow(false);
198 return true;
201 if (nChar == VK_DOWN || nChar == VK_UP
202 || nChar == VK_PRIOR || nChar == VK_NEXT
203 || nChar == VK_HOME || nChar == VK_END || nChar == VK_RETURN)
206 ** Vers. 1.1
207 ** NEW: _MODE_CURSOR_O_LIST_
209 if(!m_Liste.IsWindowVisible() && (m_iMode & _MODE_CURSOR_O_LIST_))
211 GetWindowText(m_EditText);
212 if(m_EditText.IsEmpty())
214 m_Liste.CopyList();
215 return true;
219 if(m_Liste.IsWindowVisible())
221 int pos;
224 if(m_iMode & _MODE_STANDARD_
225 || m_iMode & _MODE_FILESYSTEM_
226 || m_iMode & _MODE_FS_START_DIR_)
228 m_CursorMode = true;
230 if(!m_bFromChild)
231 m_EditText = m_Liste.GetNextString(nChar);
232 else
233 m_EditText = m_Liste.GetString();
235 if(m_iMode & _MODE_FILESYSTEM_)
237 if (CStringUtils::EndsWith(m_EditText, L'\\'))
238 m_EditText = m_EditText.Left(m_EditText.GetLength() - 1);
241 if (nChar != VK_RETURN)
242 m_Liste.SelectItem(m_Liste.GetSelectedItem());
243 else
245 m_Liste.SelectItem(-1);
246 SetWindowText(m_EditText);
247 pos = m_EditText.GetLength();
249 if (m_iType == _COMBOBOX_)
251 m_pEdit->SetSel(pos, pos, true);
252 m_pEdit->SetModify(true);
255 if (m_iType == _EDIT_)
257 ((CEdit*)this)->SetSel(pos, pos, true);
258 ((CEdit*)this)->SetModify(true);
262 GetParent()->SendMessage(ENAC_UPDATE, WM_KEYDOWN, GetDlgCtrlID());
263 m_CursorMode = false;
264 if (nChar == VK_RETURN)
265 m_Liste.ShowWindow(false);
266 return true;
269 if(m_iMode & _MODE_SEPARATION_)
271 CString m_Text,m_Left,m_Right;
272 int left,right,pos2=0,len;
274 m_CursorMode = true;
276 GetWindowText(m_EditText);
278 if(m_iType == _EDIT_)
279 pos2 = LOWORD(((CEdit*)this)->CharFromPos(GetCaretPos()));
281 if(m_iType == _COMBOBOX_)
282 pos2 = m_pEdit->CharFromPos(m_pEdit->GetCaretPos());
284 left = FindSepLeftPos(pos2-1,true);
285 right = FindSepRightPos(pos2);
287 m_Text = m_EditText.Left(left);
289 if(!m_bFromChild)
290 m_Text += m_Liste.GetNextString(nChar);
291 else
292 m_Text += m_Liste.GetString();
294 if (nChar != VK_RETURN)
295 m_Liste.SelectItem(m_Liste.GetSelectedItem());
296 else
298 m_Liste.SelectItem(-1);
299 m_Text += m_EditText.Mid(right);
300 len = m_Liste.GetString().GetLength();
302 m_Text += this->m_SeparationStr;
304 SetWindowText(m_Text);
305 GetParent()->SendMessage(ENAC_UPDATE, WM_KEYDOWN, GetDlgCtrlID());
307 right = FindSepLeftPos2(pos2 - 1);
308 left -= right;
309 len += right;
311 left += m_SeparationStr.GetLength();
313 if (m_iType == _EDIT_)
315 ((CEdit*)this)->SetModify(true);
316 ((CEdit*)this)->SetSel(left + len, left + len, false);
319 if (m_iType == _COMBOBOX_)
321 m_pEdit->SetModify(true);
322 m_pEdit->SetSel(left, left + len, true);
325 m_CursorMode = false;
326 if (nChar == VK_RETURN)
327 m_Liste.ShowWindow(false);
328 return true;
332 return false;
335 /*********************************************************************/
337 void CACEdit::OnChange()
339 CString m_Text;
340 int pos=0,len;
342 if(m_iType == -1)
343 {ASSERT(0); return;}
345 GetWindowText(m_EditText);
346 len = m_EditText.GetLength();
347 //----------------------------------------------
348 if(m_iMode & _MODE_FILESYSTEM_ || m_iMode & _MODE_FS_START_DIR_)
350 if(!m_CursorMode)
352 if(m_iType == _EDIT_)
353 pos = LOWORD(((CEdit*)this)->CharFromPos(GetCaretPos()));
355 if(m_iType == _COMBOBOX_)
356 pos = m_pEdit->CharFromPos(m_pEdit->GetCaretPos());
358 if(m_iMode & _MODE_FS_START_DIR_)
360 if(len)
361 m_Liste.FindString(-1,m_EditText);
362 else
363 m_Liste.ShowWindow(false);
365 else
367 if(len > 2 && pos == len)
369 if(_taccess(m_EditText,0) == 0)
371 ReadDirectory(m_EditText);
373 m_Liste.FindString(-1,m_EditText);
375 else
376 m_Liste.ShowWindow(false);
378 } // m_CursorMode
380 //----------------------------------------------
381 if(m_iMode & _MODE_SEPARATION_)
383 if(!m_CursorMode)
385 if(m_iType == _EDIT_)
386 pos = LOWORD(((CEdit*)this)->CharFromPos(GetCaretPos()));
388 if(m_iType == _COMBOBOX_)
389 pos = m_pEdit->CharFromPos(m_pEdit->GetCaretPos());
391 int left,right;
392 left = FindSepLeftPos(pos-1);
393 right = FindSepRightPos(pos);
394 m_Text = m_EditText.Mid(left,right-left);
395 m_Liste.FindString(-1,m_Text);
398 //----------------------------------------------
399 if(m_iMode & _MODE_STANDARD_)
401 if(!m_CursorMode)
402 m_Liste.FindString(-1,m_EditText);
404 //----------------------------------------------
405 GetParent()->SendMessage(ENAC_UPDATE, EN_UPDATE, GetDlgCtrlID());
408 /*********************************************************************/
410 int CACEdit::FindSepLeftPos(int pos,bool m_bIncludePrefix)
412 int len = m_EditText.GetLength();
413 TCHAR ch;
414 int i;
416 if(pos >= len && len != 1)
417 pos = len -1;
419 for(i = pos; i >= 0 ; i--)
421 ch = m_EditText.GetAt(i);
422 if(m_PrefixChar == ch)
423 return i + (m_bIncludePrefix ? 1 : 0);
424 if(m_SeparationStr.Find(ch) != -1)
425 break;
428 return i + 1;
431 /*********************************************************************/
433 int CACEdit::FindSepLeftPos2(int pos)
435 int len = m_EditText.GetLength();
436 TCHAR ch;
438 if(pos >= len && len != 1)
439 pos = len -1;
441 if(len == 1)
442 return 0;
444 for(int i = pos; i >= 0 ; i--)
446 ch = m_EditText.GetAt(i);
447 if(m_PrefixChar == ch)
448 return 1;
451 return 0;
454 /*********************************************************************/
456 int CACEdit::FindSepRightPos(int pos)
458 int len = m_EditText.GetLength();
459 TCHAR ch;
460 int i;
462 for(i = pos; i < len ; i++)
464 ch = m_EditText.GetAt(i);
465 if(m_SeparationStr.Find(ch) != -1)
466 break;
469 return i;
472 /*********************************************************************/
473 LRESULT CACEdit::OnUpdateFromList(WPARAM lParam, LPARAM /*wParam*/)
475 UpdateData(true);
477 if(lParam == WM_KEYDOWN)
478 HandleKey(VK_RETURN, true);
479 return 0;
482 /*********************************************************************/
484 void CACEdit::OnCloseList()
486 m_Liste.ShowWindow(false);
489 /*********************************************************************/
491 BOOL CACEdit::PreTranslateMessage(MSG* pMsg)
493 if(pMsg->message == WM_KEYDOWN)
495 if(m_Liste.IsWindowVisible())
497 if(m_iType == _COMBOBOX_)
499 if(pMsg->wParam == VK_DOWN || pMsg->wParam == VK_UP)
500 if (HandleKey((UINT)pMsg->wParam, false))
501 return true;
504 if(pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN)
505 if (HandleKey((UINT)pMsg->wParam, false))
506 return true;
509 return CWnd::PreTranslateMessage(pMsg);
512 /*********************************************************************/
514 void CACEdit::ReadDirectory(CString m_Dir)
516 CFileFind FoundFiles;
517 TCHAR ch;
518 CWaitCursor hg;
520 // Wenn mittem im Pfad,
521 // vorheriges Verzeichnis einlesen.
522 if (!CStringUtils::EndsWith(m_Dir, L'\\'))
524 _wsplitpath_s(m_Dir, m_szDrive, m_szDir, m_szFname, m_szExt);
525 m_Dir.Format(L"%s%s",m_szDrive, m_szDir);
528 //ist hübscher
529 ch = (TCHAR)towupper(m_Dir.GetAt(0));
530 m_Dir.SetAt(0,ch);
532 CString m_Name,m_File,m_Dir1 = m_Dir;
533 if (!CStringUtils::EndsWith(m_Dir, L'\\'))
534 m_Dir += L'\\';
536 if(m_LastDirectory.CompareNoCase(m_Dir) == 0 && m_Liste.m_SearchList.GetSize())
537 return;
539 m_LastDirectory = m_Dir;
540 m_Dir += L"*.*";
542 BOOL bContinue = FoundFiles.FindFile(m_Dir);
543 if(bContinue)
544 RemoveSearchAll();
546 while (bContinue == TRUE)
548 bContinue = FoundFiles.FindNextFile();
549 m_File = FoundFiles.GetFileName();
551 if(FoundFiles.IsHidden() || FoundFiles.IsSystem())
552 continue;
553 if(FoundFiles.IsDirectory())
555 if(m_iMode & _MODE_ONLY_FILES)
556 continue;
557 if(FoundFiles.IsDots())
558 continue;
560 if (!CStringUtils::EndsWith(m_File, L'\\'))
561 m_File += L'\\';
564 if(!FoundFiles.IsDirectory())
565 if(m_iMode & _MODE_ONLY_DIRS)
566 continue;
568 if(m_iMode & _MODE_FS_START_DIR_)
570 m_Name = m_File;
572 else
574 m_Name = m_Dir1;
575 if (!CStringUtils::EndsWith(m_Name, L'\\'))
576 m_Name += L'\\';
578 m_Name += m_File;
581 AddSearchString(m_Name);
583 FoundFiles.Close();
584 return;
587 /*********************************************************************/
589 void CACEdit::SetStartDirectory(LPCTSTR lpszString)
591 if(m_iType == -1) {ASSERT(0); return;}
593 if(m_iMode & _MODE_FS_START_DIR_)
594 ReadDirectory(lpszString);
597 /*********************************************************************
598 ** CComboBox
599 ** NEW:V1.1
600 *********************************************************************/
602 int CACEdit::AddString( LPCTSTR lpszString )
604 if(m_iType == _COMBOBOX_)
606 return ((CComboBox *)this)->AddString(lpszString);
608 return CB_ERR;
611 /*********************************************************************/
613 int CACEdit::SetDroppedWidth( UINT nWidth )
615 if(m_iType == _COMBOBOX_)
617 return ((CComboBox *)this)->SetDroppedWidth(nWidth);
619 return CB_ERR;
622 /*********************************************************************/
624 int CACEdit::FindString( int nStartAfter, LPCTSTR lpszString )
626 if(m_iType == _COMBOBOX_)
628 return ((CComboBox *)this)->FindString(nStartAfter,lpszString);
630 return CB_ERR;
633 /*********************************************************************/
635 int CACEdit::SelectString( int nStartAfter, LPCTSTR lpszString )
637 if(m_iType == _COMBOBOX_)
639 return ((CComboBox *)this)->SelectString(nStartAfter,lpszString);
641 return CB_ERR;
644 /*********************************************************************/
646 void CACEdit::ShowDropDown(BOOL bShowIt)
648 if(m_iType == _COMBOBOX_)
650 ((CComboBox *)this)->ShowDropDown(bShowIt);
654 /*********************************************************************/
656 void CACEdit::ResetContent()
658 if(m_iType == _COMBOBOX_)
660 ((CComboBox *)this)->ResetContent();
664 /*********************************************************************/
666 int CACEdit::GetCurSel()
668 if(m_iType == _COMBOBOX_)
670 return ((CComboBox *)this)->GetCurSel();
672 return CB_ERR;
675 /*********************************************************************/
677 int CACEdit::GetLBText( int nIndex, LPTSTR lpszText )
679 if(m_iType == _COMBOBOX_)
681 return ((CComboBox *)this)->GetLBText(nIndex,lpszText);
683 return CB_ERR;
686 /*********************************************************************/
688 void CACEdit::GetLBText( int nIndex, CString& rString )
690 if(m_iType == _COMBOBOX_)
692 ((CComboBox *)this)->GetLBText(nIndex,rString);
696 /*********************************************************************/