Refactored construction of Swing player controls to their own class.
This commit is contained in:
parent
ab0680b5ee
commit
05cebf59fb
2
pom.xml
2
pom.xml
@ -32,7 +32,7 @@
|
||||
<manifest>
|
||||
<addClasspath>true</addClasspath>
|
||||
<classpathPrefix>lib/</classpathPrefix>
|
||||
<mainClass>musicplayer.PlayerGUI</mainClass>
|
||||
<mainClass>musicplayer.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
</configuration>
|
||||
|
29
src/main/java/musicplayer/Main.java
Normal file
29
src/main/java/musicplayer/Main.java
Normal 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);
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package musicplayer;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Singleton;
|
||||
import musicplayer.callbacks.PlayerCallbackInterface;
|
||||
import musicplayer.db.HibernateDatabase;
|
||||
import musicplayer.db.IDatabase;
|
||||
import musicplayer.library.ILibrary;
|
||||
@ -10,6 +11,7 @@ import musicplayer.player.GStreamerPlayer;
|
||||
import musicplayer.player.IPlayer;
|
||||
import musicplayer.playlist.IPlaylist;
|
||||
import musicplayer.playlist.JTablePlaylist;
|
||||
import musicplayer.swingui.PlayerGUI;
|
||||
|
||||
class SwingUIModule extends AbstractModule {
|
||||
|
||||
@ -19,5 +21,6 @@ class SwingUIModule extends AbstractModule {
|
||||
bind(IDatabase.class).to(HibernateDatabase.class).in(Singleton.class);
|
||||
bind(IPlaylist.class).to(JTablePlaylist.class).in(Singleton.class);
|
||||
bind(ILibrary.class).to(JTreeLibrary.class).in(Singleton.class);
|
||||
bind(PlayerCallbackInterface.class).to(PlayerGUI.class);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,5 @@
|
||||
package musicplayer.callbacks;
|
||||
|
||||
import com.google.inject.ImplementedBy;
|
||||
import musicplayer.PlayerGUI;
|
||||
|
||||
@ImplementedBy(PlayerGUI.class)
|
||||
public interface PlayerCallbackInterface {
|
||||
|
||||
/**
|
||||
|
119
src/main/java/musicplayer/swingui/ControlBar.java
Normal file
119
src/main/java/musicplayer/swingui/ControlBar.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package musicplayer;
|
||||
package musicplayer.swingui;
|
||||
|
||||
import musicplayer.util.ConfigManager;
|
||||
|
@ -1,14 +1,12 @@
|
||||
package musicplayer;
|
||||
package musicplayer.swingui;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Injector;
|
||||
import musicplayer.StartPlayingException;
|
||||
import musicplayer.callbacks.PlayerCallbackInterface;
|
||||
import musicplayer.library.ILibrary;
|
||||
import musicplayer.player.IPlayer;
|
||||
import musicplayer.playlist.IPlaylist;
|
||||
import musicplayer.util.ConfigManager;
|
||||
import musicplayer.util.Icons;
|
||||
import org.jnativehook.GlobalScreen;
|
||||
import org.jnativehook.NativeHookException;
|
||||
import org.jnativehook.keyboard.NativeKeyEvent;
|
||||
@ -61,7 +59,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
}
|
||||
});
|
||||
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(ex.getMessage());
|
||||
System.out.println(Arrays.toString(ex.getStackTrace()));
|
||||
@ -69,17 +67,6 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
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.
|
||||
*
|
||||
@ -87,7 +74,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
*/
|
||||
public void setSeekBarPosition(int position) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
if(!seeking.get())
|
||||
if (!seeking.get())
|
||||
seekBar.setValue(position);
|
||||
});
|
||||
}
|
||||
@ -101,7 +88,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
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" +
|
||||
"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));
|
||||
final JSplitPane libraryAndPlaylistPane = new JSplitPane();
|
||||
libraryAndPlaylistPane.setDividerLocation(240);
|
||||
libraryAndPlaylistPane.setRightComponent((JScrollPane)playlist);
|
||||
libraryAndPlaylistPane.setRightComponent((JScrollPane) playlist);
|
||||
this.add(libraryAndPlaylistPane, BorderLayout.CENTER);
|
||||
libraryAndPlaylistPane.setLeftComponent((JPanel)library);
|
||||
libraryAndPlaylistPane.setLeftComponent((JPanel) library);
|
||||
final JPanel controlPane = new JPanel();
|
||||
controlPane.setLayout(new BorderLayout(0, 0));
|
||||
this.add(controlPane, BorderLayout.SOUTH);
|
||||
@ -144,52 +131,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
private JToolBar createControlButtons() {
|
||||
JToolBar toolBar = new JToolBar();
|
||||
toolBar.setFloatable(false);
|
||||
JPanel controlBar = new JPanel(new GridLayout(1, 5));
|
||||
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(new ControlBar(player));
|
||||
toolBar.add(createVolumeControls());
|
||||
return toolBar;
|
||||
}
|
||||
@ -252,7 +194,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
FileNameExtensionFilter m3uExtensionFilter = new FileNameExtensionFilter("m3u playlist", "m3u");
|
||||
menuItem = new JMenuItem("Save Playlist");
|
||||
menuItem.addActionListener(e -> {
|
||||
if(!playlist.isEmpty()) {
|
||||
if (!playlist.isEmpty()) {
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
|
||||
fileChooser.setSelectedFile(new File("playlist.m3u"));
|
||||
@ -276,7 +218,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
JFileChooser fileChooser = new JFileChooser();
|
||||
fileChooser.setDialogType(JFileChooser.OPEN_DIALOG);
|
||||
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);
|
||||
}
|
||||
});
|
||||
@ -288,7 +230,7 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
JMenu helpMenu = new JMenu("Help");
|
||||
menuItem = new JMenuItem("About");
|
||||
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));
|
||||
messagePane.setEditable(false);
|
||||
messagePane.addHyperlinkListener(hl ->
|
||||
@ -319,10 +261,14 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
*/
|
||||
private class SeekbarMouseListener implements MouseListener {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) { seeking.set(true); }
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
seeking.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) { seeking.set(true); }
|
||||
public void mousePressed(MouseEvent e) {
|
||||
seeking.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
@ -331,10 +277,12 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {}
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {}
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
}
|
||||
|
||||
private class GlobalKeyboardShortcuts implements NativeKeyListener {
|
||||
@ -346,19 +294,19 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
|
||||
@Override
|
||||
public void nativeKeyPressed(NativeKeyEvent nativeKeyEvent) {
|
||||
if(nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L)
|
||||
if (nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L)
|
||||
modified = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeKeyReleased(NativeKeyEvent nativeKeyEvent) {
|
||||
if(nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L)
|
||||
if (nativeKeyEvent.getKeyCode() == NativeKeyEvent.VC_ALT_L)
|
||||
modified = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nativeKeyTyped(NativeKeyEvent nativeKeyEvent) {
|
||||
if(modified){
|
||||
if (modified) {
|
||||
try {
|
||||
switch (nativeKeyEvent.getRawCode()) {
|
||||
case playPause:
|
||||
@ -378,10 +326,10 @@ public class PlayerGUI extends JPanel implements PlayerCallbackInterface {
|
||||
player.next();
|
||||
break;
|
||||
}
|
||||
}catch (StartPlayingException ex){
|
||||
} catch (StartPlayingException ex) {
|
||||
showError(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -42,11 +42,7 @@ public final class ConfigManager {
|
||||
*/
|
||||
public static void saveLibraryDirectories(List<File> folderList){
|
||||
librarySettings.setProperty(foldersKey, folderList.stream().map(File::toString).collect(Collectors.joining(",")));
|
||||
try(FileWriter fileWriter = new FileWriter(settingsFilename)){
|
||||
librarySettings.store(fileWriter, "");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -61,11 +57,7 @@ public final class ConfigManager {
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
librarySettings.setProperty(databaseKey, "musicDB");
|
||||
try(FileWriter fileWriter = new FileWriter(settingsFilename)){
|
||||
librarySettings.store(fileWriter, "");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
writeSettings();
|
||||
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){
|
||||
librarySettings.setProperty(libraryDisplayKey, index.toString());
|
||||
try(FileWriter fileWriter = new FileWriter(settingsFilename)){
|
||||
librarySettings.store(fileWriter, "");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
public static int getLastVolume(){
|
||||
@ -109,6 +97,10 @@ public final class ConfigManager {
|
||||
|
||||
public static void setLastVolume(Integer index){
|
||||
librarySettings.setProperty(lastVolumeKey, index.toString());
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
private static void writeSettings(){
|
||||
try(FileWriter fileWriter = new FileWriter(settingsFilename)){
|
||||
librarySettings.store(fileWriter, "");
|
||||
} catch (IOException e) {
|
||||
|
@ -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 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 repeatSingleIcon = new ImageIcon(classLoader.getResource("glyphicons-86-repeat.png"));
|
||||
public static final Icon repeatMultiIcon = new ImageIcon(classLoader.getResource("glyphicons-83-roundabout.png"));
|
||||
}
|
||||
|
BIN
src/main/resources/glyphicons-83-roundabout.png
Normal file
BIN
src/main/resources/glyphicons-83-roundabout.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
BIN
src/main/resources/glyphicons-86-repeat.png
Normal file
BIN
src/main/resources/glyphicons-86-repeat.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
Loading…
Reference in New Issue
Block a user