[Schmitzm-commits] r2280 - in trunk: . schmitzm-mp3 schmitzm-mp3/src schmitzm-mp3/src/main schmitzm-mp3/src/main/java schmitzm-mp3/src/main/java/de schmitzm-mp3/src/main/java/de/schmitzm schmitzm-mp3/src/main/java/de/schmitzm/mp3 schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3 schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io schmitzm-mp3/src/main/resources schmitzm-mp3/src/main/resources/de schmitzm-mp3/src/main/resources/de/schmitzm schmitzm-mp3/src/main/resources/de/schmitzm/mp3 schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3 schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales

scm-commit at wald.intevation.org scm-commit at wald.intevation.org
Sun Mar 24 12:19:19 CET 2013


Author: mojays
Date: 2013-03-24 12:19:19 +0100 (Sun, 24 Mar 2013)
New Revision: 2280

Added:
   trunk/schmitzm-mp3/
   trunk/schmitzm-mp3/pom.xml
   trunk/schmitzm-mp3/src/
   trunk/schmitzm-mp3/src/main/
   trunk/schmitzm-mp3/src/main/java/
   trunk/schmitzm-mp3/src/main/java/de/
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagField.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagUtil.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3V1_1aTag.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/GUIUtil.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3Tag2FilenameParserPanel.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagFieldSequencePanel.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagPanel.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV1Panel.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV2Panel.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionDialog.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionPanel.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/ID3Tag2FilenameParser.java
   trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/MP3File.java
   trunk/schmitzm-mp3/src/main/resources/
   trunk/schmitzm-mp3/src/main/resources/de/
   trunk/schmitzm-mp3/src/main/resources/de/schmitzm/
   trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/
   trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/
   trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/
   trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/
   trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle.properties
   trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle_de.properties
Log:
New SCHMITZM sub-project for general/reusable MP3 classes and utilities

Added: trunk/schmitzm-mp3/pom.xml
===================================================================
--- trunk/schmitzm-mp3/pom.xml	                        (rev 0)
+++ trunk/schmitzm-mp3/pom.xml	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,113 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>de.schmitzm</groupId>
+	<artifactId>schmitzm-mp3</artifactId>
+	<version>2.8-SNAPSHOT</version>
+	<packaging>jar</packaging>
+
+	<parent>
+		<groupId>de.schmitzm</groupId>
+		<artifactId>schmitzm-parent</artifactId>
+		<version>2.8-SNAPSHOT</version>
+		<relativePath>../schmitzm-parent/pom.xml</relativePath>
+	</parent>
+
+	<name>schmitzm-mp3</name>
+	<dependencies>
+		<dependency>
+			<groupId>de.schmitzm</groupId>
+			<artifactId>schmitzm-core</artifactId>
+			<version>${schmitzm.version}</version>
+			<type>jar</type>
+			<scope>compile</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.blinkenlights</groupId>
+			<artifactId>jid3</artifactId>
+			<version>0.46</version>
+			<type>jar</type>
+			<scope>compile</scope>
+		</dependency>
+	</dependencies>
+
+	<profiles>
+		<profile>
+			<id>resourceOperationRemove</id>
+			<!-- When this profile is activated (e.g with "mavn install -P resourceOperationRemove" 
+				the build will remove any lines in the resource bundes that are tagged with 
+				REMOVEME_ -->
+			<build>
+				<plugins>
+					<plugin>
+						<groupId>org.codehaus.mojo</groupId>
+						<artifactId>exec-maven-plugin</artifactId>
+						<version>1.2</version>
+						<executions>
+							<execution>
+								<phase>generate-sources</phase>
+								<goals>
+									<goal>java</goal>
+								</goals>
+								<configuration>
+									<mainClass>de.schmitzm.lang.ResourceProviderOperator</mainClass>
+									<arguments>
+										<argument>-s</argument>
+										<argument>${basedir}/src/main/resources</argument>
+										<argument>-b</argument>
+										<argument>de.schmitzm.mp3.id3.resource.locales.ID3TagResourceBundle
+										</argument>
+									</arguments>
+								</configuration>
+							</execution>
+						</executions>
+					</plugin>
+				</plugins>
+			</build>
+		</profile>
+	</profiles>
+
+	<build>
+
+		<pluginManagement>
+			<plugins>
+				<!--This plugin's configuration is used to store Eclipse m2e settings 
+					only. It has no influence on the Maven build itself. -->
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>
+											org.codehaus.mojo
+										</groupId>
+										<artifactId>
+											exec-maven-plugin
+										</artifactId>
+										<versionRange>
+											[1.2,)
+										</versionRange>
+										<goals>
+											<goal>java</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<ignore></ignore>
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+
+
+	</build>
+
+</project>

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagField.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagField.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagField.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,80 @@
+package de.schmitzm.mp3.id3;
+
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.Transferable;
+import java.awt.datatransfer.UnsupportedFlavorException;
+import java.io.IOException;
+
+/**
+ * Enum representing the common ID3-Tag parts which are used in all
+ * common versions (>= v1.1).
+ * @author Martin O.J. Schmitz
+ *
+ */
+public enum ID3TagField implements Transferable {
+  /** Title of song. */
+  TITLE,
+  /** Artist of song. */
+  ARTIST,
+  /** Album of song. */
+  ALBUM,
+  /** Total number of tracks (only ID3v2). */
+  TOTALTRACKS,
+  /** Tracknumber. */
+  TRACKNO,
+  /** Year */
+  YEAR,
+  /** Genre */
+  GENRE,
+  /** Comment for file. */
+  COMMENT;
+  
+  /**
+   * Returns a title for ID3-Tag field.
+   */
+  public String getTitle() {
+    return getTitle(this);
+  }
+
+  /**
+   * Returns a title for ID3-Tag field.
+   */
+  public static String getTitle(ID3TagField field) {
+    switch (field) {
+      case TITLE: return ID3TagUtil.R("ID3Tag.Title");
+      case ARTIST: return ID3TagUtil.R("ID3Tag.Artist");
+      case ALBUM: return ID3TagUtil.R("ID3Tag.Album");
+      case TRACKNO: return ID3TagUtil.R("ID3Tag.TrackNo");
+      case TOTALTRACKS: return ID3TagUtil.R("ID3Tag.TotalTracks");
+      case GENRE: return ID3TagUtil.R("ID3Tag.Genre");
+      case YEAR: return ID3TagUtil.R("ID3Tag.Year");
+      case COMMENT: return ID3TagUtil.R("ID3Tag.Comment");
+    }
+    throw new UnsupportedOperationException("Unknown enum: "+field);
+  }
+
+  
+  
+  public static final DataFlavor FLAVOR = new DataFlavor(ID3TagField.class,"ID3TagField");
+  private static final DataFlavor[] flavors = new DataFlavor[] {FLAVOR};
+  
+  
+  @Override
+  public DataFlavor[] getTransferDataFlavors() {
+    return flavors;
+  }
+
+  @Override
+  public boolean isDataFlavorSupported(DataFlavor flavor) {
+    return flavor.equals(FLAVOR) || flavor.equals(DataFlavor.stringFlavor);
+  }
+
+  @Override
+  public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException, IOException {
+    if (flavor.equals(FLAVOR)) {
+      return this;
+    } else {
+      throw new UnsupportedFlavorException(flavor);
+    }
+  }
+}
\ No newline at end of file

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagUtil.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagUtil.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3TagUtil.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,647 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3;
+
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.commons.lang.StringUtils;
+import org.blinkenlights.jid3.ID3Exception;
+import org.blinkenlights.jid3.ID3Tag;
+import org.blinkenlights.jid3.v1.ID3V1Tag;
+import org.blinkenlights.jid3.v1.ID3V1Tag.Genre;
+import org.blinkenlights.jid3.v1.ID3V1_1Tag;
+import org.blinkenlights.jid3.v2.ContentType;
+import org.blinkenlights.jid3.v2.ID3V2Tag;
+import org.blinkenlights.jid3.v2.ID3V2_3_0Tag;
+
+import de.schmitzm.lang.LangUtil;
+import de.schmitzm.lang.ResourceProvider;
+
+/**
+ * Utility methods for JID3 library. 
+ * @author Martin O.J. Schmitz
+ */
+public class ID3TagUtil {
+
+  
+  /**
+   * {@link ResourceProvider} for the localisation of the GUI components.
+   */
+  public static ResourceProvider RESOURCE = ResourceProvider.newInstance(
+          LangUtil.extendPackagePath(ID3TagUtil.class,
+                  "resource.locales.ID3TagResourceBundle"), Locale.ENGLISH);
+  /**
+   * Shortcut for {@code RESOURCE.getString(..)}.
+   */
+  public static String R(String key, Object... values) {
+      return RESOURCE.getString(key, values);
+  }
+  
+  
+  
+  
+  /** Contains all available ID3 v1 genres as array. */
+  public static final Genre[] ALL_GENRE_ID3V1;
+  static {
+    List<Genre> genreList = new ArrayList<Genre>();
+    for (int i=0; i<256; i++)
+      try {
+        Genre g = Genre.lookupGenre(i);
+        genreList.add(g);
+      } catch (ID3Exception e) {
+        // ignore
+      }
+    ALL_GENRE_ID3V1 = genreList.toArray(new Genre[0]);
+  }
+  /** Contains all available ID3 v1 genre descriptions as array. */
+  public static String[] ALL_GENRE_TITLES_ID3V1 = new String[ALL_GENRE_ID3V1.length];
+  static {
+    for (int i=0; i<ALL_GENRE_ID3V1.length; i++)
+      ALL_GENRE_TITLES_ID3V1[i] = ALL_GENRE_ID3V1[i].toString();
+  }
+  
+  /** Contains all available ID3 v2 genres as array. */
+  public static ContentType.Genre[] ALL_GENRE_ID3V2 = {
+      ContentType.Genre.Blues,
+      ContentType.Genre.ClassicRock,
+      ContentType.Genre.Country,
+      ContentType.Genre.Dance,
+      ContentType.Genre.Disco,
+      ContentType.Genre.Funk,
+      ContentType.Genre.Grunge,
+      ContentType.Genre.HipHop,
+      ContentType.Genre.Jazz,
+      ContentType.Genre.Metal,
+      ContentType.Genre.NewAge,
+      ContentType.Genre.Oldies,
+      ContentType.Genre.Other,
+      ContentType.Genre.Pop,
+      ContentType.Genre.RhythmBlues,
+      ContentType.Genre.Rap,
+      ContentType.Genre.Reggae,
+      ContentType.Genre.Rock,
+      ContentType.Genre.Techno,
+      ContentType.Genre.Industrial,
+      ContentType.Genre.Alternative,
+      ContentType.Genre.Ska,
+      ContentType.Genre.DeathMetal,
+      ContentType.Genre.Pranks,
+      ContentType.Genre.Soundtrack,
+      ContentType.Genre.EuroTechno,
+      ContentType.Genre.Ambient,
+      ContentType.Genre.TripHop,
+      ContentType.Genre.Vocal,
+      ContentType.Genre.JazzFunk,
+      ContentType.Genre.Fusion,
+      ContentType.Genre.Trance,
+      ContentType.Genre.Classical,
+      ContentType.Genre.Instrumental,
+      ContentType.Genre.Acid,
+      ContentType.Genre.House,
+      ContentType.Genre.Game,
+      ContentType.Genre.SoundClip,
+      ContentType.Genre.Gospel,
+      ContentType.Genre.Noise,
+      ContentType.Genre.AlternativeRock,
+      ContentType.Genre.Bass,
+      ContentType.Genre.Soul,
+      ContentType.Genre.Punk,
+      ContentType.Genre.Space,
+      ContentType.Genre.Meditative,
+      ContentType.Genre.InstrumentalPop,
+      ContentType.Genre.InstrumentalRock,
+      ContentType.Genre.Ethnic,
+      ContentType.Genre.Gothic,
+      ContentType.Genre.DarkWave,
+      ContentType.Genre.TechnoIndustrial,
+      ContentType.Genre.Electronic,
+      ContentType.Genre.PopFolk,
+      ContentType.Genre.EuroDance,
+      ContentType.Genre.Dream,
+      ContentType.Genre.SouthernRock,
+      ContentType.Genre.Comedy,
+      ContentType.Genre.Cult,
+      ContentType.Genre.Gangsta,
+      ContentType.Genre.Top40,
+      ContentType.Genre.ChristianRap,
+      ContentType.Genre.PopFunk,
+      ContentType.Genre.Jungle,
+      ContentType.Genre.NativeAmerican,
+      ContentType.Genre.Cabaret,
+      ContentType.Genre.NewWave,
+      ContentType.Genre.Psychedelic,
+      ContentType.Genre.Rave,
+      ContentType.Genre.ShowTunes,
+      ContentType.Genre.Trailer,
+      ContentType.Genre.LowFi,
+      ContentType.Genre.Tribal,
+      ContentType.Genre.AcidPunk,
+      ContentType.Genre.AcidJazz,
+      ContentType.Genre.Polka,
+      ContentType.Genre.Retro,
+      ContentType.Genre.Musical,
+      ContentType.Genre.RockNRoll,
+      ContentType.Genre.HardRock,
+      ContentType.Genre.EXT_Folk,
+      ContentType.Genre.EXT_FolkRock,
+      ContentType.Genre.EXT_NationalFolk,
+      ContentType.Genre.EXT_Swing,
+      ContentType.Genre.EXT_FastFusion,
+      ContentType.Genre.EXT_Bebop,
+      ContentType.Genre.EXT_Latin,
+      ContentType.Genre.EXT_Revival,
+      ContentType.Genre.EXT_Celtic,
+      ContentType.Genre.EXT_Bluegrass,
+      ContentType.Genre.EXT_AvanteGarde,
+      ContentType.Genre.EXT_GothicRock,
+      ContentType.Genre.EXT_ProgressiveRock,
+      ContentType.Genre.EXT_PsychedelicRock,
+      ContentType.Genre.EXT_SymphonicRock,
+      ContentType.Genre.EXT_SlowRock,
+      ContentType.Genre.EXT_BigBand,
+      ContentType.Genre.EXT_Chorus,
+      ContentType.Genre.EXT_EasyListening,
+      ContentType.Genre.EXT_Acoustic,
+      ContentType.Genre.EXT_Humour,
+      ContentType.Genre.EXT_Speech,
+      ContentType.Genre.EXT_Chanson,
+      ContentType.Genre.EXT_Opera,
+      ContentType.Genre.EXT_ChamberMusic,
+      ContentType.Genre.EXT_Sonata,
+      ContentType.Genre.EXT_Symphony,
+      ContentType.Genre.EXT_BootyBass,
+      ContentType.Genre.EXT_Primus,
+      ContentType.Genre.EXT_PornGroove,
+      ContentType.Genre.EXT_Satire,
+      ContentType.Genre.EXT_SlowJam,
+      ContentType.Genre.EXT_Club,
+      ContentType.Genre.EXT_Tango,
+      ContentType.Genre.EXT_Samba,
+      ContentType.Genre.EXT_Folklore,
+      ContentType.Genre.EXT_Ballad,
+      ContentType.Genre.EXT_PowerBallad,
+      ContentType.Genre.EXT_RhythmicSoul,
+      ContentType.Genre.EXT_Freestyle,
+      ContentType.Genre.EXT_Duet,
+      ContentType.Genre.EXT_PunkRock,
+      ContentType.Genre.EXT_DrumSolo,
+      ContentType.Genre.EXT_ACappella,
+      ContentType.Genre.EXT_EuroHouse,
+      ContentType.Genre.EXT_DanceHall
+  };
+
+  /** Contains all available ID3 v2 genre descriptions as array. */
+  public static String[] ALL_GENRE_TITLES_ID3V2 = new String[ALL_GENRE_ID3V2.length];
+  static {
+    for (int i=0; i<ALL_GENRE_ID3V2.length; i++)
+      ALL_GENRE_TITLES_ID3V2[i] = ALL_GENRE_ID3V2[i].toString();
+  }
+
+  /** Maximum length for title in ID3v1 tag. */
+  public static int ID3V1_LENGTH_TITLE = 30;
+  /** Maximum length for artist in ID3v1 tag. */
+  public static int ID3V1_LENGTH_ARTIST = 30;
+  /** Maximum length for album in ID3v1 tag. */
+  public static int ID3V1_LENGTH_ALBUM = 30;
+  /** Maximum length for year in ID3v1 tag. */
+  public static int ID3V1_LENGTH_YEAR = 4;
+  /** Maximum length for title in ID3v1.1 tag. */
+  public static int ID3V1_LENGTH_COMMENT = 28;
+  /** Maximum length (digit count) for track numberin ID3v1.1 tag. */
+  public static int ID3V1_LENGTH_TRACKNO = 3;
+  
+  
+  /**
+   * Returns the year from {@link ID3V2Tag}.
+   * @return {@code null} if there is no such information (instead of
+   *         {@link ID3Exception}) 
+   */
+  public static Integer getYear(ID3V2Tag tag) {
+    try {
+      return tag.getYear();
+    } catch (ID3Exception e) {
+      return null;
+    }
+  }
+
+  /**
+   * Returns the track number from {@link ID3V2Tag}.
+   * @return {@code null} if there is no such information (instead of
+   *         {@link ID3Exception}) 
+   */
+  public static Integer getTrackNumber(ID3V2Tag tag) {
+    try {
+      return tag.getTrackNumber();
+    } catch (ID3Exception e) {
+      return null;
+    }
+  }
+  
+  /**
+   * Returns the total number of tracks from an {@link ID3V2Tag}.
+   * @return {@code null} if there is no such information (instead of
+   *         {@link ID3Exception}) 
+   */
+  public static Integer getTotalTracks(ID3V2Tag tag) {
+    try {
+      return tag.getTotalTracks();
+    } catch (ID3Exception e) {
+      return null;
+    }
+  }
+  
+  
+  /**
+   * Returns a basic field from ID3-Tag regardless of the ID3Tag version.
+   * @param tag ID3-Tag to determine the field from
+   * @param field field to determine
+   * @param format optional {@link NumberFormat} to encode year or track number
+   * @return {@code null} if field is not provided for ID3-Tag
+   */
+  public static String getID3TagField(ID3Tag tag, ID3TagField field, NumberFormat... format) {
+    NumberFormat numberFormat = ( format != null && format.length > 0 && format[0] != null ) ? format[0] : null;
+    
+    switch (field) {
+      case TITLE: if ( tag instanceof ID3V1Tag )
+                    return ((ID3V1Tag)tag).getTitle();
+                  if ( tag instanceof ID3V2Tag )
+                    return ((ID3V2Tag)tag).getTitle();
+                  break;
+      case ARTIST: if ( tag instanceof ID3V1Tag )
+                     return ((ID3V1Tag)tag).getArtist();
+                   if ( tag instanceof ID3V2Tag )
+                     return ((ID3V2Tag)tag).getArtist();
+                   break;
+      case ALBUM: if ( tag instanceof ID3V1Tag )
+                    return ((ID3V1Tag)tag).getAlbum();
+                  if ( tag instanceof ID3V2Tag )
+                    return ((ID3V2Tag)tag).getAlbum();
+                  break;
+      case TRACKNO: Integer track = null; 
+                    if ( tag instanceof ID3V1_1Tag )
+                      track = ((ID3V1_1Tag)tag).getAlbumTrack();
+                    if ( tag instanceof ID3V2Tag )
+                      track = getTrackNumber(((ID3V2Tag)tag));
+                    if ( track == null )
+                      return null;
+                    if ( numberFormat != null )
+                      return numberFormat.format(track);
+                    return String.valueOf(track);
+      case TOTALTRACKS: Integer totalTracks = null; 
+                        if ( tag instanceof ID3V2Tag )
+                          totalTracks = getTotalTracks(((ID3V2Tag)tag));
+                        if ( totalTracks == null )
+                          return null;
+                        if ( numberFormat != null )
+                          return numberFormat.format(totalTracks);
+                        return String.valueOf(totalTracks);
+      case GENRE: if ( tag instanceof ID3V1Tag ) {
+                    Genre genre = ((ID3V1Tag)tag).getGenre();
+                    return genre != null ? genre.toString() : null;
+                  }
+                  if ( tag instanceof ID3V2Tag )
+                    return ((ID3V2Tag)tag).getGenre();
+                  break;
+      case YEAR:  Integer year = null;
+                  if ( tag instanceof ID3V1Tag ) {
+                    String yearStr = ((ID3V1Tag)tag).getYear();
+                    year =  (yearStr != null) ? Integer.parseInt(yearStr) : null;
+                  }
+                  if ( tag instanceof ID3V2Tag )
+                    year = getYear((ID3V2Tag)tag);
+                  if ( year == null )
+                    return null;
+                  if ( numberFormat != null )
+                    return numberFormat.format(year);
+                  return String.valueOf(year);
+      case COMMENT: if ( tag instanceof ID3V1Tag )
+                      return ((ID3V1Tag)tag).getComment();
+                    if ( tag instanceof ID3V2Tag )
+                      return ((ID3V2Tag)tag).getComment();
+      break;
+    }
+    return null;
+  }
+
+  /**
+   * Sets the title of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new title value
+   */
+  public static void setTitle(ID3V2Tag tag, String value) throws ID3Exception {
+    if ( value == null && tag instanceof ID3V2_3_0Tag )
+      ((ID3V2_3_0Tag)tag).removeTIT2TextInformationFrame();
+    else
+      tag.setTitle(value);
+  }
+
+  /**
+   * Sets the artist of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new artist value
+   */
+  public static void setArtist(ID3V2Tag tag, String value) throws ID3Exception {
+    if ( value == null && tag instanceof ID3V2_3_0Tag )
+      ((ID3V2_3_0Tag)tag).removeTPE1TextInformationFrame();
+    else
+      tag.setArtist(value);
+  }
+
+  /**
+   * Sets the album of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new album value
+   */
+  public static void setAlbum(ID3V2Tag tag, String value) throws ID3Exception {
+    if ( value == null && tag instanceof ID3V2_3_0Tag )
+      ((ID3V2_3_0Tag)tag).removeTALBTextInformationFrame();
+    else
+      tag.setAlbum(value);
+  }
+
+  
+  /**
+   * Sets the track number of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new track number
+   */
+  public static void setTrackNumber(ID3V2Tag tag, Integer value) throws ID3Exception {
+//    if ( value == null && tag instanceof ID3V2_3_0Tag )
+//      ((ID3V2_3_0Tag)tag).removeTRCKTextInformationFrame();
+//    else
+//      tag.setTrackNumber(value);
+    // keep TotalTracks unchanged
+    Integer totalTracks = getTotalTracks(tag);
+    setTrackInformation(tag, value, totalTracks);
+  }
+
+  /**
+   * Sets the total number of tracks of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new track number
+   */
+  public static void setTotalTracks(ID3V2Tag tag, Integer value) throws ID3Exception {
+    // keep track no unchanged
+    Integer trackNo = getTrackNumber(tag);
+    setTrackInformation(tag, trackNo, value);
+  }
+
+  /**
+   * Sets the track number and the total number of tracks of an ID3 v2 tag.
+   * If {@code null} value is given for both information, the header is removed from tag.
+   * @param tag tag to modify
+   * @param value new track number
+   */
+  public static void setTrackInformation(ID3V2Tag tag, Integer trackNo, Integer totalTracks) throws ID3Exception {
+    if ( totalTracks == null && trackNo != null && trackNo == 0 )
+      trackNo = null;
+    
+    if ( trackNo == null && totalTracks == null && tag instanceof ID3V2_3_0Tag )
+      ((ID3V2_3_0Tag)tag).removeTRCKTextInformationFrame();
+    else {
+      if ( totalTracks == null )
+        tag.setTrackNumber(trackNo);
+      else
+        tag.setTrackNumber(trackNo != null ? trackNo : 0,totalTracks);
+    }
+  }
+
+  /**
+   * Sets the year of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new year value
+   */
+  public static void setYear(ID3V2Tag tag, Integer value) throws ID3Exception {
+    if ( value == null && tag instanceof ID3V2_3_0Tag )
+      ((ID3V2_3_0Tag)tag).removeTYERTextInformationFrame();
+    else
+      tag.setYear(value);
+  }
+
+  /**
+   * Sets the genre of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new genre value
+   */
+  public static void setGenre(ID3V2Tag tag, String value) throws ID3Exception {
+    if ( value == null && tag instanceof ID3V2_3_0Tag )
+      ((ID3V2_3_0Tag)tag).removeTCONTextInformationFrame();
+    else
+      tag.setGenre(value);
+  }
+
+  /**
+   * Sets the comment of an ID3 v2 tag. If {@code null} value is given, the
+   * header is removed from tag.
+   * @param tag tag to modify
+   * @param value new comment value
+   */
+  public static void setComment(ID3V2Tag tag, String value) throws ID3Exception {
+    if ( value == null && tag instanceof ID3V2_3_0Tag )
+      ((ID3V2_3_0Tag)tag).removeCOMMFrame("eng", null);
+    else
+      tag.setComment(value);
+  }
+
+  /**
+   * Sets a basic field from ID3-Tag regardless of the ID3Tag version.
+   * @param tag ID3-Tag to set the field for
+   * @param field field to set
+   * @param value value to set (year and track number must be given as {@link String})
+   * @return {@code null} if field is not provided for ID3-Tag
+   */
+  public static void setID3TagField(ID3Tag tag, ID3TagField field, String value) throws ID3Exception {
+    switch (field) {
+      case TITLE: if ( tag instanceof ID3V1Tag )
+                    ((ID3V1Tag)tag).setTitle(value);
+                  if ( tag instanceof ID3V2Tag )
+                    setTitle((ID3V2Tag)tag, value);
+                  break;
+      case ARTIST: if ( tag instanceof ID3V1Tag )
+                     ((ID3V1Tag)tag).setArtist(value);
+                   if ( tag instanceof ID3V2Tag )
+                     setArtist((ID3V2Tag)tag, value);
+                   break;
+      case ALBUM: if ( tag instanceof ID3V1Tag )
+                    ((ID3V1Tag)tag).setAlbum(value);
+                  if ( tag instanceof ID3V2Tag )
+                    setAlbum((ID3V2Tag)tag, value);
+                  break;
+      case TRACKNO: if ( tag instanceof ID3V1_1Tag )
+                      ((ID3V1_1Tag)tag).setAlbumTrack( value != null ? Integer.parseInt(value) : 0 );
+                    if ( tag instanceof ID3V2Tag )
+                      setTrackNumber((ID3V2Tag)tag, value != null ? Integer.parseInt(value) : null );
+                    break;
+      case TOTALTRACKS: if ( tag instanceof ID3V2Tag )
+                          setTotalTracks((ID3V2Tag)tag, value != null ? Integer.parseInt(value) : null );
+                        break;
+      case GENRE: if ( tag instanceof ID3V1Tag ) {
+                    Genre genre = value != null ? Genre.lookupGenre(value) : null;
+                    ((ID3V1Tag)tag).setGenre(genre);
+                  }
+                  if ( tag instanceof ID3V2Tag )
+                    setGenre((ID3V2Tag)tag, value);
+                  break;
+      case YEAR: if ( tag instanceof ID3V1Tag )
+                   ((ID3V1Tag)tag).setYear(value != null ? value : "");
+                  if ( tag instanceof ID3V2Tag )
+                    setYear((ID3V2Tag)tag, value != null ? Integer.parseInt(value) : null );
+                  break;
+      case COMMENT: if ( tag instanceof ID3V1Tag )
+                      ((ID3V1Tag)tag).setComment(value);
+                    if ( tag instanceof ID3V2Tag )
+                      setComment((ID3V2Tag)tag, value);
+      break;
+    }
+  }
+
+  /**
+   * Converts a ID3 Tag v1.x instance to {@link ID3V1_1aTag} to
+   * Does nothing if given instance already is a {@link ID3V1_1aTag}.
+   */
+  public static ID3V1_1Tag convertToID3V1_1a(ID3V1Tag tag) throws ID3Exception {
+    if ( tag instanceof ID3V1_1aTag )
+      return (ID3V1_1Tag)tag;
+    return createID3V1_1(tag);
+  }
+  
+  /**
+   * Creates a new ID3 Tag v1.1 instance.
+   */
+  public static ID3V1_1Tag createID3V1_1() throws ID3Exception {
+    return new ID3V1_1aTag();
+  }
+  
+  /**
+   * Creates a new ID3 Tag v1.1 instance from existing ID3 Tag v1. If existing tag is not
+   * a v1.1 tag track number will not be set in new tag.
+   * @return empty v1.1 tag if {@code null} is given
+   */
+  public static ID3V1_1Tag createID3V1_1(ID3V1Tag tag) throws ID3Exception {
+    ID3V1_1Tag newTag = createID3V1_1();
+    if ( tag == null )
+      return newTag;
+    newTag.setAlbum( tag.getAlbum() );
+    newTag.setArtist( tag.getArtist() );
+    newTag.setComment( tag.getComment() );
+    newTag.setGenre( tag.getGenre() );
+    newTag.setTitle( tag.getTitle() );
+    newTag.setYear( tag.getYear() );
+    if ( tag instanceof ID3V1_1Tag )
+      newTag.setAlbumTrack( ((ID3V1_1Tag)tag).getAlbumTrack() );
+    return newTag;
+  }
+
+  /**
+   * Creates a new ID3 Tag v1.1 instance from existing ID3 Tag v2.
+   * @return empty v1.1 tag if {@code null} is given
+   */
+  public static ID3V1_1Tag createID3V1_1(ID3V2Tag tag) throws ID3Exception {
+    ID3V1_1Tag newTag = createID3V1_1();
+    if ( tag == null )
+      return newTag;
+    newTag.setAlbum( StringUtils.trimToEmpty(tag.getAlbum()) );
+    newTag.setArtist( StringUtils.trimToEmpty(tag.getArtist()) );
+    newTag.setComment( StringUtils.trimToEmpty(tag.getComment()) );
+    newTag.setGenre( tag.getGenre() == null ? null : Genre.lookupGenre(tag.getGenre()) );
+    newTag.setTitle( StringUtils.trimToEmpty(tag.getTitle()) );
+    Integer year = getYear(tag);
+    newTag.setYear( year == null ? "" : year.toString() );
+    Integer track = getTrackNumber(tag);
+    newTag.setAlbumTrack( track == null ? 0 : track );
+    return newTag;
+  }
+
+  /**
+   * Creates a new ID3 Tag v2.3.0 instance.
+   */
+  public static ID3V2_3_0Tag createID3V2_3_0() throws ID3Exception {
+    return new ID3V2_3_0Tag();
+  }
+  
+  /**
+   * Creates a new ID3 Tag v2.3.0 instance from existing ID3 Tag v1.
+   * @param totalTracks total number of tracks which should be set in created
+   *                    track (because is not specified in v1 tag); can be {@code null}
+   * @return empty v2.3.0 tag if {@code null} is given
+   */
+  public static ID3V2_3_0Tag createID3V2_3_0(ID3V1Tag tag, Integer totalTracks) throws ID3Exception {
+    ID3V2_3_0Tag newTag = createID3V2_3_0();
+    if ( tag == null )
+      return newTag;
+    setAlbum( newTag, tag.getAlbum() );
+    setArtist( newTag, tag.getArtist() );
+    setComment( newTag, tag.getComment() );
+    setGenre( newTag, tag.getGenre() == null ? null : tag.getGenre().toString() );
+    setTitle( newTag, tag.getTitle() );
+    String yearStr = tag.getYear();
+    setYear(newTag,  StringUtils.isBlank(yearStr) ? null : Integer.parseInt(yearStr) );
+    int track = (tag instanceof ID3V1_1Tag) ? ((ID3V1_1Tag)tag).getAlbumTrack() : 0;
+    setTrackInformation(newTag, track <= 0 ? null : track, totalTracks);
+    return newTag;
+  }
+
+  /**
+   * Creates a new ID3 Tag v2.3.0 instance from existing ID3 Tag v2. 
+   * @return empty v2.3.0 tag if {@code null} is given
+   */
+  public static ID3V2_3_0Tag createID3V2_3_0(ID3V2Tag tag) throws ID3Exception {
+    ID3V2_3_0Tag newTag = createID3V2_3_0();
+    if ( tag == null )
+      return newTag;
+    setAlbum(newTag, tag.getAlbum() );
+    setArtist(newTag, tag.getArtist() );
+    setComment(newTag, tag.getComment() );
+    setGenre(newTag, tag.getGenre() );
+    setTitle(newTag, tag.getTitle() );
+    setYear(newTag, tag.getYear() );
+    setTrackNumber(newTag, tag.getTrackNumber() );
+    setTotalTracks(newTag, tag.getTotalTracks() );
+    return newTag;
+  }
+
+
+
+
+
+
+
+
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3V1_1aTag.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3V1_1aTag.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/ID3V1_1aTag.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,98 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3;
+
+import org.blinkenlights.jid3.ID3Exception;
+import org.blinkenlights.jid3.v1.ID3V1Tag;
+
+/**
+ * This class works exactly like {@link org.blinkenlights.jid3.v1.ID3V1_1Tag}, with the
+ * only exception that setting track number 0 leads to no exception! Track number 0
+ * can be treaten as "NULL" track number!
+ * @author Martin O.J. Schmitz
+ */
+public class ID3V1_1aTag extends org.blinkenlights.jid3.v1.ID3V1_1Tag {
+
+  /** Unfortunately the super class field {@code m_iAlbumTrack} is
+   *  declared as private, so it is not possible so set is directly to 0.
+   *  We have to use a flag, which indicates the NULL track number. */
+  protected boolean isNullTrackNo = true;
+  
+  /**
+   * Creates a new tag.
+   */
+  public ID3V1_1aTag() {
+    this(null);
+  }
+
+  /**
+   * Creates a new tag.
+   */
+  public ID3V1_1aTag(ID3V1Tag tag) {
+    super();
+    if ( tag != null ) {
+      setTitle( tag.getTitle() );
+      setArtist( tag.getArtist() );
+      setAlbum( tag.getAlbum() );
+      setGenre( tag.getGenre() );
+      setYear( tag.getYear() );
+      if ( tag instanceof org.blinkenlights.jid3.v1.ID3V1_1Tag )
+        try {
+          setAlbumTrack( ((org.blinkenlights.jid3.v1.ID3V1_1Tag) tag).getAlbumTrack() );
+        } catch (ID3Exception e) {
+          // ignore, should not occur because our setter allows 0 track number
+        }
+    }
+  }
+
+  /**
+   * Set the track number for this title on the album from which it came.
+   * In contrast to super method a track number 0 does not lead to
+   * exception.
+   * @param iAlbumTrack a track number from 0 to 255
+   * @throws ID3Exception if the track number is outside the valid range
+   */
+  @Override
+  public void setAlbumTrack(int iAlbumTrack) throws ID3Exception {
+    isNullTrackNo = ( iAlbumTrack == 0 );
+    if ( !isNullTrackNo )
+      super.setAlbumTrack(iAlbumTrack);
+  }
+
+  /** 
+   * Returns the album track number.
+   */
+  public int getAlbumTrack() {
+    if ( isNullTrackNo )
+      return 0;
+    return super.getAlbumTrack();
+  }
+
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/GUIUtil.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/GUIUtil.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/GUIUtil.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,112 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.io.FileFilter;
+
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+
+import org.apache.log4j.Logger;
+
+import de.schmitzm.io.FilterUtil;
+import de.schmitzm.io.FilterUtil.FilterMode;
+import de.schmitzm.lang.LangUtil;
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.swing.FileExtensionFilter;
+import de.schmitzm.swing.SwingUtil;
+
+/**
+ * Static helper classes for GUI.
+ * @author Martin O.J. Schmitz
+ */
+public class GUIUtil {
+  private static final Logger LOGGER = LangUtil.createLogger(GUIUtil.class);
+
+  /** Font for comment labels in the frames. */
+  public static final Font FONT_COMMENT_LABEL = SwingUtil.DEFAULT_FONT
+      .deriveFont(Font.ITALIC).deriveFont( SwingUtil.DEFAULT_FONT.getSize()-1f );
+  /** Font for header labels in the frames. */
+  public static final Font FONT_HEADER_LABEL = SwingUtil.DEFAULT_FONT
+        .deriveFont(Font.BOLD);
+  /** Font for section labels in the frames. */
+  public static final Font FONT_SECTION_LABEL = SwingUtil.DEFAULT_FONT
+        .deriveFont(Font.BOLD).deriveFont( SwingUtil.DEFAULT_FONT.getSize()+1f );
+  /** Color for section labels in the frames. */
+  public static final Color COLOR_SECTION_LABEL = new Color(0,51,153); // dark blue
+
+  /**  {@link JFileChooser} filter to show only mp3-files.  */
+  public static final FileExtensionFilter FILECHOOSER_FILTER_MP3 = new FileExtensionFilter(ID3TagUtil.R("ID3TagUtil.mp3filter.desc"), true, ".mp3");
+  /**  {@link FileFilter} filter to show only mp3-files.  */
+  public static final FileFilter FILE_FILTER_MP3 = FilterUtil.createSimpleFileFilter("*.mp3", FilterMode.FILES_ONLY);
+
+  
+  /**
+  * Creates a {@link JLabel} styled as header label in
+  * {@link KontaktInformationPanel}.
+  */
+  public static JLabel createHeaderLabel(String caption) {
+    JLabel label = new JLabel(caption);
+    label.setFont(FONT_HEADER_LABEL);
+    return label;
+  }
+  
+  /**
+  * Creates a {@link JLabel} styled as header label in
+  * {@link KontaktInformationPanel}.
+  */
+  public static JLabel createSectionLabel(String caption) {
+    JLabel label = new JLabel(caption);
+    label.setFont(FONT_SECTION_LABEL);
+    label.setForeground(COLOR_SECTION_LABEL);
+    return label;
+  }
+
+  /**
+  * Creates a {@link JLabel} styled to show a comment in
+  * {@link KontaktInformationPanel}.
+  */
+  public static JLabel createCommentLabel(String caption) {
+    JLabel label = new JLabel(caption);
+    label.setFont(FONT_COMMENT_LABEL);
+    return label;
+  }
+  
+  /**
+  * Creates a {@link JLabel} styled to show normal (read-only) content in
+  * {@link KontaktInformationPanel}.
+  */
+  public static JLabel createContentLabel(String caption) {
+    JLabel label = new JLabel(caption);
+    return label;
+  }
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3Tag2FilenameParserPanel.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3Tag2FilenameParserPanel.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3Tag2FilenameParserPanel.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,247 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import java.awt.Font;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+import javax.swing.event.CaretEvent;
+import javax.swing.event.CaretListener;
+import javax.swing.event.ListDataEvent;
+import javax.swing.event.ListDataListener;
+
+import net.miginfocom.swing.MigLayout;
+
+import org.apache.commons.lang.StringUtils;
+
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.mp3.id3.io.ID3Tag2FilenameParser;
+import de.schmitzm.swing.JPanel;
+import de.schmitzm.swing.JToggleButtonLabel;
+import de.schmitzm.swing.LimitedDocument;
+import de.schmitzm.swing.SwingUtil;
+
+/**
+ * Panel to configure a {@link ID3Tag2FilenameParser}.
+ * @author Martin O.J. Schmitz
+ */
+public class ID3Tag2FilenameParserPanel extends JPanel implements ActionListener, CaretListener, ListDataListener {
+  /** Holds the parser which is currently configured by the panel. */
+  protected ID3Tag2FilenameParser parser;
+  
+  protected ID3TagFieldSequencePanel sequence;
+  protected JTextField delim;
+  protected JLabel delimCaption;
+  protected JCheckBox spaces;
+  protected JLabel spacesCaption;
+  protected JLabel numberFormatDesc;
+  protected JTextField trackNoFormat;
+  protected JLabel trackNoFormatCaption;
+  protected JLabel trackNoFormatExample;
+  protected JTextField yearFormat;
+  protected JLabel yearFormatCaption;
+  protected JLabel yearFormatExample;
+  protected JLabel preview;
+
+  /** Flag which avoids that update listener methods re-call {@link #updatePreview()}
+   *  during preview / gui update. */
+  protected boolean valueIsAdjusting = false;
+  
+  /**
+   * Creates panel with default settings.
+   */
+  public ID3Tag2FilenameParserPanel() {
+    this(null);
+  }
+  
+  
+  /**
+   * Creates panel with settings according to given parser.
+   */
+  public ID3Tag2FilenameParserPanel(ID3Tag2FilenameParser parser) {
+    super( new MigLayout("wrap 4","[]8[]20[][grow]","top") );
+    this.parser = parser != null ? parser : new ID3Tag2FilenameParser( ID3Tag2FilenameParser.DEFAULT_PARSER );
+    
+    this.sequence = new ID3TagFieldSequencePanel();
+    sequence.addListDataListener(this);
+    sequence.setBorder( BorderFactory.createEmptyBorder(0,0,0,0) );
+    this.delim = SwingUtil.createLimitedTextField(1, LimitedDocument.STYLE_BASIC_STRING);
+    delim.addCaretListener(this);
+    delim.setHorizontalAlignment(JTextField.CENTER);
+    delim.setText("-");
+    this.delimCaption = new JLabel(ID3TagUtil.R("ID3Tag2FilenameParserPanel.delim"));
+    this.spaces = new JCheckBox();
+    spaces.setSelected(true);
+    spaces.addActionListener(this);
+    this.spacesCaption = new JToggleButtonLabel(spaces,ID3TagUtil.R("ID3Tag2FilenameParserPanel.spaces"));
+    this.numberFormatDesc = GUIUtil.createHeaderLabel(ID3TagUtil.R("ID3Tag2FilenameParserPanel.numberFormat"));
+    this.trackNoFormat = new JTextField("");
+    this.trackNoFormatCaption = GUIUtil.createContentLabel(ID3TagUtil.R("ID3Tag2FilenameParserPanel.numberFormat.trackNo"));
+    this.trackNoFormatExample = GUIUtil.createCommentLabel(ID3TagUtil.R("ID3Tag2FilenameParserPanel.numberFormat.trackNo.example"));
+    this.yearFormat = new JTextField("");
+    this.yearFormatCaption = GUIUtil.createContentLabel(ID3TagUtil.R("ID3Tag2FilenameParserPanel.numberFormat.year"));
+    this.yearFormatExample = GUIUtil.createCommentLabel(ID3TagUtil.R("ID3Tag2FilenameParserPanel.numberFormat.year.example"));
+    
+    
+    this.preview = GUIUtil.createCommentLabel("");
+    preview.setFont( preview.getFont().deriveFont( Font.BOLD+Font.ITALIC ) );
+    
+    add(delimCaption,"aligny center");
+    add(delim,"w 20!");
+    add(spaces,"");
+    add(spacesCaption,"");
+//    add(numberFormatDesc, "span 4");
+    add(trackNoFormatCaption, "aligny center");
+    add(trackNoFormat, "w 50::, span 3, split 2");
+    add(trackNoFormatExample, "");
+    add(yearFormatCaption, "aligny center");
+    add(yearFormat, "w 50::, span 3, split 2");
+    add(yearFormatExample, "");
+    add(sequence,"span 4, growx, growy");
+    add(preview,"center, span 4");
+   
+    updateGUI();
+  }
+  
+  /**
+   * Updates the preview label.
+   */
+  protected void updatePreview() {
+    if ( preview != null )
+      preview.setText( "\"" + getParser().getSequenceStr()+".mp3\"" );
+  }
+  
+
+  /**
+   * Updates the GUI components according to the given format. 
+   */
+  public void updateGUI(ID3Tag2FilenameParser parser) {
+    this.valueIsAdjusting = true;
+    String delimStr = parser.getDelimiter();
+    String delimChar = StringUtils.trimToEmpty(parser.getDelimiter()); 
+    delim.setText( delimChar.length() > 1 ? delimChar.substring(0,1): delimChar );
+    spaces.setSelected( delimStr.startsWith(" ") );
+    sequence.setSequence( parser.getSequence() );
+    trackNoFormat.setText( parser.getTrackNoFormat().toPattern() );
+    yearFormat.setText( parser.getYearFormat().toPattern() );
+    updatePreview();
+    this.valueIsAdjusting = false;
+  }
+  
+  /**
+   * Updates the GUI components.. 
+   */
+  public void updateGUI() {
+    updateGUI(parser);
+  }
+
+  /**
+   * Updates a parser configuration according to the current panel settings.
+   */
+  public ID3Tag2FilenameParser updateParser(ID3Tag2FilenameParser parser) {
+    if ( parser == null )
+      parser = new ID3Tag2FilenameParser();
+    String delimStr = delim.getText();
+    if ( spaces.isSelected() )
+      delimStr = " "+delimStr+" ";
+    parser.setDelimiter(delimStr);
+    parser.setSequence(sequence.getSequence());
+    parser.setTrackNoFormat(StringUtils.trimToNull(trackNoFormat.getText()));
+    parser.setYearFormat(StringUtils.trimToNull(yearFormat.getText()));
+    return parser;
+  }
+  
+  /**
+   * Returns a parser configured according to the current panel settings.
+   */
+  public ID3Tag2FilenameParser getParser() {
+    return updateParser(parser);
+  }
+
+
+  /**
+   * Updates the preview (when {@link #delim} changes).
+   */
+  @Override
+  public void actionPerformed(ActionEvent e) {
+    if ( valueIsAdjusting )
+      return;
+    updatePreview();
+  }
+
+
+  /**
+   * Updates the preview (when {@link #spaces} changes).
+   */
+  @Override
+  public void caretUpdate(CaretEvent e) {
+    if ( valueIsAdjusting )
+      return;
+    updatePreview();
+  }
+
+
+  /**
+   * Updates the preview (when {@link #sequence} changes).
+   */
+  @Override
+  public void intervalAdded(ListDataEvent e) {
+    if ( valueIsAdjusting )
+      return;
+    updatePreview();
+  }
+
+
+  /**
+   * Updates the preview (when {@link #sequence} changes).
+   */
+  @Override
+  public void intervalRemoved(ListDataEvent e) {
+    if ( valueIsAdjusting )
+      return;
+    updatePreview();
+  }
+
+
+  /**
+   * Updates the preview (when {@link #sequence} changes).
+   */
+  @Override
+  public void contentsChanged(ListDataEvent e) {
+    if ( valueIsAdjusting )
+      return;
+    updatePreview();
+  }
+}
\ No newline at end of file

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagFieldSequencePanel.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagFieldSequencePanel.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagFieldSequencePanel.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,269 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListDataListener;
+
+import net.miginfocom.swing.MigLayout;
+import de.schmitzm.mp3.id3.ID3TagField;
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.mp3.id3.io.ID3Tag2FilenameParser;
+import de.schmitzm.swing.JPanel;
+import de.schmitzm.swing.ListMaintainancePanel;
+import de.schmitzm.swing.dnd.JListTransferHandler;
+import de.schmitzm.swing.dnd.ListingTransferHandler;
+
+/**
+ * Panel to define a sequence of {@link ID3TagField} to specify the format
+ * for {@link ID3Tag2FilenameParser}. 
+ * @author Martin O.J. Schmitz
+ *
+ */
+public class ID3TagFieldSequencePanel extends JPanel {
+  protected JLabel fieldSequenceCaption;
+  protected ListMaintainancePanel<ID3TagField> fieldSequence;
+  protected JLabel availableFieldsCaption;
+  protected ListMaintainancePanel<ID3TagField> availableFields;
+  
+  /**
+   * Creates a new panel.
+   */
+  public ID3TagFieldSequencePanel() {
+    super( new MigLayout("wrap 2","0[grow][grow]0","0[top]") );
+    
+    fieldSequenceCaption = GUIUtil.createHeaderLabel( ID3TagUtil.R("ID3TagFieldSequencePanel.fields.sequence")+":");
+    fieldSequence = new ListMaintainancePanel<ID3TagField>(true, true, false, true) {
+      @Override
+      protected ID3TagField[] createNewElements() {
+        // new elements are the selected elements in availableFields
+        List<ID3TagField> selectedValues = availableFields.getSelectedElements();
+        return selectedValues != null ? selectedValues.toArray(new ID3TagField[0]) : null;
+      }
+      @Override
+      public void updateActions() {
+        super.updateActions();
+        if ( availableFields == null ) // avoid exception in initializer 
+          return;
+        // ADD action only enabled if elements in "availableFields" are selected
+        boolean listSelected = availableFields.getList().getSelectedIndices().length > 0;
+        boolean panelEnabled = isEnabled();
+        if ( addAction != null )
+          addAction.setEnabled( panelEnabled && listSelected );
+      }
+      @Override
+      public void addElement(int idx, ID3TagField element) {
+        super.addElement(idx, element);
+        availableFields.removeElement(element);
+      }
+      @Override
+      public void removeElement(ID3TagField element) {
+        super.removeElement(element);
+        availableFields.addElement(element);
+      }
+    };
+    fieldSequence.getList().setCellRenderer(ID3TagFieldCellRenderer.DEFAULT);
+    fieldSequence.getList().setSelectionMode( ListSelectionModel.SINGLE_INTERVAL_SELECTION );
+
+    availableFieldsCaption = GUIUtil.createHeaderLabel( ID3TagUtil.R("ID3TagFieldSequencePanel.fields.available")+":");
+    availableFields = new ListMaintainancePanel<ID3TagField>(false,false,false,false);
+    availableFields.getList().setCellRenderer(ID3TagFieldCellRenderer.DEFAULT);
+    availableFields.getList().addListSelectionListener( fieldSequence );
+    
+    // Activate Drag&Drop from available fields to field sequence 
+    ListingTransferHandler<JList> th = new JListTransferHandler(true,fieldSequence.getList(), availableFields.getList()) {
+      @Override
+      protected boolean checkDragDropAllowed(Component fromList, Component toList) {
+        // reorder only allowed for sequence list
+        if ( fromList == toList && fromList != fieldSequence.getList() )
+          return false;
+        return super.checkDragDropAllowed(fromList, toList);
+      }
+
+      @Override
+      protected void reorderListItems(JList list, int[] selectedIdx, int fromIdx, int toIdx) {
+        if ( list != fieldSequence.getList() )
+          return;
+        List<ID3TagField> selectedValues = fieldSequence.getSelectedElements();
+        int firstIdx = selectedIdx[0];
+        int lastIdx  = selectedIdx[selectedIdx.length-1];
+        if ( toIdx == fromIdx )
+          return;
+        // MOVE UP
+        if ( toIdx < fromIdx ) {
+          if ( firstIdx > 0 ) {
+            fieldSequence.getModel().removeRange(firstIdx, lastIdx);
+            fieldSequence.getModel().addElements(toIdx, selectedValues);
+            fieldSequence.getList().addSelectionInterval(toIdx, toIdx+selectedIdx.length-1);
+          }
+        }
+        // MOVE DOWN
+        if ( toIdx > fromIdx ) {
+          if ( lastIdx < fieldSequence.getModel().getSize()-1 ) {
+            int moveDist = toIdx - lastIdx - 1;
+            if ( moveDist > 0 ) {
+              fieldSequence.getModel().removeRange(firstIdx, lastIdx);
+              // because elements are already removed, insert index changes by
+              // number of (re)moved elements
+              toIdx = toIdx - selectedIdx.length;
+              fieldSequence.getModel().addElements(toIdx, selectedValues);
+              fieldSequence.getList().addSelectionInterval(toIdx,  toIdx+selectedIdx.length-1);
+            }
+          }
+          
+        }
+      }
+
+      @Override
+      protected void moveListItems(JList fromList, int[] selIdx, int from, JList toList, int toIdx) {
+        List<ID3TagField> selectedValues = fromList.getSelectedValuesList();
+        ((ListMaintainancePanel<ID3TagField>.ListModel<ID3TagField>)fromList.getModel()).removeElements(selectedValues);
+        ((ListMaintainancePanel<ID3TagField>.ListModel<ID3TagField>)toList.getModel()).addElements(toIdx,selectedValues);
+      }
+    };
+    th.initializeLists();
+    
+    clearSequence();
+    
+    add(fieldSequenceCaption,"");
+    add(availableFieldsCaption,"");
+    add(fieldSequence,"sgxFIELDS, growx, growy");
+    add(availableFields,"sgxFIELDS, growx, growy");
+  }
+  
+  /**
+   * Adds a {@link ListDataListener} to the {@linkplain #fieldSequence field sequence list}
+   * which is informed on each sequence change.
+   */
+  public void addListDataListener(ListDataListener l) {
+    fieldSequence.getList().getModel().addListDataListener(l);
+  }
+  
+  /**
+   * Removes a {@link ListDataListener} from the {@linkplain #fieldSequence field sequence list}.
+   */
+  public void removeListDataListener(ListDataListener l) {
+    fieldSequence.getList().getModel().removeListDataListener(l);
+  }
+
+  /**
+   * Removes all list entries from field sequence and puts them back to
+   * available fields. 
+   */
+  public void clearSequence() {
+    // remove all entries from field sequence
+    fieldSequence.clearList();
+    // initialize available field with all fields
+    availableFields.setData( new ArrayList<ID3TagField>(Arrays.asList( ID3TagField.values() )));
+  }
+
+  /**
+   * Initializes the field sequence from given list. 
+   */
+  public void setSequence(List<ID3TagField> sequence) {
+    clearSequence();
+    for (ID3TagField f : sequence)
+      addSequenceField(f);
+  }
+  
+  /**
+   * Moves a field from available fields to field sequence. Does nothing if
+   * given field is already in field sequence list. 
+   */
+  public void addSequenceField(int idx, ID3TagField field) {
+    if ( !availableFields.getModel().contains(field) )
+      return;
+    // remove field from available fields
+    availableFields.removeElement(field);
+    // add field to sequence
+    if ( idx >= 0 )
+      fieldSequence.getModel().insertElementAt(field, idx);
+    else
+      fieldSequence.getModel().addElement(field);
+  }
+  
+  /**
+   * Moves a field from available fields to field sequence. Does nothing if
+   * given field is already in field sequence list. 
+   */
+  public void addSequenceField(ID3TagField field) {
+    addSequenceField(-1,field);
+  }
+  
+  /**
+   * Moves a field from field sequence to  available fields. Does nothing if
+   * given field is already in available fields list. 
+   */
+  public void removeSequenceField(ID3TagField field) {
+    if ( !availableFields.getModel().contains(field) )
+      return;
+    // remove field from sequence
+    fieldSequence.removeElement(field);
+    // add field to available fields
+    availableFields.addElement(field);
+  }
+  
+  /**
+   * Returns the sequence of {@link ID3TagField} specified by
+   * the panel.
+   */
+  public List<ID3TagField> getSequence() {
+    return fieldSequence.getData();
+  }
+  
+  /**
+   * {@link ListCellRenderer} which shows the {@linkplain ID3TagField#getTitle() field title}.
+   * @author Martin O.J. Schmitz
+   *
+   */
+  public static class ID3TagFieldCellRenderer extends DefaultListCellRenderer {
+    public static final ID3TagFieldCellRenderer DEFAULT = new ID3TagFieldCellRenderer();
+    @Override
+    public Component getListCellRendererComponent(
+        JList<?> list, Object value, int index,
+        boolean isSelected, boolean cellHasFocus) {
+      ID3TagField field = (ID3TagField)value;
+      if ( value != null )
+        value = field.getTitle();
+      return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+    }
+  }
+
+
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagPanel.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagPanel.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagPanel.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,237 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import java.awt.Component;
+import java.util.ArrayList;
+import java.util.List;
+
+import net.miginfocom.swing.MigLayout;
+
+import org.apache.commons.lang.StringUtils;
+import org.blinkenlights.jid3.ID3Exception;
+import org.blinkenlights.jid3.ID3Tag;
+
+import de.schmitzm.mp3.id3.ID3TagField;
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.swing.JPanel;
+import de.schmitzm.swing.input.BooleanInputOption;
+import de.schmitzm.swing.input.InputOption;
+import de.schmitzm.swing.input.ManualInputOption;
+import de.schmitzm.swing.input.SelectionInputOption;
+
+/**
+ * Abstract panel which shows all ID3Tag options.
+ * @author Martin O.J. Schmitz
+ */
+public abstract class ID3TagPanel<ID3 extends ID3Tag, GENRE> extends JPanel {
+  /** Empty dummy panel */
+  private static final ID3TagPanel<?, ?> EMPTY_PANEL = new ID3TagV1Panel();
+  
+  
+  protected BooleanInputOption titleCheckbox;
+  protected ManualInputOption.Text title;
+  protected BooleanInputOption artistCheckbox;
+  protected ManualInputOption.Text artist;
+  protected BooleanInputOption albumCheckbox;
+  protected ManualInputOption.Text album;
+  protected BooleanInputOption trackNoCheckbox;
+  protected ManualInputOption.Integer trackNo;
+  protected BooleanInputOption yearCheckbox;
+  protected ManualInputOption.Integer year;
+  protected BooleanInputOption genreCheckbox;
+  protected SelectionInputOption.Combo<GENRE> genre;
+  protected BooleanInputOption commentCheckbox;
+  protected ManualInputOption.Text comment;
+  
+  public ID3TagPanel() {
+    super( new MigLayout("wrap 2","[][grow]","[top]") );
+
+    title = new ManualInputOption.Text(null);
+    titleCheckbox = new BooleanInputOption(ID3TagUtil.R("ID3Tag.Title"), false);
+    titleCheckbox.connectInputOptions(true,title);
+    artist = new ManualInputOption.Text(null);
+    artistCheckbox = new BooleanInputOption(ID3TagUtil.R("ID3Tag.Artist"), false);
+    artistCheckbox.connectInputOptions(true,artist);
+    album = new ManualInputOption.Text(null);
+    albumCheckbox = new BooleanInputOption(ID3TagUtil.R("ID3Tag.Album"), false);
+    albumCheckbox.connectInputOptions(true,album);
+    trackNo = new ManualInputOption.Integer(null);
+    trackNoCheckbox = new BooleanInputOption(ID3TagUtil.R("ID3Tag.TrackNo"), false);
+    trackNoCheckbox.connectInputOptions(true,trackNo);
+    year = new ManualInputOption.Integer(null);
+    yearCheckbox = new BooleanInputOption(ID3TagUtil.R("ID3Tag.Year"), false);
+    yearCheckbox.connectInputOptions(true,year);
+    genre = new SelectionInputOption.Combo<GENRE>(null,false);
+    genreCheckbox = new BooleanInputOption(ID3TagUtil.R("ID3Tag.Genre"), false);
+    genreCheckbox.connectInputOptions(true,genre);
+    comment = new ManualInputOption.Text(null);
+    commentCheckbox = new BooleanInputOption(ID3TagUtil.R("ID3Tag.Comment"), false);
+    commentCheckbox.connectInputOptions(true,comment);
+
+    titleCheckbox.setValue(false);
+    artistCheckbox.setValue(false);
+    albumCheckbox.setValue(false);
+    trackNoCheckbox.setValue(false);
+    yearCheckbox.setValue(false);
+    genreCheckbox.setValue(false);
+    commentCheckbox.setValue(false);
+    
+    add(titleCheckbox,"");
+    add(title,"growx");
+    add(artistCheckbox,"");
+    add(artist,"growx");
+    add(albumCheckbox,"");
+    add(album,"growx");
+    add(trackNoCheckbox,"");
+    add(trackNo,"w 50, sgxTrackYear");
+    add(yearCheckbox,"");
+    add(year,"w 50, sgxTrackYear");
+    add(genreCheckbox,"");
+    add(genre,"growx");
+    add(commentCheckbox,"");
+    add(comment,"growx");
+    
+  }
+  
+  /**
+   * Returns a list of the input components of the {@link ID3TagPanel}.
+   */
+  public List<InputOption<?>> getInputOptions() {
+    List<InputOption<?>> ioList = new ArrayList<InputOption<?>>();
+    for (Component c : getComponents())
+      if ( c instanceof InputOption )
+        ioList.add((InputOption<?>)c);
+    return ioList;
+  }
+  
+  /**
+   * Returns whether at least on of the tag fields is enabled.
+   */
+  public boolean isFieldEnabled() {
+    for (Component c : getComponents())
+      if ( c instanceof BooleanInputOption && ((BooleanInputOption)c).getValue() )
+        return true;
+    return false;
+  }
+  
+  /**
+   * Returns whether a tag fields is enabled.
+   */
+  public boolean isFieldEnabled(ID3TagField field) {
+    switch (field) {
+      case TITLE: return titleCheckbox.getValue();
+      case ARTIST: return artistCheckbox.getValue();
+      case ALBUM: return albumCheckbox.getValue();
+      case TRACKNO: return trackNoCheckbox.getValue();
+      case GENRE: return genreCheckbox.getValue();
+      case YEAR: return yearCheckbox.getValue();
+      case COMMENT: return commentCheckbox.getValue();    
+    }
+    return false;
+  }
+  
+  /**
+   * Clears the fields in the panel regardless whether fields are
+   * activated or not.
+   */
+  public void clear() {
+    clear(true);
+  }
+
+  /**
+   * Clears the fields in the panel.
+   * @param force if {@code true} all fields are cleared regardless whether
+   *              field is active or not; if {@code false} only these values
+   *              are cleared which are activated 
+   */
+  public void clear(boolean force) {
+    setValues(EMPTY_PANEL, force);
+  }
+  
+  /**
+   * Updates the panel from another panel.
+   * @param panel panel to copy the values from
+   * @param force if {@code true} all fields are set regardless whether
+   *              field is active or not; if {@code false} only these values
+   *              are set which are activated 
+   */
+  public void setValues(ID3TagPanel<?, ?> panel, boolean force) {
+    if ( force || titleCheckbox.getValue() )
+      title.setValue( StringUtils.trimToEmpty(panel.title.getValue()) );
+    if ( force || artistCheckbox.getValue() )
+      artist.setValue( StringUtils.trimToEmpty(panel.artist.getValue()) );
+    if ( force || albumCheckbox.getValue() )
+      album.setValue( StringUtils.trimToEmpty(panel.album.getValue()) );
+    if ( force || yearCheckbox.getValue() )
+      year.setValue( panel.year.getValue() );
+    if ( force || genreCheckbox.getValue() )
+      genre.setSelectedDisplayItem( panel.genre.getSelectedDisplayItem() );
+    if ( force || commentCheckbox.getValue() )
+      comment.setValue( StringUtils.trimToEmpty(panel.comment.getValue()) );
+    if ( force || trackNoCheckbox.getValue() )
+      trackNo.setValue( panel.trackNo.getValue() );
+  }
+
+  /**
+   * Updates the panel from an ID3Tag regardless whether fields are
+   * activated or not.
+   * @param tag ID3Tag to update the panel with
+   */
+  public void setValues(ID3 tag) throws ID3Exception {
+    setValues(tag, true);
+  }
+
+  /**
+   * Updates the panel from an ID3Tag.
+   * @param tag ID3Tag to update the panel with
+   * @param force if {@code true} all fields are set regardless whether
+   *              field is active or not; if {@code false} only these values
+   *              are set which are activated 
+   */
+  public abstract void setValues(ID3 tag, boolean force) throws ID3Exception;
+  
+  /**
+   * Updates an ID3Tag from panel.
+   * @param tag ID3Tag to update
+   */
+  public abstract void updateID3Tag(ID3 tag) throws ID3Exception;
+
+  /**
+   * Creates an ID3Tag from panel.
+   */
+  public abstract ID3 createID3Tag() throws ID3Exception;
+
+  /**
+   * Copies ID3-Tag field values from {@code tag1} to {@code tag2}, but
+   * only for these fields which are activated in the panel. 
+   */
+  public abstract void copyValues(ID3 tag1, ID3 tag2) throws ID3Exception;
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV1Panel.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV1Panel.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV1Panel.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,160 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import org.apache.commons.lang.StringUtils;
+import org.blinkenlights.jid3.ID3Exception;
+import org.blinkenlights.jid3.v1.ID3V1Tag;
+import org.blinkenlights.jid3.v1.ID3V1Tag.Genre;
+import org.blinkenlights.jid3.v1.ID3V1_1Tag;
+
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.swing.LimitedDocument;
+
+/**
+ * Panel which shows all ID3Tag v1 options.
+ * @author Martin O.J. Schmitz
+ */
+public class ID3TagV1Panel extends ID3TagPanel<ID3V1Tag, Genre> {
+  
+  /**
+   * Creates a new panel.
+   */
+  public ID3TagV1Panel() {
+    super();
+    // initialize genre
+    genre.setSelectionObjects(ID3TagUtil.ALL_GENRE_ID3V1, ID3TagUtil.ALL_GENRE_TITLES_ID3V1);
+    // limit input on text fields
+    title.setDocument(new LimitedDocument(ID3TagUtil.ID3V1_LENGTH_TITLE, LimitedDocument.STYLE_NO_LIMIT));
+    artist.setDocument(new LimitedDocument(ID3TagUtil.ID3V1_LENGTH_ARTIST, LimitedDocument.STYLE_NO_LIMIT));
+    album.setDocument(new LimitedDocument(ID3TagUtil.ID3V1_LENGTH_ALBUM, LimitedDocument.STYLE_NO_LIMIT));
+    trackNo.setDocument(new LimitedDocument(ID3TagUtil.ID3V1_LENGTH_TRACKNO, LimitedDocument.STYLE_INTEGER));
+    year.setDocument(new LimitedDocument(ID3TagUtil.ID3V1_LENGTH_YEAR, LimitedDocument.STYLE_NO_LIMIT));
+    comment.setDocument(new LimitedDocument(ID3TagUtil.ID3V1_LENGTH_COMMENT, LimitedDocument.STYLE_NO_LIMIT));
+
+  }
+  
+  /**
+   * Updates the panel from an ID3Tag.
+   * @param tag ID3Tag to update the panel with
+   * @param force if {@code true} all fields are set regardless whether
+   *              field is active or not; if {@code false} only these values
+   *              are set which are activated 
+   */
+  @Override
+  public void setValues(ID3V1Tag tag, boolean force) {
+    if( tag == null ) {
+      title.setValue( null );
+      artist.setValue( null );
+      album.setValue( null );
+      trackNo.setValue( null );
+      year.setValue( null );
+      genre.setValue( null );
+      comment.setValue( null );
+      return;
+    }
+    if ( force || titleCheckbox.getValue() )
+      title.setValue( StringUtils.trimToEmpty(tag.getTitle()) );
+    if ( force || artistCheckbox.getValue() )
+      artist.setValue( StringUtils.trimToEmpty(tag.getArtist()) );
+    if ( force || albumCheckbox.getValue() )
+      album.setValue( StringUtils.trimToEmpty(tag.getAlbum()) );
+    if ( force || yearCheckbox.getValue() )
+      year.setValue( tag.getYear() );
+    if ( force || titleCheckbox.getValue() )
+      genre.setValue( tag.getGenre() );
+    if ( force || commentCheckbox.getValue() )
+      comment.setValue( StringUtils.trimToEmpty(tag.getComment()) );
+    if ( force || trackNoCheckbox.getValue() )
+      trackNo.setValue( tag instanceof ID3V1_1Tag ? ((ID3V1_1Tag)tag).getAlbumTrack() : null);
+  }
+  
+  /**
+   * Updates an ID3Tag from panel.
+   * @param tag ID3Tag to update
+   */
+  @Override
+  public void updateID3Tag(ID3V1Tag tag) throws ID3Exception {
+    if( tag == null )
+      return;
+    if ( titleCheckbox.getValue() )
+      tag.setTitle( StringUtils.trimToEmpty(title.getValue()) );
+    if ( artistCheckbox.getValue() )
+      tag.setArtist( StringUtils.trimToEmpty(artist.getValue()) );
+    if ( albumCheckbox.getValue() )
+      tag.setAlbum( StringUtils.trimToEmpty(album.getValue()) );
+    if ( yearCheckbox.getValue() )
+      tag.setYear( year.getValue() == null ? null : year.getValue().toString() );
+    if ( genreCheckbox.getValue() )
+      tag.setGenre( (Genre)genre.getValue() );
+    if ( commentCheckbox.getValue() )
+      tag.setComment( StringUtils.trimToEmpty(comment.getValue()) );
+    if ( trackNoCheckbox.getValue() && tag instanceof ID3V1_1Tag ) {
+      Integer track = trackNo.getValue();
+      if ( track == null )
+        track = 0;
+      ((ID3V1_1Tag)tag).setAlbumTrack( track );
+    }
+  }
+  
+  /**
+   * Creates an ID3Tag from panel.
+   */
+  @Override
+  public ID3V1Tag createID3Tag() throws ID3Exception {
+    ID3V1Tag tag = ID3TagUtil.createID3V1_1();
+    updateID3Tag(tag);
+    return tag;
+  }
+
+  /**
+   * Copies ID3-Tag field values from {@code tag1} to {@code tag2}, but
+   * only for these fields which are activated in the panel. 
+   */
+  @Override
+  public void copyValues(ID3V1Tag tag1, ID3V1Tag tag2) throws ID3Exception {
+    if( tag1 == null || tag2 == null )
+      return;
+    if ( titleCheckbox.getValue() )
+      tag2.setTitle( tag1.getTitle() );
+    if ( artistCheckbox.getValue() )
+      tag2.setArtist( tag1.getArtist() );
+    if ( albumCheckbox.getValue() )
+      tag2.setAlbum( tag1.getAlbum() );
+    if ( yearCheckbox.getValue() )
+      tag2.setYear( tag1.getYear() );
+    if ( genreCheckbox.getValue() )
+      tag2.setGenre( tag1.getGenre() );
+    if ( commentCheckbox.getValue() )
+      tag2.setComment( tag1.getComment() );
+    if ( trackNoCheckbox.getValue() && tag1 instanceof ID3V1_1Tag  && tag2 instanceof ID3V1_1Tag )
+      ((ID3V1_1Tag)tag2).setAlbumTrack( ((ID3V1_1Tag)tag1).getAlbumTrack() );
+  }
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV2Panel.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV2Panel.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/ID3TagV2Panel.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,198 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import javax.swing.JLabel;
+
+import org.blinkenlights.jid3.ID3Exception;
+import org.blinkenlights.jid3.v2.ContentType.Genre;
+import org.blinkenlights.jid3.v2.ID3V2Tag;
+
+import de.schmitzm.mp3.id3.ID3TagField;
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.swing.input.BooleanInputOption;
+import de.schmitzm.swing.input.ManualInputOption;
+
+/**
+ * Panel which shows all ID3Tag v2 options.
+ * @author Martin O.J. Schmitz
+ */
+public class ID3TagV2Panel extends ID3TagPanel<ID3V2Tag, Genre> {
+  protected JLabel totalTracksCaption;
+  protected BooleanInputOption totalTracksCheckbox;
+  protected ManualInputOption.Integer totalTracks;
+
+  /**
+   * Creates a new panel.
+   */
+  public ID3TagV2Panel() {
+    super();
+    // initialize genre
+    genre.setSelectionObjects( ID3TagUtil.ALL_GENRE_ID3V2, ID3TagUtil.ALL_GENRE_TITLES_ID3V2);
+    
+    totalTracksCaption = GUIUtil.createContentLabel(ID3TagUtil.R("ID3Tag.of"));
+    totalTracks = new ManualInputOption.Integer(null);
+    totalTracksCheckbox = new BooleanInputOption(null, false);
+    totalTracksCheckbox.connectInputOptions(true,totalTracks);
+    
+    add(totalTracksCaption,"aligny center, cell 1 3, gap 7! 7!");
+    add(totalTracksCheckbox,"cell 1 3");
+    add(totalTracks,"cell 1 3, w 50");
+  }
+
+  /**
+   * Returns whether a tag fields is enabled.
+   */
+  @Override
+  public boolean isFieldEnabled(ID3TagField field) {
+    switch (field) {
+      case TOTALTRACKS: return totalTracksCheckbox.getValue();
+    }
+    return super.isFieldEnabled(field);
+  }
+
+  /**
+   * Clears the fields in the panel.
+   * @param force if {@code true} all fields are cleared regardless whether
+   *              field is active or not; if {@code false} only these values
+   *              are cleared which are activated 
+   */
+  @Override
+  public void clear(boolean force) {
+    super.clear(force);
+    if ( force || totalTracksCheckbox.getValue() )
+      totalTracks.setValue(null);
+  }
+  
+
+  /**
+   * Updates the panel from an ID3Tag.
+   * @param tag ID3Tag to update the panel with
+   * @param force if {@code true} all fields are set regardless whether
+   *              field is active or not; if {@code false} only these values
+   *              are set which are activated 
+   */
+  @Override
+  public void setValues(ID3V2Tag tag, boolean force) throws ID3Exception {
+    if( tag == null ) {
+      title.setValue( null );
+      artist.setValue( null );
+      album.setValue( null );
+      trackNo.setValue( null );
+      totalTracks.setValue( null );
+      year.setValue( null );
+      genre.setValue( null );
+      comment.setValue( null );
+      // TODO: add more ID3v2 options
+      return;
+    }
+    if ( force || titleCheckbox.getValue() )
+      title.setValue( tag.getTitle() );
+    if ( force || artistCheckbox.getValue() )
+      artist.setValue( tag.getArtist() );
+    if ( force || albumCheckbox.getValue() )
+      album.setValue( tag.getAlbum() );
+    if ( force || trackNoCheckbox.getValue() )
+      trackNo.setValue( ID3TagUtil.getTrackNumber(tag) );
+    if ( force || totalTracksCheckbox.getValue() )
+      totalTracks.setValue( ID3TagUtil.getTotalTracks(tag) );
+    if ( force || yearCheckbox.getValue() )
+      year.setValue( ID3TagUtil.getYear(tag) );
+    if ( force || genreCheckbox.getValue() )
+      genre.setSelectedDisplayItem( tag.getGenre() );
+    if ( force || commentCheckbox.getValue() )
+      comment.setValue( tag.getComment() );
+    // TODO: add more ID3v2 options
+  }
+  
+  /**
+   * Updates an ID3Tag from panel.
+   * @param tag ID3Tag to update
+   */
+  @Override
+  public void updateID3Tag(ID3V2Tag tag) throws ID3Exception {
+    if( tag == null )
+      return;
+    if ( titleCheckbox.getValue() )
+      ID3TagUtil.setTitle(tag, title.getValue());
+    if ( artistCheckbox.getValue() )
+      ID3TagUtil.setArtist(tag, artist.getValue());
+    if ( albumCheckbox.getValue() )
+      ID3TagUtil.setAlbum(tag, album.getValue());
+    if ( trackNoCheckbox.getValue() )
+      ID3TagUtil.setTrackNumber(tag, trackNo.getValue());
+    if ( totalTracksCheckbox.getValue() )
+      ID3TagUtil.setTotalTracks(tag, totalTracks.getValue());
+    if ( yearCheckbox.getValue() )
+      ID3TagUtil.setYear(tag, year.getValue());
+    if ( genreCheckbox.getValue() )
+      ID3TagUtil.setGenre(tag, genre.getValue() == null ? null : ((Genre)genre.getValue()).toString());
+    if ( commentCheckbox.getValue() )
+      ID3TagUtil.setComment(tag, comment.getValue());
+    // TODO: add more ID3v2 options
+  }
+
+  /**
+   * Creates an ID3Tag from panel.
+   */
+  @Override
+  public ID3V2Tag createID3Tag() throws ID3Exception {
+    ID3V2Tag tag = ID3TagUtil.createID3V2_3_0();
+    updateID3Tag(tag);
+    return tag;
+  }
+
+  /**
+   * Copies ID3-Tag field values from {@code tag1} to {@code tag2}, but
+   * only for these fields which are activated in the panel. 
+   */
+  @Override
+  public void copyValues(ID3V2Tag tag1, ID3V2Tag tag2) throws ID3Exception {
+    if( tag1 == null || tag2 == null )
+      return;
+    if ( titleCheckbox.getValue() )
+      tag2.setTitle( tag1.getTitle() );
+    if ( artistCheckbox.getValue() )
+      tag2.setArtist( tag1.getArtist() );
+    if ( albumCheckbox.getValue() )
+      tag2.setAlbum( tag1.getAlbum() );
+    if ( trackNoCheckbox.getValue() )
+      ID3TagUtil.setTrackNumber(tag2, ID3TagUtil.getTrackNumber(tag1));
+    if ( totalTracksCheckbox.getValue() )
+      ID3TagUtil.setTotalTracks(tag2, ID3TagUtil.getTotalTracks(tag1));
+    if ( yearCheckbox.getValue() )
+      tag2.setYear( tag1.getYear() );
+    if ( genreCheckbox.getValue() )
+      tag2.setGenre( tag1.getGenre() );
+    if ( commentCheckbox.getValue() )
+      tag2.setComment( tag1.getComment() );
+    // TODO: add more ID3v2 options
+  }
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionDialog.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionDialog.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionDialog.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+
+import javax.swing.JLabel;
+
+import net.miginfocom.swing.MigLayout;
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.swing.JPanel;
+import de.schmitzm.swing.OkCancelDialog;
+import de.schmitzm.swing.SwingUtil;
+
+/**
+ * Dialog to configure some options to modify strings:
+ * <ul>
+ *   <li>Regular expression replacement</li>
+ *   <li>UpperCase / LowerCase / CamelCase</li>
+ *   <li>Replace Umlauts (and vice versa)<li>
+ * </ul>.
+ * @see StringConversionPanel
+ * @author Martin O.J. Schmitz
+ */
+public class StringConversionDialog extends OkCancelDialog {
+  private static StringConversionDialog instance = null;
+
+  protected JPanel mainPanel;
+  protected StringConversionPanel conversionPanel;
+  protected JLabel desc;
+  
+  /**
+   * Creates an empty frame.
+   */
+  public StringConversionDialog(Frame owner) {
+    super(owner, ID3TagUtil.R("StringConversionDialog.title"), true);
+  }
+  
+  /**
+   * Returns the application wide used instance of this frame.
+   * @param owner owner frame used when new instance is created
+   */
+  public static StringConversionDialog getInstance(Frame owner) {
+    if ( instance == null )
+      instance = new StringConversionDialog(owner);
+    return instance;
+  }
+
+  /**
+   * Returns the application wide used instance of this frame.
+   */
+  public static StringConversionDialog getInstance() {
+    return getInstance(null);
+  }
+  
+  /**
+   * Initializes the frame GUI.
+   */
+  @Override
+  public void init() {
+    super.init();
+    setDefaultCloseOperation(HIDE_ON_CLOSE);
+    setPreferredSize( new Dimension(550,370) );
+    
+    this.mainPanel = new JPanel( new MigLayout("wrap 1","[grow]","top") );
+    this.desc = GUIUtil.createCommentLabel( ID3TagUtil.R("StringConversionDialog.desc") );
+    this.conversionPanel = new StringConversionPanel();
+    conversionPanel.addActionListener(this);
+    
+    mainPanel.add(desc,"");
+    mainPanel.add(conversionPanel,"");
+    
+    updateActions();
+
+    getContentPane().add( mainPanel, BorderLayout.CENTER );
+    pack();
+    SwingUtil.setRelativeFramePosition(this, getOwner(), 0.5, 0.5);
+  }
+  
+  /**
+   * Called also to enable/disable the GUI actions.
+   */
+  @Override
+  public void actionPerformed(ActionEvent e) {
+    if ( e.getSource() == okButton ||
+         e.getSource() == cancelButton ) {
+      super.actionPerformed(e);
+      return;
+    }
+    updateActions();
+  }
+
+  /**
+   * Updates action enable/disable.
+   */
+  public void updateActions() {
+    okAction.setEnabled( conversionPanel.isRegexReplace() ||
+                         conversionPanel.isUpperCase() || conversionPanel.isLowerCase() || conversionPanel.isCamelCase() ||
+                         conversionPanel.isReplaceUmlauts() || conversionPanel.isCreateUmlauts()
+    );
+  }
+  
+  /**
+   * Sets the description label of the dialog.
+   */
+  public void setDesc(String desc) {
+    this.desc.setText(desc);
+  }
+  
+  /**
+   * Returns the panel which holds all the configuration components and
+   * provides access to the configuration.
+   */
+  public StringConversionPanel getStringConversionPanel() {
+    return conversionPanel;
+  }
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionPanel.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionPanel.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/gui/StringConversionPanel.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,445 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.gui;
+
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+
+import net.miginfocom.swing.MigLayout;
+import de.schmitzm.lang.LangUtil;
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.swing.ButtonGroup;
+import de.schmitzm.swing.JPanel;
+
+/**
+ * Panel to configure some options to modify strings:
+ * <ul>
+ *   <li>Regular expression replacement</li>
+ *   <li>UpperCase / LowerCase / CamelCase</li>
+ *   <li>Replace Umlauts (and vice versa)<li>
+ * </ul>.
+ * @author Martin O.J. Schmitz
+ */
+public class StringConversionPanel extends JPanel {
+
+  protected JLabel regexReplaceCaption;
+  protected RegexPanel regexPanel;
+  protected JLabel caseCaption;
+  protected CasePanel casePanel;
+  protected JLabel umlautsCaption;
+  protected UmlautsPanel umlautsPanel;
+  
+  /**
+   * Creates an empty frame.
+   */
+  public StringConversionPanel() {
+    this(null);
+  }
+
+  /**
+   * Creates an empty frame.
+   */
+  public StringConversionPanel(Frame owner) {
+    super(new MigLayout("wrap 1","0[grow]0","[]0[][]0[][]0[]") );
+ 
+    this.regexReplaceCaption = GUIUtil.createHeaderLabel( ID3TagUtil.R("StringConversionPanel.RegexPanel.desc") );
+    this.regexPanel = new RegexPanel();
+    this.caseCaption = GUIUtil.createHeaderLabel( ID3TagUtil.R("StringConversionPanel.CasePanel.desc") );
+    this.casePanel = new CasePanel();
+    this.umlautsCaption = GUIUtil.createHeaderLabel( ID3TagUtil.R("StringConversionPanel.UmlautsPanel.desc") );
+    this.umlautsPanel = new UmlautsPanel();
+    
+    add(regexReplaceCaption,"");
+    add(regexPanel,"");
+    add(caseCaption, "");
+    add(casePanel,"");
+    add(umlautsCaption, "");
+    add(umlautsPanel,"");
+  }
+  
+  /**
+   * Adds an {@link ActionListener} to all check boxes.
+   */
+  public void addActionListener(ActionListener l) {
+    regexPanel.addActionListener(l);
+    casePanel.addActionListener(l);
+    umlautsPanel.addActionListener(l);
+  }
+  
+  /**
+   * Removes an {@link ActionListener} from all check boxes.
+   */
+  public void removeActionListener(ActionListener l) {
+    regexPanel.removeActionListener(l);
+    casePanel.removeActionListener(l);
+    umlautsPanel.removeActionListener(l);
+  }
+
+  /**
+   * Converts a {@link String} according to the configuration of the panel.
+   */
+  public String convertString(String str) {
+    if ( isRegexReplace() ) {
+      String pattern = getRegexPattern();
+      String repl = getRegexReplace();
+      if ( isRegexReplaceAll() )
+        str = str.replaceAll(pattern, repl);
+      else
+        str = str.replaceFirst(pattern, repl);
+    }
+    
+    if ( isUpperCase() )
+      str = str.toUpperCase();
+    if ( isLowerCase() )
+      str = str.toLowerCase();
+    if ( isCamelCase() )
+      str = LangUtil.toCamelCase(str, false);
+    if ( isReplaceUmlauts() )
+      str = LangUtil.replaceUmlauts(str);
+    if ( isCreateUmlauts() )
+      str = LangUtil.createUmlauts(str);
+    
+    return str;
+
+  }
+  
+  /**
+   * Returns whether dialog is configured to apply regular expression replacement.
+   */
+  public boolean isRegexReplace() {
+    return regexPanel.isRegexReplace();
+  }
+  
+  /**
+   * Returns the regular expression pattern.
+   * @return {@code null} if regular expression is not activated
+   */
+  public String getRegexPattern() {
+    return regexPanel.getRegexPattern();
+  }
+  
+  /**
+   * Returns the regular expression replacement.
+   * @return {@code null} if regular expression is not activated
+   */
+  public String getRegexReplace() {
+    return regexPanel.getRegexReplace();
+  }
+
+  /**
+   * Returns whether dialog is configured to apply regular expression replacement to
+   * all pattern occurrences in filename.
+   */
+  public boolean isRegexReplaceAll() {
+    return regexPanel.isRegexReplaceAll();
+  }
+  
+  /**
+   * Returns whether dialog is configured to convert filename to upper-case.
+   */
+  public boolean isUpperCase() {
+    return casePanel.isUpperCase();
+  }
+
+  /**
+   * Returns whether dialog is configured to convert filename to lower-case.
+   */
+  public boolean isLowerCase() {
+    return casePanel.isLowerCase();
+  }
+  
+  /**
+   * Returns whether dialog is configured to convert filename to camel-case.
+   */
+  public boolean isCamelCase() {
+    return casePanel.isCamelCase();
+  }
+
+  /**
+   * Returns whether dialog is configured to replace umlauts in filename.
+   */
+  public boolean isReplaceUmlauts() {
+    return umlautsPanel.isReplaceUmlauts();
+  }
+
+  /**
+   * Returns whether dialog is configured to create umlauts in filename.
+   */
+  public boolean isCreateUmlauts() {
+    return umlautsPanel.isCreateUmlauts();
+  }
+  
+
+  /**
+   * Panel to configure regular expression replacement.
+   * @author Martin O.J. Schmitz
+   */
+  public static class RegexPanel extends JPanel implements ActionListener {
+    protected JCheckBox regexReplace;
+    protected JLabel regexCaption;
+    protected JTextField regex;
+    protected JButton replaceCaption;
+    protected JTextField replace;
+    protected JCheckBox replaceAll;
+
+    /**
+     * Creates new panel.
+     */
+    public RegexPanel() {
+      super( new MigLayout("wrap 5","0[][][grow][][grow]0","top") );
+
+      this.regexReplace = new JCheckBox( ID3TagUtil.R("StringConversionPanel.RegexPanel") );
+      this.regexCaption = GUIUtil.createContentLabel(ID3TagUtil.R("StringConversionPanel.RegexPanel.pattern") );
+      this.regex = new JTextField();
+      this.replaceCaption = new JButton( ID3TagUtil.R("StringConversionPanel.RegexPanel.replace") ); //GUIUtil.createContentLabel( GUIUtil.R("FilenameConversionDialog.regex.replace") );
+      this.replace = new JTextField();
+      this.replaceAll = new JCheckBox( ID3TagUtil.R("StringConversionPanel.RegexPanel.replace.all") );
+      replaceCaption.addActionListener(this);
+      regexReplace.addActionListener(this);
+
+      add(regexReplace,"");
+      add(regexCaption,"aligny center");
+      add(regex,"w 50::, growx, aligny center");
+      add(replaceCaption,"h 20!, aligny center");
+      add(replace,"w 50::, growx, aligny center");
+      add(replaceAll,"span 5");
+      
+      updateActions();
+    }
+
+    /**
+     * Adds an {@link ActionListener} to all check boxes.
+     */
+    public void addActionListener(ActionListener l) {
+      replaceCaption.addActionListener(l);
+      regexReplace.addActionListener(l);
+    }
+    
+    /**
+     * Removes an {@link ActionListener} from all check boxes.
+     */
+    public void removeActionListener(ActionListener l) {
+      replaceCaption.removeActionListener(l);
+      regexReplace.removeActionListener(l);
+    }
+
+    /**
+     * Called also to enable/disable the GUI actions.
+     */
+    @Override
+    public void actionPerformed(ActionEvent e) {
+      if ( e.getSource() == replaceCaption ) {
+        String pattern = regex.getText();
+        regex.setText(replace.getText());
+        replace.setText(pattern);
+        return;
+      }
+      updateActions();
+    }
+
+    /**
+     * Updates action enable/disable.
+     */
+    public void updateActions() {
+      boolean regexEnabled = regexReplace.isSelected();
+      regexCaption.setEnabled( regexEnabled );
+      regex.setEnabled( regexEnabled );
+      replaceCaption.setEnabled( regexEnabled );
+      replace.setEnabled( regexEnabled );
+      replaceAll.setEnabled( regexEnabled );
+    }
+
+    /**
+     * Returns whether dialog is configured to apply regular expression replacement.
+     */
+    public boolean isRegexReplace() {
+      return regexReplace.isSelected();
+    }
+    
+    /**
+     * Returns the regular expression pattern.
+     * @return {@code null} if regular expression is not activated
+     */
+    public String getRegexPattern() {
+      return isRegexReplace() ? regex.getText() : null;
+    }
+    
+    /**
+     * Returns the regular expression replacement.
+     * @return {@code null} if regular expression is not activated
+     */
+    public String getRegexReplace() {
+      return isRegexReplace() ? replace.getText() : null;
+    }
+
+    /**
+     * Returns whether dialog is configured to apply regular expression replacement to
+     * all pattern occurrences in filename.
+     */
+    public boolean isRegexReplaceAll() {
+      return replaceAll.isSelected();
+    }
+  }
+
+  /**
+   * Panel to configure upper-case, lower-case, camel-case replacement.
+   * @author Martin O.J. Schmitz
+   *
+   */
+  public static class CasePanel extends JPanel {
+    protected JCheckBox upperCase;
+    protected JCheckBox lowerCase;
+    protected JCheckBox camelCase;
+
+    /**
+     * Creates new panel.
+     */
+    public CasePanel() {
+//    super( new MigLayout("wrap 5","[][][grow][][grow]","top") );
+    super( new MigLayout("wrap 1","0[grow]0","top") );
+
+      this.upperCase = new JCheckBox( ID3TagUtil.R("StringConversionPanel.CasePanel.upper") );
+      this.lowerCase = new JCheckBox( ID3TagUtil.R("StringConversionPanel.CasePanel.lower") );
+      this.camelCase = new JCheckBox( ID3TagUtil.R("StringConversionPanel.CasePanel.camel") );
+
+      ButtonGroup caseGroup = new ButtonGroup();
+      caseGroup.add(upperCase);
+      caseGroup.add(lowerCase);
+      caseGroup.add(camelCase);
+
+      add(upperCase, "");
+      add(lowerCase, "");
+      add(camelCase, "");
+    }
+    
+    /**
+     * Adds an {@link ActionListener} to all check boxes.
+     */
+    public void addActionListener(ActionListener l) {
+      upperCase.addActionListener(l);
+      lowerCase.addActionListener(l);
+      camelCase.addActionListener(l);
+    }
+    
+    /**
+     * Removes an {@link ActionListener} from all check boxes.
+     */
+    public void removeActionListener(ActionListener l) {
+      upperCase.removeActionListener(l);
+      lowerCase.removeActionListener(l);
+      camelCase.removeActionListener(l);
+    }
+    
+    /**
+     * Returns whether dialog is configured to convert filename to upper-case.
+     */
+    public boolean isUpperCase() {
+      return upperCase.isSelected();
+    }
+
+    /**
+     * Returns whether dialog is configured to convert filename to lower-case.
+     */
+    public boolean isLowerCase() {
+      return lowerCase.isSelected();
+    }
+    
+    /**
+     * Returns whether dialog is configured to convert filename to camel-case.
+     */
+    public boolean isCamelCase() {
+      return camelCase.isSelected();
+    }
+  }
+
+  /**
+   * Panel to configure umlauts replacement.
+   * @author Martin O.J. Schmitz
+   *
+   */
+  public static class UmlautsPanel extends JPanel {
+    protected JCheckBox replaceUmlauts;
+    protected JCheckBox createUmlauts;
+
+    /**
+     * Creates new panel.
+     */
+    public UmlautsPanel() {
+//      super( new MigLayout("wrap 5","[][][grow][][grow]","top") );
+      super( new MigLayout("wrap 1","0[grow]0","top") );
+
+      this.createUmlauts = new JCheckBox( ID3TagUtil.R("StringConversionPanel.UmlautsPanel.create") );
+      this.replaceUmlauts = new JCheckBox( ID3TagUtil.R("StringConversionPanel.UmlautsPanel.replace") );
+      
+      ButtonGroup umlautsGroup = new ButtonGroup();
+      umlautsGroup.add(createUmlauts);
+      umlautsGroup.add(replaceUmlauts);
+
+      add(replaceUmlauts, "");
+      add(createUmlauts, "");
+    }    
+    
+    /**
+     * Adds an {@link ActionListener} to all check boxes.
+     */
+    public void addActionListener(ActionListener l) {
+      createUmlauts.addActionListener(l);
+      replaceUmlauts.addActionListener(l);
+    }
+    
+    /**
+     * Removes an {@link ActionListener} from all check boxes.
+     */
+    public void removeActionListener(ActionListener l) {
+      createUmlauts.removeActionListener(l);
+      replaceUmlauts.removeActionListener(l);
+    }
+
+    /**
+     * Returns whether dialog is configured to replace umlauts in filename.
+     */
+    public boolean isReplaceUmlauts() {
+      return replaceUmlauts.isSelected();
+    }
+
+    /**
+     * Returns whether dialog is configured to create umlauts in filename.
+     */
+    public boolean isCreateUmlauts() {
+      return createUmlauts.isSelected();
+    }
+  }
+}

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/ID3Tag2FilenameParser.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/ID3Tag2FilenameParser.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/ID3Tag2FilenameParser.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,345 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.io;
+
+import java.io.File;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.lang.StringUtils;
+import org.blinkenlights.jid3.ID3Exception;
+import org.blinkenlights.jid3.ID3Tag;
+
+import de.schmitzm.io.IOUtil;
+import de.schmitzm.lang.LangUtil;
+import de.schmitzm.mp3.id3.ID3TagField;
+import de.schmitzm.mp3.id3.ID3TagUtil;
+
+/**
+ * Parser to create filename from ID3-Tag or vice versa. Parser format can be specified
+ * individually. 
+ * @author Martin O.J. Schmitz
+ *
+ */
+public class ID3Tag2FilenameParser {
+
+  /** Default parser ("Artist - Album - TrackNo - Title.mp3"). */
+  public static final ID3Tag2FilenameParser DEFAULT_PARSER = new ID3Tag2FilenameParser(" - ",
+                                                                                       ID3TagField.ARTIST,
+                                                                                       ID3TagField.ALBUM,
+                                                                                       ID3TagField.TRACKNO,
+                                                                                       ID3TagField.TITLE
+                                                                                       );
+  /** Default fallback parser ("Artist - Title.mp3") used by {@link #DEFAULT_PARSER}
+   *  when no album or no track number is set in ID3Tag. */
+  public static final ID3Tag2FilenameParser DEFAULT_PARSER_FALLBACK = new ID3Tag2FilenameParser(" - ",
+                                                                                       ID3TagField.ARTIST,
+                                                                                       ID3TagField.TITLE
+                                                                                       );
+
+  
+  /** Holds the sequence of ID3-Tag fields the filename is build up. */
+  protected List<ID3TagField> id3sequence;
+  /** Holds the delimiter used to separate ID3-Tag fields in filename. */
+  protected String delim;
+  /** Holds the filename extension used for filename (usually ".mp3"). */
+  protected String fileExt = ".mp3";
+  /** Holds the number format to encode track number in filename. */
+  protected DecimalFormat trackNoFormat;
+  /** Holds the number format to encode year in filename. */
+  protected DecimalFormat yearFormat;
+  
+  
+  /**
+   * Creates a new parser with no format defined.
+   */
+  public ID3Tag2FilenameParser() {
+    this(null);
+  }
+
+  /**
+   * Creates a new parser as a copy of another parser.
+   */
+  public ID3Tag2FilenameParser(ID3Tag2FilenameParser parser) {
+    this(parser.getDelimiter(), parser.getSequence());
+  }
+
+  /**
+   * Creates a new parser
+   * @param delim delimiter used to separate ID3-Tag fields in filename
+   * @param tagSeq sequence of ID3-Tag fields the filename is build up
+   */
+  public ID3Tag2FilenameParser(String delim, ID3TagField... tagSeq) {
+    this(delim, Arrays.asList(tagSeq));
+  }
+
+  /**
+   * Creates a new parser
+   * @param delim delimiter used to split ID3-Tag parts in filename
+   * @param tagSeq sequence of ID3-Tag fields the filename is organized by
+   */
+  public ID3Tag2FilenameParser(String delim, List<ID3TagField> tagSeq) {
+    setSequence(tagSeq);
+    setDelimiter(delim);
+    setTrackNoFormat((DecimalFormat)null);
+    setYearFormat((DecimalFormat)null);
+  }
+
+  /**
+   * Returns a {@link String} which describes the parser sequence. 
+   */
+  public String getSequenceStr() {
+    StringBuffer sb = new StringBuffer();
+    for (ID3TagField field : getSequence()) {
+      if ( sb.length() > 0 )
+        sb.append( getDelimiter() );
+      sb.append(field.getTitle());
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Returns the sequence of ID3 fields the filename is build up
+   * @return always a new {@link List} instance so changes on the returned
+   *         list do not effect this parser!
+   */
+  public List<ID3TagField> getSequence() {
+    return new ArrayList<ID3TagField>(id3sequence);
+  }
+
+
+  /**
+   * Sets the sequence of ID3 fields the filename is build up
+   */
+  public void setSequence(ID3TagField... tagSeq) {
+    setSequence(Arrays.asList(tagSeq));
+    setDelimiter(delim);
+  }
+
+  /**
+   * Sets the sequence of ID3 fields the filename is build up
+   */
+  public void setSequence(List<ID3TagField> tagSeq) {
+    this.id3sequence = tagSeq;
+  }
+
+  /**
+   * Returns the delimiter used to separate ID3-Tag fields in filename.
+   */
+  public String getDelimiter() {
+    return delim == null ? "" : delim;
+  }
+
+  /**
+   * Sets the delimiter used to separate ID3-Tag fields in filename.
+   */
+  public void setDelimiter(String delim) {
+    this.delim = delim;
+  }
+  
+  /**
+   * Returns the filename extension used for filename (usually ".mp3").
+   */
+  public String getFileExt(boolean inclDot) {
+    String ext = fileExt;
+    if ( ext == null )
+      ext = ".";
+    if ( !inclDot )
+      ext = ext.substring(1);
+    return fileExt;
+  }
+
+  /**
+   * Sets the filename extension used for filename (usually ".mp3").
+   * @param fileExt the filename extemsion to set
+   * @param inclDot indicates whether {@code fileExt} already includes
+   *                the dot
+   */
+  public void setFileExt(String fileExt, boolean inclDot) {
+    if ( fileExt == null )
+      fileExt = "";
+    if ( !inclDot )
+      fileExt = "." + fileExt;
+    this.fileExt = fileExt;
+  }
+
+  /**
+   * Returns the number format to encode track number in filename.
+   */
+  public DecimalFormat getTrackNoFormat() {
+    return trackNoFormat;
+  }
+
+  /**
+   * Sets the number format to encode track number in filename. If set to {@code null}
+   * the default format (2 digits with leading zero) is set.
+   */
+  public void setTrackNoFormat(DecimalFormat format) {
+    if ( format == null )
+      format = new DecimalFormat("00");
+    this.trackNoFormat = format;
+  }
+
+  /**
+   * Sets the number format to encode track number in filename. If set to {@code null}
+   * the default format (2 digits with leading zero) is set.
+   */
+  public void setTrackNoFormat(String numberFormatPattern) {
+    DecimalFormat format = null;
+    if ( numberFormatPattern != null )
+      format = new DecimalFormat(numberFormatPattern);
+    setTrackNoFormat(format);
+  }
+  
+  /**
+   * Returns the number format to encode year in filename.
+   */
+  public DecimalFormat getYearFormat() {
+    return yearFormat;
+  }
+
+  /**
+   * Sets the number format to encode year in filename. If set to {@code null}
+   * the default format (4 digits with leading zero) is set.
+   */
+  public void setYearFormat(DecimalFormat format) {
+    if ( format == null )
+      format = new DecimalFormat("0000");
+    this.yearFormat = format;
+  }
+
+  /**
+   * Sets the number format to encode year in filename. If set to {@code null}
+   * the default format (4 digits with leading zero) is set.
+   */
+  public void setYearFormat(String numberFormatPattern) {
+    DecimalFormat format = null;
+    if ( numberFormatPattern != null )
+      format = new DecimalFormat(numberFormatPattern);
+    setYearFormat(format);
+  }
+
+  /**
+   * Creates file name from ID3 tag.
+   * @param tag the ID3-Tag to create the filename from
+   * @param replUmlaute indicates whether umlauts are automatically
+   *                    replaced in filename
+   */
+  public String createFilename(ID3Tag tag, boolean replUmlaute) {
+    if ( tag == null )
+      return null;
+
+    // if DEFAULT_PARSER is used and tag does not provide album or track number
+    // fall back to DEFAULT_PARSER_FALLBACK
+    if ( this == DEFAULT_PARSER &&
+         (   StringUtils.isBlank( ID3TagUtil.getID3TagField(tag, ID3TagField.ALBUM) )
+          || StringUtils.isBlank( ID3TagUtil.getID3TagField(tag, ID3TagField.TRACKNO) ) )
+       )
+      return DEFAULT_PARSER_FALLBACK.createFilename(tag, replUmlaute);
+    
+    StringBuffer filename = new StringBuffer();
+    for (ID3TagField field : getSequence()) {
+      if ( filename.length() > 0 )
+        filename.append( getDelimiter() );
+      NumberFormat format = null;
+      switch (field) {
+        case TRACKNO: format = getTrackNoFormat(); break;
+        case YEAR:    format = getYearFormat(); break;
+      }
+      String str = ID3TagUtil.getID3TagField(tag, field, format);
+      str = StringUtils.trimToEmpty(str);
+      filename.append( str );
+    }
+    filename.append( getFileExt(true) );
+    String filenameStr = filename.toString();
+    if ( replUmlaute )
+      filenameStr = LangUtil.replaceUmlauts(filenameStr);
+    return filenameStr;
+  }
+
+  /**
+   * Creates an ID3-Tag from filename.
+   * @param filename the filename to create the ID3-Tag from
+   * @param tag the ID3-Tag to be updated ({@code null} NOT allowed!) 
+   * @param replUmlaute indicates whether umlauts are automatically
+   *                    replaced in ID3 tag fields
+   * @return always {@code tag}
+   */
+  public <ID3 extends ID3Tag> ID3 updateID3Tag(String filename, ID3 tag, boolean replUmlaute) throws ID3Exception, ParseException {
+    filename = IOUtil.getBaseFileName(new File(filename));
+    // if DEFAULT_PARSER is given and filename does only provide 2 fields,
+    // fall back to DEFAULT_PARSER_FALLBACK
+    if ( this == DEFAULT_PARSER && 
+         filename.indexOf(getDelimiter()) == filename.lastIndexOf(getDelimiter()) )
+      return DEFAULT_PARSER_FALLBACK.updateID3Tag(filename, tag, replUmlaute);
+    
+    for (int i=0; i<id3sequence.size(); i++) {
+      ID3TagField field = id3sequence.get(i);
+      int idx = filename.indexOf(getDelimiter());
+      String fieldValueStr = (idx < 0 || i == id3sequence.size()-1) ? filename : filename.substring(0,idx);
+      String fieldValue = fieldValueStr;
+      switch (field) {
+        case TRACKNO: fieldValue = getTrackNoFormat().parse(fieldValue).toString();
+                      break;
+        case YEAR: fieldValue = getYearFormat().parse(fieldValue).toString();
+                   break;
+      }
+      if ( replUmlaute )
+        fieldValue = LangUtil.replaceUmlauts(fieldValue);
+      ID3TagUtil.setID3TagField(tag, field, StringUtils.trimToEmpty(fieldValue));
+      
+      // remove field value from temporary filename
+      filename = filename.substring(fieldValueStr.length());
+      if ( StringUtils.isBlank(filename) )
+        break;
+      // remove delimiter from temporary filename
+      filename = filename.substring(getDelimiter().length());
+    }
+    return tag;
+  }
+
+  /**
+   * Creates file name from ID3 tag.
+   * @param file the file to create the ID3-Tag from
+   * @param tag the ID3-Tag to be updated ({@code null} NOT allowed!) 
+   * @param replUmlaute indicates whether umlauts are automatically
+   *                    replaced in ID3 tag fields
+   * @return always {@code tag}
+   */
+  public <ID3 extends ID3Tag> ID3 updateID3Tag(File file, ID3 tag, boolean replUmlaute) throws ID3Exception, ParseException {
+    return updateID3Tag(file.getName(), tag, replUmlaute);
+  }
+  
+}
+

Added: trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/MP3File.java
===================================================================
--- trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/MP3File.java	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/java/de/schmitzm/mp3/id3/io/MP3File.java	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focusing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program 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 3
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Tzeggai - additional utility classes
+ */
+package de.schmitzm.mp3.id3.io;
+
+import java.io.File;
+
+import org.blinkenlights.jid3.ID3Exception;
+import org.blinkenlights.jid3.io.IFileSource;
+import org.blinkenlights.jid3.v1.ID3V1Tag;
+
+import de.schmitzm.mp3.id3.ID3TagUtil;
+import de.schmitzm.mp3.id3.ID3V1_1aTag;
+
+/**
+ * Works like {@link org.blinkenlights.jid3.MP3File}, but provides access
+ * to the underlying {@link IFileSource} object.
+ * Furthermore it provides a method {@link #getID3V1Tag(boolean))} that returns
+ * the ID3 v1 tag automatically converted to {@link ID3V1_1aTag}, which empty track number.
+ * @author Martin O.J. Schmitz
+ */
+public class MP3File extends org.blinkenlights.jid3.MP3File {
+
+  /**
+   * Creates new file.
+   */
+  public MP3File(File oSourceFile) {
+    super(oSourceFile);
+  }
+
+  /**
+   * Creates new file.
+   */
+  public MP3File(IFileSource oFileSource) {
+    super(oFileSource);
+  }
+  
+  /**
+   * Returns the file source.
+   */
+  public IFileSource getFileSource() {
+    return m_oFileSource;
+  }
+  
+  /**
+   * Returns the v1 tag.
+   * @param convert indicates whether the tag is automatically converted
+   *                to {@link ID3V1_1aTag}
+   */
+  public ID3V1Tag getID3V1Tag(boolean convert) throws ID3Exception {
+    ID3V1Tag tag = getID3V1Tag();
+    if ( convert )
+      tag = ID3TagUtil.convertToID3V1_1a(tag);
+    return tag;
+  }
+}

Added: trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle.properties
===================================================================
--- trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle.properties	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle.properties	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,80 @@
+##########
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program 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 3
+#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.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Tzeggai - additional utility classes
+##########
+# ---------------------------------------------------------------
+# ------ Default Translations (english) for GUI components ------
+# ------ in Package de.schmitzm.mp3.id3                    ------
+# ---------------------------------------------------------------
+
+
+ID3Tag.Title=Title
+ID3Tag.Artist=Artist
+ID3Tag.Album=Album
+ID3Tag.TrackNo=Track No.
+ID3Tag.Year=Year
+ID3Tag.Genre=Genre
+ID3Tag.Comment=Comment
+ID3Tag.TotalTracks=Total tracks
+ID3Tag.of=of
+
+ID3TagUtil.mp3filter.desc=mp3 files
+
+ID3TagFieldSequencePanel.fields.sequence=Field sequence
+ID3TagFieldSequencePanel.fields.available=Available fields
+ID3TagFieldSequencePanel.action.add=<<<
+ID3TagFieldSequencePanel.action.add.desc=Add selected fields to sequence
+ID3TagFieldSequencePanel.action.remove=>>>
+ID3TagFieldSequencePanel.action.remove.desc=Remove selected fields from sequence
+ID3TagFieldSequencePanel.action.moveUp=Up
+ID3TagFieldSequencePanel.action.moveUp.desc=Move selected fields up in sequence
+ID3TagFieldSequencePanel.action.moveDown=Dn
+ID3TagFieldSequencePanel.action.moveDown.desc=Move selected fields down in sequence
+
+ID3Tag2FilenameParserPanel.delim=Field delimiter character:
+ID3Tag2FilenameParserPanel.spaces=Space before/after delimiter
+ID3Tag2FilenameParserPanel.numberFormat=Filename number formats:
+ID3Tag2FilenameParserPanel.numberFormat.trackNo=Track No. number format:
+ID3Tag2FilenameParserPanel.numberFormat.trackNo.example=e.g. "00"
+ID3Tag2FilenameParserPanel.numberFormat.year=Year number format:
+ID3Tag2FilenameParserPanel.numberFormat.year.example=e.g. "0000"
+
+StringConversionPanel.RegexPanel.desc=Regular expression
+StringConversionPanel.RegexPanel=Regular expression:
+StringConversionPanel.RegexPanel.pattern=Replace pattern
+StringConversionPanel.RegexPanel.replace=with
+StringConversionPanel.RegexPanel.replace.all=Replace all occurrences
+StringConversionPanel.CasePanel.desc=Upper/Lower-Case
+StringConversionPanel.CasePanel.upper=Convert to upper-case letters
+StringConversionPanel.CasePanel.lower=Convert to lower-case letters
+StringConversionPanel.CasePanel.camel=Convert to camel-case letters
+StringConversionPanel.UmlautsPanel.desc=Umlauts
+StringConversionPanel.UmlautsPanel.create=Create umlauts (convert to ä, ö, ü, ß) [PROPRIETARY!!]
+StringConversionPanel.UmlautsPanel.replace=Replace umlauts (by ae, oe, ue, ss)
+
+StringConversionDialog.title=Convert filename(s)
+StringConversionDialog.desc=By this dialog you can configure how to modify the filename of the selected files
+

Added: trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle_de.properties
===================================================================
--- trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle_de.properties	                        (rev 0)
+++ trunk/schmitzm-mp3/src/main/resources/de/schmitzm/mp3/id3/resource/locales/ID3TagResourceBundle_de.properties	2013-03-24 11:19:19 UTC (rev 2280)
@@ -0,0 +1,78 @@
+##########
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program 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 3
+#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.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Tzeggai - additional utility classes
+##########
+# ---------------------------------------------------------------
+# ------ Germal Translations for GUI components            ------
+# ------ in Package de.schmitzm.mp3.id3                    ------
+# ---------------------------------------------------------------
+ID3Tag.Title=Titel
+ID3Tag.Artist=Interpret
+ID3Tag.Album=Album
+ID3Tag.TrackNo=Track Nr.
+ID3Tag.Year=Jahr
+ID3Tag.Genre=Genre
+ID3Tag.Comment=Kommentar
+ID3Tag.TotalTracks=Gesamt Tracks
+ID3Tag.of=von
+
+ID3TagUtil.mp3filter.desc=mp3 Dateien
+
+ID3TagFieldSequencePanel.fields.sequence=Feld-Reihenfolge
+ID3TagFieldSequencePanel.fields.available=Verfügbare Felder
+ID3TagFieldSequencePanel.action.add=<<<
+ID3TagFieldSequencePanel.action.add.desc=Ausgewählte Felder der Reihenfolge hinzufügen
+ID3TagFieldSequencePanel.action.remove=>>>
+ID3TagFieldSequencePanel.action.remove.desc=Ausgewählte Felder aus der Reihenfolge entfernen
+ID3TagFieldSequencePanel.action.moveUp=Hoch
+ID3TagFieldSequencePanel.action.moveUp.desc=Ausgewählte Felder in der Reihenfolge nach oben/vorne verschieben
+ID3TagFieldSequencePanel.action.moveDown=Runter
+ID3TagFieldSequencePanel.action.moveDown.desc=Ausgewählte Felder in der Reihenfolge nach unten/hinten verschieben
+
+ID3Tag2FilenameParserPanel.delim=Trennzeichen für Felder:
+ID3Tag2FilenameParserPanel.spaces=Leerzeichen vor/nach Trennzeichen
+ID3Tag2FilenameParserPanel.numberFormat=Zahlenformate für Dateinamen:
+ID3Tag2FilenameParserPanel.numberFormat.trackNo=Track Nr. Zahlenformat:
+ID3Tag2FilenameParserPanel.numberFormat.trackNo.example=z.B. "00"
+ID3Tag2FilenameParserPanel.numberFormat.year=Jahr Zahlenformat:
+ID3Tag2FilenameParserPanel.numberFormat.year.example=z.B. "0000"
+
+StringConversionPanel.RegexPanel.desc=Reguläre Ausdrücke
+StringConversionPanel.RegexPanel=Reguläre Ausdrücke:
+StringConversionPanel.RegexPanel.pattern=Ersetze Muster
+StringConversionPanel.RegexPanel.replace=durch
+StringConversionPanel.RegexPanel.replace.all=Alle Vorkommen ersetzen
+StringConversionPanel.CasePanel.desc=Gross-/Klein-Buchstaben
+StringConversionPanel.CasePanel.upper=In Grossbuchstaben umwandeln
+StringConversionPanel.CasePanel.lower=In Kleinbuchstaben umwandeln
+StringConversionPanel.CasePanel.camel=In "Höcker"-Schreibweise umwandeln
+StringConversionPanel.UmlautsPanel.desc=Umlaute
+StringConversionPanel.UmlautsPanel.create=Umlaute erzeugen (ae, oe, ue, ss in ä, ö, ü, ß umwandeln) [PROPRIETÄR!!]
+StringConversionPanel.UmlautsPanel.replace=Umlaute ersetzen (ä, ö, ü, ß durch ae, oe, ue, ss ersetzen)
+
+StringConversionDialog.title=Strings konvertieren
+StringConversionDialog.desc=Über diesen Dialog wird konfigurtiert, wie Strings modifiziert werden:
+



More information about the Schmitzm-commits mailing list