Beispiel #1
0
/*----------------------------------------------------------------------------------------------
	Set the text of the control to be equal to ptss. If ptss is NULL, the edit box is cleared.
	Message: FW_EM_SETTEXT.
----------------------------------------------------------------------------------------------*/
void TssEdit::SetText(ITsString * ptss)
{
	AssertPtrN(ptss); // NULL can be used to clear string.
	Assert(m_qcda);

	ITsStringPtr qtss = ptss;
	if (!ptss)
	{
		ITsStrFactoryPtr qtsf;
		qtsf.CreateInstance(CLSID_TsStrFactory);
		CheckHr(qtsf->MakeStringRgch(L"", 0, m_wsBase, &qtss));
	}
	ITsStringPtr qtssOld;
	CheckHr(m_qcda->get_StringProp(khvoString, ktagString, &qtssOld));
	int cchOld;
	CheckHr(qtssOld->get_Length(&cchOld));
	CheckHr(m_qcda->CacheStringProp(khvoString, ktagString, qtss));
	int cchNew;
	CheckHr(qtss->get_Length(&cchNew));
	// Pretend the whole length has been deleted and the whole new inserted.
	CheckHr(m_qcda->PropChanged(NULL, kpctNotifyAll, khvoString, ktagString, 0, cchNew, cchOld));
	OnUpdate();
	::UpdateWindow(m_hwnd);
	OnChange();
}
Beispiel #2
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 AfDeFeCliRef::EndEdit(bool fForce)
{
	if (!fForce)
	{
		if (!m_pss)
		{
			// The user added a new item.
			ITsStringPtr qtss;
			int cch;
			StrUni stu; // Name/Abbr string entered by user.
			OLECHAR * pchBuf;

			// Get the characters from the edit box.
			::SendMessage(m_hwnd, FW_EM_GETTEXT, 0, (LPARAM)&qtss);
			qtss->get_Length(&cch);
			stu.SetSize(cch, &pchBuf);
			qtss->FetchChars(0, cch, pchBuf);

			if (cch)
			{
				// If a non-null string is present, create a new item.
				m_fSaving = true; // Disable updates while adding a new item.
				// The user created a new item, so add it to the possibility list.
				m_pss = CreatePss(m_hvoPssl, stu.Chars(), m_pnt, m_fHier);
				Assert(m_pss); // What should we do if we have an error?
				m_fSaving = false;
			}
		}
	}
	// When we close the edit window, the squiggley will automatically be removed.
	SuperClass::EndEdit(fForce);
}
Beispiel #3
0
/*----------------------------------------------------------------------------------------------
	Save the text to a file.
----------------------------------------------------------------------------------------------*/
bool WpDa::SaveToFile(StrAnsi staFileName)
{
	IStreamPtr qstrm;
	FileStream::Create(staFileName.Chars(), kfstgmWrite | kfstgmCreate, &qstrm);
//	FileStream::Create("c:\\output.txt", kfstgmWrite | kfstgmCreate, &qstrm);

	ULONG cbWritten;
	//	Write byte-order mark.
	byte b = 0xFF;
	CheckHr(qstrm->Write(&b, 1, &cbWritten));
	b = 0xFE;
	CheckHr(qstrm->Write(&b, 1, &cbWritten));

	int ctss;
	CheckHr(get_VecSize(1, kflidStText_Paragraphs, &ctss));

	for (int itss = 0; itss < ctss; itss++)
	{
		ITsStringPtr qtss;
		CheckHr(get_StringProp(itss + 2, kflidStTxtPara_Contents, &qtss));
		BSTR bstr = NULL;
		int cchw;
		CheckHr(qtss->get_Length(&cchw));
		qtss->GetChars(0, cchw, &bstr);

		//	Write the string to the file.
		if (cchw > 0)
		{
			Assert(bstr);
			CheckHr(qstrm->Write(bstr, cchw * isizeof(wchar), &cbWritten));
		}

		if (itss < ctss - 1)
		{
			//	CRLF--little-endian
			b = 13;
			CheckHr(qstrm->Write(&b, 1, &cbWritten));
			b = 0;
			CheckHr(qstrm->Write(&b, 1, &cbWritten));
			b = 10;
			CheckHr(qstrm->Write(&b, 1, &cbWritten));
			b = 0;
			CheckHr(qstrm->Write(&b, 1, &cbWritten));
		}

		ReleaseBstr(bstr);
	}

	return true;
}
Beispiel #4
0
/*----------------------------------------------------------------------------------------------
	Return true if the text buffer is empty--that is, containing only one empty string.
----------------------------------------------------------------------------------------------*/
bool WpDa::IsEmpty()
{
	int ctss;
	CheckHr(get_VecSize(1, kflidStText_Paragraphs, &ctss));

	if (ctss == 0)
		return true;
	if (ctss > 1)
		return false;

	ITsStringPtr qtss;
	CheckHr(get_StringProp(2, kflidStTxtPara_Contents, &qtss));
	int cchw;
	CheckHr(qtss->get_Length(&cchw));
	return (cchw == 0);
}
Beispiel #5
0
/*----------------------------------------------------------------------------------------------
	Display TsString in the control
	(may be explicitly called when created by ATL, because in this case TssEdit::Create() will
	not be called)
----------------------------------------------------------------------------------------------*/
void TssEdit::PostCreate(ITsString * ptss)
{
	AssertPtrN(ptss);

	if (ptss)
	{
		int cch;
		ITsStringPtr qtss = ptss;
		CheckHr(qtss->get_Length(&cch));
		// Treat as inserting all the characters, since the cache previously had nothing.
		CheckHr(m_qcda->PropChanged(NULL, kpctNotifyAll, khvoString, ktagString, 0, cch, 0));
		OnUpdate();
		::UpdateWindow(m_hwnd);
		OnChange();
	}
}
Beispiel #6
0
/*----------------------------------------------------------------------------------------------
	Check the requirments of the FldSpec, and verify that data in the field meets the
	requirement. It returns:
		kFTReqNotReq if the all requirements are met.
		kFTReqWs if data is missing, but it is encouraged.
		kFTReqReq if data is missing, but it is required.
----------------------------------------------------------------------------------------------*/
FldReq AfDeFeSt::HasRequiredData()
{
	if (m_qfsp->m_fRequired == kFTReqNotReq)
		return kFTReqNotReq;
	CustViewDaPtr qcvd;
	GetDataAccess(&qcvd);
	AssertPtr(qcvd);
	bool fEmpty = true;
	ITsStringPtr qtss;
	int cch = 0;
	HVO hvoPara;
	int iPara;

	if (!m_hvoText)
		goto LExit;

	int cPara;
	CheckHr(qcvd->get_VecSize(m_hvoText, kflidStText_Paragraphs, &cPara));
	if (!cPara)
		goto LExit;

	// Make sure at least some paragraph has data.
	for (iPara = 0; iPara < cPara; ++iPara)
	{
		CheckHr(qcvd->get_VecItem(m_hvoText, kflidStText_Paragraphs, iPara, &hvoPara));
		// At some point we may need to handle something other than StTxtPara.
		CheckHr(qcvd->get_StringProp(hvoPara, kflidStTxtPara_Contents, &qtss));
		if (qtss)
			CheckHr(qtss->get_Length(&cch));
		if (cch)
			break; // Have a valid string
	}

	fEmpty = iPara == cPara;

LExit:
	if (fEmpty)
		return m_qfsp->m_fRequired;
	else
		return kFTReqNotReq;
}
Beispiel #7
0
/*----------------------------------------------------------------------------------------------
	Selects a range of characters.
	Message: EM_SETSEL.
----------------------------------------------------------------------------------------------*/
void TssEdit::SetSel(int ichAnchor, int ichEnd)
{
	Assert(m_qrootb);

	int cch = 0;
	ITsStringPtr qtss;
	CheckHr(m_qcda->get_StringProp(khvoString, ktagString, &qtss));
	if (qtss)
		CheckHr(qtss->get_Length(&cch));
	if (ichAnchor < 0)
		ichAnchor = cch;
	if (ichEnd < 0)
		ichEnd = cch;
	if (ichAnchor > cch)
		ichAnchor = cch;
	// This can happen; apparently when a tab brings the focus to this window, Windows passes
	// a large number rather than -1 to set the end of the range.
	if (ichEnd > cch)
		ichEnd = cch;
	CheckHr(m_qrootb->MakeTextSelection(0, 0, NULL, ktagString, 0, ichAnchor, ichEnd, 0, true,
		-1, NULL, true, NULL));
}
Beispiel #8
0
/*----------------------------------------------------------------------------------------------
	Load the data needed to display this view. In this case, we need to load the class, owner
	(so we can tell whether it is a subitem), the title, and create date. If all of these are
	already in the cache, don't reload it.
	@param pvwenv Pointer to the view environment.
	@param hvo The id of the object we are displaying.
	@param frag Identifies the part of the view we are currently displaying.
	@return HRESULT indicating success (S_OK), or failure (E_FAIL).
----------------------------------------------------------------------------------------------*/
STDMETHODIMP CleRecVc::LoadDataFor(IVwEnv * pvwenv, HVO hvo, int frag)
{
	BEGIN_COM_METHOD;
	ChkComArgPtr(pvwenv);

	Assert(false);  // TODO: rework

	StrUni stuSql;
	ISilDataAccessPtr qsda;
	CheckHr(pvwenv->get_DataAccess(&qsda));
	bool fLoaded = false;
	int clid;
	CheckHr(qsda->get_IntProp(hvo, kflidCmObject_Class, &clid));
	if (clid)
	{
		HVO hvoOwn;
		CheckHr(qsda->get_ObjectProp(hvo, kflidCmObject_Owner, &hvoOwn));
		if (hvoOwn)
		{
			int64 tim;
			// REVIEW KenZ(RandyR) Whey are DN flids in this app?
			CheckHr(qsda->get_TimeProp(hvo, kflidRnGenericRec_DateCreated, &tim));
			if (tim)
			{
				ITsStringPtr qtss;
				CheckHr(qsda->get_StringProp(hvo, kflidRnGenericRec_Title, &qtss));
				if (qtss)
				{
					int cch;
					CheckHr(qtss->get_Length(&cch));
					if (cch)
						fLoaded = true;
				}
			}
		}
	}

	if (!fLoaded)
	{
		// If any field is missing from the cache, load everything.
		IDbColSpecPtr qdcs;
		IVwOleDbDaPtr qda;
		CheckHr(qsda->QueryInterface(IID_IVwOleDbDa, (void**)&qda));
		stuSql.Format(L"select id, Class$, Owner$, DateCreated, Title, Title_Fmt "
			L"from RnGenericRec_ "
			L"where id = %d", hvo);
		qdcs.CreateInstance(CLSID_DbColSpec);
		CheckHr(qdcs->Push(koctBaseId, 0, 0, 0));
		CheckHr(qdcs->Push(koctInt, 1, kflidCmObject_Class, 0));
		CheckHr(qdcs->Push(koctObj, 1, kflidCmObject_Owner, 0));
			// REVIEW KenZ(RandyR) Whey are DN flids in this app?
		CheckHr(qdcs->Push(koctTime, 1, kflidRnGenericRec_DateCreated, 0));
		CheckHr(qdcs->Push(koctString, 1, kflidRnGenericRec_Title, 0));
		CheckHr(qdcs->Push(koctFmt, 1, kflidRnGenericRec_Title, 0));

		AfMainWnd * pafw = AfApp::Papp()->GetCurMainWnd();
		AssertPtr(pafw);
		AfStatusBar * pstbr = pafw->GetStatusBarWnd();
		AssertPtr(pstbr);
		bool fProgBar = pstbr->IsProgressBarActive();
		if (!fProgBar)
		{
			StrApp strMsg(kstidStBar_LoadingData);
			pstbr->StartProgressBar(strMsg.Chars(), 0, 70, 1);
		}

		// Execute the query and store results in the cache.
		CheckHr(qda->Load(stuSql.Bstr(), qdcs, hvo, 0, pstbr, NULL));
		if (!fProgBar)
			pstbr->EndProgressBar();
	}

	return S_OK;

	END_COM_METHOD(g_fact2, IID_IVwViewConstructor)
}
Beispiel #9
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 #10
0
/*----------------------------------------------------------------------------------------------
	Add a field editor for a given field at the location and indent specified.

	@param hvoRoot Id of the root object that holds the fields we want to display.
	@param clid Class of the root object.
	@param nLev Level (main/sub) of the root object in the window.
	@param pfsp The FldSpec that defines this field.
	@param pcvd Pointer to the CustViewDa specifying what fields to display.
	@param idfe Index where the new fields are to be inserted. On return it contains
		an index to the field following any inserted fields.
	@param nInd Indent of the fields to be added.
	@param fAlwaysVisible If true, show field regardless of pbsp->m_eVisibility
----------------------------------------------------------------------------------------------*/
void CleDeSplitChild::AddField(HVO hvoRoot, int clid, int nLev, FldSpec * pfsp,
	CustViewDa * pcvd, int & idfe, int nInd, bool fAlwaysVisible)
{
	AssertPtr(pcvd);
	AssertPtr(pfsp);

	bool fCheckMissingData = fAlwaysVisible ? false : pfsp->m_eVisibility == kFTVisIfData;

	// If the user never wants to see this field, skip it.
	if (pfsp->m_eVisibility == kFTVisNever)
		return;

	ITsStringPtr qtss;

	AfLpInfo * plpi = pcvd->GetLpInfo();
	AssertPtr(plpi);

	AfStatusBarPtr qstbr = MainWindow()->GetStatusBarWnd();
	Assert(qstbr);

	switch(pfsp->m_ft)
	{
	case kftEnum:
		{
			AfDeFeComboBox * pdecb = NewObj AfDeFeComboBox();
			ITsStrFactoryPtr qtsf;
			qtsf.CreateInstance(CLSID_TsStrFactory);
			int itss;
			CheckHr(pcvd->get_IntProp(hvoRoot, pfsp->m_flid, &itss));
			pdecb->Initialize(hvoRoot, pfsp->m_flid, nInd, pfsp->m_qtssLabel,
				pfsp->m_qtssHelp, this, pfsp);
			pdecb->Init(pfsp->m_pnt);
			ComVector<ITsString> * pvtss;
			pvtss = pdecb->GetVec();
			int stid;
			switch (pfsp->m_flid)
			{
			case kflidCmPerson_Gender:
				stid = kstidEnumGender;
				break;
#ifdef ADD_LEXTEXT_LISTS
			case kflidCmAnnotationDefn_AllowsComment: // Fall through.
			case kflidCmAnnotationDefn_AllowsFeatureStructure: // Fall through.
			case kflidCmAnnotationDefn_AllowsInstanceOf: // Fall through.
			case kflidCmAnnotationDefn_UserCanCreate: // Fall through.
			case kflidCmAnnotationDefn_CanCreateOrphan: // Fall through.
			case kflidCmAnnotationDefn_PromptUser: // Fall through.
			case kflidCmAnnotationDefn_CopyCutPastable: // Fall through.
			case kflidCmAnnotationDefn_ZeroWidth: // Fall through.
			case kflidCmAnnotationDefn_Multi: // Fall through.
#endif
			case kflidMoInflAffixSlot_Optional: // Fall through.
			case kflidCmPerson_IsResearcher:
				stid = kstidEnumNoYes;
				if (itss)
					itss = 1;
				break;
			default:
				Assert(false); // A list must be provided above.
				break;
			}
			StrUni stuEnum(stid);
			const wchar * pszEnum = stuEnum.Chars();
			const wchar * pszEnumLim = stuEnum.Chars() + stuEnum.Length();
			while (pszEnum < pszEnumLim)
			{
				const wchar * pszEnumNl = wcschr(pszEnum, '\n');
				if (!pszEnumNl)
					pszEnumNl = pszEnumLim;

				AfDbInfo * pdbi = plpi->GetDbInfo();
				AssertPtr(pdbi);
				int wsUser = pdbi->UserWs();

				qtsf->MakeStringRgch(pszEnum, pszEnumNl - pszEnum, wsUser,
					&qtss);
				pvtss->Push(qtss);
				pszEnum = pszEnumNl + 1;
			}
			pdecb->SetIndex(itss);
			m_vdfe.Insert(idfe++, pdecb);
		}
		return;

	case kftMsa:	// Fall through.
	case kftMta:
		{
			Vector<int> vwsT;
			Vector<int> & vws = vwsT;

			// We need a special editor for name and address to catch changes to update the
			// tree views.
			if ((pfsp->m_flid == kflidCmPossibility_Name) ||
				(pfsp->m_flid == kflidCmPossibility_Abbreviation))
			{
				CleMainWnd * pcmw = dynamic_cast<CleMainWnd *>(MainWindow());
				Assert(pcmw);
		//		PossListInfoPtr qpli = pcmw->GetPossListInfoPtr();
				int wsPL= pcmw->GetWsPssl();
				switch (wsPL)
				{
				case kwsAnals:
					vws = plpi->AnalWss();
					break;
				case kwsVerns:
					vws = plpi->VernWss();
					break;
				case kwsAnal:
					vwsT.Push(plpi->AnalWs());
					break;
				case kwsVern:
					vwsT.Push(plpi->VernWs());
					break;
				case kwsAnalVerns:
					vws = plpi->AnalVernWss();
					break;
				case kwsVernAnals:
					vws = plpi->VernAnalWss();
					break;
				default:
					vwsT.Push(wsPL);
					break;
				}

				if (fCheckMissingData)
				{
					ITsStringPtr qtss;
					int iws;
					for (iws = vws.Size(); --iws >= 0; )
					{
						CheckHr(pcvd->get_MultiStringAlt(hvoRoot, pfsp->m_flid, vws[iws],
							&qtss));
						int cch;
						CheckHr(qtss->get_Length(&cch));
						if (cch)
							break;
					}
					if (iws < 0)
						return; // All writing systems are empty.
				}
				// An extra ref cnt is created here which is eventually assigned to the vector.
				CleDeFeStringPtr qdfs = NewObj CleDeFeString;
				qdfs->Initialize(hvoRoot, pfsp->m_flid, nInd, pfsp->m_qtssLabel,
					pfsp->m_qtssHelp, this, pfsp);

				if (pfsp->m_ft == kftMta)
					qdfs->Init(&vws, ktptSemiEditable);
				else
					qdfs->Init(&vws, ktptIsEditable);

				m_vdfe.Insert(idfe++, qdfs);
			}
			else
			{
				switch (pfsp->m_ws)
				{
				case kwsAnals:
					vws = plpi->AnalWss();
					break;
				case kwsVerns:
					vws = plpi->VernWss();
					break;
				case kwsAnal:
					vwsT.Push(plpi->AnalWs());
					break;
				case kwsVern:
					vwsT.Push(plpi->VernWs());
					break;
				case kwsAnalVerns:
					vwsT = plpi->AnalVernWss();
					break;
				case kwsVernAnals:
					vwsT = plpi->VernAnalWss();
					break;
				default:
					vwsT.Push(pfsp->m_ws);
					Assert(pfsp->m_ws);
					break;
				}

				if (fCheckMissingData)
				{
					ITsStringPtr qtss;
					int iws;
					for (iws = vws.Size(); --iws >= 0; )
					{
						CheckHr(pcvd->get_MultiStringAlt(hvoRoot, pfsp->m_flid, vws[iws],
							&qtss));
						int cch;
						CheckHr(qtss->get_Length(&cch));
						if (cch)
							break;
					}
					if (iws < 0)
						return; // All writing systems are empty.
				}
				// An extra ref cnt is created here which is eventually assigned to the vector.
				AfDeFeStringPtr qdfs = NewObj AfDeFeString;
				qdfs->Initialize(hvoRoot, pfsp->m_flid, nInd, pfsp->m_qtssLabel,
					pfsp->m_qtssHelp, this, pfsp);

				if (pfsp->m_ft == kftMta)
					qdfs->Init(&vws, ktptSemiEditable);
				else
					qdfs->Init(&vws, ktptIsEditable);

				m_vdfe.Insert(idfe++, qdfs);
			}

		}
		return;
	case kftExpandable:	// Fall through.
	case kftSubItems:
		return;

	case kftObjRefAtomic:	// Fall through.
	case kftObjRefSeq:
		{
			bool fMultiRefs;
			if (pfsp->m_ft == kftObjRefAtomic)
			{
				HVO hvoRef;
				CheckHr(pcvd->get_ObjectProp(hvoRoot, pfsp->m_flid, &hvoRef));
				fMultiRefs = false;
				if (fCheckMissingData && !hvoRef)
					return;
			}
			else
			{
				fMultiRefs = true;
				if (fCheckMissingData) // otherwise no need to check
				{
					int chvo;
					CheckHr(pcvd->get_VecSize(hvoRoot, pfsp->m_flid, &chvo));
					if (!chvo)
						return;
				}
			}
			AfDeFeRefs * pdfr = NewObj AfDeFeRefs;
			pdfr->Initialize(hvoRoot, pfsp->m_flid, nInd, pfsp->m_qtssLabel,
				pfsp->m_qtssHelp, this, pfsp);
			switch (pfsp->m_flid)
			{
			default:
				// Standard kftObjRefAtomic & kftObjRefSeq fields are all handled in the superclass.
				SuperClass::AddField(hvoRoot, clid, nLev, pfsp, pcvd, idfe, nInd, fAlwaysVisible);
				return;
			}
			m_vdfe.Insert(idfe++, pdfr);
		}
		return;
	}
	qstbr->StepProgressBar(10);

	// Standard fields are all handled in the superclass.
	SuperClass::AddField(hvoRoot, clid, nLev, pfsp, pcvd, idfe, nInd, fAlwaysVisible);
	return;
}