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