Beispiel #1
0
/*----------------------------------------------------------------------------------------------
	Refresh the field from the data cache.
	We only need to do something if a new text has been edited.
----------------------------------------------------------------------------------------------*/
void AfDeFeSt::UpdateField()
{
	// See if we have a dummy cache filling a missing text.
	if (!m_qvcdMissing)
		return; // If not, the view code updates things automatically from the real cache.

	HVO hvoText;
	CheckHr(m_qcvd->get_ObjectProp(m_hvoObj, m_flid, &hvoText));
	if (!hvoText)
		return; // The main cache doesn't have anything yet.

	// We now have a text, but we still have a dummy data cache, so
	// we need to throw out the dummy data cache and use the real cache.
	m_hvoText = hvoText;
	m_qvcdMissing.Clear();
	// Update the root object to point at the real text in the main cache.
	int frag = kfrText;
	IVwViewConstructor * pvvc = m_qstvc;
	CheckHr(m_qrootb->putref_DataAccess(m_qcvd));
	CheckHr(m_qrootb->SetRootObjects(&m_hvoText, &pvvc, &frag,
		GetLpInfo()->GetAfStylesheet(), 1));
	if (m_hwnd)
	{
		// If we have an editing window open, make it redraw.
		::InvalidateRect(m_hwnd, NULL, true);
	}
}
Beispiel #2
0
/*----------------------------------------------------------------------------------------------
	This initializes the string based after the pssl and pss have been set. It takes into
	account whether the view is hierarchical or not.
	@param fHier
	@param pnt
----------------------------------------------------------------------------------------------*/
void AfDeFeCliRef::InitContents(bool fHier, PossNameType pnt)
{
	Assert(m_hvoPssl); // This must be set prior to calling this method.
	Assert(pnt < kpntLim);

	SuperClass::Init(); // Initialize the superclass.

	m_fHier = fHier;
	m_pnt = pnt;

	if (!m_pss)
		return; // If the reference isn't set, we don't have anything to display.

	ITsStringPtr qtss;
	ITsStrFactoryPtr qtsf;
	StrUni stu;
	PossListInfoPtr qpli;
	PossItemInfo * ppii;
	int ipss;

	qtsf.CreateInstance(CLSID_TsStrFactory);
	GetLpInfo()->LoadPossList(m_hvoPssl, m_wsMagic, &qpli);
	AssertPtr(qpli);
	ipss = qpli->GetIndexFromId(m_pss);
	ppii = qpli->GetPssFromIndex(ipss);
	AssertPtr(ppii);
	if (m_fHier)
		ppii->GetHierName(qpli, stu, m_pnt);
	else
		ppii->GetName(stu, m_pnt);
	int ws = ppii->GetWs();
	qtsf->MakeStringRgch(stu.Chars(), stu.Length(), ws, &qtss);
	m_qtss = qtss;
	qpli->AddNotify(this);
}
Beispiel #3
0
/*----------------------------------------------------------------------------------------------
	Complete initialization of the property by storing the appropriate items, names, and lists.
	@param pssl The id for the People possibility list we are showing in this field.
	@param hvoOwner The owner of the RnRoledPartic we are displaying in this field.
	@param flid The flid in hvoOwner owning the RnRoledPartic we are displaying.
	@param pssRole The id of the CmPossibility from the Role list that we are using to display
		the label. (May be NULL for the unspecified item).
	@param fHier True if item names include parent items in the hierarchy.
	@param pnt Indicates whether we show name, abbr, or both for each item.
----------------------------------------------------------------------------------------------*/
void RnDeFeRoleParts::Init(HVO pssl, HVO hvoOwner, int flid, HVO pssRole, bool fHier,
	PossNameType pnt)
{
	Assert(m_flid); // Don't call this until Initialize has been called.
	Assert(pssl);
	Assert(hvoOwner);
	Assert(flid);
	Assert((uint)pnt < (uint)kpntLim);

	// Save the list id.
	m_vpssl.Push(pssl);
	m_fHier = fHier;
	m_pnt = pnt;
	m_hvoOwner = hvoOwner;
	m_flidOwner = flid;
	m_pssRole = pssRole;

	// Set the proper m_wsMagic value for the People possibility list.
	m_wsMagic = kwsVernAnals;

	// Set up a notifier for the people list.
	PossListInfoPtr qpli;
	GetLpInfo()->LoadPossList(pssl, m_wsMagic, &qpli);
	AssertPtr(qpli);
	qpli->AddNotify(this);
	// Set up a notifier for the role list.
	if (pssRole)
	{
		GetLpInfo()->LoadPossListForItem(pssRole, m_wsMagic, &qpli);
		AssertPtr(qpli);
		qpli->AddNotify(this);
		m_psslRole = qpli->GetPsslId();
	}

	// Create the display cache.
	m_qvcd.CreateInstance(CLSID_VwCacheDa);
	// Create the view constructor.
	m_qtgvc.Attach(NewObj TagsVc(m_qfsp->m_stuSty.Chars(), m_chrp.clrBack));

	// Set the writing system info (especially for Right-To-Left handling).
	ILgWritingSystemFactoryPtr qwsf;
	GetLpInfo()->GetDbInfo()->GetLgWritingSystemFactory(&qwsf);
	m_qtgvc->SetWritingSystemInfo(m_ws, qwsf);

	// Add information to the display cache.
	FillDisplayCache();
}
Beispiel #4
0
/*----------------------------------------------------------------------------------------------
	Relase all smart pointers.
----------------------------------------------------------------------------------------------*/
void AfDeFeCliRef::OnReleasePtr()
{
	PossListInfoPtr qpli;
	if (GetLpInfo()->GetPossList(m_hvoPssl, m_wsMagic, &qpli))
	{
		AssertPtr(qpli);
		qpli->RemoveNotify(this);
	}
	SuperClass::OnReleasePtr();
}
Beispiel #5
0
/*----------------------------------------------------------------------------------------------
	Refresh the field from the data cache.
----------------------------------------------------------------------------------------------*/
void AfDeFeCliRef::UpdateField()
{
	// Get the item info from the cache.
	CustViewDaPtr qcvd;
	GetDataAccess(&qcvd);
	AssertPtr(qcvd);
	HVO hvoPss;
	CheckHr(qcvd->get_ObjectProp(m_hvoObj, m_flid, &hvoPss));
	m_pss = hvoPss;

	// Get the string from the poss cache.
	ITsStringPtr qtss;
	ITsStrFactoryPtr qtsf;
	StrUni stu;
	PossListInfoPtr qpli;
	PossItemInfo * ppii;
	int ipss;

	qtsf.CreateInstance(CLSID_TsStrFactory);
	int ws = m_ws;
	if (m_pss)
	{
		GetLpInfo()->LoadPossList(m_hvoPssl, m_wsMagic, &qpli);
		AssertPtr(qpli);
		ipss = qpli->GetIndexFromId(m_pss);
		if (ipss >= 0)
		{
			ppii = qpli->GetPssFromIndex(ipss);
			AssertPtr(ppii);
			if (m_fHier)
				ppii->GetHierName(qpli, stu, m_pnt);
			else
				ppii->GetName(stu, m_pnt);
			ws = ppii->GetWs();
		}
	}
	qtsf->MakeStringRgch(stu.Chars(), stu.Length(), ws, &qtss);
	m_qtss = qtss;

	// If we have an edit box, update the contents.
	if (m_hwnd)
	{
		// Setting the property causes a recursive call to OnChange, so we want to block it
		// from making a further change. (e.g., when you backspace to set the string to null
		// then tab to the next field, we want it to stay null, not go to the first item in
		// the list.)
		m_fRecurse = true;
		::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, (LPARAM)m_qtss.Ptr());
	}
}
Beispiel #6
0
/*----------------------------------------------------------------------------------------------
	Finish initialization.
----------------------------------------------------------------------------------------------*/
void AfDeFeSt::Init(CustViewDa * pcvd, HVO hvoText)
{
	AssertPtr(pcvd);
	Assert(m_hvoObj); // Initialize should have been called prior to this.
	AssertPtr(m_qadsc);

	// Get the current default writing system for this field and convert any magic number.
	AfLpInfo * plpi = GetLpInfo();
	AssertPtr(plpi);
	m_qcvd = pcvd;
	m_hvoText = hvoText;
	ILgWritingSystemFactoryPtr qwsf;
	plpi->GetDbInfo()->GetLgWritingSystemFactory(&qwsf);
	m_qstvc.Attach(NewObj StVc(m_qfsp->m_stuSty.Chars(), m_ws, m_chrp.clrBack, qwsf));
}
Beispiel #7
0
/*----------------------------------------------------------------------------------------------
	Initialize font after superclass initialization is done.
----------------------------------------------------------------------------------------------*/
void AfDeFeEdBoxBut::Init()
{
	Assert(m_hvoObj); // Initialize should have been called first.

	CreateFont();
	ILgWritingSystemFactoryPtr qwsf;
	IWritingSystemPtr qws;
	GetLpInfo()->GetDbInfo()->GetLgWritingSystemFactory(&qwsf);
	AssertPtr(qwsf);
	ComBool fRTL = FALSE;
	CheckHr(qwsf->get_EngineOrNull(m_ws, &qws));
	if (qws)
		CheckHr(qws->get_RightToLeft(&fRTL));
	m_fRtl = bool(fRTL);
}
Beispiel #8
0
/*----------------------------------------------------------------------------------------------
	The Ok button in the list chooser has been hit. Process the results from the list chooser.
	@param pplc Pointer to the dialog box being closed.
	----------------------------------------------------------------------------------------------*/
void AfDeFeCliRef::ChooserApplied(PossChsrDlg * pplc)
{
	// Get the output values.
	StrUni stu;
	ITsStringPtr qtss;
	ITsStrFactoryPtr qtsf;
	HVO pssId;
	qtsf.CreateInstance(CLSID_TsStrFactory);
	pplc->GetDialogValues(pssId);
	m_pss = pssId;
	m_fRecurse = true;
	if (pssId)
	{
		PossListInfoPtr qpli;
		AfLpInfo * plpi = GetLpInfo();
		AssertPtr(plpi);
		plpi->LoadPossList(m_hvoPssl, m_wsMagic, &qpli);
		AssertPtr(qpli);
		int ipss = qpli->GetIndexFromId(pssId);
		PossItemInfo * ppii = qpli->GetPssFromIndex(ipss);
		if (m_fHier)
			ppii->GetHierName(qpli, stu, m_pnt);
		else
			ppii->GetName(stu, m_pnt);
		int ws = ppii->GetWs();
		qtsf->MakeStringRgch(stu.Chars(), stu.Length(), ws, &qtss);
		m_qtss = qtss;
		::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, (LPARAM)qtss.Ptr());
	}
	else
	{
		m_qtss = NULL;
		::SendMessage(m_hwnd, FW_EM_SETTEXT, 0, NULL);
	}
	// I (KenZ) don't fully understand this. But if a user enters the chooser, and opens a
	// list editor from there and adds a new item, closes the list editor, checks the new
	// item in the chooser, selects OK, then moves to the next record without moving from
	// the field, the added item is lost. We get ksyncPossList and ksyncAddPss sync messages
	// from the list editor, but for some reason we are getting an extra ksyncPossList
	// message after this method completes. That extra message is calling ListChanged which
	// calls UpdateField, which reloads our temporary cache from the main cache and wipes out
	// the change we just made. So until we can do something better, we'll save the changes
	// here to make sure the UpdateField doesn't wipe out our change.
	SaveEdit();
	::InvalidateRect(m_hwnd, NULL, true);
}
Beispiel #9
0
void AfDeFeSt::MakeRoot(IVwGraphics * pvg, ILgWritingSystemFactory * pwsf, IVwRootBox ** pprootb)
{
	AssertPtrN(pwsf);
	*pprootb = NULL;

	// Do we have a real text object? If not, make a fake one.
	int cpara = 0;
	ISilDataAccessPtr qsda = m_qcvd;
	if (m_hvoText)
		CheckHr(qsda->get_VecSize(m_hvoText, kflidStText_Paragraphs, &cpara));
	if (!cpara)
	{
		// We make a dummy text that is complete enough to edit, in a separate data access
		// object. On loss of focus, if this data access is dirty, we make corresponding
		// real objects.
		if (!m_hvoText)
			m_hvoText = -1;
		HVO hvoPara = -2;
		m_qvcdMissing.CreateInstance(CLSID_VwCacheDa);
		CheckHr(m_qvcdMissing->QueryInterface(IID_ISilDataAccess, (void **)&qsda));
		m_qvcdMissing->CacheVecProp(m_hvoText, kflidStText_Paragraphs, &hvoPara,1);
		ITsStrFactoryPtr qtsf;
		qtsf.CreateInstance(CLSID_TsStrFactory);
		ITsStringPtr qtssMissing;
		CheckHr(qtsf->MakeStringRgch(L"", 0, m_ws, &qtssMissing));
		m_qvcdMissing->CacheStringProp(hvoPara, kflidStTxtPara_Contents, qtssMissing);
	}

	IVwRootBoxPtr qrootb;
	qrootb.CreateInstance(CLSID_VwRootBox);
	CheckHr(qrootb->SetSite(this)); // pass root site
	int frag = kfrText;
	IVwViewConstructor * pvvc = m_qstvc;
	if (pwsf)
		CheckHr(qsda->putref_WritingSystemFactory(pwsf));
	CheckHr(qrootb->putref_DataAccess(qsda));
	CheckHr(qrootb->SetRootObjects(&m_hvoText, &pvvc, &frag,
		GetLpInfo()->GetAfStylesheet(), 1));
	*pprootb = qrootb;
	(*pprootb)->AddRef();

	RecMainWnd * prmw = dynamic_cast<RecMainWnd *>(m_qadsc->MainWindow());
	if (prmw)
		prmw->RegisterRootBox(qrootb);
}
Beispiel #10
0
/*----------------------------------------------------------------------------------------------
	Release all smart pointers.
----------------------------------------------------------------------------------------------*/
void RnDeFeRoleParts::OnReleasePtr()
{
	// Remove the notifier for the role list.
	if (m_psslRole)
	{
		PossListInfoPtr qpli;
		// Note: We need to use GetPossList here rather than LoadPossList since the
		// latter will try to reload the list if not present. During shutdown, the
		// possibility lists have already been cleared from AfLpInfo before we reach
		// this, so we want to quitely shut down. Using LoadPossList here produces a
		// massive memory leak.
		if (GetLpInfo()->GetPossList(m_psslRole, m_wsMagic, &qpli))
		{
			AssertPtr(qpli);
			qpli->RemoveNotify(this);
		}
		m_psslRole = 0;
	}

	SuperClass::OnReleasePtr();
}
Beispiel #11
0
/*----------------------------------------------------------------------------------------------
	Close the current editor, saving changes that were made. hwnd is the editor hwnd.
	@param fForce True if we want to force the editor closed without making any
		validity checks or saving any changes.
----------------------------------------------------------------------------------------------*/
void AfDeFeSt::EndEdit(bool fForce)
{
	if (m_qvcdMissing && !fForce)
	{
		ComBool fDirty;
		ISilDataAccessPtr qsdaTemp;
		CheckHr(m_qvcdMissing->QueryInterface(IID_ISilDataAccess, (void **)&qsdaTemp));
		qsdaTemp->IsDirty(&fDirty);
		if (fDirty)
		{
			// The text got edited. So, make a real text and copy the relevant info.
			// First get the paragraph list
			HvoVec vhvoParas;
			int chvoParas;

			// If we already had a text, we will notify it of new paragraphs.
			bool fNotifyText = m_hvoText > 0;

			CheckHr(qsdaTemp->get_VecSize(m_hvoText, kflidStText_Paragraphs, &chvoParas));
			int ihvo; // used twice
			for (ihvo = 0; ihvo < chvoParas; ihvo++)
			{
				HVO hvoPara;
				CheckHr(qsdaTemp->get_VecItem(m_hvoText, kflidStText_Paragraphs, ihvo,
					&hvoPara));
				vhvoParas.Push(hvoPara);
			}
			// Actually, we may have had a real text...if so, skip this step
			if (m_hvoText < 0)
			{
				m_qcvd->MakeNewObject(kclidStText, m_hvoObj, m_flid, -2, &m_hvoText);
			}
			else
			{
				// Check if the record has been edited by someone else since we first loaded
				// the data.
				HRESULT hrTemp;
				if ((hrTemp = m_qcvd->CheckTimeStamp(m_hvoText)) != S_OK)
				{
					// If it was changed and the user does not want to overwrite it, perform a
					// refresh so the displayed field will revert to it's original value.
					SuperClass::EndEdit(fForce);
					// REVIEW KenZ (PaulP):  There may need to be a refresh call made here.
					// It's difficult to know, however, since I haven't tracked down when
					// this method actually gets called.
					m_fDirty = false;
					return;
				}
			}

			// Now make real paragraph objects and set their properties.
			for (ihvo = 0; ihvo < chvoParas; ihvo++)
			{
				HVO hvoPara = vhvoParas[ihvo];
				ITsStringPtr qtss;
				ITsTextPropsPtr qttp;
				IUnknownPtr qunkTtp;
				CheckHr(qsdaTemp->get_UnknownProp(hvoPara, kflidStStyle_Rules, &qunkTtp));
				CheckHr(qunkTtp->QueryInterface(IID_ITsTextProps, (void **) &qttp));
				CheckHr(qsdaTemp->get_StringProp(hvoPara, kflidStTxtPara_Contents,
						&qtss));
				CheckHr(m_qcvd->MakeNewObject(kclidStTxtPara, m_hvoText, kflidStText_Paragraphs,
					ihvo, &hvoPara));
				if (qttp)
					CheckHr(m_qcvd->SetUnknown(hvoPara, kflidStPara_StyleRules, qttp));
				CheckHr(m_qcvd->SetString(hvoPara, kflidStTxtPara_Contents, qtss));
			}
			m_qvcdMissing.Clear();
			// Update the root object to point at the real text we just made.
			int frag = kfrText;
			IVwViewConstructor * pvvc = m_qstvc;
			CheckHr(m_qrootb->putref_DataAccess(m_qcvd));
			CheckHr(m_qrootb->SetRootObjects(&m_hvoText, &pvvc, &frag,
				GetLpInfo()->GetAfStylesheet(), 1));
			m_qadsc->UpdateAllDEWindows(m_hvoObj, m_flid);
			if (fNotifyText)
			{
				CheckHr(m_qcvd->PropChanged(m_qrootb, kpctNotifyAllButMe, m_hvoText,
					kflidStText_Paragraphs, 0,
							chvoParas, chvoParas));
			}
			else
			{
				CheckHr(m_qcvd->PropChanged(m_qrootb, kpctNotifyAllButMe, m_hvoObj, m_flid, 0,
							1, 1));
			}
		}
	}
	// Do this after the changes above, otherwise, our hwnd is no longer the child of a main
	// window, and we can't find the style sheet for the SetRootObjects call.
	SuperClass::EndEdit(fForce);
	m_fDirty = false;
}
Beispiel #12
0
/*----------------------------------------------------------------------------------------------
	Make an edit box to allow editing. hwnd is the parent hwnd. rc is the size of the child
	window. Store the hwnd and return true.
	@param hwnd
	@param rc
	@param dxpCursor
	@param fTopCursor
	@param tpte
	@return true if successful

	TODO: To handle extra long field contents (and RTL?) the button cannot be a child of the
	edit control, because they must occupy seperate rectangles inside the field proper.
----------------------------------------------------------------------------------------------*/
bool AfDeFeEdBoxBut::BeginEdit(HWND hwnd, Rect &rc, int dxpCursor, bool fTopCursor,
	TptEditable tpte)
{
	if (!SuperClass::BeginEdit(hwnd, rc, dxpCursor, fTopCursor))
		return false;
	DeEditPtr qde;
	qde.Create();
	qde->SetEditable(tpte);
	qde->m_pdee = this;
	IActionHandler * pacth = BeginTempEdit();
	ILgWritingSystemFactoryPtr qwsf;
	GetLpInfo()->GetDbInfo()->GetLgWritingSystemFactory(&qwsf);
	AssertPtr(qwsf);
#if 1
	int nRet = 0;
	ComBool fRTL = FALSE;
	IWritingSystemPtr qws;
	CheckHr(qwsf->get_EngineOrNull(m_ws, &qws));
	if (qws)
		CheckHr(qws->get_RightToLeft(&fRTL));
	if (fRTL)
		qde->Create(hwnd, kwidEditChild, WS_CHILD | ES_RIGHT | ES_AUTOHSCROLL, NULL, m_qtss,
			qwsf, m_ws, pacth);
	else
#endif
	qde->Create(hwnd, kwidEditChild, WS_CHILD | ES_LEFT | ES_AUTOHSCROLL, NULL, m_qtss,
		qwsf, m_ws, pacth);
	m_hwnd = qde->Hwnd();
	Rect rcT(rc.left + 2, rc.top + 1, rc.right, rc.bottom);
	nRet = ::MoveWindow(m_hwnd, rcT.left, rcT.top, rcT.Width(), rcT.Height(), true);
#if 99-99
	Rect rcParentClient;
	Rect rcParent;
	::GetClientRect(hwnd, &rcParentClient);
	::GetWindowRect(hwnd, &rcParent);
	Rect rcEdit;
	Rect rcEditClient;
	::GetWindowRect(m_hwnd, &rcEdit);
	::GetClientRect(m_hwnd, &rcEditClient);
#endif
	Rect rcTb;
	::GetClientRect(m_hwnd, &rcTb);
	rcTb.left = rcTb.right - 16;
	rcTb.bottom = rcTb.top + Min((int)rcTb.bottom - (int)rcTb.top, (int)kdxpButtonHeight);

	WndCreateStruct wcsButton;
	wcsButton.InitChild(_T("BUTTON"), m_hwnd, kwidEditChild);
	wcsButton.style |= WS_VISIBLE | BS_OWNERDRAW;
	wcsButton.SetRect(rcTb);

	DeButtonPtr qdb;
	qdb.Create();
	qdb->CreateAndSubclassHwnd(wcsButton);
	qdb->m_pdee = this;
	m_hwndButton = qdb->Hwnd();

#if 1-1
	// Resize the edit control window to exclude the button
	nRet = ::MoveWindow(m_hwnd, rcT.left, rcT.top, rcT.Width() - 18, rcT.Height(), true);
#endif
	// Add text to the window.
	::SendMessage(m_hwnd, FW_EM_SETSTYLE, m_chrp.clrBack, (LPARAM)&m_qfsp->m_stuSty);
	::SendMessage(m_hwnd, EM_SETMARGINS, EC_RIGHTMARGIN | EC_LEFTMARGIN, MAKELPARAM(0, 18));
	::ShowWindow(m_hwnd, SW_SHOW);
	//::SendMessage(m_hwnd, WM_SETFONT, (WPARAM)::GetStockObject(DEFAULT_GUI_FONT), 0);
	// Foreground/background colors are set via WM_CTLCOLOREDIT in AfDeFeWnd.
	// Set cursor to desired offset.
	//int ich;
	//ich = LOWORD(::SendMessage(m_hwnd, EM_CHARFROMPOS, 0, dxpCursor));
	// For some reason the above always comes back with -1 instead of the correct index.
	// Is this a bug in TssEdit or am I doing something wrong?
	//::SendMessage(m_hwnd, EM_SETSEL, ich, ich);
	//::mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0); // Send LButton to place cursor in edit ctrl.
#if 99-99
	Rect rcEditNew;
	Rect rcEditNewClient;
	Rect rcBut;
	Rect rcButClient;
	::GetWindowRect(m_hwnd, &rcEditNew);
	::GetClientRect(m_hwnd, &rcEditNewClient);
	::GetWindowRect(m_hwndButton, &rcBut);
	::GetClientRect(m_hwndButton, &rcButClient);
#endif

	return true;
}
Beispiel #13
0
/*----------------------------------------------------------------------------------------------
	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;
}
Beispiel #14
0
/*----------------------------------------------------------------------------------------------
	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);
}