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