An object sequence hash map represents a mapping from sequences of objects to sequences of objects. The key may be anything that implements IList. The value is also a list. It is expected that very commonly only one value will be stored for a given key. The implementation is optimized for this by storing the object directly rather than a sequence holding the one object. Two objects are typically stored as an array, three or more as an ArrayList. (This means lists of lists don't work.)
Exemplo n.º 1
0
        public void CreateIndentedNodes_basic()
        {
            m_DataTree = new DataTree();
            m_Slice    = GenerateSlice(Cache, m_DataTree);

            // Data taken from a running Sena 3
            var caller = CreateXmlElementFromOuterXmlOf("<part ref=\"AsLexemeForm\" label=\"Lexeme Form\" expansion=\"expanded\"><indent><part ref=\"IsAbstractBasic\" label=\"Is Abstract Form\" visibility=\"never\" /><!-- could use 'ifTrue' if we had it --><part ref=\"MorphTypeBasic\" visibility=\"ifdata\" /><part ref=\"PhoneEnvBasic\" visibility=\"ifdata\" /><part ref=\"StemNameForLexemeForm\" visibility=\"ifdata\" /></indent></part>");

            var       obj    = Cache.ServiceLocator.GetInstance <IMoStemAllomorphFactory>().Create();
            const int indent = 0;
            int       insPos = 1;

            var path = GeneratePath();

            var reuseMap = new ObjSeqHashMap();
            // Data taken from a running Sena 3
            var node = CreateXmlElementFromOuterXmlOf("<slice field=\"Form\" label=\"Form\" editor=\"multistring\" ws=\"all vernacular\" weight=\"light\" menu=\"mnuDataTree-LexemeForm\" contextMenu=\"mnuDataTree-LexemeFormContext\" spell=\"no\"><properties><bold value=\"on\" /><fontsize value=\"120%\" /></properties></slice>");

            m_Slice.CreateIndentedNodes(caller, obj, indent, ref insPos, path, reuseMap, node);
        }
Exemplo n.º 2
0
        public void CreateGhostStringSlice_ParentSliceNotNull()
        {
            var path     = GeneratePath();
            var reuseMap = new ObjSeqHashMap();
            var obj      = Cache.ServiceLocator.GetInstance <IMoStemAllomorphFactory>().Create();

            m_DataTree        = new DataTree();
            m_Slice           = GenerateSlice(Cache, m_DataTree);
            m_Mediator        = new Mediator();
            m_Slice.Mediator  = m_Mediator;
            m_propertyTable   = new PropertyTable(m_Mediator);
            m_Slice.PropTable = m_propertyTable;
            var node           = CreateXmlElementFromOuterXmlOf("<seq field=\"Pronunciations\" layout=\"Normal\" ghost=\"Form\" ghostWs=\"pronunciation\" ghostLabel=\"Pronunciation\" menu=\"mnuDataTree-Pronunciation\" />");
            int indent         = 0;
            int insertPosition = 0;
            int flidEmptyProp  = 5002031;               // runtime flid of ghost field

            m_DataTree.MakeGhostSlice(path, node, reuseMap, obj, m_Slice, flidEmptyProp, null, indent, ref insertPosition);
            var ghostSlice = m_DataTree.Slices[0];

            Assert.NotNull(ghostSlice);
            Assert.AreEqual(ghostSlice.PropTable, m_Slice.PropTable);
        }
Exemplo n.º 3
0
		/// <summary>
		/// Create slices appropriate for current root object and layout, reusing any existing slices,
		/// and clearing out any that remain unused. If it is for a different object, reuse is more limited.
		/// </summary>
		private void CreateSlices(bool differentObject)
		{
			var watch = new Stopwatch();
			watch.Start();
			bool wasVisible = this.Visible;
			var previousSlices = new ObjSeqHashMap();
			int oldSliceCount = Slices.Count;
			ConstructingSlices = true;
			try
			{
				// Bizarrely, calling Hide has been known to cause OnEnter to be called in a slice; we need to suppress this,
				// hence guarding it by setting ConstructingSlices.
				Hide();
				if (m_currentSlice != null)
					m_currentSlice.SetCurrentState(false); // needs to know no longer current, may want to save something.
				m_currentSlice = null;
				if (differentObject)
					m_currentSliceNew = null;
				//if (differentObject)
				//	Slices.Clear();
				var dummySlices = new List<Slice>(Slices.Count);
				foreach (Slice slice in Slices)
				{
					slice.Visible = false;
					if (slice.Key != null) // dummy slices may not have keys and shouldn't be reused.
						previousSlices.Add(slice.Key, slice);
					else
						dummySlices.Add(slice);
				}
				bool gonnerHasToolTip = false; // Does any goner have one?
				// Get rid of the dummies we aren't going to remove.
				foreach (Slice slice in dummySlices)
				{
					gonnerHasToolTip |= slice.ToolTip != null;
					RemoveSlice(slice);
				}
				previousSlices.ClearUnwantedPart(differentObject);
				CreateSlicesFor(m_root, null, m_rootLayoutName, m_layoutChoiceField, 0, 0, new ArrayList(20), previousSlices, null);
				// Clear out any slices NOT reused. RemoveSlice both
				// removes them from the DataTree's controls collection and disposes them.
				foreach (Slice gonner in previousSlices.Values)
				{
					gonnerHasToolTip |= gonner.ToolTip != null;
					RemoveSlice(gonner);
				}
				if (gonnerHasToolTip)
				{
					// Since the dumb MS ToolTip class can't just remove one,
					// we have to remove them all and re-add the remaining ones
					// in order to have it really turn loose of the SliceTreeNode.
					m_tooltip.RemoveAll();
					foreach (Slice keeper in Slices)
						SetToolTip(keeper);
				}
				ResetTabIndices(0);
			}
			finally
			{
				ConstructingSlices = false;
			}
			if (wasVisible)
				Show();
			watch.Stop();
			// Uncomment this to investigate slice performance or issues with dissappearing slices
			//Debug.WriteLine("CreateSlices took " + watch.ElapsedMilliseconds + " ms. Originally had " + oldSliceCount + " controls; now " + Slices.Count);
			//previousSlices.Report();
		}
Exemplo n.º 4
0
		public override void GenerateChildren(XmlNode node, XmlNode caller, ICmObject obj, int indent,
			ref int insPos, ArrayList path, ObjSeqHashMap reuseMap)
		{
			CheckDisposed();
			// If node has children, figure what to do with them...
			XmlNodeList children = node.ChildNodes;

			// It's important to initialize m_refs here rather than in FinishInit, because we need it
			// to be updated when the slice is reused in a regenerate.
			// Refactor JohnT: better still, make it a virtual attribute, and Refresh will automatically
			// clear it from the cache.
			if (m_vh != null)
			{
				m_refs = m_vh.LexReferences(m_obj.Hvo);
			}
			else
			{
				// DEPRECATED.
				string className = m_cache.MetaDataCacheAccessor.GetClassName((uint)m_obj.ClassID);
//				m_flid = AutoDataTreeMenuHandler.ContextMenuHelper.GetFlid(m_cache.MetaDataCacheAccessor,
//					className, m_fieldName);
				string qry = string.Format("SELECT DISTINCT [Src] FROM LexReference_Targets WHERE [Dst]={0}",
					m_obj.Hvo);
				m_refs = DbOps.ReadIntsFromCommand(m_cache, qry, null);
			}

			if (m_refs.Count == 0)
			{
				// It could have children but currently can't: we always show this as collapsedEmpty.
				Expansion = DataTree.TreeItemState.ktisCollapsedEmpty;
				return;
			}

			for (int i = 0; i < m_refs.Count; i++)
			{
				GenerateChildNode(i, node, caller, indent, ref insPos, path, reuseMap);
			}

			Expansion = DataTree.TreeItemState.ktisExpanded;
		}
Exemplo n.º 5
0
        /// <summary></summary>
        public static Slice Create(FdoCache cache, string editor, int flid, XmlNode node, ICmObject obj,
                                   StringTable stringTbl, IPersistenceProvider persistenceProvider, Mediator mediator, XmlNode caller, ObjSeqHashMap reuseMap)
        {
            Slice slice;

            switch (editor)
            {
            case "multistring":                     // first, these are the most common slices.
            {
                if (flid == 0)
                {
                    throw new ApplicationException("field attribute required for multistring " + node.OuterXml);
                }
                string wsSpec  = XmlUtils.GetOptionalAttributeValue(node, "ws");
                int    wsMagic = WritingSystemServices.GetMagicWsIdFromName(wsSpec);
                if (wsMagic == 0)
                {
                    throw new ApplicationException(
                              "ws must be 'all vernacular', 'all analysis', 'analysis vernacular', or 'vernacular analysis'"
                              + " it said '" + wsSpec + "'.");
                }


                bool forceIncludeEnglish = XmlUtils.GetOptionalBooleanAttributeValue(node, "forceIncludeEnglish", false);
                bool spellCheck          = XmlUtils.GetOptionalBooleanAttributeValue(node, "spell", true);
                // Either the part or the caller can specify that it isn't editable.
                // (The part may 'know' this, e.g. because it's a virtual attr not capable of editing;
                // more commonly the caller knows there isn't enough context for safe editing.
                bool editable = XmlUtils.GetOptionalBooleanAttributeValue(caller, "editable", true) &&
                                XmlUtils.GetOptionalBooleanAttributeValue(node, "editable", true);
                string           optionalWsSpec  = XmlUtils.GetOptionalAttributeValue(node, "optionalWs");
                int              wsMagicOptional = WritingSystemServices.GetMagicWsIdFromName(optionalWsSpec);
                MultiStringSlice msSlice         = reuseMap.GetSliceToReuse("MultiStringSlice") as MultiStringSlice;
                if (msSlice == null)
                {
                    slice = new MultiStringSlice(obj, flid, wsMagic, wsMagicOptional, forceIncludeEnglish, editable, spellCheck);
                }
                else
                {
                    slice = msSlice;
                    msSlice.Reuse(obj, flid, wsMagic, wsMagicOptional, forceIncludeEnglish, editable, spellCheck);
                }
                break;
            }

            case "defaultvectorreference":                     // second most common.
            {
                var rvSlice = reuseMap.GetSliceToReuse("ReferenceVectorSlice") as ReferenceVectorSlice;
                if (rvSlice == null)
                {
                    slice = new ReferenceVectorSlice(cache, obj, flid);
                }
                else
                {
                    slice = rvSlice;
                    rvSlice.Reuse(obj, flid);
                }
                break;
            }

            case "possvectorreference":
            {
                var prvSlice = reuseMap.GetSliceToReuse("PossibilityReferenceVectorSlice") as PossibilityReferenceVectorSlice;
                if (prvSlice == null)
                {
                    slice = new PossibilityReferenceVectorSlice(cache, obj, flid);
                }
                else
                {
                    slice = prvSlice;
                    prvSlice.Reuse(obj, flid);
                }
                break;
            }

            case "semdomvectorreference":
            {
                var prvSlice = reuseMap.GetSliceToReuse("SemanticDomainReferenceVectorSlice") as SemanticDomainReferenceVectorSlice;
                if (prvSlice == null)
                {
                    slice = new SemanticDomainReferenceVectorSlice(cache, obj, flid);
                }
                else
                {
                    slice = prvSlice;
                    prvSlice.Reuse(obj, flid);
                }
                break;
            }

            case "string":
            {
                if (flid == 0)
                {
                    throw new ApplicationException("field attribute required for basic properties " + node.OuterXml);
                }
                int ws = GetWs(mediator, cache, node);
                if (ws != 0)
                {
                    slice = new StringSlice(obj, flid, ws);
                }
                else
                {
                    slice = new StringSlice(obj, flid);
                }
                var fShowWsLabel = XmlUtils.GetOptionalBooleanAttributeValue(node, "labelws", false);
                if (fShowWsLabel)
                {
                    (slice as StringSlice).ShowWsLabel = true;
                }
                int wsEmpty = GetWs(mediator, cache, node, "wsempty");
                if (wsEmpty != 0)
                {
                    (slice as StringSlice).DefaultWs = wsEmpty;
                }
                break;
            }

            case "jtview":
            {
                string layout = XmlUtils.GetOptionalAttributeValue(caller, "param");
                if (layout == null)
                {
                    layout = XmlUtils.GetManditoryAttributeValue(node, "layout");
                }
                // Editable if BOTH the caller (part ref) AND the node itself (the slice) say so...or at least if neither says not.
                bool editable = XmlUtils.GetOptionalBooleanAttributeValue(caller, "editable", true) &&
                                XmlUtils.GetOptionalBooleanAttributeValue(node, "editable", true);
                slice = new ViewSlice(new XmlView(obj.Hvo, layout, stringTbl, editable));
                break;
            }

            case "summary":
            {
                slice = new SummarySlice();
                break;
            }

            case "enumcombobox":
            {
                slice = new EnumComboSlice(cache, obj, flid, stringTbl, node["deParams"]);
                break;
            }

            case "referencecombobox":
            {
                slice = new ReferenceComboBoxSlice(cache, obj, flid, persistenceProvider);
                break;
            }

            case "typeaheadrefatomic":
            {
                slice = new AtomicRefTypeAheadSlice(obj, flid);
                break;
            }

            case "msareferencecombobox":
            {
                slice = new MSAReferenceComboBoxSlice(cache, obj, flid, persistenceProvider);
                break;
            }

            case "lit":                     // was "message"
            {
                string message = XmlUtils.GetManditoryAttributeValue(node, "message");
                if (stringTbl != null)
                {
                    string sTranslate = XmlUtils.GetOptionalAttributeValue(node, "translate", "");
                    if (sTranslate.Trim().ToLower() != "do not translate")
                    {
                        message = stringTbl.LocalizeLiteralValue(message);
                    }
                }
                slice = new MessageSlice(message);
                break;
            }

            case "picture":
            {
                slice = new PictureSlice((ICmPicture)obj);
                break;
            }

            case "image":
            {
                try
                {
                    slice = new ImageSlice(DirectoryFinder.FWCodeDirectory, XmlUtils.GetManditoryAttributeValue(node, "param1"));
                }
                catch (Exception error)
                {
                    slice = new MessageSlice(String.Format(DetailControlsStrings.ksImageSliceFailed,
                                                           error.Message));
                }
                break;
            }

            case "checkbox":
            {
                slice = new CheckboxSlice(cache, obj, flid, node);
                break;
            }

            case "checkboxwithrefresh":
            {
                slice = new CheckboxRefreshSlice(cache, obj, flid, node);
                break;
            }

            case "time":
            {
                slice = new DateSlice(cache, obj, flid);
                break;
            }

            case "integer":                 // produced in the auto-generated parts from the conceptual model
            case "int":                     // was "integer"
            {
                slice = new IntegerSlice(cache, obj, flid);
                break;
            }

            case "gendate":
            {
                slice = new GenDateSlice(cache, obj, flid);
                break;
            }

            case "morphtypeatomicreference":
            {
                slice = new MorphTypeAtomicReferenceSlice(cache, obj, flid);
                break;
            }

            case "atomicreferencepos":
            {
                slice = new AtomicReferencePOSSlice(cache, obj, flid, persistenceProvider, mediator);
                break;
            }

            case "possatomicreference":
            {
                slice = new PossibilityAtomicReferenceSlice(cache, obj, flid);
                break;
            }

            case "atomicreferenceposdisabled":
            {
                slice = new AutomicReferencePOSDisabledSlice(cache, obj, flid, persistenceProvider, mediator);
                break;
            }

            case "defaultatomicreference":
            {
                slice = new AtomicReferenceSlice(cache, obj, flid);
                break;
            }

            case "defaultatomicreferencedisabled":
            {
                slice = new AtomicReferenceDisabledSlice(cache, obj, flid);
                break;
            }

            case "derivmsareference":
            {
                slice = new DerivMSAReferenceSlice(cache, obj, flid);
                break;
            }

            case "inflmsareference":
            {
                slice = new InflMSAReferenceSlice(cache, obj, flid);
                break;
            }

            case "phoneenvreference":
            {
                slice = new PhoneEnvReferenceSlice(cache, obj, flid);
                break;
            }

            case "sttext":
            {
                slice = new StTextSlice(obj, flid, GetWs(mediator, cache, node));
                break;
            }

            case "custom":
            {
                slice = (Slice)DynamicLoader.CreateObject(node);
                break;
            }

            case "customwithparams":
            {
                slice = (Slice)DynamicLoader.CreateObject(node,
                                                          new object[] { cache, editor, flid, node, obj, stringTbl,
                                                                         persistenceProvider, GetWs(mediator, cache, node) });
                break;
            }

            case "ghostvector":
            {
                slice = new GhostReferenceVectorSlice(cache, obj, node);
                break;
            }

            case "command":
            {
                slice = new CommandSlice(node["deParams"]);
                break;
            }

            case null:                          //grouping nodes do not necessarily have any editor
            {
                slice = new Slice();
                break;
            }

            case "message":
                // case "integer": // added back in to behave as "int" above
                throw new Exception("use of obsolete editor type (message->lit, integer->int)");

            case "autocustom":
                slice = MakeAutoCustomSlice(cache, obj, caller);
                if (slice == null)
                {
                    return(null);
                }
                break;

            case "defaultvectorreferencedisabled":                     // second most common.
            {
                ReferenceVectorDisabledSlice rvSlice = reuseMap.GetSliceToReuse("ReferenceVectorDisabledSlice") as ReferenceVectorDisabledSlice;
                if (rvSlice == null)
                {
                    slice = new ReferenceVectorDisabledSlice(cache, obj, flid);
                }
                else
                {
                    slice = rvSlice;
                    rvSlice.Reuse(obj, flid);
                }
                break;
            }

            default:
            {
                //Since the editor has not been implemented yet,
                //is there a bitmap file that we can show for this editor?
                //Such bitmaps belong in the distFiles xde directory
                string fwCodeDir = DirectoryFinder.FWCodeDirectory;
                string editorBitmapRelativePath = "xde/" + editor + ".bmp";
                if (File.Exists(Path.Combine(fwCodeDir, editorBitmapRelativePath)))
                {
                    slice = new ImageSlice(fwCodeDir, editorBitmapRelativePath);
                }
                else
                {
                    slice = new MessageSlice(String.Format(DetailControlsStrings.ksBadEditorType, editor));
                }
                break;
            }
            }
            slice.AccessibleName = editor;

            return(slice);
        }
Exemplo n.º 6
0
		/// <summary></summary>
		public virtual void GenerateChildren(XmlNode node, XmlNode caller, ICmObject obj, int indent,
			ref int insPos, ArrayList path, ObjSeqHashMap reuseMap, bool fUsePersistentExpansion)
		{
			CheckDisposed();

			// If node has children, figure what to do with them...
			// XmlNodeList children = node.ChildNodes; // unused variable
			DataTree.NodeTestResult ntr;
			// We may get child nodes from either the node itself or the calling part, but currently
			// don't try to handle both; we consider the children of the caller, if any, to override
			// the children of the node (but not unify with them, since a different kind of children
			// are involved).
			// A newly created slice is always in state ktisFixed, but that is not appropriate if it
			// has children from either source. However, a node which notionally has children may in fact have nothing to
			// show, perhaps because a sequence is empty. First evaluate this, and if true, set it
			// to ktisCollapsedEmpty.
			//bool fUseChildrenOfNode;
			XmlNode indentNode = null;
			if (caller != null)
				indentNode = caller.SelectSingleNode("indent");
			if (indentNode != null)
			{
				// Similarly pretest for children of caller, to see whether anything is produced.
				ContainingDataTree.ApplyLayout(obj, this, indentNode, indent + ExtraIndent(indentNode), insPos, path, reuseMap,
					true, out ntr);
				//fUseChildrenOfNode = false;
			}
			else
			{
				int insPosT = insPos; // don't modify the real one in this test call.
				ntr = ContainingDataTree.ProcessPartChildren(node, path, reuseMap, obj, this, indent + ExtraIndent(node), ref insPosT,
					true, null, false, node);
				//fUseChildrenOfNode = true;
			}

			if (ntr == DataTree.NodeTestResult.kntrNothing)
				Expansion = DataTree.TreeItemState.ktisFixed; // probably redundant, but play safe
			else if (ntr == DataTree.NodeTestResult.kntrPossible)
			{
				// It could have children but currently can't: we always show this as collapsedEmpty.
				Expansion = DataTree.TreeItemState.ktisCollapsedEmpty;
			}
			// Remaining branches are for a node that really has children.
			else if (Expansion == DataTree.TreeItemState.ktisCollapsed)
			{
				// Reusing a node that was collapsed (and it has something to expand):
				// leave it that way (whatever the spec says).
			}
			else
			{
				// It has children: decide whether to expand them.
				// Old code does not expand by default, couple of ways to override.
				//			else if (Expansion == DataTree.TreeItemState.ktisExpanded
				//				|| (fUseChildrenOfNode && XmlUtils.GetOptionalAttributeValue(node, "expansion") == "expanded")
				//				|| (XmlUtils.GetOptionalAttributeValue(caller, "expansion") == "expanded")
				//				|| Expansion == DataTree.TreeItemState.ktisCollapsedEmpty)
				bool fExpand = XmlUtils.GetOptionalAttributeValue(node, "expansion") != "doNotExpand";
				if (fUsePersistentExpansion && m_mediator != null) // mediator null only in testing?
				{
					Expansion = DataTree.TreeItemState.ktisCollapsed; // Needs to be an expandable state to have ExpansionStateKey.
					fExpand = m_mediator.PropertyTable.GetBoolProperty(ExpansionStateKey, fExpand);
				}
				if (fExpand)
				{
					// Record the expansion state and generate the children.
					Expansion = DataTree.TreeItemState.ktisExpanded;
					CreateIndentedNodes(caller, obj, indent, ref insPos, path, reuseMap, node);
				}
				else
				{
					// Record expansion state and skip generating children.
					Expansion = DataTree.TreeItemState.ktisCollapsed;
				}
			}
		}
Exemplo n.º 7
0
		public override void GenerateChildren(XmlNode node, XmlNode caller, ICmObject obj, int indent,
			ref int insPos, ArrayList path, ObjSeqHashMap reuseMap, bool fUsePersistentExpansion)
		{
			CheckDisposed();
			// If node has children, figure what to do with them...

			// It's important to initialize m_refs here rather than in FinishInit, because we need it
			// to be updated when the slice is reused in a regenerate.
			// Refactor JohnT: better still, make it a virtual attribute, and Refresh will automatically
			// clear it from the cache.

			SetRefs();

			if (m_refs.Count == 0)
			{
				// It could have children but currently can't: we always show this as collapsedEmpty.
				Expansion = DataTree.TreeItemState.ktisCollapsedEmpty;
				return;
			}

			for (int i = 0; i < m_refs.Count; i++)
			{
				GenerateChildNode(i, node, caller, indent, ref insPos, path, reuseMap);
			}

			Expansion = DataTree.TreeItemState.ktisExpanded;
		}
Exemplo n.º 8
0
		public override void GenerateChildren(XmlNode node, XmlNode caller, ICmObject obj, int indent, ref int insPos,
			ArrayList path, ObjSeqHashMap reuseMap, bool fUsePersistentExpansion)
		{
			CheckDisposed();

			foreach (IRnRoledPartic roledPartic in Record.ParticipantsOC)
			{
				if (roledPartic.RoleRA != null)
					GenerateChildNode(roledPartic, node, caller, indent, ref insPos, path, reuseMap);
			}
			Expansion = Record.ParticipantsOC.Count == 0 ? DataTree.TreeItemState.ktisCollapsedEmpty : DataTree.TreeItemState.ktisExpanded;
		}
Exemplo n.º 9
0
		/// <summary>
		/// Apply a layout to an object, producing the specified slices.
		/// </summary>
		/// <param name="obj">The object we want a detai view of</param>
		/// <param name="template">the 'layout' element</param>
		/// <param name="indent">How deeply indented the tree is at this point.</param>
		/// <param name="insertPosition">index in slices where we should insert nodes</param>
		/// <param name="path">sequence of nodes and HVOs inside which this is nested</param>
		/// <param name="reuseMap">map of key/slice combinations from a DataTree being refreshed. Exact matches may be
		/// reused, and also, the expansion state of exact matches is preserved.</param>
		/// <returns> updated insertPosition for next item after the ones inserted.</returns>
		public int ApplyLayout(ICmObject obj, XmlNode template, int indent, int insertPosition,
			ArrayList path, ObjSeqHashMap reuseMap)
		{
			CheckDisposed();
			NodeTestResult ntr;
			return ApplyLayout(obj, template, indent, insertPosition, path, reuseMap, false, out ntr);
		}
Exemplo n.º 10
0
		/// <summary>
		/// Look for a reusable slice that matches the current path. If found, remove from map and return;
		/// otherwise, return null.
		/// </summary>
		private Slice GetMatchingSlice(ArrayList path, ObjSeqHashMap reuseMap)
		{
			// Review JohnT(RandyR): I don't see how this can really work.
			// The original path (the key) used to set this does not, (and cannot) change,
			// but it is very common for slices to come and go, as they are inserted/deleted,
			// or when the Show hidden control is changed.
			// Those kinds of big changes will produce the input 'path' parm,
			// which has little hope of matching that fixed orginal key, won't it.
			// I can see how it would work when a simple F4 refresh is being done,
			// since the count of slcies should remain the same.

			IList list = reuseMap[(IList)path];
			if (list.Count > 0)
			{
				Slice slice = (Slice)list[0];
				reuseMap.Remove(path, slice);
				return slice;
			}

			return null;
		}
Exemplo n.º 11
0
		/// <summary>
		/// Create slices for the specified object by finding a relevant template in the spec.
		/// </summary>
		/// <param name="obj"> The object to make slices for.</param>
		/// <param name="mode">If not null, use only templates having this mode.</param>
		/// <param name="level">level at which to put the new top-level slices</param>
		/// <param name="preceding">index after which to insert the new slice(s) in slices array.</param>
		/// <param name="path">sequence of nodes and HVOs inside which this is nested</param>
		/// <param name="reuseMap">map of key/slice combinations from a DataTree being refreshed. Exact matches may be
		/// reused, and also, the expansion state of exact matches is preserved.</param>
		/// <param name="unifyWith">If not null, this is a node to be 'unified' with the one looked up
		/// using the layout name.</param>
		/// <returns> updated insertPosition for next item after the ones inserted.</returns>
		public virtual int CreateSlicesFor(ICmObject obj, string layoutName, int indent,
			int insertPosition, ArrayList path, ObjSeqHashMap reuseMap, XmlNode unifyWith)
		{
			CheckDisposed();

			// NB: 'path' can hold either ints or XmlNodes, so a generic can't be used for it.
			if (obj == null)
				return insertPosition;
			XmlNode template = GetTemplateForObjLayout(obj, layoutName);
			path.Add(template);
			XmlNode template2 = template;
			if (unifyWith != null && unifyWith.ChildNodes.Count > 0)
			{
				// This assumes that the attributes don't need to be unified.
				template2 = m_layoutInventory.GetUnified(template, unifyWith);
			}
			insertPosition = ApplyLayout(obj, template2, indent, insertPosition, path, reuseMap);
			path.RemoveAt(path.Count - 1);
			return insertPosition;
		}
Exemplo n.º 12
0
		/// <summary>
		/// Create slices appropriate for current root object and layout, reusing any existing slices,
		/// and clearing out any that remain unused.
		/// </summary>
		private void CreateSlices()
		{
			m_currentSlice = null;
			ObjSeqHashMap previousSlices = new ObjSeqHashMap();
			List<Slice> dummySlices = new List<Slice>(Controls.Count);
			foreach (Slice slice in Controls)
			{
				if (slice.Key != null) // dummy slices may not have keys and shouldn't be reused.
					previousSlices.Add(slice.Key, slice);
				else
					dummySlices.Add(slice);
			}
			// Get rid of the dummies we aren't going to remove.
			foreach (Slice slice in dummySlices)
				RemoveSlice(slice);
			CreateSlicesFor(m_root, m_rootLayoutName, 0, 0, new ArrayList(20), previousSlices, null);
			// Clear out any slices NOT reused. Removing them from the collection both
			// removes them from the DataTree's controls collection and disposes them.
			foreach (IList sliceList in previousSlices.Values)
			{
				foreach (Slice gonner in sliceList)
				{
					RemoveSlice(gonner);
				}
			}
			ResetTabIndices(0);
		}
Exemplo n.º 13
0
		/// <summary>
		/// Tests to see if it should add the field (IfData), then adds the field.
		/// </summary>
		/// <param name="path">The path.</param>
		/// <param name="node">The node.</param>
		/// <param name="reuseMap">The reuse map.</param>
		/// <param name="editor">Type of Contained Data</param>
		/// <param name="flid">Field ID</param>
		/// <param name="obj">The obj.</param>
		/// <param name="parentSlice">The parent slice.</param>
		/// <param name="indent">The indent.</param>
		/// <param name="insPos">The ins pos.</param>
		/// <param name="fTestOnly">if set to <c>true</c> [f test only].</param>
		/// <param name="fVisIfData">IfData</param>
		/// <param name="caller">The caller.</param>
		/// <returns>
		/// NodeTestResult, an enum showing if usable data is contained in the field
		/// </returns>
		private NodeTestResult AddSimpleNode(ArrayList path, XmlNode node, ObjSeqHashMap reuseMap, string editor,
			int flid, ICmObject obj, Slice parentSlice, int indent, ref int insPos, bool fTestOnly, bool fVisIfData, XmlNode caller)
		{
			var realSda = m_cache.DomainDataByFlid;
			if (parentSlice != null)
				Debug.Assert(!parentSlice.IsDisposed, "AddSimpleNode parameter 'parentSlice' is Disposed!");
			IWritingSystemContainer wsContainer = m_cache.ServiceLocator.WritingSystems;
			if (fVisIfData) // Contains the tests to see if usable data is inside the field (for all types of fields)
			{
				if (editor != null && editor == "custom")
				{
					Type typeFound;
					System.Reflection.MethodInfo mi =
						XmlUtils.GetStaticMethod(node, "assemblyPath", "class", "ShowSliceForVisibleIfData", out typeFound);
					if (mi != null)
					{
						var parameters = new object[2];
						parameters[0] = node;
						parameters[1] = obj;
						object result = mi.Invoke(typeFound,
							System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public |
							System.Reflection.BindingFlags.NonPublic, null, parameters, null);
						if (!(bool)result)
							return NodeTestResult.kntrNothing;
					}
				}
				else if (flid == 0 && editor != null && editor == "autocustom")
				{
					flid = SliceFactory.GetCustomFieldFlid(caller, realSda.MetaDataCache, obj);
				}

				if (flid != 0)
				{
					var fieldType = (CellarPropertyType)(realSda.MetaDataCache.GetFieldType(flid) & (int)CellarPropertyTypeFilter.VirtualMask);
					switch (fieldType)
					{
						default: // if we don't know how to check, make it visible.
							break;
							// These cases are a bit tricky. We're duplicating some information here about how the slices
							// interpret their ws parameter. Don't see how to avoid it, though, without creating the slices even if not needed.
						case CellarPropertyType.MultiString:
						case CellarPropertyType.MultiUnicode:
							string ws = XmlUtils.GetOptionalAttributeValue(node, "ws", null);
							switch (ws)
							{
								case "vernacular":
									if (realSda.get_MultiStringAlt(obj.Hvo, flid,
										wsContainer.DefaultVernacularWritingSystem.Handle).Length == 0)
										return NodeTestResult.kntrNothing;
									break;
								case "analysis":
									if (realSda.get_MultiStringAlt(obj.Hvo,
										flid,
										wsContainer.DefaultAnalysisWritingSystem.Handle).Length == 0)
										return NodeTestResult.kntrNothing;
									break;
								default:
									if (editor == "jtview")
									{
										if (realSda.get_MultiStringAlt(obj.Hvo,
											flid,
											wsContainer.DefaultAnalysisWritingSystem.Handle).Length == 0)
											return NodeTestResult.kntrNothing;
									}
									// try one of the magic ones for multistring
									int wsMagic = WritingSystemServices.GetMagicWsIdFromName(ws);
									if (wsMagic == 0 && editor == "autocustom")
									{
										wsMagic = realSda.MetaDataCache.GetFieldWs(flid);
									}
									if (wsMagic == 0 && editor != "autocustom")
										break; // not recognized, treat as visible
									var rgws = WritingSystemServices.GetWritingSystemList(m_cache, wsMagic, false).ToArray();
									bool anyNonEmpty = false;
									foreach (IWritingSystem wsInst in rgws)
									{
										if (realSda.get_MultiStringAlt(obj.Hvo, flid, wsInst.Handle).Length != 0)
										{
											anyNonEmpty = true;
											break;
										}
									}
									if (!anyNonEmpty)
										return NodeTestResult.kntrNothing;
									break;
							}
							break;
						case CellarPropertyType.String:
							if (realSda.get_StringProp(obj.Hvo, flid).Length == 0)
								return NodeTestResult.kntrNothing;
							break;
						case CellarPropertyType.Unicode:
							string val = realSda.get_UnicodeProp(obj.Hvo, flid);
							if (string.IsNullOrEmpty(val))
								return NodeTestResult.kntrNothing;
							break;
							// Usually, the header nodes for sequences and atomic object props
							// have no editor. But sometimes they may have a jtview summary
							// or the like. If an object-prop flid is specified, check it,
							// in case we want to suppress the whole header.
						case CellarPropertyType.OwningAtomic:
						case CellarPropertyType.ReferenceAtomic:
							int hvoT = realSda.get_ObjectProp(obj.Hvo, flid);
							if (hvoT == 0)
								return NodeTestResult.kntrNothing;
							var objt = m_cache.ServiceLocator.GetInstance<ICmObjectRepository>().GetObject(hvoT);
							if (objt.ClassID == StTextTags.kClassId) // if clid is an sttext clid
							{
								var txt = (IStText) objt;
								// Test if the StText has only one paragraph
								int cpara = txt.ParagraphsOS.Count;
								if (cpara == 1)
								{
									// Tests if paragraph is empty
									ITsString tss = ((IStTxtPara) txt.ParagraphsOS[0]).Contents;
									if (tss == null || tss.Length == 0)
										return NodeTestResult.kntrNothing;
								}
							}
							break;
						case CellarPropertyType.ReferenceCollection:
							// Currently this special case is only needed for ReferenceCollection (specifically for PublishIn).
							// We can broaden it if necessary, but why take the time to look for it elsewhere?
							int visibilityFlid = flid;
							string visField = XmlUtils.GetOptionalAttributeValue(node, "visField");
							if (visField != null)
							{
								int clsid = Cache.MetaDataCacheAccessor.GetOwnClsId(flid);
								visibilityFlid = Cache.MetaDataCacheAccessor.GetFieldId2(clsid, visField, true);
							}
							if (realSda.get_VecSize(obj.Hvo, visibilityFlid) == 0)
								return NodeTestResult.kntrNothing;
							break;
						case CellarPropertyType.OwningCollection:
						case CellarPropertyType.OwningSequence:

						case CellarPropertyType.ReferenceSequence:
							if (realSda.get_VecSize(obj.Hvo, flid) == 0)
								return NodeTestResult.kntrNothing;
							break;
					}
				}
				else if (editor == null)
				{
					// may be a summary node for a sequence or atomic node. Suppress it as well as the prop.
					XmlNode child = null;
					int cnodes = 0;
					foreach (XmlNode n in node.ChildNodes)
					{
						if (node is XmlComment)
							continue;
						cnodes++;
						if (cnodes > 1)
							break;
						child = n;
					}
					if (child != null && cnodes == 1) // exactly one non-comment child
					{
						int flidChild = GetFlidFromNode(child, obj);
						// If it's an obj or seq node and the property is empty, we'll show nothing.
						if (flidChild != 0)
						{
							if ((child.Name == "seq" || child.Name == "obj")
								&& realSda.get_VecSize(obj.Hvo, flidChild) == 0)
							{
								return NodeTestResult.kntrNothing;
							}
						}
					}
				}
			}
			if (fTestOnly)
				return NodeTestResult.kntrSomething; // slices always produce something.

			path.Add(node);
			Slice slice = GetMatchingSlice(path, reuseMap);
			if (slice == null)
			{
				slice = SliceFactory.Create(m_cache, editor, flid, node, obj, StringTbl, PersistenceProvder, m_mediator, caller, reuseMap);
				if (slice == null)
				{
					// One way this can happen in TestLangProj is with a part ref for a custom field that
					// has been deleted.
					return NodeTestResult.kntrNothing;
				}
				Debug.Assert(slice != null);
				// Set the label and abbreviation (in that order...abbr defaults to label if not given
				if (slice.Label == null)
					slice.Label = GetLabel(caller, node, obj, "label");
				slice.Abbreviation = GetLabelAbbr(caller, node, obj, slice.Label, "abbr");

				// Install new item at appropriate position and level.
				slice.Indent = indent;
				slice.Object = obj;
				slice.Cache = m_cache;
				slice.StringTbl = StringTbl;
				slice.PersistenceProvider = PersistenceProvder;

				// We need a copy since we continue to modify path, so make it as compact as possible.
				slice.Key = path.ToArray();
				// old code just set mediator, nothing ever set m_configurationParams. Maybe the two are redundant and should merge?
				slice.Init(m_mediator, null);
				slice.ConfigurationNode = node;
				slice.CallerNode = caller;
				slice.OverrideBackColor(XmlUtils.GetOptionalAttributeValue(node, "backColor"));
				slice.ShowContextMenu += OnShowContextMenu;
				slice.SmallImages = SmallImages;
				SetNodeWeight(node, slice);

				slice.FinishInit();
				// Now done in Slice.ctor
				//slice.Visible = false; // don't show it until we position and size it.

				InsertSliceAndRegisterWithContextHelp(insPos, slice);
			}
			else
			{
				// Now done in Slice.ctor
				//slice.Visible = false; // Since some slices are invisible, all must be, or Show() will reorder them.
				EnsureValidIndexForReusedSlice(slice, insPos);
			}
			slice.ParentSlice = parentSlice;
			insPos++;
			slice.GenerateChildren(node, caller, obj, indent, ref insPos, path, reuseMap, true);
			path.RemoveAt(path.Count - 1);

			return NodeTestResult.kntrNothing; // arbitrary what we return if not testing (see first line of method.)
		}
Exemplo n.º 14
0
		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;
		}
Exemplo n.º 15
0
		/// <summary>
		/// Tests to see if it should add the field (IfData), then adds the field.
		/// </summary>
		/// <param name="path"></param>
		/// <param name="node"></param>
		/// <param name="reuseMap"></param>
		/// <param name="editor">Type of Contained Data</param>
		/// <param name="flid">Field ID</param>
		/// <param name="obj"></param>
		/// <param name="indent"></param>
		/// <param name="insPos"></param>
		/// <param name="fTestOnly"></param>
		/// <param name="fVisIfData">IfData</param>
		/// <param name="caller"></param>
		/// <returns>NodeTestResult, an enum showing if usable data is contained in the field</returns>
		private NodeTestResult AddSimpleNode(ArrayList path, XmlNode node, ObjSeqHashMap reuseMap, string editor,
			int flid, ICmObject obj, int indent, ref int insPos, bool fTestOnly, bool fVisIfData, XmlNode caller)
		{
			if (fVisIfData) // Contains the tests to see if usable data is inside the field (for all types of fields)
			{
				if (editor != null && editor == "custom")
				{
					System.Type typeFound;
					System.Reflection.MethodInfo mi =
						XmlUtils.GetStaticMethod(node, "assemblyPath", "class", "ShowSliceForVisibleIfData", out typeFound);
					if (mi != null)
					{
						object[] parameters = new object[2];
						parameters[0] = (object)node;
						parameters[1] = (object)obj;
						object result = mi.Invoke(typeFound,
							System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public |
							System.Reflection.BindingFlags.NonPublic, null, parameters, null);
						if (!(bool)result)
							return NodeTestResult.kntrNothing;
					}
				}
				else if (flid == 0 && editor != null && editor == "autocustom")
				{
					flid = SliceFactory.GetCustomFieldFlid(caller, m_cache.MetaDataCacheAccessor, obj);
				}

				if (flid != 0)
				{
					FieldType fieldType = m_cache.GetFieldType(flid);
					fieldType &= FieldType.kcptVirtualMask; // strip virtual bit.
					switch (fieldType)
					{
						default: // if we don't know how to check, make it visible.
							break;
							// These cases are a bit tricky. We're duplicating some information here about how the slices
							// interpret their ws parameter. Don't see how to avoid it, though, without creating the slices even if not needed.
						case FieldType.kcptMultiString:
						case FieldType.kcptMultiUnicode:
						case FieldType.kcptMultiBigString:
						case FieldType.kcptMultiBigUnicode:
							string ws = XmlUtils.GetOptionalAttributeValue(node, "ws", null);
							switch(ws)
							{
								case "vernacular":
									if (m_cache.MainCacheAccessor.get_MultiStringAlt(obj.Hvo, flid, m_cache.DefaultVernWs).Length == 0)
										return NodeTestResult.kntrNothing;
									break;
								case "analysis":
									if (m_cache.MainCacheAccessor.get_MultiStringAlt(obj.Hvo, flid, m_cache.DefaultAnalWs).Length == 0)
										return NodeTestResult.kntrNothing;
									break;
								default:
									if (editor == "jtview")
									{
										if (m_cache.MainCacheAccessor.get_MultiStringAlt(obj.Hvo, flid, m_cache.DefaultAnalWs).Length == 0)
											return NodeTestResult.kntrNothing;
									}
									// try one of the magic ones for multistring
									int wsMagic = LangProject.GetMagicWsIdFromName(ws);
									if (wsMagic == 0 && editor == "autocustom")
									{
										wsMagic = m_cache.MetaDataCacheAccessor.GetFieldWs((uint)flid);
									}
									if (wsMagic == 0 && editor != "autocustom")
										break; // not recognized, treat as visible
									ILgWritingSystem[] rgws = SIL.FieldWorks.Common.Widgets.LabeledMultiStringView.GetWritingSystemList(m_cache, wsMagic, false);
									bool anyNonEmpty = false;
									foreach (ILgWritingSystem wsInst in rgws)
									{
										if (m_cache.MainCacheAccessor.get_MultiStringAlt(obj.Hvo, flid, wsInst.Hvo).Length != 0)
										{
											anyNonEmpty = true;
											break;
										}
									}
									if (!anyNonEmpty)
										return NodeTestResult.kntrNothing;
									break;
							}
							break;
						case FieldType.kcptString:
						case FieldType.kcptBigString:
							if (m_cache.MainCacheAccessor.get_StringProp(obj.Hvo, flid).Length == 0)
								return NodeTestResult.kntrNothing;
							break;
						case FieldType.kcptUnicode:
						case FieldType.kcptBigUnicode:
							string val = m_cache.MainCacheAccessor.get_UnicodeProp(obj.Hvo, flid);
							if (val == null || val.Length == 0)
								return NodeTestResult.kntrNothing;
							break;
							// Usually, the header nodes for sequences and atomic object props
							// have no editor. But sometimes they may have a jtview summary
							// or the like. If an object-prop flid is specified, check it,
							// in case we want to suppress the whole header.
						case FieldType.kcptOwningAtom:
						case FieldType.kcptReferenceAtom:
							int hvoT = m_cache.MainCacheAccessor.get_ObjectProp(obj.Hvo, flid);
							if (hvoT == 0)
								return NodeTestResult.kntrNothing;
							int clid = m_cache.GetClassOfObject(hvoT);
							if (clid == (int)CellarModuleDefns.kclidStText) // if clid is an sttext clid
							{
								// Test if the StText has only one paragraph
								int cpara = m_cache.GetVectorSize(hvoT, (int)CellarModuleDefns.kflidStText_Paragraphs);
								if (cpara == 1)
								{
									// Tests if paragraph is empty
									int hvoPara = m_cache.GetVectorItem(hvoT, (int)CellarModuleDefns.kflidStText_Paragraphs, 0);
									if (hvoPara == 0)
										return NodeTestResult.kntrNothing;
									ITsString tss = m_cache.GetTsStringProperty(hvoPara, (int)CellarModuleDefns.kflidStTxtPara_Contents);
									if (tss == null || tss.Length == 0)
										return NodeTestResult.kntrNothing;
								}
							}
							break;
						case FieldType.kcptOwningCollection:
						case FieldType.kcptOwningSequence:
						case FieldType.kcptReferenceCollection:
						case FieldType.kcptReferenceSequence:
							if (m_cache.MainCacheAccessor.get_VecSize(obj.Hvo, flid) == 0)
								return NodeTestResult.kntrNothing;
							break;
					}
				}
				else if (editor == null)
				{
					// may be a summary node for a sequence or atomic node. Suppress it as well as the prop.
					XmlNode child = null;
					int cnodes = 0;
					foreach (XmlNode n in node.ChildNodes)
					{
						if (node.GetType() == typeof(XmlComment))
							continue;
						cnodes++;
						if (cnodes > 1)
							break;
						child = n;
					}
					if (cnodes == 1) // exactly one non-comment child
					{
						int flidChild = GetFlidFromNode(child, obj);
						// If it's an obj or seq node and the property is empty, we'll show nothing.
						if (flidChild != 0 && child.Name == "seq" &&
							m_cache.MainCacheAccessor.get_VecSize(obj.Hvo, flidChild) == 0)
						{
							return NodeTestResult.kntrNothing;
						}
						if (flidChild != 0 && child.Name == "obj" &&
							m_cache.MainCacheAccessor.get_ObjectProp(obj.Hvo, flidChild) == 0)
						{
							return NodeTestResult.kntrNothing;
						}
					}
				}
			}
			if (fTestOnly)
				return NodeTestResult.kntrSomething; // slices always produce something.

			path.Add(node);
			Slice slice = GetMatchingSlice(path, reuseMap);
			if (slice == null)
			{
				slice = SliceFactory.Create(m_cache, editor, flid, node, obj, StringTbl, PersistenceProvder, m_mediator, caller);
				if (slice == null)
				{
					// One way this can happen in TestLangProj is with a part ref for a custom field that
					// has been deleted.
					return NodeTestResult.kntrNothing;
				}
				Debug.Assert(slice != null);
				// Set the label and abbreviation (in that order...abbr defaults to label if not given
				if (slice.Label == null)
					slice.Label = GetLabel(caller, node, obj, "label");
				slice.Abbreviation = GetLabelAbbr(caller, node, obj, slice.Label, "abbr");

				// Install new item at appropriate position and level.
				slice.Indent = indent;
				slice.Object = obj;
				slice.Cache = m_cache;
				slice.Mediator = m_mediator;


				// We need a copy since we continue to modify path, so make it as compact as possible.
				slice.Key = path.ToArray();
				slice.ConfigurationNode = node;
				slice.CallerNode = caller;
				slice.OverrideBackColor(XmlUtils.GetOptionalAttributeValue(node, "backColor"));
				slice.ShowContextMenu += new TreeNodeEventHandler(this.OnShowContextMenu);
				slice.SmallImages = SmallImages;
				SetNodeWeight(node, slice);

				slice.FinishInit();
				slice.Visible = false; // don't show it until we position and size it.

				InsertSliceAndRegisterWithContextHelp(insPos, slice, node);
			}
			else
			{
				EnsureValidIndexForReusedSlice(slice, insPos);
			}
			insPos++;
			slice.GenerateChildren(node, caller, obj, indent, ref insPos, path, reuseMap);
			path.RemoveAt(path.Count - 1);

			return NodeTestResult.kntrNothing; // arbitrary what we return if not testing (see first line of method.)
		}
Exemplo n.º 16
0
		/// <summary>
		/// Calls ApplyLayout for each child of the argument node.
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="template"></param>
		/// <param name="indent"></param>
		/// <param name="insertPosition"></param>
		/// <param name="path"></param>
		/// <param name="reuseMap"></param>
		/// <returns></returns>
		public int ApplyChildren(ICmObject obj, XmlNode template, int indent, int insertPosition, ArrayList path, ObjSeqHashMap reuseMap)
		{
			CheckDisposed();
			int insertPos = insertPosition;
			foreach (XmlNode node in template.ChildNodes)
			{
				if (node.Name == "ChangeRecordHandler")
					continue;	// Handle only at the top level (at least for now).
				insertPos = ApplyLayout(obj, node, indent, insertPos, path, reuseMap);
			}
			return insertPos;
		}
Exemplo n.º 17
0
		/// <summary>
		/// This is the guts of ApplyLayout, but it has extra arguments to allow it to be used both to actually produce
		/// slices, and just to query whether any slices will be produced.
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="template"></param>
		/// <param name="indent"></param>
		/// <param name="insertPosition"></param>
		/// <param name="path"></param>
		/// <param name="reuseMap"></param>
		/// <param name="fTestOnly"></param>
		/// <param name="fGotAnything"></param>
		/// <returns></returns>
		protected internal virtual int ApplyLayout(ICmObject obj, XmlNode template, int indent, int insertPosition, ArrayList path, ObjSeqHashMap reuseMap,
			bool isTestOnly, out NodeTestResult testResult)
		{
			int insPos = insertPosition;
			testResult = NodeTestResult.kntrNothing;
			int cPossible = 0;
			// This loop handles the multiple parts of a layout.
			foreach (XmlNode partRef in template.ChildNodes)
			{
				if (partRef.GetType() == typeof(XmlComment))
					continue;

				// This code looks for the a special part definition with an attribute called "customFields"
				// It doesn't matter what this attribute is set to, as long as it exists.  If this attribute is
				// found, the custom fields will not be generated.
				if(XmlUtils.GetOptionalAttributeValue(partRef, "customFields", null) != null)
				{
					if(!isTestOnly)
						EnsureCustomFields(obj, template, partRef);

					continue;
				}

				testResult = ProcessPartRefNode(partRef, path, reuseMap, obj, indent, ref insPos,
					isTestOnly);

				if (isTestOnly)
				{
					switch (testResult)
					{
					case NodeTestResult.kntrNothing:
						break;
					case NodeTestResult.kntrPossible:
						// nothing definite yet, but flag at least one possible.
						++cPossible;
						break;
					default:
						// if we're just looking to see if there would be any slices, and
						// there was, then don't bother thinking about any more slices.
						return insertPosition;
					}
				}
			}

			if (cPossible > 0)
				testResult = NodeTestResult.kntrPossible;	// everything else was nothing...

			//TODO: currently, we are making a custom fields show up all over the place... i.e.,
			//	the initial algorithm here (show the custom fields for a class whenever we are applying a template of that class)
			//		has turned out to be too simplistic, since apparently we and templates of a given class multiple times
			//		to show different parts of the class.
			//			if(template.Name == "template")
			//if (fGenerateCustomFields)
			//	testResult = AddCustomFields(obj, template, indent, ref insPos, path, reuseMap,isTestOnly);

			return insPos;
		}
Exemplo n.º 18
0
		private void GenerateChildNode(IRnRoledPartic roledPartic, XmlNode node, XmlNode caller, int indent,
			ref int insPos, ArrayList path, ObjSeqHashMap reuseMap)
		{
			var sliceElem = new XElement("slice",
				new XAttribute("label", roledPartic.RoleRA.Name.BestAnalysisAlternative.Text),
				new XAttribute("field", "Participants"),
				new XAttribute("editor", "possVectorReference"),
				new XAttribute("menu", "mnuDataTree-Participants"));
			foreach (XmlNode childNode in node.ChildNodes)
			{
				if (childNode.NodeType != XmlNodeType.Comment)
					sliceElem.Add(XElement.Parse(childNode.OuterXml));
			}
			node.InnerXml = sliceElem.ToString();
			CreateIndentedNodes(caller, roledPartic, indent, ref insPos, path, reuseMap, node);
			node.InnerXml = "";
		}
Exemplo n.º 19
0
		/// <summary>
		/// Process a top-level child of a layout (other than a comment).
		/// Currently these are all part nodes (with ref= indicating the part to use).
		/// </summary>
		/// <param name="part"></param>
		/// <param name="path"></param>
		/// <param name="reuseMap"></param>
		/// <param name="obj"></param>
		/// <param name="indent"></param>
		/// <param name="insPos"></param>
		/// <param name="isTestOnly"></param>
		/// <returns>NodeTestResult</returns>
		private NodeTestResult ProcessPartRefNode(XmlNode partRef, ArrayList path, ObjSeqHashMap reuseMap,
			ICmObject obj, int indent, ref int insPos, bool isTestOnly)
		{
			// Use the part inventory to find the indicated part.
			Debug.Assert(partRef.Name == "part");
			// If the previously selected slice doesn't display in this refresh, we try for the next
			// visible slice instead.  So m_fSetCurrentSliceNew might still be set.  See LT-9010.
			string partName = XmlUtils.GetManditoryAttributeValue(partRef, "ref");
			if (!m_fSetCurrentSliceNew && m_currentSlicePartName != null && obj.Hvo == m_currentSliceObjHvo)
			{
				for (uint clid = (uint)obj.ClassID; clid != 0; clid = m_mdc.GetBaseClsId(clid))
				{
					string sFullPartName = String.Format("{0}-Detail-{1}", m_mdc.GetClassName(clid), partName);
					if (m_currentSlicePartName == sFullPartName)
					{
						m_fSetCurrentSliceNew = true;
						break;
					}
				}
			}
			string visibility = "always";
			if (!m_fShowAllFields)
			{
				visibility = XmlUtils.GetOptionalAttributeValue(partRef, "visibility", "always");
				if (visibility == "never")
					return NodeTestResult.kntrNothing;
				Debug.Assert(visibility == "always" || visibility == "ifdata");
			}

			uint classId = (uint)obj.ClassID;
			string classname;
			XmlNode part = null;
			for( ; ; )
			{
				classname = m_mdc.GetClassName(classId);
				// Inventory of parts has key ID. The ID is made up of the class name, "-Detail-", partname.
				string key = classname + "-Detail-"+partName;
				part = m_partInventory.GetElement("part", new string[] {key});
				int temp = 0;
				if (part != null)
					temp = part.GetHashCode();
				if (part != null)
					break;
				if (classId == 0) // we've just tried CmObject.
				{
					Debug.WriteLine("Warning: No matching part found for " + classname + "-Detail-" + partName);
					// Just omit the missing part.
					return NodeTestResult.kntrNothing;
				}
				// Otherwise try superclass.
				classId = m_mdc.GetBaseClsId(classId);
			}
			string parameter = XmlUtils.GetOptionalAttributeValue(partRef, "param", null);
			// If you are wondering why we put the partref in the key, one reason is that it may be needed
			// when expanding a collapsed slice.
			path.Add(partRef);
			NodeTestResult ntr = ProcessPartChildren(part, path, reuseMap, obj, indent, ref insPos, isTestOnly,
				parameter, visibility=="ifdata", partRef);
			path.RemoveAt(path.Count - 1);
			return ntr;
		}
Exemplo n.º 20
0
		public void CreateIndentedNodes_basic()
		{
			m_DataTree = new DataTree();
			m_Slice = GenerateSlice(Cache, m_DataTree);

			// Data taken from a running Sena 3
			var caller = CreateXmlElementFromOuterXmlOf("<part ref=\"AsLexemeForm\" label=\"Lexeme Form\" expansion=\"expanded\"><indent><part ref=\"IsAbstractBasic\" label=\"Is Abstract Form\" visibility=\"never\" /><!-- could use 'ifTrue' if we had it --><part ref=\"MorphTypeBasic\" visibility=\"ifdata\" /><part ref=\"PhoneEnvBasic\" visibility=\"ifdata\" /><part ref=\"StemNameForLexemeForm\" visibility=\"ifdata\" /></indent></part>");

			var obj = Cache.ServiceLocator.GetInstance<IMoStemAllomorphFactory>().Create();
			const int indent = 0;
			int insPos = 1;

			var path = GeneratePath();

			var reuseMap = new ObjSeqHashMap();
			// Data taken from a running Sena 3
			var node = CreateXmlElementFromOuterXmlOf("<slice field=\"Form\" label=\"Form\" editor=\"multistring\" ws=\"all vernacular\" weight=\"light\" menu=\"mnuDataTree-LexemeForm\" contextMenu=\"mnuDataTree-LexemeFormContext\" spell=\"no\"><properties><bold value=\"on\" /><fontsize value=\"120%\" /></properties></slice>");

			m_Slice.CreateIndentedNodes(caller, obj, indent, ref insPos, path, reuseMap, node);
		}
Exemplo n.º 21
0
		internal NodeTestResult ProcessPartChildren(XmlNode part, ArrayList path,
			ObjSeqHashMap reuseMap, ICmObject obj, int indent, ref int insPos, bool isTestOnly,
			string parameter, bool fVisIfData, XmlNode caller)
		{
			CheckDisposed();
			// The children of the part element must now be processed. Often there is only one.
			foreach (XmlNode node in part.ChildNodes)
			{
				if (node.GetType() == typeof(XmlComment))
					continue;
				NodeTestResult testResult = ProcessSubpartNode(node, path, reuseMap, obj,
					indent, ref insPos, isTestOnly, parameter, fVisIfData, caller);
				// If we're just looking to see if there would be any slices, and there was,
				// then don't bother thinking about any more slices.
				if (isTestOnly && testResult != NodeTestResult.kntrNothing)
					return testResult;
			}
			return NodeTestResult.kntrNothing; // valid if isTestOnly, otherwise don't care.
		}
Exemplo n.º 22
0
		/// <summary></summary>
		public virtual void CreateIndentedNodes(XmlNode caller, ICmObject obj, int indent, ref int insPos,
			ArrayList path, ObjSeqHashMap reuseMap, XmlNode node)
		{
			CheckDisposed();

			string parameter = null;
			if (caller != null)
				parameter = XmlUtils.GetOptionalAttributeValue(caller, "param");
			XmlNode indentNode = null;
			if (caller != null)
				indentNode = caller.SelectSingleNode("indent");
			if (indentNode != null)
			{
				DataTree.NodeTestResult ntr;
				insPos = ContainingDataTree.ApplyLayout(obj, this, indentNode, indent + ExtraIndent(indentNode),
					insPos, path, reuseMap, false, out ntr);
			}
			else
				ContainingDataTree.ProcessPartChildren(node, path, reuseMap, obj, this, indent + ExtraIndent(node), ref insPos,
					false, parameter, false, caller);
		}
Exemplo n.º 23
0
		/// <summary>
		/// Handle one (non-comment) child node of a template (or other node) being used to
		/// create slices.  Update insertPosition to indicate how many were added (it also
		/// specifies where to add).  If fTestOnly is true, do not update insertPosition, just
		/// return true if any slices would be created.  Note that this method is recursive
		/// indirectly through ProcessPartChildren().
		/// </summary>
		/// <param name="node"></param>
		/// <param name="path"></param>
		/// <param name="reuseMap"></param>
		/// <param name="obj"></param>
		/// <param name="indent"></param>
		/// <param name="insertPosition"></param>
		/// <param name="fTestOnly"></param>
		/// <param name="parameter"></param>
		/// <param name="fVisIfData">If true, show slice only if data present.</param>
		/// <returns></returns>
		private NodeTestResult ProcessSubpartNode(XmlNode node, ArrayList path,
			ObjSeqHashMap reuseMap, ICmObject obj, int indent, ref int insertPosition,
			bool fTestOnly, string parameter, bool fVisIfData, XmlNode caller)
		{
			string editor = XmlUtils.GetOptionalAttributeValue(node, "editor");

			try
			{
				if (editor != null)
					editor = editor.ToLower();
				int flid = GetFlidFromNode(node, obj);

				if (m_sliceFilter != null &&
					flid != 0 &&
					!m_sliceFilter.IncludeSlice(node, obj, flid))
				{
					return NodeTestResult.kntrNothing;
				}

				switch (node.Name)
				{
					default:
						break; // Nothing to do for unrecognized element, such as deParams.

					case "slice":
						return AddSimpleNode(path, node, reuseMap, editor, flid, obj, indent,
							ref insertPosition, fTestOnly, fVisIfData, caller);

					case "seq":
						return AddSeqNode(path, node, reuseMap, editor, flid, obj, indent + Slice.ExtraIndent(node),
							ref insertPosition, fTestOnly, parameter, fVisIfData, caller);

					case "obj":
						return AddAtomicNode(path, node, reuseMap, editor, flid, obj, indent  + Slice.ExtraIndent(node),
							ref insertPosition, fTestOnly, parameter, fVisIfData, caller);

					case "if":
						if (XmlVc.ConditionPasses(node, obj.Hvo, m_cache))
						{
							NodeTestResult ntr = ProcessPartChildren(node, path, reuseMap, obj,
								indent, ref insertPosition, fTestOnly, parameter, fVisIfData,
								caller);
							if (fTestOnly && ntr != NodeTestResult.kntrNothing)
								return ntr;
						}
						break;

					case "ifnot":
						if (!XmlVc.ConditionPasses(node, obj.Hvo, m_cache))
						{
							NodeTestResult ntr = ProcessPartChildren(node, path, reuseMap, obj,
								indent, ref insertPosition, fTestOnly, parameter, fVisIfData,
								caller);
							if (fTestOnly && ntr != NodeTestResult.kntrNothing)
								return ntr;
						}
						break;

					case "choice":
						foreach (XmlNode clause in node.ChildNodes)
						{
							if (clause.Name == "where")
							{
								if (XmlVc.ConditionPasses(clause, obj.Hvo, m_cache))
								{
									NodeTestResult ntr = ProcessPartChildren(clause, path,
										reuseMap, obj, indent, ref insertPosition, fTestOnly,
										parameter, fVisIfData, caller);
									if (fTestOnly && ntr != NodeTestResult.kntrNothing)
										return ntr;
									break;
								}
								// Allow multiple where elements to be processed, but expand only
								// the first one whose condition passes.
							}
							else if (clause.Name == "otherwise")
							{
								// enhance: verify last node?
								NodeTestResult ntr = ProcessPartChildren(clause, path,
									reuseMap, obj, indent, ref insertPosition, fTestOnly,
									parameter, fVisIfData, caller);
								if (fTestOnly && ntr != NodeTestResult.kntrNothing)
									return ntr;
								break;
							}
							else
							{
								throw new Exception(
									"elements in choice must be <where...> or <otherwise>.");
							}
						}
						break;

					case "RecordChangeHandler":
						// No, since it isn't owned by the data tree, even though it created it.
						//if (m_rch != null && m_rch is IDisposable)
						//	(m_rch as IDisposable).Dispose();
						if (m_rch != null && !m_rch.HasRecordListUpdater && m_rch is IDisposable)
						{
							// The above version of the Dispose call was bad,
							// when m_rlu 'owned' the m_rch.
							// Now, we know there is no 'owning' m_rlu, so we have to do it.
							(m_rch as IDisposable).Dispose();
							m_rch = null;
						}
						m_rch = (IRecordChangeHandler)DynamicLoader.CreateObject(node, null);
						m_rch.Disposed += new EventHandler(m_rch_Disposed);
						Debug.Assert(m_rch != null);
						m_listName = XmlUtils.GetOptionalAttributeValue(node,
							"listName");
						m_rlu = null;
						ResetRecordListUpdater();
						// m_rlu may still be null, but that appears to be just fine.
						m_rch.Setup(obj, m_rlu);
						return NodeTestResult.kntrNothing;
				}
			}
			catch (Exception error)
			{
				// This doesn't need to be localized because it's displayed in a "yellow box"
				// error report.
				string s = "FieldWorks ran into a problem trying to display this object";
				s += " in DataTree::ApplyLayout: " + error.Message;
				s += "\r\nThe object id was " + obj.Hvo.ToString() + ".";
				if (editor != null)
					s += " The editor was '" + editor + "'.\r\n";
				s += " The text of the current node was " + node.OuterXml;
				//now send it on
				throw new ApplicationException(s, error);
			}
			// other types of child nodes, for example, parameters for jtview, don't even have
			// the potential for expansion.
			return NodeTestResult.kntrNothing;
		}
Exemplo n.º 24
0
		public static Slice Create(FdoCache cache, string editor, int flid, XmlNode node, ICmObject obj,
			StringTable stringTbl, IPersistenceProvider persistenceProvider, Mediator mediator, XmlNode caller, ObjSeqHashMap reuseMap)
		{
			Slice slice;
			switch(editor)
			{
				case "multistring": // first, these are the most common slices.
					{
						if (flid == 0)
							throw new ApplicationException("field attribute required for multistring " + node.OuterXml);
						string wsSpec = XmlUtils.GetOptionalAttributeValue(node, "ws");
						int wsMagic = WritingSystemServices.GetMagicWsIdFromName(wsSpec);
						if (wsMagic == 0)
							throw new ApplicationException(
								"ws must be 'all vernacular', 'all analysis', 'analysis vernacular', or 'vernacular analysis'"
								+ " it said '" + wsSpec + "'.");


						bool forceIncludeEnglish = XmlUtils.GetOptionalBooleanAttributeValue(node, "forceIncludeEnglish", false);
						bool spellCheck = XmlUtils.GetOptionalBooleanAttributeValue(node, "spell", true);
						// Either the part or the caller can specify that it isn't editable.
						// (The part may 'know' this, e.g. because it's a virtual attr not capable of editing;
						// more commonly the caller knows there isn't enough context for safe editing.
						bool editable = XmlUtils.GetOptionalBooleanAttributeValue(caller, "editable", true)
							&& XmlUtils.GetOptionalBooleanAttributeValue(node, "editable", true);
						string optionalWsSpec = XmlUtils.GetOptionalAttributeValue(node, "optionalWs");
						int wsMagicOptional = WritingSystemServices.GetMagicWsIdFromName(optionalWsSpec);
						MultiStringSlice msSlice = reuseMap.GetSliceToReuse("MultiStringSlice") as MultiStringSlice;
						if (msSlice == null)
							slice = new MultiStringSlice(obj, flid, wsMagic, wsMagicOptional, forceIncludeEnglish, editable, spellCheck);
						else
						{
							slice = msSlice;
							msSlice.Reuse(obj, flid, wsMagic, wsMagicOptional, forceIncludeEnglish, editable, spellCheck);
						}
						break;
					}
				case "defaultvectorreference": // second most common.
					{
						var rvSlice = reuseMap.GetSliceToReuse("ReferenceVectorSlice") as ReferenceVectorSlice;
						if (rvSlice == null)
							slice = new ReferenceVectorSlice(cache, obj, flid);
						else
						{
							slice = rvSlice;
							rvSlice.Reuse(obj, flid);
						}
						break;
					}
				case "possvectorreference":
					{
						var prvSlice = reuseMap.GetSliceToReuse("PossibilityReferenceVectorSlice") as PossibilityReferenceVectorSlice;
						if (prvSlice == null)
							slice = new PossibilityReferenceVectorSlice(cache, obj, flid);
						else
						{
							slice = prvSlice;
							prvSlice.Reuse(obj, flid);
						}
						break;
					}
				case "semdomvectorreference":
					{
						var prvSlice = reuseMap.GetSliceToReuse("SemanticDomainReferenceVectorSlice") as SemanticDomainReferenceVectorSlice;
						if (prvSlice == null)
							slice = new SemanticDomainReferenceVectorSlice(cache, obj, flid);
						else
						{
							slice = prvSlice;
							prvSlice.Reuse(obj, flid);
						}
						break;
					}
				case "string":
				{
					if (flid == 0)
						throw new ApplicationException("field attribute required for basic properties " + node.OuterXml);
					int ws = GetWs(mediator, cache, node);
					if (ws != 0)
						slice = new StringSlice(obj, flid, ws);
					else
						slice = new StringSlice(obj, flid);
					var fShowWsLabel = XmlUtils.GetOptionalBooleanAttributeValue(node, "labelws", false);
					if (fShowWsLabel)
						(slice as StringSlice).ShowWsLabel = true;
					int wsEmpty = GetWs(mediator, cache, node, "wsempty");
					if (wsEmpty != 0)
						(slice as StringSlice).DefaultWs = wsEmpty;
					break;
				}
				case "jtview":
				{
					string layout = XmlUtils.GetOptionalAttributeValue(caller, "param");
					if (layout == null)
						layout = XmlUtils.GetManditoryAttributeValue(node, "layout");
					// Editable if BOTH the caller (part ref) AND the node itself (the slice) say so...or at least if neither says not.
					bool editable = XmlUtils.GetOptionalBooleanAttributeValue(caller, "editable", true)
						&& XmlUtils.GetOptionalBooleanAttributeValue(node, "editable", true);
					slice = new ViewSlice(new XmlView(obj.Hvo, layout, stringTbl, editable));
					break;
				}
				case "summary":
				{
					slice = new SummarySlice();
					break;
				}
				case "enumcombobox":
				{
					slice = new EnumComboSlice(cache, obj, flid, stringTbl, node["deParams"]);
					break;
				}
				case "referencecombobox":
				{
					slice = new ReferenceComboBoxSlice(cache, obj, flid, persistenceProvider);
					break;
				}
				case "typeaheadrefatomic":
				{
					slice = new AtomicRefTypeAheadSlice(obj, flid);
					break;
				}
				case "msareferencecombobox":
				{
					slice = new MSAReferenceComboBoxSlice(cache, obj, flid, persistenceProvider);
					break;
				}
				case "lit": // was "message"
				{
					string message = XmlUtils.GetManditoryAttributeValue(node, "message");
					if (stringTbl != null)
					{
						string sTranslate = XmlUtils.GetOptionalAttributeValue(node, "translate", "");
						if (sTranslate.Trim().ToLower() != "do not translate")
							message = stringTbl.LocalizeLiteralValue(message);
					}
					slice = new MessageSlice(message);
					break;
				}
				case "picture":
				{
					slice = new PictureSlice((ICmPicture)obj);
					break;
				}
				case "image":
				{
					try
					{
						slice = new ImageSlice(FwDirectoryFinder.CodeDirectory, XmlUtils.GetManditoryAttributeValue(node, "param1"));
					}
					catch (Exception error)
					{
						slice = new MessageSlice(String.Format(DetailControlsStrings.ksImageSliceFailed,
							error.Message));
					}
					break;
				}
				case "checkbox":
				{
					slice = new CheckboxSlice(cache, obj, flid, node);
					break;
				}
				case "checkboxwithrefresh":
				{
					slice = new CheckboxRefreshSlice(cache, obj, flid, node);
					break;
				}
				case "time":
				{
					slice = new DateSlice(cache, obj, flid);
					break;
				}
				case "integer": // produced in the auto-generated parts from the conceptual model
				case "int": // was "integer"
				{
					slice = new IntegerSlice(cache, obj, flid);
					break;
				}

				case "gendate":
				{
					slice = new GenDateSlice(cache, obj, flid);
					break;
				}

				case "morphtypeatomicreference":
				{
					slice = new MorphTypeAtomicReferenceSlice(cache, obj, flid);
					break;
				}

				case "atomicreferencepos":
				{
					slice = new AtomicReferencePOSSlice(cache, obj, flid, persistenceProvider, mediator);
					break;
				}
				case "possatomicreference":
				{
					slice = new PossibilityAtomicReferenceSlice(cache, obj, flid);
					break;
				}
				case "atomicreferenceposdisabled":
				{
					slice = new AutomicReferencePOSDisabledSlice(cache, obj, flid, persistenceProvider, mediator);
					break;
				}

				case "defaultatomicreference":
				{
					slice = new AtomicReferenceSlice(cache, obj, flid);
					break;
				}
				case "defaultatomicreferencedisabled":
				{
					slice = new AtomicReferenceDisabledSlice(cache, obj, flid);
					break;
				}

				case "derivmsareference":
				{
					slice = new DerivMSAReferenceSlice(cache, obj, flid);
					break;
				}

				case "inflmsareference":
				{
					slice = new InflMSAReferenceSlice(cache, obj, flid);
					break;
				}

				case "phoneenvreference":
				{
					slice = new PhoneEnvReferenceSlice(cache, obj, flid);
					break;
				}

				case "sttext":
				{
					slice = new StTextSlice(obj, flid, GetWs(mediator, cache, node));
					break;
				}

				case "custom":
				{
					slice = (Slice)DynamicLoader.CreateObject(node);
					break;
				}

				case "customwithparams":
				{
					slice = (Slice)DynamicLoader.CreateObject(node,
						new object[]{cache, editor, flid, node, obj, stringTbl,
										persistenceProvider, GetWs(mediator, cache, node)});
					break;
				}
				case "ghostvector":
				{
					slice = new GhostReferenceVectorSlice(cache, obj, node);
					break;
				}

				case "command":
				{
					slice = new CommandSlice(node["deParams"]);
					break;
				}

				case null:	//grouping nodes do not necessarily have any editor
				{
					slice = new Slice();
					break;
				}
				case "message":
					// case "integer": // added back in to behave as "int" above
					throw new Exception("use of obsolete editor type (message->lit, integer->int)");
				case "autocustom":
					slice = MakeAutoCustomSlice(cache, obj, caller);
					if (slice == null)
						return null;
					break;
				case "defaultvectorreferencedisabled": // second most common.
					{
						ReferenceVectorDisabledSlice rvSlice = reuseMap.GetSliceToReuse("ReferenceVectorDisabledSlice") as ReferenceVectorDisabledSlice;
						if (rvSlice == null)
							slice = new ReferenceVectorDisabledSlice(cache, obj, flid);
						else
						{
							slice = rvSlice;
							rvSlice.Reuse(obj, flid);
						}
						break;
					}
				default:
				{
					//Since the editor has not been implemented yet,
					//is there a bitmap file that we can show for this editor?
					//Such bitmaps belong in the distFiles xde directory
					string fwCodeDir = FwDirectoryFinder.CodeDirectory;
					string editorBitmapRelativePath = "xde/" + editor + ".bmp";
					if(File.Exists(Path.Combine(fwCodeDir, editorBitmapRelativePath)))
						slice = new ImageSlice(fwCodeDir, editorBitmapRelativePath);
					else
						slice = new MessageSlice(String.Format(DetailControlsStrings.ksBadEditorType, editor));
					break;
				}
			}
			slice.AccessibleName = editor;

			return slice;
		}
Exemplo n.º 25
0
		private NodeTestResult AddAtomicNode(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)
		{
			// Facilitate insertion of an expandable tree node representing an owned or ref'd object.
			if (flid == 0)
				throw new ApplicationException("field attribute required for atomic properties " + node.OuterXml);
			ICmObject innerObj = obj.GetObjectInAtomicField(flid);
			m_monitoredProps.Add(new KeyValuePair<int, int>(obj.Hvo, flid));
			if (fVisIfData && innerObj == null)
				return NodeTestResult.kntrNothing;
			if (fTestOnly)
			{
				if (innerObj != null || XmlUtils.GetOptionalAttributeValue(node, "ghost") != null)
					return NodeTestResult.kntrSomething;
				else
					return NodeTestResult.kntrPossible;
			}
			path.Add(node);
			if(innerObj != null)
			{
				string layoutOverride = XmlUtils.GetOptionalAttributeValue(node, "layout", layoutName);
				path.Add(innerObj.Hvo);
				insertPosition = CreateSlicesFor(CmObject.CreateFromDBObject(m_cache, innerObj.Hvo),
					layoutOverride, indent, insertPosition, path, reuseMap, caller);
				path.RemoveAt(path.Count - 1);
			}
			else
			{
				// No inner object...do we want a ghost slice?
				if (XmlUtils.GetOptionalAttributeValue(node, "ghost") != null)
				{
					MakeGhostSlice(path, node, reuseMap, obj, flid, caller, indent, ref insertPosition);
				}
			}
			path.RemoveAt(path.Count - 1);
			return NodeTestResult.kntrNothing;
		}
Exemplo n.º 26
0
		void MakeGhostSlice(ArrayList path, XmlNode node, ObjSeqHashMap reuseMap, ICmObject obj,
			int flidEmptyProp, XmlNode caller, int indent, ref int insertPosition)
		{
			// It's a really bad idea to add it to the path, since it kills
			// the code that hot swaps it, when becoming real.
			//path.Add(node);
			Slice slice = GetMatchingSlice(path, reuseMap);
			if (slice == null)
			{
				slice = new GhostStringSlice(obj.Hvo, flidEmptyProp, node, m_cache);
				// Set the label and abbreviation (in that order...abbr defaults to label if not given.
				// Note that we don't have a "caller" here, so we pass 'node' as both arguments...
				// means it gets searched twice if not found, but that's fairly harmless.
				slice.Label = GetLabel(node, node, obj, "ghostLabel");
				slice.Abbreviation = GetLabelAbbr(node, node, obj, slice.Label, "ghostAbbr");

				// Install new item at appropriate position and level.
				slice.Indent = indent;
				slice.Object = obj;
				slice.Cache = m_cache;
				slice.Mediator = m_mediator;


				// We need a copy since we continue to modify path, so make it as compact as possible.
				slice.Key = path.ToArray();
				slice.ConfigurationNode = node;
				slice.CallerNode = caller;
				// don't mess with this, the obj/seq node would not have a meaningful back color override
				// for the slice. If we need it invent a new attribute.
				//slice.OverrideBackColor(XmlUtils.GetOptionalAttributeValue(node, "backColor"));

				// dubious...should the string slice really get the context menu for the object?
				slice.ShowContextMenu += new TreeNodeEventHandler(this.OnShowContextMenu);

				slice.SmallImages = SmallImages;
				SetNodeWeight(node, slice);

				slice.FinishInit();
				InsertSliceAndRegisterWithContextHelp(insertPosition, slice, node);
			}
			else
			{
				EnsureValidIndexForReusedSlice(slice, insertPosition);
			}
			insertPosition++;
			// Since we didn't add it to the path,
			// then there is nothign to do at this end either..
			//slice.GenerateChildren(node, caller, obj, indent, ref insertPosition, path, reuseMap);
			//path.RemoveAt(path.Count - 1);
		}
Exemplo n.º 27
0
		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;
		}
Exemplo n.º 28
0
		private void GenerateChildNode(int iChild, XmlNode node, XmlNode caller, int indent,
			ref int insPos, ArrayList path, ObjSeqHashMap reuseMap)
		{
			ILexReference lr = LexReference.CreateFromDBObject(m_cache, (int)m_refs[iChild]);
			ILexRefType lrt = LexRefType.CreateFromDBObject(m_cache, lr.OwnerHVO);
			string sLabel = lrt.ShortName;
			if (sLabel == null || sLabel == string.Empty)
				sLabel = lrt.Abbreviation.BestAnalysisAlternative.Text;
			bool fTreeRoot = true;
			ISilDataAccess sda = m_cache.MainCacheAccessor;
			int chvoTargets = sda.get_VecSize(lr.Hvo, (int)LexReference.LexReferenceTags.kflidTargets);
			// change the label for a Tree relationship.
			switch ((LexRefType.MappingTypes)lrt.MappingType)
			{
				case LexRefType.MappingTypes.kmtSenseTree:
				case LexRefType.MappingTypes.kmtEntryTree:
				case LexRefType.MappingTypes.kmtEntryOrSenseTree:
				case LexRefType.MappingTypes.kmtSenseAsymmetricPair: // Sense Pair with different Forward/Reverse names
				case LexRefType.MappingTypes.kmtEntryAsymmetricPair: // Entry Pair with different Forward/Reverse names
				case LexRefType.MappingTypes.kmtEntryOrSenseAsymmetricPair: // Entry or sense Pair with different Forward/Reverse names
					//int chvo = sda.get_VecSize(lr.Hvo, (int)LexReference.LexReferenceTags.kflidTargets);
					if (chvoTargets > 0)
					{
						int hvoFirst = sda.get_VecItem(lr.Hvo, (int)LexReference.LexReferenceTags.kflidTargets, 0);
						if (hvoFirst != m_obj.Hvo)
						{
							sLabel = lrt.ReverseName.BestAnalysisAlternative.Text;
							if (sLabel == null || sLabel == string.Empty)
								sLabel = lrt.ReverseAbbreviation.BestAnalysisAlternative.Text;
							fTreeRoot = false;
						}
					}
					break;
			}

			if (sLabel == null || sLabel == string.Empty)
				sLabel = LexEdStrings.ksStars;
			string sXml = "<slice label=\"" + sLabel + "\" field=\"Targets\"" +
				" editor=\"Custom\" assemblyPath=\"LexEdDll.dll\"";
			//string sMenu = "mnuDataTree-DeleteFromLexSenseReference"; we used to have distinct strings in the menu
			string sMenu = "mnuDataTree-DeleteAddLexReference";

			// generate Xml for a specific slice matching this reference
			switch ((LexRefType.MappingTypes)lrt.MappingType)
			{
				case LexRefType.MappingTypes.kmtSenseCollection:
					sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceCollectionSlice\"";
					break;
				case LexRefType.MappingTypes.kmtSensePair:
				case LexRefType.MappingTypes.kmtSenseAsymmetricPair: // Sense Pair with different Forward/Reverse names
				case LexRefType.MappingTypes.kmtEntryPair:
				case LexRefType.MappingTypes.kmtEntryAsymmetricPair: // Entry Pair with different Forward/Reverse names
				case LexRefType.MappingTypes.kmtEntryOrSensePair:
				case LexRefType.MappingTypes.kmtEntryOrSenseAsymmetricPair: // Entry or sense Pair with different forward/Reverse names
					sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferencePairSlice\"";
					sMenu = "mnuDataTree-DeleteReplaceLexReference";
					break;
				case LexRefType.MappingTypes.kmtSenseTree:
					if (fTreeRoot)
					{
						sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceTreeBranchesSlice\"";
						sMenu = "mnuDataTree-DeleteAddLexReference";
					}
					else
					{
						sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceTreeRootSlice\"";
						sMenu = "mnuDataTree-DeleteReplaceLexReference";
					}
					break;
				case LexRefType.MappingTypes.kmtSenseSequence:
				case LexRefType.MappingTypes.kmtEntrySequence:
				case LexRefType.MappingTypes.kmtEntryOrSenseSequence:
					sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceSequenceSlice\"";
					break;
				case LexRefType.MappingTypes.kmtEntryCollection:
					sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceCollectionSlice\"";
					//sMenu = "mnuDataTree-DeleteFromLexEntryReference"; we used to have distinct strings in the menu
					sMenu = "mnuDataTree-DeleteAddLexReference";
					break;
				case LexRefType.MappingTypes.kmtEntryTree:
					//sMenu = "mnuDataTree-DeleteFromLexEntryReference"; we used to have distinct strings in the menu
					sMenu = "mnuDataTree-DeleteAddLexReference";
					if (fTreeRoot)
					{
						sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceTreeBranchesSlice\"";
						sMenu = "mnuDataTree-DeleteAddLexReference";
					}
					else
					{
						sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceTreeRootSlice\"";
						sMenu = "mnuDataTree-DeleteReplaceLexReference";
					}
					break;
				case LexRefType.MappingTypes.kmtEntryOrSenseCollection:
					sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceCollectionSlice\"";
					if (m_obj is LexEntry)
						//sMenu = "mnuDataTree-DeleteFromLexEntryReference"; we used to have distinct strings in the menu
						sMenu = "mnuDataTree-DeleteAddLexReference";
					break;
				case LexRefType.MappingTypes.kmtEntryOrSenseTree:
					if (m_obj is LexEntry)
						//sMenu = "mnuDataTree-DeleteFromLexEntryReference"; we used to have distinct strings in the menu
						sMenu = "mnuDataTree-DeleteAddLexReference";
					if (fTreeRoot)
					{
						sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceTreeBranchesSlice\"";
						sMenu = "mnuDataTree-DeleteAddLexReference";
					}
					else
					{
						sXml +=	" class=\"SIL.FieldWorks.XWorks.LexEd.LexReferenceTreeRootSlice\"";
					}
					break;

			}

			sXml += " mappingType=\"" + lrt.MappingType + "\" hvoDisplayParent=\"" + m_obj.Hvo + "\"" +
				" menu=\"" + sMenu + "\"><deParams displayProperty=\"HeadWord\"/></slice>";
			node.InnerXml = sXml;
			int firstNewSliceIndex = insPos;
			CreateIndentedNodes(caller, lr, indent, ref insPos, path, reuseMap, node);
			for (int islice = firstNewSliceIndex; islice < insPos; islice++)
			{
				Slice child = Parent.Controls[islice] as Slice;
				if (child is ILexReferenceSlice)
				{
					(child as ILexReferenceSlice).MasterSlice = this;
				}
			}
			node.InnerXml = "";
		}
Exemplo n.º 29
0
		public virtual void GenerateChildren(XmlNode node, XmlNode caller, ICmObject obj, int indent, ref int insPos, ArrayList path, ObjSeqHashMap reuseMap)
		{
			CheckDisposed();

			// If node has children, figure what to do with them...
			XmlNodeList children = node.ChildNodes;
			DataTree.NodeTestResult ntr = DataTree.NodeTestResult.kntrNothing;
			// We may get child nodes from either the node itself or the calling part, but currently
			// don't try to handle both; we consider the children of the caller, if any, to override
			// the children of the node (but not unify with them, since a different kind of children
			// are involved).
			// A newly created slice is always in state ktisFixed, but that is not appropriate if it
			// has children from either source. However, a node which notionally has children may in fact have nothing to
			// show, perhaps because a sequence is empty. First evaluate this, and if true, set it
			// to ktisCollapsedEmpty.
			//bool fUseChildrenOfNode;
			XmlNode indentNode = null;
			if (caller != null)
				indentNode = caller.SelectSingleNode("indent");
			if (indentNode != null)
			{
				// Similarly pretest for children of caller, to see whether anything is produced.
				ContainingDataTree.ApplyLayout(obj, indentNode, indent + ExtraIndent(indentNode), insPos, path, reuseMap, true, out ntr);
				//fUseChildrenOfNode = false;
			}
			else
			{
				int insPosT = insPos; // don't modify the real one in this test call.
				ntr = ContainingDataTree.ProcessPartChildren(node, path, reuseMap, obj, indent + ExtraIndent(node), ref insPosT, true, null, false, node);
				//fUseChildrenOfNode = true;
			}

			if (ntr == DataTree.NodeTestResult.kntrNothing)
				Expansion = DataTree.TreeItemState.ktisFixed; // probably redundant, but play safe
			else if (ntr == DataTree.NodeTestResult.kntrPossible)
			{
				// It could have children but currently can't: we always show this as collapsedEmpty.
				Expansion = DataTree.TreeItemState.ktisCollapsedEmpty;
			}
			// Remaining branches are for a node that really has children.
			else if (Expansion == DataTree.TreeItemState.ktisCollapsed)
			{
				// Reusing a node that was collapsed (and it has something to expand):
				// leave it that way (whatever the spec says).
			}
			else if (XmlUtils.GetOptionalAttributeValue(node, "expansion") != "doNotExpand")
			// Old code does not expand by default, couple of ways to override.
			//			else if (Expansion == DataTree.TreeItemState.ktisExpanded
			//				|| (fUseChildrenOfNode && XmlUtils.GetOptionalAttributeValue(node, "expansion") == "expanded")
			//				|| (XmlUtils.GetOptionalAttributeValue(caller, "expansion") == "expanded")
			//				|| Expansion == DataTree.TreeItemState.ktisCollapsedEmpty)
			{
				// Either re-using a node that was expanded, or the slice spec says to auto-expand,
				// or the calling element says to auto-expand,
				// or a node that was previously empty now has real children, probably a first object
				// that was just added that the user wants to see:
				// fill in the children.
				Expansion = DataTree.TreeItemState.ktisExpanded;
				CreateIndentedNodes(caller, obj, indent, ref insPos, path, reuseMap, node);
			}
			else
			{
				// Either a new node or one previously collapsedEmpty. But it now definitely has children,
				// so neither of those states is appropriate. And we've covered all the cases where it
				// ought to be expanded. So show it as collapsed.
				Expansion = DataTree.TreeItemState.ktisCollapsed;
			}
		}