public CategorySortingHat CategorizeEnabledNodes()
        {
            HashSet<string> enabledNodes = new HashSet<string>();

            if (Properties.Settings.Default.ToolBarNodes != null)
            {
                foreach (string nodeTypeName in Properties.Settings.Default.ToolBarNodes)
                {
                    enabledNodes.Add(nodeTypeName);
                }
            }

            var categorizer = new CategorySortingHat();

            foreach (MyNodeConfig nodeConfig in MyConfiguration.KnownNodes.Values)
            {
                if (nodeConfig.CanBeAdded && (enabledNodes.Contains(nodeConfig.NodeType.Name)))
                {
                    categorizer.AddNodeAndCategory(nodeConfig);
                }
            }

            return categorizer;
        }
        private void GenerateNodeList()
        {
            var enabledNodes = new HashSet<string>();

            if (Properties.Settings.Default.ToolBarNodes != null)
            {
                foreach (string nodeTypeName in Properties.Settings.Default.ToolBarNodes)
                {
                    enabledNodes.Add(nodeTypeName);
                }
            }

            var knownNodes = new Dictionary<string, List<MyNodeConfig>>();

            foreach (MyNodeConfig nodeConfig in MyConfiguration.KnownNodes.Values)
            {
                if (!nodeConfig.CanBeAdded || (nodeConfig.NodeType == null))
                    continue;

                string nameSpace = nodeConfig.NodeType.Namespace ?? "(unknown)";
                if (!knownNodes.ContainsKey(nameSpace))
                {
                    knownNodes[nameSpace] = new List<MyNodeConfig>();
                }

                knownNodes[nameSpace].Add(nodeConfig);
            }

            knownNodes["Worlds"] = new List<MyNodeConfig>();

            foreach (MyWorldConfig nodeConfig in MyConfiguration.KnownWorlds.Values)
            {
                knownNodes["Worlds"].Add(nodeConfig);
            }

            var categorizer = new CategorySortingHat();

            int i = 0;

            nodeImageList.Images.Add(GeneratePaddedIcon(Properties.Resources.group));
            i++;
            nodeImageList.Images.Add(GeneratePaddedIcon(Properties.Resources.world));
            i++;

            List<string> moduleNameSpaces = knownNodes.Keys.ToList().OrderBy(x => x).ToList();

            foreach (string nameSpace in moduleNameSpaces)
            {
                ListViewGroup group = new ListViewGroup(nameSpace, nameSpace.Replace("BrainSimulator.", ""));
                nodeListView.Groups.Add(group);

                List<MyNodeConfig> nodesInGroup = knownNodes[nameSpace].OrderBy(x => x.NodeType.Name).ToList(); ;

                foreach (MyNodeConfig nodeConfig in nodesInGroup)
                {
                    categorizer.AddNodeAndCategory(nodeConfig);

                    MyObsoleteAttribute obsolete = nodeConfig.NodeType.GetCustomAttribute<MyObsoleteAttribute>(true);

                    bool complete;
                    string[] subitems = ProduceSubitemTexts(nodeConfig, obsolete, out complete);

                    ListViewItem item = new ListViewItem(subitems)
                    {
                        Tag = nodeConfig,
                        Group = @group,
                        Checked = enabledNodes.Contains(nodeConfig.NodeType.Name)
                    };

                    // forbid to remove currently selected world
                    if (nodeConfig.NodeType == m_mainForm.Project.World.GetType())
                    {
                        item.BackColor = Color.FromArgb(150, 200, 240);  // (light gray-blue)
                        item.ToolTipText = "This world is being used by the current project (can't be deselected).";
                        // NOTE: the item's checkbox can't be disabled, we just override changes in nodeListView_ItemCheck()
                    }

                    if (obsolete != null)
                    {
                        item.ForeColor = SystemColors.GrayText;
                    }
                    else
                    {
                        if (!complete)
                        {
                            item.ForeColor = Color.Red;
                        }
                    }

                    if (nameSpace != "Worlds")
                    {
                        item.ImageIndex = i;
                        nodeImageList.Images.Add(GeneratePaddedIcon(nodeConfig.SmallImage));
                        i++;
                    }
                    else
                    {
                        item.ImageIndex = 1;
                    }

                    m_nodeInfoItems.Add(new UiNodeInfo(item, nodeConfig, string.Join("|", subitems)));
                }
            }

            PopulateCategoryListView(categorizer);
        }
        private void InitQuickToolBar(CategorySortingHat categorizer)
        {
            Settings settings = Settings.Default;
            if (settings.QuickToolBarNodes == null)
            {
                settings.QuickToolBarNodes = new StringCollection();
            }

            foreach (MyNodeConfig nodeConfig in categorizer.Nodes)
            {
                if (settings.QuickToolBarNodes.Contains(nodeConfig.NodeType.Name))
                    AddNodeButton(nodeConfig);
            }
        }
        private void PopulateCategoryListView(CategorySortingHat categorizer)
        {
            foreach (NodeCategory category in categorizer.SortedCategories)
            {
                filterImageList.Images.Add(GeneratePaddedIcon(category.SmallImage));

                var categoryItem = new ListViewItem(new string[1] { category.Name })
                {
                    Tag = category.Name,  // TODO(Premek): consider tagging with NodeCategory object
                    ImageIndex = filterImageList.Images.Count - 1
                };

                filterList.Items.Add(categoryItem);
            }
        }