001: // The contents of this file are subject to the Mozilla Public License Version
002: // 1.1
003: //(the "License"); you may not use this file except in compliance with the
004: //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
005: //
006: //Software distributed under the License is distributed on an "AS IS" basis,
007: //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
008: //for the specific language governing rights and
009: //limitations under the License.
010: //
011: //The Original Code is "The Columba Project"
012: //
013: //The Initial Developers of the Original Code are Frederik Dietz and Timo
014: // Stich.
015: //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
016: //
017: //All Rights Reserved.
018: package org.columba.chat.ui.roaster;
019:
020: import java.lang.reflect.InvocationTargetException;
021: import java.util.logging.Logger;
022:
023: import javax.swing.JOptionPane;
024: import javax.swing.JTree;
025: import javax.swing.SwingUtilities;
026: import javax.swing.tree.DefaultMutableTreeNode;
027: import javax.swing.tree.DefaultTreeModel;
028: import javax.swing.tree.TreePath;
029:
030: import org.columba.chat.Connection;
031: import org.columba.chat.MainInterface;
032: import org.columba.chat.command.AddContactCommand;
033: import org.columba.chat.command.ChatCommandReference;
034: import org.columba.chat.command.SubscriptionCommand;
035: import org.columba.chat.conn.api.ConnectionChangedEvent;
036: import org.columba.chat.conn.api.IConnectionChangedListener;
037: import org.columba.chat.conn.api.IConnection.STATUS;
038: import org.columba.chat.model.BuddyList;
039: import org.columba.chat.model.BuddyStatus;
040: import org.columba.chat.model.api.IBuddyStatus;
041: import org.columba.chat.ui.frame.api.IChatFrameMediator;
042: import org.columba.chat.ui.roaster.api.IRoasterController;
043: import org.columba.core.command.CommandProcessor;
044: import org.columba.core.gui.frame.FrameManager;
045: import org.jivesoftware.smack.PacketListener;
046: import org.jivesoftware.smack.filter.PacketTypeFilter;
047: import org.jivesoftware.smack.packet.Packet;
048: import org.jivesoftware.smack.packet.Presence;
049:
050: /**
051: * @author fdietz
052: *
053: */
054: public class RoasterTree extends JTree implements IRoasterController,
055: IConnectionChangedListener {
056:
057: private static final Logger LOG = Logger
058: .getLogger("org.columba.chat.ui.roaster");
059:
060: private DefaultTreeModel model;
061:
062: private DefaultMutableTreeNode root;
063:
064: private IChatFrameMediator mediator;
065:
066: private SubscriptionListener subscriptionListener = new SubscriptionListener();
067:
068: private PresenceListener presenceListener = new PresenceListener();
069:
070: public RoasterTree(IChatFrameMediator mediator) {
071: this .mediator = mediator;
072:
073: root = new DefaultMutableTreeNode("Roster");
074:
075: model = new DefaultTreeModel(root);
076:
077: setModel(model);
078:
079: setCellRenderer(new RoasterTreeRenderer());
080:
081: // setPreferredSize(new Dimension(250, 300));
082: setRootVisible(false);
083: setShowsRootHandles(true);
084:
085: MainInterface.connection.addConnectionChangedListener(this );
086:
087: }
088:
089: /*
090: * (non-Javadoc)
091: *
092: * @see org.columba.chat.ui.roaster.IRoasterTree#getSelected()
093: */
094: public IBuddyStatus getSelected() {
095: TreePath path = getSelectionPath();
096: if (path == null)
097: return null;
098: DefaultMutableTreeNode node = (DefaultMutableTreeNode) path
099: .getLastPathComponent();
100:
101: if (node != null) {
102: IBuddyStatus b = (IBuddyStatus) node.getUserObject();
103:
104: return b;
105: }
106:
107: return null;
108: }
109:
110: /*
111: * (non-Javadoc)
112: *
113: * @see org.columba.chat.ui.roaster.IRoasterTree#updateBuddyPresence(org.columba.chat.api.IBuddyStatus)
114: */
115: public void updateBuddyPresence(IBuddyStatus buddy) {
116: DefaultMutableTreeNode node = findBuddy(root, buddy);
117: if (node != null) {
118:
119: model.nodeChanged(node);
120:
121: }
122:
123: updateUI();
124: }
125:
126: private DefaultMutableTreeNode findBuddy(
127: DefaultMutableTreeNode parent, IBuddyStatus buddy) {
128: for (int i = 0; i < parent.getChildCount(); i++) {
129: DefaultMutableTreeNode child = (DefaultMutableTreeNode) parent
130: .getChildAt(i);
131:
132: Object o = child.getUserObject();
133:
134: if (o instanceof BuddyStatus) {
135: if (buddy.getJabberId().equals(
136: ((IBuddyStatus) o).getJabberId()))
137: return child;
138: }
139: }
140:
141: return null;
142: }
143:
144: public void populate(DefaultMutableTreeNode rootNode) {
145: this .root = rootNode;
146:
147: model.setRoot(root);
148:
149: model.nodeStructureChanged(root);
150:
151: }
152:
153: class SubscriptionListener implements PacketListener {
154:
155: public SubscriptionListener() {
156: super ();
157: }
158:
159: /**
160: * @see org.jivesoftware.smack.PacketListener#processPacket(org.jivesoftware.smack.packet.Packet)
161: */
162:
163: public void processPacket(Packet p) {
164: Presence presence = (Presence) p;
165:
166: // we are only interested on subscription requests
167: if (presence.getType().equals(Presence.Type.SUBSCRIBE)) {
168: // ask the user
169: String from = presence.getFrom();
170:
171: // example: fdietz@jabber.org/Jabber-client
172: // -> remove "/Jabber-client"
173: String normalizedFrom = from.replaceAll("\\/.*", "");
174:
175: int option = JOptionPane
176: .showConfirmDialog(
177: FrameManager.getInstance()
178: .getActiveFrame(),
179: "The user "
180: + from
181: + " requests presence notification.\nDo you wish to allow them to see your "
182: + "online presence?",
183: "Subscription Request",
184: JOptionPane.YES_NO_OPTION);
185:
186: if (option == JOptionPane.YES_OPTION) {
187:
188: CommandProcessor.getInstance().addOp(
189: new SubscriptionCommand(mediator,
190: new ChatCommandReference(
191: normalizedFrom)));
192:
193: } else {
194: return;
195: }
196:
197: option = JOptionPane.showConfirmDialog(null,
198: "Do you wish to add " + from
199: + " to your roaster?", "Add user",
200: JOptionPane.YES_NO_OPTION);
201:
202: if (option == JOptionPane.YES_OPTION) {
203: CommandProcessor.getInstance().addOp(
204: new AddContactCommand(mediator,
205: new ChatCommandReference(
206: normalizedFrom)));
207: }
208: }
209:
210: }
211:
212: }
213:
214: class PresenceListener implements PacketListener {
215:
216: public PresenceListener() {
217: super ();
218:
219: }
220:
221: /**
222: * @see org.jivesoftware.smack.PacketListener#processPacket(org.jivesoftware.smack.packet.Packet)
223: */
224: public void processPacket(Packet packet) {
225: Presence presence = (Presence) packet;
226:
227: String from = presence.getFrom();
228:
229: if ((presence.getType() != Presence.Type.AVAILABLE)
230: && (presence.getType() != Presence.Type.UNAVAILABLE))
231: return;
232:
233: LOG.info("From=" + from);
234: LOG.info("Presence Mode=" + presence.getMode());
235:
236: // example: fdietz@jabber.org/Jabber-client
237: // -> remove "/Jabber-client"
238: String normalizedFrom = from.replaceAll("\\/.*", "");
239:
240: final IBuddyStatus status = BuddyList.getInstance()
241: .getBuddy(normalizedFrom);
242: // just ignore unknown people
243: if (status == null)
244: return;
245:
246: status.setPresenceMode(presence.getMode());
247: if (presence.getType() == Presence.Type.AVAILABLE) {
248: status.setSignedOn(true);
249:
250: } else if (presence.getType() == Presence.Type.UNAVAILABLE) {
251: status.setSignedOn(false);
252:
253: }
254:
255: Runnable updateAComponent = new Runnable() {
256:
257: public void run() {
258: updateBuddyPresence(status);
259: }
260: };
261:
262: try {
263: SwingUtilities.invokeAndWait(updateAComponent);
264: } catch (InterruptedException e) {
265: // TODO Auto-generated catch block
266: e.printStackTrace();
267: } catch (InvocationTargetException e) {
268: // TODO Auto-generated catch block
269: e.printStackTrace();
270: }
271:
272: }
273: }
274:
275: /**
276: * @see org.columba.chat.conn.api.IConnectionChangedListener#connectionChanged(org.columba.chat.conn.api.ConnectionChangedEvent)
277: */
278: public void connectionChanged(ConnectionChangedEvent object) {
279: //IAccount account = object.getAccount();
280: STATUS status = object.getStatus();
281:
282: if (status == STATUS.ONLINE) {
283: setEnabled(true);
284:
285: Connection.XMPPConnection.addPacketListener(
286: subscriptionListener, new PacketTypeFilter(
287: Presence.class));
288:
289: Connection.XMPPConnection.addPacketListener(
290: presenceListener, new PacketTypeFilter(
291: Presence.class));
292:
293: } else if (status == STATUS.OFFLINE) {
294: setEnabled(false);
295:
296: Connection.XMPPConnection
297: .removePacketListener(subscriptionListener);
298:
299: Connection.XMPPConnection
300: .removePacketListener(presenceListener);
301:
302: }
303: }
304:
305: }
|