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}