public void HandleCreateMenuItem(object sender, EventArgs ea) { Slice slice = m_dataEntryForm.CurrentSlice; if (slice != null) { ClassAndPropInfo cpi = (ClassAndPropInfo)m_rgcpiCreateOptions[((MenuItem)sender).Index]; var cache = slice.ContainingDataTree.Cache; int hvoOwner = cpi.hvoOwner; int ihvoPosition = cpi.ihvoPosition; if (ihvoPosition == ClassAndPropInfo.kposNotSet && cpi.fieldType == (int)CellarPropertyType.OwningSequence) { // 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.DomainDataByFlid.MakeNewObject((int)(cpi.signatureClsid), hvoOwner, (int)(cpi.flid), ihvoPosition); cache.DomainDataByFlid.PropChanged(null, (int)PropChangeType.kpctNotifyAll, hvoOwner, (int)(cpi.flid), ihvoPosition, 1, 0); m_helper = null; // allow old one to be garbage. if (hvoOwner == slice.Object.Hvo && slice.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. slice.TreeNode.ToggleExpansion(slice.IndexInContainer); } Slice child = slice.ExpandSubItem(hvoNew); if (child != null) { child.FocusSliceOrChild(); } } }
/// <summary> /// Append to options a sequence of ClassAndPropInfo objects indicating classes of object /// that can be added as siblings of the object represented by this slice. /// The ihvoPosition setting in the object will be for inserting before the object /// of the current slice if fBefore is true, after if it is false. /// </summary> /// <param name="options"></param> /// <param name="fBefore"></param> public void GetCreateSiblingOptions(Slice slice, List <ClassAndPropInfo> options, bool fBefore) { int hvoOwner; int flid; int ihvoPosition; if (!slice.GetSeqContext(out hvoOwner, out flid, out ihvoPosition)) { return; // empty } // If in a sequence, and if we want to insert after this object, increment the position. // In a collection ihvoPosition is not used. if (!fBefore) { ihvoPosition++; } int firstSibling = options.Count; slice.Cache.AddClassesForField((int)flid, true, options); // NB: Do NOT change this to a ForEach!! It must NOT operate on all items in the collection, // ONLY on the sibling options just added. for (int i = firstSibling; i < options.Count; ++i) { ClassAndPropInfo cpi = (ClassAndPropInfo)options[i]; cpi.hvoOwner = hvoOwner; cpi.ihvoPosition = ihvoPosition; } }
/// <summary> /// Setup DependencyPaths property /// </summary> /// <param name="configuration"></param> /// <param name="cache"></param> protected void SetupDependencies(XmlNode configuration, FdoCache cache) { if (DependencyPaths.Count > 0) { return; // already setup. } string dependsStr = XmlUtils.GetOptionalAttributeValue(configuration, "depends"); if (dependsStr == null || cache == null) { return; } string[] depends = dependsStr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); foreach (string fieldPath in depends) { string[] fieldtree = fieldPath.Split(new char[] { '.' }); List <int> tags = new List <int>(fieldtree.Length); string srcClassName = this.ClassName; foreach (string field in fieldtree) { int tag = cache.GetFlid(0, srcClassName, field); Debug.Assert(tag > 0, String.Format("Invalid dependency field {0} in field path {1}.", field, fieldPath)); if (tag <= 0) { break; } tags.Add(tag); if (tags.Count < fieldtree.Length) { string nextFieldName = fieldtree[tags.Count]; // make dst class the source class of next field uint clsidDst = 0; if (field == "OwnerHVO") { // handle the special case where we need the owning class // this is only possible if srcClassName is has a unique owner. // find the first class that owns the given 'classId' and the given fieldName. clsidDst = GetClassOwningClassAndFieldName(cache, srcClassName, nextFieldName); } else { ClassAndPropInfo cpi = cache.GetClassAndPropInfo((uint)tag); if (ClassHasField(cache, cache.GetClassName(cpi.signatureClsid), nextFieldName)) { clsidDst = cpi.signatureClsid; } else if (cpi.isAbstract) { // find a subclasses that could refer to the nextFieldName. clsidDst = GetSubclassOwningNextField(cache, tag, nextFieldName); } } srcClassName = cache.GetClassName(clsidDst); } } m_fieldPaths.Add(tags); } }
private void SetupGhostOwningFlidInfo(FdoCache cache, int ghostListFlid) { if (ghostListFlid == 0) return; IVwVirtualHandler vh; cache.TryGetVirtualHandler(ghostListFlid, out vh); m_vh = vh as FDOGhostSequencePropertyVirtualHandler; // the ghost owner is on the last level. m_cpiForOwningFlidForGhost = m_vh.RealOwningPath[m_vh.RealOwningPath.Count - 1]; }
/// <summary> /// Set up the submenu items for 'Create' and 'Insert' menus. /// </summary> protected void SetupContextMenu(Slice slice, SliceTreeNode sliceTreeNode) { // Get rid of old sub-menu items. m_mnuCreate.MenuItems.Clear(); m_helper = new ContextMenuHelper(sliceTreeNode); m_rgcpiCreateOptions = slice.Object.PropsAndClassesOwnedBy; // Fill in info about which object will be the new owner. for (int index = m_rgcpiCreateOptions.Count; --index >= 0;) { ClassAndPropInfo cpi = m_rgcpiCreateOptions[index]; cpi.hvoOwner = slice.Object.Hvo; } // Drop atomic property options if not empty for (int index = m_rgcpiCreateOptions.Count; --index >= 0;) { ClassAndPropInfo cpi = (ClassAndPropInfo)m_rgcpiCreateOptions[index]; if (cpi.fieldType == (int)FieldType.kcptOwningAtom) { FDO.FdoCache cache = slice.ContainingDataTree.Cache; if (cache.GetObjProperty(cpi.hvoOwner, (int)(cpi.flid)) != 0) { m_rgcpiCreateOptions.RemoveAt(index); } } } int iBefore = m_rgcpiCreateOptions.Count; GetCreateSiblingOptions(slice, m_rgcpiCreateOptions, true); bool fSeq = m_rgcpiCreateOptions.Count > iBefore && m_rgcpiCreateOptions[iBefore].fieldType == (int)FieldType.kcptOwningSequence; int iAfter = m_rgcpiCreateOptions.Count; if (fSeq) { // In a sequence we make another set of options to insert after the current item. GetCreateSiblingOptions(slice, m_rgcpiCreateOptions, false); } for (int index = 0; index < m_rgcpiCreateOptions.Count; index++) { ClassAndPropInfo cpi = (ClassAndPropInfo)m_rgcpiCreateOptions[index]; String format = DetailControlsStrings.ksNewItem; if (index >= iAfter) { format = DetailControlsStrings.ksNewItemAfter; // can't happen if not sequence } else if (index >= iBefore) { if (fSeq) { format = DetailControlsStrings.ksNewItemBefore; } else // sibling collection { format = DetailControlsStrings.ksNewItemWithin; } } m_mnuCreate.MenuItems.Add(new MenuItem( String.Format(format, new object[] { cpi.signatureClassName, cpi.fieldName }), new EventHandler(this.HandleCreateMenuItem))); } m_mnuCreate.Enabled = m_mnuCreate.MenuItems.Count > 0; m_helper.SetupDeleteMenu(m_mnuDelete); }