// XTPSyntaxEditAutoCompleteWnd.cpp: implementation of the CXTPSyntaxEditAutoCompleteWnd class. // // This file is a part of the XTREME TOOLKIT PRO MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME SYNTAX EDIT LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Resource.h" // common includes #include "Common/XTPDrawHelpers.h" #include "Common/XTPSmartPtrInternalT.h" #include "Common/XTPSystemHelpers.h" #include "Common/XTPColorManager.h" // syntax editor includes #include "XTPSyntaxEditDefines.h" #include "XTPSyntaxEditStruct.h" #include "XTPSyntaxEditAutoCompleteWnd.h" #include "XTPSyntaxEditCtrl.h" #include "XTPSyntaxEditDrawTextProcessor.h" #include #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define XTP_SYNTAXEDIT_AUTOCOMPLETE_HEIGHT_MAX 160 ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// BEGIN_MESSAGE_MAP(CXTPSyntaxEditAutoCompleteWnd, CWnd) ON_WM_LBUTTONDOWN() ON_WM_RBUTTONDOWN() ON_WM_LBUTTONDBLCLK() ON_WM_MOUSEWHEEL() ON_WM_KEYDOWN() ON_WM_CHAR() ON_WM_VSCROLL() ON_WM_SETCURSOR() ON_WM_PAINT() END_MESSAGE_MAP() CXTPSyntaxEditAutoCompleteWnd::CXTPSyntaxEditAutoCompleteWnd() { RegisterWindowClass(); m_strSearch = _T(""); m_pParentWnd = NULL; m_nLineHeight = 0; m_nLines = 0; m_nWndHeight = 0; m_nWndWidth = 160; m_nHighLightLine = -1; m_nFirstDisplayedStr = 0; m_nBordersHeight = 0; m_bActive = FALSE; m_bFixedBottom = FALSE; m_strDelims = _T(""); VERIFY( m_ilACGlyphs.Create(XTP_IDB_EDIT_GLYPHS, 16, 16, RGB(255, 255, 255)) ); } CXTPSyntaxEditAutoCompleteWnd::~CXTPSyntaxEditAutoCompleteWnd() { RemoveAll(); DestroyWindow(); } BOOL CXTPSyntaxEditAutoCompleteWnd::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/) { WNDCLASS wndcls; if (hInstance == NULL) hInstance = AfxGetInstanceHandle(); if (!(::GetClassInfo(hInstance, XTP_EDIT_CLASSNAME_AUTOCOMPLETEWND, &wndcls))) { // otherwise we need to register a new class wndcls.style = CS_SAVEBITS | CS_DBLCLKS; wndcls.lpfnWndProc = ::DefWindowProc; wndcls.cbClsExtra = wndcls.cbWndExtra = 0; wndcls.hInstance = hInstance; wndcls.hIcon = NULL; wndcls.hCursor = ::LoadCursor(NULL, IDC_ARROW); wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wndcls.lpszMenuName = NULL; wndcls.lpszClassName = XTP_EDIT_CLASSNAME_AUTOCOMPLETEWND; if (!AfxRegisterClass(&wndcls)) { AfxThrowResourceException(); return FALSE; } } return TRUE; } BOOL CXTPSyntaxEditAutoCompleteWnd::Create(CWnd* pParentWnd) { if (!CWnd::CreateEx(WS_EX_TOOLWINDOW, XTP_EDIT_CLASSNAME_AUTOCOMPLETEWND, NULL, WS_CHILD | WS_DLGFRAME | WS_VSCROLL | WS_DISABLED, CRect(0, 0, 160, 160), GetDesktopWindow(), NULL)) { TRACE0("Failed to create Auto Complete View.\n"); return FALSE; } CXTPClientRect rcClient(this); CXTPWindowRect rcWin(this); m_nBordersHeight = (rcWin.Height()-rcClient.Height()); m_pParentWnd = DYNAMIC_DOWNCAST(CXTPSyntaxEditCtrl, pParentWnd); return TRUE; } void CXTPSyntaxEditAutoCompleteWnd::Show(CPoint pt, CString strSearch) { if (Filter(strSearch) < 1) return; m_nFirstDisplayedStr = 0; int nSearch = Search(strSearch); m_nHighLightLine = nSearch; //<<>>Forum Proposal m_bHighLight = (m_nHighLightLine >= 0); //<<>> ScrollTo(nSearch); RefreshMetrics(); AdjusLayout(); CRect rcWnd(pt.x - 21, pt.y, pt.x - 21 + m_nWndWidth, pt.y + m_nWndHeight); if (GetParent()) GetParent()->ClientToScreen(&rcWnd); _AdjustWndRect(rcWnd); if (GetParent()) GetParent()->ScreenToClient(&rcWnd); //SetWindowPos(NULL, pt.x - 21, pt.y, m_nWndWidth, m_nWndHeight, SWP_SHOWWINDOW); SetWindowPos(NULL, rcWnd.left, rcWnd.top, rcWnd.Width(), rcWnd.Height(), SWP_SHOWWINDOW); BOOL bVScrollEnabled = AdjusLayout(rcWnd.Height()); ShowScrollBar(SB_VERT, bVScrollEnabled); RedrawWindow(); EnableWindow(TRUE); SetFocus(); m_bActive = TRUE; int nSearchLen = strSearch.GetLength(); m_bFilteredMode = nSearchLen > 0; m_nStartReplacePos = m_pParentWnd->GetCurCol() - nSearchLen; m_nEndReplacePos = m_nStartReplacePos + nSearchLen; m_strSearch = strSearch; } void CXTPSyntaxEditAutoCompleteWnd::_AdjustWndRect(CRect& rc) { CRect rcWorkArea = XTPMultiMonitor()->GetWorkArea(); //from cursor point //CRect rcWorkArea = XTPMultiMonitor()->GetWorkArea(this); m_bFixedBottom = rc.bottom > rcWorkArea.bottom; if (m_bFixedBottom) { int nNewTop = rc.top - m_nWndHeight - m_pParentWnd->GetDrawTextProcessor().GetRowHeight(); rc.top = max(rcWorkArea.top, nNewTop); rc.bottom = min(rcWorkArea.bottom, rc.top + m_nWndHeight); m_bFixedBottom = TRUE; } if (rc.right > rcWorkArea.right) { int nOffsetX = rc.right - rcWorkArea.right; rc.left = max(rcWorkArea.left, rc.left - nOffsetX); rc.right = rcWorkArea.right; } if (rc.left < rcWorkArea.left) { int nOffsetX = rcWorkArea.left - rc.left; rc.right = rc.right + nOffsetX; rc.left = rcWorkArea.left; } } void CXTPSyntaxEditAutoCompleteWnd::SetWndWidth(int nWidth) { m_nWndWidth = nWidth; if (m_hWnd) { CXTPWindowRect rcWnd(this); if (GetParent()) GetParent()->ScreenToClient(&rcWnd); rcWnd.right = rcWnd.left + m_nWndWidth; MoveWindow(&rcWnd); AdjusLayout(rcWnd.Height()); RedrawWindow(); } } void CXTPSyntaxEditAutoCompleteWnd::UpdateFilteredList() { int nIdx = Search(m_strSearch); if (nIdx >=0) { Filter(m_strSearch); m_nFirstDisplayedStr = 0; nIdx = Search(m_strSearch); m_nHighLightLine = nIdx; AdjusLayout(); ScrollTo(nIdx); CXTPWindowRect rcWnd(this); CRect rcWorkArea = XTPMultiMonitor()->GetWorkArea(this); if (m_bFixedBottom) rcWnd.top = rcWnd.bottom - m_nWndHeight; else rcWnd.bottom = min(rcWorkArea.bottom, rcWnd.top + m_nWndHeight); if (GetParent()) GetParent()->ScreenToClient(&rcWnd); MoveWindow(&rcWnd); AdjusLayout(rcWnd.Height()); RedrawWindow(); } } void CXTPSyntaxEditAutoCompleteWnd::OnLButtonDown(UINT nFlags, CPoint point) { CWnd::OnLButtonDown(nFlags, point); int nHitLine = HitTest(point); if (nHitLine > -1) { m_bHighLight = TRUE; m_nHighLightLine = m_nFirstDisplayedStr + nHitLine; RedrawWindow(); } } void CXTPSyntaxEditAutoCompleteWnd::OnRButtonDown(UINT nFlags, CPoint point) { CWnd::OnRButtonDown(nFlags, point); int nHitLine = HitTest(point); if (nHitLine > -1) { m_nHighLightLine = m_nFirstDisplayedStr + nHitLine; RedrawWindow(); } } void CXTPSyntaxEditAutoCompleteWnd::OnLButtonDblClk(UINT nFlags, CPoint point) { CWnd::OnLButtonDblClk(nFlags, point); m_bHighLight = TRUE; ReturnSelected(FALSE); Hide(); } void CXTPSyntaxEditAutoCompleteWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { int nDataMax = (int)m_arrACDataFiltered.GetSize(); int nPage = m_nLines - 1; int nLastDisp = m_nFirstDisplayedStr + nPage; m_bHighLight = TRUE; switch (nChar) { case VK_UP: m_nHighLightLine -= nRepCnt; if (m_nHighLightLine >= 0) { if (m_nFirstDisplayedStr > m_nHighLightLine && ScrollTo(m_nHighLightLine)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); } RedrawWindow(); } else { m_nHighLightLine = 0; } break; case VK_DOWN: m_nHighLightLine += nRepCnt; if (m_nHighLightLine < nDataMax) { int nL = m_nLines - 1; nLastDisp = m_nFirstDisplayedStr + nL; if (nLastDisp < m_nHighLightLine) { if (ScrollTo(m_nHighLightLine - nL)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); } } RedrawWindow(); } else { m_nHighLightLine = nDataMax - 1; } break; case VK_PRIOR: if (m_nFirstDisplayedStr < m_nHighLightLine) { m_nHighLightLine = m_nFirstDisplayedStr; } else { if (m_nHighLightLine > 0) m_nHighLightLine = max(0, m_nHighLightLine - m_nLines + 1); else m_nHighLightLine -= m_nLines + 1; } if (m_nHighLightLine >= 0) { if (m_nFirstDisplayedStr > m_nHighLightLine && ScrollTo(m_nHighLightLine)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); } RedrawWindow(); } else { m_nHighLightLine = 0; } break; case VK_NEXT: if (m_nFirstDisplayedStr + nPage > m_nHighLightLine) { m_nHighLightLine = m_nFirstDisplayedStr + nPage; } else { if (m_nHighLightLine < nDataMax) m_nHighLightLine = min(nDataMax - 1, m_nHighLightLine + nPage); else m_nHighLightLine += nPage; } if (m_nHighLightLine < nDataMax) { if (nLastDisp < m_nHighLightLine) { if (ScrollTo(m_nHighLightLine - nPage)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); } } RedrawWindow(); } else { m_nHighLightLine = nDataMax - 1; } break; case VK_END: if (m_nHighLightLine != nDataMax - 1 && ScrollTo(nDataMax - m_nLines)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); m_nHighLightLine = nDataMax - 1; RedrawWindow(); } break; case VK_HOME: if (m_nHighLightLine != 0 && ScrollTo(0)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); m_nHighLightLine = 0; RedrawWindow(); } break; case VK_BACK: m_nEndReplacePos--; if (m_strSearch.GetLength() > 0) m_strSearch = m_strSearch.Left(m_strSearch.GetLength() - 1); if (m_nStartReplacePos >= m_nEndReplacePos) { Hide(); m_pParentWnd->SendMessage(WM_LBUTTONUP, 0, 0); } else { UpdateFilteredList(); } break; case VK_LEFT : case VK_RIGHT : case VK_MENU : case VK_CONTROL: case VK_ESCAPE: Hide(); break; case VK_RETURN: case VK_SPACE: ReturnSelected(FALSE); Hide(); break; } CWnd::OnKeyDown(nChar, nRepCnt, nFlags); } void CXTPSyntaxEditAutoCompleteWnd::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { if (IsCloseTag((TCHAR)nChar)) { ReturnSelected(FALSE); Hide(); } if (isalnum((TCHAR)nChar) || (TCHAR)nChar == _T('_')) //<<>> { m_nEndReplacePos++; m_strSearch += (TCHAR)nChar; UpdateFilteredList(); int nFound = Search(m_strSearch); if (nFound >= 0) { m_nHighLightLine = nFound; m_bHighLight = TRUE; if (m_nFirstDisplayedStr > m_nHighLightLine) { if (ScrollTo(m_nHighLightLine)) SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); } if (m_nFirstDisplayedStr + m_nLines <= m_nHighLightLine) { if (ScrollTo(m_nHighLightLine - m_nLines + 1)) SetScrollPos(SB_VERT, m_nFirstDisplayedStr, TRUE); } RedrawWindow(); CString sTxt = m_arrACDataFiltered.GetAt(m_nHighLightLine)->m_strText; if (m_bFilteredMode && sTxt.CompareNoCase(m_strSearch) == 0) { int nCnt = (int) m_arrACDataFiltered.GetSize(); if (nCnt == 1) { ReturnSelected(TRUE); Hide(); } } } else if (m_bFilteredMode) { Hide(); } else { m_bHighLight = FALSE; RedrawWindow(); } } CWnd::OnChar(nChar, nRepCnt, nFlags); } void CXTPSyntaxEditAutoCompleteWnd::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { UNREFERENCED_PARAMETER(nPos); UNREFERENCED_PARAMETER(pScrollBar); SCROLLINFO info; GetScrollInfo(SB_VERT, &info); switch (nSBCode) { case SB_LINEDOWN: if (ScrollTo(m_nFirstDisplayedStr + 1)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr); RedrawWindow(); } break; case SB_LINEUP: if (ScrollTo(m_nFirstDisplayedStr - 1)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr); RedrawWindow(); } break; case SB_PAGEDOWN: if (ScrollTo(m_nFirstDisplayedStr + m_nLines - 1)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr); RedrawWindow(); } break; case SB_PAGEUP: if (ScrollTo(m_nFirstDisplayedStr - m_nLines + 1)) { SetScrollPos(SB_VERT, m_nFirstDisplayedStr); RedrawWindow(); } break; case SB_TOP: SetScrollPos(SB_VERT, info.nMin); RedrawWindow(); break; case SB_BOTTOM: SetScrollPos(SB_VERT, info.nMax); RedrawWindow(); break; case SB_THUMBTRACK: { SCROLLINFO si; ZeroMemory(&si, sizeof(SCROLLINFO)); si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_TRACKPOS; if (GetScrollInfo(SB_VERT, &si)) { if (si.nTrackPos != m_nFirstDisplayedStr && ScrollTo(si.nTrackPos)) { SetScrollPos(SB_VERT, si.nTrackPos); RedrawWindow(); } } } break; case SB_ENDSCROLL: return; default: break; } } BOOL CXTPSyntaxEditAutoCompleteWnd::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { int nCount = labs(zDelta) / WHEEL_DELTA; for (int i = 0; i < nCount; i++) { SendMessage(WM_VSCROLL, (WPARAM)(zDelta > 0 ? SB_LINEUP : SB_LINEDOWN)); } return CWnd::OnMouseWheel(nFlags, zDelta, pt); } BOOL CXTPSyntaxEditAutoCompleteWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { UNREFERENCED_PARAMETER(message); UNREFERENCED_PARAMETER(nHitTest); UNREFERENCED_PARAMETER(pWnd); ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW)); return TRUE; } BOOL CXTPSyntaxEditAutoCompleteWnd::AdjusLayout(int nHeightMax) { CWindowDC dc(NULL); CXTPFontDC fontDC(&dc, &m_fontBasic); int nDataLines = (int)m_arrACDataFiltered.GetSize(); m_nLineHeight = dc.GetTextExtent(_T("A"), 1).cy + 6; if (nHeightMax <= 0) nHeightMax = XTP_SYNTAXEDIT_AUTOCOMPLETE_HEIGHT_MAX; if (nDataLines * m_nLineHeight < nHeightMax) { m_nLines = nDataLines; } else { m_nLines = (int) nHeightMax / m_nLineHeight; } BOOL bVScrollEnabled = nDataLines > m_nLines; ShowScrollBar(SB_VERT, bVScrollEnabled); EnableScrollBarCtrl(SB_VERT, bVScrollEnabled); //-------------------------------------------------- m_nWndHeight = m_nLines * m_nLineHeight + m_nBordersHeight; CXTPClientRect rcClient(this); CRect rc(0, 0, rcClient.Width(), m_nLineHeight); m_arrGrid.RemoveAll(); for (int nLine = 0; nLine < m_nLines; nLine++) { m_arrGrid.Add(rc); rc.OffsetRect(0, m_nLineHeight); } //-------------------------------------------------- if (bVScrollEnabled) { SCROLLINFO scrollInfo; scrollInfo.cbSize = sizeof(SCROLLINFO); scrollInfo.fMask = SIF_ALL; scrollInfo.nMin = 0; scrollInfo.nMax = max(0, nDataLines-1); scrollInfo.nPage = m_nLines; scrollInfo.nPos = m_nFirstDisplayedStr; SetScrollInfo(SB_VERT, &scrollInfo, FALSE); } return bVScrollEnabled; } void CXTPSyntaxEditAutoCompleteWnd::OnPaint() { CPaintDC dc(this); CXTPFontDC fontDC(&dc, &m_fontBasic); CRect rc; CRect rcText; CString str; int nData = 0; int nHighLightedLine = m_nHighLightLine - m_nFirstDisplayedStr; for (int nLine = 0; nLine < m_nLines; nLine++) { rc.CopyRect(m_arrGrid.GetAt(nLine)); int nIcon = min(m_arrACDataFiltered.GetAt(nData)->m_nIcon, m_ilACGlyphs.GetImageCount() - 1); m_ilACGlyphs.Draw(&dc, nIcon, CPoint(rc.left, rc.top), ILD_NORMAL); rc.DeflateRect(19, 0, 0, 0); if (nLine == nHighLightedLine && m_bHighLight) { dc.FillSolidRect(rc.left, rc.top, rc.Width(), rc.Height(), m_clrHighLight); dc.SetTextColor(m_clrHighLightText); } else { dc.SetTextColor(m_clrWindowText); dc.FillSolidRect(rc.left, rc.top, rc.Width(), rc.Height(), m_clrWindow); } rcText.CopyRect(rc); rcText.DeflateRect(2, 3, 2, 3); nData = m_nFirstDisplayedStr + nLine; dc.TextOut(rcText.left, rcText.top, m_arrACDataFiltered.GetAt(nData)->m_strText); if (nLine == nHighLightedLine) { dc.DrawFocusRect(rc); } } } void CXTPSyntaxEditAutoCompleteWnd::RefreshMetrics() { m_fontBasic.CreateStockObject(DEFAULT_GUI_FONT); m_clrHighLight = GetSysColor(COLOR_HIGHLIGHT); m_clrWindow = GetSysColor(COLOR_WINDOW); m_clrWindowText = GetSysColor(COLOR_WINDOWTEXT); m_clrHighLightText = GetSysColor(COLOR_HIGHLIGHTTEXT); } int CXTPSyntaxEditAutoCompleteWnd::HitTest(CPoint ptTest) const { int nHitLine = -1; for (int nLine = 0; nLine < m_nLines; nLine++) { if (m_arrGrid.GetAt(nLine).PtInRect(ptTest)) { nHitLine = nLine; } } return nHitLine; } void CXTPSyntaxEditAutoCompleteWnd::SetList(CXTPSyntaxEditACDataArray& parrData) { RemoveAll(); m_arrACData.Copy(parrData); Sort(); } void CXTPSyntaxEditAutoCompleteWnd::SetCloseTags(CString strCloseTags) { m_strCloseTags = strCloseTags; } BOOL CXTPSyntaxEditAutoCompleteWnd::IsCloseTag(CString strToTest) { BOOL bTagFound = FALSE; if (strToTest == _T("~")) return bTagFound; m_strTmpCloseTag += strToTest; int nTmpLen = m_strTmpCloseTag.GetLength(); int nFound = -1; if ((nFound = m_strCloseTags.Find(m_strTmpCloseTag)) >=0) { if (nFound+nTmpLen == m_strCloseTags.GetLength()) { bTagFound = TRUE; } else { TCHAR ch = m_strCloseTags.GetAt(nFound + nTmpLen); if (ch == _T('~')) { bTagFound = TRUE; } } } else { m_strTmpCloseTag = _T(""); } return bTagFound; } void CXTPSyntaxEditAutoCompleteWnd::SetOpenTags(CString strOpenTags) { m_strOpenTags = strOpenTags; } BOOL CXTPSyntaxEditAutoCompleteWnd::IsOpenTag(CString strToTest) { BOOL bTagFound = FALSE; if (strToTest == _T("~")) return bTagFound; m_strTmpOpenTag += strToTest; int nTmpLen = m_strTmpOpenTag.GetLength(); int nFound = -1; if ((nFound = m_strOpenTags.Find(m_strTmpOpenTag)) >=0 ) { if (nFound + nTmpLen == m_strOpenTags.GetLength()) { bTagFound = TRUE; } else { TCHAR ch = m_strOpenTags.GetAt(nFound + nTmpLen); if (ch == _T('~')) { bTagFound = TRUE; } } } else { m_strTmpOpenTag = _T(""); } return bTagFound; } BOOL CXTPSyntaxEditAutoCompleteWnd::ScrollTo(int nNewLine) { BOOL bScrollRequestCompleted = FALSE; if (nNewLine + m_nLines <= m_arrACDataFiltered.GetSize() && nNewLine >= 0) { bScrollRequestCompleted = TRUE; m_nFirstDisplayedStr = nNewLine; } return bScrollRequestCompleted; } void CXTPSyntaxEditAutoCompleteWnd::ReturnSelected(BOOL bAdjust) { if (m_nHighLightLine < 0 || !m_bHighLight) return; int nCurrentRow = m_pParentWnd->GetCurrentDocumentRow(); CString strRet = m_arrACDataFiltered.GetAt(m_nHighLightLine)->m_strText; if (m_strTmpCloseTag.GetLength() > 0) { strRet += m_strTmpCloseTag; m_strTmpCloseTag = _T(""); } else if (bAdjust) { strRet = strRet.Left(strRet.GetLength() - 1); m_nEndReplacePos = max(m_nStartReplacePos, m_nEndReplacePos - 1); } m_pParentWnd->Select(nCurrentRow, m_nStartReplacePos, nCurrentRow, m_nEndReplacePos, FALSE); m_pParentWnd->ReplaceSel(strRet); m_pParentWnd->SetCurCaretPos(m_pParentWnd->GetCurrentDocumentRow(), m_pParentWnd->m_nDispCol); m_pParentWnd->SetDocModified(); } void CXTPSyntaxEditAutoCompleteWnd::Hide() { if (!m_bActive) return; m_bActive = FALSE; EnableWindow(FALSE); ShowWindow(SW_HIDE); m_bFilteredMode = FALSE; m_pParentWnd->PostMessage(WM_LBUTTONUP, 0, 0); RedrawWindow(); } int CXTPSyntaxEditAutoCompleteWnd::CompareACData(const XTP_EDIT_ACDATA** p1, const XTP_EDIT_ACDATA** p2) { const XTP_EDIT_ACDATA* pData1 = *p1; const XTP_EDIT_ACDATA* pData2 = *p2; return _tcsicmp((LPCTSTR)pData1->m_strText, (LPCTSTR)pData2->m_strText); } void CXTPSyntaxEditAutoCompleteWnd::Sort() { int nCount = (int)m_arrACData.GetSize(); if (nCount > 1) { typedef int (_cdecl *GENERICCOMPAREFUNC)(const void *, const void*); qsort(m_arrACData.GetData(), nCount, sizeof(XTP_EDIT_ACDATA*), (GENERICCOMPAREFUNC)CompareACData); } } int CXTPSyntaxEditAutoCompleteWnd::CompareACDataToSearch(const XTP_EDIT_ACDATA** ppKey, const XTP_EDIT_ACDATA** ppElem) { int nKeyLength = (*ppKey)->m_strText.GetLength(); return (*ppElem)->m_strText.Left(nKeyLength).CompareNoCase((*ppKey)->m_strText); } int CXTPSyntaxEditAutoCompleteWnd::Search(CString strSearch) { int nFirstOccurrence = -1; if (strSearch.GetLength() == 0) return 0; XTP_EDIT_ACDATA* key = new XTP_EDIT_ACDATA(0, strSearch); XTP_EDIT_ACDATA** pFirst = &m_arrACDataFiltered[0]; UINT nNum = (UINT)m_arrACDataFiltered.GetSize(); typedef int (_cdecl *GENERICCOMPAREFUNC)(const void *, const void*); XTP_EDIT_ACDATA** pRez = (XTP_EDIT_ACDATA**)_lfind(&key, pFirst, &nNum, sizeof(XTP_EDIT_ACDATA*), (GENERICCOMPAREFUNC)CompareACDataToSearch); delete key; if (pRez) { nFirstOccurrence = (LONG)((LONG_PTR)pRez - (LONG_PTR)pFirst)/sizeof(XTP_EDIT_ACDATA*); } return nFirstOccurrence; } int CXTPSyntaxEditAutoCompleteWnd::Filter(CString strSearch) { int nFound = 0; m_arrACDataFiltered.RemoveAll(); if (strSearch.GetLength() == 0) { m_arrACDataFiltered.Copy(m_arrACData); return (int)m_arrACDataFiltered.GetSize(); } if (!m_arrACData.GetSize()) { return 0; } XTP_EDIT_ACDATA* key = new XTP_EDIT_ACDATA(0, strSearch); XTP_EDIT_ACDATA** pFirst = &m_arrACData[0]; XTP_EDIT_ACDATA** pNext = NULL; UINT nNum = (UINT)m_arrACData.GetSize(); typedef int (_cdecl *GENERICCOMPAREFUNC)(const void *, const void*); while (nNum > 0) { pNext = (XTP_EDIT_ACDATA**)_lfind(&key, pFirst, &nNum, sizeof(XTP_EDIT_ACDATA*), (GENERICCOMPAREFUNC)CompareACDataToSearch); if (pNext) { nNum -= (LONG) ((LONG_PTR)pNext - (LONG_PTR)pFirst)/sizeof(XTP_EDIT_ACDATA*); pFirst = pNext; nNum --; pFirst++; m_arrACDataFiltered.Add(*pNext); nFound++; } else { nNum --; pFirst++; } } delete key; return nFound; } void CXTPSyntaxEditAutoCompleteWnd::RemoveAll() { int nDataLines = (int)m_arrACData.GetSize(); m_arrACDataFiltered.RemoveAll(); XTP_EDIT_ACDATA* pACData = NULL; for (int nDataLine = 0; nDataLine < nDataLines; nDataLine++) { pACData = m_arrACData.GetAt(nDataLine); ASSERT(pACData); delete pACData; } m_arrACData.RemoveAll(); }