package org.lysty.ui.model; import java.io.File; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import javax.swing.table.DefaultTableModel; import org.lysty.dao.Song; import org.lysty.dao.SongSelectionProfile; import org.lysty.db.DBHandler; import org.lysty.ui.Reorderable; import org.lysty.ui.SongDroppable; import org.lysty.ui.exception.SongNotIndexedException; public class PlaylistProfileModel extends DefaultTableModel implements Reorderable, SongDroppable { private static final int DEFAULT_ROW_COUNT = 10; SongSelectionProfile selProfile; List<Song> songs; private boolean isEdited; /** * Updates the size to new size. this is a best attempt method. If it is not * possible to update to the given size (if asked to reduce to a size * smaller than the number of songs selected for the list, it does its best * to reduce as much as possible * * @param newSize * the new size of the songs list. * @return the actual new size of the list after modification. might not be * the same as newSize since this is a best attempt algo */ public int updateSize(int newSize) { int rows = songs.size(); if (newSize == rows) { // no change. no need to do anything return newSize; } Map<Song, Integer> blanks = new HashMap<Song, Integer>(); Song cSong = new Song(); cSong.setId(-1);// dummy song to signal the beginning of the array int cnt = 0; int totalBlanks = 0; for (int i = 0; i < rows; i++) { if (songs.get(i) != null) { blanks.put(cSong, cnt); cSong = songs.get(i); cnt = 0; } else if (songs.get(i) == null) { cnt++; totalBlanks++; } } blanks.put(cSong, cnt); // put the follow up blanks after last song int cCnt; int rand; if (newSize > rows) { // size is increased int adds = newSize - rows; int indexToAddBlank; Iterator<Entry<Song, Integer>> it; Entry<Song, Integer> entry; for (int i = 0; i < adds; i++) { cCnt = 0; rand = (int) (Math.random() * totalBlanks); it = blanks.entrySet().iterator(); while (it.hasNext()) { entry = it.next(); cCnt += entry.getValue(); if (rand <= cCnt) { if (entry.getKey().getId() == -1) { indexToAddBlank = 0; } else { indexToAddBlank = songs.indexOf(entry.getKey()) + 1; } if (indexToAddBlank >= songs.size()) { songs.add(null); } else { songs.add(indexToAddBlank, null); } break; } } } } else if (newSize < rows) { // size is decreased int rems = rows - newSize; int indexToRemBlank; Iterator<Entry<Song, Integer>> it; Entry<Song, Integer> entry; for (int i = 0; i < rems; i++) { cCnt = 0; rand = (int) (Math.random() * totalBlanks); it = blanks.entrySet().iterator(); while (it.hasNext()) { entry = it.next(); cCnt += entry.getValue(); if (rand <= cCnt) { if (entry.getKey().getId() == -1) { indexToRemBlank = 0; } else { indexToRemBlank = songs.indexOf(entry.getKey()) + 1; } if (indexToRemBlank < songs.size() && songs.get(indexToRemBlank) == null) { songs.remove(indexToRemBlank); break; } } } } } fireTableDataChanged(); return songs.size(); } public PlaylistProfileModel(int size) { selProfile = new SongSelectionProfile(); songs = new ArrayList<Song>(size); for (int i = 0; i < size; i++) songs.add(null); } @Override public int getRowCount() { // TODO Auto-generated method stub if (songs == null) return 0; return songs.size(); } @Override public int getColumnCount() { // TODO Auto-generated method stub return 1; } @Override public String getColumnName(int colIndex) { return "Name"; } @Override public Class<?> getColumnClass(int columnIndex) { // TODO Auto-generated method stub return String.class; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { // TODO Auto-generated method stub return false; } public Song getSongAt(int rowIndex) { return songs.get(rowIndex); } @Override public Object getValueAt(int rowIndex, int columnIndex) { try { Song song = songs.get(rowIndex); if (song == null) return ""; return song.getName(); } catch (IndexOutOfBoundsException e) { return ""; } } public void saved() { isEdited = false; } public boolean isEdited() { return isEdited; } @Override public void setValueAt(Object val, int rowIndex, int columnIndex) { songs.set(rowIndex, (Song) val); } public SongSelectionProfile getSelProfile() { selProfile.setSize(songs.size()); selProfile.updateRelPosMap(songs); return selProfile; } public void loadFromSelProfile(SongSelectionProfile profile) { songs = new ArrayList<Song>(); selProfile = profile; int rows = 10; if (selProfile.getSizeType() == SongSelectionProfile.SIZE_TYPE_LENGTH) { rows = selProfile.getSize(); } Map<Song, Integer> map = selProfile.getRelPosMap(); Iterator<Entry<Song, Integer>> it = map.entrySet().iterator(); Entry<Song, Integer> entry; for (int i = 0; i < rows; i++) { songs.add(null); } while (it.hasNext()) { entry = it.next(); songs.set(entry.getValue(), entry.getKey()); } fireTableDataChanged(); } @Override public void addSong(File file, int row) throws SongNotIndexedException { isEdited = true; Song song = DBHandler.getInstance().getSong(file); while (row >= songs.size()) { songs.add(null); } if (song == null) throw new SongNotIndexedException(file); if (songs.size() <= row) { songs.add(null); } if (songs.get(row) != null) { songs.add(row, song); } else { songs.set(row, song); } fireTableDataChanged(); } @Override public void removeRow(int row) { songs.remove(row); fireTableDataChanged(); } @Override public void reorder(int fromIndex, int toIndex) { Song song = songs.get(fromIndex); songs.remove(fromIndex); songs.add(toIndex, song); fireTableDataChanged(); } }