/* * Entagged Audio Tag library * Copyright (c) 2003-2005 Rapha�l Slinckx <raphael@slinckx.net> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package entagged.audioformats.generic; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import entagged.audioformats.Tag; /** * This class is the default implementation for * {@link entagged.audioformats.Tag} and introduces some more useful * functionality to be implemented.<br> * * @author Rapha�l Slinckx */ public abstract class AbstractTag implements Tag { /** * Stores the amount of {@link TagField} with {@link TagField#isCommon()} * <code>true</code>. */ protected int commonNumber = 0; /** * This map stores the {@linkplain TagField#getId() ids} of the stored * fields to the {@linkplain TagField fields} themselves.<br> */ protected HashMap fields = new HashMap(); /** * (overridden) The use of this method is not recommended. One must know the * underlying audio files implementation. * * @see entagged.audioformats.Tag#add(entagged.audioformats.generic.TagField) */ /** * (overridden) * * @see entagged.audioformats.Tag#add(entagged.audioformats.generic.TagField) */ public void add(TagField field) { if (field == null || field.isEmpty()) return; List list = (List) fields.get(field.getId()); // There was no previous item if (list == null) { list = new ArrayList(); list.add(field); fields.put(field.getId(), list); if (field.isCommon()) commonNumber++; } else { // We append to existing list list.add(field); } } /** * (overridden) * * @see entagged.audioformats.Tag#addAlbum(java.lang.String) */ public void addAlbum(String s) { add(createAlbumField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#addArtist(java.lang.String) */ public void addArtist(String s) { add(createArtistField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#addComment(java.lang.String) */ public void addComment(String s) { add(createCommentField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#addGenre(java.lang.String) */ public void addGenre(String s) { add(createGenreField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#addTitle(java.lang.String) */ public void addTitle(String s) { add(createTitleField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#addTrack(java.lang.String) */ public void addTrack(String s) { add(createTrackField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#addYear(java.lang.String) */ public void addYear(String s) { add(createYearField(s)); } /** * Creates a field which represents the "album".<br> * The field will already contain the given content. * * @param content * The content of the created field. * @return tagfield representing the "album" */ protected abstract TagField createAlbumField(String content); /** * Creates a field which represents the "artist".<br> * The field will already contain the given content. * * @param content * The content of the created field. * @return tagfield representing the "artist" */ protected abstract TagField createArtistField(String content); /** * Creates a field which represents the "comment".<br> * The field will already contain the given content. * * @param content * The content of the created field. * @return tagfield representing the "comment" */ protected abstract TagField createCommentField(String content); /** * Creates a field which represents the "genre".<br> * The field will already contain the given content. * * @param content * The content of the created field. * @return tagfield representing the "genre" */ protected abstract TagField createGenreField(String content); /** * Creates a field which represents the "title".<br> * The field will already contain the given content. * * @param content * The content of the created field. * @return tagfield representing the "title" */ protected abstract TagField createTitleField(String content); /** * Creates a field which represents the "track".<br> * The field will already contain the given content. * * @param content * The content of the created field. * @return tagfield representing the "track" */ protected abstract TagField createTrackField(String content); /** * Creates a field which represents the "year".<br> * The field will already contain the given content. * * @param content * The content of the created field. * @return tagfield representing the "year" */ protected abstract TagField createYearField(String content); /** * (overridden) * * @see entagged.audioformats.Tag#get(java.lang.String) */ public List get(String id) { List list = (List) fields.get(id); if (list == null) return new ArrayList(); return list; } /** * (overridden) * * @see entagged.audioformats.Tag#getAlbum() */ public List getAlbum() { return get(getAlbumId()); } /** * Returns the identifier for a field representing the "album"<br> * * @see TagField#getId() * @return identifier for the "album" field. */ protected abstract String getAlbumId(); /** * (overridden) * * @see entagged.audioformats.Tag#getArtist() */ public List getArtist() { return get(getArtistId()); } /** * Returns the identifier for a field representing the "artist"<br> * * @see TagField#getId() * @return identifier for the "artist" field. */ protected abstract String getArtistId(); /** * (overridden) * * @see entagged.audioformats.Tag#getComment() */ public List getComment() { return get(getCommentId()); } /** * Returns the identifier for a field representing the "comment"<br> * * @see TagField#getId() * @return identifier for the "comment" field. */ protected abstract String getCommentId(); /** * (overridden) * * @see entagged.audioformats.Tag#getFields() */ public Iterator getFields() { final Iterator it = this.fields.entrySet().iterator(); return new Iterator() { private Iterator fieldsIt; private void changeIt() { if (!it.hasNext()) return; List l = (List) ((Map.Entry) it.next()).getValue(); fieldsIt = l.iterator(); } public boolean hasNext() { if (fieldsIt == null) { changeIt(); } return it.hasNext() || (fieldsIt != null && fieldsIt.hasNext()); } public Object next() { if (!fieldsIt.hasNext()) changeIt(); return fieldsIt.next(); } public void remove() { fieldsIt.remove(); } }; } /** * (overridden) * * @see entagged.audioformats.Tag#getFirstAlbum() */ public String getFirstAlbum() { List l = get(getAlbumId()); return (l.size() != 0) ? ((TagTextField) l.get(0)).getContent() : ""; } /** * (overridden) * * @see entagged.audioformats.Tag#getFirstArtist() */ public String getFirstArtist() { List l = get(getArtistId()); return (l.size() != 0) ? ((TagTextField) l.get(0)).getContent() : ""; } /** * (overridden) * * @see entagged.audioformats.Tag#getFirstComment() */ public String getFirstComment() { List l = get(getCommentId()); return (l.size() != 0) ? ((TagTextField) l.get(0)).getContent() : ""; } /** * (overridden) * * @see entagged.audioformats.Tag#getFirstGenre() */ public String getFirstGenre() { List l = get(getGenreId()); return (l.size() != 0) ? ((TagTextField) l.get(0)).getContent() : ""; } /** * (overridden) * * @see entagged.audioformats.Tag#getFirstTitle() */ public String getFirstTitle() { List l = get(getTitleId()); return (l.size() != 0) ? ((TagTextField) l.get(0)).getContent() : ""; } /** * (overridden) * * @see entagged.audioformats.Tag#getFirstTrack() */ public String getFirstTrack() { List l = get(getTrackId()); return (l.size() != 0) ? ((TagTextField) l.get(0)).getContent() : ""; } /** * (overridden) * * @see entagged.audioformats.Tag#getFirstYear() */ public String getFirstYear() { List l = get(getYearId()); return (l.size() != 0) ? ((TagTextField) l.get(0)).getContent() : ""; } /** * (overridden) * * @see entagged.audioformats.Tag#getGenre() */ public List getGenre() { return get(getGenreId()); } /** * Returns the identifier for a field representing the "genre"<br> * * @see TagField#getId() * @return identifier for the "genre" field. */ protected abstract String getGenreId(); /** * (overridden) * * @see entagged.audioformats.Tag#getTitle() */ public List getTitle() { return get(getTitleId()); } /** * Returns the identifier for a field representing the "title"<br> * * @see TagField#getId() * @return identifier for the "title" field. */ protected abstract String getTitleId(); /** * (overridden) * * @see entagged.audioformats.Tag#getTrack() */ public List getTrack() { return get(getTrackId()); } /** * Returns the identifier for a field representing the "track"<br> * * @see TagField#getId() * @return identifier for the "track" field. */ protected abstract String getTrackId(); /** * (overridden) * * @see entagged.audioformats.Tag#getYear() */ public List getYear() { return get(getYearId()); } /** * Returns the identifier for a field representing the "year"<br> * * @see TagField#getId() * @return identifier for the "year" field. */ protected abstract String getYearId(); /** * (overridden) * * @see entagged.audioformats.Tag#hasCommonFields() */ public boolean hasCommonFields() { return commonNumber != 0; } /** * (overridden) * * @see entagged.audioformats.Tag#hasField(java.lang.String) */ public boolean hasField(String id) { return get(id).size() != 0; } /** * Determines whether the given charset encoding may be used for the * represented tagging system. * * @param enc * charset encoding. * @return <code>true</code> if the given encoding can be used. */ protected abstract boolean isAllowedEncoding(String enc); /** * (overridden) * * @see entagged.audioformats.Tag#isEmpty() */ public boolean isEmpty() { return fields.size() == 0; } /** * (overridden) * * @see entagged.audioformats.Tag#merge(entagged.audioformats.Tag) */ public void merge(Tag tag) { // FIXME: Improve me, for the moment, // it overwrites this tag with other values // FIXME: TODO: an abstract method that merges particular things for // each // format if (getTitle().size() == 0) setTitle(tag.getFirstTitle()); if (getArtist().size() == 0) setArtist(tag.getFirstArtist()); if (getAlbum().size() == 0) setAlbum(tag.getFirstAlbum()); if (getYear().size() == 0) setYear(tag.getFirstYear()); if (getComment().size() == 0) setComment(tag.getFirstComment()); if (getTrack().size() == 0) setTrack(tag.getFirstTrack()); if (getGenre().size() == 0) setGenre(tag.getFirstGenre()); } /** * (overridden) * * @see entagged.audioformats.Tag#set(entagged.audioformats.generic.TagField) */ public void set(TagField field) { if (field == null) return; // If an empty field is passed, we delete all the previous ones if (field.isEmpty()) { Object removed = fields.remove(field.getId()); if (removed != null && field.isCommon()) commonNumber--; return; } // If there is already an existing field with same id // and both are TextFields, we update the first element List l = (List) fields.get(field.getId()); if (l != null) { TagField f = (TagField) l.get(0); f.copyContent(field); return; } // Else we put the new field in the fields. l = new ArrayList(); l.add(field); fields.put(field.getId(), l); if (field.isCommon()) commonNumber++; } /** * (overridden) * * @see entagged.audioformats.Tag#setAlbum(java.lang.String) */ public void setAlbum(String s) { set(createAlbumField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#setArtist(java.lang.String) */ public void setArtist(String s) { set(createArtistField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#setComment(java.lang.String) */ public void setComment(String s) { set(createCommentField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#setEncoding(java.lang.String) */ public boolean setEncoding(String enc) { if (!isAllowedEncoding(enc)) { return false; } Iterator it = getFields(); while (it.hasNext()) { TagField field = (TagField) it.next(); if (field instanceof TagTextField) { ((TagTextField) field).setEncoding(enc); } } return true; } /** * (overridden) * * @see entagged.audioformats.Tag#setGenre(java.lang.String) */ public void setGenre(String s) { set(createGenreField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#setTitle(java.lang.String) */ public void setTitle(String s) { set(createTitleField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#setTrack(java.lang.String) */ public void setTrack(String s) { set(createTrackField(s)); } /** * (overridden) * * @see entagged.audioformats.Tag#setYear(java.lang.String) */ public void setYear(String s) { set(createYearField(s)); } /** * (overridden) * * @see java.lang.Object#toString() */ public String toString() { StringBuffer out = new StringBuffer(); out.append("Tag content:\n"); Iterator it = getFields(); while (it.hasNext()) { TagField field = (TagField) it.next(); out.append("\t"); out.append(field.getId()); out.append(" : "); out.append(field.toString()); out.append("\n"); } return out.toString().substring(0, out.length() - 1); } }