1 /*
   2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.ext.device.ios.ipod;
  27 
  28 import java.util.ArrayList;
  29 import java.util.LinkedList;
  30 import java.util.List;
  31 
  32 import static com.sun.javafx.ext.device.ios.ipod.MediaFilter.MediaFilterType;
  33 
  34 /**
  35  * The MediaQuery class is the central entity of the iPod library access API. Its purpose is to provide
  36  * access to the user's iPod library content. It allows you to retrieve lists of media items fulfilling
  37  * certain criteria and group them by some shared properties. E.g. it is possible to filter out media items
  38  * of a particular genre, composer, title, etc. See the MediaFilter class description for the list of
  39  * available filters. It is possible to use multiple filters at the same time.
  40  * <br/>
  41  * The MediaQuery class also supports so called grouping. Grouping allows you to retrieve sorted and arranged
  42  * collections of media items. The arrangement you get depends on the value you set by calling the
  43  * MediaQuery.setGrouping() method.
  44  * <br/>
  45  * The possible arrangements you can achieve with grouping are as follows:
  46  * <ul>
  47  * <li><strong>Title</strong> - groups and sorts media item collections by title.</li>
  48  * <li><strong>Album</strong> - groups and sorts media item collections by album,
  49  * and sorts songs within an album by track order.</li>
  50  * <li><strong>Artist</strong> - groups and sorts media item collections by performing artist.</li>
  51  * <li><strong>AlbumArtist</strong> - groups and sorts media item collections by album artist
  52  * (the primary performing artist for an album as a whole).</li>
  53  * <li><strong>Composer</strong> - groups and sorts media item collections by composer.</li>
  54  * <li><strong>Genre</strong> - groups and sorts media item collections by musical or film genre.</li>
  55  * <li><strong>PlayList</strong> - groups and sorts media item collections by playlist.</li>
  56  * <li><strong>PodcastTitle</strong> - groups and sorts media item collections by podcast title.</li>
  57  * </ul>
  58  * The following code example creates an instance of the MediaQuery class to get a list of all items in the
  59  * user's iPod library:
  60  * <pre>
  61  * final MediaQuery mQuery = new MediaQuery();
  62  * final List&lt;MediaItem&gt; list = mQuery.getItems();
  63  * </pre>
  64  * The following example creates a MediaQuery instance, adds two filters to the query and retrieves the items.
  65  * The filters will make sure that we get a list of all musical items of the artist "TheBigLooser"
  66  * <pre>
  67  * final MediaQuery mQuery = new MediaQuery();
  68  *
  69  * final MediaFilter artistFilter = new MediaFilter(MediaFilter.MediaFilterType.Artist, "TheBigLooser");
  70  * mQuery.addFilter(artistFilter);
  71  *
  72  * final MediaFilter typeFilter = new MediaFilter(MediaFilter.MediaFilterType.MediaType, MediaItem.MediaItemType.Music);
  73  * mQuery.addFilter(typeFilter);
  74  *
  75  * final List&lt;MediaItem&gt; list = mQuery.getItems();
  76  * </pre>
  77  * If you add the following line, your results will be sorted and grouped by the album on which they appeared.
  78  * <pre>
  79  * mQuery.setGrouping(MediaQuery.MediaGroupingType.Album);
  80  * </pre>
  81  * However, remember that when you employ grouping, you are supposed to receive media item collections in a form
  82  * of a List of Lists (List&lt;List&lt;MediaItem&gt;&gt;) of media items.
  83  * <p>
  84  * The following example demonstrates how to use both filtering, grouping and how to display each media item's
  85  * properties:
  86  * <pre>
  87  * final MediaQuery mediaQuery = new MediaQuery();
  88  * final MediaFilter filter = new MediaFilter(MediaFilter.MediaFilterType.Artist, "RingtoneFeeder.com");
  89  * mediaQuery.addFilter(filter);
  90  * mediaQuery.setGroupingType(MediaQuery.MediaGroupingType.AlbumArtist);
  91  * final List&lt;List&lt;MediaItem&gt;&gt; collections = mediaQuery.getCollections();
  92  * for (final List&lt;MediaItem&gt; collection : collections) {
  93  *     for (final MediaItem item : collection) {
  94  *         System.out.println("      media type :        " + item.getMediaType());
  95  *         System.out.println("      title:              " + item.getTitle());
  96  *         System.out.println("      album title:        " + item.getAlbumTitle());
  97  *         System.out.println("      artist:             " + item.getArtist());
  98  *         System.out.println("      album artist:       " + item.getAlbumArtist());
  99  *         System.out.println("      genre:              " + item.getGenre());
 100  *         System.out.println("      composer:           " + item.getComposer());
 101  *         System.out.println("      playback duration:  " + item.getPlaybackDuration());
 102  *         System.out.println("      album track number: " + item.getAlbumTrackNumber());
 103  *         System.out.println("      album track count:  " + item.getAlbumTrackCount());
 104  *         System.out.println("      disc number:        " + item.getDiscNumber());
 105  *         System.out.println("      disc count:         " + item.getDiscCount());
 106  *         System.out.println("      lyrics:             " + item.getLyrics());
 107  *         System.out.println("      is compilation ?    " + item.isCompilation());
 108  *
 109  *         final SimpleDateFormat df = new SimpleDateFormat();
 110  *         df.applyPattern("dd/MM/yyyy");
 111  *         final Calendar date = item.getReleaseDate();
 112  *
 113  *         System.out.println("      release date:       " + df.format(date.getTime()));
 114  *         System.out.println("      beats per minute:   " + item.getBeatsPerMinute());
 115  *         System.out.println("      comments:           " + item.getComments());
 116  *         System.out.println("      url:                " + item.getURL());
 117  *     }
 118  * }
 119  * </pre>
 120  *
 121  */
 122 public class MediaQuery {
 123 
 124     /**
 125      * The MediaGroupingType enum defines valid values for grouping of a MediaQuery. See the
 126      * MediaQuery description for an explanation of the grouping functionality.
 127      *
 128      */
 129     public static enum MediaGroupingType {
 130         /**
 131          * Groups and sorts media item collections by title.
 132          */
 133         Title(0),
 134         /**
 135          * Groups and sorts media item collections by album, and sorts songs within an album by track order.
 136          */
 137         Album(1),
 138         /**
 139          * Groups and sorts media item collections by performing artist.
 140          */
 141         Artist(2),
 142         /**
 143          * Groups and sorts media item collections by album artist (the primary performing artist for an album as a whole).
 144          */
 145         AlbumArtist(3),
 146         /**
 147          * Groups and sorts media item collections by composer.
 148          */
 149         Composer(4),
 150         /**
 151          * Groups and sorts media item collections by musical or film genre.
 152          */
 153         Genre(5),
 154         /**
 155          * Groups and sorts media item collections by playlist.
 156          */
 157         PlayList(6),
 158         /**
 159          * Groups and sorts media item collections by podcast title.
 160          */
 161         PodcastTitle(7);
 162 
 163         private final int value;
 164 
 165         private MediaGroupingType(int value) {
 166             this.value = value;
 167         }
 168 
 169         /**
 170          * Returns the integer value associated with this enum value.
 171          * @return the integer value associated with this enum value.
 172          */
 173         public int getValue() {
 174             return value;
 175         }
 176     }
 177 
 178     private List<MediaFilter> filters;
 179     private MediaGroupingType groupingType;
 180 
 181     private List<MediaItem> items;
 182     private List<List<MediaItem>> collections;
 183 
 184     /* Native methods */
 185     private native void nCreateQuery();
 186     private native void nAddNumberPredicate(int key, int value);
 187     private native void nAddStringPredicate(int key, String value);
 188     private native void nSetGroupingType(int type);
 189     private native void nFillItemList();
 190     private native void nFillCollections();
 191     private native void nDisposeQuery();
 192 
 193     /* Methods called from native to fill up the lists */
 194     private void addMediaItem(final MediaItem item) {
 195         items.add(item);
 196     }
 197 
 198     private void addCollection(final List<MediaItem> collection) {
 199         collections.add(collection);
 200     }
 201 
 202     /**
 203      * Instantiates a new MediaQuery with no filtering and no grouping. Calling <code>getItems()</code>
 204      * right after this constructor would result in all media items from the iPod library being returned.
 205      */
 206     public MediaQuery() {
 207         filters = new ArrayList<MediaFilter>();
 208         items = new LinkedList<MediaItem>();
 209         collections = new LinkedList<List<MediaItem>>();
 210     }
 211 
 212     /**
 213      * Constructs a new MediaQuery instance and adds the given MediaFilter to the query.
 214      * @param filter An initial MediaFilter filter
 215      */
 216     public MediaQuery(final MediaFilter filter) {
 217         this();
 218         addFilter(filter);
 219     }
 220 
 221     /**
 222      * Adds another MediaFilter to this query.
 223      * @param filter the MediaFilter to be added to this query
 224      */
 225     public void addFilter(final MediaFilter filter) {
 226         filters.add(filter);
 227     }
 228 
 229     /**
 230      * Removes the specified filter from this query.
 231      * @param filter the MediaFilter to be removed from this query
 232      */
 233     public void removeFilter(final MediaFilter filter) {
 234         filters.remove(filter);
 235     }
 236 
 237     private void setupFilters() {
 238         for (final MediaFilter filter : filters) {
 239             final MediaFilterType type = filter.getFilterType();
 240             if (type == MediaFilterType.MediaType) {
 241                 final MediaItem.MediaItemType mediaType = (MediaItem.MediaItemType) filter.getFilterValue();
 242                 nAddNumberPredicate(type.getValue(), mediaType.getValue());
 243             }
 244             else if (type == MediaFilterType.IsCompilation) {
 245                 final boolean isCompilation = (Boolean) filter.getFilterValue();
 246                 nAddNumberPredicate(type.getValue(), isCompilation ? 1 : 0);
 247             }
 248             else {
 249                 nAddStringPredicate(type.getValue(), (String) filter.getFilterValue());
 250             }
 251         }
 252     }
 253 
 254     /**
 255      * Returns a list of media items from the iPod library that fulfill all the criteria imposed
 256      * by all the filters that were added to this query prior to this call. This method neglects
 257      * grouping. In order to employ grouping, use the <code>getCollections()</code> method instead.
 258      * @return a list of media items being a result of this query evaluation
 259      */
 260     public List<MediaItem> getItems() {
 261 
 262         nCreateQuery();
 263         setupFilters();
 264 
 265         if (!items.isEmpty()) {
 266             items.clear();
 267         }
 268 
 269         nFillItemList();
 270         nDisposeQuery();
 271 
 272         return items;
 273     }
 274 
 275     /**
 276      * Sets up grouping. For the list of available grouping types, see the MediaGroupingType enum.
 277      * @param groupingType the grouping type to use for creating media items collections
 278      */
 279     public void setGroupingType(final MediaGroupingType groupingType) {
 280         this.groupingType = groupingType;
 281     }
 282 
 283     /**
 284      * Returns a list of media items from the iPod library that fulfill all the criteria imposed
 285      * by all the filters that were added to this query prior to this call, arranged and grouped
 286      * by the grouping type set by calling the <code>setGroupingType</code> method. Collections are
 287      * returned in a form of lists of media items. See the <code>MediaQuery</code> class description
 288      * for an example on how to use grouping.
 289      * @return
 290      */
 291     public List<List<MediaItem>> getCollections() {
 292 
 293         nCreateQuery();
 294         setupFilters();
 295 
 296         if (!collections.isEmpty()) {
 297             for (final List<MediaItem> collection : collections) {
 298                 collection.clear();
 299             }
 300             collections.clear();
 301         }
 302 
 303         nSetGroupingType(groupingType.getValue());
 304         nFillCollections();
 305         nDisposeQuery();
 306 
 307         return collections;
 308     }
 309 
 310 }