001/* 002 * Copyright 2010-2015 Institut Pasteur. 003 * 004 * This file is part of Icy. 005 * 006 * Icy is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * Icy is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with Icy. If not, see <http://www.gnu.org/licenses/>. 018 */ 019package icy.gui.preferences; 020 021import java.awt.BorderLayout; 022import java.awt.Dimension; 023import java.awt.Point; 024import java.awt.event.ActionEvent; 025import java.awt.event.ActionListener; 026import java.util.ArrayList; 027import java.util.List; 028 029import javax.swing.BorderFactory; 030import javax.swing.Box; 031import javax.swing.BoxLayout; 032import javax.swing.JButton; 033import javax.swing.JPanel; 034import javax.swing.JScrollPane; 035import javax.swing.JSeparator; 036import javax.swing.JSplitPane; 037import javax.swing.JTree; 038import javax.swing.event.TreeSelectionEvent; 039import javax.swing.event.TreeSelectionListener; 040import javax.swing.tree.DefaultMutableTreeNode; 041import javax.swing.tree.TreeSelectionModel; 042 043import icy.gui.dialog.ConfirmDialog; 044import icy.gui.frame.IcyFrame; 045import icy.gui.util.ComponentUtil; 046import icy.gui.util.WindowPositionSaver; 047import icy.main.Icy; 048import icy.preferences.IcyPreferences; 049import icy.util.StringUtil; 050 051/** 052 * @author fab & stephane 053 */ 054public class PreferenceFrame extends IcyFrame implements TreeSelectionListener 055{ 056 public static final String NODE_NAME = "Preferences"; 057 058 /** singleton frame */ 059 private static PreferenceFrame instance = null; 060 061 // needed to keep trace of non singleton frame 062 List<PreferencePanel> preferencePanels; 063 064 private JTree tree; 065 private JSplitPane mainPanel; 066 private DefaultMutableTreeNode node; 067 068 boolean needRestart; 069 boolean doRestart; 070 071 // we need to keep reference on it as the object only use weak reference 072 WindowPositionSaver positionSaver; 073 074 public PreferenceFrame(String section) 075 { 076 super(NODE_NAME, true, true, false, false); 077 078 // frame already opened ? 079 if (instance != null) 080 { 081 // just put it on front 082 instance.toFront(); 083 return; 084 } 085 instance = this; 086 087 positionSaver = new WindowPositionSaver(this, "frame/preference", new Point(100, 100), new Dimension(640, 480)); 088 089 needRestart = false; 090 doRestart = false; 091 092 preferencePanels = new ArrayList<PreferencePanel>(); 093 094 preferencePanels.add(new GeneralPreferencePanel(this)); 095 preferencePanels.add(new GUICanvasPreferencePanel(this)); 096 preferencePanels.add(new NetworkPreferencePanel(this)); 097 // preferencePanels.add(new ChatPreferencePanel(this)); 098 preferencePanels.add(new RepositoryPreferencePanel(this)); 099 preferencePanels.add(new PluginPreferencePanel(this)); 100 preferencePanels.add(new PluginLocalPreferencePanel(this)); 101 preferencePanels.add(new PluginOnlinePreferencePanel(this)); 102 preferencePanels.add(new PluginStartupPreferencePanel(this)); 103 preferencePanels.add(new WorkspacePreferencePanel(this)); 104 preferencePanels.add(new WorkspaceLocalPreferencePanel(this)); 105 preferencePanels.add(new WorkspaceOnlinePreferencePanel(this)); 106 // TODO : add here PreferencePanel type plugins 107 108 // build selection tree 109 node = new DefaultMutableTreeNode(NODE_NAME); 110 111 for (PreferencePanel panel : preferencePanels) 112 getNode(panel.getParentName()).add(panel.getNode()); 113 114 tree = new JTree(node); 115 116 tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); 117 // tree.setOpaque(true); 118 tree.setRootVisible(false); 119 // select first node 120 tree.setSelectionRow(0); 121 ComponentUtil.expandAllTree(tree); 122 // disable double click expansion/reduction 123 tree.setToggleClickCount(0); 124 tree.addTreeSelectionListener(this); 125 126 final JScrollPane treeScrollPane = new JScrollPane(tree); 127 treeScrollPane.setMinimumSize(new Dimension(136, 100)); 128 129 mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScrollPane, null); 130 mainPanel.setDividerSize(6); 131 mainPanel.setDividerLocation(150); 132 133 // final JButton helpButton = new Help(NODE_NAME).getHelpButton("Help"); 134 final JButton resetButton = new JButton("Reset to default"); 135 final JButton cancelButton = new JButton("Cancel"); 136 final JButton okButton = new JButton("Ok"); 137 final JButton applyButton = new JButton("Apply"); 138 139 resetButton.addActionListener(new ActionListener() 140 { 141 @Override 142 public void actionPerformed(ActionEvent e) 143 { 144 // need confirmation 145 if (ConfirmDialog.confirm("Reset all setting to default values ?")) 146 { 147 // clear all preferences 148 IcyPreferences.clear(); 149 // reload 150 for (PreferencePanel panel : preferencePanels) 151 panel.load(); 152 } 153 } 154 }); 155 156 cancelButton.addActionListener(new ActionListener() 157 { 158 @Override 159 public void actionPerformed(ActionEvent e) 160 { 161 // just close the frame 162 close(); 163 } 164 }); 165 166 okButton.addActionListener(new ActionListener() 167 { 168 @Override 169 public void actionPerformed(ActionEvent e) 170 { 171 // set back panel informations in preferences 172 for (PreferencePanel panel : preferencePanels) 173 panel.save(); 174 // validate the need restart state 175 doRestart = needRestart; 176 // then close the frame 177 close(); 178 } 179 }); 180 181 applyButton.addActionListener(new ActionListener() 182 { 183 @Override 184 public void actionPerformed(ActionEvent e) 185 { 186 // set back panel informations in preferences 187 for (PreferencePanel panel : preferencePanels) 188 panel.save(); 189 // validate the need restart state 190 doRestart = needRestart; 191 } 192 }); 193 194 final JPanel bottomPanel = new JPanel(); 195 196 bottomPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8)); 197 bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS)); 198 199 // bottomPanel.add(helpButton); 200 // bottomPanel.add(Box.createHorizontalStrut(8)); 201 bottomPanel.add(resetButton); 202 bottomPanel.add(Box.createHorizontalStrut(8)); 203 bottomPanel.add(Box.createHorizontalGlue()); 204 bottomPanel.add(applyButton); 205 bottomPanel.add(Box.createHorizontalStrut(8)); 206 bottomPanel.add(okButton); 207 bottomPanel.add(Box.createHorizontalStrut(8)); 208 bottomPanel.add(cancelButton); 209 210 final JPanel tmpPanel = new JPanel(); 211 tmpPanel.setLayout(new BoxLayout(tmpPanel, BoxLayout.PAGE_AXIS)); 212 tmpPanel.add(new JSeparator()); 213 tmpPanel.add(bottomPanel); 214 215 setLayout(new BorderLayout()); 216 217 add(mainPanel, BorderLayout.CENTER); 218 add(tmpPanel, BorderLayout.SOUTH); 219 220 updateRightPanel(); 221 222 setMinimumSize(new Dimension(640, 440)); 223 setPreferredSize(new Dimension(800, 600)); 224 225 addToDesktopPane(); 226 setVisible(true); 227 228 if (!StringUtil.isEmpty(section)) 229 setSelection(section); 230 } 231 232 @Override 233 public void onClosed() 234 { 235 // test if we are on singleton frame 236 if (preferencePanels != null) 237 { 238 for (PreferencePanel panel : preferencePanels) 239 panel.closed(); 240 241 instance = null; 242 243 // restart needed and validated, ask user 244 if (doRestart) 245 { 246 Icy.confirmRestart(); 247 doRestart = false; 248 } 249 } 250 251 super.onClosed(); 252 } 253 254 private DefaultMutableTreeNode getNode(String name) 255 { 256 // first search directly on root node 257 if (node.getUserObject().equals(name)) 258 return node; 259 260 // then search in children 261 final int len = node.getChildCount(); 262 for (int i = 0; i < len; i++) 263 { 264 final DefaultMutableTreeNode n = (DefaultMutableTreeNode) node.getChildAt(i); 265 266 if (n.getUserObject().equals(name)) 267 return n; 268 } 269 270 return null; 271 } 272 273 private void updateRightPanel() 274 { 275 final Object selected = tree.getSelectionPath().getLastPathComponent(); 276 277 for (PreferencePanel panel : preferencePanels) 278 { 279 if (panel.getNode().equals(selected)) 280 { 281 final int divLocation = mainPanel.getDividerLocation(); 282 283 panel.setVisible(true); 284 mainPanel.setRightComponent(panel); 285 // restore divider location (lost with setRightComponent) 286 mainPanel.setDividerLocation(divLocation); 287 } 288 else 289 panel.setVisible(true); 290 } 291 } 292 293 @Override 294 public void valueChanged(TreeSelectionEvent e) 295 { 296 updateRightPanel(); 297 } 298 299 public void setSelection(String selection) 300 { 301 for (PreferencePanel panel : preferencePanels) 302 { 303 final DefaultMutableTreeNode node = panel.getNode(); 304 305 if (node.getUserObject().equals(selection)) 306 { 307 tree.setSelectionPath(ComponentUtil.buildTreePath(node)); 308 return; 309 } 310 } 311 } 312 313 public void setNeedRestart() 314 { 315 needRestart = true; 316 } 317}