1 /* 2 * aTunes 3 * Copyright (C) Alex Aranda, Sylvain Gaudard and contributors 4 * 5 * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors 6 * 7 * http://www.atunes.org 8 * http://sourceforge.net/projects/atunes 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 package net.sourceforge.atunes.kernel.modules.navigator; 22 23 import java.util.ArrayList; 24 import java.util.List; 25 import java.util.Map; 26 27 import net.sourceforge.atunes.model.IAudioObject; 28 import net.sourceforge.atunes.model.IFolder; 29 import net.sourceforge.atunes.model.ILocalAudioObject; 30 import net.sourceforge.atunes.model.INavigationTree; 31 import net.sourceforge.atunes.model.INavigationView; 32 import net.sourceforge.atunes.model.INavigationViewSorter; 33 import net.sourceforge.atunes.model.IOSManager; 34 import net.sourceforge.atunes.model.ITreeGenerator; 35 import net.sourceforge.atunes.model.ITreeNode; 36 import net.sourceforge.atunes.model.ITreeObject; 37 import net.sourceforge.atunes.utils.I18nUtils; 38 39 /** 40 * Builds a Folder ViewMode for a view. Several views can use this code 41 * (Repository and Device) 42 * 43 * @author fleax 44 * 45 */ 46 public class FolderTreeGenerator implements ITreeGenerator { 47 48 private INavigationViewSorter folderSorter; 49 50 private IOSManager osManager; 51 52 /** 53 * @param osManager 54 */ setOsManager(final IOSManager osManager)55 public void setOsManager(final IOSManager osManager) { 56 this.osManager = osManager; 57 } 58 59 /** 60 * @param folderSorter 61 */ setFolderSorter(final INavigationViewSorter folderSorter)62 public void setFolderSorter(final INavigationViewSorter folderSorter) { 63 this.folderSorter = folderSorter; 64 } 65 66 @SuppressWarnings("unchecked") 67 @Override buildTree(final INavigationTree tree, final String rootTextKey, final INavigationView view, final Map<String, ?> structure, final String currentFilter, final List<ITreeObject<? extends IAudioObject>> objectsSelected, final List<ITreeObject<? extends IAudioObject>> objectsExpanded)68 public void buildTree(final INavigationTree tree, final String rootTextKey, 69 final INavigationView view, final Map<String, ?> structure, 70 final String currentFilter, 71 final List<ITreeObject<? extends IAudioObject>> objectsSelected, 72 final List<ITreeObject<? extends IAudioObject>> objectsExpanded) { 73 // Refresh nodes 74 tree.setRoot(new NavigationTreeRoot(I18nUtils.getString(rootTextKey), 75 view.getIcon())); 76 77 addFolderNodes(tree, structure, currentFilter, this.folderSorter); 78 79 tree.reload(); 80 81 if (objectsExpanded.isEmpty()) { 82 // In folder view root child nodes must be expanded always 83 // So when refreshing folder view for first time add these nodes to 84 // list of expanded objects 85 List<?> rootChilds = tree.getRootChilds(); 86 for (Object rootChild : rootChilds) { 87 objectsExpanded 88 .add((ITreeObject<? extends IAudioObject>) rootChild); 89 } 90 } 91 92 // Get nodes to select after refresh 93 List<ITreeNode> nodesToSelect = tree.getNodes(objectsSelected); 94 95 // Get nodes to expand after refresh 96 List<ITreeNode> nodesToExpand = tree.getNodes(objectsExpanded); 97 98 // Expand nodes 99 tree.expandNodes(nodesToExpand); 100 101 // Once tree has been refreshed, select previously selected nodes 102 tree.selectNodes(nodesToSelect); 103 } 104 105 @Override selectAudioObject(final INavigationTree tree, final IAudioObject audioObject)106 public void selectAudioObject(final INavigationTree tree, 107 final IAudioObject audioObject) { 108 if (audioObject instanceof ILocalAudioObject) { 109 String filePath = audioObject.getUrl(); 110 ITreeNode folderNode = new FolderAudioObjectSelector() 111 .getNodeRepresentingAudioObject(tree, filePath); 112 if (folderNode != null) { 113 IFolder f = (IFolder) folderNode.getUserObject(); 114 String searchPath = filePath 115 .substring(f.getName().length() + 1); 116 String[] paths = searchPath.split(this.osManager 117 .getFileSeparator()); 118 ITreeNode node = getTreeNodeForLevel(paths, 0, tree, folderNode); 119 if (node != null) { 120 tree.selectNode(node); 121 tree.scrollToNode(node); 122 tree.expandNode(node); 123 } 124 } 125 } 126 } 127 getTreeNodeForLevel(final String[] paths, final int currentLevel, final INavigationTree tree, final ITreeNode foldersRootNode)128 private ITreeNode getTreeNodeForLevel(final String[] paths, 129 final int currentLevel, final INavigationTree tree, 130 final ITreeNode foldersRootNode) { 131 ITreeNode folderNode = new FolderAudioObjectSelector() 132 .getNodeRepresentingAudioObject(tree, foldersRootNode, 133 paths[currentLevel]); 134 if (folderNode != null) { 135 if (currentLevel == paths.length - 2) { 136 return folderNode; 137 } else { 138 return getTreeNodeForLevel(paths, currentLevel + 1, tree, 139 folderNode); 140 } 141 } 142 return null; 143 } 144 145 @Override selectArtist(final INavigationTree tree, final String artist)146 public void selectArtist(final INavigationTree tree, final String artist) { 147 } 148 149 /** 150 * Adds the folder nodes to root node 151 * 152 * @param folders 153 * the folders 154 * @param currentFilter 155 * the current filter 156 * @param sorter 157 * the comparator for node sorting 158 */ addFolderNodes(final INavigationTree tree, final Map<String, ?> folders, final String currentFilter, final INavigationViewSorter sorter)159 private void addFolderNodes(final INavigationTree tree, 160 final Map<String, ?> folders, final String currentFilter, 161 final INavigationViewSorter sorter) { 162 List<String> folderNamesList = new ArrayList<String>(folders.keySet()); 163 sorter.sort(folderNamesList); 164 for (int i = 0; i < folderNamesList.size(); i++) { 165 IFolder f = (IFolder) folders.get(folderNamesList.get(i)); 166 ITreeNode child = tree.createNode(f); 167 tree.addNode(child); 168 addFolderNodes(tree, f.getFolders(), child, currentFilter, sorter); 169 } 170 } 171 172 /** 173 * Adds the folder nodes. 174 * 175 * @param folders 176 * the folders 177 * @param node 178 * the node 179 * @param currentFilter 180 * the current filter 181 * @param sorter 182 * the comparator for node sorting 183 */ addFolderNodes(final INavigationTree tree, final Map<String, ?> folders, final ITreeNode node, final String currentFilter, final INavigationViewSorter sorter)184 private void addFolderNodes(final INavigationTree tree, 185 final Map<String, ?> folders, final ITreeNode node, 186 final String currentFilter, final INavigationViewSorter sorter) { 187 List<String> folderNamesList = new ArrayList<String>(folders.keySet()); 188 sorter.sort(folderNamesList); 189 for (int i = 0; i < folderNamesList.size(); i++) { 190 IFolder f = (IFolder) folders.get(folderNamesList.get(i)); 191 if (folderMatchesFilter(currentFilter, f)) { 192 ITreeNode child = tree.createNode(f); 193 node.add(child); 194 addFolderNodes(tree, f.getFolders(), child, currentFilter, 195 sorter); 196 } 197 } 198 } 199 folderMatchesFilter(final String currentFilter, final IFolder f)200 private boolean folderMatchesFilter(final String currentFilter, 201 final IFolder f) { 202 return currentFilter == null 203 || folderOrSubfoldersMatchFilter(currentFilter, f); 204 } 205 folderOrSubfoldersMatchFilter(final String currentFilter, final IFolder f)206 private boolean folderOrSubfoldersMatchFilter(final String currentFilter, 207 final IFolder f) { 208 if (folderMatches(currentFilter, f)) { 209 return true; 210 } else if (!f.isLeaf()) { 211 for (IFolder childFolder : f.getFolders().values()) { 212 if (folderOrSubfoldersMatchFilter(currentFilter, childFolder)) { 213 return true; 214 } 215 } 216 } 217 return false; 218 } 219 220 /** 221 * @param currentFilter 222 * @param f 223 * @return 224 */ folderMatches(final String currentFilter, final IFolder f)225 private boolean folderMatches(final String currentFilter, final IFolder f) { 226 return f.getName().toUpperCase().contains(currentFilter.toUpperCase()); 227 } 228 } 229