Exemplo n.º 1
0
/*----------------------------------------------------------------------------------------------
	Close the current editor, saving changes that were made.  This also updates the the cache
	if the name or abbr fields were edited, this then causing the treebar to be updated.
	@param fForce True if we want to force the editor closed without making any
		validity checks or saving any changes.
----------------------------------------------------------------------------------------------*/
void CleDeFeString::EndEdit(bool fForce)
{
	if (fForce)
	{
		SuperClass::EndEdit(fForce);
		return;
	}

	CleMainWnd * pcmw = dynamic_cast<CleMainWnd *>(MainWindow());
	Assert(pcmw);

	PossListInfoPtr qpli = pcmw->GetPossListInfoPtr();
	int ipss = qpli->GetIndexFromId(m_hvoObj);
	if (ipss < 0)
	{
		SuperClass::EndEdit(fForce); // Closing an old editor after an item was removed.
		return;
	}
	PossItemInfo * ppii = qpli->GetPssFromIndex(ipss);
	AssertPtr(ppii);
	StrUni stu;

	const OLECHAR * prgwch;
	int cch;
	ITsStringPtr qtss;
	AssertPtr(m_qadsc->MainWindow());
	AfLpInfo * plpi = m_qadsc->MainWindow()->GetLpInfo();
	AssertPtr(plpi);
	AfDbInfo * pdbi;
	pdbi = plpi->GetDbInfo();
	AssertPtr(pdbi);
	int wsMagic = qpli->GetWs();
	int ws = plpi->ActualWs(wsMagic);

	// At this point, all strings in a PossList cache are assumed to have the same writing system.
	// However, if that writing system is missing, a non-null string from a different writing system is
	// loaded. Thus if FRN is the writing system for the PossList cache, we can't tell from the
	// cache whether the string we are getting is FRN or ENG, or some other writing system. When
	// we display strings in this editor, we show actual strings for each writing system shown.
	// Suppose we are showing FRN and ENG, but FRN is missing. If a person edits the ENG
	// string that is showing, the user would expect the tree to reflect this change, since
	// FRN is still missing. However we can't do this at this point because we don't know
	// which writing system is actually being substituted in the tree. It could actually be a GER
	// string because there also wasn't an ENG string. So until we cache encodings with each
	// string, the best we can do is only modify the PossList cache if the string for the
	// primary writing system changed. In that case, we now have a FRN string, so it should show
	// in the tree as well.
	CustViewDaPtr qcvd = pcmw->MainDa();
	AssertPtr(qcvd);

	// Get the current primary string.
	CheckHr(qcvd->get_MultiStringAlt(m_hvoObj, m_flid, ws, &qtss));
	if (qtss)
	{
		qtss->LockText(&prgwch, &cch);
		qtss->UnlockText(prgwch);
	}

	// Trim leading and trailing space characters.
	UnicodeString ust(prgwch, cch);
	ust.trim();
	stu.Assign(ust.getBuffer(), ust.length());

	// We don't expect to use this for anything except name or abbr.
	Assert(m_flid == kflidCmPossibility_Name || m_flid == kflidCmPossibility_Abbreviation);
	// We don't allow long strings.
	if (stu.Length() > kcchPossNameAbbrMax) // Need constant here and the line below.
	{
		::MessageBeep(MB_ICONEXCLAMATION); // Beep if we truncated the length.
		stu.Replace(kcchPossNameAbbrMax, stu.Length(), L"");
	}

	ITsStrFactoryPtr qtsf;
	qtsf.CreateInstance(CLSID_TsStrFactory);
	qtsf->MakeStringRgch(stu.Chars(), stu.Length(), ws, &qtss);

	// If we changed the length, store the trimmed string.
	if (cch != stu.Length())
	{
		// Check if the record has been edited by someone else since we first loaded the data.
		HRESULT hrTemp;
		if ((hrTemp = qcvd->CheckTimeStamp(m_hvoObj)) != 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 its original value.
			CheckHr(qcvd->PropChanged(NULL, kpctNotifyAll, m_hvoObj, m_flid, 0, 1, 1));
			return;
		}

		// Update the value in the cache and refresh views.
		CheckHr(qcvd->SetMultiStringAlt(m_hvoObj, m_flid, ws, qtss));
		CheckHr(qcvd->PropChanged(NULL, kpctNotifyAll, m_hvoObj, m_flid, 0, 1, 1));
	}

	SuperClass::EndEdit(fForce);

	// See if the primary string has changed.
	ComBool fEqual;
	CheckHr(qtss->Equals(m_qtssOld, &fEqual));
	if (fEqual)
		return; // No change was made, so we don't need to do anything else.

	// A change was made.
	if (m_flid != kflidCmPossibility_Name && m_flid != kflidCmPossibility_Abbreviation)
		return; // Nothing more to do if it isn't a name or abbreviation.

	// We've changed the primary name or abbreviation, so update the PossList cache.
	ppii->SetName(stu, m_flid == kflidCmPossibility_Name ? kpntName : kpntAbbreviation);

	if (qpli->GetIsSorted())
	{
		// The list is sorted, so we need to move the item to its new location.
		if (qpli->PutInSortedPosition(m_hvoObj, false))
		{
			int ihvo;
			pcmw->LoadData();
			HvoClsidVec & vhc = pcmw->Records();
			for (ihvo = vhc.Size(); --ihvo >= 0; )
			{
				if (vhc[ihvo].hvo == m_hvoObj)
					break;
			}
			Assert(ihvo >= 0); // Should have found item.
			pcmw->SetCurRecIndex(ihvo);
		}
	}
	// We can't do a sync in this method that opens new editors, so just flag
	// that it needs to be done.
	// We need to sync if either name or abbreviation has changed. Even though we may only
	// be showing one or the other in our lists, there may be overlays or something else
	// showing the other, so to be safe, we need to do a sync if either changed.
	dynamic_cast<CleDeSplitChild *>(m_qadsc.Ptr())->SetNeedSync(true);
}
Exemplo n.º 2
0
/*----------------------------------------------------------------------------------------------
	This processes Windows messages on the window. In general, it normally calls the
	appropriate method on the edit class.
----------------------------------------------------------------------------------------------*/
bool TssEdit::FWndProc(uint wm, WPARAM wp, LPARAM lp, long & lnRet)
{
	bool fRet;

	switch (wm)
	{
	case WM_GETDLGCODE:
		// This is essential when embedded in a dialog to tell the dialog manager that it
		// wants to get key strokes. (We could try DLGC_WANTALLKEYS but I think we would then
		// get the Tab and Return keys...we may get them anyway with this combination...)
		// The last value tells Windows that when tabbing to this control we should use
		// EM_SETSEL to select all the text.
		lnRet = DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL;
		return true;
	case EM_GETLINE:	// Use FW_EM_GETLINE.
	case EM_REPLACESEL:	// Use FW_EM_REPLACESEL.
		// We don't support these methods. Use the replacement TsString versions instead.
		Assert(false);
		lnRet = LB_ERR;
		return true;

	// NOTE: DO NOT send this message to a TssEdit if you want the actual text. Send the
	// FW_EM_GETTEXT message instead. This method is required for TssEdit controls on a
	// dialog because Windows will send the message to the control anytime the user hits a
	// key.
	case WM_GETTEXT:
		{
			ITsStringPtr qtss;
			GetText(&qtss);
			const wchar * pwrgch;
			int cch;
			HRESULT hr;
			IgnoreHr(hr = qtss->LockText(&pwrgch, &cch));
			if (FAILED(hr))
				return true;
			StrApp str(pwrgch, cch);
			qtss->UnlockText(pwrgch);
			lnRet = Min(cch + 1, (int)wp);
			achar * psz = reinterpret_cast<achar *>(lp);
			StrCpyN(psz, str.Chars(), lnRet);
		}
		return true;

	// NOTE: You should be sending an FW_EM_SETTEXT message instead of this.
	case WM_SETTEXT:
		{
			achar * psz = reinterpret_cast<achar *>(lp);
			StrUni stu(psz);
			ITsStrFactoryPtr qtsf;
			qtsf.CreateInstance(CLSID_TsStrFactory);
			ITsStringPtr qtss;
			CheckHr(qtsf->MakeStringRgch(stu.Chars(), stu.Length(), m_wsBase, &qtss));
			SetText(qtss);
		}
		return true;

	case EM_CANUNDO:
	case EM_CHARFROMPOS:
	case EM_EMPTYUNDOBUFFER:
	case EM_FMTLINES:
	case EM_GETFIRSTVISIBLELINE:
	case EM_GETHANDLE:
	case EM_GETMODIFY:
	case EM_GETPASSWORDCHAR:
	case EM_GETRECT:
	case EM_GETTHUMB:
	case EM_GETWORDBREAKPROC:
	case EM_POSFROMCHAR:
	case EM_SETHANDLE:
	case EM_SETMODIFY:
	case EM_SETPASSWORDCHAR:
	case EM_SETRECT:
	case EM_SETRECTNP:
	case EM_SETTABSTOPS:
	case EM_SETWORDBREAKPROC:
	case EM_UNDO:
	case WM_GETFONT:
	case WM_SETFONT:
		// We don't support these methods.
		Assert(false);
		lnRet = LB_ERR;
		return true;

	case EM_GETLIMITTEXT:
		lnRet = GetLimitText();
		return true;

	case FW_EM_GETLINE:
		lnRet = GetLine(wp, (ITsString **)lp);
		return true;

	case EM_GETLINECOUNT:
		lnRet = GetLineCount();
		return true;

	case EM_GETMARGINS:
		lnRet = GetMargins();
		return true;

	case FW_EM_GETSTYLE:
		GetStyle((StrUni *)lp, (COLORREF *)wp);
		return true;

	case EM_GETSEL:
		lnRet = GetSel((int *)wp, (int *)lp);
		return true;

	case EM_LINEFROMCHAR:
		lnRet = LineFromChar(wp);
		return true;

	case EM_LINEINDEX:
		lnRet = LineIndex(wp);
		return true;

	case EM_LINELENGTH:
		lnRet = LineLength(wp);
		return true;

	case EM_LINESCROLL:
		LineScroll(lp, wp);
		return true;

	case FW_EM_REPLACESEL:
		ReplaceSel((ITsString *)lp);
		return true;

	case EM_SCROLL:
		lnRet = ::SendMessage(m_hwnd, WM_VSCROLL, LOWORD(wp), 0);
		return true;

	case EM_SCROLLCARET:
		ScrollCaret();
		return true;

	case EM_SETLIMITTEXT:
		SetLimitText(wp);
		return true;

	case EM_SETMARGINS:
		SetMargins(wp, LOWORD(lp), HIWORD(lp));
		return true;

	case EM_SETREADONLY:
		SetReadOnly(wp);
		return true;

	case EM_SETSEL:
		SetSel(wp, lp);
		return true;

	case FW_EM_SETSTYLE:
		SetStyle((StrUni *)lp, (COLORREF)wp);
		return true;

	case WM_GETTEXTLENGTH:
		lnRet = GetTextLength();
		return true;

	case FW_EM_GETTEXT:
		GetText((ITsString **)lp);
		return true;

	case FW_EM_SETTEXT:
		SetText((ITsString *)lp);
		return true;

	case WM_COPY:
		Copy();
		return true;

	case WM_CUT:
		Cut();
		return true;

	case WM_PASTE:
		Paste();
		return true;

	case WM_HSCROLL:
		if (!OnHScroll(LOWORD(wp), HIWORD(wp), (HWND)lp))
		{
			::SendMessage(::GetParent(m_hwnd), WM_COMMAND,
				MAKEWPARAM(::GetDlgCtrlID(m_hwnd), EN_HSCROLL), (LPARAM)m_hwnd);
		}
		return true;

	case WM_VSCROLL:
		if (!OnVScroll(LOWORD(wp), HIWORD(wp), (HWND)lp))
		{
			::SendMessage(::GetParent(m_hwnd), WM_COMMAND,
				MAKEWPARAM(::GetDlgCtrlID(m_hwnd), EN_VSCROLL), (LPARAM)m_hwnd);
		}
		return true;

	case WM_KILLFOCUS:
		if (!OnKillFocus((HWND)wp))
		{
			::SendMessage(::GetParent(m_hwnd), WM_COMMAND,
				MAKEWPARAM(::GetDlgCtrlID(m_hwnd), EN_KILLFOCUS), (LPARAM)m_hwnd);
		}
		return true;

	case WM_SETFOCUS:
		if (!OnSetFocus((HWND)wp))
		{
			::SendMessage(::GetParent(m_hwnd), WM_COMMAND,
				MAKEWPARAM(::GetDlgCtrlID(m_hwnd), EN_SETFOCUS), (LPARAM)m_hwnd);
		}
		return true;
		// Calling SuperClass here causes two OnSetFocus calls for each OnKillFocus.
		//return SuperClass::FWndProc(wm, wp, lp, lnRet);

	case WM_CHAR:
		fRet = false;
		if (wp == VK_TAB)  // '\t'
		{
			fRet = OnCharTab();
		}
		else if (wp == VK_RETURN) // '\r'
		{
			fRet = OnCharEnter();
		}
		else if (wp == VK_ESCAPE) // '\33'
		{
			fRet = OnCharEscape();
		}
		if (fRet)
			return fRet;
		else
			return SuperClass::FWndProc(wm, wp, lp, lnRet);

	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_MBUTTONDOWN:
	case WM_MBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
	case WM_MOUSEMOVE:
		if (HasToolTip())
		{
			// Notify the tooltip belonging to the parent toolbar of the mouse message.
			Assert(m_hwndToolTip);
			MSG msg;
			msg.hwnd = m_hwnd; // ::GetParent(m_hwnd);
			msg.message = wm;
			msg.wParam = wp;
			msg.lParam = lp;
			::SendMessage(m_hwndToolTip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
		}
		break;

	default:
		break;
	}
	return SuperClass::FWndProc(wm, wp, lp, lnRet);
}
Exemplo n.º 3
0
/*----------------------------------------------------------------------------------------------
	Check to see if the edit box has valid data.  if so return true.  If not then put up a
	message to the user, then return false.
----------------------------------------------------------------------------------------------*/
bool CleDeFeString::IsOkToClose(bool fWarn)
{
	CleMainWnd * pcmw = dynamic_cast<CleMainWnd *>(m_qadsc->MainWindow());
	Assert(pcmw);

	IVwSelectionPtr qvwsel;
	CheckHr(m_qrootb->get_Selection(&qvwsel));
	if (qvwsel)
	{
		ComBool fOk;
		CheckHr(qvwsel->Commit(&fOk));
	}

	PossListInfoPtr qpli = pcmw->GetPossListInfoPtr();
	int ipss = qpli->GetIndexFromId(m_hvoObj);
	StrUni stuNew;

	const OLECHAR * prgwch;
	int cch;
	ITsStringPtr qtss;
	CustViewDaPtr qcvd;

	GetDataAccess(&qcvd);
	AssertPtr(qcvd);
	int ws = m_qsvc->WritingSystems()[0];

	CheckHr(qcvd->get_MultiStringAlt(m_hvoObj, m_flid, ws, &qtss));
	Assert(qtss);
	qtss->LockText(&prgwch, &cch);
	qtss->UnlockText(prgwch);

	// Trim leading and trailing space characters.
	UnicodeString ust(prgwch, cch);
	ust.trim();
	stuNew.Assign(ust.getBuffer(), ust.length());

	//  Obtain pointer to IOleDbEncap interface.
	IOleDbEncapPtr qode;
	IOleDbCommandPtr qodc;
	StrUni stuSql;
	ComBool fIsNull;
	ComBool fMoreRows;
	AssertPtr(m_qadsc->MainWindow());
	AfLpInfo * plpi = m_qadsc->MainWindow()->GetLpInfo();
	AssertPtr(plpi);
	AfDbInfo * pdbi = plpi->GetDbInfo();
	AssertPtr(pdbi);
	pdbi->GetDbAccess(&qode);
	AssertPtr(qode);
	CheckHr(qode->CreateCommand(&qodc));
	int cpii = qpli->GetCount();

	if ((m_flid == kflidCmPossibility_Name) || (m_flid == kflidCmPossibility_Abbreviation))
	{
		// Make sure it does not have a ":" or a " - " in the string
		int ich = stuNew.FindStr(L":");
		StrUni stuTmp;
		bool fFixed = false;
		while (ich > 0)
		{
			stuNew.Replace(ich,ich + 1,"-");
			fFixed = true;
			ich = stuNew.FindStr(L":");
		}
		ich = stuNew.FindStr(L" - ");
		while (ich > 0)
		{
			stuNew.Replace(ich,ich + 3,"-");
			fFixed = true;
			ich = stuNew.FindStr(L" - ");
		}
		if (fFixed)
		{
			if (fWarn)
			{
				ITsStrFactoryPtr qtsf;
				qtsf.CreateInstance(CLSID_TsStrFactory);
				qtsf->MakeStringRgch(stuNew.Chars(), stuNew.Length(), pcmw->UserWs(), &qtss);
				CheckHr(qcvd->SetMultiStringAlt(m_hvoObj, m_flid, ws, qtss));
				CheckHr(qcvd->PropChanged(NULL, kpctNotifyAll, m_hvoObj, m_flid, 0, 1, 1));
				StrApp strMsg(kstidFixedStr);
				StrApp strTitle(kstidFixedStrTitle);
				::MessageBox(m_hwnd, strMsg.Chars(), strTitle.Chars(),
					MB_OK | MB_ICONINFORMATION);
			}
			return false;
		}
	}

	if (qpli->GetAllowDup())
		return true;

	ILgWritingSystemFactoryPtr qwsf;
	pdbi->GetLgWritingSystemFactory(&qwsf);
	AssertPtr(qwsf);
	switch (m_flid)
	{
		case kflidCmPossibility_Name:
		{
			for (int ipii = 0; ipii < cpii; ipii++)
			{
				if (ipii == ipss)
					continue;
				PossItemInfo * ppii = qpli->GetPssFromIndex(ipii);
				AssertPtr(ppii);
				StrUni stu;
				ppii->GetName(stu, kpntName);
				if (stu == stuNew)
				{
					stuSql.Format(L"select ws from CmPossibility_Name "
						L"where obj = %d and ws = %d",
						ppii->GetPssId(), ws);
					CheckHr(qode->CreateCommand(&qodc));
					CheckHr(qodc->ExecCommand(stuSql.Bstr(), knSqlStmtSelectWithOneRowset));
					CheckHr(qodc->GetRowset(0));
					CheckHr(qodc->NextRow(&fMoreRows));

					if (fMoreRows)
					{
						if (fWarn)
						{
							// this name already exists
							IWritingSystemPtr qws;
							CheckHr(qwsf->get_EngineOrNull(ws, &qws));
							AssertPtr(qws);
							SmartBstr sbstr;
							qws->get_Name(ws, &sbstr);

							StrUni stu(kstidDupItemName);
							StrUni stuMsg;
							stuMsg.Format(stu,sbstr.Chars());
							StrApp str(stuMsg);
							StrApp strTitle(kstidDupItemTitle);
							::MessageBox(m_hwnd, str.Chars(), strTitle.Chars(),
								MB_OK | MB_ICONINFORMATION);
						}
						return false;
					}
				}
			}
			break;
		}
		case kflidCmPossibility_Abbreviation:
		{
			for (int ipii = 0; ipii < cpii; ipii++)
			{
				if (ipii == ipss)
					continue;
				PossItemInfo * ppii = qpli->GetPssFromIndex(ipii);
				AssertPtr(ppii);
				StrUni stu;
				ppii->GetName(stu, kpntAbbreviation);
				if (stu == stuNew)
				{
					stuSql.Format(L"select ws from CmPossibility_Abbreviation "
						L"where obj = %d and ws = %d",
						ppii->GetPssId(), ws);
					CheckHr(qode->CreateCommand(&qodc));
					CheckHr(qodc->ExecCommand(stuSql.Bstr(), knSqlStmtSelectWithOneRowset));
					CheckHr(qodc->GetRowset(0));
					CheckHr(qodc->NextRow(&fMoreRows));

					if (fMoreRows)
					{
						if (fWarn)
						{
							// this abbreviation already exists
							IWritingSystemPtr qws;
							CheckHr(qwsf->get_EngineOrNull(ws, &qws));
							AssertPtr(qws);
							SmartBstr sbstr;
							qws->get_Name(ws, &sbstr);

							StrUni stu(kstidDupItemAbbr);
							StrUni stuMsg;
							stuMsg.Format(stu,sbstr.Chars());
							StrApp str(stuMsg);
							StrApp strTitle(kstidDupItemTitle);
							::MessageBox(m_hwnd, str.Chars(), strTitle.Chars(),
								MB_OK | MB_ICONINFORMATION);
						}
						return false;
					}
				}
			}
			break;
		}
	}
	return true;
}