summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/app/FilterUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/app/FilterUtils.java')
-rw-r--r--src/com/android/gallery3d/app/FilterUtils.java257
1 files changed, 257 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/app/FilterUtils.java b/src/com/android/gallery3d/app/FilterUtils.java
new file mode 100644
index 000000000..bc28a9cc1
--- /dev/null
+++ b/src/com/android/gallery3d/app/FilterUtils.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.app;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.data.MediaObject;
+import com.android.gallery3d.data.Path;
+
+// This class handles filtering and clustering.
+//
+// We allow at most only one filter operation at a time (Currently it
+// doesn't make sense to use more than one). Also each clustering operation
+// can be applied at most once. In addition, there is one more constraint
+// ("fixed set constraint") described below.
+//
+// A clustered album (not including album set) and its base sets are fixed.
+// For example,
+//
+// /cluster/{base_set}/time/7
+//
+// This set and all sets inside base_set (recursively) are fixed because
+// 1. We can not change this set to use another clustering condition (like
+// changing "time" to "location").
+// 2. Neither can we change any set in the base_set.
+// The reason is in both cases the 7th set may not exist in the new clustering.
+// ---------------------
+// newPath operation: create a new path based on a source path and put an extra
+// condition on top of it:
+//
+// T = newFilterPath(S, filterType);
+// T = newClusterPath(S, clusterType);
+//
+// Similar functions can be used to replace the current condition (if there is one).
+//
+// T = switchFilterPath(S, filterType);
+// T = switchClusterPath(S, clusterType);
+//
+// For all fixed set in the path defined above, if some clusterType and
+// filterType are already used, they cannot not be used as parameter for these
+// functions. setupMenuItems() makes sure those types cannot be selected.
+//
+public class FilterUtils {
+ @SuppressWarnings("unused")
+ private static final String TAG = "FilterUtils";
+
+ public static final int CLUSTER_BY_ALBUM = 1;
+ public static final int CLUSTER_BY_TIME = 2;
+ public static final int CLUSTER_BY_LOCATION = 4;
+ public static final int CLUSTER_BY_TAG = 8;
+ public static final int CLUSTER_BY_SIZE = 16;
+ public static final int CLUSTER_BY_FACE = 32;
+
+ public static final int FILTER_IMAGE_ONLY = 1;
+ public static final int FILTER_VIDEO_ONLY = 2;
+ public static final int FILTER_ALL = 4;
+
+ // These are indices of the return values of getAppliedFilters().
+ // The _F suffix means "fixed".
+ private static final int CLUSTER_TYPE = 0;
+ private static final int FILTER_TYPE = 1;
+ private static final int CLUSTER_TYPE_F = 2;
+ private static final int FILTER_TYPE_F = 3;
+ private static final int CLUSTER_CURRENT_TYPE = 4;
+ private static final int FILTER_CURRENT_TYPE = 5;
+
+ public static void setupMenuItems(GalleryActionBar actionBar, Path path, boolean inAlbum) {
+ int[] result = new int[6];
+ getAppliedFilters(path, result);
+ int ctype = result[CLUSTER_TYPE];
+ int ftype = result[FILTER_TYPE];
+ int ftypef = result[FILTER_TYPE_F];
+ int ccurrent = result[CLUSTER_CURRENT_TYPE];
+ int fcurrent = result[FILTER_CURRENT_TYPE];
+
+ setMenuItemApplied(actionBar, CLUSTER_BY_TIME,
+ (ctype & CLUSTER_BY_TIME) != 0, (ccurrent & CLUSTER_BY_TIME) != 0);
+ setMenuItemApplied(actionBar, CLUSTER_BY_LOCATION,
+ (ctype & CLUSTER_BY_LOCATION) != 0, (ccurrent & CLUSTER_BY_LOCATION) != 0);
+ setMenuItemApplied(actionBar, CLUSTER_BY_TAG,
+ (ctype & CLUSTER_BY_TAG) != 0, (ccurrent & CLUSTER_BY_TAG) != 0);
+ setMenuItemApplied(actionBar, CLUSTER_BY_FACE,
+ (ctype & CLUSTER_BY_FACE) != 0, (ccurrent & CLUSTER_BY_FACE) != 0);
+
+ actionBar.setClusterItemVisibility(CLUSTER_BY_ALBUM, !inAlbum || ctype == 0);
+
+ setMenuItemApplied(actionBar, R.id.action_cluster_album, ctype == 0,
+ ccurrent == 0);
+
+ // A filtering is available if it's not applied, and the old filtering
+ // (if any) is not fixed.
+ setMenuItemAppliedEnabled(actionBar, R.string.show_images_only,
+ (ftype & FILTER_IMAGE_ONLY) != 0,
+ (ftype & FILTER_IMAGE_ONLY) == 0 && ftypef == 0,
+ (fcurrent & FILTER_IMAGE_ONLY) != 0);
+ setMenuItemAppliedEnabled(actionBar, R.string.show_videos_only,
+ (ftype & FILTER_VIDEO_ONLY) != 0,
+ (ftype & FILTER_VIDEO_ONLY) == 0 && ftypef == 0,
+ (fcurrent & FILTER_VIDEO_ONLY) != 0);
+ setMenuItemAppliedEnabled(actionBar, R.string.show_all,
+ ftype == 0, ftype != 0 && ftypef == 0, fcurrent == 0);
+ }
+
+ // Gets the filters applied in the path.
+ private static void getAppliedFilters(Path path, int[] result) {
+ getAppliedFilters(path, result, false);
+ }
+
+ private static void getAppliedFilters(Path path, int[] result, boolean underCluster) {
+ String[] segments = path.split();
+ // Recurse into sub media sets.
+ for (int i = 0; i < segments.length; i++) {
+ if (segments[i].startsWith("{")) {
+ String[] sets = Path.splitSequence(segments[i]);
+ for (int j = 0; j < sets.length; j++) {
+ Path sub = Path.fromString(sets[j]);
+ getAppliedFilters(sub, result, underCluster);
+ }
+ }
+ }
+
+ // update current selection
+ if (segments[0].equals("cluster")) {
+ // if this is a clustered album, set underCluster to true.
+ if (segments.length == 4) {
+ underCluster = true;
+ }
+
+ int ctype = toClusterType(segments[2]);
+ result[CLUSTER_TYPE] |= ctype;
+ result[CLUSTER_CURRENT_TYPE] = ctype;
+ if (underCluster) {
+ result[CLUSTER_TYPE_F] |= ctype;
+ }
+ }
+ }
+
+ private static int toClusterType(String s) {
+ if (s.equals("time")) {
+ return CLUSTER_BY_TIME;
+ } else if (s.equals("location")) {
+ return CLUSTER_BY_LOCATION;
+ } else if (s.equals("tag")) {
+ return CLUSTER_BY_TAG;
+ } else if (s.equals("size")) {
+ return CLUSTER_BY_SIZE;
+ } else if (s.equals("face")) {
+ return CLUSTER_BY_FACE;
+ }
+ return 0;
+ }
+
+ private static void setMenuItemApplied(
+ GalleryActionBar model, int id, boolean applied, boolean updateTitle) {
+ model.setClusterItemEnabled(id, !applied);
+ }
+
+ private static void setMenuItemAppliedEnabled(GalleryActionBar model, int id, boolean applied, boolean enabled, boolean updateTitle) {
+ model.setClusterItemEnabled(id, enabled);
+ }
+
+ // Add a specified filter to the path.
+ public static String newFilterPath(String base, int filterType) {
+ int mediaType;
+ switch (filterType) {
+ case FILTER_IMAGE_ONLY:
+ mediaType = MediaObject.MEDIA_TYPE_IMAGE;
+ break;
+ case FILTER_VIDEO_ONLY:
+ mediaType = MediaObject.MEDIA_TYPE_VIDEO;
+ break;
+ default: /* FILTER_ALL */
+ return base;
+ }
+
+ return "/filter/mediatype/" + mediaType + "/{" + base + "}";
+ }
+
+ // Add a specified clustering to the path.
+ public static String newClusterPath(String base, int clusterType) {
+ String kind;
+ switch (clusterType) {
+ case CLUSTER_BY_TIME:
+ kind = "time";
+ break;
+ case CLUSTER_BY_LOCATION:
+ kind = "location";
+ break;
+ case CLUSTER_BY_TAG:
+ kind = "tag";
+ break;
+ case CLUSTER_BY_SIZE:
+ kind = "size";
+ break;
+ case CLUSTER_BY_FACE:
+ kind = "face";
+ break;
+ default: /* CLUSTER_BY_ALBUM */
+ return base;
+ }
+
+ return "/cluster/{" + base + "}/" + kind;
+ }
+
+ // Change the topmost clustering to the specified type.
+ public static String switchClusterPath(String base, int clusterType) {
+ return newClusterPath(removeOneClusterFromPath(base), clusterType);
+ }
+
+ // Remove the topmost clustering (if any) from the path.
+ private static String removeOneClusterFromPath(String base) {
+ boolean[] done = new boolean[1];
+ return removeOneClusterFromPath(base, done);
+ }
+
+ private static String removeOneClusterFromPath(String base, boolean[] done) {
+ if (done[0]) return base;
+
+ String[] segments = Path.split(base);
+ if (segments[0].equals("cluster")) {
+ done[0] = true;
+ return Path.splitSequence(segments[1])[0];
+ }
+
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < segments.length; i++) {
+ sb.append("/");
+ if (segments[i].startsWith("{")) {
+ sb.append("{");
+ String[] sets = Path.splitSequence(segments[i]);
+ for (int j = 0; j < sets.length; j++) {
+ if (j > 0) {
+ sb.append(",");
+ }
+ sb.append(removeOneClusterFromPath(sets[j], done));
+ }
+ sb.append("}");
+ } else {
+ sb.append(segments[i]);
+ }
+ }
+ return sb.toString();
+ }
+}