extend core listener
[jSite2.git] / src / net / pterodactylus / jsite / gui / ManageNodesDialog.java
1 /*
2  * jSite2 - ManageNodeDialog.java -
3  * Copyright © 2008 David Roden
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
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 net.pterodactylus.jsite.gui;
21
22 import java.awt.BorderLayout;
23 import java.awt.FlowLayout;
24 import java.awt.event.ActionEvent;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Iterator;
28 import java.util.List;
29
30 import javax.swing.AbstractListModel;
31 import javax.swing.BorderFactory;
32 import javax.swing.JButton;
33 import javax.swing.JDialog;
34 import javax.swing.JList;
35 import javax.swing.JOptionPane;
36 import javax.swing.JPanel;
37 import javax.swing.JScrollPane;
38 import javax.swing.border.EtchedBorder;
39 import javax.swing.event.ListSelectionEvent;
40 import javax.swing.event.ListSelectionListener;
41
42 import net.pterodactylus.jsite.core.Core;
43 import net.pterodactylus.jsite.core.Node;
44 import net.pterodactylus.jsite.i18n.I18n;
45 import net.pterodactylus.jsite.i18n.I18nable;
46 import net.pterodactylus.jsite.i18n.gui.I18nAction;
47 import net.pterodactylus.jsite.main.Version;
48 import net.pterodactylus.util.swing.SwingUtils;
49
50 /**
51  * Dialog that lets the user manage her nodes.
52  *
53  * @author David ‘Bombe’ Roden <bombe@freenetproject.org>
54  * @version $Id$
55  */
56 public class ManageNodesDialog extends JDialog implements ListSelectionListener, I18nable {
57
58         /** The core. */
59         private final Core core;
60
61         /** The original list of nodes. */
62         private List<Node> originalNodeList;
63
64         /** The “add node” action. */
65         private I18nAction addNodeAction;
66
67         /** The “edit node” action. */
68         private I18nAction editNodeAction;
69
70         /** The “delete node” action. */
71         private I18nAction deleteNodeAction;
72
73         /** The “okay” action. */
74         private I18nAction okayAction;
75
76         /** The “cancel” action. */
77         private I18nAction cancelAction;
78
79         /** The “edit node” dialog. */
80         private EditNodeDialog editNodeDialog;
81
82         /** The node list. */
83         private JList nodeList;
84
85         /** The mode for the node list. */
86         private NodeListModel nodeListModel = new NodeListModel();
87
88         /**
89          * Creates a new node manager dialog.
90          *
91          * @param swingInterface
92          *            The Swing interface
93          */
94         public ManageNodesDialog(SwingInterface swingInterface) {
95                 super(swingInterface.getMainWindow(), I18n.get("manageNodesDialog.title") + " – jSite " + Version.getVersion(), true);
96                 this.core = swingInterface.getCore();
97                 initActions();
98                 initComponents();
99                 initDialogs();
100                 pack();
101                 I18n.registerI18nable(this);
102                 SwingUtils.center(this);
103         }
104
105         //
106         // ACCESSORS
107         //
108
109         /**
110          * Expose the edit node dialog for the simple mode.
111          *
112          * @return The edit node dialog
113          */
114         EditNodeDialog getEditNodeDialog() {
115                 return editNodeDialog;
116         }
117
118         /**
119          * Returns the list of nodes.
120          *
121          * @return The list of nodes
122          */
123         public List<Node> getNodeList() {
124                 return originalNodeList;
125         }
126
127         /**
128          * Sets the list of nodes.
129          *
130          * @param nodeList
131          *            The list of nodes
132          */
133         public void setNodeList(List<Node> nodeList) {
134                 originalNodeList = new ArrayList<Node>(nodeList);
135                 nodeListModel.clear();
136                 for (Node node: nodeList) {
137                         nodeListModel.addNode(node);
138                 }
139         }
140
141         //
142         // PRIVATE METHODS
143         //
144
145         /**
146          * Initializes all actions.
147          */
148         private void initActions() {
149                 okayAction = new I18nAction("general.button.okay") {
150
151                         /**
152                          * {@inheritDoc}
153                          */
154                         @SuppressWarnings("synthetic-access")
155                         public void actionPerformed(ActionEvent e) {
156                                 confirm();
157                         }
158                 };
159                 cancelAction = new I18nAction("general.button.cancel") {
160
161                         /**
162                          * {@inheritDoc}
163                          */
164                         @SuppressWarnings("synthetic-access")
165                         public void actionPerformed(ActionEvent e) {
166                                 cancel();
167                         }
168                 };
169                 addNodeAction = new I18nAction("manageNodesDialog.button.addNode") {
170
171                         /**
172                          * {@inheritDoc}
173                          */
174                         @SuppressWarnings("synthetic-access")
175                         public void actionPerformed(ActionEvent e) {
176                                 addNode();
177                         }
178                 };
179                 editNodeAction = new I18nAction("manageNodesDialog.button.editNode", false) {
180
181                         /**
182                          * {@inheritDoc}
183                          */
184                         @SuppressWarnings("synthetic-access")
185                         public void actionPerformed(ActionEvent e) {
186                                 editNode();
187                         }
188                 };
189                 deleteNodeAction = new I18nAction("manageNodesDialog.button.deleteNode", false) {
190
191                         /**
192                          * {@inheritDoc}
193                          */
194                         @SuppressWarnings("synthetic-access")
195                         public void actionPerformed(ActionEvent e) {
196                                 deleteNodes();
197                         }
198                 };
199         }
200
201         /**
202          * Initializes all components.
203          */
204         private void initComponents() {
205                 JPanel rootPanel = new JPanel(new BorderLayout(12, 12));
206                 rootPanel.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
207
208                 JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING, 12, 12));
209                 rootPanel.add(buttonPanel, BorderLayout.PAGE_END);
210                 buttonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
211
212                 buttonPanel.add(new JButton(cancelAction));
213                 JButton okayButton = new JButton(okayAction);
214                 getRootPane().setDefaultButton(okayButton);
215                 buttonPanel.add(okayButton);
216
217                 JPanel contentPanel = new JPanel(new BorderLayout(12, 12));
218                 rootPanel.add(contentPanel, BorderLayout.CENTER);
219                 contentPanel.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), BorderFactory.createEmptyBorder(12, 12, 12, 12)));
220
221                 JPanel listButtonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 12, 12));
222                 contentPanel.add(listButtonPanel, BorderLayout.PAGE_END);
223                 listButtonPanel.setBorder(BorderFactory.createEmptyBorder(-12, -12, -12, -12));
224                 listButtonPanel.add(new JButton(addNodeAction));
225                 listButtonPanel.add(new JButton(editNodeAction));
226                 listButtonPanel.add(new JButton(deleteNodeAction));
227
228                 nodeList = new JList(nodeListModel);
229                 nodeList.addListSelectionListener(this);
230                 contentPanel.add(new JScrollPane(nodeList), BorderLayout.CENTER);
231
232                 setContentPane(rootPanel);
233         }
234
235         /**
236          * Initializes all child dialogs.
237          */
238         private void initDialogs() {
239                 editNodeDialog = new EditNodeDialog(this);
240         }
241
242         //
243         // PRIVATE ACTIONS
244         //
245
246         /**
247          * Adds a new node via {@link #editNodeDialog}.
248          */
249         private void addNode() {
250                 editNodeDialog.setNodeName(I18n.get("general.newNode.name"));
251                 editNodeDialog.setNodeHostname("localhost");
252                 editNodeDialog.setNodePort(9481);
253                 editNodeDialog.setVisible(true);
254                 if (!editNodeDialog.wasCancelled()) {
255                         Node newNode = new Node();
256                         newNode.setName(editNodeDialog.getNodeName());
257                         newNode.setHostname(editNodeDialog.getNodeHostname());
258                         newNode.setPort(editNodeDialog.getNodePort());
259                         nodeListModel.addNode(newNode);
260                 }
261         }
262
263         /**
264          * Edits a node via {@link #editNodeDialog}.
265          */
266         private void editNode() {
267                 Node selectedNode = (Node) nodeList.getSelectedValue();
268                 editNodeDialog.setNodeName(selectedNode.getName());
269                 editNodeDialog.setNodeHostname(selectedNode.getHostname());
270                 editNodeDialog.setNodePort(selectedNode.getPort());
271                 editNodeDialog.setVisible(true);
272                 if (!editNodeDialog.wasCancelled()) {
273                         selectedNode.setName(editNodeDialog.getNodeName());
274                         selectedNode.setHostname(editNodeDialog.getNodeHostname());
275                         selectedNode.setPort(editNodeDialog.getNodePort());
276                         nodeList.repaint();
277                 }
278         }
279
280         /**
281          * Deletes the selected node.
282          */
283         private void deleteNodes() {
284                 Object[] selectedNodes = nodeList.getSelectedValues();
285                 for (Object node: selectedNodes) {
286                         Node selectedNode = (Node) node;
287                         if (core.isNodeConnected(selectedNode)) {
288                                 int response = JOptionPane.showConfirmDialog(this, I18n.get("manageNodesDialog.error.nodeConnected.message", selectedNode.getName()), I18n.get("manageNodesDialog.error.nodeConnected.title"), JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
289                                 if (response == JOptionPane.CANCEL_OPTION) {
290                                         break;
291                                 } else if (response == JOptionPane.NO_OPTION) {
292                                         continue;
293                                 }
294                         }
295                         nodeListModel.removeNode(selectedNode);
296                 }
297                 nodeList.clearSelection();
298         }
299
300         /**
301          * Checks whether the list of nodes is not empty.
302          *
303          * @return <code>true</code> if there is at least one node defined,
304          *         <code>false</code> otherwise
305          */
306         private boolean verifyNodesExist() {
307                 return nodeListModel.getSize() > 0;
308         }
309
310         /**
311          * This method is called when the “okay” button is pressed. The nodes from
312          * the list are read and the {@link #originalNodeList} member is set so that
313          * the calling code can use {@link #getNodeList()} to get the changed
314          * values.
315          */
316         private void confirm() {
317                 if (!verifyNodesExist()) {
318                         JOptionPane.showMessageDialog(this, I18n.get("manageNodesDialog.error.nodeListEmpty.message"), I18n.get("manageNodesDialog.error.nodeListEmpty.title"), JOptionPane.ERROR_MESSAGE);
319                         return;
320                 }
321                 originalNodeList.clear();
322                 for (Node node: nodeListModel) {
323                         originalNodeList.add(node);
324                 }
325                 setVisible(false);
326         }
327
328         /**
329          * Cancels the dialog.
330          */
331         private void cancel() {
332                 setVisible(false);
333         }
334
335         //
336         // INTERFACE ListSelectionListener
337         //
338
339         /**
340          * {@inheritDoc}
341          */
342         public void valueChanged(ListSelectionEvent listSelectionEvent) {
343                 JList list = (JList) listSelectionEvent.getSource();
344                 int selectCount = list.getSelectedIndices().length;
345                 editNodeAction.setEnabled(selectCount == 1);
346                 deleteNodeAction.setEnabled(selectCount >= 1);
347         }
348
349         //
350         // INTERFACE I18nable
351         //
352
353         /**
354          * {@inheritDoc}
355          */
356         public void updateI18n() {
357                 okayAction.updateI18n();
358                 cancelAction.updateI18n();
359                 addNodeAction.updateI18n();
360                 editNodeAction.updateI18n();
361                 deleteNodeAction.updateI18n();
362                 setTitle(I18n.get("manageNodesDialog.title") + " – jSite " + Version.getVersion());
363                 SwingUtils.repackCentered(this);
364         }
365
366         /**
367          * List model for the {@link ManageNodesDialog#nodeList}. TODO
368          *
369          * @author David ‘Bombe’ Roden &lt;bombe@freenetproject.org&gt;
370          * @version $Id$
371          */
372         private class NodeListModel extends AbstractListModel implements Iterable<Node> {
373
374                 /** The list of nodes. */
375                 @SuppressWarnings("hiding")
376                 private final List<Node> nodeList = new ArrayList<Node>();
377
378                 /**
379                  * Creates a new node list model.
380                  */
381                 public NodeListModel() {
382                         /* do nothing. */
383                 }
384
385                 /**
386                  * Adds the given node to the list model.
387                  *
388                  * @see Collection#add(Object)
389                  * @param node
390                  *            The node to add
391                  */
392                 public void addNode(Node node) {
393                         nodeList.add(node);
394                         fireIntervalAdded(this, nodeList.size() - 1, nodeList.size() - 1);
395                 }
396
397                 /**
398                  * Removes the given node from the list model.
399                  *
400                  * @see Collection#remove(Object)
401                  * @param node
402                  *            The node to remove
403                  */
404                 public void removeNode(Node node) {
405                         int nodeIndex = nodeList.indexOf(node);
406                         nodeList.remove(node);
407                         fireIntervalRemoved(this, nodeIndex, nodeIndex);
408                 }
409
410                 /**
411                  * Removes all nodes from the list model.
412                  *
413                  * @see Collection#clear()
414                  */
415                 public void clear() {
416                         int nodeCount = nodeList.size();
417                         if (nodeCount > 0) {
418                                 nodeList.clear();
419                                 fireIntervalRemoved(this, 0, nodeCount - 1);
420                         }
421                 }
422
423                 /**
424                  * {@inheritDoc}
425                  */
426                 public Iterator<Node> iterator() {
427                         return nodeList.iterator();
428                 }
429
430                 /**
431                  * {@inheritDoc}
432                  */
433                 @SuppressWarnings("synthetic-access")
434                 public Object getElementAt(int index) {
435                         return nodeList.get(index);
436                 }
437
438                 /**
439                  * {@inheritDoc}
440                  */
441                 public int getSize() {
442                         return nodeList.size();
443                 }
444
445         }
446
447 }