Java tutorial
/* * aTunes 1.14.0 * Copyright (C) 2006-2009 Alex Aranda, Sylvain Gaudard, Thomas Beckers and contributors * * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors * * http://www.atunes.org * http://sourceforge.net/projects/atunes * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package net.sourceforge.atunes.kernel.modules.repository; import java.io.File; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import java.util.concurrent.ExecutionException; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import net.sourceforge.atunes.gui.views.dialogs.MultiFolderSelectionDialog; import net.sourceforge.atunes.gui.views.dialogs.ReviewImportDialog; import net.sourceforge.atunes.gui.views.dialogs.SelectorDialog; import net.sourceforge.atunes.kernel.ControllerProxy; import net.sourceforge.atunes.kernel.Handler; import net.sourceforge.atunes.kernel.modules.device.DeviceHandler; import net.sourceforge.atunes.kernel.modules.process.ProcessListener; import net.sourceforge.atunes.kernel.modules.repository.audio.AudioFile; import net.sourceforge.atunes.kernel.modules.repository.model.Album; import net.sourceforge.atunes.kernel.modules.repository.model.Artist; import net.sourceforge.atunes.kernel.modules.repository.model.Folder; import net.sourceforge.atunes.kernel.modules.repository.model.Genre; import net.sourceforge.atunes.kernel.modules.search.SearchHandler; import net.sourceforge.atunes.kernel.modules.search.searchableobjects.RepositorySearchableObject; import net.sourceforge.atunes.kernel.modules.state.ApplicationState; import net.sourceforge.atunes.kernel.modules.state.ApplicationStateHandler; import net.sourceforge.atunes.kernel.modules.visual.VisualHandler; import net.sourceforge.atunes.misc.RankList; import net.sourceforge.atunes.misc.SystemProperties; import net.sourceforge.atunes.misc.log.LogCategories; import net.sourceforge.atunes.model.AudioObject; import net.sourceforge.atunes.utils.DateUtils; import net.sourceforge.atunes.utils.FileNameUtils; import net.sourceforge.atunes.utils.LanguageTool; import net.sourceforge.atunes.utils.StringUtils; import net.sourceforge.atunes.utils.TimeUtils; import org.apache.commons.io.FilenameUtils; /** * The repository handler */ public final class RepositoryHandler extends Handler implements LoaderListener, AudioFilesRemovedListener { public enum SortType { /** by track sort order */ BY_TRACK_NUMBER, /** by artist sort order */ BY_ARTIST_AND_ALBUM, /** by title sort order */ BY_TITLE, /** by file name sort order */ BY_FILE, /** by modification date sort order */ BY_MODIFICATION_TIME } private static RepositoryHandler instance = new RepositoryHandler(); Repository repository; private Repository tempRepository; private int filesLoaded; private RepositoryLoader currentLoader; RepositoryAutoRefresher repositoryRefresher; Repository repositoryRetrievedFromCache = null; /** Listeners notified when an audio file is removed */ private List<AudioFilesRemovedListener> audioFilesRemovedListeners = new ArrayList<AudioFilesRemovedListener>(); /** * Instantiates a new repository handler. */ private RepositoryHandler() { } @Override public void applicationStateChanged(ApplicationState newState) { } @Override protected void initHandler() { // Add itself as listener addAudioFilesRemovedListener(this); } @Override public void applicationStarted() { SearchHandler.getInstance().registerSearchableObject(RepositorySearchableObject.getInstance()); RepositoryHandler.this.repositoryRefresher = new RepositoryAutoRefresher(RepositoryHandler.this); } /** * Gets the single instance of RepositoryHandler. * * @return single instance of RepositoryHandler */ public static RepositoryHandler getInstance() { return instance; } /** * Adds the given files to repository and refresh. * * @param files * the files */ public void addFilesAndRefresh(final List<File> files) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { VisualHandler.getInstance().showProgressBar(true, StringUtils.getString(LanguageTool.getString("REFRESHING"), "...")); } }); SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { @Override protected Void doInBackground() throws Exception { RepositoryLoader.addToRepository(repository, files); return null; } @Override protected void done() { super.done(); // Persist ApplicationStateHandler.getInstance().persistRepositoryCache(repository, false); VisualHandler.getInstance().showProgressBar(false, null); VisualHandler.getInstance().showRepositoryAudioFileNumber(getAudioFiles().size(), getRepositoryTotalSize(), repository.getTotalDurationInSeconds()); if (ControllerProxy.getInstance().getNavigationController() != null) { ControllerProxy.getInstance().getNavigationController().notifyReload(); } getLogger().info(LogCategories.REPOSITORY, "Repository refresh done"); } }; worker.execute(); } /** * Adds the external picture for album. * * @param artistName * the artist name * @param albumName * the album name * @param picture * the picture */ public void addExternalPictureForAlbum(String artistName, String albumName, File picture) { if (repository != null) { Artist artist = repository.getStructure().getTreeStructure().get(artistName); if (artist == null) { return; } Album album = artist.getAlbum(albumName); if (album == null) { return; } List<AudioFile> audioFiles = album.getAudioFiles(); for (AudioFile af : audioFiles) { af.addExternalPicture(picture); } } } /** * Permanently deletes an audio file from the repository metainformation * * @param file * File to be removed permanently */ private void deleteFile(AudioFile file) { String albumArtist = file.getAlbumArtist(); String artist = file.getArtist(); String album = file.getAlbum(); String genre = file.getGenre(); // Only do this if file is in repository if (getFolderForFile(file) != null) { // Remove from file structure Folder f = getFolderForFile(file); if (f != null) { f.removeFile(file); // If folder is empty, remove too if (f.isEmpty()) { f.getParentFolder().removeFolder(f); } } // Remove from tree structure Artist a = repository.getStructure().getTreeStructure().get(albumArtist); if (a == null) { a = repository.getStructure().getTreeStructure().get(artist); } if (a != null) { Album alb = a.getAlbum(album); if (alb != null) { if (alb.getAudioObjects().size() == 1) { a.removeAlbum(alb); } else { alb.removeAudioFile(file); } if (a.getAudioObjects().size() <= 1) { repository.getStructure().getTreeStructure().remove(a.getName()); } } } // Remove from genre structure Genre g = repository.getStructure().getGenreStructure().get(genre); if (g != null) { Artist art = g.getArtist(artist); if (art != null) { Album alb = art.getAlbum(album); if (alb != null) { if (alb.getAudioObjects().size() == 1) { art.removeAlbum(alb); } else { alb.removeAudioFile(file); } } if (art.getAudioObjects().size() <= 1) { g.removeArtist(art); } } if (g.getAudioObjects().size() <= 1) { repository.getStructure().getGenreStructure().remove(genre); } } // Remove from file list repository.getAudioFiles().remove(file.getUrl()); // Update repository size repository.setTotalSizeInBytes(repository.getTotalSizeInBytes() - file.getFile().length()); // Update repository duration repository.removeDurationInSeconds(file.getDuration()); } // File is on a device else if (DeviceHandler.getInstance().isDevicePath(file.getUrl())) { getLogger().info(LogCategories.REPOSITORY, StringUtils.getString("Deleted file ", file, " from device")); } } /** * Finish. */ public void applicationFinish() { if (repositoryRefresher != null) { repositoryRefresher.interrupt(); } ApplicationStateHandler.getInstance().persistRepositoryCache(repository, true); // Execute command after last access to repository String command = ApplicationState.getInstance().getCommandAfterAccessRepository(); if (command != null && !command.trim().equals("")) { try { Process p = Runtime.getRuntime().exec(command); // Wait process to end p.waitFor(); int rc = p.exitValue(); getLogger().info(LogCategories.END, StringUtils.getString("Command '", command, "' return code: ", rc)); } catch (Exception e) { getLogger().error(LogCategories.END, e); } } } /** * Gets the album most played. * * @return the album most played */ public Map<String, Integer> getAlbumMostPlayed() { Map<String, Integer> result = new HashMap<String, Integer>(); if (repository != null && repository.getStats().getAlbumsRanking().size() > 0) { String firstAlbum = repository.getStats().getAlbumsRanking().getNFirstElements(1).get(0).toString(); Integer count = repository.getStats().getAlbumsRanking().getNFirstElementCounts(1).get(0); result.put(firstAlbum, count); } else { result.put(null, 0); } return result; } /** * Gets the albums. * * @return the albums */ public List<Album> getAlbums() { List<Album> result = new ArrayList<Album>(); if (repository != null) { Collection<Artist> artists = repository.getStructure().getTreeStructure().values(); for (Artist a : artists) { result.addAll(a.getAlbums().values()); } Collections.sort(result); } return result; } /** * Gets the album times played. * * @param audioFile * the audio file * * @return the album times played */ public Integer getAlbumTimesPlayed(AudioFile audioFile) { if (audioFile != null) { if (repository != null) { Album a = repository.getStructure().getTreeStructure().get(audioFile.getArtist()) .getAlbum(audioFile.getAlbum()); if (repository.getStats().getAlbumsRanking().getCount(a) != null) { return repository.getStats().getAlbumsRanking().getCount(a); } } return 0; } return null; } /** * Gets the artist and album structure. * * @return the artist and album structure */ public Map<String, Artist> getArtistStructure() { if (repository != null) { return repository.getStructure().getTreeStructure(); } return new HashMap<String, Artist>(); } /** * Gets the artist most played. * * @return the artist most played */ public Map<String, Integer> getArtistMostPlayed() { Map<String, Integer> result = new HashMap<String, Integer>(); if (repository != null && repository.getStats().getArtistsRanking().size() > 0) { String firstArtist = repository.getStats().getArtistsRanking().getNFirstElements(1).get(0).toString(); Integer count = repository.getStats().getArtistsRanking().getNFirstElementCounts(1).get(0); result.put(firstArtist, count); } else { result.put(null, 0); } return result; } /** * Gets the artists. * * @return the artists */ public List<Artist> getArtists() { List<Artist> result = new ArrayList<Artist>(); if (repository != null) { result.addAll(repository.getStructure().getTreeStructure().values()); Collections.sort(result); } return result; } /** * Gets the artist times played. * * @param audioFile * the audio file * * @return the artist times played */ public Integer getArtistTimesPlayed(Artist artist) { if (repository != null) { if (repository.getStats().getArtistsRanking().getCount(artist) != null) { return repository.getStats().getArtistsRanking().getCount(artist); } } return 0; } /** * Gets the different audio files played. * * @return the different audio files played */ public int getDifferentAudioFilesPlayed() { if (repository != null) { return repository.getStats().getDifferentAudioFilesPlayed(); } return 0; } /** * Gets the file if loaded. * * @param fileName * the file name * * @return the file if loaded */ public AudioFile getFileIfLoaded(String fileName) { return repository == null ? null : repository.getFile(fileName); } /** * Finds folder that contains file. * * @param file * Audio file for which the folder is wanted * * @return Either folder or null if file is not in repository */ private Folder getFolderForFile(AudioFile file) { // Get repository folder where file is File repositoryFolder = getRepositoryFolderContainingFile(file); // If the file is not in the repository, return null if (repositoryFolder == null) { return null; } // Get root folder Folder rootFolder = repository.getStructure().getFolderStructure().get(repositoryFolder.getAbsolutePath()); // Now navigate through folder until find folder that contains file String path = file.getFile().getParentFile().getAbsolutePath(); path = path.replace(repositoryFolder.getAbsolutePath(), ""); Folder f = rootFolder; StringTokenizer st = new StringTokenizer(path, SystemProperties.FILE_SEPARATOR); while (st.hasMoreTokens()) { String folderName = st.nextToken(); f = f.getFolder(folderName); } return f; } /** * Gets the folder structure. * * @return the folder structure */ public Map<String, Folder> getFolderStructure() { if (repository != null) { return repository.getStructure().getFolderStructure(); } return new HashMap<String, Folder>(); } /** * Gets the genre structure. * * @return the genre structure */ public Map<String, Genre> getGenreStructure() { if (repository != null) { return repository.getStructure().getGenreStructure(); } return new HashMap<String, Genre>(); } /** * Gets the album structure * * @return */ public Map<String, Album> getAlbumStructure() { if (repository != null) { Map<String, Album> albumsStructure = new HashMap<String, Album>(); Collection<Artist> artistCollection = repository.getStructure().getTreeStructure().values(); for (Artist artist : artistCollection) { for (Album album : artist.getAlbums().values()) { albumsStructure.put(album.getNameAndArtist(), album); } } return albumsStructure; } return new HashMap<String, Album>(); } /** * Gets the most played albums. * * @param n * the n * * @return the most played albums */ public List<Album> getMostPlayedAlbums(int n) { if (repository != null) { List<Album> albums = repository.getStats().getAlbumsRanking().getNFirstElements(n); if (albums != null) { return albums; } } return null; } /** * Gets the most played albums in ranking. * * @param n * the n * * @return the most played albums in ranking */ public List<Object[]> getMostPlayedAlbumsInRanking(int n) { if (repository != null) { List<Object[]> result = new ArrayList<Object[]>(); List<Album> albums = repository.getStats().getAlbumsRanking().getNFirstElements(n); List<Integer> count = repository.getStats().getAlbumsRanking().getNFirstElementCounts(n); if (albums != null) { for (int i = 0; i < albums.size(); i++) { Object[] obj = new Object[2]; obj[0] = albums.get(i).toString(); obj[1] = count.get(i); result.add(obj); } } return result; } return null; } /** * Gets the most played artists. * * @param n * the n * * @return the most played artists */ public List<Artist> getMostPlayedArtists(int n) { if (repository != null) { List<Artist> artists = repository.getStats().getArtistsRanking().getNFirstElements(n); if (artists != null) { return artists; } } return null; } /** * Gets the most played artists in ranking. * * @param n * the n * * @return the most played artists in ranking */ public List<Object[]> getMostPlayedArtistsInRanking(int n) { if (repository != null) { List<Object[]> result = new ArrayList<Object[]>(); List<Artist> artists = repository.getStats().getArtistsRanking().getNFirstElements(n); List<Integer> count = repository.getStats().getArtistsRanking().getNFirstElementCounts(n); if (artists != null) { for (int i = 0; i < artists.size(); i++) { Object[] obj = new Object[2]; obj[0] = artists.get(i).toString(); obj[1] = count.get(i); result.add(obj); } } return result; } return null; } /** * Gets the most played audio files. * * @param n * the n * * @return the most played audio files */ public List<AudioFile> getMostPlayedAudioFiles(int n) { if (repository != null) { List<AudioFile> audioFiles = repository.getStats().getAudioFilesRanking().getNFirstElements(n); if (audioFiles != null) { return audioFiles; } } return null; } /** * Gets the most played audio files in ranking. * * @param n * the n * * @return the most played audio files in ranking */ public List<Object[]> getMostPlayedAudioFilesInRanking(int n) { if (repository != null) { List<Object[]> result = new ArrayList<Object[]>(); List<AudioFile> audioFiles = repository.getStats().getAudioFilesRanking().getNFirstElements(n); List<Integer> count = repository.getStats().getAudioFilesRanking().getNFirstElementCounts(n); if (audioFiles != null) { for (int i = 0; i < audioFiles.size(); i++) { Object[] obj = new Object[2]; AudioFile audioFile = audioFiles.get(i); obj[0] = StringUtils.getString(audioFile.getTitleOrFileName(), " (", audioFile.getArtist(), ")"); obj[1] = count.get(i); result.add(obj); } } return result; } return null; } /** * Gets the path for new audio files ripped. * * @return the path for new audio files ripped */ public String getPathForNewAudioFilesRipped() { return StringUtils.getString(RepositoryHandler.getInstance().getRepositoryPath(), SystemProperties.FILE_SEPARATOR, Album.getUnknownAlbum(), " - ", DateUtils.toPathString(new Date())); } /** * Gets the repository. * * @return the repository */ public Repository getRepository() { return repository; } /** * Returns repository root folder that contains file. * * @param file * the file * * @return the repository folder containing file */ public File getRepositoryFolderContainingFile(AudioFile file) { if (repository == null) { return null; } for (File folder : repository.getFolders()) { if (file.getUrl().startsWith(folder.getAbsolutePath())) { return folder; } } return null; } /** * Gets the repository path. * * @return the repository path */ public String getRepositoryPath() { return repository != null ? repository.getFolders().get(0).getAbsolutePath() : ""; } /** * Gets the repository total size. * * @return the repository total size */ public long getRepositoryTotalSize() { return repository != null ? repository.getTotalSizeInBytes() : 0; } /** * Gets the audio file most played. * * @return the audio file most played */ public Map<AudioFile, Integer> getAudioFileMostPlayed() { Map<AudioFile, Integer> result = new HashMap<AudioFile, Integer>(); if (repository != null && repository.getStats().getAudioFilesRanking().size() > 0) { AudioFile firstAudioFile = repository.getStats().getAudioFilesRanking().getNFirstElements(1).get(0); Integer count = repository.getStats().getAudioFilesRanking().getNFirstElementCounts(1).get(0); result.put(firstAudioFile, count); } else { result.put(null, 0); } return result; } /** * Gets the audio files. * * @return the audio files */ public List<AudioFile> getAudioFiles() { if (repository != null) { return repository.getAudioFilesList(); } return new ArrayList<AudioFile>(); } /** * Gets the audio files for albums. * * @param albums * the albums * * @return the audio files for albums */ public List<AudioFile> getAudioFilesForAlbums(Map<String, Album> albums) { List<AudioFile> result = new ArrayList<AudioFile>(); for (Map.Entry<String, Album> entry : albums.entrySet()) { result.addAll(entry.getValue().getAudioFiles()); } return result; } /** * Gets the auio files for artists. * * @param artists * the artists * * @return the audio files for artists */ public List<AudioFile> getAudioFilesForArtists(Map<String, Artist> artists) { List<AudioFile> result = new ArrayList<AudioFile>(); for (Map.Entry<String, Artist> entry : artists.entrySet()) { result.addAll(entry.getValue().getAudioFiles()); } return result; } /** * Gets the audio files played. * * @return the audio files played */ public String getAudioFilesPlayed() { if (repository != null) { int totalPlays = repository.getStats().getDifferentAudioFilesPlayed(); int total = repository.countFiles(); float perCent = (float) totalPlays / (float) total * 100; return StringUtils.getString(totalPlays, " / ", total, " (", StringUtils.toString(perCent, 2), "%)"); } return "0 / 0 (0%)"; } /** * Gets the audio file statistics. * * @param audioFile * the audio file * * @return the audio file statistics */ public AudioFileStats getAudioFileStatistics(AudioFile audioFile) { if (repository != null) { return repository.getStats().getStatsForAudioFile(audioFile); } return null; } /** * Gets the total audio files played. * * @return the total audio files played */ public int getTotalAudioFilesPlayed() { return repository != null ? repository.getStats().getTotalPlays() : -1; } /** * Gets the unplayed audio files. * * @return the unplayed audio files */ public List<AudioFile> getUnplayedAudioFiles() { if (repository != null) { List<AudioFile> unplayedAudioFiles = repository.getAudioFilesList(); unplayedAudioFiles.removeAll(repository.getStats().getAudioFilesRanking().getNFirstElements(-1)); return unplayedAudioFiles; } return new ArrayList<AudioFile>(); } /** * Returns true if folder is in repository. * * @param folder * the folder * * @return true, if checks if is repository */ public boolean isRepository(File folder) { if (repository == null) { return false; } String path = folder.getAbsolutePath(); for (File folders : repository.getFolders()) { if (path.startsWith(folders.getAbsolutePath())) { return true; } } return false; } /** * Notify cancel. */ public void notifyCancel() { currentLoader.interruptLoad(); VisualHandler.getInstance().getProgressDialog().setVisible(false); VisualHandler.getInstance().getProgressDialog().deactivateGlassPane(); VisualHandler.getInstance().getProgressDialog().setCancelButtonVisible(false); VisualHandler.getInstance().getProgressDialog().setCancelButtonEnabled(true); } /* * (non-Javadoc) * * @seenet.sourceforge.atunes.kernel.modules.repository.LoaderListener# * notifyCurrentPath(java.lang.String) */ @Override public void notifyCurrentPath(final String dir) { VisualHandler.getInstance().getProgressDialog().getFolderLabel().setText(dir); } /* * (non-Javadoc) * * @seenet.sourceforge.atunes.kernel.modules.repository.LoaderListener# * notifyFileLoaded() */ @Override public void notifyFileLoaded() { this.filesLoaded++; VisualHandler.getInstance().getProgressDialog().getProgressLabel().setText(Integer.toString(filesLoaded)); VisualHandler.getInstance().getProgressDialog().getProgressBar().setValue(filesLoaded); } /* * (non-Javadoc) * * @seenet.sourceforge.atunes.kernel.modules.repository.LoaderListener# * notifyFilesInRepository(int) */ @Override public void notifyFilesInRepository(int totalFiles) { getLogger().debug(LogCategories.REPOSITORY, new String[] { Integer.toString(totalFiles) }); VisualHandler.getInstance().getProgressDialog().getProgressBar().setIndeterminate(false); VisualHandler.getInstance().getProgressDialog().getTotalFilesLabel() .setText(StringUtils.getString(totalFiles)); VisualHandler.getInstance().getProgressDialog().getProgressBar().setMaximum(totalFiles); } /* * (non-Javadoc) * * @seenet.sourceforge.atunes.kernel.modules.repository.LoaderListener# * notifyFinishRead * (net.sourceforge.atunes.kernel.modules.repository.RepositoryLoader) */ @Override public void notifyFinishRead(RepositoryLoader loader) { if (loader != null) { tempRepository = loader.getRepository(); } VisualHandler.getInstance().getProgressDialog().setCancelButtonEnabled(false); VisualHandler.getInstance().getProgressDialog().getLabel() .setText(LanguageTool.getString("STORING_REPOSITORY_INFORMATION")); VisualHandler.getInstance().getProgressDialog().getProgressLabel().setText(""); VisualHandler.getInstance().getProgressDialog().getTotalFilesLabel().setText(""); VisualHandler.getInstance().getProgressDialog().getFolderLabel().setText(" "); // Set new repository repository = tempRepository; // Save folders: if repository config is lost application can reload data without asking user to select folders again List<String> repositoryFolders = new ArrayList<String>(); for (File folder : repository.getFolders()) { repositoryFolders.add(folder.getAbsolutePath()); } ApplicationState.getInstance().setLastRepositoryFolders(repositoryFolders); VisualHandler.getInstance().getProgressDialog().setVisible(false); VisualHandler.getInstance().getProgressDialog().deactivateGlassPane(); VisualHandler.getInstance().getProgressDialog().setCancelButtonVisible(false); VisualHandler.getInstance().getProgressDialog().setCancelButtonEnabled(true); notifyFinishRepositoryRead(); } /* * (non-Javadoc) * * @seenet.sourceforge.atunes.kernel.modules.repository.LoaderListener# * notifyFinishRefresh * (net.sourceforge.atunes.kernel.modules.repository.RepositoryLoader) */ @Override public void notifyFinishRefresh(RepositoryLoader loader) { tempRepository = loader.getRepository(); // Save stats transferStatsFrom(tempRepository, repository); // Set new repository repository = tempRepository; // Persist ApplicationStateHandler.getInstance().persistRepositoryCache(repository, false); VisualHandler.getInstance().showProgressBar(false, null); VisualHandler.getInstance().showRepositoryAudioFileNumber(getAudioFiles().size(), getRepositoryTotalSize(), repository.getTotalDurationInSeconds()); if (ControllerProxy.getInstance().getNavigationController() != null) { ControllerProxy.getInstance().getNavigationController().notifyReload(); } getLogger().info(LogCategories.REPOSITORY, "Repository refresh done"); } /** * Notify finish repository read. */ private void notifyFinishRepositoryRead() { ControllerProxy.getInstance().getNavigationController().notifyReload(); VisualHandler.getInstance().showRepositoryAudioFileNumber(getAudioFiles().size(), getRepositoryTotalSize(), repository.getTotalDurationInSeconds()); } /* * (non-Javadoc) * * @seenet.sourceforge.atunes.kernel.modules.repository.LoaderListener# * notifyRemainingTime(long) */ @Override public void notifyRemainingTime(final long millis) { VisualHandler.getInstance().getProgressDialog().getRemainingTimeLabel().setText(StringUtils.getString( LanguageTool.getString("REMAINING_TIME"), ": ", TimeUtils.milliseconds2String(millis))); } @Override protected Runnable getPreviousInitializationTask() { return new Runnable() { @Override public void run() { // This is the first access to repository, so execute the command defined by user String command = ApplicationState.getInstance().getCommandBeforeAccessRepository(); if (command != null && !command.trim().equals("")) { try { Process p = Runtime.getRuntime().exec(command); // Wait process to end p.waitFor(); int rc = p.exitValue(); getLogger().info(LogCategories.START, StringUtils.getString("Command '", command, "' return code: ", rc)); } catch (Exception e) { getLogger().error(LogCategories.START, e); } } repositoryRetrievedFromCache = ApplicationStateHandler.getInstance().retrieveRepositoryCache(); } }; } /** * Sets the repository. */ public void setRepository() { // Try to read repository cache. If fails or not exists, should be selected again final Repository rep = repositoryRetrievedFromCache; if (rep != null) { if (!rep.exists()) { Object selection = null; // Test if repository exists and show message until repository exists or user doesn't press "RETRY" do { selection = VisualHandler.getInstance().showMessage( StringUtils.getString(LanguageTool.getString("REPOSITORY_NOT_FOUND"), ": ", rep.getFolders().get(0)), LanguageTool.getString("REPOSITORY_NOT_FOUND"), JOptionPane.WARNING_MESSAGE, new String[] { LanguageTool.getString("RETRY"), LanguageTool.getString("SELECT_REPOSITORY") }); } while (LanguageTool.getString("RETRY").equals(selection) && !rep.exists()); if (!rep.exists() && !selectRepository(true)) { // select "old" repository if repository was not found and no new repository was selected repository = rep; } else if (rep.exists()) { // repository exists tempRepository = rep; notifyFinishRead(null); } } else { // repository exists tempRepository = rep; notifyFinishRead(null); } } else { // If any repository was loaded previously, try to reload folders List<String> lastRepositoryFolders = ApplicationState.getInstance().getLastRepositoryFolders(); if (lastRepositoryFolders != null && !lastRepositoryFolders.isEmpty()) { List<File> foldersToRead = new ArrayList<File>(); for (String f : lastRepositoryFolders) { foldersToRead.add(new File(f)); } VisualHandler.getInstance().showMessage(LanguageTool.getString("RELOAD_REPOSITORY_MESSAGE")); retrieve(foldersToRead); return; } VisualHandler.getInstance().showRepositorySelectionInfoDialog(); selectRepository(); } } /** * Read repository. * * @param folders * the folders */ private void readRepository(List<File> folders) { VisualHandler.getInstance().getProgressDialog().setCancelButtonVisible(true); VisualHandler.getInstance().getProgressDialog().setCancelButtonEnabled(true); currentLoader = new RepositoryLoader(folders, false); currentLoader.setOldRepository(repository); currentLoader.addRepositoryLoaderListener(this); currentLoader.start(); } /** * Refresh. */ private void refresh() { getLogger().info(LogCategories.REPOSITORY, "Refreshing repository"); filesLoaded = 0; currentLoader = new RepositoryLoader(repository.getFolders(), true); currentLoader.addRepositoryLoaderListener(this); currentLoader.setOldRepository(repository); currentLoader.start(); } /** * Refresh file. * * @param file * the file */ public void refreshFile(AudioFile file) { RepositoryLoader.refreshFile(repository, file); } /** * Refresh repository. */ public void refreshRepository() { if (!repositoryIsNull()) { String text = StringUtils.getString(LanguageTool.getString("REFRESHING"), "..."); VisualHandler.getInstance().showProgressBar(true, text); refresh(); } } /** * Removes a list of folders from repository. * * @param foldersToRemove */ public void removeFolders(List<Folder> foldersToRemove) { for (Folder folder : foldersToRemove) { // Remove content remove(folder.getAudioFiles()); // Remove from model if (folder.getParentFolder() != null) { folder.getParentFolder().removeFolder(folder); } // Update navigator ControllerProxy.getInstance().getNavigationController().notifyReload(); } } /** * Removes a list of files from repository * * @param filesToRemove * Files that should be removed */ public void remove(List<AudioFile> filesToRemove) { if (filesToRemove == null || filesToRemove.isEmpty()) { return; } for (AudioFile fileToRemove : filesToRemove) { deleteFile(fileToRemove); } // Notify listeners for (AudioFilesRemovedListener listener : audioFilesRemovedListeners) { listener.audioFilesRemoved(filesToRemove); } } /** * Renames an audio file * * @param audioFile * the audio file that should be renamed * @param name * the new name of the audio file */ public void rename(AudioFile audioFile, String name) { File file = audioFile.getFile(); String extension = FilenameUtils.getExtension(file.getAbsolutePath()); File newFile = new File(StringUtils.getString(file.getParentFile().getAbsolutePath() + "/" + FileNameUtils.getValidFileName(name) + "." + extension)); boolean succeeded = file.renameTo(newFile); if (succeeded) { repository.getAudioFiles().remove(file.getAbsolutePath()); audioFile.setFile(newFile); repository.getAudioFiles().put(file.getAbsolutePath(), audioFile); ControllerProxy.getInstance().getNavigationController().notifyReload(); } } /** * Repository is null. * * @return true, if successful */ public boolean repositoryIsNull() { return repository == null; } /** * Retrieve. * * @param folders * the folders * * @return true, if successful */ public boolean retrieve(List<File> folders) { VisualHandler.getInstance().getProgressDialog().setTitle(LanguageTool.getString("PLEASE_WAIT")); VisualHandler.getInstance().getProgressDialog().setVisible(true); VisualHandler.getInstance().getProgressDialog().activateGlassPane(); filesLoaded = 0; try { if (folders == null || folders.isEmpty()) { repository = null; return false; } readRepository(folders); return true; } catch (Exception e) { repository = null; getLogger().error(LogCategories.REPOSITORY, e); return false; } } /** * Select repository. * * @return true, if successful */ public boolean selectRepository() { return selectRepository(false); } /** * Select repository. * * @param repositoryNotFound * the repository not found * * @return true, if successful */ public boolean selectRepository(boolean repositoryNotFound) { MultiFolderSelectionDialog dialog = VisualHandler.getInstance().getMultiFolderSelectionDialog(); dialog.setText(LanguageTool.getString("SELECT_REPOSITORY_FOLDERS")); dialog.startDialog((repository != null && !repositoryNotFound) ? repository.getFolders() : null); if (!dialog.isCancelled()) { List<File> folders = dialog.getSelectedFolders(); if (!folders.isEmpty()) { this.retrieve(folders); return true; } } return false; } /** * Sets the audio file statistics. * * @param audioFile * the new audio file statistics */ public void setAudioFileStatistics(AudioFile audioFile) { if (repository != null) { RepositoryLoader.fillStats(repository, audioFile); } } /** * Sort. * * @param audioObjects * the audio objects * * @return the list */ public List<AudioObject> sort(List<? extends AudioObject> audioObjects) { return sort(audioObjects, ApplicationState.getInstance().getSortType()); } /** * Sort. * * @param audioObjects * the audio objects * @param type * the type * * @return the list */ public List<AudioObject> sort(List<? extends AudioObject> audioObjects, SortType type) { AudioObject[] array = audioObjects.toArray(new AudioObject[audioObjects.size()]); if (type == SortType.BY_TRACK_NUMBER) { Arrays.sort(array, new Comparator<AudioObject>() { @Override public int compare(AudioObject a1, AudioObject a2) { return a1.getTrackNumber().compareTo(a2.getTrackNumber()); } }); } else if (type == SortType.BY_ARTIST_AND_ALBUM) { Arrays.sort(array, new Comparator<AudioObject>() { @Override public int compare(AudioObject a1, AudioObject a2) { // Sort by album artist int c1 = a1.getAlbumArtist().compareTo(a2.getAlbumArtist()); if (c1 != 0) { return c1; } /* * If album artist is "" in both audio objects (we just need * to check only one audio object since if execution reaches * this code both album artist fields are equal) then sort * by artist, album and track If album artist is not "", * then only sort by album and track */ if (a1.getAlbumArtist().isEmpty()) { int c2 = a1.getArtist().compareTo(a2.getArtist()); if (c2 != 0) { return c2; } } // Sort by album int c3 = a1.getAlbum().compareTo(a2.getAlbum()); if (c3 != 0) { return c3; } // Sort by disc number int c4 = a1.getDiscNumber().compareTo(a2.getDiscNumber()); if (c4 != 0) { return c4; } return a1.getTrackNumber().compareTo(a2.getTrackNumber()); } }); } else if (type == SortType.BY_TITLE) { Arrays.sort(array, new Comparator<AudioObject>() { @Override public int compare(AudioObject a0, AudioObject a1) { return a0.getTitleOrFileName().compareTo(a1.getTitleOrFileName()); } }); } else if (type == SortType.BY_MODIFICATION_TIME) { Arrays.sort(array, new Comparator<AudioObject>() { @Override public int compare(AudioObject o1, AudioObject o2) { if (o1 instanceof AudioFile && o2 instanceof AudioFile) { return Long.valueOf(((AudioFile) o1).getFile().lastModified()) .compareTo(Long.valueOf(((AudioFile) o2).getFile().lastModified())); } return 0; } }); } else { // Sort audio objects by file name // This call uses compareTo methods of every class Arrays.sort(array); } return Arrays.asList(array); } /** * Gets stats from a repository. * * @param oldRepository * the old repository * @param newRepository * the new repository */ public void transferStatsFrom(Repository newRepository, Repository oldRepository) { // Total plays newRepository.getStats().setTotalPlays(oldRepository.getStats().getTotalPlays()); // Different audio files played newRepository.getStats() .setDifferentAudioFilesPlayed(oldRepository.getStats().getDifferentAudioFilesPlayed()); // Audio file stats newRepository.getStats().setAudioFilesStats(oldRepository.getStats().getAudioFilesStats()); // Audio files ranking newRepository.getStats().setAudioFilesRanking(oldRepository.getStats().getAudioFilesRanking()); // Album ranking RankList<Album> albumsRanking = oldRepository.getStats().getAlbumsRanking(); List<Album> albums = albumsRanking.getOrder(); for (int i = 0; i < albums.size(); i++) { Album oldAlbum = albums.get(i); Artist artist = newRepository.getStructure().getTreeStructure().get(oldAlbum.getArtist()); if (artist != null) { Album newAlbum = artist.getAlbum(oldAlbum.getName()); if (newAlbum != null) { albumsRanking.replaceItem(oldAlbum, newAlbum); } } } newRepository.getStats().setAlbumsRanking(albumsRanking); // Artist Ranking RankList<Artist> artistsRanking = oldRepository.getStats().getArtistsRanking(); List<Artist> artists = artistsRanking.getOrder(); for (int i = 0; i < artists.size(); i++) { Artist oldArtist = artists.get(i); Artist newArtist = newRepository.getStructure().getTreeStructure().get(oldArtist.getName()); if (newArtist != null) { artistsRanking.replaceItem(oldArtist, newArtist); } } newRepository.getStats().setArtistsRanking(artistsRanking); } /** * Imports folders to repository */ public void importFoldersToRepository() { // First check if repository is selected. If not, display a message if (getRepository() == null) { VisualHandler.getInstance().showErrorDialog(LanguageTool.getString("SELECT_REPOSITORY_BEFORE_IMPORT")); return; } // Now show dialog to select folders MultiFolderSelectionDialog dialog = VisualHandler.getInstance().getMultiFolderSelectionDialog(); dialog.setTitle(LanguageTool.getString("IMPORT")); dialog.setText(LanguageTool.getString("SELECT_FOLDERS_TO_IMPORT")); dialog.startDialog(null); if (!dialog.isCancelled()) { List<File> folders = dialog.getSelectedFolders(); // If user selected folders... if (!folders.isEmpty()) { String path; // If repository folders are more than one then user must select where to import songs if (getRepository().getFolders().size() > 1) { String[] folderNames = new String[getRepository().getFolders().size()]; for (int i = 0; i < getRepository().getFolders().size(); i++) { folderNames[i] = getRepository().getFolders().get(i).getAbsolutePath(); } SelectorDialog selector = new SelectorDialog(VisualHandler.getInstance().getFrame().getFrame(), LanguageTool.getString("SELECT_REPOSITORY_FOLDER_TO_IMPORT"), folderNames, null); selector.setVisible(true); path = selector.getSelection(); // If user closed dialog then select first entry if (path == null) { path = getRepositoryPath(); } } else { path = getRepositoryPath(); } this.importFolders(folders, path); } } } /** * Imports folders passed as argument to repository * * @param folders * @param path */ private void importFolders(final List<File> folders, final String path) { SwingWorker<List<AudioFile>, Void> worker = new SwingWorker<List<AudioFile>, Void>() { @Override protected List<AudioFile> doInBackground() throws Exception { VisualHandler.getInstance().showIndeterminateProgressDialog( StringUtils.getString(LanguageTool.getString("READING_FILES_TO_IMPORT"), "...")); return RepositoryLoader.getSongsForFolders(folders); } @Override protected void done() { super.done(); VisualHandler.getInstance().hideIndeterminateProgressDialog(); try { final List<AudioFile> filesToLoad = get(); TagAttributesReviewed tagAttributesReviewed = null; // Review tags if selected in settings if (ApplicationState.getInstance().isReviewTagsBeforeImport()) { ReviewImportDialog reviewImportDialog = VisualHandler.getInstance().getReviewImportDialog(); reviewImportDialog.show(folders, filesToLoad); if (reviewImportDialog.isDialogCancelled()) { return; } tagAttributesReviewed = reviewImportDialog.getResult(); } final ImportFilesProcess process = new ImportFilesProcess(filesToLoad, folders, path, tagAttributesReviewed); process.addProcessListener(new ProcessListener() { @Override public void processCanceled() { // Nothing to do, files copied will be removed before calling this method } @Override public void processFinished(final boolean ok) { if (!ok) { try { SwingUtilities.invokeAndWait(new Runnable() { @Override public void run() { VisualHandler.getInstance().showErrorDialog( LanguageTool.getString("ERRORS_IN_IMPORT_PROCESS")); } }); } catch (InterruptedException e) { // Do nothing } catch (InvocationTargetException e) { // Do nothing } } else { // If import is ok then add files to repository addFilesAndRefresh(process.getFilesTransferred()); } } }); process.execute(); } catch (InterruptedException e) { getLogger().error(LogCategories.REPOSITORY, e); } catch (ExecutionException e) { getLogger().error(LogCategories.REPOSITORY, e); } } }; worker.execute(); } /** * Adds a listener to be notified when an audio file is removed * * @param listener */ public void addAudioFilesRemovedListener(AudioFilesRemovedListener listener) { audioFilesRemovedListeners.add(listener); } @Override public void audioFilesRemoved(List<AudioFile> audioFiles) { // Update status bar VisualHandler.getInstance().showRepositoryAudioFileNumber(getAudioFiles().size(), getRepositoryTotalSize(), repository.getTotalDurationInSeconds()); } }