1 package org.convey;
2 
3 import javax.swing.*;
4 import javax.swing.text.*;
5 
6 import java.awt.*;
7 
8 import java.awt.event.*;
9 
10 import com.echomine.jabber.*;
11 import com.echomine.common.*;
12 import com.echomine.net.*;
13 
14 import org.jdom.*;
15 
16 import java.util.*;
17 
18 import java.text.*;
19 
20 /**
21  * @author Andy Ames
22  * @version 0.3
23  */
24 public class JabberCanvasPanel extends CanvasPanel implements ActionListener {
25 
26 	protected boolean autoScrollChatHistory = true;
27 
28 	protected boolean initiator;
29 
30 	protected boolean requestPen = false;
31 
32 	protected boolean revokePen = false;
33 
34 	protected boolean deniedPen = false;
35 
36 	protected int timeout = -1;
37 
38 	/**
39 	 * Straight text chat text field.
40 	 */
41 	protected JTextField chatTextField;
42 
43 	/**
44 	 * Straight text chat history text pane.
45 	 */
46 	protected JTextPane chatHistoryTextPane;
47 
48 	protected JScrollPane chatHistoryScrollPane;
49 
50 	/**
51 	 * Jabber chat conversation thread identifier. This is non-null when the user
52 	 * is connected, has indicated a chat user that will receive messages sent,
53 	 * and at least one message has been sent to the user indicated. Otherwise,
54 	 * its null.
55 	 */
56 	protected String threadId = null;
57 
58 	/**
59 	 * Jabber chat user who will receive messages. This is non-null when the user
60 	 * is connected and has indicated a chat user that will receive messages sent.
61 	 * <p>
62 	 * This field consists of the username, an ampersand, and the server
63 	 * (johndoe@jabber.org). The Jabbber resource is not included.
64 	 * (johndoe@jabber.org/Convey is incorrect.)
65 	 */
66 	protected String to = null;
67 
68 	protected String subject = null;
69 
JabberCanvasPanel(ConveyFrame conveyFrame, String to, String subject)70 	public JabberCanvasPanel(ConveyFrame conveyFrame, String to, String subject) {
71 		super(conveyFrame);
72 		super.setNetworked();
73 
74 		this.to = to;
75 
76 		if(subject != null)
77 			this.subject = subject;
78 		else
79 			this.subject = "";
80 
81 		this.threadId = String.valueOf(System.currentTimeMillis());
82 
83 		super.graphicPanel.setHasPen(false);
84 	}
85 
JabberCanvasPanel(ConveyFrame conveyFrame, String to, String threadId, String subject)86 	public JabberCanvasPanel(ConveyFrame conveyFrame, String to, String threadId, String subject) {
87 		super(conveyFrame);
88 
89 		this.to = to;
90 
91 		this.threadId = threadId;
92 
93 		if(subject != null)
94 			this.subject = subject;
95 		else
96 			this.subject = "";
97 
98 		super.graphicPanel.setHasPen(false);
99 	}
100 
initCenterComponent()101 	public void initCenterComponent() {
102 		JPanel chatPanel = new JPanel(new BorderLayout(5, 5));
103 
104 		this.chatHistoryTextPane = new JTextPane();
105 		this.chatHistoryTextPane.setEditable(false);
106 		this.chatTextField = new JTextField();
107 		this.chatTextField.addActionListener(this);
108 
109 		this.chatHistoryScrollPane = new JScrollPane(this.chatHistoryTextPane,
110 				JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
111 				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
112 		MouseListener ml = new MouseAdapter() {
113 			public void mouseReleased(MouseEvent e) {
114 				JScrollBar scrollBar = (JScrollBar)e.getSource();
115 				if(scrollBar.getValue() + scrollBar.getModel().getExtent() == scrollBar.getMaximum())
116 					autoScrollChatHistory = true;
117 				else
118 					autoScrollChatHistory = false;
119 			}
120 		};
121 		this.chatHistoryScrollPane.getVerticalScrollBar().addMouseListener(ml);
122 
123 		chatPanel.add(this.chatHistoryScrollPane, BorderLayout.CENTER);
124 
125 		Box chatMessageBox = new Box(BoxLayout.X_AXIS);
126 		JLabel messageLabel = new JLabel(" Message ");
127 		chatMessageBox.add(messageLabel);
128 		chatMessageBox.add(this.chatTextField);
129 		chatPanel.add(chatMessageBox, BorderLayout.SOUTH);
130 
131 		JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, super.graphicPanel, chatPanel);
132 		splitPane.setDividerLocation(350);
133 
134 		super.add(splitPane, BorderLayout.CENTER);
135 		super.setNetworked();
136 	}
137 
138 	/**
139 	 * Sends straight text message if the user is connected and has indicated a
140 	 * chat receiver and has typed text into chatTextField.
141 	 */
sendText()142 	public void sendText() {
143 		JabberSession session = super.conveyFrame.getJabberSession();
144 		if(session != null && this.to != null) {
145 			if(this.chatTextField.getText().length() > 0) {
146 				JabberConveyMessage msg = new JabberConveyMessage();
147 				msg.setThreadID(this.threadId);
148 				if(this.subject != null)
149 					msg.setSubject(this.subject);
150 				msg.setTo(this.to);
151 				msg.setFrom(super.conveyFrame.getFrom());
152 				msg.setBody(this.chatTextField.getText());
153 				try {
154 					session.sendMessage(msg);
155 				} catch(SendMessageFailedException e) {
156 					e.printStackTrace();
157 				}
158 
159 				this.appendMessage(msg, Color.blue);
160 
161 				this.chatTextField.setText("");
162 
163 				if(this.autoScrollChatHistory) {
164 					JScrollBar scrollBar = this.chatHistoryScrollPane.getVerticalScrollBar();
165 					scrollBar.setValue(scrollBar.getMaximum() - scrollBar.getModel().getExtent());
166 				}
167 			}
168 		}
169 	}
170 
171 	/**
172 	 * Action event receiver for when the user presses &lt;Enter&gt; while the
173 	 * chat text field has focus.
174 	 */
actionPerformed(ActionEvent e)175 	public void actionPerformed(ActionEvent e) {
176 		sendText();
177 	}
178 
appendMessage(JabberConveyMessage msg, Color nameColor)179 	public void appendMessage(JabberConveyMessage msg, Color nameColor) {
180 		StringTokenizer tokenizer = new StringTokenizer(msg.getFrom(), "@");
181 		StringBuffer name = new StringBuffer(" <");
182 		name.append(tokenizer.nextToken());
183 		name.append('>');
184 		DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
185 		StringBuffer date = new StringBuffer(format.format(new Date()));
186 		date.insert(0, '[');
187 		date.append(']');
188 		StringBuffer message = new StringBuffer(" ");
189 		message.append(msg.getBody());
190 		message.append('\n');
191 
192 		// Need package name to avoid conflict with org.jdom.Document
193 		javax.swing.text.Document doc = this.chatHistoryTextPane.getDocument();
194 		try {
195 			SimpleAttributeSet set = new SimpleAttributeSet();
196 			StyleConstants.setForeground(set, Color.lightGray);
197 			doc.insertString(doc.getLength(), date.toString(), set);
198 			StyleConstants.setForeground(set, nameColor);
199 			doc.insertString(doc.getLength(), name.toString(), set);
200 			StyleConstants.setForeground(set, Color.black);
201 			doc.insertString(doc.getLength(), message.toString(), set);
202 		} catch(Exception e) {
203 			e.printStackTrace();
204 		}
205 	}
206 
getThreadId()207 	public String getThreadId() {
208 		return this.threadId;
209 	}
210 
getSubject()211 	public String getSubject() {
212 		return this.subject;
213 	}
214 
getTo()215 	public String getTo() {
216 		return this.to;
217 	}
218 
handleMessage(JabberConveyMessage msg)219 	public void handleMessage(JabberConveyMessage msg) {
220 		if(msg.isConvey())
221 			super.graphicPanel.handleConveyElement(msg.getConveyElement());
222 		else if(msg.isPen())
223 			this.handlePenElement(msg.getPenElement());
224 		else {
225 			this.appendMessage(msg, Color.red);
226 
227 			if(this.autoScrollChatHistory) {
228 				JScrollBar scrollBar = this.chatHistoryScrollPane.getVerticalScrollBar();
229 				scrollBar.setValue(scrollBar.getMaximum() - scrollBar.getModel().getExtent());
230 			}
231 		}
232 	}
233 
sendGraphicEvent(GraphicEvent event)234 	public void sendGraphicEvent(GraphicEvent event) {
235 		JabberSession session = super.getConveyFrame().getJabberSession();
236 		if(session != null && this.to != null) {
237 			org.jdom.Element element = event.toElement();
238 			if(element != null) {
239 				org.jdom.Element conveyElement = new org.jdom.Element("convey", JabberConveyMessage.CONVEY_XMLNS);
240 				conveyElement.addContent(element);
241 
242 				JabberConveyMessage msg = new JabberConveyMessage();
243 				msg.setThreadID(this.threadId);
244 				if(this.subject != null)
245 					msg.setSubject(this.subject);
246 				msg.setTo(this.to);
247 				msg.setFrom(super.getConveyFrame().getFrom());
248 				msg.setConveyElement(conveyElement);
249 				try {
250 					session.sendMessage(msg);
251 				} catch(SendMessageFailedException e) {
252 					e.printStackTrace();
253 				}
254 			}
255 		}
256 	}
257 
setInitiator(boolean value)258 	public void setInitiator(boolean value) {
259 		this.initiator = value;
260 	}
261 
isInitiator()262 	public boolean isInitiator() {
263 		return this.initiator;
264 	}
265 
handlePenElement(org.jdom.Element penElement)266 	public void handlePenElement(org.jdom.Element penElement) {
267 		if(penElement.getChild("request") != null) {
268 			this.requestPen = true;
269 			if(this.getConveyFrame().getSelectedCanvasPanel() == this)
270 				doRequest();
271 		} else if(penElement.getChild("revoke") != null) {
272 			this.requestPen = false;
273 			this.revokePen = true;
274 			if(this.getConveyFrame().getSelectedCanvasPanel() == this)
275 				doRevoke();
276 		} else if(penElement.getChild("yield") != null) {
277 			this.requestPen = false;
278 			this.revokePen = false;
279 			super.graphicPanel.setHasPen(true);
280 		} else if(penElement.getChild("granted") != null) {
281 			this.requestPen = false;
282 			this.revokePen = false;
283 			super.graphicPanel.setHasPen(true);
284 		} else if(penElement.getChild("denied") != null) {
285 			this.deniedPen = true;
286 			if(this.getConveyFrame().getSelectedCanvasPanel() == this) {
287 				if(this.requestPen)
288 					doRequest();
289 			}
290 		}
291 
292 		super.getConveyFrame().updateButtons();
293 	}
294 
doRequest()295 	public void doRequest() {
296 		if(super.graphicPanel.hasPen()) {
297 			int res = JOptionPane.showConfirmDialog(this, this.to + " is requesting the Pen. Do you wish to grant Pen request?", "Pen Request",
298 																							JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
299 																							ResourceLoader.loadImageIcon("org/convey/images/requestpen.png"));
300 			if(res == JOptionPane.YES_OPTION) {
301 				super.graphicPanel.flushGraphicEventQueue();
302 				super.graphicPanel.setHasPen(false);
303 				this.sendPenEvent(new PenEvent(PenEvent.GRANTED));
304 			} else
305 				this.sendPenEvent(new PenEvent(PenEvent.DENIED));
306 		} else if(this.deniedPen) {
307 			JOptionPane.showConfirmDialog(this, this.to + " denied your Pen request.", "Pen Request",
308 																		JOptionPane.OK_OPTION, JOptionPane.INFORMATION_MESSAGE,
309 																		ResourceLoader.loadImageIcon("org/convey/images/requestpen.png"));
310 			this.deniedPen = false;
311 		} else
312 			super.graphicPanel.setHasPen(true);
313 
314 		this.requestPen = false;
315 	}
316 
doRevoke()317 	public void doRevoke() {
318 		if(super.graphicPanel.hasPen()) {
319 			super.graphicPanel.flushGraphicEventQueue();
320 			super.graphicPanel.setHasPen(false);
321 			this.sendPenEvent(new PenEvent(PenEvent.YIELD));
322 			JOptionPane.showConfirmDialog(this, this.to + " is revoking the Pen.", "Pen Revoke",
323 																		JOptionPane.OK_OPTION, JOptionPane.INFORMATION_MESSAGE,
324 																		ResourceLoader.loadImageIcon("org/convey/images/revokepen.png"));
325 		}
326 
327 		this.revokePen = false;
328 	}
329 
isRequest()330 	public boolean isRequest() {
331 		return this.requestPen;
332 	}
333 
isRevoke()334 	public boolean isRevoke() {
335 		return this.revokePen;
336 	}
337 
sendPenEvent(PenEvent event)338 	public void sendPenEvent(PenEvent event) {
339 		JabberSession session = super.getConveyFrame().getJabberSession();
340 		if(session != null && this.to != null) {
341 			org.jdom.Element element = event.toElement();
342 			if(element != null) {
343 				org.jdom.Element conveyElement = new org.jdom.Element("pen", JabberConveyMessage.CONVEY_XMLNS);
344 				conveyElement.addContent(element);
345 
346 				JabberConveyMessage msg = new JabberConveyMessage();
347 				msg.setThreadID(this.threadId);
348 				if(this.subject != null)
349 					msg.setSubject(this.subject);
350 				msg.setTo(this.to);
351 				msg.setFrom(super.getConveyFrame().getFrom());
352 				msg.setConveyElement(conveyElement);
353 				try {
354 					session.sendMessage(msg);
355 				} catch(SendMessageFailedException e) {
356 					e.printStackTrace();
357 				}
358 			}
359 		}
360 	}
361 
penYield()362 	void penYield() {
363 		super.graphicPanel.flushGraphicEventQueue();
364 
365 		super.graphicPanel.setHasPen(false);
366 		this.sendPenEvent(new PenEvent(PenEvent.YIELD));
367 
368 		super.getConveyFrame().updateButtons();
369 	}
370 
penRequest()371 	void penRequest() {
372 		this.requestPen = true;
373 		this.sendPenEvent(new PenEvent(PenEvent.REQUEST));
374 	}
375 
penRevoke()376 	void penRevoke() {
377 		this.requestPen = false;
378 		this.revokePen = true;
379 		this.sendPenEvent(new PenEvent(PenEvent.REVOKE));
380 	}
381 
382 }