示例#1
0
        internal bool MakeOrClearSelection(NodeCategoryViewModel selectedClass)
        {
            if (currentClass != null)
            {
                if (currentClass != selectedClass)
                {
                    // If 'itemIndex' is '-1', then the selection will be cleared,
                    // otherwise the selection is set to the same as 'itemIndex'.
                    var itemIndex = collection.IndexOf(selectedClass);
                    classListView.SelectedIndex = itemIndex;
                    return true; // The call is handled.
                }
                else
                {
                    // If current item is selected item, then class button was pressed second time.
                    // Selection should be cleaned.
                    classListView.SelectedIndex = -1;
                    return true;
                }
            }
            else
            {
                // No selection, if item is within collection, select it.
                var itemIndex = collection.IndexOf(selectedClass);
                if (itemIndex != -1)
                {
                    classListView.SelectedIndex = itemIndex;
                    return true; // The call is handled.
                }
            }

            // The call is not handled.
            return false;
        }
示例#2
0
        // TODO: classes functionality.
        internal void AddClassToGroup(NodeCategoryViewModel memberNode)
        {
            // TODO: The following limit of displaying only two classes are 
            // temporary, it should be updated whenever the design intent has been finalized.
            // http://adsk-oss.myjetbrains.com/youtrack/issue/MAGN-6199

            //const int maxClassesCount = 2;
            //if (classes.Count >= maxClassesCount)
            //    return;

            // Parent should be of 'BrowserInternalElement' type or derived.
            // Root category can't be added to classes list. 
            // TODO(Vladimir): Implement the logic when classes are shown in search results.
        }
        public void InsertSubCategory(NodeCategoryViewModel newSubCategory)
        {
            var list = SubCategories.Where(cat => !(cat is ClassesNodeCategoryViewModel));
            var nextLargerItemIndex = FindInsertionPointByName(list, newSubCategory.Name);

            if (nextLargerItemIndex >= 0)
            {
                bool hasClasses = SubCategories.FirstOrDefault() is ClassesNodeCategoryViewModel;
                var  offset     = hasClasses ? 1 : 0;
                SubCategories.Insert(nextLargerItemIndex + offset, newSubCategory);
            }
            else
            {
                SubCategories.Add(newSubCategory);
            }
        }
示例#4
0
        public void InsertSubCategory(NodeCategoryViewModel newSubCategory)
        {
            var first = SubCategories.Select((x, i) => new { x.Name, Idx = i })
                        .FirstOrDefault(
                x =>
                string.Compare(
                    x.Name,
                    newSubCategory.Name,
                    StringComparison.Ordinal)
                >= 0);

            if (first != null)
            {
                SubCategories.Insert(first.Idx, newSubCategory);
            }
            else
            {
                SubCategories.Add(newSubCategory);
            }
        }
示例#5
0
 private static IEnumerable<NodeSearchElementViewModel> GetVisibleSearchResults(NodeCategoryViewModel category)
 {
     foreach (var item in category.Items)
     {
         var sub = item as NodeCategoryViewModel;
         if (sub != null)
         {
             foreach (var visible in GetVisibleSearchResults(sub))
                 yield return visible;
         }
         else
             yield return (NodeSearchElementViewModel)item;
     }
 }
示例#6
0
 private void AddEntryToExistingCategory(NodeCategoryViewModel category,
     NodeSearchElementViewModel entry)
 {
     category.RequestBitmapSource += SearchViewModelRequestBitmapSource;
     category.Entries.Add(entry);
 }
示例#7
0
        private void InsertEntryIntoNewCategory(
            NodeCategoryViewModel category,
            NodeSearchElementViewModel entry,
            IEnumerable<string> categoryNames)
        {
            if (!categoryNames.Any())
            {
                AddEntryToExistingCategory(category, entry);
                return;
            }

            // With the example of 'MyAssembly.MyNamespace.MyClass.Foo', 'path' would have been 
            // set to 'MyAssembly' here. The Select statement below would store two entries into
            // 'newTargets' variable:
            // 
            //      NodeCategoryViewModel("MyAssembly.MyNamespace")
            //      NodeCategoryViewModel("MyAssembly.MyNamespace.MyClass")
            // 
            var path = category.FullCategoryName;
            var newTargets = categoryNames.Select(name =>
            {
                path = MakeFullyQualifiedName(path, name);

                var cat = new NodeCategoryViewModel(name);
                cat.FullCategoryName = path;
                cat.Assembly = entry.Assembly;
                return cat;
            }).ToList();

            // The last entry 'NodeCategoryViewModel' represents a class. For our example the 
            // entries in 'newTargets' are:
            // 
            //      NodeCategoryViewModel("MyAssembly.MyNamespace")
            //      NodeCategoryViewModel("MyAssembly.MyNamespace.MyClass")
            // 
            // Since all class entries are contained under a 'ClassesNodeCategoryViewModel', 
            // we need to create a new 'ClassesNodeCategoryViewModel' instance, and insert it 
            // right before the class entry itself to get the following list:
            // 
            //      NodeCategoryViewModel("MyAssembly.MyNamespace")
            //      ClassesNodeCategoryViewModel("Classes")
            //      NodeCategoryViewModel("MyAssembly.MyNamespace.MyClass")
            // 
            int indexToInsertClass = newTargets.Count - 1;
            var classParent = indexToInsertClass > 0 ? newTargets[indexToInsertClass - 1] : category;
            var newClass = new ClassesNodeCategoryViewModel(classParent);
            newTargets.Insert(indexToInsertClass, newClass);

            // Here, all the entries in 'newTargets' are added under 'MyAssembly' recursively,
            // resulting in the following hierarchical structure:
            // 
            //      NodeCategoryViewModel("MyAssembly")
            //          NodeCategoryViewModel("MyAssembly.MyNamespace")
            //              ClassesNodeCategoryViewModel("Classes")
            //                  NodeCategoryViewModel("MyAssembly.MyNamespace.MyClass")
            // 
            foreach (var newTarget in newTargets)
            {
                category.SubCategories.Add(newTarget);
                category = newTarget;
            }

            AddEntryToExistingCategory(category, entry);
        }
示例#8
0
        private static IEnumerable<NodeCategoryViewModel> GetTreeBranchToNode(
            NodeCategoryViewModel rootNode, NodeSearchElement leafNode)
        {
            var nodesOnBranch = new Stack<NodeCategoryViewModel>();
            var nameStack = new Stack<string>(leafNode.Categories.Reverse());
            var target = rootNode;
            bool isCheckedForClassesCategory = false;
            while (nameStack.Any())
            {
                var next = nameStack.Pop();
                var categories = target.SubCategories;
                var newTarget = categories.FirstOrDefault(c => c.Name == next);
                if (newTarget == null)
                {
                    // The last entry in categories list can be a class name. When the desired class 
                    // cannot be located with "MyAssembly.MyNamespace.ClassCandidate" pattern, try 
                    // searching with "MyAssembly.MyNamespace.Classes.ClassCandidate" instead. This 
                    // is because a class always resides under a "ClassesNodeCategoryViewModel" node.
                    //
                    if (!isCheckedForClassesCategory && nameStack.Count == 0)
                    {
                        nameStack.Push(next);
                        nameStack.Push(Configurations.ClassesDefaultName);

                        isCheckedForClassesCategory = true;
                        continue;
                    }

                    return Enumerable.Empty<NodeCategoryViewModel>();
                }
                nodesOnBranch.Push(target);
                target = newTarget;
            }

            nodesOnBranch.Push(target);
            return nodesOnBranch;
        }
        public void PopulateMemberCollections(NodeCategoryViewModel element)
        {
            createMembers.Clear();
            actionMembers.Clear();
            queryMembers.Clear();
            PrimaryHeaderItems.Clear();
            ActionHeaderItems.Clear();
            QueryHeaderItems.Clear();

            foreach (var subElement in element.Entries)
            {
                switch (subElement.Model.Group)
                {
                    case SearchElementGroup.Create:
                        createMembers.Add(subElement);
                        break;

                    case SearchElementGroup.Action:
                        actionMembers.Add(subElement);
                        break;

                    case SearchElementGroup.Query:
                        queryMembers.Add(subElement);
                        break;
                }
            }

            // Populate headers collections.
            string headerStripText = string.Empty;
            if (createMembers.Any())
            {
                headerStripText = Configurations.HeaderCreate;
            }

            if (actionMembers.Any())
            {
                // As soon as primary headers collection is defined, 
                // add item to secondary headers collection.
                if (string.IsNullOrEmpty(headerStripText))
                    headerStripText = Configurations.HeaderAction;
                else
                    ActionHeaderItems.Add(new HeaderStripItem() { Text = Configurations.HeaderAction });
            }

            if (queryMembers.Any())
            {
                // As soon as primary headers collection is defined, 
                // add item to secondary headers collection.
                if (string.IsNullOrEmpty(headerStripText))
                    headerStripText = Configurations.HeaderQuery;
                else
                    QueryHeaderItems.Add(new HeaderStripItem() { Text = Configurations.HeaderQuery });
            }

            PrimaryHeaderItems.Add(new HeaderStripItem() { Text = headerStripText });
        }
示例#10
0
        public void BrowserInternalElementToBoolConverterTest()
        {
            var converter = new NodeCategoryVMToBoolConverter();
            var NcVM = new NodeCategoryViewModel("");
            var RncVM = new RootNodeCategoryViewModel("");
            var CncVM = new ClassesNodeCategoryViewModel(RncVM);
            object result;

            //1. Element is null.            
            //2. Element is NodeCategoryViewModel.
            //2. Element is RootNodeCategoryViewModel.
            //2. Element is ClassesNodeCategoryViewModel.

            // 1 case
            result = converter.Convert(null, null, null, null);
            Assert.AreEqual(false, result);

            // 2 case
            result = converter.Convert(NcVM, null, null, null);
            Assert.AreEqual(true, result);

            // 3 case
            result = converter.Convert(RncVM, null, null, null);
            Assert.AreEqual(false, result);

            // 4 case
            result = converter.Convert(CncVM, null, null, null);
            Assert.AreEqual(false, result);
        }
示例#11
0
        public void PopulateMemberCollections(NodeCategoryViewModel element)
        {
            createMembers.Clear();
            actionMembers.Clear();
            queryMembers.Clear();
            PrimaryHeaderItems.Clear();
            ActionHeaderItems.Clear();
            QueryHeaderItems.Clear();

            foreach (var subElement in element.Entries)
            {
                switch (subElement.Model.Group)
                {
                case SearchElementGroup.Create:
                    createMembers.Add(subElement);
                    break;

                case SearchElementGroup.Action:
                    actionMembers.Add(subElement);
                    break;

                case SearchElementGroup.Query:
                    queryMembers.Add(subElement);
                    break;
                }
            }

            // Populate headers collections.
            string headerStripText = string.Empty;

            if (createMembers.Any())
            {
                headerStripText = Configurations.HeaderCreate;
            }

            if (actionMembers.Any())
            {
                // As soon as primary headers collection is defined,
                // add item to secondary headers collection.
                if (string.IsNullOrEmpty(headerStripText))
                {
                    headerStripText = Configurations.HeaderAction;
                }
                else
                {
                    ActionHeaderItems.Add(new HeaderStripItem()
                    {
                        Text = Configurations.HeaderAction
                    });
                }
            }

            if (queryMembers.Any())
            {
                // As soon as primary headers collection is defined,
                // add item to secondary headers collection.
                if (string.IsNullOrEmpty(headerStripText))
                {
                    headerStripText = Configurations.HeaderQuery;
                }
                else
                {
                    QueryHeaderItems.Add(new HeaderStripItem()
                    {
                        Text = Configurations.HeaderQuery
                    });
                }
            }

            PrimaryHeaderItems.Add(new HeaderStripItem()
            {
                Text = headerStripText
            });
        }
示例#12
0
        private void OnClassViewSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var selectedIndex = (sender as ListView).SelectedIndex;

            // As focus moves within the class details, class button gets selected which 
            // triggers a selection change. During a selection change the items in the 
            // wrap panel gets reordered through "OrderListItems", but this is not always 
            // necessary. Here we determine if the "translatedIndex" is the same as
            // "selectedClassProspectiveIndex", if so simply returns to avoid a repainting.
            var translatedIndex = TranslateSelectionIndex(selectedIndex);
            if (selectedClassProspectiveIndex == translatedIndex)
                return;

            selectedClassProspectiveIndex = translatedIndex;

            int classInfoIndex = GetClassInformationIndex();

            // If user clicks on the same item when it is expanded, then 'OnClassButtonCollapse'
            // is invoked to deselect the item. This causes 'OnClassViewSelectionChanged' to be 
            // called again, with 'SelectedIndex' set to '-1', indicating that no item is selected,
            // in which case we need to hide the ClassInformationView.
            if (selectedClassProspectiveIndex == -1)
            {
                if (classInfoIndex != -1)
                {
                    (collection[classInfoIndex] as ClassInformationViewModel).ClassDetailsVisibility = false;
                    currentClass = null;
                }
                OrderListItems();
                return;
            }
            else
            {
                (collection[classInfoIndex] as ClassInformationViewModel).ClassDetailsVisibility = true;
            }

            currentClass = collection[selectedIndex] as NodeCategoryViewModel;
            OrderListItems(); // Selection change, we may need to reorder items.
        }
示例#13
0
        private bool ExpandCategory(IEnumerable<NodeCategoryViewModel> categories, NodeCategoryViewModel selectedClass)
        {
            bool foundSelectedClass = false;

            // Get all current expanded categories.
            var allExpandedCategories = categories.Where(cat =>
            {
                return cat.IsExpanded && (!(cat is ClassesNodeCategoryViewModel));

            }).ToList();
            var categoryToBeExpanded = categories.FirstOrDefault(cat => cat == selectedClass);

            // If categoryToBeExpanded is null, that means the clicked item does not
            // represent a category button, but a class button. In the recursive call 
            // the category in which this clicked class belong will be identified.
            if (categoryToBeExpanded != null)
            {
                categoryToBeExpanded.IsExpanded = !categoryToBeExpanded.IsExpanded;
                foundSelectedClass = true;
            }

            // Get expanded categories that should be collapsed.
            allExpandedCategories.Remove(categoryToBeExpanded);

            // Close all expanded categories except the one that contains the target
            // class button. If the clicked NodeCategoryViewModel represents a category
            // itself, then expand it and close out other sibling NodeCategoryViewModel.
            foreach (var expandedCategory in allExpandedCategories)
            {
                var searchFurtherInNextLevel = true;

                // If class button was clicked.
                if (selectedClass.IsClassButton)
                {
                    var categoryClasses = expandedCategory.Items[0] as ClassesNodeCategoryViewModel;
                    if (categoryClasses != null) // There are classes under this category...
                    {
                        if (expandedCategory.IsClassButton)
                        {
                            // If the category does not contain any sub category, 
                            // then we won't look for the selected class within it.
                            expandedCategory.IsExpanded = false;
                            searchFurtherInNextLevel = false;
                        }
                        else if (categoryClasses.Items.Contains(selectedClass))
                        {
                            // If the category contains the selected class directly 
                            // within, then keep it expanded instead of collapsing it.
                            expandedCategory.IsExpanded = true;

                            // Found the selected class! Collapse all other sub categories.
                            foreach (var ele in expandedCategory.SubCategories)
                                ele.IsExpanded = false;

                            searchFurtherInNextLevel = false;
                        }
                    }
                }

                if (searchFurtherInNextLevel)
                {
                    var childCategories = expandedCategory.Items.OfType<NodeCategoryViewModel>();
                    expandedCategory.IsExpanded = ExpandCategory(childCategories, selectedClass);
                }

                // If the category remains expanded after this, we can 
                // be sure that the selected class was found within it.
                foundSelectedClass = foundSelectedClass || expandedCategory.IsExpanded;
            }

            return foundSelectedClass;
        }
示例#14
0
 public ClassesNodeCategoryViewModel(NodeCategoryViewModel parent)
     : base(Configurations.ClassesDefaultName)
 {
     FullCategoryName = Configurations.ClassesDefaultName;
     Parent = parent;
 }
示例#15
0
        public void InsertSubCategory(NodeCategoryViewModel newSubCategory)
        {
            var list = SubCategories.Where(cat => !(cat is ClassesNodeCategoryViewModel));
            var nextLargerItemIndex = FindInsertionPointByName(list, newSubCategory.Name);

            if (nextLargerItemIndex >= 0)
            {
                bool hasClasses = SubCategories.FirstOrDefault() is ClassesNodeCategoryViewModel;
                var offset = hasClasses ? 1 : 0;
                SubCategories.Insert(nextLargerItemIndex + offset, newSubCategory);
            }
            else
                SubCategories.Add(newSubCategory);
        }
示例#16
0
        private static NodeCategoryViewModel GetCategoryViewModel(NodeCategoryViewModel rootCategory,
            IEnumerable<string> categories)
        {
            var nameStack = new Stack<string>(categories.Reverse());
            NodeCategoryViewModel target = rootCategory;
            NodeCategoryViewModel newTarget = null;
            bool isCheckedForClassesCategory = false;
            while (nameStack.Any())
            {
                var currentCategory = nameStack.Pop();
                newTarget = target.SubCategories.FirstOrDefault(c => c.Name == currentCategory);
                if (newTarget == null)
                {
                    if (!isCheckedForClassesCategory && !target.IsClassButton &&
                        target.SubCategories[0] is ClassesNodeCategoryViewModel)
                    {
                        isCheckedForClassesCategory = true;
                        nameStack.Push(currentCategory);
                        nameStack.Push(Configurations.ClassesDefaultName);
                        continue;
                    }

                    return null;
                }

                target = newTarget;
            }

            return target;
        }
示例#17
0
        public void ElementTypeToBoolConverterTest()
        {
            var converter = new ElementTypeToBoolConverter();
            var NseVM = new NodeSearchElementViewModel(
                new NodeModelSearchElement(new TypeLoadData(typeof(Nodes.Symbol))), null);
            var NcVM = new NodeCategoryViewModel("");
            var RncVM = new RootNodeCategoryViewModel("");
            var CncVM = new ClassesNodeCategoryViewModel(RncVM);

            object result;

            //1. Element is null.
            //2. Element is NodeSearchElement.
            //3. Element is NodeCategoryViewModel.
            //4. Element is RootNodeCategoryViewModel.
            //5. Element is RootNodeCategoryViewModel with ClassesNodeCategoryViewModel.

            // 1 case
            result = converter.Convert(null, null, null, null);
            Assert.AreEqual(false, result);

            // 2 case
            result = converter.Convert(NseVM, null, null, null);
            Assert.AreEqual(false, result);

            // 3 case
            result = converter.Convert(NcVM, null, null, null);
            Assert.AreEqual(true, result);

            // 4 case
            result = converter.Convert(RncVM, null, null, null);
            Assert.AreEqual(true, result);

            // 5 case
            RncVM.SubCategories.Add(CncVM);
            result = converter.Convert(RncVM, null, null, null);
            Assert.AreEqual(false, result);
        }
示例#18
0
 private void AddEntryToExistingCategory(NodeCategoryViewModel category,
     NodeSearchElementViewModel entry)
 {
     category.RequestBitmapSource += SearchViewModelRequestBitmapSource; 
     // Check if the category exists already. 
     // ex : clockwork package. For clockwork 
     // package the category names in dyf is different from what we show it 
     // on the tree view. so when you click on the category to populate it 
     // triggers an update to category name. on the same instance when you uninstall
     // and insall the clockwork package, the categories are named correctly but 
     // every install triggers an update that gives a duplicate entry. so check if the
     // entry is already added (specific to browse).
     if (category.Entries.All(x => x.FullName != entry.FullName))
     {
         category.Entries.Add(entry);
     }
 }
示例#19
0
        public void LibraryTreeItemsHostVisibilityConverterTest()
        {
            var converter = new LibraryTreeItemsHostVisibilityConverter();

            var result = converter.Convert(null, null, null, null);
            Assert.AreEqual(Visibility.Visible, result);

            var NcVM = new NodeCategoryViewModel("");
            result = converter.Convert(NcVM, null, null, null);
            Assert.AreEqual(Visibility.Visible, result);

            var RncVM = new ClassesNodeCategoryViewModel(NcVM);

            result = converter.Convert(RncVM, null, null, null);
            Assert.AreEqual(Visibility.Collapsed, result);
        }
示例#20
0
 private IEnumerable<RootNodeCategoryViewModel> CategorizeEntries(IEnumerable<NodeSearchElement> entries, bool expanded)
 {
     var tempRoot =
         entries.GroupByRecursive<NodeSearchElement, string, NodeCategoryViewModel>(
             element => element.Categories,
             (name, subs, es) =>
             {
                 var category =
                     new NodeCategoryViewModel(name, es.OrderBy(en => en.Name).Select(MakeNodeSearchElementVM), subs);
                 category.IsExpanded = expanded;
                 category.RequestBitmapSource += SearchViewModelRequestBitmapSource;
                 return category;
             }, "");
     var result =
         tempRoot.SubCategories.Select(
             cat =>
                 new RootNodeCategoryViewModel(cat.Name, cat.Entries, cat.SubCategories)
                 {
                     IsExpanded = expanded
                 });
     tempRoot.Dispose();
     return result.OrderBy(cat => cat.Name);
 }
示例#21
0
 public ClassesNodeCategoryViewModel(NodeCategoryViewModel parent)
     : base(Configurations.ClassesDefaultName)
 {
     FullCategoryName = Configurations.ClassesDefaultName;
     Parent           = parent;
 }
示例#22
0
 internal SearchMemberGroup(string fullyQualifiedName, NodeCategoryViewModel category = null)
 {
     FullyQualifiedName = fullyQualifiedName;
     Category = category;
     members = new List<NodeSearchElementViewModel>();
 }