diff --git a/src/main/java/handiebot/HandieBot.java b/src/main/java/handiebot/HandieBot.java index 20b1e3d..a964838 100644 --- a/src/main/java/handiebot/HandieBot.java +++ b/src/main/java/handiebot/HandieBot.java @@ -17,9 +17,7 @@ import sx.blah.discord.handle.obj.Permissions; import sx.blah.discord.util.DiscordException; import sx.blah.discord.util.RateLimitException; -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; +import java.io.*; import java.util.*; /** @@ -32,6 +30,7 @@ public class HandieBot { //Application name is the name of application as it appears on display window. public static final String APPLICATION_NAME = "HandieBot"; + //The token required for logging into Discord. This is secure and must not be in the source code on GitHub. private static final String TOKEN; static { @@ -43,8 +42,22 @@ public class HandieBot { } //Variable to enable or disable GUI. private static boolean USE_GUI = true; + + //Settings for the bot. Tries to load the settings, or if that doesn't work, it will load defaults. + public static Properties settings; + static{ + try { + Properties defaultSettings = new Properties(); + defaultSettings.load(HandieBot.class.getClassLoader().getResourceAsStream("default_settings")); + settings = new Properties(defaultSettings); + settings.load(new FileInputStream(FileUtil.getDataDirectory()+"settings")); + } catch (IOException e) { + e.printStackTrace(); + } + } + //Resource bundle for localized strings. - public static ResourceBundle resourceBundle = ResourceBundle.getBundle("Strings"); + public static ResourceBundle resourceBundle = ResourceBundle.getBundle("Strings", Locale.forLanguageTag(settings.getProperty("language"))); //Discord client object. public static IDiscordClient client; @@ -150,6 +163,11 @@ public class HandieBot { musicPlayer.quitAll(); client.logout(); window.dispose(); + try { + settings.store(new FileWriter(FileUtil.getDataDirectory()+"settings"), "Settings for HandieBot"); + } catch (IOException e) { + e.printStackTrace(); + } System.exit(0); } diff --git a/src/main/java/handiebot/view/BotWindow.java b/src/main/java/handiebot/view/BotWindow.java index 222e1f1..3eaa321 100644 --- a/src/main/java/handiebot/view/BotWindow.java +++ b/src/main/java/handiebot/view/BotWindow.java @@ -1,16 +1,18 @@ package handiebot.view; import handiebot.HandieBot; -import handiebot.lavaplayer.playlist.Playlist; +import handiebot.view.tableModels.PlaylistTableModel; +import handiebot.view.tableModels.SongsTableModel; import javax.imageio.ImageIO; import javax.swing.*; import javax.swing.event.ListSelectionListener; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumnModel; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; -import java.util.List; import static handiebot.HandieBot.resourceBundle; @@ -24,10 +26,8 @@ public class BotWindow extends JFrame { private JTextPane outputArea; //Playlist display variables. - private DefaultListModel playlistNamesModel; - private DefaultListModel currentPlaylistModel; - private JList playlistNamesList; - private JList currentPlaylistList; + private PlaylistTableModel playlistTableModel; + private SongsTableModel songsTableModel; private ListSelectionListener playlistListener; private JPanel playlistDisplayPanel; @@ -43,29 +43,30 @@ public class BotWindow extends JFrame { scrollPane.setAutoscrolls(true); getContentPane().add(scrollPane, BorderLayout.CENTER); - //Playlist shower - this.playlistNamesModel = new DefaultListModel<>(); - this.currentPlaylistModel = new DefaultListModel<>(); - this.playlistNamesList = new JList<>(this.playlistNamesModel); - this.playlistNamesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); - this.currentPlaylistList = new JList<>(this.currentPlaylistModel); - this.currentPlaylistList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); - - updatePlaylistNames(); - this.playlistNamesList.addListSelectionListener(new PlaylistSelectionListener(this.currentPlaylistModel)); - - //Create the panel to hold both of the sub-panels. + //updatePlaylistNames(); playlistDisplayPanel = new JPanel(); playlistDisplayPanel.setPreferredSize(new Dimension(250, 0)); playlistDisplayPanel.setLayout(new BorderLayout()); + this.songsTableModel = new SongsTableModel(); + this.playlistTableModel = new PlaylistTableModel(); + + JTable songsTable = new JTable(this.songsTableModel); + JTable playlistTable = new JTable(playlistTableModel); + //Playlist name scroll pane. - JScrollPane playlistNamesScrollPane = new JScrollPane(playlistNamesList); - playlistNamesScrollPane.setColumnHeaderView(new JLabel("Playlists")); + playlistTable.setRowSelectionAllowed(true); + playlistTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + playlistTable.getSelectionModel().addListSelectionListener(new PlaylistSelectionListener(this.songsTableModel, playlistTable, songsTable)); + JScrollPane playlistNamesScrollPane = new JScrollPane(playlistTable); + playlistNamesScrollPane.setPreferredSize(new Dimension(250, 200)); playlistDisplayPanel.add(playlistNamesScrollPane, BorderLayout.PAGE_START); //Song names scroll pane. - JScrollPane songNamesScrollPane = new JScrollPane(this.currentPlaylistList); + songsTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + songsTable.setRowSelectionAllowed(true); + songsTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + JScrollPane songNamesScrollPane = new JScrollPane(songsTable); songNamesScrollPane.setColumnHeaderView(new JLabel("Selected Playlist")); playlistDisplayPanel.add(songNamesScrollPane, BorderLayout.CENTER); @@ -110,11 +111,7 @@ public class BotWindow extends JFrame { * Updates the list of playlist names. */ public void updatePlaylistNames(){ - List playlistNames = Playlist.getAvailablePlaylists(); - this.playlistNamesModel.clear(); - for (String name : playlistNames){ - this.playlistNamesModel.addElement(name); - } + this.playlistTableModel = new PlaylistTableModel(); } /** @@ -124,6 +121,25 @@ public class BotWindow extends JFrame { this.playlistDisplayPanel.setVisible(!this.playlistDisplayPanel.isVisible()); } + /** + * Automatically resizes a table to shrink the index column. + * @param table The table to resize. + */ + public static void autoSizeTable(JTable table){ + final TableColumnModel columnModel = table.getColumnModel(); + int freeSpace = 230; + for (int col = 0; col < columnModel.getColumnCount(); col++) { + int width = 0; + for (int row = 0; row < table.getRowCount(); row++) { + TableCellRenderer renderer = table.getCellRenderer(row, col); + Component component = table.prepareRenderer(renderer, row, col); + width = Math.max(component.getPreferredSize().width + 1, width); + } + columnModel.getColumn(col).setPreferredWidth(width); + freeSpace -= width; + } + } + public JTextPane getOutputArea(){ return this.outputArea; } diff --git a/src/main/java/handiebot/view/MenuBar.java b/src/main/java/handiebot/view/MenuBar.java index 7a337fd..33e8e03 100644 --- a/src/main/java/handiebot/view/MenuBar.java +++ b/src/main/java/handiebot/view/MenuBar.java @@ -9,6 +9,7 @@ import java.util.Locale; import java.util.ResourceBundle; import static handiebot.HandieBot.resourceBundle; +import static handiebot.HandieBot.settings; /** * @author Andrew Lalis & Zino Holwerda @@ -26,10 +27,18 @@ public class MenuBar extends JMenuBar { this.add(fileMenu); JMenu viewMenu = new JMenu(resourceBundle.getString("menu.viewMenu.view")); JMenu language = new JMenu(resourceBundle.getString("menu.viewMenu.language")); - language.add(new ActionItem(resourceBundle.getString("menu.viewMenu.language.english"), e -> resourceBundle = ResourceBundle.getBundle("Strings", Locale.US))); - language.add(new ActionItem(resourceBundle.getString("menu.viewMenu.language.dutch"), e -> resourceBundle = ResourceBundle.getBundle("Strings", Locale.forLanguageTag("nl")))); + language.add(new ActionItem(resourceBundle.getString("menu.viewMenu.language.english"), e -> { + resourceBundle = ResourceBundle.getBundle("Strings", Locale.US); + settings.setProperty("language", "en"); + })); + language.add(new ActionItem(resourceBundle.getString("menu.viewMenu.language.dutch"), e -> { + resourceBundle = ResourceBundle.getBundle("Strings", Locale.forLanguageTag("nl")); + settings.setProperty("language", "nl"); + })); viewMenu.add(language); viewMenu.add(new ActionItem(resourceBundle.getString("menu.viewMenu.playlistsVisible"), e -> window.togglePlaylistsVisibility())); + //TODO: Add method to toggle visibility of the servers panel. + viewMenu.add(new ActionItem(resourceBundle.getString("menu.viewMenu.serversVisible"), e -> {})); this.add(viewMenu); } diff --git a/src/main/java/handiebot/view/PlaylistSelectionListener.java b/src/main/java/handiebot/view/PlaylistSelectionListener.java index 8135911..a5fd9c5 100644 --- a/src/main/java/handiebot/view/PlaylistSelectionListener.java +++ b/src/main/java/handiebot/view/PlaylistSelectionListener.java @@ -1,12 +1,11 @@ package handiebot.view; import handiebot.lavaplayer.playlist.Playlist; -import handiebot.lavaplayer.playlist.UnloadedTrack; +import handiebot.view.tableModels.SongsTableModel; import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; -import java.util.List; /** * @author Andrew Lalis @@ -14,16 +13,24 @@ import java.util.List; */ public class PlaylistSelectionListener implements ListSelectionListener { - private DefaultListModel songsListModel; + //The table model for the songs list. + private SongsTableModel songsModel; - public PlaylistSelectionListener(DefaultListModel songsListModel){ - this.songsListModel = songsListModel; + //The table that shows the playlist names. + private JTable table; + private JTable songsTable; + + public PlaylistSelectionListener(SongsTableModel songsModel, JTable table, JTable songsTable){ + this.songsModel = songsModel; + this.table = table; + this.songsTable = songsTable; } @Override public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()){ - updatePlaylistData((JList) e.getSource()); + updatePlaylistData(); + BotWindow.autoSizeTable(songsTable); } } @@ -31,16 +38,12 @@ public class PlaylistSelectionListener implements ListSelectionListener { * Updates the list of songs for a selected playlist. * Does not update the list of playlists. */ - private void updatePlaylistData(JList playlistNamesList) { - String selectedValue = playlistNamesList.getSelectedValue(); + private void updatePlaylistData() { + String selectedValue = (String) this.table.getModel().getValueAt(this.table.getSelectedRow(), 0); if (selectedValue != null && Playlist.playlistExists(selectedValue)){ Playlist playlist = new Playlist(selectedValue); playlist.load(); - List tracks = playlist.getTracks(); - songsListModel.clear(); - for (int i = 0; i < playlist.getTrackCount(); i++){ - songsListModel.addElement(tracks.get(i).getTitle()); - } + this.songsModel.setPlaylist(playlist); } } diff --git a/src/main/java/handiebot/view/tableModels/PlaylistTableModel.java b/src/main/java/handiebot/view/tableModels/PlaylistTableModel.java new file mode 100644 index 0000000..178e4cb --- /dev/null +++ b/src/main/java/handiebot/view/tableModels/PlaylistTableModel.java @@ -0,0 +1,56 @@ +package handiebot.view.tableModels; + +import handiebot.lavaplayer.playlist.Playlist; + +import javax.swing.table.AbstractTableModel; +import java.util.List; + +/** + * @author Andrew Lalis + * Class for a model of data to be supplied to a table. + */ +public class PlaylistTableModel extends AbstractTableModel { + + private static final String[] columnNames = { + "Playlist", + "Tracks" + }; + + private String[][] data; + + public PlaylistTableModel(){ + List playlistNames = Playlist.getAvailablePlaylists(); + data = new String[playlistNames.size()][columnNames.length]; + for (int i = 0; i < playlistNames.size(); i++){ + data[i][0] = playlistNames.get(i); + Playlist p = new Playlist(playlistNames.get(i)); + p.load(); + data[i][1] = Integer.toString(p.getTrackCount()); + } + } + + @Override + public int getRowCount() { + return data.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public String getColumnName(int col) { + return columnNames[col]; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + data[rowIndex][columnIndex] = (String)aValue; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return data[rowIndex][columnIndex]; + } +} diff --git a/src/main/java/handiebot/view/tableModels/SongsTableModel.java b/src/main/java/handiebot/view/tableModels/SongsTableModel.java new file mode 100644 index 0000000..a37efb0 --- /dev/null +++ b/src/main/java/handiebot/view/tableModels/SongsTableModel.java @@ -0,0 +1,58 @@ +package handiebot.view.tableModels; + +import handiebot.lavaplayer.playlist.Playlist; + +import javax.swing.table.AbstractTableModel; + +/** + * @author Andrew Lalis + */ +public class SongsTableModel extends AbstractTableModel { + + private static final String[] columnNames = { + "#", + "Song", + "Time" + }; + + private String[][] data; + + public SongsTableModel(Playlist playlist){ + setPlaylist(playlist); + } + + public SongsTableModel(){ + this.data = new String[0][0]; + } + + @Override + public int getRowCount() { + return data.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public String getColumnName(int column) { + return columnNames[column]; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return data[rowIndex][columnIndex]; + } + + public void setPlaylist(Playlist playlist){ + this.data = new String[playlist.getTrackCount()][columnNames.length]; + for (int i = 0; i < playlist.getTrackCount(); i++){ + this.data[i][0] = Integer.toString(i+1); + this.data[i][1] = playlist.getTracks().get(i).getTitle(); + this.data[i][2] = playlist.getTracks().get(i).getFormattedDuration().replace("[","").replace("]",""); + } + this.fireTableDataChanged(); + } + +} diff --git a/src/main/resources/Strings.properties b/src/main/resources/Strings.properties index 6d23d25..d292196 100644 --- a/src/main/resources/Strings.properties +++ b/src/main/resources/Strings.properties @@ -21,6 +21,7 @@ menu.viewMenu.language=Language menu.viewMenu.language.english=English menu.viewMenu.language.dutch=Dutch menu.viewMenu.playlistsVisible=Playlists +menu.viewMenu.serversVisible=Servers #Actions action.menu.playlist=Edit playlists action.menu.playlist.add=Add diff --git a/src/main/resources/default_settings b/src/main/resources/default_settings new file mode 100644 index 0000000..488284c --- /dev/null +++ b/src/main/resources/default_settings @@ -0,0 +1,2 @@ +#HandieBot default settings +language:en \ No newline at end of file