/*
* Copyright (c) 2008, 2009, 2010, 2011 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.playlist;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import com.tulskiy.musique.gui.dialogs.ProgressDialog;
import com.tulskiy.musique.gui.dialogs.Task;
import com.tulskiy.musique.playlist.Playlist;
import com.tulskiy.musique.playlist.PlaylistListener;
import com.tulskiy.musique.playlist.PlaylistManager;
import com.tulskiy.musique.system.Application;
import com.tulskiy.musique.system.configuration.Configuration;
import com.tulskiy.musique.util.Util;
/**
* Author: Denis Tulskiy
* Date: Jun 21, 2010
*/
public class PlaylistTabs extends JPanel {
private Application app = Application.getInstance();
private Configuration config = app.getConfiguration();
private PlaylistManager playlistManager = app.getPlaylistManager();
private JTabbedPane tabbedPane;
private Component singleTab;
private boolean tabsVisible;
private PlaylistTable selectedTable;
private int dragTo = -1;
private int dragFrom;
private String singleTitle;
public PlaylistTabs() {
setLayout(new BorderLayout());
tabbedPane = new JTabbedPane();
add(tabbedPane);
tabsVisible = true;
tabbedPane.setFocusable(false);
if (Util.isGTKLaF()) {
tabbedPane.setPreferredSize(new Dimension(10000, 30));
} else {
tabbedPane.setPreferredSize(new Dimension(10000, 25));
}
buildListeners();
createActions();
}
private void checkTabCount() {
if (!config.getBoolean("playlists.tabs.hideSingle", true)) {
return;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
int count = tabbedPane.getTabCount();
if (tabsVisible && count <= 1) {
tabsVisible = false;
remove(tabbedPane);
if (count == 1) {
singleTab = tabbedPane.getComponentAt(0);
singleTitle = tabbedPane.getTitleAt(0);
tabbedPane.removeAll();
add(singleTab, BorderLayout.CENTER);
setBorder(BorderFactory.createEtchedBorder());
}
revalidate();
repaint();
} else if (!tabsVisible && count > 0) {
tabsVisible = true;
removeAll();
tabbedPane.add(singleTab, 0);
tabbedPane.setTitleAt(0, singleTitle);
singleTab = null;
add(tabbedPane, BorderLayout.CENTER);
setBorder(BorderFactory.createEmptyBorder());
revalidate();
repaint();
}
}
});
}
@Override
public void updateUI() {
super.updateUI();
if (tabbedPane != null)
tabbedPane.updateUI();
}
public PlaylistTable getTableAt(int index) {
try {
Component comp;
if (!tabsVisible) {
comp = singleTab;
} else {
comp = tabbedPane.getComponentAt(index);
}
return (PlaylistTable) ((JScrollPane) comp).getViewport().getView();
} catch (Exception e) {
return null;
}
}
public PlaylistTable getSelectedTable() {
return selectedTable;
}
private void buildListeners() {
tabbedPane.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
int index = tabbedPane.getSelectedIndex();
if (index == -1)
return;
selectedTable = getTableAt(index);
playlistManager.setVisiblePlaylist(selectedTable.getPlaylist());
}
});
tabbedPane.addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent e) {
dragTo = tabbedPane.indexAtLocation(e.getX(), e.getY());
repaint();
}
@Override
public void mouseMoved(MouseEvent e) {
}
});
tabbedPane.addMouseListener(new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent e) {
if (dragFrom != -1 && dragTo != -1 && dragFrom != dragTo) {
playlistManager.movePlaylist(dragFrom, dragTo);
Component comp = tabbedPane.getComponentAt(dragFrom);
String title = tabbedPane.getTitleAt(dragFrom);
tabbedPane.removeTabAt(dragFrom);
tabbedPane.insertTab(title, null, comp, null, dragTo);
tabbedPane.setSelectedIndex(dragTo);
}
dragTo = -1;
}
@Override
public void mousePressed(MouseEvent e) {
dragFrom = tabbedPane.indexAtLocation(e.getX(), e.getY());
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1 &&
e.getClickCount() == 2) {
tabbedPane.getActionMap().get("newPlaylist").actionPerformed(
new ActionEvent(this, ActionEvent.ACTION_PERFORMED, null));
} else if (e.getButton() == MouseEvent.BUTTON2) {
int index = tabbedPane.indexAtLocation(e.getX(), e.getY());
if (index != -1) {
Playlist playlist = getTableAt(index).getPlaylist();
playlistManager.removePlaylist(playlist);
}
}
}
});
playlistManager.addPlaylistListener(new PlaylistListener() {
@Override
public void playlistRemoved(Playlist playlist) {
if (tabbedPane.getTabCount() > 0) {
for (int i = 0; i < getTabCount(); i++) {
if (getTableAt(i).getPlaylist() == playlist) {
tabbedPane.remove(i);
checkTabCount();
break;
}
}
} else {
singleTab = null;
}
}
@Override
public void playlistAdded(Playlist playlist) {
addPlaylist(playlist);
tabbedPane.setSelectedIndex(getTabCount() - 1);
}
@Override
public void playlistSelected(Playlist playlist) {
if (getTabCount() > 1)
for (int i = 0; i < getTabCount(); i++) {
if (getTableAt(i).getPlaylist() == playlist) {
tabbedPane.setSelectedIndex(i);
break;
}
}
}
});
}
private void createActions() {
ActionMap aMap = tabbedPane.getActionMap();
aMap.put("newPlaylist", new AbstractAction("Add New Playlist") {
@Override
public void actionPerformed(ActionEvent e) {
String name = JOptionPane.showInputDialog("Enter Playlist Name", "New Playlist");
if (!Util.isEmpty(name))
addPlaylist(name);
}
});
aMap.put("renamePlaylist", new AbstractAction("Rename") {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedTable != null) {
Playlist playlist = selectedTable.getPlaylist();
String name = JOptionPane.showInputDialog("Rename", playlist.getName());
if (!Util.isEmpty(name)) {
playlist.setName(name);
tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), center(name));
}
}
}
});
aMap.put("removePlaylist", new AbstractAction("Remove Playlist") {
@Override
public void actionPerformed(ActionEvent e) {
if (selectedTable != null) {
playlistManager.removePlaylist(selectedTable.getPlaylist());
checkTabCount();
}
}
});
aMap.put("savePlaylist", new AbstractAction("Save Playlist") {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
String path = config.getString("playlists.lastDir", "");
if (!path.isEmpty()) fc.setCurrentDirectory(new File(path));
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setAcceptAllFileFilterUsed(false);
FileNameExtensionFilter musFiler = new FileNameExtensionFilter("Musique Playlist", "mus");
FileNameExtensionFilter m3uFilter = new FileNameExtensionFilter("M3U Playlist", "m3u", "m3u8");
FileNameExtensionFilter plsFiler = new FileNameExtensionFilter("PLS Playlist", "pls");
fc.addChoosableFileFilter(musFiler);
fc.addChoosableFileFilter(m3uFilter);
fc.addChoosableFileFilter(plsFiler);
Playlist playlist = selectedTable.getPlaylist();
String fileName = playlist.getName().toLowerCase().replaceAll("\\s+", "_");
fc.setSelectedFile(new File(fileName));
int ret = fc.showSaveDialog(getRootPane());
if (ret == JFileChooser.APPROVE_OPTION) {
FileNameExtensionFilter filter = (FileNameExtensionFilter) fc.getFileFilter();
File file = fc.getSelectedFile();
String suffix = filter.getExtensions()[0];
if (!file.getName().endsWith(suffix)) {
file = new File(file.getParent(),
Util.removeExt(file.getName()) + "." + suffix);
}
if (filter == musFiler) {
playlist.save(file);
} else if (filter == m3uFilter) {
playlist.saveM3U(file);
} else if (filter == plsFiler) {
playlist.savePLS(file);
}
config.setString("playlists.lastDir", fc.getCurrentDirectory().getAbsolutePath());
}
}
});
aMap.put("loadPlaylist", new AbstractAction("Load Playlist") {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser fc = new JFileChooser();
String path = config.getString("playlists.lastDir", "");
if (!path.isEmpty()) fc.setCurrentDirectory(new File(path));
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
fc.addChoosableFileFilter(new FileNameExtensionFilter("All supported formats", "mus", "m3u", "m3u8", "pls"));
fc.addChoosableFileFilter(new FileNameExtensionFilter("Musique Playlist", "mus"));
fc.addChoosableFileFilter(new FileNameExtensionFilter("M3U Playlist", "m3u", "m3u8"));
fc.addChoosableFileFilter(new FileNameExtensionFilter("PLS Playlist", "pls"));
int ret = fc.showOpenDialog(getRootPane());
if (ret == JFileChooser.APPROVE_OPTION) {
File file = fc.getSelectedFile();
Playlist playlist = addPlaylist(Util.capitalize(Util.removeExt(file.getName()), " "));
ProgressDialog dialog = new ProgressDialog(tabbedPane, "Adding Files");
dialog.show(new Task.FileAddingTask(playlist, new File[]{fc.getSelectedFile()}, -1));
config.setString("playlists.lastDir", fc.getCurrentDirectory().getAbsolutePath());
}
}
});
tabbedPane.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
show(e);
}
@Override
public void mouseReleased(MouseEvent e) {
show(e);
}
public void show(MouseEvent e) {
if (e.isPopupTrigger()) {
int index = tabbedPane.indexAtLocation(e.getX(), e.getY());
if (index != -1)
tabbedPane.setSelectedIndex(index);
buildPopupMenu().show(e.getComponent(), e.getX(), e.getY());
}
}
});
}
private JPopupMenu buildPopupMenu() {
ActionMap aMap = tabbedPane.getActionMap();
final JPopupMenu tabMenu = new JPopupMenu();
ImageIcon emptyIcon = new ImageIcon(new BufferedImage(10, 10, BufferedImage.TYPE_INT_ARGB));
tabMenu.add(aMap.get("newPlaylist")).setIcon(emptyIcon);
tabMenu.add(aMap.get("renamePlaylist"));
tabMenu.add(aMap.get("removePlaylist"));
tabMenu.addSeparator();
tabMenu.add(aMap.get("savePlaylist"));
tabMenu.add(aMap.get("loadPlaylist"));
Util.fixIconTextGap(tabMenu);
return tabMenu;
}
public Playlist addPlaylist(String name) {
return playlistManager.addPlaylist(name);
}
public PlaylistTable addPlaylist(Playlist playlist) {
PlaylistTable newTable = new PlaylistTable(playlist, playlist.getColumns());
newTable.setUpDndCCP();
addTab(playlist.getName(), newTable.getScrollPane());
return newTable;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (dragTo != -1 && dragFrom != -1 && dragTo != dragFrom) {
Rectangle b = tabbedPane.getBoundsAt(dragTo);
g.setColor(Color.GRAY);
int x = (int) (b.getX());
if (dragTo > dragFrom)
x += b.getWidth();
int y = (int) b.getY();
g.fillRect(x - 1, y + 2, 3, (int) b.getHeight() - 2);
int[] xP = {x - 1, x - 5, x + 5, x + 1};
int[] yP = {y + 2, y - 5, y - 5, y + 2};
g.fillPolygon(xP, yP, xP.length);
}
}
public void setSelectedIndex(int i) {
if (tabbedPane.getTabCount() > i)
tabbedPane.setSelectedIndex(i);
}
public int getTabCount() {
if (!tabsVisible) {
return singleTab != null ? 1 : 0;
} else {
return tabbedPane.getTabCount();
}
}
public void addTab(String name, JComponent comp) {
String title = center(name);
tabbedPane.addTab(title, comp);
checkTabCount();
}
private String center(String name) {
return Util.center(name, 7, 10);
}
public ActionMap getActions() {
return tabbedPane.getActionMap();
}
}