Esempio n. 1
0
 public TreeBuilderContext(TreeBuilderContext other)
 {
     CurrentCriteria = new HashSet <string>(other.CurrentCriteria, StringComparer.OrdinalIgnoreCase);
     MatchedItems    = new HashSet <ItemDescriptor <TItem> >();
 }
Esempio n. 2
0
        private static DecisionTreeNode <TItem> GenerateNode(
            TreeBuilderContext context,
            DecisionCriterionValueEqualityComparer comparer,
            List <ItemDescriptor <TItem> > items)
        {
            // The extreme use of generics here is intended to reduce the number of intermediate
            // allocations of wrapper classes. Performance testing found that building these trees allocates
            // significant memory that we can avoid and that it has a real impact on startup.
            var criteria = new Dictionary <string, Criterion>(StringComparer.OrdinalIgnoreCase);

            // Matches are items that have no remaining criteria - at this point in the tree
            // they are considered accepted.
            var matches = new List <TItem>();

            // For each item in the working set, we want to map it to it's possible criteria-branch
            // pairings, then reduce that tree to the minimal set.
            foreach (var item in items)
            {
                var unsatisfiedCriteria = 0;

                foreach (var kvp in item.Criteria)
                {
                    // context.CurrentCriteria is the logical 'stack' of criteria that we've already processed
                    // on this branch of the tree.
                    if (context.CurrentCriteria.Contains(kvp.Key))
                    {
                        continue;
                    }

                    unsatisfiedCriteria++;

                    if (!criteria.TryGetValue(kvp.Key, out var criterion))
                    {
                        criterion = new Criterion(comparer);
                        criteria.Add(kvp.Key, criterion);
                    }

                    if (!criterion.TryGetValue(kvp.Value, out var branch))
                    {
                        branch = new List <ItemDescriptor <TItem> >();
                        criterion.Add(kvp.Value, branch);
                    }

                    branch.Add(item);
                }

                // If all of the criteria on item are satisfied by the 'stack' then this item is a match.
                if (unsatisfiedCriteria == 0)
                {
                    matches.Add(item.Item);
                }
            }

            // Iterate criteria in order of branchiness to determine which one to explore next. If a criterion
            // has no 'new' matches under it then we can just eliminate that part of the tree.
            var reducedCriteria = new List <DecisionCriterion <TItem> >();

            foreach (var criterion in criteria.OrderByDescending(c => c.Value.Count))
            {
                var reducedBranches = new Dictionary <object, DecisionTreeNode <TItem> >(comparer.InnerComparer);

                foreach (var branch in criterion.Value)
                {
                    bool hasReducedItems = false;

                    foreach (var item in branch.Value)
                    {
                        if (context.MatchedItems.Add(item))
                        {
                            hasReducedItems = true;
                        }
                    }

                    if (hasReducedItems)
                    {
                        var childContext = new TreeBuilderContext(context);
                        childContext.CurrentCriteria.Add(criterion.Key);

                        var newBranch = GenerateNode(childContext, comparer, branch.Value);
                        reducedBranches.Add(branch.Key.Value, newBranch);
                    }
                }

                if (reducedBranches.Count > 0)
                {
                    var newCriterion = new DecisionCriterion <TItem>()
                    {
                        Key      = criterion.Key,
                        Branches = reducedBranches,
                    };

                    reducedCriteria.Add(newCriterion);
                }
            }

            return(new DecisionTreeNode <TItem>()
            {
                Criteria = reducedCriteria,
                Matches = matches,
            });
        }
        public virtual void Initialize(string label, string icon, NodeBuilder[] builders, TreePadOption[] options)
        {
            // Create default options

            this.options = options;
            globalOptions = new TreeOptions ();
            foreach (TreePadOption op in options)
                globalOptions [op.Id] = op.DefaultValue;

            globalOptions.Pad = this;

            // Check that there is only one node builder per type

            Hashtable bc = new Hashtable ();
            foreach (NodeBuilder nb in builders) {
                TypeNodeBuilder tnb = nb as TypeNodeBuilder;
                if (tnb != null) {
                    TypeNodeBuilder other = (TypeNodeBuilder) bc [tnb.NodeDataType];
                    if (other != null)
                        throw new ApplicationException (string.Format ("The type node builder {0} can't be used in this context because the type {1} is already handled by {2}", nb.GetType(), tnb.NodeDataType, other.GetType()));
                    bc [tnb.NodeDataType] = tnb;
                }
                else if (!(nb is NodeBuilderExtension))
                    throw new InvalidOperationException (string.Format ("Invalid NodeBuilder type: {0}. NodeBuilders must inherit either from TypeNodeBuilder or NodeBuilderExtension", nb.GetType()));
            }

            NodeBuilders = builders;
            Title = label;
            Icon = icon;

            builderContext = new TreeBuilderContext (this);

            tree = new Gtk.TreeView ();

            /*
            0 -- Text
            1 -- Icon (Open)
            2 -- Icon (Closed)
            3 -- Node Data
            4 -- Builder chain
            5 -- Pango weight
            6 -- Expanded
            */
            store = new Gtk.TreeStore (typeof (string), typeof (Gdk.Pixbuf), typeof (Gdk.Pixbuf), typeof (object), typeof (object), typeof(int), typeof(bool));
            tree.Model = store;

            tree.EnableModelDragDest (target_table, Gdk.DragAction.Copy | Gdk.DragAction.Move);
            Gtk.Drag.SourceSet (tree, Gdk.ModifierType.Button1Mask, target_table, Gdk.DragAction.Copy | Gdk.DragAction.Move);

            store.DefaultSortFunc = new Gtk.TreeIterCompareFunc (CompareNodes);
            store.SetSortColumnId (/* GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID */ -1, Gtk.SortType.Ascending);

            tree.HeadersVisible = false;
            tree.SearchColumn = 0;
            tree.EnableSearch = true;
            complete_column = new Gtk.TreeViewColumn ();
            complete_column.Title = "column";

            Gtk.CellRendererPixbuf pix_render = new Gtk.CellRendererPixbuf ();
            complete_column.PackStart (pix_render, false);
            complete_column.AddAttribute (pix_render, "pixbuf", OpenIconColumn);
            complete_column.AddAttribute (pix_render, "pixbuf-expander-open", OpenIconColumn);
            complete_column.AddAttribute (pix_render, "pixbuf-expander-closed", ClosedIconColumn);

            text_render = new Gtk.CellRendererText ();
            text_render.Edited += new Gtk.EditedHandler (HandleOnEdit);

            complete_column.PackStart (text_render, true);
            complete_column.AddAttribute (text_render, "text", TextColumn);
            complete_column.AddAttribute (text_render, "weight", WeightColumn);

            tree.AppendColumn (complete_column);

            Gtk.ScrolledWindow sw = new Gtk.ScrolledWindow ();
            sw.Add(tree);
            contentPanel = new Gtk.Frame ();
            contentPanel.Add(sw);

            tree.TestExpandRow += new Gtk.TestExpandRowHandler (OnTestExpandRow);
            tree.RowActivated += new Gtk.RowActivatedHandler(OnNodeActivated);

            contentPanel.ButtonReleaseEvent += new Gtk.ButtonReleaseEventHandler(OnButtonRelease);
            contentPanel.PopupMenu += new Gtk.PopupMenuHandler (OnPopupMenu);

            foreach (NodeBuilder nb in builders)
                nb.SetContext (builderContext);

            workNode = new TreeNodeNavigator (this);
            compareNode1 = new TreeNodeNavigator (this);
            compareNode2 = new TreeNodeNavigator (this);

            tree.DragBegin += new Gtk.DragBeginHandler (OnDragBegin);
            tree.DragDataReceived += new Gtk.DragDataReceivedHandler (OnDragDataReceived);
            tree.DragDrop += new Gtk.DragDropHandler (OnDragDrop);
            tree.DragEnd += new Gtk.DragEndHandler (OnDragEnd);
            tree.DragMotion += new Gtk.DragMotionHandler (OnDragMotion);

            tree.CursorChanged += new EventHandler (OnSelectionChanged);

            contentPanel.ShowAll ();
        }