Version 1: Basic functionality #1
4
pom.xml
4
pom.xml
|
@ -13,8 +13,8 @@
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<source>1.7</source>
|
<source>1.8</source>
|
||||||
<target>1.7</target>
|
<target>1.8</target>
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
|
|
@ -2,6 +2,9 @@ package handiebot;
|
||||||
|
|
||||||
import handiebot.command.CommandHandler;
|
import handiebot.command.CommandHandler;
|
||||||
import handiebot.lavaplayer.MusicPlayer;
|
import handiebot.lavaplayer.MusicPlayer;
|
||||||
|
import handiebot.view.BotLog;
|
||||||
|
import handiebot.view.BotWindow;
|
||||||
|
import handiebot.view.View;
|
||||||
import sx.blah.discord.api.ClientBuilder;
|
import sx.blah.discord.api.ClientBuilder;
|
||||||
import sx.blah.discord.api.IDiscordClient;
|
import sx.blah.discord.api.IDiscordClient;
|
||||||
import sx.blah.discord.api.events.EventSubscriber;
|
import sx.blah.discord.api.events.EventSubscriber;
|
||||||
|
@ -9,30 +12,26 @@ import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedE
|
||||||
import sx.blah.discord.util.DiscordException;
|
import sx.blah.discord.util.DiscordException;
|
||||||
import sx.blah.discord.util.RateLimitException;
|
import sx.blah.discord.util.RateLimitException;
|
||||||
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
* Main Class for the discord bot. Contains client loading information and general event processing.
|
* Main Class for the discord bot. Contains client loading information and general event processing.
|
||||||
*/
|
*/
|
||||||
public class HandieBot {
|
public class HandieBot {
|
||||||
|
|
||||||
public static Logger log = Logger.getLogger("HandieBotLog");
|
public static final String APPLICATION_NAME = "HandieBot";
|
||||||
|
|
||||||
private static final String TOKEN = "MjgzNjUyOTg5MjEyNjg4Mzg0.C45A_Q.506b0G6my1FEFa7_YY39lxLBHUY";
|
private static final String TOKEN = "MjgzNjUyOTg5MjEyNjg4Mzg0.C45A_Q.506b0G6my1FEFa7_YY39lxLBHUY";
|
||||||
|
|
||||||
public static IDiscordClient client;
|
public static IDiscordClient client;
|
||||||
|
public static View view;
|
||||||
|
public static BotWindow window;
|
||||||
|
public static BotLog log;
|
||||||
|
|
||||||
private CommandHandler commandHandler;
|
private CommandHandler commandHandler;
|
||||||
private MusicPlayer musicPlayer;
|
public static MusicPlayer musicPlayer;
|
||||||
|
|
||||||
private HandieBot() {
|
private HandieBot() {
|
||||||
this.commandHandler = new CommandHandler(this);
|
this.commandHandler = new CommandHandler(this);
|
||||||
this.musicPlayer = new MusicPlayer();
|
|
||||||
}
|
|
||||||
|
|
||||||
public MusicPlayer getMusicPlayer(){
|
|
||||||
return this.musicPlayer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventSubscriber
|
@EventSubscriber
|
||||||
|
@ -41,10 +40,28 @@ public class HandieBot {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws DiscordException, RateLimitException {
|
public static void main(String[] args) throws DiscordException, RateLimitException {
|
||||||
System.out.println("Logging bot in.");
|
|
||||||
|
musicPlayer = new MusicPlayer();
|
||||||
|
|
||||||
|
view = new View();
|
||||||
|
log = new BotLog(view.getOutputArea());
|
||||||
|
window = new BotWindow(view);
|
||||||
|
|
||||||
|
log.log(BotLog.TYPE.INFO, "Logging client in.");
|
||||||
client = new ClientBuilder().withToken(TOKEN).build();
|
client = new ClientBuilder().withToken(TOKEN).build();
|
||||||
client.getDispatcher().registerListener(new HandieBot());
|
client.getDispatcher().registerListener(new HandieBot());
|
||||||
client.login();
|
client.login();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Safely shuts down the bot on all guilds.
|
||||||
|
*/
|
||||||
|
public static void quit(){
|
||||||
|
musicPlayer.quitAll();
|
||||||
|
client.logout();
|
||||||
|
window.dispose();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,19 +39,19 @@ public class CommandHandler {
|
||||||
if (command.equals("play")){
|
if (command.equals("play")){
|
||||||
//Play or queue a song.
|
//Play or queue a song.
|
||||||
if (args.length == 1) {
|
if (args.length == 1) {
|
||||||
this.bot.getMusicPlayer().loadToQueue(guild, args[0]);
|
this.bot.musicPlayer.loadToQueue(guild, args[0]);
|
||||||
} else if (args.length == 0){
|
} else if (args.length == 0){
|
||||||
this.bot.getMusicPlayer().playQueue(guild);
|
this.bot.musicPlayer.playQueue(guild);
|
||||||
}
|
}
|
||||||
} else if (command.equals("skip") && args.length == 0){
|
} else if (command.equals("skip") && args.length == 0){
|
||||||
//Skip the current song.
|
//Skip the current song.
|
||||||
this.bot.getMusicPlayer().skipTrack(guild);
|
this.bot.musicPlayer.skipTrack(guild);
|
||||||
} else if (command.equals("help")){
|
} else if (command.equals("help")){
|
||||||
//Send a PM to the user with help info.
|
//Send a PM to the user with help info.
|
||||||
this.sendHelpInfo(user);//TODO finish the help command and fill in with new descriptions each time.
|
this.sendHelpInfo(user);//TODO finish the help command and fill in with new descriptions each time.
|
||||||
} else if (command.equals("queue") && args.length == 0){
|
} else if (command.equals("queue") && args.length == 0){
|
||||||
//Display the first few items of the queue.
|
//Display the first few items of the queue.
|
||||||
this.bot.getMusicPlayer().showQueueList(guild);
|
this.bot.musicPlayer.showQueueList(guild);
|
||||||
} else if (command.equals("repeat")){
|
} else if (command.equals("repeat")){
|
||||||
//Toggle repeat.
|
//Toggle repeat.
|
||||||
//TODO implement repeat command.
|
//TODO implement repeat command.
|
||||||
|
@ -60,7 +60,7 @@ public class CommandHandler {
|
||||||
} else if (command.equals("quit")){
|
} else if (command.equals("quit")){
|
||||||
//Quit the application.
|
//Quit the application.
|
||||||
channel.sendMessage("Quitting HandieBot functions.");
|
channel.sendMessage("Quitting HandieBot functions.");
|
||||||
this.bot.getMusicPlayer().quit(guild);
|
this.bot.musicPlayer.quit(guild);
|
||||||
} else if (command.equals("playlist")){
|
} else if (command.equals("playlist")){
|
||||||
//Do playlist actions.
|
//Do playlist actions.
|
||||||
//TODO perform actions!
|
//TODO perform actions!
|
||||||
|
|
|
@ -9,6 +9,7 @@ import com.sedmelluq.discord.lavaplayer.track.AudioPlaylist;
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||||
import handiebot.command.CommandHandler;
|
import handiebot.command.CommandHandler;
|
||||||
import handiebot.utils.DisappearingMessage;
|
import handiebot.utils.DisappearingMessage;
|
||||||
|
import handiebot.view.BotLog;
|
||||||
import sx.blah.discord.handle.obj.IChannel;
|
import sx.blah.discord.handle.obj.IChannel;
|
||||||
import sx.blah.discord.handle.obj.IGuild;
|
import sx.blah.discord.handle.obj.IGuild;
|
||||||
import sx.blah.discord.handle.obj.IMessage;
|
import sx.blah.discord.handle.obj.IMessage;
|
||||||
|
@ -20,6 +21,8 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static handiebot.HandieBot.log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
* This class is a container for all the music related functions, and contains methods for easy playback and queue
|
* This class is a container for all the music related functions, and contains methods for easy playback and queue
|
||||||
|
@ -58,7 +61,7 @@ public class MusicPlayer {
|
||||||
*/
|
*/
|
||||||
private GuildMusicManager getMusicManager(IGuild guild){
|
private GuildMusicManager getMusicManager(IGuild guild){
|
||||||
if (!this.musicManagers.containsKey(guild)){
|
if (!this.musicManagers.containsKey(guild)){
|
||||||
System.out.println("Registering guild, creating audio provider.");
|
log.log(BotLog.TYPE.MUSIC, "Creating new music manager and audio provider for guild: "+guild.getName());
|
||||||
this.musicManagers.put(guild, new GuildMusicManager(this.playerManager, guild));
|
this.musicManagers.put(guild, new GuildMusicManager(this.playerManager, guild));
|
||||||
guild.getAudioManager().setAudioProvider(this.musicManagers.get(guild).getAudioProvider());
|
guild.getAudioManager().setAudioProvider(this.musicManagers.get(guild).getAudioProvider());
|
||||||
}
|
}
|
||||||
|
@ -75,7 +78,7 @@ public class MusicPlayer {
|
||||||
if (!this.chatChannels.containsKey(guild)){
|
if (!this.chatChannels.containsKey(guild)){
|
||||||
List<IChannel> channels = guild.getChannelsByName(CHANNEL_NAME.toLowerCase());
|
List<IChannel> channels = guild.getChannelsByName(CHANNEL_NAME.toLowerCase());
|
||||||
if (channels.isEmpty()){
|
if (channels.isEmpty()){
|
||||||
System.out.println("Found "+channels.size()+" matches for message channel, creating new one.");
|
log.log(BotLog.TYPE.MUSIC, "No chat channel found, creating a new one.");
|
||||||
this.chatChannels.put(guild, guild.createChannel(CHANNEL_NAME.toLowerCase()));
|
this.chatChannels.put(guild, guild.createChannel(CHANNEL_NAME.toLowerCase()));
|
||||||
} else {
|
} else {
|
||||||
this.chatChannels.put(guild, channels.get(0));
|
this.chatChannels.put(guild, channels.get(0));
|
||||||
|
@ -94,7 +97,7 @@ public class MusicPlayer {
|
||||||
if (!this.voiceChannels.containsKey(guild)){
|
if (!this.voiceChannels.containsKey(guild)){
|
||||||
List<IVoiceChannel> channels = guild.getVoiceChannelsByName(CHANNEL_NAME);
|
List<IVoiceChannel> channels = guild.getVoiceChannelsByName(CHANNEL_NAME);
|
||||||
if (channels.isEmpty()){
|
if (channels.isEmpty()){
|
||||||
System.out.println("Found "+channels.size()+" matches for voice channel, creating new one.");
|
log.log(BotLog.TYPE.MUSIC, "No voice channel found, creating a new one.");
|
||||||
this.voiceChannels.put(guild, guild.createVoiceChannel(CHANNEL_NAME));
|
this.voiceChannels.put(guild, guild.createVoiceChannel(CHANNEL_NAME));
|
||||||
} else {
|
} else {
|
||||||
this.voiceChannels.put(guild, channels.get(0));
|
this.voiceChannels.put(guild, channels.get(0));
|
||||||
|
@ -144,7 +147,7 @@ public class MusicPlayer {
|
||||||
this.playerManager.loadItemOrdered(getMusicManager(guild), trackURL, new AudioLoadResultHandler() {
|
this.playerManager.loadItemOrdered(getMusicManager(guild), trackURL, new AudioLoadResultHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void trackLoaded(AudioTrack audioTrack) {
|
public void trackLoaded(AudioTrack audioTrack) {
|
||||||
System.out.println("Track successfully loaded: "+audioTrack.getInfo().title);
|
log.log(BotLog.TYPE.MUSIC, "Track successfully loaded: "+audioTrack.getInfo().title);
|
||||||
addToQueue(guild, audioTrack);
|
addToQueue(guild, audioTrack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,9 +188,11 @@ public class MusicPlayer {
|
||||||
getMusicManager(guild).scheduler.queue(track);
|
getMusicManager(guild).scheduler.queue(track);
|
||||||
//Build message.
|
//Build message.
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (timeUntilPlay > 0) {
|
||||||
sb.append("Added **").append(track.getInfo().title).append("** to the queue.");
|
sb.append("Added **").append(track.getInfo().title).append("** to the queue.");
|
||||||
|
}
|
||||||
//If there's some tracks in the queue, get the time until this one plays.
|
//If there's some tracks in the queue, get the time until this one plays.
|
||||||
if (timeUntilPlay != 0){
|
if (timeUntilPlay > 0){
|
||||||
sb.append(String.format("\nTime until play: %d min, %d sec",
|
sb.append(String.format("\nTime until play: %d min, %d sec",
|
||||||
TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay),
|
TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay),
|
||||||
TimeUnit.MILLISECONDS.toSeconds(timeUntilPlay) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay))
|
TimeUnit.MILLISECONDS.toSeconds(timeUntilPlay) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(timeUntilPlay))
|
||||||
|
@ -215,6 +220,7 @@ public class MusicPlayer {
|
||||||
*/
|
*/
|
||||||
public void skipTrack(IGuild guild){
|
public void skipTrack(IGuild guild){
|
||||||
getMusicManager(guild).scheduler.nextTrack();
|
getMusicManager(guild).scheduler.nextTrack();
|
||||||
|
log.log(BotLog.TYPE.MUSIC, "Skipping the current track. ");
|
||||||
new DisappearingMessage(getChatChannel(guild), "Skipping the current track.", 3000);
|
new DisappearingMessage(getChatChannel(guild), "Skipping the current track.", 3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -230,4 +236,18 @@ public class MusicPlayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs the same functions as quit, but with every guild.
|
||||||
|
*/
|
||||||
|
public void quitAll(){
|
||||||
|
this.musicManagers.forEach((guild, musicManager) -> {
|
||||||
|
musicManager.scheduler.quit();
|
||||||
|
IVoiceChannel vc = this.getVoiceChannel(guild);
|
||||||
|
if (vc.isConnected()){
|
||||||
|
vc.leave();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.playerManager.shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,6 +79,9 @@ public class Playlist {
|
||||||
* @return The AudioTrack that should be played next.
|
* @return The AudioTrack that should be played next.
|
||||||
*/
|
*/
|
||||||
public AudioTrack getNextTrackAndRemove(boolean shouldShuffle){
|
public AudioTrack getNextTrackAndRemove(boolean shouldShuffle){
|
||||||
|
if (this.tracks.isEmpty()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return this.tracks.remove((shouldShuffle ? getShuffledIndex(this.tracks.size()) : 0));
|
return this.tracks.remove((shouldShuffle ? getShuffledIndex(this.tracks.size()) : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +90,9 @@ public class Playlist {
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public AudioTrack getNextTrackAndRequeue(boolean shouldShuffle){
|
public AudioTrack getNextTrackAndRequeue(boolean shouldShuffle){
|
||||||
|
if (this.tracks.isEmpty()){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
AudioTrack track = this.tracks.remove((shouldShuffle ? getShuffledIndex(this.tracks.size()) : 0));
|
AudioTrack track = this.tracks.remove((shouldShuffle ? getShuffledIndex(this.tracks.size()) : 0));
|
||||||
this.tracks.add(track);
|
this.tracks.add(track);
|
||||||
return track;
|
return track;
|
||||||
|
|
|
@ -5,11 +5,16 @@ import com.sedmelluq.discord.lavaplayer.player.event.AudioEventAdapter;
|
||||||
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
import com.sedmelluq.discord.lavaplayer.tools.FriendlyException;
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrack;
|
||||||
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
|
import com.sedmelluq.discord.lavaplayer.track.AudioTrackEndReason;
|
||||||
|
import handiebot.view.BotLog;
|
||||||
import sx.blah.discord.handle.obj.IChannel;
|
import sx.blah.discord.handle.obj.IChannel;
|
||||||
import sx.blah.discord.handle.obj.IGuild;
|
import sx.blah.discord.handle.obj.IGuild;
|
||||||
|
import sx.blah.discord.handle.obj.IMessage;
|
||||||
|
import sx.blah.discord.util.RequestBuffer;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static handiebot.HandieBot.log;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
*/
|
*/
|
||||||
|
@ -100,7 +105,6 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
player.startTrack(track, false);
|
player.startTrack(track, false);
|
||||||
} else {
|
} else {
|
||||||
this.activePlaylist.addTrack(track);
|
this.activePlaylist.addTrack(track);
|
||||||
this.activePlaylist.save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,8 +113,11 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
*/
|
*/
|
||||||
public void nextTrack(){
|
public void nextTrack(){
|
||||||
AudioTrack track = (this.repeat ? this.activePlaylist.getNextTrackAndRequeue(this.shuffle) : this.activePlaylist.getNextTrackAndRemove(this.shuffle));
|
AudioTrack track = (this.repeat ? this.activePlaylist.getNextTrackAndRequeue(this.shuffle) : this.activePlaylist.getNextTrackAndRemove(this.shuffle));
|
||||||
this.activePlaylist.save();
|
if (track != null) {
|
||||||
player.startTrack(track, false);
|
player.startTrack(track, false);
|
||||||
|
} else {
|
||||||
|
player.stopTrack();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,14 +125,17 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
*/
|
*/
|
||||||
public void quit(){
|
public void quit(){
|
||||||
this.player.stopTrack();
|
this.player.stopTrack();
|
||||||
|
this.player.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onTrackStart(AudioPlayer player, AudioTrack track) {
|
public void onTrackStart(AudioPlayer player, AudioTrack track) {
|
||||||
System.out.println("Started audio track: "+track.getInfo().title);
|
log.log(BotLog.TYPE.MUSIC, "Started audio track: "+track.getInfo().title);
|
||||||
List<IChannel> channels = this.guild.getChannelsByName(MusicPlayer.CHANNEL_NAME.toLowerCase());
|
List<IChannel> channels = this.guild.getChannelsByName(MusicPlayer.CHANNEL_NAME.toLowerCase());
|
||||||
if (channels.size() > 0){
|
if (channels.size() > 0){
|
||||||
channels.get(0).sendMessage("Now playing: **"+track.getInfo().title+"**.");
|
IMessage message = channels.get(0).sendMessage("Now playing: **"+track.getInfo().title+"**.");
|
||||||
|
RequestBuffer.request(() -> {message.addReaction(":thumbsup:");}).get();
|
||||||
|
RequestBuffer.request(() -> {message.addReaction(":thumbsdown:");});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,6 +146,7 @@ public class TrackScheduler extends AudioEventAdapter {
|
||||||
System.out.println("Moving to next track.");
|
System.out.println("Moving to next track.");
|
||||||
nextTrack();
|
nextTrack();
|
||||||
} else {
|
} else {
|
||||||
|
log.log(BotLog.TYPE.ERROR, "Unable to go to the next track. Reason: "+endReason.name());
|
||||||
System.out.println(endReason.toString());
|
System.out.println(endReason.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package handiebot.view;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.text.BadLocationException;
|
||||||
|
import javax.swing.text.Style;
|
||||||
|
import javax.swing.text.StyleConstants;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static handiebot.view.BotLog.TYPE.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrew Lalis
|
||||||
|
*/
|
||||||
|
public class BotLog {
|
||||||
|
|
||||||
|
public enum TYPE {
|
||||||
|
INFO,
|
||||||
|
MUSIC,
|
||||||
|
ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<TYPE, Style> logStyles;
|
||||||
|
private Style defaultStyle;
|
||||||
|
|
||||||
|
private JTextPane outputArea;
|
||||||
|
|
||||||
|
public BotLog(JTextPane outputArea){
|
||||||
|
this.outputArea = outputArea;
|
||||||
|
initStyles();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the styles for the various log data.
|
||||||
|
*/
|
||||||
|
private void initStyles(){
|
||||||
|
this.logStyles = new HashMap<>();
|
||||||
|
//Define default style.
|
||||||
|
this.defaultStyle = this.outputArea.addStyle("LogStyle", null);
|
||||||
|
this.defaultStyle.addAttribute(StyleConstants.FontFamily, "Lucida Console");
|
||||||
|
this.defaultStyle.addAttribute(StyleConstants.FontSize, 12);
|
||||||
|
//Define each type's color.
|
||||||
|
for (TYPE type : TYPE.values()) {
|
||||||
|
this.logStyles.put(type, outputArea.addStyle(type.name(), this.defaultStyle));
|
||||||
|
}
|
||||||
|
this.logStyles.get(INFO).addAttribute(StyleConstants.Foreground, Color.blue);
|
||||||
|
this.logStyles.get(MUSIC).addAttribute(StyleConstants.Foreground, new Color(51, 175, 66));
|
||||||
|
this.logStyles.get(ERROR).addAttribute(StyleConstants.Foreground, Color.red);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a string to the output window with the given tag and text.
|
||||||
|
* @param type The type of message to write.
|
||||||
|
* @param message The content of the message.
|
||||||
|
*/
|
||||||
|
public void log(TYPE type, String message){
|
||||||
|
Date date = new Date(System.currentTimeMillis());
|
||||||
|
DateFormat formatter = new SimpleDateFormat("HH:mm:ss:SSS");
|
||||||
|
String dateFormatted = formatter.format(date);
|
||||||
|
try {
|
||||||
|
this.outputArea.getStyledDocument().insertString(this.outputArea.getStyledDocument().getLength(), dateFormatted, this.defaultStyle);
|
||||||
|
this.outputArea.getStyledDocument().insertString(this.outputArea.getStyledDocument().getLength(), '['+type.name()+"] ", this.logStyles.get(type));
|
||||||
|
this.outputArea.getStyledDocument().insertString(this.outputArea.getStyledDocument().getLength(), message+'\n', this.defaultStyle);
|
||||||
|
} catch (BadLocationException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package handiebot.view;
|
||||||
|
|
||||||
|
import handiebot.HandieBot;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.WindowAdapter;
|
||||||
|
import java.awt.event.WindowEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrew Lalis
|
||||||
|
* This class inherits JFrame and simplifies the creation of a window.
|
||||||
|
*/
|
||||||
|
public class BotWindow extends JFrame {
|
||||||
|
|
||||||
|
public BotWindow(View view){
|
||||||
|
super(HandieBot.APPLICATION_NAME);
|
||||||
|
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
|
||||||
|
addWindowListener(new WindowAdapter() {
|
||||||
|
@Override
|
||||||
|
public void windowClosing(WindowEvent e) {
|
||||||
|
if (JOptionPane.showConfirmDialog((JFrame) e.getSource(), "Are you sure you want to exit and shutdown the bot?",
|
||||||
|
"Confirm shutdown",
|
||||||
|
JOptionPane.YES_NO_OPTION,
|
||||||
|
JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION){
|
||||||
|
HandieBot.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setContentPane(view.mainPanel);
|
||||||
|
setJMenuBar(new MenuBar());
|
||||||
|
setPreferredSize(new Dimension(800, 600));
|
||||||
|
pack();
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package handiebot.view;
|
||||||
|
|
||||||
|
import handiebot.view.actions.QuitAction;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.KeyListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by Andrew's Computer on 21-Jun-17.
|
||||||
|
*/
|
||||||
|
public class CommandLineListener implements KeyListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyTyped(KeyEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ENTER){
|
||||||
|
//user wishes to submit command.
|
||||||
|
JTextField commandLine = (JTextField) e.getSource();
|
||||||
|
String[] words = commandLine.getText().trim().split(" ");
|
||||||
|
String command = words[0];
|
||||||
|
String[] args = new String[words.length-1];
|
||||||
|
for (int i = 1; i < words.length; i++) {
|
||||||
|
args[i-1] = words[i];
|
||||||
|
}
|
||||||
|
executeCommand(command, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void keyReleased(KeyEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a given command on the command line.
|
||||||
|
* @param command The first word typed, or the command itself.
|
||||||
|
* @param args The list of arguments for the command.
|
||||||
|
*/
|
||||||
|
private void executeCommand(String command, String[] args){
|
||||||
|
if (command.equals("quit")){
|
||||||
|
new QuitAction().actionPerformed(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package handiebot.view;
|
||||||
|
|
||||||
|
import handiebot.view.actions.ActionItem;
|
||||||
|
import handiebot.view.actions.QuitAction;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrew Lalis
|
||||||
|
* Custom menu bar to be added to the console control panel.
|
||||||
|
*/
|
||||||
|
public class MenuBar extends JMenuBar {
|
||||||
|
|
||||||
|
public MenuBar(){
|
||||||
|
JMenu fileMenu = new JMenu("File");
|
||||||
|
fileMenu.add(new ActionItem("Quit", new QuitAction()));
|
||||||
|
this.add(fileMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="handiebot.view.View">
|
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="handiebot.view.View">
|
||||||
<grid id="27dc6" binding="panel1" default-binding="true" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
<grid id="27dc6" binding="mainPanel" layout-manager="GridLayoutManager" row-count="2" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||||
<margin top="0" left="0" bottom="0" right="0"/>
|
<margin top="0" left="0" bottom="0" right="0"/>
|
||||||
<constraints>
|
<constraints>
|
||||||
<xy x="20" y="20" width="500" height="400"/>
|
<xy x="20" y="20" width="500" height="400"/>
|
||||||
|
@ -12,16 +12,19 @@
|
||||||
<constraints>
|
<constraints>
|
||||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="7" hsize-policy="7" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<properties/>
|
<properties>
|
||||||
|
<font name="Consolas" size="12"/>
|
||||||
|
</properties>
|
||||||
<border type="none"/>
|
<border type="none"/>
|
||||||
<children>
|
<children>
|
||||||
<component id="42510" class="javax.swing.JTextArea" binding="outputArea">
|
<component id="186aa" class="javax.swing.JTextPane" binding="outputArea">
|
||||||
<constraints/>
|
<constraints/>
|
||||||
<properties>
|
<properties>
|
||||||
<lineWrap value="true"/>
|
<editable value="false"/>
|
||||||
<selectedTextColor color="-39481"/>
|
<font name="Consolas" size="12"/>
|
||||||
<selectionColor color="-7743853"/>
|
<selectedTextColor color="-1"/>
|
||||||
<wrapStyleWord value="true"/>
|
<selectionColor color="-9843846"/>
|
||||||
|
<text value=""/>
|
||||||
</properties>
|
</properties>
|
||||||
</component>
|
</component>
|
||||||
</children>
|
</children>
|
||||||
|
|
|
@ -6,7 +6,16 @@ import javax.swing.*;
|
||||||
* @author Andrew Lalis
|
* @author Andrew Lalis
|
||||||
*/
|
*/
|
||||||
public class View {
|
public class View {
|
||||||
private JPanel panel1;
|
public JPanel mainPanel;
|
||||||
private JTextArea outputArea;
|
private JTextPane outputArea;
|
||||||
private JTextField commandField;
|
private JTextField commandField;
|
||||||
|
|
||||||
|
public View(){
|
||||||
|
this.commandField.addKeyListener(new CommandLineListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
public JTextPane getOutputArea(){
|
||||||
|
return this.outputArea;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package handiebot.view.actions;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrew Lalis
|
||||||
|
*/
|
||||||
|
public class ActionItem extends JMenuItem {
|
||||||
|
|
||||||
|
public ActionItem(String name, ActionListener listener){
|
||||||
|
super(name);
|
||||||
|
this.addActionListener(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package handiebot.view.actions;
|
||||||
|
|
||||||
|
import handiebot.HandieBot;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Andrew Lalis
|
||||||
|
*/
|
||||||
|
public class QuitAction implements ActionListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
HandieBot.quit();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue