/* Copyright (c) 2013, nifty-gui / Joris van der Wel * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the <organization> nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package aphelion.client.graphics.nifty.chat; import de.lessvoid.nifty.Nifty; import de.lessvoid.nifty.NiftyEvent; import de.lessvoid.nifty.controls.*; import de.lessvoid.nifty.controls.chatcontrol.ChatEntryModelClass; import de.lessvoid.nifty.elements.Element; import de.lessvoid.nifty.input.NiftyInputEvent; import de.lessvoid.nifty.render.NiftyImage; import de.lessvoid.nifty.screen.KeyInputHandler; import de.lessvoid.nifty.screen.Screen; import de.lessvoid.xml.xpp3.Attributes; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; /** * This is the main controller for the chat control. * * @author Mark * @author Joris */ public class AphelionChatControl extends AbstractController implements KeyInputHandler { private static final String CHAT_BOX = "#chatBox"; private static final String PLAYER_LIST = "#playerList"; private static final String CHAT_TEXT_INPUT = "#chat-text-input"; private static final Logger log = Logger.getLogger(AphelionChatControl.class.getName()); private TextField textControl; private final PlayerComparator playerComparator = new PlayerComparator(); private Nifty nifty; private final List<PlayerEntry> playerBuffer = new ArrayList<>(); private final List<ChatEntryModelClass> linesBuffer = new ArrayList<>(); /** * Default constructor. */ public AphelionChatControl() { } /** * {@inheritDoc} */ @Override public final void bind(final Nifty niftyParam, final Screen screenParam, final Element newElement, final Properties properties, final Attributes controlDefinitionAttributes) { super.bind(newElement); log.fine("binding chat control"); nifty = niftyParam; // this buffer is needed because in some cases the entry is added to either list before the emelent is bound. final ListBox<PlayerEntry> playerList = getListBox(PLAYER_LIST); while (!playerBuffer.isEmpty()) { PlayerEntry player = playerBuffer.remove(0); log.log(Level.FINE, "adding player {0}", (playerList.itemCount() + 1)); playerList.addItem(player); playerList.sortAllItems(playerComparator); playerList.showItem(player); } final ListBox<ChatEntryModelClass> chatBox = getListBox(CHAT_BOX); for (int i = 0; i < chatBox.getDisplayItemCount() - 1; ++i) { chatBox.addItem(new ChatEntryModelClass("", null)); } while (!linesBuffer.isEmpty()) { ChatEntryModelClass line = linesBuffer.remove(0); log.log(Level.FINE, "adding message {0}", (chatBox.itemCount() + 1)); chatBox.addItem(line); chatBox.showItemByIndex(chatBox.itemCount() - 1); } } /** * {@inheritDoc} */ @Override public void onFocus(final boolean arg0) { textControl.setFocus(); } /** * {@inheritDoc} */ @Override public final void onStartScreen() { log.fine("starting chat screen"); textControl = getElement().findNiftyControl(CHAT_TEXT_INPUT, TextField.class); textControl.getElement().addInputHandler(this); } public final void receivedChatLine(final String text, final NiftyImage icon) { receivedChatLine(text, icon, null); } public void receivedChatLine(String text, NiftyImage icon, String style) { text = text.replace("$", "\\$"); if (linesBuffer.isEmpty()) { try { final ListBox<ChatEntryModelClass> chatBox = getListBox(CHAT_BOX); log.log(Level.FINE, "adding message {0}", (chatBox.itemCount() + 1)); final ChatEntryModelClass item = new ChatEntryModelClass(text, icon, style); chatBox.addItem(item); chatBox.showItemByIndex(chatBox.itemCount() - 1); } catch (NullPointerException npe) { linesBuffer.add(new ChatEntryModelClass(text, icon, style)); } } else { linesBuffer.add(new ChatEntryModelClass(text, icon, style)); } } public final void addPlayer(int pid, String playerName, NiftyImage playerIcon) { playerName = playerName.replace("$", "\\$"); addPlayer(pid, playerName, playerIcon, null); } public void addPlayer(int pid, String playerName, NiftyImage playerIcon, String style) { playerName = playerName.replace("$", "\\$"); if (playerBuffer.isEmpty()) { try { final ListBox<PlayerEntry> playerList = getListBox(PLAYER_LIST); log.log(Level.FINE, "adding player {0}", (playerList.itemCount() + 1)); final PlayerEntry item = new PlayerEntry(pid, playerName, playerIcon, style); playerList.addItem(item); playerList.sortAllItems(playerComparator); playerList.showItem(item); } catch (NullPointerException npe) { playerBuffer.add(new PlayerEntry(pid, playerName, playerIcon, style)); } } else { playerBuffer.add(new PlayerEntry(pid, playerName, playerIcon, style)); } } public final void renamePlayer(int pid, String playerName) { playerName = playerName.replace("$", "\\$"); final ListBox<PlayerEntry> playerList = getListBox(PLAYER_LIST); int i = playerList.getItems().indexOf(new PlayerEntry(pid, null, null)); if (i >= 0) { PlayerEntry item = playerList.getItems().get(i); item.setLabel(playerName); } } public final void removePlayer(int pid) { final ListBox<PlayerEntry> playerList = getListBox(PLAYER_LIST); log.log(Level.FINE, "removing player {0}", pid); final PlayerEntry item = new PlayerEntry(pid, null, null); playerList.removeItem(item); } public List<PlayerEntry> getPlayers() { final ListBox<PlayerEntry> playerList = getListBox(PLAYER_LIST); return playerList.getItems(); } public List<ChatEntryModelClass> getLines() { final ListBox<ChatEntryModelClass> chatBox = getListBox(CHAT_BOX); return chatBox.getItems(); } public void update() { getListBox(PLAYER_LIST).refresh(); } /** * This method is called when the player either presses the send button or * the Return key. */ public final void sendText() { final String text = textControl.getText(); log.log(Level.INFO, "sending text {0}", text); nifty.publishEvent(getId(), new AphelionChatTextSendEvent(this, text)); textControl.setText(""); } private ListBox getListBox(final String name) { return getElement().findNiftyControl(name, ListBox.class); } /** * {@inheritDoc} */ @Override public boolean keyEvent(final NiftyInputEvent inputEvent) { if (inputEvent == null) { return false; } log.log(Level.FINE, "event received: {0}", inputEvent); if (inputEvent == NiftyInputEvent.SubmitText) { sendText(); return true; } else if (inputEvent == NiftyInputEvent.MoveCursorRight) { } return false; } /** * {@inheritDoc} */ @Override public boolean inputEvent(final NiftyInputEvent inputEvent) { return keyEvent(inputEvent); } /** * Class used to sort the list of players by name. * * @author Mark * @version 0.2 */ private class PlayerComparator implements Comparator<PlayerEntry> { /** * Default constructor. */ PlayerComparator() { } /** * {@inheritDoc} */ @Override public int compare(final PlayerEntry player1, final PlayerEntry player2) { String left = player1.getLabel(); String right = player2.getLabel(); return left.compareToIgnoreCase(right); } } public static class AphelionChatTextSendEvent implements NiftyEvent<Void> { private final AphelionChatControl chatControl; private final String text; public AphelionChatTextSendEvent(final AphelionChatControl chatControl, final String textParam) { this.chatControl = chatControl; this.text = textParam; } public AphelionChatControl getChatControl() { return chatControl; } public String getText() { return text; } } }