Filtering the datasource - implementation

Create a filter class

One way to implement a filter is to create a class, an instance of which will replace the original datasource to ToC or Paged Document Control. This class won't store the data itself but will create maps between the original and filtered structure and implement methods that are called on the datasource.

@interface MyFilterDataSource : NSObject

This makes a new NSObject-derived class that conforms to the KGDocumentDataSource protocol. If you need further functions then you may need to make it conform to KGDocumentExtendedDataSource. Check the header files for related classes to determine which is the best for your needs.

Your class should:

  • Create instance variables for the original datasource object and for two arrays for a map and a reverse map so you can determine the original page number from the new page number and vice versa.
  • Create a custom init method to receive the original datasource and determine the property that you want to filter by.
  • Properties you could filter by include section, page type and level, all of which have values determined in the feed taxonomy.

In your custom init method initialize the arrays to the length of the incoming datasource, use the numberOfPages method call. To populate these two arrays, you need to iterate through the objects in the datasource and test to see if each one matches the property you want to filter by.

  • In the page map array you would put the index of each item in the original datasource that matches the filter property. For instance, if original page 5 is a match then you add the number object ‘5’ at the end of the page map array. The index of this entry is then the new, filtered, page number.
  • In the reverse page map array you want to use the original page number as the index to insert at. For the value to insert into that index you use either: the index of the entry added into the page map array (if the page matches the property filter required) OR an entry that will indicate that there is not index page at this index, we typically use -1.

Here's an example implementation of the code for the creation of the maps.

    self.mappedPageCount = 0;
    for (NSUInteger ii = 0; ii < [originalSource numberOfPages]; ii++) {
      NSUInteger reverseMapValue = -1;
      BOOL matchedFilter = [[[originalDataSource entryForPageNumber:ii] categoryWithScheme:@""] isEqualToString:FILTERTERM;
      if (matchedFilter) {
        [pageMap addObject:[NSNumber numberWithInt:ii]];
        reverseMapValue = mappedPageCount;
      [reversePageMap addObject:[NSNumber numberWithInt:reverseMapValue]];

Methods to implement

In order to make sure you are conforming to the KGDocumentDataSource protocol, your class should at the very least implement the following methods:

- (NSUInteger)numberOfPages;

This should return the number of pages that match the requested filter, returning the page map arrays count will be perfect.

- (NSURL*)urlForPageNumber:(NSUInteger)pageNumber;

This should return the URL for the page in the original datasource, use the mapping arrays to determine the new page number from the passed page number.

- (NSInteger)pageNumberForURL:(NSURL*)url;

The reverse of the previous method, where the URL is the search term and the page number found should mapped before returning. Note that pageNumberForURL on the original data source will return -1 when no page is found, such as with external URLs. This is used by framework, so an overridden method should do the same.

If you are conforming to one of the other, specialised document datasource types then there maybe more methods to override, consult the header files for the class to determine the exact scope of the protocol.

Using the filter class

To use this filtering mechanism, find the code that defines the datasource for the control you want to filter content for. We’ll use the ToC as an example. If you created your project from the pugpig template in Xcode, you’ll find this in the DocumentViewController.m file. Look for this:

 [tableOfContents setDataSource:(id)dataSource]; 

And replace it with:

 YourFilterDataSource *fds = [[[YourFilterDataSource alloc] initWithDataSource:dataSource withFilter:@"filter"] autorelease];
[tableOfContents setDataSource:fds]; 

Consider the image store

If you are filtering content that is shown in a Paged Document control object and also use a Thumbnail Control to show the snapshots then you will also want to provide a way for the backing image store for the thumbnails to be filtered to only show snapshots for the relevant pages.

Like the datasource the KGDocumentImageStore is a protocol, so create an NSObject-based class that conforms to the protocol and implements the methods required. Create a custom init method that receives the original image store and the filtered datasource and use these and their associated methods to return the correct values.

Simple filtering for the Table of Contents

There is a simple way to filter the display of content in the standard KGTableOfContentsControl object. The class provides three methods that will apply filtering to the content displayed.

Available Methods

- (void)setShowsArticleItems:(BOOL)shouldshow

Determines whether articles will appear in the ToC

- (void)setShowsSectionItems:(BOOL)shouldshow

Dtermines whether sections will appear in the ToC

- (void)setShouldHideUnsectionedItems:(BOOL)shouldshow

Determines whether items that are not linked to a section in the feed should appear. This is a good way of filtering out items like advertisements from the ToC datasource.

Interacting with Paged Doc Control

Note that this does not provide the same method of filtering in the same way as creating a filter class on the datasource would. The most important consequence of this is that the ToC's page numbers will be those from the original datasource and therefore will probably not be consecutive. For example if we were showing only section pages in the ToC and the relevant pages were 0,3,5,9,27,36 then these would be the page numbers referenced when selecting a section. If this is intended to be passed to a Paged Document Control object that DOES use a filtered datasource via a custom class then you will need to use the mapping functions of that custom class to make sure the correct page number is sent.

Was this article helpful?
0 out of 0 found this helpful
Have more questions? Submit a request


Powered by Zendesk