001: /*
002: * Copyright 2001-2006 C:1 Financial Services GmbH
003: *
004: * This software is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License Version 2.1, as published by the Free Software Foundation.
007: *
008: * This software is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
011: * Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public
014: * License along with this library; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
016: */
017:
018: package de.finix.contelligent.client.modules.message;
019:
020: import java.awt.BorderLayout;
021: import java.awt.Dimension;
022: import java.awt.FlowLayout;
023: import java.awt.event.ActionEvent;
024: import java.awt.event.ActionListener;
025: import java.awt.event.KeyEvent;
026: import java.awt.event.KeyListener;
027: import java.util.Iterator;
028: import java.util.Vector;
029: import java.util.logging.Logger;
030:
031: import javax.swing.Action;
032: import javax.swing.JButton;
033: import javax.swing.JComboBox;
034: import javax.swing.JLabel;
035: import javax.swing.JList;
036: import javax.swing.JPanel;
037: import javax.swing.JScrollPane;
038: import javax.swing.JSplitPane;
039: import javax.swing.JTextField;
040: import javax.swing.JTextPane;
041: import javax.swing.text.BadLocationException;
042: import javax.swing.text.Document;
043: import javax.swing.text.Style;
044: import javax.swing.text.StyleConstants;
045: import javax.swing.text.StyleContext;
046:
047: import de.finix.contelligent.client.base.RemoteSession;
048: import de.finix.contelligent.client.base.RemoteSessionListener;
049: import de.finix.contelligent.client.base.Session;
050: import de.finix.contelligent.client.event.ContelligentEventDispatcher;
051: import de.finix.contelligent.client.event.MessageEvent;
052: import de.finix.contelligent.client.event.MessageEventListener;
053: import de.finix.contelligent.client.i18n.Resources;
054: import de.finix.contelligent.client.modules.AbstractModule;
055: import de.finix.contelligent.client.remote.ActionResult;
056: import de.finix.contelligent.client.remote.Actions;
057: import de.finix.contelligent.client.remote.RemoteActionException;
058:
059: /**
060: * Module for sending chat messages between contelligent clients.
061: */
062: public class MessageModule extends AbstractModule implements
063: ActionListener, MessageEventListener, KeyListener,
064: RemoteSessionListener {
065:
066: /**
067: * For logging messages and errors.
068: */
069: private static Logger logger = Logger.getLogger(MessageModule.class
070: .getName());
071:
072: /**
073: * The levels of importance of a message.
074: */
075: private static final String[] IMPORTANCE_LEVELS = new String[] {
076: "high", "medium" };
077:
078: /**
079: * The default importance level of a message.
080: */
081: private static final int IMPORTANCE_LEVEL_DEFAULT = 1;
082:
083: private JTextPane mainTextPane = null;
084:
085: private JTextField inputField = null;
086:
087: private JComboBox importanceCombo = null;
088:
089: private JList userList = null;
090:
091: JButton clearSelectionButton = null;
092:
093: private Vector remoteSessions = null;
094:
095: public void actionPerformed(ActionEvent ae) {
096: Object source = ae.getSource();
097: if (source.equals(clearSelectionButton)) {
098: userList.clearSelection();
099: } else {
100: // Ignore the action.
101: }
102: }
103:
104: /**
105: * Create the panel containing the controls for specifying the importance of
106: * the message being sent.
107: *
108: * @return the importance panel.
109: */
110: private JPanel createImportancePanel() {
111: JPanel importancePanel = new JPanel(new FlowLayout());
112: JLabel importanceLabel = new JLabel(Resources
113: .getLocalString("importance")
114: + ":");
115: importancePanel.add(importanceLabel);
116: return importancePanel;
117: }
118:
119: /**
120: * Create the panel for inputting the text message to be sent.
121: *
122: * @return the input panel.
123: */
124: private JPanel createInputPanel() {
125: JPanel inputPanel = new JPanel(new BorderLayout());
126: JLabel messageLabel = new JLabel(Resources
127: .getLocalString("message")
128: + ":");
129: inputPanel.add(messageLabel, BorderLayout.WEST);
130: inputField = new JTextField();
131: inputField.addKeyListener(this );
132: inputPanel.add(inputField);
133: importanceCombo = new JComboBox(new String[] {
134: Resources.getLocalString(IMPORTANCE_LEVELS[0]),
135: Resources.getLocalString(IMPORTANCE_LEVELS[1]) });
136: importanceCombo.setSelectedIndex(IMPORTANCE_LEVEL_DEFAULT);
137: inputPanel.add(importanceCombo, BorderLayout.EAST);
138: return inputPanel;
139: }
140:
141: /**
142: * Create the panel for displaying user logged in to the server.
143: *
144: * @return the user panel.
145: */
146: private JPanel createUserPanel() {
147: JPanel userPanel = new JPanel(new BorderLayout());
148: JLabel usersLabel = new JLabel(Resources
149: .getLocalString("users")
150: + ":", JLabel.CENTER);
151: userPanel.add(usersLabel, BorderLayout.NORTH);
152: userList = new JList();
153: userList
154: .setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
155: JScrollPane listPane = new JScrollPane(userList);
156: userPanel.add(listPane);
157: updateUserList();
158: clearSelectionButton = new JButton(Resources
159: .getLocalString("clear_selection"));
160: clearSelectionButton.setToolTipText(Resources
161: .getLocalString("clear_selection_tooltip"));
162: clearSelectionButton.addActionListener(this );
163: userPanel.add(clearSelectionButton, BorderLayout.SOUTH);
164: return userPanel;
165: }
166:
167: /**
168: * Display the message in the main text pane.
169: *
170: * @param sender
171: * the name of the user who sent the message.
172: * @param message
173: * the message text to be displayed.
174: * @param type
175: * the type of message to be displayed. The types of messages are
176: * defined in MessageEvent.
177: */
178: private void displayMessage(String user, String message, int type) {
179: try {
180: Document d = mainTextPane.getDocument();
181: StyleContext defaultStyleContext = StyleContext
182: .getDefaultStyleContext();
183: Style defaultStyle = defaultStyleContext
184: .getStyle(StyleContext.DEFAULT_STYLE);
185: Style s = defaultStyleContext.addStyle(null, defaultStyle);
186: String prefix = user;
187: switch (type) {
188: case MessageEvent.TYPE_FROM:
189: prefix = Resources.getLocalString("from") + " "
190: + prefix;
191: StyleConstants.setItalic(s, true);
192: break;
193: case MessageEvent.TYPE_TO:
194: prefix = Resources.getLocalString("to") + " " + prefix;
195: StyleConstants.setItalic(s, true);
196: break;
197: case MessageEvent.TYPE_TO_ALL:
198: StyleConstants.setItalic(s, false);
199: break;
200: case MessageEvent.TYPE_TO_SELF:
201: prefix = Resources.getLocalString("to_yourself");
202: StyleConstants.setItalic(s, true);
203: break;
204: default:
205: // Unknown message type.
206: }
207: d.insertString(d.getLength(), prefix + "> " + message
208: + "\n", s);
209: } catch (BadLocationException ble) {
210: logger.severe(ble.getMessage());
211: }
212: }
213:
214: public Action[] getActions() {
215: return new Action[] {};
216: }
217:
218: /**
219: * Get the importance status of the message to be sent.
220: *
221: * @return the importance status.
222: */
223: private String getImportance() {
224: return IMPORTANCE_LEVELS[importanceCombo.getSelectedIndex()];
225: }
226:
227: /**
228: * Get the message text to be sent.
229: *
230: * @return the message text.
231: */
232: private String getMessageText() {
233: return inputField.getText();
234: }
235:
236: /**
237: * Get the id of the session corresponding to the selected user.
238: *
239: * @return the id of the session.
240: */
241: private String getReceiver() {
242: int selectedIndex = userList.getSelectedIndex();
243: String receiverId = null;
244: if (selectedIndex >= 0) {
245: RemoteSession rs = (RemoteSession) remoteSessions
246: .elementAt(selectedIndex);
247: receiverId = rs.getSessionId();
248: } else {
249: receiverId = "";
250: }
251: return receiverId;
252: }
253:
254: /**
255: * Get the id of the current client session.
256: *
257: * @return the id of the client session.
258: */
259: private String getSender() {
260: Session s = Session.getInstance();
261: String contelligentSessionHandle = s
262: .getContelligentSessionHandle();
263: int equalIndex = contelligentSessionHandle.indexOf('=') + 1;
264: String sessionId = contelligentSessionHandle
265: .substring(equalIndex);
266: return sessionId;
267: }
268:
269: public void init() {
270: // Add content.
271: mainTextPane = new JTextPane();
272: mainTextPane.setEditable(false);
273: JPanel userPanel = createUserPanel();
274: JSplitPane mainPanel = new JSplitPane(
275: JSplitPane.HORIZONTAL_SPLIT, new JScrollPane(
276: mainTextPane), userPanel);
277: add(mainPanel);
278: JPanel inputPanel = createInputPanel();
279: add(inputPanel, BorderLayout.SOUTH);
280:
281: // Set size.
282: int width = getFontMetrics(getFont()).charWidth('n') * 80;
283: int height = width / 2;
284: setPreferredSize(new Dimension(width, height));
285:
286: // Set divider location.
287: Dimension userPanelSize = userPanel.getPreferredSize();
288: int userPanelWidth = (int) userPanelSize.getWidth();
289: int dividerSize = mainPanel.getDividerSize();
290: int dividerLocation = width - userPanelWidth - 2 * dividerSize;
291: mainPanel.setDividerLocation(dividerLocation);
292:
293: // Add listeners.
294: Session.getInstance().addMessageEventListener(this ,
295: ContelligentEventDispatcher.DOES_USE_SWING);
296: Session.getInstance().addRemoteSessionListener(this );
297: }
298:
299: public void keyPressed(KeyEvent ke) {
300: }
301:
302: public void keyReleased(KeyEvent ke) {
303: if (ke.getKeyCode() == KeyEvent.VK_ENTER) {
304: String sender = getSender();
305: String message = getMessageText();
306: String importance = getImportance();
307: String receiver = getReceiver();
308: sendMessage(sender, message, importance, receiver);
309: inputField.setText("");
310: importanceCombo.setSelectedIndex(IMPORTANCE_LEVEL_DEFAULT);
311: }
312: }
313:
314: public void keyTyped(KeyEvent ke) {
315: }
316:
317: public void onMessageReceived(MessageEvent me) {
318: displayMessage(me.getUser(), me.getMessage(), me.getType());
319: }
320:
321: public void remoteSessionClosed(RemoteSession rs) {
322: updateUserList();
323: }
324:
325: public void remoteSessionOpened(RemoteSession rs) {
326: updateUserList();
327: }
328:
329: /**
330: * Send to the server a message that was typed into the input pane.
331: *
332: * @param sender
333: * the id of client session from which the message is being sent.
334: * @param message
335: * the message text to be sent.
336: * @param importance
337: * the importance of the message. This can be `medium' or `high'.
338: * @param receiver
339: * the id of the client session to receive the message.
340: */
341: private void sendMessage(String sender, String message,
342: String importance, String receiver) {
343: try {
344: ActionResult result = Actions.sendMessage(sender, message,
345: importance, receiver);
346: result.showErrors();
347: } catch (RemoteActionException rae) {
348: logger.severe(rae.getMessage());
349: }
350: }
351:
352: /**
353: * Update the list of logged in users. For example, when a user has logged
354: * in or out.
355: */
356: private void updateUserList() {
357: Session s = Session.getInstance();
358: remoteSessions = new Vector(s.getRemoteSessions());
359: Vector userEntries = new Vector(remoteSessions.size());
360: Iterator i = remoteSessions.iterator();
361: while (i.hasNext()) {
362: RemoteSession rs = (RemoteSession) i.next();
363: String userName = rs.getUserName();
364: String hostName = rs.getHostName();
365: userEntries.add(userName + "@" + hostName);
366: }
367: userList.setListData(userEntries);
368: }
369: }
|