Esempio n. 1
0
        private static List <MdFileInfo> FileInfosFromSearchModel(NodeSearchModel nodeSearchModel)
        {
            var fileInfos = new List <MdFileInfo>();

            foreach (var entry in nodeSearchModel.SearchEntries)
            {
                if (MdFileInfo.TryGetMdFileInfoFromSearchEntry(entry, out MdFileInfo info))
                {
                    fileInfos.Add(info);
                }
            }

            return(fileInfos);
        }
Esempio n. 2
0
        private static DynamoDictionaryEntry GetMatchingDictionaryEntry(
            IEnumerable <DynamoDictionaryEntry> dictEntrys, MdFileInfo info,
            LayoutSpecification spec)
        {
            // The DynamoDictionary only gives information about the name of the node
            // and the folder path, the MdFileInfo knows about the name of the node and
            // its namespace. The DynamoDictionary Folder path is the same as the namespace
            // except its separated by "/" instead of ".".
            // In order to find the correct dict entry we need to convert the namespace
            // into a folder path, and then get the entry where the folder path and name is matching.
            var infoNameSpaceFolderPath = ConvertNamespaceToDictionaryFolderPath(info.NodeNamespace);
            var infoCategoryFolderPath  = ConvertNamespaceToDictionaryFolderPath(info.FullCategory);

            // First we try and find a match using the fileInfo directly.
            // There are cases where a LayoutSpecification is not provided
            // and therefor we need to find a match from the fileInfo directly.
            // There are also instances where the particular node/namespace
            // has not been added to the LayoutSpecification (I think!!) which is
            // another reason to always try and make the match using the fileInfo directly first.
            var matchingEntry = dictEntrys
                                .Where(x =>
                                       x.FolderPath.StartsWith(infoNameSpaceFolderPath) ||
                                       x.FolderPath.StartsWith(infoCategoryFolderPath) &&
                                       x.Name == info.NodeName)
                                .FirstOrDefault();

            // If we couldn't find a match using the fileInfo directly and a LayoutSpecification is provided
            // we try and find a match using that.
            if (matchingEntry is null && spec != null)
            {
                if (TryGetMatchingEntryFromLayoutSpec(spec.sections.Cast <LayoutElement>().ToList(), dictEntrys, info, string.Empty, out matchingEntry))
                {
                    return(matchingEntry);
                }
            }

            return(matchingEntry);
        }
Esempio n. 3
0
        /// <summary>
        /// Trys to find a DictionaryEntry that matches the input MdFileInfo while applying LayoutElement from a LayoutSpecification
        /// by recursively checking LayoutElements from the LayoutSpecification until a match is found.
        /// </summary>
        /// <param name="sections">All Sections coming from a LayoutSpecification</param>
        /// <param name="dictEntrys">All DictionaryEntrys</param>
        /// <param name="info">MdFileInfo we are trying to find a DictionaryEntry match for</param>
        /// <param name="matchingPath">A path matching the DictionaryEntrys path, this path is generated during this recursive function</param>
        /// <param name="matchingEntry">The DictionaryEntry that matches the MdFileInfo</param>
        /// <returns></returns>
        private static bool TryGetMatchingEntryFromLayoutSpec(
            IEnumerable <LayoutElement> sections, IEnumerable <DynamoDictionaryEntry> dictEntrys,
            MdFileInfo info, string matchingPath,
            out DynamoDictionaryEntry matchingEntry)
        {
            var nodeNameWithoutArgs = info.NodeName
                                      .Split('(')
                                      .FirstOrDefault();

            matchingEntry = null;
            foreach (var item in sections)
            {
                if (!(item is LayoutSection))
                {
                    matchingPath = $"{matchingPath}/{item.text}";
                }

                if (item.include.Count > 0)
                {
                    // We need to test a lot of options here, the dictionary json paths can come from different places it seems
                    // Mostly when dealing with ZT nodes the full category name works, with NodeModels we need to use the namespace
                    var matchingLayoutInfo = item.include.Where(x =>
                                                                info.FullCategory.StartsWith(x.path) ||
                                                                $"{info.FullCategory}.{nodeNameWithoutArgs}" == x.path ||
                                                                info.NodeNamespace == x.path ||
                                                                info.NodeNamespace.StartsWith(x.path) ||
                                                                $"{info.NodeNamespace}.{nodeNameWithoutArgs}" == x.path)
                                             .FirstOrDefault();

                    if (matchingLayoutInfo != null)
                    {
                        // At this point matchingPath looks something like : "/Display/Color"
                        // therefor we need to remove the first '/'
                        var path = matchingPath.Remove(0, 1);

                        // There are cases where the NodeName has two words separated by a "."
                        // this is true for many of the List nodes in CoreNodeModels, e.g. List.LaceLongest.
                        // The dictionary entry for List.LaceLongest only has LaceLongest in the name
                        // therefor we need to first try and match with the name, and after that try and match with the "List." part removed.
                        var endIndex = info.NodeName.LastIndexOf(".");
                        var nodeNameWithoutPrefix = endIndex > 0 ?
                                                    info.NodeName.Remove(0, endIndex + 1) :
                                                    info.NodeName;

                        // First we try and match the folder path that we create in this recursive func with the folder path in the dict entry.
                        // Then we check if either the NodeName on the info object or the nodeNameWithoutPrefix matches the Name from the dict entry.
                        // Lastly we need to make sure that the last part of the infos FullCategory is contained in the folder path of the dict entry.
                        // The last check is needed because the layoutspec does not always match what is in the dictionary json,
                        // heres an example:
                        // When trying to get a matching entry for the node "ByThreePoints" which namespace is
                        // ProtoGeometry.Autodesk.DesignScript.Geometry.Arc, the DynamoCore layout spec puts all
                        // ProtoGeometry.Autodesk.DesignScript.Geometry.Arc under "Curves", which means we get a matchingLayoutInfo
                        // when the matching path is Geometry/Curves, but in the dictionary json
                        // "ByThreePoints" folder path is specified as "Geometry/Curves/Arc/Query"
                        // meaning we are missing the "Arc" part, we can get Arc from the last part of the FullCategory.
                        // If we do not add that part to the matching we might end up with an incorrect entry.
                        var matchingEntries = dictEntrys
                                              .Where(x =>
                                                     x.FolderPath.StartsWith(path) &&
                                                     // below regex compares the two string without considering whitespace.
                                                     // we need this as the Dictionary specify overloaded nodes with args like this:
                                                     // Max (int1, int2) - adding unnecessary white space between node name and args.
                                                     // the MdFileInfo will specify the same like this : Max(int1, int2).
                                                     (Regex.Replace(x.Name, @"\s+", "") == Regex.Replace(info.NodeName, @"\s+", "") ||
                                                      Regex.Replace(x.Name, @"\s+", "") == Regex.Replace(nodeNameWithoutPrefix, @"\s+", "")));

                        if (matchingEntries.Count() > 1)
                        {
                            matchingEntry = matchingEntries
                                            .Where(x => x.FolderPath.Contains(info.FullCategory.Split(new char[] { '.' }).Last()))
                                            .FirstOrDefault();
                        }
                        else
                        {
                            matchingEntry = matchingEntries.FirstOrDefault();
                        }

                        if (matchingEntry != null)
                        {
                            return(true);
                        }
                    }
                }

                if (TryGetMatchingEntryFromLayoutSpec(item.childElements, dictEntrys, info, matchingPath, out matchingEntry))
                {
                    return(true);
                }

                if (string.IsNullOrEmpty(matchingPath))
                {
                    continue;
                }

                matchingPath = matchingPath.Substring(0, matchingPath.LastIndexOf('/'));
            }

            return(false);
        }