int InsertObject(int flid, int newObjectClassId)
{
CheckDisposed();
bool fAbstract = m_cache.DomainDataByFlid.MetaDataCache.GetAbstract(newObjectClassId);
if (fAbstract)
{
// We've been handed an abstract class to insert. Try to determine the desired
// concrete from the context.
if (newObjectClassId == MoFormTags.kClassId && Object is ILexEntry)
{
var entry = (Object as ILexEntry);
newObjectClassId = entry.GetDefaultClassForNewAllomorph();
}
else
{
return -1;
}
}
// OK, we can add to property flid of the object of slice slice.
int insertionPosition = 0;//leave it at 0 if it does not matter
int hvoOwner = Object.Hvo;
int clidOwner = Object.ClassID;
int clidOfFlid = flid / 1000;
if (clidOwner != clidOfFlid && clidOfFlid == Object.Owner.ClassID)
{
hvoOwner = Object.Owner.Hvo;
}
int type = GetFieldType(flid);
if (type == (int)CellarPropertyType.OwningSequence)
{
try
{
// We might not be on the right slice to insert this item. See FWR-898.
insertionPosition = Cache.DomainDataByFlid.get_VecSize(hvoOwner, flid);
}
catch
{
return -1;
}
if (ContainingDataTree != null && ContainingDataTree.CurrentSlice != null)
{
ISilDataAccess sda = m_cache.DomainDataByFlid;
int chvo = insertionPosition;
// See if the current slice in any way indicates a position in that property.
object[] key = ContainingDataTree.CurrentSlice.Key;
bool fGotIt = false;
for (int ikey = key.Length - 1; ikey >= 0 && !fGotIt; ikey--)
{
if (!(key[ikey] is int))
continue;
var hvoTarget = (int)key[ikey];
for (int i = 0; i < chvo; i++)
{
if (hvoTarget == sda.get_VecItem(hvoOwner, flid, i))
{
insertionPosition = i + 1; // insert after current object.
fGotIt = true; // break outer loop
break;
}
}
}
}
}
var slices = new Set<Slice>(ContainingDataTree.Slices);
// Save DataTree for the finally block. Note premature return below due to IsDisposed. See LT-9005.
DataTree dtContainer = ContainingDataTree;
try
{
dtContainer.SetCurrentObjectFlids(hvoOwner, flid);
var fieldType = (CellarPropertyType) m_cache.MetaDataCacheAccessor.GetFieldType(flid);
switch (fieldType)
{
case CellarPropertyType.OwningCollection:
insertionPosition = -1;
break;
case CellarPropertyType.OwningAtomic:
insertionPosition = -2;
break;
}
using (CmObjectUi uiObj = CmObjectUi.CreateNewUiObject(m_mediator, newObjectClassId, hvoOwner, flid, insertionPosition))
{
// If uiObj is null, typically CreateNewUiObject displayed a dialog and the user cancelled.
// We return -1 to make the caller give up trying to insert, so we don't get another dialog if
// there is another slice that could insert this kind of object.
// If 'this' isDisposed, typically the inserted object occupies a place in the record list for
// this view, and inserting an object caused the list to be refreshed and all slices for this
// record to be disposed. In that case, we won't be able to find a child of this to activate,
// so we'll just settle for having created the object.
// Enhance JohnT: possibly we could load information from the slice into local variables before
// calling CreateNewUiObject so that we could do a better job of picking the slice to focus
// after an insert which disposes 'this'. Or perhaps we could improve the refresh list process
// so that it more successfully restores the current item without disposing of all the slices.
if (IsDisposed)
return -1;
if (uiObj == null)
return -2; // Nothing created.
switch (fieldType)
{
case CellarPropertyType.OwningCollection:
// order is not fully predicatable, figure where it DID show up.
insertionPosition = m_cache.DomainDataByFlid.GetObjIndex(hvoOwner, flid, uiObj.Object.Hvo);
break;
case CellarPropertyType.OwningAtomic:
insertionPosition = 0;
break;
}
// if (ihvoPosition == ClassAndPropInfo.kposNotSet && cpi.fieldType == DataTree.kcptOwningSequence)
// {
// // insert at end of sequence.
// ihvoPosition = cache.DomainDataByFlid.get_VecSize(hvoOwner, (int)cpi.flid);
// } // otherwise we already worked out the position or it doesn't matter
// // Note: ihvoPosition ignored if sequence(?) or atomic.
// int hvoNew = cache.CreateObject((int)(cpi.signatureClsid), hvoOwner, (int)(cpi.flid), ihvoPosition);
// cache.DomainDataByFlid.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoOwner, (int)(cpi.flid), ihvoPosition, 1, 0);
if (hvoOwner == Object.Hvo && Expansion == DataTree.TreeItemState.ktisCollapsed)
{
// We added something to the object of the current slice...almost certainly it
// will be something that will display under this node...if it is still collapsed,
// expand it to show the thing inserted.
TreeNode.ToggleExpansion(IndexInContainer);
}
Slice child = ExpandSubItem(uiObj.Object.Hvo);
if (child != null)
child.FocusSliceOrChild();
else
{
// If possible, jump to the newly inserted sub item.
if (m_mediator.BroadcastMessageUntilHandled("JumpToRecord", uiObj.Object.Hvo))
return insertionPosition;
// If we haven't found a slice...common now, because there's rarely a need to expand anything...
// and some slice was added, focus it.
foreach (Slice slice in Parent.Controls)
{
if (!slices.Contains(slice))
{
slice.FocusSliceOrChild();
break;
}
}
}
}
}
finally
{
dtContainer.ClearCurrentObjectFlids();
}
return insertionPosition;
}