View Javadoc

1   /*
2    *  XNap - A P2P framework and client.
3    *
4    *  See the file AUTHORS for copyright information.
5    *
6    *  This program is free software; you can redistribute it and/or modify
7    *  it under the terms of the GNU General Public License as published by
8    *  the Free Software Foundation.
9    *
10   *  This program is distributed in the hope that it will be useful,
11   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   *  GNU General Public License for more details.
14   *
15   *  You should have received a copy of the GNU General Public License
16   *  along with this program; if not, write to the Free Software
17   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  
20  package org.xnap.plugin.opennap.gui;
21  
22  import javax.swing.AbstractAction;
23  import javax.swing.AbstractButton;
24  import javax.swing.Action;
25  import javax.swing.JCheckBox;
26  import javax.swing.JFileChooser;
27  import javax.swing.JLabel;
28  import javax.swing.JOptionPane;
29  import javax.swing.JPanel;
30  import javax.swing.JPopupMenu;
31  import javax.swing.JScrollPane;
32  import javax.swing.KeyStroke;
33  import javax.swing.SwingUtilities;
34  import javax.swing.event.TreeSelectionEvent;
35  import javax.swing.event.TreeSelectionListener;
36  import javax.swing.tree.TreePath;
37  
38  import java.awt.BorderLayout;
39  import java.awt.FlowLayout;
40  import java.awt.event.ActionEvent;
41  import java.awt.event.KeyEvent;
42  import java.awt.event.MouseListener;
43  import java.io.File;
44  import java.text.SimpleDateFormat;
45  import java.util.Date;
46  import java.util.LinkedList;
47  
48  import org.xnap.XNap;
49  import org.xnap.event.StatusListener;
50  import org.xnap.gui.ActionProvider;
51  import org.xnap.gui.StatusBar;
52  import org.xnap.gui.action.CollapseAllNodesAction;
53  import org.xnap.gui.action.ExpandAllNodesAction;
54  import org.xnap.gui.component.XNapButton;
55  import org.xnap.gui.component.XNapCheckBox;
56  import org.xnap.gui.component.XNapMenuItem;
57  import org.xnap.gui.event.DoubleClickListener;
58  import org.xnap.gui.event.PopupListener;
59  import org.xnap.gui.table.JTreeTable;
60  import org.xnap.gui.table.LeafTreeTableNode;
61  import org.xnap.gui.table.TreeTableNode;
62  import org.xnap.gui.tree.NetworkTreeCellRenderer;
63  import org.xnap.gui.util.FocusManager;
64  import org.xnap.gui.util.GUIHelper;
65  import org.xnap.gui.util.IconHelper;
66  import org.xnap.io.FileExtensionFilter;
67  import org.xnap.plugin.opennap.OpenNapPlugin;
68  import org.xnap.plugin.opennap.action.OpenNapGetServerListAction;
69  import org.xnap.plugin.opennap.net.OpenNapBrowse;
70  import org.xnap.plugin.opennap.net.OpenNapServer;
71  import org.xnap.plugin.opennap.util.OpenNapPreferences;
72  import org.xnap.search.DefaultSearchFilter;
73  import org.xnap.search.Search;
74  import org.xnap.search.SearchFilter;
75  import org.xnap.search.SearchManager;
76  import org.xnap.util.FileHelper;
77  import org.xnap.util.IllegalOperationException;
78  
79  /***
80   * This class provides a {@link JTreeTable} that contains a list of
81   * {@link OpenNapServer} objects that are grouped by network.
82   */
83  public class OpenNapServerPanel extends JPanel 
84      implements ActionProvider, TreeSelectionListener, StatusListener {
85  
86      // --- Data Field(s) ---
87  
88      private OpenNapPreferences napPrefs = OpenNapPlugin.getPreferences();
89  
90      private JTreeTable jttServers;
91      private OpenNapServerTableModel tmServers;
92      private JLabel jlStatus;
93  
94  	private JFileChooser jfcDefault = new JFileChooser();
95  
96      private Action acConnect = new ConnectAction();
97      private Action acDisconnect = new DisconnectAction();
98      private Action acAddServer = new AddServerAction();
99      private Action acEditServer = new EditServerAction();
100     private Action acRemoveServer = new RemoveServerAction();
101     private Action acOpenServerFile = new OpenServerFileAction(jfcDefault);
102     private Action acSaveServerFile = new SaveServerFileAction(jfcDefault);
103     private Action acUseAutoConnector = new UseAutoConnectorAction();
104 	private Action acCollapseAllNodes;
105 	private Action acExpandAllNodes;
106 	private Action browseAction = new BrowseAction();
107 	private Action chatAction = new ChatAction();
108 
109     // --- Constructor(s) ---
110 
111     public OpenNapServerPanel() 
112     {
113 		initialize();
114     }
115 
116     // --- Method(s) ---
117 
118     private void initialize()
119     {
120         setLayout(new BorderLayout());
121 
122         // server table
123         tmServers = new OpenNapServerTableModel();
124 		jttServers = tmServers.createTreeTable(napPrefs, "server");
125 		jttServers.getTree().getSelectionModel().addTreeSelectionListener(this);
126 		jttServers.getTree().setCellRenderer
127 			(new NetworkTreeCellRenderer(tmServers));
128 		DoubleClickListener.install(jttServers, acConnect);
129 		GUIHelper.bindEnterKey(jttServers, acConnect);
130 
131 		acCollapseAllNodes = new CollapseAllNodesAction(jttServers.getTree());
132 		acExpandAllNodes = new ExpandAllNodesAction(jttServers.getTree());
133 
134         // popup-context menu
135         JPopupMenu popup = new JPopupMenu();
136         popup.add(new XNapMenuItem(acConnect));
137         popup.add(new XNapMenuItem(acDisconnect));
138         popup.addSeparator();
139 		popup.add(new XNapMenuItem(browseAction));
140 		popup.add(new XNapMenuItem(chatAction));
141         popup.addSeparator();
142         popup.add(new XNapMenuItem(acAddServer));
143         popup.addSeparator();
144 		popup.add(new XNapMenuItem(acEditServer));
145         popup.add(new XNapMenuItem(acRemoveServer));
146 
147 		MouseListener popupListener = new PopupListener(popup);
148 		jttServers.addMouseListener(popupListener);
149 
150 		jttServers.getInputMap().put(KeyStroke.getKeyStroke
151 									 (KeyEvent.VK_ENTER, 0), acConnect);
152 		jttServers.getActionMap().put(acConnect, acConnect);
153 
154 
155         // button panel
156         JPanel jpButtons = new JPanel();
157         jpButtons.setLayout(new FlowLayout(FlowLayout.LEFT));
158 
159         jpButtons.add(new XNapButton(new OpenNapGetServerListAction()));
160         jpButtons.add(new XNapButton(new FindWSXFiles()));
161 
162         JCheckBox jcbAutoConnect = new JCheckBox(acUseAutoConnector);
163         jcbAutoConnect.setSelected(napPrefs.getUseAutoconnector());
164         jpButtons.add(jcbAutoConnect);
165 
166 		JCheckBox jcbRemoveServers 
167 			= new XNapCheckBox(new RemoveFailedServersAction());
168 		jpButtons.add(jcbRemoveServers);
169 
170 		// status line
171 		jlStatus = new JLabel(OpenNapPlugin.getServerManager().getStats());
172 	
173         // add containers to panel
174 		add(jlStatus, BorderLayout.NORTH);
175         add(new JScrollPane(jttServers), BorderLayout.CENTER);
176         add(jpButtons, BorderLayout.SOUTH);
177 
178 		// stats updates
179 		//  	Connector.getInstance().addStatsListener(new StatsListener());
180 		//  	Connector.getInstance().setStatusListener(this);
181 
182 		// file chooser for open and save
183 		jfcDefault.setSelectedFile
184 			(new File(FileHelper.getHomeDir() + "hosts"));
185 		jfcDefault.addChoosableFileFilter(new FileExtensionFilter("wsx"));
186 		jfcDefault.addChoosableFileFilter
187 			(new FileExtensionFilter("hosts", XNap.tr("XNap Server")));
188 
189 		valueChanged();
190     }
191 
192     public Action[] getActions()
193     {
194 		return new Action[] {
195 			acOpenServerFile, acSaveServerFile, null, acConnect, acDisconnect, 
196 			null, acAddServer, null, acEditServer, acRemoveServer, null,
197 			acCollapseAllNodes, acExpandAllNodes
198 		};
199     }
200 
201     /***
202      * Returns the currently selected servers. 
203      *
204      * @return null, if nothing is selected
205      */
206     public OpenNapServer[] getSelectedServers()
207     {
208 		TreePath[] paths = jttServers.getTree().getSelectionPaths();
209 		if (paths != null) {
210 			LinkedList results = new LinkedList();
211 			for (int i = 0; i < paths.length; i++) {
212 				TreeTableNode node 
213 					= (TreeTableNode)paths[i].getLastPathComponent();
214 				if (node instanceof LeafTreeTableNode) {
215 					results.add((OpenNapServer)node.getData());
216 				}
217 			}
218 			return (results.size() > 0) 
219 				? (OpenNapServer[])results.toArray(new OpenNapServer[0]) : null;
220 		}
221 		return null;
222     }
223 
224     public void setStatus(final String newValue)
225     {
226 		Runnable runner = new Runnable()
227 			{
228 				public void run() 
229 				{
230 					jlStatus.setText(newValue);
231 				}
232 			};
233 		SwingUtilities.invokeLater(runner);
234     }
235 
236     public void valueChanged(TreeSelectionEvent e) 
237     {
238 		valueChanged();
239     }
240 
241     public void valueChanged()
242 	{
243 		boolean selected = (getSelectedServers() != null);
244 		acConnect.setEnabled(selected);
245 		acDisconnect.setEnabled(selected);
246 		acEditServer.setEnabled(selected);
247 		acRemoveServer.setEnabled(selected);
248 		browseAction.setEnabled(selected);
249 		chatAction.setEnabled(selected);
250 	}
251 
252     //--- Inner Class(es) ---
253     
254     /***
255      * AddServerAction class handles the command to add a user defined
256      * server to the list.
257      */
258     private class AddServerAction extends AbstractAction {
259 
260         public AddServerAction() 
261 		{
262             putValue(Action.NAME, XNap.tr("Add Server") + "...");
263             putValue(Action.SHORT_DESCRIPTION, 
264 					 XNap.tr("Add a server to the list."));
265 			putValue(IconHelper.XNAP_ICON, "filenew.png");
266         }
267 
268         public void actionPerformed( ActionEvent event ) 
269 		{
270 			OpenNapServerEditorDialog d = new OpenNapServerEditorDialog();
271 			d.setNetworks(tmServers.getNetworkNames());
272 			d.show(OpenNapServerPanel.this);
273         }
274 
275     }
276 
277     private class BrowseAction extends AbstractAction {
278 
279         public BrowseAction() 
280 		{
281             putValue(Action.NAME, XNap.tr("Browse User") + "...");
282             putValue(Action.SHORT_DESCRIPTION, 
283 					 XNap.tr("Prompts for a nick."));
284 			putValue(IconHelper.XNAP_ICON, "filefind.png");
285         }
286 
287         public void actionPerformed( ActionEvent event ) 
288 		{
289 			OpenNapServer[] servers = getSelectedServers();
290 			if (servers != null) {
291 				for (int i = 0; i < servers.length; i++) {
292 					String nick = JOptionPane.showInputDialog
293 						(OpenNapServerPanel.this, XNap.tr("Nick"),
294 						 XNap.tr("Browse User"), JOptionPane.QUESTION_MESSAGE);
295 					
296 					if (nick != null) {
297 						OpenNapBrowse b 
298 							= new OpenNapBrowse(servers[i].getUser(nick));
299 						SearchManager.getInstance().handle(b);
300 						FocusManager.setFocusTo("search");
301 					}
302 				}
303 			}
304         }
305 
306     }
307 
308     private class ChatAction extends AbstractAction {
309 
310         public ChatAction() 
311 		{
312             putValue(Action.NAME, XNap.tr("Chat With User") + "...");
313             putValue(Action.SHORT_DESCRIPTION, 
314 					 XNap.tr("Prompts for a nick."));
315 			putValue(IconHelper.XNAP_ICON, "mail_generic.png");
316         }
317 
318         public void actionPerformed( ActionEvent event ) 
319 		{
320 			OpenNapServer[] servers = getSelectedServers();
321 			if (servers != null) {
322 				for (int i = 0; i < servers.length; i++) {
323 					String nick = JOptionPane.showInputDialog
324 						(OpenNapServerPanel.this, XNap.tr("Nick"),
325 						 XNap.tr("Chat With User"), 
326 						 JOptionPane.QUESTION_MESSAGE);
327 					
328 					if (nick != null) {
329 						OpenNapPlugin.getMessageHandler().getPrivateChannel
330 							(servers[i].getUser(nick));
331 						FocusManager.setFocusTo("chat");
332 					}
333 				}
334 			}
335         }
336 
337     }
338 
339     /***
340      * This class connects the selected servers.
341      */
342     private class ConnectAction extends AbstractAction {
343 
344         public ConnectAction() 
345 		{
346             putValue(Action.NAME, XNap.tr("Connect"));
347             putValue(Action.SHORT_DESCRIPTION,
348 					 XNap.tr("Connects to the selected servers."));
349 			putValue(IconHelper.XNAP_ICON, "connect_creating.png");
350         }
351 
352         public void actionPerformed(ActionEvent event) 
353 		{
354 			OpenNapServer[] servers = getSelectedServers();
355 			if (servers != null) {
356 				for (int i = 0; i < servers.length; i++) {
357 					try {
358 						servers[i].connect();
359 					}
360 					catch (IllegalOperationException e) {
361 						StatusBar.setText(e.getLocalizedMessage());
362 					}
363 				}
364 			}
365         }
366 
367     }
368 
369     /***
370      * This class provides an action that disconnects the selected servers.
371      */
372     private class DisconnectAction extends AbstractAction {
373 
374         public DisconnectAction() 
375 		{
376             putValue(Action.NAME, XNap.tr("Disconnect"));
377             putValue(Action.SHORT_DESCRIPTION,
378 					 XNap.tr("Disconnect from the selected servers."));
379 			putValue(IconHelper.XNAP_ICON, "connect_no.png");
380         }
381 
382         public void actionPerformed( ActionEvent event ) 
383 		{
384 			OpenNapServer[] servers = getSelectedServers();
385 			if (servers != null) {
386 				for (int i = 0; i < servers.length; i++) {
387 					try {
388 						servers[i].disconnect();
389 					}
390 					catch (IllegalOperationException e) {
391 						StatusBar.setText(e.getLocalizedMessage());
392 					}
393 				}
394 			}
395 		}
396     }
397 
398     /***
399      * This class provides an action that opens a 
400      * {@link OpenNapServerEditorDialog} for each selected server.
401      */
402     private class EditServerAction extends AbstractAction {
403 
404         public EditServerAction() 
405 		{
406             putValue(Action.NAME, XNap.tr("Edit Server") + "...");
407             putValue(Action.SHORT_DESCRIPTION, 
408 					 XNap.tr("Opens a dialog with the server properties."));
409 			putValue(IconHelper.XNAP_ICON, "edit.png");
410         }
411 
412         public void actionPerformed( ActionEvent event )
413 		{
414 			OpenNapServer[] servers = getSelectedServers();
415 			if (servers != null) {
416 				for (int i = 0; i < servers.length; i++) {
417 					OpenNapServerEditorDialog d 
418 						= new OpenNapServerEditorDialog(servers[i]);
419 					d.setNetworks(tmServers.getNetworkNames());
420 					d.show(OpenNapServerPanel.this);
421 				}
422 			}
423 			else {
424 				StatusBar.setText(XNap.tr("Please select a server."));
425 			}
426         }
427 
428     }
429 	
430     /***
431      * RemoveServerAction class handles the command to remove the selected
432      * server(s) from the list.  For each selected server it calls
433      * tmServers.removeServer(server).
434      */
435     private class RemoveServerAction extends AbstractAction {
436 
437         public RemoveServerAction() 
438 		{
439             putValue(Action.NAME, XNap.tr("Remove Server"));
440             putValue(Action.SHORT_DESCRIPTION,
441 					 XNap.tr("Remove the selected servers from the list"));
442 			putValue(IconHelper.XNAP_ICON, "eraser.png");
443         }
444 
445         public void actionPerformed( ActionEvent event ) 
446 		{
447 			OpenNapServer[] servers = getSelectedServers();
448 			if (servers != null) {
449 				for (int i = 0; i < servers.length; i++) {
450 					OpenNapPlugin.getServerManager().remove(servers[i]);
451 				}
452 			}
453 			else {
454 				StatusBar.setText(XNap.tr("Please select a server."));
455 			}
456         }
457 
458     } 
459 
460     /***
461      * 
462      */
463     private class UseAutoConnectorAction extends AbstractAction {
464 
465         public UseAutoConnectorAction() 
466 		{
467             putValue(Action.NAME, XNap.tr("Connect automatically"));
468             putValue(Action.SHORT_DESCRIPTION,
469 					 XNap.tr("Automatically connect to servers"));
470         }
471 
472         public void actionPerformed(ActionEvent event) 
473 		{
474 			AbstractButton ab = (AbstractButton)event.getSource();
475 			OpenNapPlugin.getServerManager().getConnector().setEnabled
476 				(ab.isSelected());
477         }
478 
479     }
480 
481 
482     /***
483      * 
484      */
485     private class FindWSXFiles extends AbstractAction {
486 
487         public FindWSXFiles() 
488 		{
489             putValue(Action.NAME, XNap.tr("Find WSX Files"));
490 			putValue(IconHelper.XNAP_ICON, "editfind.png");
491             putValue(Action.SHORT_DESCRIPTION,
492 					 XNap.tr("Find servers file."));
493         }
494 
495         public void actionPerformed(ActionEvent event) 
496 		{
497 			SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
498 
499 			DefaultSearchFilter filter = new DefaultSearchFilter();
500 			filter.put(SearchFilter.TEXT, "PUBLIC " + df.format(new Date()));
501 			filter.put("nap.minBitrate", new Long(24));
502 			filter.put("nap.maxBitrate", new Long(24));
503 			filter.put("nap.minFrequency", new Long(16000));
504 			filter.put("nap.maxFrequency", new Long(16000));
505 
506 			Search search = OpenNapPlugin.getSearchManager().search(filter);
507 			SearchManager.getInstance().handle(search);
508 
509 			FocusManager.setFocusTo("search", event);
510         }
511 
512     }
513 
514 }