/**
* $RCSfile: ,v $
* $Revision: $
* $Date: $
*
* Copyright (C) 2004-2011 Jive Software. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.spark.ui;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.StyleConstants;
import javax.swing.undo.CannotUndoException;
import javax.swing.undo.UndoManager;
import org.jivesoftware.spark.SparkManager;
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
/**
* This is implementation of ChatArea that should be used as the sendField
* in any chat room implementation.
*/
public class ChatInputEditor extends ChatArea implements DocumentListener {
private static final long serialVersionUID = -3085035737908538581L;
private final UndoManager undoManager;
private KeyStroke undoKeyStroke;
private KeyStroke ctrlbackspaceKeyStroke;
private KeyStroke escapeKeyStroke;
/**
* Creates a new Default ChatSendField.
*/
public ChatInputEditor() {
undoManager = new UndoManager();
this.setDragEnabled(true);
this.getDocument().addUndoableEditListener(undoManager);
Action undo = new AbstractAction() {
private static final long serialVersionUID = -8897769620508545403L;
public void actionPerformed(ActionEvent e) {
try {
undoManager.undo();
} catch (CannotUndoException cue) {
// no more undoing for you
}
}
};
Action escape = new AbstractAction() {
private static final long serialVersionUID = -2973535045376312313L;
@Override
public void actionPerformed(ActionEvent e) {
SparkManager.getChatManager().getChatContainer().closeActiveRoom();
}
};
Action ctrlbackspace = new AbstractAction() {
private static final long serialVersionUID = -2973535045376312313L;
@Override
public void actionPerformed(ActionEvent e) {
// We have Text selected, remove it
if (getSelectedText() != null && getSelectedText().length() > 0) {
ChatInputEditor.this.removeWordInBetween(getSelectionStart(),
getSelectionEnd());
// We are somewhere in betwee 0 and str.length
} else if (getCaretPosition() < getText().length()) {
String preCaret = getText()
.substring(0, getCaretPosition());
int lastSpace = preCaret.lastIndexOf(" ") != -1 ? preCaret
.lastIndexOf(" ") : 0;
if (lastSpace != -1 && lastSpace!=0)
{
// Do we have anymore spaces before the current one?
for (int i = lastSpace; getText().charAt(i) == ' '; --i) {
lastSpace--;
}
lastSpace++;
}
ChatInputEditor.this.removeWordInBetween(lastSpace,
getCaretPosition());
if (lastSpace <= getText().length()) {
setCaretPosition(lastSpace);
} else {
setCaretPosition(getText().length());
}
// We are at the end and will remove until the next SPACE
} else if (getText().contains(" ")) {
int untilhere = getText().lastIndexOf(" ");
// Do we have anymore spaces before the last one?
for (int i = untilhere; getText().charAt(i) == ' '; --i) {
untilhere--;
}
untilhere++;
ChatInputEditor.this.removeLastWord(getText().substring(
untilhere));
} else {
ChatInputEditor.this.removeLastWord(getText());
}
}
};
undoKeyStroke = KeyStroke.getKeyStroke('z', ActionEvent.CTRL_MASK);
ctrlbackspaceKeyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, KeyEvent.CTRL_MASK);
escapeKeyStroke = KeyStroke.getKeyStroke("ESCAPE");
getInputMap().put(ctrlbackspaceKeyStroke, "ctrlbackspace");
getInputMap().put(undoKeyStroke, "undo");
getInputMap().put(escapeKeyStroke, "escape");
getInputMap().put(KeyStroke.getKeyStroke("Ctrl W"), "escape");
registerKeyboardAction(undo, KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_MASK), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
registerKeyboardAction(ctrlbackspace, KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, KeyEvent.CTRL_MASK), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
registerKeyboardAction(escape, KeyStroke.getKeyStroke("ESCAPE"), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
getDocument().addDocumentListener(this);
addMouseListener(this);
}
public void insertUpdate(DocumentEvent e) {
// this.setCaretPosition(e.getOffset());
this.requestFocusInWindow();
}
/**
* Appends the Text at the end
*/
public void setText(String str) {
super.setText(str);
}
public void removeUpdate(DocumentEvent e) {
}
public void changedUpdate(DocumentEvent e) {
}
/**
* Remove dependices when no longer in use.
*/
public void close() {
getDocument().removeDocumentListener(this);
getDocument().removeUndoableEditListener(undoManager);
removeMouseListener(this);
getInputMap().remove(undoKeyStroke);
getInputMap().remove(ctrlbackspaceKeyStroke);
getInputMap().remove(escapeKeyStroke);
getInputMap().remove(KeyStroke.getKeyStroke("Ctrl W"));
}
/**
* Disables the Chat Editor, rendering it to the system default
* color.
*/
public void showAsDisabled() {
this.setEditable(false);
this.setEnabled(false);
clear();
final Color disabledColor = (Color)UIManager.get("Button.disabled");
this.setBackground(disabledColor);
}
/**
* Enable the Chat Editor.
*/
public void showEnabled() {
this.setEditable(true);
this.setEnabled(true);
this.setBackground(Color.white);
}
/**
* Inserts text into the current document.
*
* @param text the text to insert
* @throws BadLocationException if the location is not available for insertion.
*/
@Override
public void insertText(String text) throws BadLocationException {
final Document doc = getDocument();
styles.removeAttribute("link");
doc.insertString(this.getCaret().getDot(), text, styles);
}
/**
* Inserts text into the current document.
*
* @param text the text to insert
* @param color the color of the text
* @throws BadLocationException if the location is not available for insertion.
*/
@Override
public void insertText(String text, Color color) throws BadLocationException {
final Document doc = getDocument();
StyleConstants.setForeground(styles, color);
doc.insertString(this.getCaret().getDot(), text, styles);
}
/**
* Inserts a link into the current document.
*
* @param link - the link to insert( ex. http://www.javasoft.com )
* @throws BadLocationException if the location is not available for insertion.
*/
@Override
public void insertLink(String link) throws BadLocationException {
final Document doc = getDocument();
styles.addAttribute("link", link);
StyleConstants.setForeground(styles, (Color)UIManager.get("Link.foreground"));
StyleConstants.setUnderline(styles, true);
doc.insertString(this.getCaret().getDot(), link, styles);
StyleConstants.setUnderline(styles, false);
StyleConstants.setForeground(styles, (Color)UIManager.get("TextPane.foreground"));
styles.removeAttribute("link");
setCharacterAttributes(styles, false);
}
/**
* Inserts a network address into the current document.
*
* @param address - the address to insert( ex. \superpc\etc\file\ OR http://localhost/ )
* @throws BadLocationException if the location is not available for insertion.
*/
@Override
public void insertAddress(String address) throws BadLocationException {
final Document doc = getDocument();
styles.addAttribute("link", address);
StyleConstants.setForeground(styles, (Color)UIManager.get("Address.foreground"));
StyleConstants.setUnderline(styles, true);
doc.insertString(this.getCaret().getDot(), address, styles);
StyleConstants.setUnderline(styles, false);
StyleConstants.setForeground(styles, (Color)UIManager.get("TextPane.foreground"));
styles.removeAttribute("link");
setCharacterAttributes(styles, false);
}
/**
* Inserts an emotion icon into the current document.
*
* @param imageKey - the smiley representation of the image.( ex. :) )
* @return true if the image was found, otherwise false.
*/
@Override
public boolean insertImage(String imageKey) {
if(!forceEmoticons && !SettingsManager.getLocalPreferences().areEmoticonsEnabled() || !emoticonsAvailable){
return false;
}
final Document doc = getDocument();
Icon emotion = emoticonManager.getEmoticonImage(imageKey.toLowerCase());
if (emotion == null) {
return false;
}
select(doc.getLength(), doc.getLength());
insertIcon(emotion);
return true;
}
}