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.tags;
22 
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 
28 import javax.swing.ImageIcon;
29 
30 import net.sourceforge.atunes.gui.views.dialogs.EditTitlesDialog;
31 import net.sourceforge.atunes.kernel.AbstractHandler;
32 import net.sourceforge.atunes.model.IAlbum;
33 import net.sourceforge.atunes.model.IAudioObject;
34 import net.sourceforge.atunes.model.IDialogFactory;
35 import net.sourceforge.atunes.model.IFileManager;
36 import net.sourceforge.atunes.model.ILocalAudioObject;
37 import net.sourceforge.atunes.model.ILocalAudioObjectReader;
38 import net.sourceforge.atunes.model.IProcessFactory;
39 import net.sourceforge.atunes.model.IStateNavigation;
40 import net.sourceforge.atunes.model.ITag;
41 import net.sourceforge.atunes.model.ITagHandler;
42 import net.sourceforge.atunes.model.ITreeObject;
43 import net.sourceforge.atunes.model.IUnknownObjectChecker;
44 import net.sourceforge.atunes.model.IWebServicesHandler;
45 import net.sourceforge.atunes.model.TextTagAttribute;
46 
47 /**
48  * Responsible of change tags
49  *
50  * @author alex
51  *
52  */
53 public class TagHandler extends AbstractHandler implements ITagHandler {
54 
55 	private IProcessFactory processFactory;
56 
57 	private IStateNavigation stateNavigation;
58 
59 	private IDialogFactory dialogFactory;
60 
61 	private Map<TextTagAttribute, ITagChecker> checkers;
62 
63 	private IUnknownObjectChecker unknownObjectChecker;
64 
65 	private IWebServicesHandler webServicesHandler;
66 
67 	private TagModifier tagModifier;
68 
69 	private IFileManager fileManager;
70 
71 	private TagFactory tagFactory;
72 
73 	private ILocalAudioObjectReader localAudioObjectReader;
74 
75 	/**
76 	 * @param localAudioObjectReader
77 	 */
setLocalAudioObjectReader( final ILocalAudioObjectReader localAudioObjectReader)78 	public void setLocalAudioObjectReader(
79 			final ILocalAudioObjectReader localAudioObjectReader) {
80 		this.localAudioObjectReader = localAudioObjectReader;
81 	}
82 
83 	/**
84 	 * @param tagFactory
85 	 */
setTagFactory(final TagFactory tagFactory)86 	public void setTagFactory(final TagFactory tagFactory) {
87 		this.tagFactory = tagFactory;
88 	}
89 
90 	/**
91 	 * @param fileManager
92 	 */
setFileManager(final IFileManager fileManager)93 	public void setFileManager(final IFileManager fileManager) {
94 		this.fileManager = fileManager;
95 	}
96 
97 	/**
98 	 * @param tagModifier
99 	 */
setTagModifier(final TagModifier tagModifier)100 	public void setTagModifier(final TagModifier tagModifier) {
101 		this.tagModifier = tagModifier;
102 	}
103 
104 	/**
105 	 * @param webServicesHandler
106 	 */
setWebServicesHandler( final IWebServicesHandler webServicesHandler)107 	public void setWebServicesHandler(
108 			final IWebServicesHandler webServicesHandler) {
109 		this.webServicesHandler = webServicesHandler;
110 	}
111 
112 	/**
113 	 * @param unknownObjectChecker
114 	 */
setUnknownObjectChecker( final IUnknownObjectChecker unknownObjectChecker)115 	public void setUnknownObjectChecker(
116 			final IUnknownObjectChecker unknownObjectChecker) {
117 		this.unknownObjectChecker = unknownObjectChecker;
118 	}
119 
120 	/**
121 	 * @param dialogFactory
122 	 */
setDialogFactory(final IDialogFactory dialogFactory)123 	public void setDialogFactory(final IDialogFactory dialogFactory) {
124 		this.dialogFactory = dialogFactory;
125 	}
126 
127 	/**
128 	 * @param stateNavigation
129 	 */
setStateNavigation(final IStateNavigation stateNavigation)130 	public void setStateNavigation(final IStateNavigation stateNavigation) {
131 		this.stateNavigation = stateNavigation;
132 	}
133 
134 	/**
135 	 * @param processFactory
136 	 */
setProcessFactory(final IProcessFactory processFactory)137 	public void setProcessFactory(final IProcessFactory processFactory) {
138 		this.processFactory = processFactory;
139 	}
140 
141 	/**
142 	 * Gets the edits the tag dialog controller.
143 	 *
144 	 * @return the edits the tag dialog controller
145 	 */
getEditTagDialogController()146 	private EditTagDialogController getEditTagDialogController() {
147 		return getBean(EditTagDialogController.class);
148 	}
149 
150 	@Override
editFiles(final List<ILocalAudioObject> list)151 	public void editFiles(final List<ILocalAudioObject> list) {
152 		getEditTagDialogController().editFiles(list);
153 	}
154 
155 	@Override
editFiles(final IAlbum a)156 	public void editFiles(final IAlbum a) {
157 		new EditTitlesDialogController(
158 				this.dialogFactory.newDialog(EditTitlesDialog.class),
159 				this.processFactory, this.webServicesHandler, this.fileManager)
160 				.editFiles(a);
161 	}
162 
163 	@Override
setTag(final ILocalAudioObject audioObject, final ITag tag)164 	public void setTag(final ILocalAudioObject audioObject, final ITag tag) {
165 		this.tagModifier.setInfo(audioObject, tag);
166 	}
167 
168 	@Override
refreshAfterTagModify( final Collection<ILocalAudioObject> audioObjectsChanged)169 	public void refreshAfterTagModify(
170 			final Collection<ILocalAudioObject> audioObjectsChanged) {
171 		this.tagModifier.refreshAfterTagModify(audioObjectsChanged);
172 	}
173 
174 	@Override
deleteTags(final ILocalAudioObject audioObject)175 	public void deleteTags(final ILocalAudioObject audioObject) {
176 		this.tagModifier.deleteTags(audioObject);
177 	}
178 
179 	@Override
setTag(final ILocalAudioObject audioObject, final ITag tag, final boolean editCover, final byte[] cover)180 	public void setTag(final ILocalAudioObject audioObject, final ITag tag,
181 			final boolean editCover, final byte[] cover) {
182 		this.tagModifier.setInfo(audioObject, tag, editCover, cover);
183 	}
184 
185 	@Override
setTitle(final ILocalAudioObject audioObject, final String newTitle)186 	public void setTitle(final ILocalAudioObject audioObject,
187 			final String newTitle) {
188 		this.tagModifier.setTitles(audioObject, newTitle);
189 	}
190 
191 	@Override
setAlbum(final ILocalAudioObject audioObject, final String albumName)192 	public void setAlbum(final ILocalAudioObject audioObject,
193 			final String albumName) {
194 		this.tagModifier.setAlbum(audioObject, albumName);
195 	}
196 
197 	@Override
setGenre(final ILocalAudioObject audioObject, final String genre)198 	public void setGenre(final ILocalAudioObject audioObject, final String genre) {
199 		this.tagModifier.setGenre(audioObject, genre);
200 	}
201 
202 	@Override
setLyrics(final ILocalAudioObject audioObject, final String lyricsString)203 	public void setLyrics(final ILocalAudioObject audioObject,
204 			final String lyricsString) {
205 		this.tagModifier.setLyrics(audioObject, lyricsString);
206 	}
207 
208 	@Override
setStars(final ILocalAudioObject audioObject, final Integer value)209 	public void setStars(final ILocalAudioObject audioObject,
210 			final Integer value) {
211 		this.tagModifier.setStars(audioObject, value);
212 	}
213 
214 	@Override
setTrackNumber(final ILocalAudioObject audioObject, final Integer integer)215 	public void setTrackNumber(final ILocalAudioObject audioObject,
216 			final Integer integer) {
217 		this.tagModifier.setTrackNumber(audioObject, integer);
218 	}
219 
220 	@Override
getNewTag()221 	public ITag getNewTag() {
222 		return this.tagFactory.getNewTag();
223 	}
224 
225 	@Override
getNewTag(final ILocalAudioObject file, final Map<String, Object> tagInformation)226 	public ITag getNewTag(final ILocalAudioObject file,
227 			final Map<String, Object> tagInformation) {
228 		return this.tagFactory.getNewTag(file, tagInformation);
229 	}
230 
231 	@Override
hasIncompleteTags(final IAudioObject audioObject)232 	public boolean hasIncompleteTags(final IAudioObject audioObject) {
233 		return hasIncompleteTags(audioObject,
234 				this.stateNavigation
235 						.getHighlightIncompleteTagFoldersAttributes());
236 	}
237 
238 	@Override
hasIncompleteTags( final ITreeObject<? extends IAudioObject> treeObject)239 	public boolean hasIncompleteTags(
240 			final ITreeObject<? extends IAudioObject> treeObject) {
241 		return hasIncompleteTags(treeObject,
242 				this.stateNavigation
243 						.getHighlightIncompleteTagFoldersAttributes());
244 	}
245 
246 	/**
247 	 * Returns true if audio file has filled all enabled attributes
248 	 *
249 	 * @param localAudioObject
250 	 * @param tagAttributesToCheck
251 	 * @return
252 	 */
hasTagAttributesFilled( final ILocalAudioObject localAudioObject, final List<TextTagAttribute> tagAttributesToCheck)253 	private boolean hasTagAttributesFilled(
254 			final ILocalAudioObject localAudioObject,
255 			final List<TextTagAttribute> tagAttributesToCheck) {
256 		if (localAudioObject.getTag() == null) {
257 			return false;
258 		}
259 
260 		for (TextTagAttribute ta : tagAttributesToCheck) {
261 			if (!analyzeAttribute(localAudioObject, ta)) {
262 				return false;
263 			}
264 		}
265 
266 		return true;
267 	}
268 
269 	/**
270 	 * @param localAudioObject
271 	 * @param ta
272 	 * @return if attribute is filled
273 	 */
analyzeAttribute(final ILocalAudioObject localAudioObject, final TextTagAttribute ta)274 	private boolean analyzeAttribute(final ILocalAudioObject localAudioObject,
275 			final TextTagAttribute ta) {
276 		return getTagCheckerForAttribute(ta)
277 				.checkTagAttribute(localAudioObject);
278 	}
279 
280 	/**
281 	 * Returns <code>true</code> if tree object contains audio objects with
282 	 * incomplete tags
283 	 *
284 	 * @param treeObject
285 	 * @param tagAttributes
286 	 * @return
287 	 */
hasIncompleteTags( final ITreeObject<? extends IAudioObject> treeObject, final List<TextTagAttribute> tagAttributes)288 	private boolean hasIncompleteTags(
289 			final ITreeObject<? extends IAudioObject> treeObject,
290 			final List<TextTagAttribute> tagAttributes) {
291 		for (IAudioObject f : treeObject.getAudioObjects()) {
292 			if (hasIncompleteTags(f, tagAttributes)) {
293 				return true;
294 			}
295 		}
296 		return false;
297 	}
298 
299 	/**
300 	 * Returns <code>true</code> if object has incomplete tag tags
301 	 *
302 	 * @param audioObject
303 	 * @param tagAttributes
304 	 * @return
305 	 */
hasIncompleteTags(final IAudioObject audioObject, final List<TextTagAttribute> tagAttributes)306 	private boolean hasIncompleteTags(final IAudioObject audioObject,
307 			final List<TextTagAttribute> tagAttributes) {
308 		if (audioObject == null) {
309 			throw new IllegalArgumentException("Null audioObject");
310 		}
311 		if (audioObject instanceof ILocalAudioObject) {
312 			return !hasTagAttributesFilled((ILocalAudioObject) audioObject,
313 					tagAttributes);
314 		}
315 		return false;
316 	}
317 
318 	/**
319 	 * @param attribute
320 	 * @return tag checker for given attribute
321 	 */
getTagCheckerForAttribute( final TextTagAttribute attribute)322 	private ITagChecker getTagCheckerForAttribute(
323 			final TextTagAttribute attribute) {
324 		if (this.checkers == null) {
325 			this.checkers = new HashMap<TextTagAttribute, ITagChecker>();
326 			this.checkers.put(TextTagAttribute.ALBUM, new AlbumTagChecker(
327 					this.unknownObjectChecker));
328 			this.checkers.put(TextTagAttribute.ALBUM_ARTIST,
329 					new AlbumArtistTagChecker(this.unknownObjectChecker));
330 			this.checkers.put(TextTagAttribute.ARTIST, new ArtistTagChecker(
331 					this.unknownObjectChecker));
332 			this.checkers
333 					.put(TextTagAttribute.COMMENT, new CommentTagChecker());
334 			this.checkers.put(TextTagAttribute.COMPOSER,
335 					new ComposerTagChecker());
336 			this.checkers.put(TextTagAttribute.DISC_NUMBER,
337 					new DiscNumberTagChecker());
338 			this.checkers.put(TextTagAttribute.GENRE, new GenreTagChecker(
339 					this.unknownObjectChecker));
340 			this.checkers.put(TextTagAttribute.LYRICS, new LyricsTagChecker());
341 			this.checkers.put(TextTagAttribute.TITLE, new TitleTagChecker());
342 			this.checkers.put(TextTagAttribute.TRACK, new TrackTagChecker());
343 			this.checkers.put(TextTagAttribute.YEAR, new YearTagChecker(
344 					this.unknownObjectChecker));
345 		}
346 		return this.checkers.get(attribute);
347 	}
348 
349 	@Override
getImage(final ILocalAudioObject audioObject, final int width, final int height)350 	public ImageIcon getImage(final ILocalAudioObject audioObject,
351 			final int width, final int height) {
352 		return this.localAudioObjectReader.getImage(audioObject, width, height);
353 	}
354 }
355