Exemplo n.º 1
0
        private async Task LoadContent(CancellationToken token = default)
        {
            token.ThrowIfCancellationRequested();
            using (CustomActivity opLoadMasterindex = await Timekeeper.StartSyncronAsync("op_load_frm_masterindex", null,
                                                                                         CustomActivity.OperationType.RequestOperation, null))
            {
                bool blnOldIsFinishedLoading = IsFinishedLoading;
                try
                {
                    IsFinishedLoading = false;
                    await _dicCachedNotes.ClearAsync(token);

                    foreach (MasterIndexEntry objExistingEntry in _lstItems.Select(x => x.Value))
                    {
                        objExistingEntry.Dispose();
                    }
                    _lstItems.Clear();
                    _lstFileNamesWithItems.Clear();
                    string strSourceFilter;
                    using (new FetchSafelyFromPool <HashSet <string> >(Utils.StringHashSetPool,
                                                                       out HashSet <string> setValidCodes))
                    {
                        foreach (XPathNavigator xmlBookNode in await(await XmlManager.LoadXPathAsync(
                                                                         "books.xml", _objSelectedSetting.EnabledCustomDataDirectoryPaths, token: token))
                                 .SelectAndCacheExpressionAsync("/chummer/books/book/code"))
                        {
                            setValidCodes.Add(xmlBookNode.Value);
                        }

                        setValidCodes.IntersectWith(_objSelectedSetting.Books);

                        strSourceFilter = setValidCodes.Count > 0
                            ? '(' + string.Join(" or ", setValidCodes.Select(x => "source = " + x.CleanXPath())) + ')'
                            : "source";
                    }

                    using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_load_andpopulate_entries",
                                                                  opLoadMasterindex))
                    {
                        ConcurrentBag <ListItem> lstItemsForLoading = new ConcurrentBag <ListItem>();
                        using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_load_entries", opLoadMasterindex))
                        {
                            ConcurrentBag <ListItem> lstFileNamesWithItemsForLoading = new ConcurrentBag <ListItem>();
                            // Prevents locking the UI thread while still benefiting from static scheduling of Parallel.ForEach
                            await Task.WhenAll(_astrFileNames.Select(strFileName => Task.Run(async() =>
                            {
                                XPathNavigator xmlBaseNode
                                    = await XmlManager.LoadXPathAsync(strFileName,
                                                                      _objSelectedSetting
                                                                      .EnabledCustomDataDirectoryPaths,
                                                                      token: token);
                                xmlBaseNode = await xmlBaseNode.SelectSingleNodeAndCacheExpressionAsync("/chummer");
                                if (xmlBaseNode == null)
                                {
                                    return;
                                }
                                bool blnLoopFileNameHasItems = false;
                                foreach (XPathNavigator xmlItemNode in xmlBaseNode.Select(
                                             ".//*[page and " + strSourceFilter + ']'))
                                {
                                    blnLoopFileNameHasItems = true;
                                    string strName          = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("name"))
                                                              ?.Value;
                                    string strDisplayName
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("translate"))
                                          ?.Value
                                          ?? strName
                                          ?? (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("id"))?.Value
                                          ?? await LanguageManager.GetStringAsync("String_Unknown");
                                    string strSource
                                                   = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("source"))?.Value;
                                    string strPage = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("page"))
                                                     ?.Value;
                                    string strDisplayPage
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("altpage"))?.Value
                                          ?? strPage;
                                    string strEnglishNameOnPage
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("nameonpage"))
                                          ?.Value
                                          ?? strName;
                                    string strTranslatedNameOnPage =
                                        (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("altnameonpage"))
                                        ?.Value
                                        ?? strDisplayName;
                                    string strNotes
                                        = (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("altnotes"))?.Value
                                          ?? (await xmlItemNode.SelectSingleNodeAndCacheExpressionAsync("notes"))
                                          ?.Value;
                                    MasterIndexEntry objEntry = new MasterIndexEntry(
                                        strDisplayName,
                                        strFileName,
                                        await SourceString.GetSourceStringAsync(
                                            strSource, strPage, GlobalSettings.DefaultLanguage,
                                            GlobalSettings.InvariantCultureInfo),
                                        await SourceString.GetSourceStringAsync(
                                            strSource, strDisplayPage, GlobalSettings.Language,
                                            GlobalSettings.CultureInfo),
                                        strEnglishNameOnPage,
                                        strTranslatedNameOnPage);
                                    lstItemsForLoading.Add(new ListItem(objEntry, strDisplayName));
                                    if (!string.IsNullOrEmpty(strNotes))
                                    {
                                        await _dicCachedNotes.TryAddAsync(objEntry, Task.FromResult(strNotes), token);
                                    }
                                }

                                if (blnLoopFileNameHasItems)
                                {
                                    lstFileNamesWithItemsForLoading.Add(new ListItem(strFileName, strFileName));
                                }
                            }, token)));

                            _lstFileNamesWithItems.AddRange(lstFileNamesWithItemsForLoading);
                        }

                        using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_populate_entries", opLoadMasterindex))
                        {
                            string strSpace = await LanguageManager.GetStringAsync("String_Space");

                            string strFormat = "{0}" + strSpace + "[{1}]";
                            Dictionary <string, List <ListItem> > dicHelper
                                = new Dictionary <string, List <ListItem> >(lstItemsForLoading.Count);
                            try
                            {
                                foreach (ListItem objItem in lstItemsForLoading)
                                {
                                    if (!(objItem.Value is MasterIndexEntry objEntry))
                                    {
                                        continue;
                                    }
                                    string strKey = objEntry.DisplayName.ToUpperInvariant();
                                    if (dicHelper.TryGetValue(strKey, out List <ListItem> lstExistingItems))
                                    {
                                        ListItem objExistingItem = lstExistingItems.Find(
                                            x => x.Value is MasterIndexEntry y &&
                                            objEntry.DisplaySource.Equals(y.DisplaySource));
                                        if (objExistingItem.Value is MasterIndexEntry objLoopEntry)
                                        {
                                            objLoopEntry.FileNames.UnionWith(objEntry.FileNames);
                                            objEntry.Dispose();
                                        }
                                        else
                                        {
                                            using (new FetchSafelyFromPool <List <ListItem> >(
                                                       Utils.ListItemListPool,
                                                       out List <ListItem> lstItemsNeedingNameChanges))
                                            {
                                                lstItemsNeedingNameChanges.AddRange(lstExistingItems.FindAll(
                                                                                        x => x.Value is MasterIndexEntry y &&
                                                                                        !objEntry.FileNames.IsSubsetOf(y.FileNames)));
                                                if (lstItemsNeedingNameChanges.Count == 0)
                                                {
                                                    _lstItems.Add(
                                                        objItem); // Not using AddRange because of potential memory issues
                                                    lstExistingItems.Add(objItem);
                                                }
                                                else
                                                {
                                                    ListItem objItemToAdd = new ListItem(
                                                        objItem.Value, string.Format(GlobalSettings.CultureInfo,
                                                                                     strFormat, objItem.Name,
                                                                                     string.Join(
                                                                                         ',' + strSpace, objEntry.FileNames)));
                                                    _lstItems.Add(
                                                        objItemToAdd); // Not using AddRange because of potential memory issues
                                                    lstExistingItems.Add(objItemToAdd);

                                                    foreach (ListItem objToRename in lstItemsNeedingNameChanges)
                                                    {
                                                        _lstItems.Remove(objToRename);
                                                        lstExistingItems.Remove(objToRename);

                                                        if (!(objToRename.Value is MasterIndexEntry objExistingEntry))
                                                        {
                                                            continue;
                                                        }
                                                        objItemToAdd = new ListItem(objToRename.Value, string.Format(
                                                                                        GlobalSettings.CultureInfo,
                                                                                        strFormat, objExistingEntry.DisplayName,
                                                                                        string.Join(
                                                                                            ',' + strSpace,
                                                                                            objExistingEntry.FileNames)));
                                                        _lstItems.Add(
                                                            objItemToAdd); // Not using AddRange because of potential memory issues
                                                        lstExistingItems.Add(objItemToAdd);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    else
                                    {
                                        _lstItems.Add(objItem); // Not using AddRange because of potential memory issues
                                        List <ListItem> lstHelperItems = Utils.ListItemListPool.Get();
                                        lstHelperItems.Add(objItem);
                                        dicHelper.Add(strKey, lstHelperItems);
                                    }
                                }
                            }
                            finally
                            {
                                foreach (List <ListItem> lstHelperItems in dicHelper.Values)
                                {
                                    Utils.ListItemListPool.Return(lstHelperItems);
                                }
                            }
                        }
                    }

                    using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_sort_entries", opLoadMasterindex))
                    {
                        _lstItems.Sort(CompareListItems.CompareNames);
                        _lstFileNamesWithItems.Sort(CompareListItems.CompareNames);
                    }

                    using (_ = await Timekeeper.StartSyncronAsync("load_frm_masterindex_populate_controls", opLoadMasterindex))
                    {
                        _lstFileNamesWithItems.Insert(
                            0, new ListItem(string.Empty, await LanguageManager.GetStringAsync("String_All")));

                        int intOldSelectedIndex = await cboFile.DoThreadSafeFuncAsync(x => x.SelectedIndex, token);

                        await cboFile.PopulateWithListItemsAsync(_lstFileNamesWithItems, token);

                        await cboFile.DoThreadSafeAsync(x =>
                        {
                            try
                            {
                                x.SelectedIndex = Math.Max(intOldSelectedIndex, 0);
                            }
                            // For some reason, some unit tests will fire this exception even when _lstFileNamesWithItems is explicitly checked for having enough items
                            catch (ArgumentOutOfRangeException)
                            {
                                x.SelectedIndex = -1;
                            }
                        }, token);

                        await lstItems.PopulateWithListItemsAsync(_lstItems, token);

                        await lstItems.DoThreadSafeAsync(x => x.SelectedIndex = -1, token);
                    }
                }
                finally
                {
                    _blnSkipRefresh   = false;
                    IsFinishedLoading = blnOldIsFinishedLoading;
                }
            }
        }