private NodeTestResult AddSeqNode(ArrayList path, XmlNode node, ObjSeqHashMap reuseMap, string editor, int flid, ICmObject obj, int indent, ref int insertPosition, bool fTestOnly, string layoutName, bool fVisIfData, XmlNode caller) { if (flid == 0) throw new ApplicationException("field attribute required for seq properties " + node.OuterXml); int cobj = m_cache.GetVectorSize(obj.Hvo, flid); // monitor it even if we're testing: result may change. m_monitoredProps.Add(new KeyValuePair<int, int>(obj.Hvo, flid)); if (fVisIfData && cobj == 0) return NodeTestResult.kntrNothing; if (fTestOnly) { if (cobj > 0 || XmlUtils.GetOptionalAttributeValue(node, "ghost") != null) return NodeTestResult.kntrSomething; else return NodeTestResult.kntrPossible; } path.Add(node); string layoutOverride = XmlUtils.GetOptionalAttributeValue(node, "layout", layoutName); if (cobj == 0) { // Nothing in seq....do we want a ghost slice? if (XmlUtils.GetOptionalAttributeValue(node, "ghost") != null) { MakeGhostSlice(path, node, reuseMap, obj, flid, caller, indent, ref insertPosition); } } else if (cobj < 15 || // This may be a little on the small side m_currentObjectFlids.Contains(flid) || (!String.IsNullOrEmpty(m_currentSlicePartName) && m_currentSliceObjHvo != 0 && m_currentSliceNew == null)) { // Create slices immediately foreach (int hvo in m_cache.GetVectorProperty(obj.Hvo, flid, false)) { path.Add(hvo); insertPosition = CreateSlicesFor(CmObject.CreateFromDBObject(m_cache, hvo), layoutOverride, indent, insertPosition, path, reuseMap, caller); path.RemoveAt(path.Count - 1); } } else { // Create unique DummyObjectSlices for each slice. This may reduce the initial // preceived benefit, but this way doesn't crash now that the slices are being // disposed of. int cnt = 0; foreach (int hvo in m_cache.GetVectorProperty(obj.Hvo, flid, false)) { path.Add(hvo); DummyObjectSlice dos = new DummyObjectSlice(this, indent, node, (ArrayList)(path.Clone()), obj, flid, cnt, layoutOverride, caller); dos.Cache = m_cache; InsertSlice(insertPosition++, dos); ////InstallSlice(dos, -1); ////ResetTabIndices(insertPosition); ////insertPosition++; path.RemoveAt(path.Count - 1); cnt++; } } path.RemoveAt(path.Count - 1); return NodeTestResult.kntrNothing; }
/// <summary> /// Turn this dummy slice into whatever it stands for, replacing itself in the data tree's /// slices (where it occupies slot index) with whatever is appropriate. /// </summary> /// <param name="index"></param> /// <returns></returns> public override Slice BecomeReal(int index) { CheckDisposed(); // We stand in for the slice at 'index', and that is to be replaced. But we might stand for earlier // slices too: how many indicates what we have to add to m_ihvoMin. // Note: I (RandyR) don't think the same one can stand in for multiple dummies now. // We don't use a dummy slice in more than one place. // Each are created individually, if more than one is needed. int ihvo = m_ihvoMin; for (int islice = index - 1; islice >= 0 && Parent.Controls[islice] == this; islice--) ihvo++; string mode = XmlUtils.GetOptionalAttributeValue(m_node, "mode"); int hvo = m_cache.GetVectorItem(m_obj.Hvo, m_flid, ihvo); // In the course of becoming real, we may get disposed. That clears m_path, which // has various bad effects on called objects that are trying to use it, as well as // causing failure here when we try to remove the thing we added temporarily. // Work with a copy, so Dispose can't get at it. ArrayList path = new ArrayList(m_path); if (ihvo == m_ihvoMin) { // made the first element real. Increment start ihvo: the first thing we are a // dummy for got one greater m_ihvoMin++; } else if (index < Parent.Controls.Count && Parent.Controls[index + 1] == this) { // Any occurrences after index get replaced by a new one with suitable ihvoMin. // Note this must be done before we insert an unknown number of extra slices // by calling CreateSlicesFor. DummyObjectSlice dosRep = new DummyObjectSlice(ContainingDataTree, m_indent, m_node, path, m_obj, m_flid, ihvo + 1, m_layoutName, m_caller); dosRep.Cache = this.Cache; for (int islice = index + 1; islice < Parent.Controls.Count && Parent.Controls[islice] == this; islice++) { ContainingDataTree.RawSetSlice(islice, dosRep); } } // Save these, we may get disposed soon, can't get them from member data any more. DataTree containingTree = ContainingDataTree; Control parent = Parent; path.Add(hvo); ICmObject objItem = CmObject.CreateFromDBObject(ContainingDataTree.Cache, hvo); Point oldPos = ContainingDataTree.AutoScrollPosition; int insertPosition = ContainingDataTree.CreateSlicesFor(objItem, m_layoutName, m_indent, index + 1, path, new ObjSeqHashMap(), m_caller); // If inserting slices somehow altered the scroll position, for example as the // silly Panel tries to make the selected control visible, put it back! if (containingTree.AutoScrollPosition != oldPos) containingTree.AutoScrollPosition = new Point(-oldPos.X, -oldPos.Y); // No need to remove, we added to copy. //m_path.RemoveAt(m_path.Count - 1); if (parent.Controls.Count > index + 1) return parent.Controls[index + 1] as Slice; else return null; }
private NodeTestResult AddSeqNode(ArrayList path, XmlNode node, ObjSeqHashMap reuseMap, int flid, ICmObject obj, Slice parentSlice, int indent, ref int insertPosition, bool fTestOnly, string layoutName, bool fVisIfData, XmlNode caller) { if (flid == 0) throw new ApplicationException("field attribute required for seq properties " + node.OuterXml); int cobj = m_cache.DomainDataByFlid.get_VecSize(obj.Hvo, flid); // monitor it even if we're testing: result may change. m_monitoredProps.Add(Tuple.Create(obj.Hvo, flid)); if (fVisIfData && cobj == 0) return NodeTestResult.kntrNothing; if (fTestOnly) { if (cobj > 0 || XmlUtils.GetOptionalAttributeValue(node, "ghost") != null) return NodeTestResult.kntrSomething; return NodeTestResult.kntrPossible; } path.Add(node); string layoutOverride = XmlUtils.GetOptionalAttributeValue(node, "layout", layoutName); string layoutChoiceField = XmlUtils.GetOptionalAttributeValue(node, "layoutChoiceField"); if (cobj == 0) { // Nothing in seq....do we want a ghost slice? if (XmlUtils.GetOptionalAttributeValue(node, "ghost") != null) { MakeGhostSlice(path, node, reuseMap, obj, parentSlice, flid, caller, indent, ref insertPosition); } } else if (cobj < kInstantSliceMax || // This may be a little on the small side m_currentObjectFlids.Contains(flid) || (!String.IsNullOrEmpty(m_currentSlicePartName) && m_currentSliceObjGuid != Guid.Empty && m_currentSliceNew == null)) { //Create slices immediately var contents = SetupContents(flid, obj); foreach (int hvo in contents) { path.Add(hvo); insertPosition = CreateSlicesFor(m_cache.ServiceLocator.GetInstance<ICmObjectRepository>().GetObject(hvo), parentSlice, layoutOverride, layoutChoiceField, indent, insertPosition, path, reuseMap, caller); path.RemoveAt(path.Count - 1); } } else { // Create unique DummyObjectSlices for each slice. This may reduce the initial // preceived benefit, but this way doesn't crash now that the slices are being // disposed of. int cnt = 0; var contents = SetupContents(flid, obj); foreach (int hvo in contents) { // TODO (DamienD): do we need to add the layout choice field to the monitored props for a dummy slice? // LT-12302 exposed a path through here that was messed up when hvo was added before Dummy slices //path.Add(hvo); // try putting this AFTER the dos creation var dos = new DummyObjectSlice(indent, node, (ArrayList)(path.Clone()), obj, flid, cnt, layoutOverride, layoutChoiceField, caller) {Cache = m_cache, ParentSlice = parentSlice}; path.Add(hvo); // This is really important. Since some slices are invisible, all must be, // or Show() will reorder them. dos.Visible = false; InsertSlice(insertPosition++, dos); path.RemoveAt(path.Count - 1); cnt++; } } path.RemoveAt(path.Count - 1); return NodeTestResult.kntrNothing; }