/// <summary> /// Integrate changes in dummy cache to real cache and DB. /// </summary> public void ConnectToRealCache() { // (FLEx) Review use of ISilDataAccess and other C++ cache related classes CheckDisposed(); // If an Undo or Redo is in progress, we CAN'T save the changes. Ideally it wouldn't be necessary because making // any savable change in the slice would discard any pending Redo, and Undo would undo any changes in the slice // before undoing anything else. Currently Undo within the slice is not this well integrated. However, doing some editing // in the slice and then Undoing or Redoing a previous command DOES save the changes in the slice; I think OnLeave() must // be called somewhere in the process of invoking Undo before it is too late. This is not ideal behavior, but it // beats crashing. if (m_fdoCache.ActionHandlerAccessor.IsUndoOrRedoInProgress) return; Form frm = FindForm(); WaitCursor wc = null; try { // frm will be null, if the record has been switched if (frm != null) wc = new WaitCursor(frm); // We're saving any changes to the real cache, so can no longer Undo/Redo local edits. CommitLocalEdits(); // [NB: m_silCache is the same cache as m_vwCache, but is is a different cache than // m_fdoCache. m_fdoCache has access to the database, and updates it, but // m_silCache does not.] if (DesignMode || m_rootb == null // It may not be valid by now, since it may have been deleted. || !m_rootObj.IsValidObject) { if (frm != null) frm.Cursor = Cursors.Default; return; } string fieldname = (m_rootFlid == MoAffixAllomorphTags.kflidPhoneEnv) ? "PhoneEnv" : "Position"; m_fdoCache.DomainDataByFlid.BeginUndoTask( String.Format(DetailControlsStrings.ksUndoSet, fieldname), String.Format(DetailControlsStrings.ksRedoSet, fieldname)); IPhEnvironmentFactory environmentFactory = m_fdoCache.ServiceLocator.GetInstance<IPhEnvironmentFactory>(); IFdoOwningSequence<IPhEnvironment> allAvailablePhoneEnvironmentsInProject = m_fdoCache.LanguageProject.PhonologicalDataOA.EnvironmentsOS; var envsBeingRequestedForThisEntry = EnvsBeingRequestedForThisEntry(); // Environments just typed into slice that are not already used for // this entry or known about in the project. var newEnvsJustTyped = envsBeingRequestedForThisEntry.Where(localDummyHvoOfAnEnvInEntry => !allAvailablePhoneEnvironmentsInProject .Select(projectEnv => RemoveSpaces(projectEnv.StringRepresentation.Text)) .Contains(RemoveSpaces(GetStringOfEnvironment(localDummyHvoOfAnEnvInEntry)))); // Add the unknown/new environments to project foreach (var localDummyHvoOfAnEnvironmentInEntry in newEnvsJustTyped) { ITsString envTssRep = GetTsStringOfEnvironment( localDummyHvoOfAnEnvironmentInEntry); IPhEnvironment newEnv = environmentFactory.Create(); allAvailablePhoneEnvironmentsInProject.Add(newEnv); newEnv.StringRepresentation = envTssRep; } var countOfExistingEnvironmentsInDatabaseForEntry = m_fdoCache.DomainDataByFlid.get_VecSize(m_rootObj.Hvo, m_rootFlid); // Contains environments already in entry or recently selected in // dialog, but not ones just typed int[] existingListOfEnvironmentHvosInDatabaseForEntry; int chvoMax = m_fdoCache.DomainDataByFlid.get_VecSize( m_rootObj.Hvo, m_rootFlid); using (ArrayPtr arrayPtr = MarshalEx.ArrayToNative<int>(chvoMax)) { m_fdoCache.DomainDataByFlid.VecProp(m_rootObj.Hvo, m_rootFlid, chvoMax, out chvoMax, arrayPtr); existingListOfEnvironmentHvosInDatabaseForEntry = MarshalEx.NativeToArray<int>(arrayPtr, chvoMax); } // Build up a list of real hvos used in database for the // environments in the entry var newListOfEnvironmentHvosForEntry = new List<int>(); foreach (var localDummyHvoOfAnEnvironmentInEntry in envsBeingRequestedForThisEntry) { ITsString envTssRep = GetTsStringOfEnvironment( localDummyHvoOfAnEnvironmentInEntry); string envStringRep = envTssRep.Text; // Pick a sensible environment from the known environments in // the project, by string IPhEnvironment anEnvironmentInEntry = FindPhoneEnv( allAvailablePhoneEnvironmentsInProject, envStringRep, newListOfEnvironmentHvosForEntry.ToArray(), existingListOfEnvironmentHvosInDatabaseForEntry); // Maybe the ws has changed, so change the real env in database, // in case. anEnvironmentInEntry.StringRepresentation = envTssRep; ITsStrBldr bldr = envTssRep.GetBldr(); ConstraintFailure failure; if (anEnvironmentInEntry.CheckConstraints(PhEnvironmentTags.kflidStringRepresentation, false, out failure, true)) ClearSquigglyLine(localDummyHvoOfAnEnvironmentInEntry, ref envTssRep, ref bldr); else MakeSquigglyLine(localDummyHvoOfAnEnvironmentInEntry, failure.XmlDescription, ref envTssRep, ref bldr); newListOfEnvironmentHvosForEntry.Add(anEnvironmentInEntry.Hvo); // Refresh m_sda.SetString(localDummyHvoOfAnEnvironmentInEntry, kEnvStringRep, bldr.GetString()); m_rootb.PropChanged(localDummyHvoOfAnEnvironmentInEntry, kEnvStringRep, 0, envTssRep.Length, envTssRep.Length); } // Only reset the main property, if it has changed. // Otherwise, the parser gets too excited about needing to reload. if ((countOfExistingEnvironmentsInDatabaseForEntry != newListOfEnvironmentHvosForEntry.Count()) || !equalArrays(existingListOfEnvironmentHvosInDatabaseForEntry, newListOfEnvironmentHvosForEntry.ToArray())) { m_fdoCache.DomainDataByFlid.Replace(m_rootObj.Hvo, m_rootFlid, 0, countOfExistingEnvironmentsInDatabaseForEntry, newListOfEnvironmentHvosForEntry.ToArray(), newListOfEnvironmentHvosForEntry.Count()); } m_fdoCache.DomainDataByFlid.EndUndoTask(); } finally { if (wc != null) { wc.Dispose(); wc = null; } } }