/* * Copyright (c) 2008, 2009, 2010 Denis Tulskiy * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3 along with this work. If not, see <http://www.gnu.org/licenses/>. */ package com.tulskiy.musique.gui.model; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.Map.Entry; import javax.swing.table.AbstractTableModel; import org.jaudiotagger.tag.FieldKey; import com.tulskiy.musique.playlist.Track; import com.tulskiy.musique.util.FieldKeyMetaHelper; /** * @author mliauchuk */ public class MultiTagFieldModel extends AbstractTableModel implements TagFieldModel { private List<TrackInfoItem> trackInfoItems = new LinkedList<TrackInfoItem>(); private List<TrackInfoItem> trackInfoItemsRemoved = new LinkedList<TrackInfoItem>(); public MultiTagFieldModel(List<Track> tracks) { loadTracks(tracks); } protected void loadTracks(List<Track> tracks) { Set<FieldKey> usedKeys = new LinkedHashSet<FieldKey>(); for (int i = 0; i < tracks.size(); i++) { tracks.get(i).getTrackData().populateWithEmptyCommonTagFields(); } for (int i = 0; i < tracks.size(); i++) { Iterator<Entry<FieldKey, FieldValues>> entries = tracks.get(i).getTrackData() .getAllTagFieldValuesIterator(); while (entries.hasNext()) { Entry<FieldKey, FieldValues> entry = entries.next(); if (!usedKeys.contains(entry.getKey())) { usedKeys.add(entry.getKey()); trackInfoItems.add(new TrackInfoItem(entry.getKey(), tracks)); } } } sort(); } public List<TrackInfoItem> getTrackInfoItems() { return trackInfoItems; } public void addTrackInfoItem(TrackInfoItem item) { int i = 0; while (i < trackInfoItemsRemoved.size()) { TrackInfoItem tii = trackInfoItemsRemoved.get(i); if (tii.getKey().equals(item.getKey())) { trackInfoItemsRemoved.remove(tii); } else { i++; } } trackInfoItems.add(item); } // TODO optimize public void mergeTrackInfoItems(List<TrackInfoItem> items) { boolean isFound; for (TrackInfoItem item : items) { isFound = false; // update existing fields for (TrackInfoItem tii : trackInfoItems) { if (tii.getKey().equals(item.getKey())) { for (int i = 0; i < item.getTracks().size() && i < tii.getTracks().size(); i++) { Track itemTrack = item.getTracks().get(i); Track tiiTrack = tii.getTracks().get(i); tii.getState().setValues(item.getState().getValues(itemTrack), tiiTrack); } isFound = true; break; } } // update removed fields if (!isFound) { for (TrackInfoItem tiir : trackInfoItemsRemoved) { if (tiir.getKey().equals(item.getKey())) { for (int i = 0; i < item.getTracks().size() && i < tiir.getTracks().size(); i++) { Track itemTrack = item.getTracks().get(i); Track tiiTrack = tiir.getTracks().get(i); tiir.getState().setValues(item.getState().getValues(itemTrack), tiiTrack); } trackInfoItems.add(tiir); trackInfoItemsRemoved.remove(tiir); isFound = true; break; } } } // add new fields if (!isFound) { List<Track> tracks = trackInfoItems.isEmpty() ? trackInfoItemsRemoved.get(0).getTracks() : trackInfoItems.get(0).getTracks(); TrackInfoItem itemNew = new TrackInfoItem(item.getKey(), tracks); for (int i = 0; i < item.getTracks().size() && i < tracks.size(); i++) { Track itemTrack = item.getTracks().get(i); Track itemNewTrack = tracks.get(i); itemNew.getState().setValues(item.getState().getValues(itemTrack), itemNewTrack); } addTrackInfoItem(itemNew); } } } public void removeTrackInfoItems(List<TrackInfoItem> items) { for (TrackInfoItem item : items) { item.getState().setValue(""); } trackInfoItemsRemoved.addAll(items); trackInfoItems.removeAll(items); } /** * Syncs removed and present track info items. Finally, empty "removed" tags * will be physically removed by AudioFileWriter. Should be used by * "apply changes" event handler only. */ private void sync() { trackInfoItems.addAll(trackInfoItemsRemoved); trackInfoItemsRemoved.clear(); } public void approveModel() { sync(); for (TrackInfoItem item : trackInfoItems) { item.approveState(true); } sort(); } public void refreshModel() { sort(); } public void rejectModel() { sync(); for (TrackInfoItem item : trackInfoItems) { item.rejectState(); } } public void sort() { Collections.sort(trackInfoItems, new TrackInfoItemComparator()); } public List<FieldKey> getAllUsedFieldKeys() { List<FieldKey> result = new LinkedList<FieldKey>(); for (TrackInfoItem item : trackInfoItems) { result.add(item.getKey()); } for (TrackInfoItem item : trackInfoItemsRemoved) { result.add(item.getKey()); } return result; } @Override public int getRowCount() { return trackInfoItems.size(); } @Override public int getColumnCount() { return 2; } @Override public Object getValueAt(int rowIndex, int columnIndex) { if (rowIndex < 0 || rowIndex > trackInfoItems.size()) return null; if (columnIndex == 0) return FieldKeyMetaHelper.getDisplayName(trackInfoItems.get(rowIndex).getKey()); else return trackInfoItems.get(rowIndex).toString(); } @Override public String getColumnName(int column) { return column == 0 ? "Key" : "Value"; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { trackInfoItems.get(rowIndex).getState().setValue((String) aValue); } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex == 1; } }