package gui; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.net.URL; import java.util.Comparator; import java.util.Properties; import java.util.Vector; import java.util.regex.PatternSyntaxException; import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.RowFilter; import javax.swing.RowSorter; import javax.swing.SwingConstants; import javax.swing.TransferHandler; import javax.swing.event.TableModelEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableModel; import javax.swing.table.TableRowSorter; import songstreams.SongStream; public class SongTable extends JTable { /** * */ private static final long serialVersionUID = 1606280135979175363L; protected MyTableRowSorter sorter; protected XTableColumnModel xColumnModel; protected SongTableModel model; protected String[] columnNames; private Properties settings; public SongTable(String[] columnNames, Properties settings) { super(); this.settings = settings; this.columnNames = columnNames; model = new SongTableModel(); initialize(model); } protected void initialize(SongTableModel model) { this.model = model; setModel(model); setColumnSelectionAllowed(false); sorter = new MyTableRowSorter(this.model); setRowSorter(sorter); getTableHeader().addMouseListener(getHeaderListener()); this.model.setColumnIdentifiers(columnNames); xColumnModel = new XTableColumnModel(); setColumnModel(xColumnModel); createDefaultColumnsFromModel(); setVisibleColumns(); for (ActionMap map = getActionMap(); map!=null; map = map.getParent()) { map.remove(TransferHandler.getCutAction().getValue(Action.NAME)); map.remove(TransferHandler.getCopyAction().getValue(Action.NAME)); map.remove(TransferHandler.getPasteAction().getValue(Action.NAME)); } } public void clear() { while (true) { try { model.removeRow(0); } catch (ArrayIndexOutOfBoundsException e) { return; } } } @Override public void tableChanged(TableModelEvent e) { super.tableChanged(e); if(e.getType() != TableModelEvent.UPDATE) autoResizeColWidth(); } protected void setVisibleColumns() { for (int i = 0; i < columnNames.length; i++) { String setting = settings.getProperty(getColumnVisibilitySettingKey(columnNames[i])); if (setting == null) { if (i < 4) setting = "true"; else setting = "false"; } xColumnModel.setColumnVisible(getColumn(columnNames[i]), Boolean.parseBoolean(setting)); } } protected String getColumnVisibilitySettingKey(String string) { String key = string.replace(" ", "_"); if(key.contains("\u2713")) key = key.substring(0, key.length() - 3); key += "_visible"; return key; } private MouseListener getHeaderListener() { final JPopupMenu popup = new JPopupMenu(); ActionListener popupMenuItemListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { JMenuItem source = (JMenuItem) e.getSource(); String key = getColumnVisibilitySettingKey(source.getText()); int index; for(index = 0; index < columnNames.length; index++) if(source.getText().contains(columnNames[index])) break; if (source.getText().contains("\u2713")) { settings.setProperty(key, "false"); String newText = source.getText().substring(0, source.getText().length() - 3); source.setText(newText); xColumnModel.setColumnVisible( xColumnModel.getColumnByModelIndex(index), false); } else { settings.setProperty(key, "true"); xColumnModel.setColumnVisible( xColumnModel.getColumnByModelIndex(index), true); source.setText(source.getText().concat(" \u2713")); } } }; JMenuItem artistName = new JMenuItem(columnNames[0]); artistName.addActionListener(popupMenuItemListener); if (Boolean.parseBoolean(settings.getProperty(getColumnVisibilitySettingKey("Artist_name"), "true"))) artistName.setText(artistName.getText().concat(" \u2713")); JMenuItem songName = new JMenuItem(columnNames[1]); songName.addActionListener(popupMenuItemListener); if (Boolean.parseBoolean(settings.getProperty(getColumnVisibilitySettingKey("Song title"), "true"))) songName.setText(songName.getText().concat(" \u2713")); JMenuItem albumName = new JMenuItem(columnNames[2]); albumName.addActionListener(popupMenuItemListener); if (Boolean.parseBoolean(settings.getProperty(getColumnVisibilitySettingKey("Album name"),"true"))) albumName.setText(albumName.getText().concat(" \u2713")); JMenuItem trackNumber = new JMenuItem(columnNames[3]); trackNumber.addActionListener(popupMenuItemListener); if (Boolean.parseBoolean(settings.getProperty(getColumnVisibilitySettingKey("Track number"),"false"))) trackNumber.setText(trackNumber.getText().concat(" \u2713")); JMenuItem year = new JMenuItem(columnNames[4]); year.addActionListener(popupMenuItemListener); if (Boolean.parseBoolean(settings .getProperty(getColumnVisibilitySettingKey("Release year"), "false"))) year.setText(year.getText().concat(" \u2713")); popup.add(artistName); popup.add(songName); popup.add(albumName); popup.add(trackNumber); popup.add(year); return new MouseListener() { @Override public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) popup.show(e.getComponent(), e.getX(), e.getY()); } public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) popup.show(e.getComponent(), e.getX(), e.getY()); } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseClicked(MouseEvent e) { } }; } public String getArtistForRow(int row) { return model.getArtistForRow(sorter.convertRowIndexToModel(row)); } public String getTitleForRow(int row) { return model.getSongTitleForRow(sorter.convertRowIndexToModel(row)); } public String getAlbumForRow(int row) { return model.getAlbumNameForRow(sorter.convertRowIndexToModel(row)); } public int getTrackNrForRow(int row) { return model.getTrackNumberForRow(sorter.convertRowIndexToModel(row)); } public int getYearForRow(int row) { return model.getYearForRow(sorter.convertRowIndexToModel(row)); } protected void autoResizeColWidth() { try { setAutoResizeMode(JTable.AUTO_RESIZE_OFF); setModel(model); int margin = 5; for (int i = 0; i < getColumnCount(); i++) { int vColIndex = i; DefaultTableColumnModel colModel = (DefaultTableColumnModel) getColumnModel(); TableColumn col = colModel.getColumn(vColIndex); if (i == 0) { col.setPreferredWidth(10); col.setMaxWidth(10); } else { int width = 0; // Get width of column header TableCellRenderer renderer = col.getHeaderRenderer(); if (renderer == null) { renderer = getTableHeader().getDefaultRenderer(); } Component comp = renderer.getTableCellRendererComponent( this, col.getHeaderValue(), false, false, 0, 0); width = comp.getPreferredSize().width; // Get maximum width of column data for (int r = 0; r < getRowCount(); r++) { renderer = getCellRenderer(r, vColIndex); comp = renderer.getTableCellRendererComponent(this, this.getValueAt(r, vColIndex), false, false, r, vColIndex); width = Math.max(width, comp.getPreferredSize().width); } // Add margin width += 2 * margin; // Set the width col.setPreferredWidth(width); } } ((DefaultTableCellRenderer) getTableHeader().getDefaultRenderer()) .setHorizontalAlignment(SwingConstants.LEFT); getTableHeader().setReorderingAllowed(true); } catch (Exception e) { e.printStackTrace(); } } public void addRow(SongStream stream) { addRow(stream.getArtist(), stream.getTitle(), stream.getAlbum(), String.valueOf(stream.getTrackNum()), String.valueOf(stream.getYear()), stream.getURL().toString()); } private void addRow(String artist, String title, String album, String trackNr, String year, String url) { model.addRow(artist, title, album, trackNr, year, url); } @Override public TableRowSorter<TableModel> getRowSorter() { return sorter; } public Vector<SongStream> getSelectedSongs() throws Exception { Vector<SongStream> result = new Vector<SongStream>(); int[] selectedRows = getSelectedRows(); for(int i = 0; i < selectedRows.length; i++) result.add(getRow(selectedRows[i])); return result; } public Vector<SongStream> getRows() { Vector<SongStream> result = new Vector<SongStream>(); for (int i = 0; i < getRowCount(); i++) { try { result.add(getRow(i)); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } return result; } @Override public void setRowSorter(RowSorter<? extends TableModel> sorter) { this.sorter = (MyTableRowSorter) sorter; super.setRowSorter(sorter); } private SongStream getRow(int i) throws Exception { String artist = getArtistForRow(i); String title = getTitleForRow(i); String album = getAlbumForRow(i); int trackNr = getTrackNrForRow(i); int year = getYearForRow(i); URL url = getURLForRow(i); // TODO return new SongStream(artist, title, album, null, year, trackNr, -1F, url.toString()); } private URL getURLForRow(int i) { try { return model.getURL(sorter.convertRowIndexToModel(i)); } catch (Exception e) { return null; } } protected void filterResults(String text) { if(this.model.getRowCount() < 2) return; String[] regexes = text.toLowerCase().trim().split(" "); RowFilter<TableModel, Integer> rf = null; try { Vector<RowFilter<Object, Object>> filtersForAtLeast = new Vector<RowFilter<Object, Object>>(); for (int k = 0; k < regexes.length; k++) { Vector<RowFilter<Object, Object>> filtersForOr = new Vector<RowFilter<Object, Object>>(); String regex = "(?i)" + regexes[k]; for (int i = 0; i < getColumnCount(); i++) { filtersForOr.add(RowFilter.regexFilter(regex, i)); } filtersForAtLeast.add(RowFilter.orFilter(filtersForOr)); } rf = new AtLeastFilter(filtersForAtLeast, regexes.length); } catch (PatternSyntaxException e) { return; } sorter.setRowFilter(rf); } protected class MyTableRowSorter extends TableRowSorter<TableModel> { private Comparator<?> comparator; public MyTableRowSorter(SongTableModel model) { super(model); comparator = new Comparator<Object>() { @Override public int compare(Object o1, Object o2) { String o1String = (String) o1; String o2String = (String) o2; try { return Integer.parseInt(o1String) - Integer.parseInt(o2String); } catch (Exception e) { return o1String.compareTo(o2String); } } }; setComparator(); } private void setComparator() { for (int i = 0; i < getModel().getColumnCount(); i++) { setComparator(i, comparator); } } @Override public void toggleSortOrder(int column) { super.toggleSortOrder(column); } @Override public void sort() { setComparator(); super.sort(); }; @Override public void allRowsChanged() { } @Override public void modelStructureChanged() { } } public void renewSorter() { setRowSorter(new MyTableRowSorter(model)); } private class AtLeastFilter extends RowFilter<TableModel, Integer> { private Vector<RowFilter<Object, Object>> filters; private int matchesAtLeast; public AtLeastFilter(Vector<RowFilter<Object, Object>> filters, int matchesAtLeast) { this.filters = filters; this.matchesAtLeast = matchesAtLeast; } @Override public boolean include( javax.swing.RowFilter.Entry<? extends TableModel, ? extends Integer> entry) { int count = 0; for (RowFilter<Object, Object> currentFilter : filters) { if (currentFilter.include(entry)) count++; if (count == matchesAtLeast) return true; } return false; } } public void removeRow(int i) { model.removeRow(i); } public void setNowPlaying(int row, boolean value) { model.setNowPlaying(sorter.convertRowIndexToModel(row), value); } }