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
14 #include "StringUtils.h"
19 static char THIS_FILE
[] = __FILE__
;
25 /////////////////////////////////////////////////////////////////////////////
30 m_iMode
= _MODE_STANDARD_
;
41 /*********************************************************************/
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
)
55 ON_CONTROL_REFLECT(EN_CHANGE
, OnChange
)
56 ON_CONTROL_REFLECT(CBN_EDITCHANGE
, OnChange
)
57 ON_CONTROL_REFLECT(CBN_DROPDOWN
, OnCloseList
)
59 ON_MESSAGE(ENAC_UPDATE
,OnUpdateFromList
)
62 /*********************************************************************/
64 void CACEdit::SetMode(int iMode
)
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
'\\';
82 if(iMode
& _MODE_FIND_ALL_
)
84 m_Liste
.m_lMode
|= _MODE_FIND_ALL_
;
88 /*********************************************************************/
92 CString szClassName
= AfxRegisterWndClass(CS_CLASSDC
|CS_SAVEBITS
|CS_HREDRAW
|CS_VREDRAW
,
93 0,(HBRUSH
) (COLOR_WINDOW
), 0);
97 VERIFY(m_Liste
.CreateEx(WS_EX_TOOLWINDOW
,
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),
106 ::GetClassName(GetSafeHwnd(), CStrBuf(m_ClassName
, 32), 32);
108 if (m_ClassName
.Compare(L
"Edit") == 0)
112 if (m_ClassName
.Compare(L
"ComboBox") == 0)
114 m_iType
= _COMBOBOX_
;
116 m_pEdit
= (CEdit
*)GetWindow(GW_CHILD
);
118 ::GetClassName(m_pEdit
->GetSafeHwnd(), CStrBuf(m_ClassName
, 32), 32);
119 VERIFY(m_ClassName
.Compare(L
"Edit") == 0);
132 /*********************************************************************/
134 void CACEdit::AddSearchStrings(LPCTSTR Strings
[])
138 if(m_iType
== -1) {ASSERT(0); return;}
147 m_Liste
.AddSearchString(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;}
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);
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
)
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())
219 if(m_Liste
.IsWindowVisible())
224 if(m_iMode
& _MODE_STANDARD_
225 || m_iMode
& _MODE_FILESYSTEM_
226 || m_iMode
& _MODE_FS_START_DIR_
)
231 m_EditText
= m_Liste
.GetNextString(nChar
);
233 m_EditText
= m_Liste
.GetString();
235 if(m_iMode
& _MODE_FILESYSTEM_
)
237 if (CStringUtils::EndsWith(m_EditText
, L
'\\'))
238 m_EditText
= m_EditText
.Mid(0,m_EditText
.GetLength()-1);
241 if (nChar
!= VK_RETURN
)
242 m_Liste
.SelectItem(m_Liste
.GetSelectedItem());
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);
269 if(m_iMode
& _MODE_SEPARATION_
)
271 CString m_Text
,m_Left
,m_Right
;
272 int left
,right
,pos2
=0,len
;
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
);
290 m_Text
+= m_Liste
.GetNextString(nChar
);
292 m_Text
+= m_Liste
.GetString();
294 if (nChar
!= VK_RETURN
)
295 m_Liste
.SelectItem(m_Liste
.GetSelectedItem());
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);
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);
335 /*********************************************************************/
337 void CACEdit::OnChange()
345 GetWindowText(m_EditText
);
346 len
= m_EditText
.GetLength();
347 //----------------------------------------------
348 if(m_iMode
& _MODE_FILESYSTEM_
|| m_iMode
& _MODE_FS_START_DIR_
)
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_
)
361 m_Liste
.FindString(-1,m_EditText
);
363 m_Liste
.ShowWindow(false);
367 if(len
> 2 && pos
== len
)
369 if(_taccess(m_EditText
,0) == 0)
371 ReadDirectory(m_EditText
);
373 m_Liste
.FindString(-1,m_EditText
);
376 m_Liste
.ShowWindow(false);
380 //----------------------------------------------
381 if(m_iMode
& _MODE_SEPARATION_
)
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());
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_
)
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();
416 if(pos
>= len
&& 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)
431 /*********************************************************************/
433 int CACEdit::FindSepLeftPos2(int pos
)
435 int len
= m_EditText
.GetLength();
438 if(pos
>= len
&& len
!= 1)
444 for(int i
= pos
; i
>= 0 ; i
--)
446 ch
= m_EditText
.GetAt(i
);
447 if(m_PrefixChar
== ch
)
454 /*********************************************************************/
456 int CACEdit::FindSepRightPos(int pos
)
458 int len
= m_EditText
.GetLength();
462 for(i
= pos
; i
< len
; i
++)
464 ch
= m_EditText
.GetAt(i
);
465 if(m_SeparationStr
.Find(ch
) != -1)
472 /*********************************************************************/
473 LRESULT
CACEdit::OnUpdateFromList(WPARAM lParam
, LPARAM
/*wParam*/)
477 if(lParam
== WM_KEYDOWN
)
478 HandleKey(VK_RETURN
, true);
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))
504 if(pMsg
->wParam
== VK_ESCAPE
|| pMsg
->wParam
== VK_RETURN
)
505 if (HandleKey((UINT
)pMsg
->wParam
, false))
509 return CWnd::PreTranslateMessage(pMsg
);
512 /*********************************************************************/
514 void CACEdit::ReadDirectory(CString m_Dir
)
516 CFileFind FoundFiles
;
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
);
529 ch
= (TCHAR
)towupper(m_Dir
.GetAt(0));
532 CString m_Name
,m_File
,m_Dir1
= m_Dir
;
533 if (!CStringUtils::EndsWith(m_Dir
, L
'\\'))
536 if(m_LastDirectory
.CompareNoCase(m_Dir
) == 0 && m_Liste
.m_SearchList
.GetSize())
539 m_LastDirectory
= m_Dir
;
542 BOOL bContinue
= FoundFiles
.FindFile(m_Dir
);
546 while (bContinue
== TRUE
)
548 bContinue
= FoundFiles
.FindNextFile();
549 m_File
= FoundFiles
.GetFileName();
551 if(FoundFiles
.IsHidden() || FoundFiles
.IsSystem())
553 if(FoundFiles
.IsDirectory())
555 if(m_iMode
& _MODE_ONLY_FILES
)
557 if(FoundFiles
.IsDots())
560 if (!CStringUtils::EndsWith(m_File
, L
'\\'))
564 if(!FoundFiles
.IsDirectory())
565 if(m_iMode
& _MODE_ONLY_DIRS
)
568 if(m_iMode
& _MODE_FS_START_DIR_
)
575 if (!CStringUtils::EndsWith(m_Name
, L
'\\'))
581 AddSearchString(m_Name
);
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 /*********************************************************************
600 *********************************************************************/
602 int CACEdit::AddString( LPCTSTR lpszString
)
604 if(m_iType
== _COMBOBOX_
)
606 return ((CComboBox
*)this)->AddString(lpszString
);
611 /*********************************************************************/
613 int CACEdit::SetDroppedWidth( UINT nWidth
)
615 if(m_iType
== _COMBOBOX_
)
617 return ((CComboBox
*)this)->SetDroppedWidth(nWidth
);
622 /*********************************************************************/
624 int CACEdit::FindString( int nStartAfter
, LPCTSTR lpszString
)
626 if(m_iType
== _COMBOBOX_
)
628 return ((CComboBox
*)this)->FindString(nStartAfter
,lpszString
);
633 /*********************************************************************/
635 int CACEdit::SelectString( int nStartAfter
, LPCTSTR lpszString
)
637 if(m_iType
== _COMBOBOX_
)
639 return ((CComboBox
*)this)->SelectString(nStartAfter
,lpszString
);
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();
675 /*********************************************************************/
677 int CACEdit::GetLBText( int nIndex
, LPTSTR lpszText
)
679 if(m_iType
== _COMBOBOX_
)
681 return ((CComboBox
*)this)->GetLBText(nIndex
,lpszText
);
686 /*********************************************************************/
688 void CACEdit::GetLBText( int nIndex
, CString
& rString
)
690 if(m_iType
== _COMBOBOX_
)
692 ((CComboBox
*)this)->GetLBText(nIndex
,rString
);
696 /*********************************************************************/