/*---------------------------------------------------------------------------------------------- The edit box changed. We need to validate what was done. @param pedit @return ----------------------------------------------------------------------------------------------*/ bool AfDeFeCliRef::OnChange(AfDeFeEdBoxBut::DeEdit * pedit) { if (m_fRecurse) { m_fRecurse = false; return true; } if (!m_hwnd) return true; // We aren't completely set up yet, so ignore this. // Get the characters from the edit box. ITsStringPtr qtss; ::SendMessage(m_hwnd, FW_EM_GETTEXT, 0, (LPARAM)&qtss); int ichMin; int ichLim; ::SendMessage(m_hwnd, EM_GETSEL, (WPARAM)&ichMin, (LPARAM)&ichLim); int cchTyped; // number of characters in the typed string // JohnT: use a StrUni rather than an StrUniBuf, because some user sometime will accidentally // paste something long here, and performance here is not critical. StrUni stuTyped; OLECHAR * pchBuf; qtss->get_Length(&cchTyped); if (cchTyped > kcchPossNameAbbrMax) { if (ichMin == cchTyped) ichMin = kcchPossNameAbbrMax; if (ichLim == cchTyped) ichLim = kcchPossNameAbbrMax; cchTyped = kcchPossNameAbbrMax; m_fRecurse = true; // Stop the recursion caused by the next instruction. // Note: This recursively calls this procedure. ::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, (LPARAM)qtss.Ptr()); ::SendMessage(m_hwnd, EM_SETSEL, ichMin, ichMin); } stuTyped.SetSize(cchTyped, &pchBuf); qtss->FetchChars(0, cchTyped, pchBuf); #ifdef DEBUG_THIS_FILE StrAnsi sta; sta.Format("AfDeFeCliRef::OnChange: pedit->m_ch=%d; ichMin=%d; ichLim=%d; pedit->m_cchMatched=%d; cchTyped=%d.\n", pedit->m_ch, ichMin, ichLim, pedit->m_cchMatched, cchTyped); OutputDebugString(sta.Chars()); #endif bool fTypeAhead = false; // allow type ahead only when adding characters at end of current item // or backspacing at end of current item. bool fNeedCompare; if (pedit->m_ch == 0) // (see kcidEditPaste special code) { // If we pasted something, force a compare. fNeedCompare = true; } else if (ichMin == pedit->m_cchMatched + 1 && pedit->m_ch != VK_BACK && pedit->m_ch != VK_DELETE) { // Need to compare if we typed a character and we are one greater than last match. fNeedCompare = true; if (cchTyped == ichMin) { fTypeAhead = true; #ifdef DEBUG_THIS_FILE sta.Format("OnChange: 1 - setting fTypeAhead to true.\n"); OutputDebugString(sta.Chars()); #endif } } else if (ichMin > pedit->m_cchMatched) { // Don't compare any other time we are past the last match. fNeedCompare = false; } // else if ((cchTyped == ichMin) && (ichMin == ichLim) && (pedit->m_ch != kscDelForward)) else if ((cchTyped == ichMin) && (ichMin == ichLim) && (pedit->m_ch != 46)) { // Need to compare if we typed a character and we are at the end of the item // Need to compare if we delete the last character in the non-type-ahead string fNeedCompare = true; fTypeAhead = true; #ifdef DEBUG_THIS_FILE sta.Format("OnChange: kscDelForward=%d.\n"); OutputDebugString(sta.Chars()); sta.Format("OnChange: 2 - setting fTypeAhead to true.\n"); OutputDebugString(sta.Chars()); #endif } else { // Always compare if we are not past the last match. fNeedCompare = true; } int cch; // Since the edit box deletes the selection on backspace, we need to use // some extra logic to make backspace actually move the selection back. if (pedit->m_cchMatched && pedit->m_ch == VK_BACK && m_pss) { // If we had a previous match and we got a backspace, we always decrement the matched // characters and start looking at that point. cch = --pedit->m_cchMatched; } else { // Otherwise we start looking at the cursor location. cch = ichMin; } AfLpInfo * plpi = GetLpInfo(); AssertPtr(plpi); PossListInfoPtr qpli; plpi->LoadPossList(m_hvoPssl, m_wsMagic, &qpli); AssertPtr(qpli); PossItemInfo * ppii = NULL; ComBool fExactMatch = false; fNeedCompare = true; if (cchTyped == 0) { // If nothing to match, get the first item in the possibility list. If we are // already at that item, remove the item. If we are already cleared, do nothing. if (!m_pss) return true; // If everything is highlighted, we want to clear the item with Del or Bsp. // But when we are backspacing, if there is only one character left and we backspace // over that, we want to switch to the first item in the list. ppii = qpli->GetPssFromIndex(0); if (ichMin != 1) { m_pss = 0; m_qtss = NULL; pedit->m_cchMatched = 0; // Keep cursor at beginning of item. m_fRecurse = true; ::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, (LPARAM)m_qtss.Ptr()); return true; } } else if (fNeedCompare) { // Try to find an item that matches what the user typed in the possibility list. StrUni stuMatch(stuTyped); ///// stuMatch.Replace(cch, stuMatch.Length(), L"");// Delete chars to right of cursor. Locale loc = GetLpInfo()->GetLocale(m_ws); if (m_fHier) { ppii = qpli->FindPssHier(stuMatch.Chars(), loc, m_pnt, fExactMatch); } else { ppii = qpli->FindPss(stuMatch.Chars(), loc, m_pnt); } if (ppii) { // found a match that starts with stuTyped int ipssTemp; // TODO TimP: check for hierarchy. If stuTyped contains hierarchy, // Was the match exact (rather than just starting with stuTyped) ? if (fExactMatch) // May have matched in the FindPssHier() call above. { #ifdef DEBUG_THIS_FILE sta.Format("OnChange: Exact match (hier).\n"); OutputDebugString(sta.Chars()); #endif } else { fExactMatch = ! qpli->PossUniqueName(-1, stuTyped, m_pnt, ipssTemp); if (fExactMatch) { #ifdef DEBUG_THIS_FILE sta.Format("OnChange: Exact match.\n"); OutputDebugString(sta.Chars()); #endif // in case FindPss() above matches "ABC" but "AB" is also in list. ppii = qpli->GetPssFromIndex(ipssTemp); } else { #ifdef DEBUG_THIS_FILE sta.Format("OnChange: Not exact match.\n"); OutputDebugString(sta.Chars()); #endif } } } } else ppii = NULL; StrUni stuFound; int ws = m_ws; if (ppii && (fTypeAhead || fExactMatch)) { // If found, process the new item. int pss = ppii->GetPssId(); m_pss = pss; if (m_fHier) ppii->GetHierName(qpli, stuFound, m_pnt); else ppii->GetName(stuFound, m_pnt); ws = ppii->GetWs(); // If the last character was a delimiter, we need to set cch accordingly. if (m_fHier && (stuTyped.Length() > 0) && (pedit->m_ch != VK_BACK) && (stuTyped.GetAt(stuTyped.Length() - 1) == kchHierDelim)) { // Need to set cch to the position of the last delimiter. cch = stuFound.FindCh(kchHierDelim, cch - 1) + 1; } pedit->m_cchMatched = cch; } else { // Something illegal was typed. Assume they are adding a new item. if (pedit->m_cchMatched + 1 == cch && pedit->m_ch != VK_BACK) ::MessageBeep(MB_ICONEXCLAMATION); // Beep on the first unmatched character. // Underline the string with a red squiggly. ITsIncStrBldrPtr qtisb; qtisb.CreateInstance(CLSID_TsIncStrBldr); qtisb->SetIntPropValues(ktptWs, ktpvDefault, m_ws); CheckHr(qtisb->SetIntPropValues(ktptUnderColor, ktpvDefault, kclrRed)); CheckHr(qtisb->SetIntPropValues(ktptUnderline, ktpvEnum, kuntSquiggle)); qtisb->AppendRgch(stuTyped.Chars(), stuTyped.Length()); qtisb->GetString(&m_qtss); m_fRecurse = true; // Stop the recursion caused by the next instruction. // Note: This recursively calls this procedure. ::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, (LPARAM)m_qtss.Ptr()); ::SendMessage(m_hwnd, EM_SETSEL, ichMin, ichMin); m_pss = 0; // We no longer have a matched HVO. return true; } // Update the edit box text and selection. ITsStrFactoryPtr qtsf; qtsf.CreateInstance(CLSID_TsStrFactory); qtsf->MakeStringRgch(stuFound.Chars(), stuFound.Length(), ws, &qtss); m_qtss = qtss; #ifdef DEBUG_THIS_FILE sta.Format("AfDeFeCliRef::OnChange: pedit->m_cchMatched=%d; stuFound.Length()=%d; ichMin=%d; ichLim=%d.\n", pedit->m_cchMatched, stuFound.Length(), ichMin, ichLim); OutputDebugString(sta.Chars()); #endif m_fRecurse = true; // Shortcut the recursion caused by the next instruction. if (fTypeAhead) { // Note: This recursively calls this procedure. ::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, (LPARAM)qtss.Ptr()); ::SendMessage(m_hwnd, EM_SETSEL, pedit->m_cchMatched, stuFound.Length()); #ifdef DEBUG_THIS_FILE sta.Format("AfDeFeCliRef::OnChange: type ahead.\n"); OutputDebugString(sta.Chars()); #endif } else { // Note: This recursively calls this procedure. ::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, (LPARAM)qtss.Ptr()); ::SendMessage(m_hwnd, EM_SETSEL, ichMin, ichMin); #ifdef DEBUG_THIS_FILE sta.Format("AfDeFeCliRef::OnChange: NOT type ahead.\n"); OutputDebugString(sta.Chars()); #endif } return true; }
/*---------------------------------------------------------------------------------------------- Return the text string that gets shown to the user when this object needs to be displayed. This is the method for displaying the name of a single reference. This view shows the name for an RnGenericRec consisting of the type of record, hyphen, title, hyphen, creation date. "Subevent - Fishing for pirana - 3/22/2001" @param pguid Pointer to a database object's assigned GUID. @param pptss Address of a pointer to an ITsString COM object used for returning the text string. @return S_OK, E_POINTER, or E_FAIL. ----------------------------------------------------------------------------------------------*/ STDMETHODIMP CleRecVc::GetStrForGuid(BSTR bstrGuid, ITsString ** pptss) { Assert(false); // rework BEGIN_COM_METHOD; ChkComBstrArg(bstrGuid); ChkComOutPtr(pptss); if (BstrLen(bstrGuid) != 8) ReturnHr(E_INVALIDARG); CleMainWnd * pcmw = dynamic_cast<CleMainWnd *>(AfApp::Papp()->GetCurMainWnd()); AssertPtr(pcmw); CleLpInfo * plpi = dynamic_cast<CleLpInfo *>(pcmw->GetLpInfo()); AssertPtr(plpi); HVO hvo = plpi->GetDbInfo()->GetIdFromGuid((GUID *)bstrGuid); CustViewDaPtr qcvd; plpi->GetDataAccess(&qcvd); AssertPtr(qcvd); int clid; HVO hvoOwn; int64 ntim; ITsStringPtr qtssTitle; CheckHr(qcvd->get_IntProp(hvo, kflidCmObject_Class, &clid)); CheckHr(qcvd->get_ObjectProp(hvo, kflidCmObject_Owner, &hvoOwn)); // REVIEW KenZ(RandyR) Whey are DN flids in this app? CheckHr(qcvd->get_TimeProp(hvo, kflidRnGenericRec_DateCreated, &ntim)); CheckHr(qcvd->get_StringProp(hvo, kflidRnGenericRec_Title, &qtssTitle)); int stid; // REVIEW KenZ(RandyR) Whey are DN flids in this app? if (clid == kclidRnEvent) { if (pcmw->GetRootObj() == hvoOwn) stid = kstidEvent; else stid = kstidSubevent; } else if (clid == kclidRnAnalysis) { if (pcmw->GetRootObj() == hvoOwn) stid = kstidAnalysis; else stid = kstidSubanalysis; } StrUni stu(stid); StrUni stuSep(kstidSpHyphenSp); ITsStrFactoryPtr qtsf; ITsIncStrBldrPtr qtisb; qtsf.CreateInstance(CLSID_TsStrFactory); CheckHr(qtsf->GetIncBldr(&qtisb)); CheckHr(qtisb->Append(stu.Bstr())); CheckHr(qtisb->Append(stuSep.Bstr())); CheckHr(qtisb->AppendTsString(qtssTitle)); // The title. CheckHr(qtisb->Append(stuSep.Bstr())); // Leave the date blank if a date doesn't exist. if (ntim) { // Convert the date to a system date. SilTime tim = ntim; SYSTEMTIME stim; stim.wYear = (unsigned short) tim.Year(); stim.wMonth = (unsigned short) tim.Month(); stim.wDay = (unsigned short) tim.Date(); // Then format it to a time based on the current user locale. achar rgchDate[50]; // Tuesday, August 15, 2000 mardi 15 août 2000 ::GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &stim, NULL, rgchDate, 50); stu = rgchDate; CheckHr(qtisb->Append(stu.Bstr())); } CheckHr(qtisb->GetString(pptss)); return S_OK; END_COM_METHOD(g_fact2, IID_IVwViewConstructor) }
/*---------------------------------------------------------------------------------------------- Something has changed in the possibility list. ----------------------------------------------------------------------------------------------*/ void RnDeFeRoleParts::ListChanged(int nAction, HVO hvoPssl, HVO hvoSrc, HVO hvoDst, int ipssSrc, int ipssDst) { if (hvoPssl != m_psslRole) { // Process changes for people lists. SuperClass::ListChanged(nAction, hvoPssl, hvoSrc, hvoDst, ipssSrc, ipssDst); return; } // If someone deleted the role we are interested in we need to clean up. if (hvoSrc == m_pssRole && nAction == kplnaDelete) { // Remove the notifier for the role list. Assert(m_psslRole); PossListInfoPtr qpli; GetLpInfo()->LoadPossList(m_psslRole, m_wsMagic, &qpli); AssertPtr(qpli); qpli->RemoveNotify(this); m_psslRole = 0; m_pssRole = 0; } // At this point we are not getting kplnaMerged at all since we are just deleting all // fields and recreating new ones. But at some point down the road we may want to switch // to where we don't delete and recreate. This would be the right action to take then. if (hvoSrc == m_pssRole && nAction == kplnaMerged) { // Switch to the new role. m_pssRole = hvoDst; } // Now reset the label in case we changed. // Use Participants for the unspecified editor label. ITsStringPtr qtssName; int wsUser = GetLpInfo()->GetDbInfo()->UserWs(); AfUtil::GetResourceTss(kstidTlsOptParticipants, wsUser, &qtssName); ITsStringPtr qtssHelp = m_qfsp->m_qtssHelp; ITsStrFactoryPtr qtsf; qtsf.CreateInstance(CLSID_TsStrFactory); if (m_pssRole) { PossItemInfo * ppii; GetLpInfo()->GetPossListAndItem(m_pssRole, wsUser, &ppii, NULL); StrUni stuName; // the Role's name ppii->GetName(stuName, m_pnt); qtsf->MakeStringRgch(stuName.Chars(), stuName.Length(), wsUser, &qtssName); ITsIncStrBldrPtr qtisb; qtisb.CreateInstance(CLSID_TsIncStrBldr); // Add the first substring. qtisb->AppendTsString(m_qfsp->m_qtssHelp); // Add the second substring. StrUni stuTemp; stuTemp.Load(kstidRnRoledPartic_HelpA); qtisb->AppendRgch(stuTemp.Chars(), stuTemp.Length()); // Turn bold on. qtisb->SetIntPropValues(ktptBold, ktpvEnum, kttvForceOn); // Add the Role's name qtisb->AppendRgch(stuName.Chars(), stuName.Length()); // Turn bold off. qtisb->SetIntPropValues(ktptBold, ktpvEnum, kttvOff); // Add the third substring. stuTemp.Load(kstidRnRoledPartic_HelpB); qtisb->AppendRgch(stuTemp.Chars(), stuTemp.Length()); // Get the completed TsString. qtisb->GetString(&qtssHelp); } m_qtssLabel = qtssName; m_qtssHelp = qtssHelp; // Force the label to redraw. Rect rcLabel; ::GetClientRect(m_qadsc->Hwnd(),&rcLabel); Rect rcEdit(m_rcClip); if (m_hwnd) { // We have an open edit box, so get the correct coordinates for the client window. ::GetClientRect(m_hwnd, &rcEdit); ::MapWindowPoints(m_hwnd, m_qadsc->Hwnd(), (POINT *)&rcEdit, 2); } rcLabel.top = rcEdit.top; rcLabel.bottom = rcEdit.bottom; rcLabel.right = m_qadsc->GetTreeWidth(); ::InvalidateRect(m_qadsc->Hwnd(), &rcLabel, false); }