/// <summary>
        /// This function should be called when you want to load more files after the loading of the library is finished.
        /// This function is mainly called when the user save a new group in the library. This function will not delete any
        /// part, but will update the existing part if you reload the same part.
        /// </summary>
        /// <param name="xmlFiles">The list of group xml to load</param>
        public void loadAdditionnalGroups(List<FileInfo> xmlFiles, List<string> groupNames)
        {
            // use a default display setting that won't be used to change the setting of the Custom tab page
            // unless this tab page doesn't exist, in which case the default setting is suitable
            PartLibDisplaySetting displaySetting = new PartLibDisplaySetting();
            CategoryBuildingInfo buildingInfo = new CategoryBuildingInfo(displaySetting.mRespectProportion);

            // first check if the Custom tab exits. If not we need to create it.
            if (this.TabPages.ContainsKey(PartLibraryPanel.sFolderNameForCustomParts))
            {
                // the tabe page exist, so get it
                TabPage tabPage = this.TabPages[this.TabPages.IndexOfKey(PartLibraryPanel.sFolderNameForCustomParts)];
                // patch the building info with the correct listview
                buildingInfo.mListView = tabPage.Controls[0] as PartListView;
                // patch also the image list
                buildingInfo.mImageList = buildingInfo.mListView.reconstructImageListFromBrickLibrary();
                // patch the respect proportion
                buildingInfo.mRespectProportion = (tabPage.ContextMenuStrip.Items[(int)ContextMenuIndex.RESPECT_PROPORTION] as ToolStripMenuItem).Checked;

                // now check if the part is already in, and remove it in order to replace it
                foreach (string name in groupNames)
                    foreach (ListViewItem item in buildingInfo.mListView.Items)
                        if (item.Tag.Equals(name))
                        {
                            int removedImageIndex = item.ImageIndex;
                            buildingInfo.mImageList.RemoveAt(removedImageIndex);
                            buildingInfo.mListView.Items.Remove(item);
                            // then iterate again on all the item to shift all the image index that are after the item removed of -1
                            foreach (ListViewItem itemToShift in buildingInfo.mListView.Items)
                                if (itemToShift.ImageIndex > removedImageIndex)
                                    itemToShift.ImageIndex = itemToShift.ImageIndex - 1;
                            // break the list view search since we found the item to remove
                            break;
                        }
            }
            else
            {
                // The custom page doesn't exist we need to create a new one
                addOneTabPageWithItsListView(buildingInfo, PartLibraryPanel.sFolderNameForCustomParts, displaySetting);
            }

            // now load the xml files
            List<FileNameWithException> imageFileUnloadable = new List<FileNameWithException>();
            List<FileNameWithException> xmlFileUnloadable = new List<FileNameWithException>();
            fillListViewWithPartsWithoutImage(buildingInfo, xmlFiles, xmlFileUnloadable, true);

            // the fill the list view with the new groups
            fillListViewWithGroupAndImageToFinalize(buildingInfo, imageFileUnloadable, xmlFileUnloadable);

            // after the loading is finished eventually display the error messages
            displayErrorMessage(imageFileUnloadable, xmlFileUnloadable);

            // Select the Custom Tab page
            int cutsomTabIndex = this.TabPages.IndexOfKey(PartLibraryPanel.sFolderNameForCustomParts);
            if (cutsomTabIndex >= 0)
            {
                // select the Custom tab
                this.SelectTab(cutsomTabIndex);
                // find the first item created and scroll it in view
                foreach (ListViewItem item in buildingInfo.mListView.Items)
                    if (item.Tag.Equals(groupNames[0]))
                    {
                        buildingInfo.mListView.EnsureVisible(item.Index);
                        break;
                    }
            }
        }
        /// <summary>
        /// This method create a new TabPage into the tab control of the library panel, and also create the ListView
        /// that holds the brick items, which is the only child of the TabPage
        /// </summary>
        /// <param name="buildingInfo">The building info that can be used to create the tab</param>
        /// <param name="tabPageName">The name of the tab page (which should be the name of the folder)</param>
        /// <param name="displaySetting">a display setting to correctly init the tab properties</param>
        private void addOneTabPageWithItsListView(CategoryBuildingInfo buildingInfo, string tabPageName, PartLibDisplaySetting displaySetting)
        {
            // add the tab in the tab control, based on the name of the folder
            TabPage newTabPage = new TabPage(tabPageName);
            newTabPage.Name = tabPageName;
            newTabPage.ContextMenuStrip = createContextMenuItemForATabPage(displaySetting.mLargeIcons, displaySetting.mRespectProportion);
            this.TabPages.Add(newTabPage);

            // then for the new tab added, we add a list control to
            // fill it with the pictures found in that folder
            // but we don't need to create it, we use the one created in the building info
            PartListView newListView = buildingInfo.mListView; // get a shortcut on the list view
            // filter the view (at this point it will be useless since there's no item in the view, but the goal is to save the filter sentence, it will be refilter later)
            newListView.filter(displaySetting.mFilterSentence, true);
            // set the tile size
            if (displaySetting.mLargeIcons)
                newListView.TileSize = PART_ITEM_LARGE_SIZE_WITH_MARGIN;
            else
                newListView.TileSize = PART_ITEM_SMALL_SIZE_WITH_MARGIN;
            // set the event handler
            newListView.MouseMove += new System.Windows.Forms.MouseEventHandler(this.listView_MouseMove);

            // add the list view to the tab page
            newTabPage.Controls.Add(newListView);
        }
        /// <summary>
        /// parse the part folder to find all the part in the library
        /// </summary>
        public void initPartsTabControl()
        {
            // suspend layout when rebuilding the library
            this.SuspendLayout();

            // init the part tab control based on the folders found on the drive
            // first clear the tab control
            this.TabPages.Clear();
            // then search the "parts" folder, if not here maybe we should display
            // an error message (something wrong with the installation of the application?)
            DirectoryInfo partsFolder = new DirectoryInfo(PartLibraryPanel.sFullPathForLibrary);
            if (partsFolder.Exists)
            {
                // create two list to record the exception thrown by some files
                List<FileNameWithException> imageFileUnloadable = new List<FileNameWithException>();
                List<FileNameWithException> xmlFileUnloadable = new List<FileNameWithException>();

                // create from the Settings a dictionary to store the display status of each tab
                Dictionary<string, PartLibDisplaySetting> tabDisplayStatus = new Dictionary<string,PartLibDisplaySetting>();
                foreach (string tabConfig in Settings.Default.UIPartLibDisplayConfig)
                {
                    // the format of the tabConfig string is: tabName00?filterSentence
                    // we will split it in the middle at the '?' char
                    string filterSentence = string.Empty;
                    // get the index of the ? character which is the separator between the tab name and the filter keywords
                    // because the ? char cannot be used in filename (and tab name comes from filename)
                    int separatorIndex = tabConfig.IndexOf('?');
                    if (separatorIndex < 0)
                        separatorIndex = tabConfig.Length; // check the case of old config file without "?" char separator
                    // get the first part before the keyword
                    string tabNameAndDisplayConfig = tabConfig.Substring(0, separatorIndex);
                    // maybe we have some keywords, so try to get them
                    if (tabConfig.Length > separatorIndex + 1)
                        filterSentence = tabConfig.Substring(separatorIndex + 1);
                    tabDisplayStatus.Add(tabNameAndDisplayConfig.Remove(separatorIndex - 2),
                                         new PartLibDisplaySetting(tabNameAndDisplayConfig[separatorIndex - 2] == '1',
                                                                    tabNameAndDisplayConfig[separatorIndex - 1] == '1',
                                                                    filterSentence));
                }

                // get all the folders in the parts folder to create a tab for each folder found
                DirectoryInfo[] categoryFolder = partsFolder.GetDirectories();

                // create a list to store all the info necessary for the library building for each category
                List<CategoryBuildingInfo> categoryList = new List<CategoryBuildingInfo>(categoryFolder.Length);

                // iterate on each folder
                foreach (DirectoryInfo category in categoryFolder)
                {
                    // try to get the display setting or construct a default one
                    PartLibDisplaySetting displaySetting = null;
                    if (!tabDisplayStatus.TryGetValue(category.Name, out displaySetting))
                        displaySetting = new PartLibDisplaySetting();

                    // create a building info and add it to the list
                    CategoryBuildingInfo buildingInfo = new CategoryBuildingInfo(displaySetting.mRespectProportion);
                    categoryList.Add(buildingInfo);

                    // create the tab page corresponding to the folder
                    addOneTabPageWithItsListView(buildingInfo, category.Name, displaySetting);

                    // fill the list view with the parts loaded from the files
                    fillListViewWithParts(buildingInfo, category, imageFileUnloadable, xmlFileUnloadable);
                }

                // reiterate on a second pass on all the list view, because we need to add the group parts
                foreach (CategoryBuildingInfo buildingInfo in categoryList)
                {
                    fillListViewWithGroupAndImageToFinalize(buildingInfo, imageFileUnloadable, xmlFileUnloadable);
                }

                // after the loading is finished eventually display the error messages
                displayErrorMessage(imageFileUnloadable, xmlFileUnloadable);

                // after creating all the tabs, sort them according to the settings
                updateAppearanceAccordingToSettings(true, false, false, false, true, true);

                // call the index event handler manually cause, it is not called on Mono
                PartLibraryPanel_SelectedIndexChanged(null, null);
            }

            // suspend layout when rebuilding the library
            this.ResumeLayout();
        }