/// <summary> /// Updates the GUI data for a filter values selection screen which reflects the available filter values for /// the current base view specification of our <see cref="AbstractScreenData._navigationData"/>. /// </summary> protected async Task ReloadFilterValuesList(bool createNewList) { MediaLibraryQueryViewSpecification currentVS = _navigationData.BaseViewSpecification as MediaLibraryQueryViewSpecification; if (currentVS == null) { // Should never happen ServiceRegistration.Get <ILogger>().Error("FilterScreenData: Wrong type of media library view '{0}'", _navigationData.BaseViewSpecification); return; } // Control other threads reentering this method lock (_syncObj) { if (_buildingList) { // Another thread is already building the items list - mark it as dirty and let the other thread // rebuild it. _listDirty = true; return; } // Mark the list as being built _buildingList = true; _listDirty = false; } try { ItemsList items; if (createNewList) { items = new ItemsList(); } else { items = _items; items.Clear(); } try { Display_ListBeingBuilt(); IFilter filter = currentVS.FilterTree.BuildFilter(_filterPath); ICollection <Guid> necessaryMIAs = _necessaryFilteredMIATypeIds ?? currentVS.NecessaryMIATypeIds; // If the number of values to create exceeds MAX_NUM_ITEMS_VISIBLE we need to try and group the items. // We request all values first, rather than groups, on the assumption that most of the time the limit // shouldn't be reached given that we are filtering the values. bool grouping = false; ICollection <FilterValue> fv = await _filterCriterion.GetAvailableValuesAsync(necessaryMIAs, _clusterFilter, filter).ConfigureAwait(false); if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE && _clusterFilter == null) { ICollection <FilterValue> groupValues = await _filterCriterion.GroupValuesAsync(necessaryMIAs, _clusterFilter, filter).ConfigureAwait(false); if (groupValues != null && groupValues.Count > 0) { fv = groupValues; grouping = true; } } if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE) { Display_TooManyItems(fv.Count); } else { bool dirty; lock (_syncObj) dirty = _listDirty; if (dirty) { UpdateOrRebuildView(items, createNewList); return; } _sortable = true; int totalNumItems = 0; List <FilterItem> itemsList = new List <FilterItem>(); // Build collection of available (filter/display) screens which will remain in the next view - that is all currently // available screens without the screen which equals this current screen. But we cannot simply remove "this" // from the collection, because "this" could be a derived screen (in case our base screen showed groups). // So we need an equality criterion when the screen to be removed is equal to this screen in terms of its // filter criterion. But with the given data, we actually cannot derive that equality. // So we simply use the MenuItemLabel, which should be the same in this and the base screen of the same filter. foreach (FilterValue f in fv) { //Used for enclosure FilterValue filterValue = f; _sortable &= filterValue.Item != null; string filterTitle = filterValue.Title; IFilter selectAttributeFilter = filterValue.SelectAttributeFilter; MediaLibraryQueryViewSpecification subVS = currentVS.CreateSubViewSpecification(filterTitle, FilterTreePath.Combine(_filterPath, filterValue.RelativeFilterPath), filterValue.Filter, filterValue.LinkedId); T filterValueItem = new T { // Support non-playable MediaItems (i.e. Series, Seasons) MediaItem = filterValue.Item, SimpleTitle = filterTitle, NumItems = filterValue.NumItems, Id = filterValue.Id, Command = new MethodDelegateCommand(() => { if (grouping) { NavigateToGroup(subVS, selectAttributeFilter); } else { NavigateToSubView(subVS); } }), View = subVS.BuildView() }; itemsList.Add(filterValueItem); if (filterValue.NumItems.HasValue) { totalNumItems += filterValue.NumItems.Value; } } if (_sortable) { Sorting.Sorting sorting = CurrentSorting; if (sorting != null) { itemsList.Sort((i1, i2) => sorting.Compare(i1.MediaItem, i2.MediaItem)); } } // Derived classes can implement special initial selection handling here, // e.g. the first unwatched episode could be selected from a list of episodes SetSelectedItem(itemsList); CollectionUtils.AddAll(items, itemsList); Display_Normal(items.Count, totalNumItems == 0 ? new int?() : totalNumItems); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("AbstractFiltersScreenData: Error creating filter values list", e); Display_ItemsInvalid(); } UpdateOrRebuildView(items, createNewList); } finally { lock (_syncObj) _buildingList = false; } }
/// <summary> /// Updates the GUI data for a filter values selection screen which reflects the available filter values for /// the current base view specification of our <see cref="AbstractScreenData._navigationData"/>. /// </summary> protected void ReloadFilterValuesList(bool createNewList) { MediaLibraryQueryViewSpecification currentVS = _navigationData.BaseViewSpecification as MediaLibraryQueryViewSpecification; if (currentVS == null) { // Should never happen ServiceRegistration.Get <ILogger>().Error("FilterScreenData: Wrong type of media library view '{0}'", _navigationData.BaseViewSpecification); return; } // Control other threads reentering this method lock (_syncObj) { if (_buildingList) { // Another thread is already building the items list - mark it as dirty and let the other thread // rebuild it. _listDirty = true; return; } // Mark the list as being built _buildingList = true; _listDirty = false; } try { ItemsList items; if (createNewList) { items = new ItemsList(); } else { items = _items; items.Clear(); } try { Display_ListBeingBuilt(); bool grouping = true; ICollection <FilterValue> fv = _clusterFilter == null? _filterCriterion.GroupValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentVS.Filter) : null; if (fv == null || fv.Count <= Consts.MAX_NUM_ITEMS_VISIBLE) { fv = _filterCriterion.GetAvailableValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentVS.Filter); grouping = false; } if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE) { Display_TooManyItems(fv.Count); } else { lock (_syncObj) if (_listDirty) { goto RebuildView; } int totalNumItems = 0; // Build collection of available (filter/display) screens which will remain in the next view - that is all currently // available screens without the screen which equals this current screen. But we cannot simply remove "this" // from the collection, because "this" could be a derived screen (in case our base screen showed groups). // So we need an equality criterion when the screen to be removed is equal to this screen in terms of its // filter criterion. But with the given data, we actually cannot derive that equality. // So we simply use the MenuItemLabel, which should be the same in this and the base screen of the same filter. foreach (FilterValue filterValue in fv) { string filterTitle = filterValue.Title; IFilter selectAttributeFilter = filterValue.SelectAttributeFilter; MediaLibraryQueryViewSpecification subVS = currentVS.CreateSubViewSpecification(filterTitle, filterValue.Filter); T filterValueItem = new T { SimpleTitle = filterTitle, NumItems = filterValue.NumItems, Command = grouping ? new MethodDelegateCommand(() => NavigateToGroup(subVS, selectAttributeFilter)) : new MethodDelegateCommand(() => NavigateToSubView(subVS)) }; items.Add(filterValueItem); if (filterValue.NumItems.HasValue) { totalNumItems += filterValue.NumItems.Value; } } Display_Normal(items.Count, totalNumItems == 0 ? new int?() : totalNumItems); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("AbstractFiltersScreenData: Error creating filter values list", e); Display_ItemsInvalid(); } RebuildView: if (_listDirty) { lock (_syncObj) _buildingList = false; ReloadFilterValuesList(createNewList); } else { _items = items; _items.FireChange(); } } finally { lock (_syncObj) _buildingList = false; } }
/// <summary> /// Updates the GUI data for a filter values selection screen which reflects the available filter values for /// the current base view specification of our <see cref="AbstractScreenData._navigationData"/>. /// </summary> protected void ReloadFilterValuesList(bool createNewList) { MediaLibraryQueryViewSpecification currentVS = _navigationData.BaseViewSpecification as MediaLibraryQueryViewSpecification; if (currentVS == null) { // Should never happen ServiceRegistration.Get <ILogger>().Error("FilterScreenData: Wrong type of media library view '{0}'", _navigationData.BaseViewSpecification); return; } // Control other threads reentering this method lock (_syncObj) { if (_buildingList) { // Another thread is already building the items list - mark it as dirty and let the other thread // rebuild it. _listDirty = true; return; } // Mark the list as being built _buildingList = true; _listDirty = false; } try { ItemsList items; if (createNewList) { items = new ItemsList(); } else { items = _items; items.Clear(); } try { Display_ListBeingBuilt(); bool grouping = true; //If currentVS is the base view it's possible that it has a filter that is incompatible with _filterCriterion. //This is the case if a plugin has added a base filter to exclude certain items, e.g. TV excludes recordings //and the new filter filters by a different media type, e.g. series'. Ignore the base filter in this case. IFilter currentFilter = (_navigationData.Parent != null && CanFilter(_navigationData.Parent.CurrentScreenData)) || currentVS.CanCombineFilters(_filteredMias) ? currentVS.Filter : null; ICollection <FilterValue> fv = _clusterFilter == null? _filterCriterion.GroupValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentFilter) : null; if (fv == null || fv.Count <= Consts.MAX_NUM_ITEMS_VISIBLE) { fv = _filterCriterion.GetAvailableValues(currentVS.NecessaryMIATypeIds, _clusterFilter, currentFilter); grouping = false; } if (fv.Count > Consts.MAX_NUM_ITEMS_VISIBLE) { Display_TooManyItems(fv.Count); } else { bool dirty; lock (_syncObj) dirty = _listDirty; if (dirty) { UpdateOrRebuildView(items, createNewList); return; } _sortable = true; int totalNumItems = 0; List <FilterItem> itemsList = new List <FilterItem>(); // Build collection of available (filter/display) screens which will remain in the next view - that is all currently // available screens without the screen which equals this current screen. But we cannot simply remove "this" // from the collection, because "this" could be a derived screen (in case our base screen showed groups). // So we need an equality criterion when the screen to be removed is equal to this screen in terms of its // filter criterion. But with the given data, we actually cannot derive that equality. // So we simply use the MenuItemLabel, which should be the same in this and the base screen of the same filter. foreach (FilterValue filterValue in fv) { _sortable &= filterValue.Item != null; string filterTitle = filterValue.Title; IFilter selectAttributeFilter = filterValue.SelectAttributeFilter; MediaLibraryQueryViewSpecification subVS = currentVS.CreateSubViewSpecification(filterTitle, filterValue.Filter, _filteredMias); T filterValueItem = new T { // Support non-playable MediaItems (i.e. Series, Seasons) MediaItem = filterValue.Item, SimpleTitle = filterTitle, NumItems = filterValue.NumItems, Id = filterValue.Id, Command = grouping ? new MethodDelegateCommand(() => NavigateToGroup(subVS, selectAttributeFilter)) : new MethodDelegateCommand(() => NavigateToSubView(subVS)) }; itemsList.Add(filterValueItem); if (filterValue.NumItems.HasValue) { totalNumItems += filterValue.NumItems.Value; } } if (_sortable) { Sorting.Sorting sorting = CurrentSorting; if (sorting != null) { itemsList.Sort((i1, i2) => sorting.Compare(i1.MediaItem, i2.MediaItem)); } } CollectionUtils.AddAll(items, itemsList); Display_Normal(items.Count, totalNumItems == 0 ? new int?() : totalNumItems); } } catch (Exception e) { ServiceRegistration.Get <ILogger>().Warn("AbstractFiltersScreenData: Error creating filter values list", e); Display_ItemsInvalid(); } UpdateOrRebuildView(items, createNewList); } finally { lock (_syncObj) _buildingList = false; } }