/// <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;
            }
        }
예제 #2
0
        /// <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;
            }
        }