Refactored construction of Swing player controls to their own class.

This commit is contained in:
neviyn 2016-03-29 16:05:08 +01:00
parent ab0680b5ee
commit 05cebf59fb
11 changed files with 188 additions and 99 deletions

View File

@ -32,7 +32,7 @@
<manifest> <manifest>
<addClasspath>true</addClasspath> <addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix> <classpathPrefix>lib/</classpathPrefix>
<mainClass>musicplayer.PlayerGUI</mainClass> <mainClass>musicplayer.Main</mainClass>
</manifest> </manifest>
</archive> </archive>
</configuration> </configuration>

View File

@ -0,0 +1,29 @@
package musicplayer;
import com.google.inject.Guice;
import com.google.inject.Injector;
import musicplayer.swingui.PlayerGUI;
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
runSwingUIMode();
}
/**
* Start the application with injection bindings contained in SwingUIModule
*/
private static void runSwingUIMode() {
Injector injector = Guice.createInjector(new SwingUIModule());
PlayerGUI playerGUI = injector.getInstance(PlayerGUI.class);
JFrame frame = new JFrame();
frame.setMinimumSize(new Dimension(600, 400));
frame.setContentPane(playerGUI);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}

View File

@ -2,6 +2,7 @@ package musicplayer;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import musicplayer.callbacks.PlayerCallbackInterface;
import musicplayer.db.HibernateDatabase; import musicplayer.db.HibernateDatabase;
import musicplayer.db.IDatabase; import musicplayer.db.IDatabase;
import musicplayer.library.ILibrary; import musicplayer.library.ILibrary;
@ -10,6 +11,7 @@ import musicplayer.player.GStreamerPlayer;
import musicplayer.player.IPlayer; import musicplayer.player.IPlayer;
import musicplayer.playlist.IPlaylist; import musicplayer.playlist.IPlaylist;
import musicplayer.playlist.JTablePlaylist; import musicplayer.playlist.JTablePlaylist;
import musicplayer.swingui.PlayerGUI;
class SwingUIModule extends AbstractModule { class SwingUIModule extends AbstractModule {
@ -19,5 +21,6 @@ class SwingUIModule extends AbstractModule {
bind(IDatabase.class).to(HibernateDatabase.class).in(Singleton.class); bind(IDatabase.class).to(HibernateDatabase.class).in(Singleton.class);
bind(IPlaylist.class).to(JTablePlaylist.class).in(Singleton.class); bind(IPlaylist.class).to(JTablePlaylist.class).in(Singleton.class);
bind(ILibrary.class).to(JTreeLibrary.class).in(Singleton.class); bind(ILibrary.class).to(JTreeLibrary.class).in(Singleton.class);
bind(PlayerCallbackInterface.class).to(PlayerGUI.class);
} }
} }

View File

@ -1,9 +1,5 @@
package musicplayer.callbacks; package musicplayer.callbacks;
import com.google.inject.ImplementedBy;
import musicplayer.PlayerGUI;
@ImplementedBy(PlayerGUI.class)
public interface PlayerCallbackInterface { public interface PlayerCallbackInterface {
/** /**

View File

@ -0,0 +1,119 @@
package musicplayer.swingui;
import musicplayer.StartPlayingException;
import musicplayer.player.IPlayer;
import musicplayer.util.Icons;
import javax.swing.*;
import java.awt.*;
public class ControlBar extends JPanel {
IPlayer player;
public ControlBar(IPlayer player){
this.player = player;
setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
add(playButton());
add(pauseButton());
add(stopButton());
add(previousButton());
add(nextButton());
add(repeatButton());
}
private JButton playButton(){
JButton playButton = new ControlButton(Icons.playIcon);
playButton.setName("playButton");
playButton.setMnemonic('P');
playButton.addActionListener(e -> {
try {
player.play();
} catch (StartPlayingException e1) {
showError(e1);
}
});
return playButton;
}
private JButton pauseButton(){
JButton pauseButton = new ControlButton(Icons.pauseIcon);
pauseButton.setMnemonic('E');
pauseButton.addActionListener(e -> player.pause());
return pauseButton;
}
private JButton stopButton(){
JButton stopButton = new ControlButton(Icons.stopIcon);
stopButton.setMnemonic('S');
stopButton.addActionListener(e -> player.stop());
return stopButton;
}
private JButton previousButton(){
JButton previousButton = new ControlButton(Icons.prevIcon);
previousButton.setMnemonic('R');
previousButton.addActionListener(e -> {
try {
player.previous();
} catch (StartPlayingException e1) {
showError(e1);
}
});
return previousButton;
}
private JButton nextButton(){
JButton nextButton = new ControlButton(Icons.nextIcon);
nextButton.setMnemonic('N');
nextButton.addActionListener(e -> {
try {
player.next();
} catch (StartPlayingException e1) {
showError(e1);
}
});
return nextButton;
}
private JButton repeatButton(){
JButton repeatButton = new ControlButton(Icons.repeatMultiIcon);
repeatButton.setToolTipText("Repeating playlist.");
repeatButton.addActionListener(e -> {
player.setRepeat(!player.isRepeating());
if(player.isRepeating()) {
repeatButton.setIcon(Icons.repeatSingleIcon);
repeatButton.setToolTipText("Repeating song.");
}
else {
repeatButton.setIcon(Icons.repeatMultiIcon);
repeatButton.setToolTipText("Repeating playlist.");
}
});
return repeatButton;
}
private void showError(StartPlayingException ex) {
JOptionPane.showMessageDialog(this, "Failed to play " + ex.getSong().toString() + ".\n" +
"If file path contains non-ASCII characters, please restart the application with UTF-8 encoding.");
}
/**
* Button for performing some control action on the player
*/
private class ControlButton extends JButton {
public ControlButton(Icon icon){
setIcon(icon);
}
final Dimension buttonSize = new Dimension(40, 40);
@Override
public Dimension getPreferredSize() {
return buttonSize;
}
@Override
public Dimension getMaximumSize() {
return buttonSize;
}
}
}

View File

@ -1,4 +1,4 @@
package musicplayer; package musicplayer.swingui;
import musicplayer.util.ConfigManager; import musicplayer.util.ConfigManager;

View File

@ -1,14 +1,12 @@
package musicplayer; package musicplayer.swingui;
import com.google.inject.Guice;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Injector; import musicplayer.StartPlayingException;
import musicplayer.callbacks.PlayerCallbackInterface; import musicplayer.callbacks.PlayerCallbackInterface;
import musicplayer.library.ILibrary; import musicplayer.library.ILibrary;
import musicplayer.player.IPlayer; import musicplayer.player.IPlayer;
import musicplayer.playlist.IPlaylist; import musicplayer.playlist.IPlaylist;
import musicplayer.util.ConfigManager; import musicplayer.util.ConfigManager;
import musicplayer.util.Icons;
import org.jnativehook.GlobalScreen; import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException; import org.jnativehook.NativeHookException;
import org.jnativehook.keyboard.NativeKeyEvent; import org.jnativehook.keyboard.NativeKeyEvent;
@ -61,7 +59,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
} }
}); });
Runtime.getRuntime().addShutdownHook(hookShutdown); Runtime.getRuntime().addShutdownHook(hookShutdown);
} catch(RuntimeException | NativeHookException |UnsatisfiedLinkError ex){ } catch (RuntimeException | NativeHookException | UnsatisfiedLinkError ex) {
System.out.println("Keyboard hook failed, global shortcuts will not work this session."); System.out.println("Keyboard hook failed, global shortcuts will not work this session.");
System.out.println(ex.getMessage()); System.out.println(ex.getMessage());
System.out.println(Arrays.toString(ex.getStackTrace())); System.out.println(Arrays.toString(ex.getStackTrace()));
@ -69,17 +67,6 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
library.refreshLibrary(); library.refreshLibrary();
} }
public static void main(String[] args) {
Injector injector = Guice.createInjector(new SwingUIModule());
PlayerGUI playerGUI = injector.getInstance(PlayerGUI.class);
JFrame frame = new JFrame();
frame.setMinimumSize(new Dimension(600, 400));
frame.setContentPane(playerGUI);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
/** /**
* Set the value of seekBar. * Set the value of seekBar.
* *
@ -87,7 +74,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
*/ */
public void setSeekBarPosition(int position) { public void setSeekBarPosition(int position) {
SwingUtilities.invokeLater(() -> { SwingUtilities.invokeLater(() -> {
if(!seeking.get()) if (!seeking.get())
seekBar.setValue(position); seekBar.setValue(position);
}); });
} }
@ -101,7 +88,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
SwingUtilities.invokeLater(() -> seekBar.setMaximum(seconds)); SwingUtilities.invokeLater(() -> seekBar.setMaximum(seconds));
} }
private void showError(StartPlayingException ex){ private void showError(StartPlayingException ex) {
JOptionPane.showMessageDialog(this, "Failed to play " + ex.getSong().toString() + ".\n" + JOptionPane.showMessageDialog(this, "Failed to play " + ex.getSong().toString() + ".\n" +
"If file path contains non-ASCII characters, please restart the application with UTF-8 encoding."); "If file path contains non-ASCII characters, please restart the application with UTF-8 encoding.");
} }
@ -123,9 +110,9 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
this.setLayout(new BorderLayout(0, 0)); this.setLayout(new BorderLayout(0, 0));
final JSplitPane libraryAndPlaylistPane = new JSplitPane(); final JSplitPane libraryAndPlaylistPane = new JSplitPane();
libraryAndPlaylistPane.setDividerLocation(240); libraryAndPlaylistPane.setDividerLocation(240);
libraryAndPlaylistPane.setRightComponent((JScrollPane)playlist); libraryAndPlaylistPane.setRightComponent((JScrollPane) playlist);
this.add(libraryAndPlaylistPane, BorderLayout.CENTER); this.add(libraryAndPlaylistPane, BorderLayout.CENTER);
libraryAndPlaylistPane.setLeftComponent((JPanel)library); libraryAndPlaylistPane.setLeftComponent((JPanel) library);
final JPanel controlPane = new JPanel(); final JPanel controlPane = new JPanel();
controlPane.setLayout(new BorderLayout(0, 0)); controlPane.setLayout(new BorderLayout(0, 0));
this.add(controlPane, BorderLayout.SOUTH); this.add(controlPane, BorderLayout.SOUTH);
@ -144,52 +131,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
private JToolBar createControlButtons() { private JToolBar createControlButtons() {
JToolBar toolBar = new JToolBar(); JToolBar toolBar = new JToolBar();
toolBar.setFloatable(false); toolBar.setFloatable(false);
JPanel controlBar = new JPanel(new GridLayout(1, 5)); toolBar.add(new ControlBar(player));
JButton playButton = new JButton();
playButton.setName("playButton");
playButton.setIcon(Icons.playIcon);
playButton.setMnemonic('P');
playButton.addActionListener(e -> {
try {
player.play();
} catch (StartPlayingException e1) {
showError(e1);
}
});
controlBar.add(playButton);
JButton pauseButton = new JButton();
pauseButton.setIcon(Icons.pauseIcon);
pauseButton.setMnemonic('E');
pauseButton.addActionListener(e -> player.pause());
controlBar.add(pauseButton);
JButton stopButton = new JButton();
stopButton.setIcon(Icons.stopIcon);
stopButton.setMnemonic('S');
stopButton.addActionListener(e -> player.stop());
controlBar.add(stopButton);
JButton previousButton = new JButton();
previousButton.setIcon(Icons.prevIcon);
previousButton.setMnemonic('R');
previousButton.addActionListener(e -> {
try {
player.previous();
} catch (StartPlayingException e1) {
showError(e1);
}
});
controlBar.add(previousButton);
JButton nextButton = new JButton();
nextButton.setIcon(Icons.nextIcon);
nextButton.setMnemonic('N');
nextButton.addActionListener(e -> {
try {
player.next();
} catch (StartPlayingException e1) {
showError(e1);
}
});
controlBar.add(nextButton);
toolBar.add(controlBar);
toolBar.add(createVolumeControls()); toolBar.add(createVolumeControls());
return toolBar; return toolBar;
} }
@ -252,7 +194,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
FileNameExtensionFilter m3uExtensionFilter = new FileNameExtensionFilter("m3u playlist", "m3u"); FileNameExtensionFilter m3uExtensionFilter = new FileNameExtensionFilter("m3u playlist", "m3u");
menuItem = new JMenuItem("Save Playlist"); menuItem = new JMenuItem("Save Playlist");
menuItem.addActionListener(e -> { menuItem.addActionListener(e -> {
if(!playlist.isEmpty()) { if (!playlist.isEmpty()) {
JFileChooser fileChooser = new JFileChooser(); JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogType(JFileChooser.SAVE_DIALOG); fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
fileChooser.setSelectedFile(new File("playlist.m3u")); fileChooser.setSelectedFile(new File("playlist.m3u"));
@ -276,7 +218,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
JFileChooser fileChooser = new JFileChooser(); JFileChooser fileChooser = new JFileChooser();
fileChooser.setDialogType(JFileChooser.OPEN_DIALOG); fileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
fileChooser.setFileFilter(m3uExtensionFilter); fileChooser.setFileFilter(m3uExtensionFilter);
if(fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){ if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
IPlaylist.readPlaylistFromFile(fileChooser.getSelectedFile()).stream().forEach(playlist::addSong); IPlaylist.readPlaylistFromFile(fileChooser.getSelectedFile()).stream().forEach(playlist::addSong);
} }
}); });
@ -288,7 +230,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
JMenu helpMenu = new JMenu("Help"); JMenu helpMenu = new JMenu("Help");
menuItem = new JMenuItem("About"); menuItem = new JMenuItem("About");
menuItem.addActionListener(e -> { menuItem.addActionListener(e -> {
try(BufferedReader reader = new BufferedReader(new InputStreamReader(PlayerGUI.class.getClassLoader().getResourceAsStream("LICENSE.txt")))) { try (BufferedReader reader = new BufferedReader(new InputStreamReader(PlayerGUI.class.getClassLoader().getResourceAsStream("LICENSE.txt")))) {
JEditorPane messagePane = new JEditorPane("text/html", reader.lines().collect(Collectors.toList()).get(0)); JEditorPane messagePane = new JEditorPane("text/html", reader.lines().collect(Collectors.toList()).get(0));
messagePane.setEditable(false); messagePane.setEditable(false);
messagePane.addHyperlinkListener(hl -> messagePane.addHyperlinkListener(hl ->
@ -319,10 +261,14 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
*/ */
private class SeekbarMouseListener implements MouseListener { private class SeekbarMouseListener implements MouseListener {
@Override @Override
public void mouseClicked(MouseEvent e) { seeking.set(true); } public void mouseClicked(MouseEvent e) {
seeking.set(true);
}
@Override @Override
public void mousePressed(MouseEvent e) { seeking.set(true); } public void mousePressed(MouseEvent e) {
seeking.set(true);
}
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
@ -331,10 +277,12 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
} }
@Override @Override
public void mouseEntered(MouseEvent e) {} public void mouseEntered(MouseEvent e) {
}
@Override @Override
public void mouseExited(MouseEvent e) {} public void mouseExited(MouseEvent e) {
}
} }
private class GlobalKeyboardShortcuts implements NativeKeyListener { private class GlobalKeyboardShortcuts implements NativeKeyListener {
@ -346,19 +294,19 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
@Override @Override
public void nativeKeyPressed(NativeKeyEvent nativeKeyEvent) { public void nativeKeyPressed(NativeKeyEvent nativeKeyEvent) {
if(nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L) if (nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L)
modified = true; modified = true;
} }
@Override @Override
public void nativeKeyReleased(NativeKeyEvent nativeKeyEvent) { public void nativeKeyReleased(NativeKeyEvent nativeKeyEvent) {
if(nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L) if (nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L)
modified = false; modified = false;
} }
@Override @Override
public void nativeKeyTyped(NativeKeyEvent nativeKeyEvent) { public void nativeKeyTyped(NativeKeyEvent nativeKeyEvent) {
if(modified){ if (modified) {
try { try {
switch (nativeKeyEvent.getRawCode()) { switch (nativeKeyEvent.getRawCode()) {
case playPause: case playPause:
@ -378,10 +326,10 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
player.next(); player.next();
break; break;
} }
}catch (StartPlayingException ex){ } catch (StartPlayingException ex) {
showError(ex); showError(ex);
} }
} }
} }
} }
} }

View File

@ -42,11 +42,7 @@ public final class ConfigManager {
*/ */
public static void saveLibraryDirectories(List<File> folderList){ public static void saveLibraryDirectories(List<File> folderList){
librarySettings.setProperty(foldersKey, folderList.stream().map(File::toString).collect(Collectors.joining(","))); librarySettings.setProperty(foldersKey, folderList.stream().map(File::toString).collect(Collectors.joining(",")));
try(FileWriter fileWriter = new FileWriter(settingsFilename)){ writeSettings();
librarySettings.store(fileWriter, "");
} catch (IOException e) {
e.printStackTrace();
}
} }
/** /**
@ -61,11 +57,7 @@ public final class ConfigManager {
} catch (IOException ignored) { } catch (IOException ignored) {
} }
librarySettings.setProperty(databaseKey, "musicDB"); librarySettings.setProperty(databaseKey, "musicDB");
try(FileWriter fileWriter = new FileWriter(settingsFilename)){ writeSettings();
librarySettings.store(fileWriter, "");
} catch (IOException e) {
e.printStackTrace();
}
return "jdbc:hsqldb:file:" + new File("musicDB").getAbsolutePath() + ";shutdown=true"; //Use relative file by default return "jdbc:hsqldb:file:" + new File("musicDB").getAbsolutePath() + ";shutdown=true"; //Use relative file by default
} }
@ -89,11 +81,7 @@ public final class ConfigManager {
*/ */
public static void setLastDisplayTypeIndex(Integer index){ public static void setLastDisplayTypeIndex(Integer index){
librarySettings.setProperty(libraryDisplayKey, index.toString()); librarySettings.setProperty(libraryDisplayKey, index.toString());
try(FileWriter fileWriter = new FileWriter(settingsFilename)){ writeSettings();
librarySettings.store(fileWriter, "");
} catch (IOException e) {
e.printStackTrace();
}
} }
public static int getLastVolume(){ public static int getLastVolume(){
@ -109,6 +97,10 @@ public final class ConfigManager {
public static void setLastVolume(Integer index){ public static void setLastVolume(Integer index){
librarySettings.setProperty(lastVolumeKey, index.toString()); librarySettings.setProperty(lastVolumeKey, index.toString());
writeSettings();
}
private static void writeSettings(){
try(FileWriter fileWriter = new FileWriter(settingsFilename)){ try(FileWriter fileWriter = new FileWriter(settingsFilename)){
librarySettings.store(fileWriter, ""); librarySettings.store(fileWriter, "");
} catch (IOException e) { } catch (IOException e) {

View File

@ -11,4 +11,6 @@ public final class Icons {
public static final Icon stopIcon = new ImageIcon(classLoader.getResource("glyphicons-176-stop.png")); public static final Icon stopIcon = new ImageIcon(classLoader.getResource("glyphicons-176-stop.png"));
public static final Icon prevIcon = new ImageIcon(classLoader.getResource("glyphicons-171-step-backward.png")); public static final Icon prevIcon = new ImageIcon(classLoader.getResource("glyphicons-171-step-backward.png"));
public static final Icon nextIcon = new ImageIcon(classLoader.getResource("glyphicons-179-step-forward.png")); public static final Icon nextIcon = new ImageIcon(classLoader.getResource("glyphicons-179-step-forward.png"));
public static final Icon repeatSingleIcon = new ImageIcon(classLoader.getResource("glyphicons-86-repeat.png"));
public static final Icon repeatMultiIcon = new ImageIcon(classLoader.getResource("glyphicons-83-roundabout.png"));
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB