001 /*
002 * $Id: McIdasPreferenceManager.java,v 1.100 2012/02/19 17:35:53 davep Exp $
003 *
004 * This file is part of McIDAS-V
005 *
006 * Copyright 2007-2012
007 * Space Science and Engineering Center (SSEC)
008 * University of Wisconsin - Madison
009 * 1225 W. Dayton Street, Madison, WI 53706, USA
010 * https://www.ssec.wisc.edu/mcidas
011 *
012 * All Rights Reserved
013 *
014 * McIDAS-V is built on Unidata's IDV and SSEC's VisAD libraries, and
015 * some McIDAS-V source code is based on IDV and VisAD source code.
016 *
017 * McIDAS-V is free software; you can redistribute it and/or modify
018 * it under the terms of the GNU Lesser Public License as published by
019 * the Free Software Foundation; either version 3 of the License, or
020 * (at your option) any later version.
021 *
022 * McIDAS-V is distributed in the hope that it will be useful,
023 * but WITHOUT ANY WARRANTY; without even the implied warranty of
024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
025 * GNU Lesser Public License for more details.
026 *
027 * You should have received a copy of the GNU Lesser Public License
028 * along with this program. If not, see http://www.gnu.org/licenses.
029 */
030
031 package edu.wisc.ssec.mcidasv;
032
033 import static javax.swing.GroupLayout.Alignment.BASELINE;
034 import static javax.swing.GroupLayout.Alignment.LEADING;
035 import static javax.swing.GroupLayout.Alignment.TRAILING;
036 import static javax.swing.GroupLayout.DEFAULT_SIZE;
037 import static javax.swing.GroupLayout.PREFERRED_SIZE;
038 import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;
039
040
041 import java.awt.CardLayout;
042 import java.awt.Color;
043 import java.awt.Component;
044 import java.awt.Container;
045 import java.awt.Dimension;
046 import java.awt.Font;
047 import java.awt.Graphics;
048 import java.awt.Graphics2D;
049 import java.awt.Insets;
050 import java.awt.RenderingHints;
051 import java.awt.event.ActionEvent;
052 import java.awt.event.ActionListener;
053 import java.beans.PropertyChangeEvent;
054 import java.beans.PropertyChangeListener;
055 import java.net.URL;
056 import java.text.DecimalFormat;
057 import java.util.ArrayList;
058 import java.util.Arrays;
059 import java.util.Collections;
060 import java.util.Enumeration;
061 import java.util.Hashtable;
062 import java.util.LinkedHashSet;
063 import java.util.List;
064 import java.util.Map;
065 import java.util.Set;
066 import java.util.TimeZone;
067 import java.util.Vector;
068
069 import javax.swing.BorderFactory;
070 import javax.swing.DefaultListCellRenderer;
071 import javax.swing.DefaultListModel;
072 import javax.swing.ImageIcon;
073 import javax.swing.JButton;
074 import javax.swing.JCheckBox;
075 import javax.swing.JComboBox;
076 import javax.swing.JComponent;
077 import javax.swing.JLabel;
078 import javax.swing.JList;
079 import javax.swing.JPanel;
080 import javax.swing.JRadioButton;
081 import javax.swing.JScrollPane;
082 import javax.swing.JTextField;
083 import javax.swing.ListSelectionModel;
084 import javax.swing.SwingUtilities;
085 import javax.swing.border.BevelBorder;
086 import javax.swing.event.ListSelectionEvent;
087 import javax.swing.event.ListSelectionListener;
088
089 import org.bushe.swing.event.annotation.AnnotationProcessor;
090 import org.bushe.swing.event.annotation.EventSubscriber;
091 import org.slf4j.Logger;
092 import org.slf4j.LoggerFactory;
093 import org.w3c.dom.Element;
094 import org.w3c.dom.NodeList;
095
096 import ucar.unidata.data.DataUtil;
097 import ucar.unidata.idv.ControlDescriptor;
098 import ucar.unidata.idv.DisplayControl;
099 import ucar.unidata.idv.IdvConstants;
100 import ucar.unidata.idv.IdvObjectStore;
101 import ucar.unidata.idv.IdvPreferenceManager;
102 import ucar.unidata.idv.IntegratedDataViewer;
103 import ucar.unidata.idv.MapViewManager;
104 import ucar.unidata.idv.ViewManager;
105 import ucar.unidata.idv.control.DisplayControlImpl;
106 import ucar.unidata.ui.CheckboxCategoryPanel;
107 import ucar.unidata.ui.FontSelector;
108 import ucar.unidata.ui.HelpTipDialog;
109 import ucar.unidata.ui.XmlUi;
110 import ucar.unidata.util.GuiUtils;
111 import ucar.unidata.util.IOUtil;
112 import ucar.unidata.util.LogUtil;
113 import ucar.unidata.util.Misc;
114 import ucar.unidata.util.Msg;
115 import ucar.unidata.util.ObjectListener;
116 import ucar.unidata.util.StringUtil;
117 import ucar.unidata.xml.PreferenceManager;
118 import ucar.unidata.xml.XmlObjectStore;
119 import ucar.unidata.xml.XmlUtil;
120 import ucar.visad.UtcDate;
121 import visad.DateTime;
122 import visad.Unit;
123 import edu.wisc.ssec.mcidasv.servermanager.EntryStore;
124 import edu.wisc.ssec.mcidasv.servermanager.AddePreferences;
125 import edu.wisc.ssec.mcidasv.servermanager.AddePreferences.AddePrefConglomeration;
126 import edu.wisc.ssec.mcidasv.startupmanager.StartupManager;
127 import edu.wisc.ssec.mcidasv.ui.McvToolbarEditor;
128 import edu.wisc.ssec.mcidasv.ui.UIManager;
129 import edu.wisc.ssec.mcidasv.util.CollectionHelpers;
130 import edu.wisc.ssec.mcidasv.util.McVGuiUtils;
131 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width;
132 import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Prefer;
133
134 /**
135 * <p>An extension of {@link ucar.unidata.idv.IdvPreferenceManager} that uses
136 * a JList instead of tabs to lay out the various PreferenceManagers.</p>
137 *
138 * @author McIDAS-V Dev Team
139 */
140 public class McIdasPreferenceManager extends IdvPreferenceManager implements ListSelectionListener, Constants {
141
142 /** Logger object. */
143 private static final Logger logger = LoggerFactory.getLogger(McIdasPreferenceManager.class);
144
145 /**
146 * <p>Controls how the preference panel list is displayed. Want to modify
147 * the preferences UI in some way? PREF_PANELS is your friend. Think of
148 * it like a really brain-dead SQLite.</p>
149 *
150 * <p>Each row is a panel, and <b>must</b> consist of three columns:
151 * <ol start="0">
152 * <li>Name of the panel.</li>
153 * <li>Path to the icon associated with the panel.</li>
154 * <li>The panel's {@literal "help ID."}</li>
155 * </ol>
156 * The {@link JList} in the preferences window will order the panels based
157 * upon {@code PREF_PANELS}.
158 * </p>
159 */
160 public static final String[][] PREF_PANELS = {
161 { Constants.PREF_LIST_GENERAL, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/mcidasv-round32.png", "idv.tools.preferences.generalpreferences" },
162 { Constants.PREF_LIST_VIEW, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/tab-new32.png", "idv.tools.preferences.displaywindowpreferences" },
163 { Constants.PREF_LIST_TOOLBAR, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/application-x-executable32.png", "idv.tools.preferences.toolbarpreferences" },
164 { Constants.PREF_LIST_DATA_CHOOSERS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/preferences-desktop-remote-desktop32.png", "idv.tools.preferences.datapreferences" },
165 { Constants.PREF_LIST_ADDE_SERVERS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/applications-internet32.png", "idv.tools.preferences.serverpreferences" },
166 { Constants.PREF_LIST_AVAILABLE_DISPLAYS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/video-display32.png", "idv.tools.preferences.availabledisplayspreferences" },
167 { Constants.PREF_LIST_NAV_CONTROLS, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/input-mouse32.png", "idv.tools.preferences.navigationpreferences" },
168 { Constants.PREF_LIST_FORMATS_DATA,"/edu/wisc/ssec/mcidasv/resources/icons/prefs/preferences-desktop-theme32.png", "idv.tools.preferences.formatpreferences" },
169 { Constants.PREF_LIST_ADVANCED, "/edu/wisc/ssec/mcidasv/resources/icons/prefs/applications-internet32.png", "idv.tools.preferences.advancedpreferences" }
170 };
171
172 /** Desired rendering hints with their desired values. */
173 public static final Object[][] RENDER_HINTS = {
174 { RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON },
175 { RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY },
176 { RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON }
177 };
178
179 /** Options for bundle loading */
180 public static final String[] loadComboOptions = {
181 "Create new window(s)",
182 "Merge with active tab(s)",
183 "Add new tab(s) to current window",
184 "Replace session"
185 };
186
187 /**
188 * @return The rendering hints to use, as determined by RENDER_HINTS.
189 */
190 public static RenderingHints getRenderingHints() {
191 RenderingHints hints = new RenderingHints(null);
192 for (int i = 0; i < RENDER_HINTS.length; i++) {
193 hints.put(RENDER_HINTS[i][0], RENDER_HINTS[i][1]);
194 }
195 return hints;
196 }
197
198 /** Help McV remember the last preference panel the user selected. */
199 private static final String LAST_PREF_PANEL = "mcv.prefs.lastpanel";
200
201 private static final String LEGEND_TEMPLATE_DATA = "%datasourcename% - %displayname%";
202 private static final String DISPLAY_LIST_TEMPLATE_DATA = "%datasourcename% - %displayname% " + UtcDate.MACRO_TIMESTAMP;
203
204 private static final String TEMPLATE_NO_DATA = "%displayname%";
205
206 /** test value for formatting */
207 private static double latlonValue = -104.56284;
208
209 /** Decimal format */
210 private static DecimalFormat latlonFormat = new DecimalFormat();
211
212 /** Provide some default values for the lat-lon preference drop down. */
213 private static final Set<String> defaultLatLonFormats = CollectionHelpers.set("##0","##0.0","##0.0#","##0.0##","0.0","0.00","0.000");
214
215 private static final Set<String> probeFormatsList = CollectionHelpers.set(DisplayControl.DEFAULT_PROBEFORMAT, "%rawvalue% [%rawunit%]", "%value%", "%rawvalue%", "%value% <i>%unit%</i>");
216
217 /**
218 * Replacing the "incoming" IDV preference tab names with whatever's in
219 * this map.
220 */
221 private static final Map<String, String> replaceMap =
222 CollectionHelpers.zipMap(
223 CollectionHelpers.arr("Toolbar", "View"),
224 CollectionHelpers.arr(Constants.PREF_LIST_TOOLBAR, Constants.PREF_LIST_VIEW));
225
226 /** Path to the McV choosers.xml */
227 private static final String MCV_CHOOSERS = "/edu/wisc/ssec/mcidasv/resources/choosers.xml";
228
229 /**
230 * Maps the {@literal "name"} of a panel to the actual thing holding the
231 * PreferenceManager.
232 */
233 private final Map<String, Container> prefMap = CollectionHelpers.concurrentMap();
234
235 /** Maps the name of a panel to an icon. */
236 private final Map<String, ImageIcon> iconCache = CollectionHelpers.concurrentMap();
237
238 /**
239 * A table of the different preference managers that'll wind up in the
240 * list.
241 */
242 private final Map<String, PreferenceManager> managerMap = CollectionHelpers.concurrentMap();
243
244 /**
245 * Each PreferenceManager has associated data contained in this table.
246 * TODO: bug Unidata about getting IdvPreferenceManager's dataList protected
247 */
248 private final Map<String, Object> dataMap = CollectionHelpers.concurrentMap();
249
250 private final Set<String> labelSet = new LinkedHashSet<String>();
251
252 /**
253 * The list that'll contain all the names of the different
254 * PreferenceManagers
255 */
256 private JList labelList;
257
258 /** The "M" in the MVC for JLists. Contains all the list data. */
259 private DefaultListModel listModel;
260
261 /** Handle scrolling like a pro. */
262 private JScrollPane listScrollPane;
263
264 /** Holds the main preference pane */
265 private JPanel mainPane;
266
267 /** Holds the buttons at the bottom */
268 private JPanel buttonPane;
269
270 /** Date formats */
271 private final Set<String> dateFormats = CollectionHelpers.set(
272 DEFAULT_DATE_FORMAT, "MM/dd/yy HH:mm z", "dd.MM.yy HH:mm z",
273 "yyyy-MM-dd", "EEE, MMM dd yyyy HH:mm z", "HH:mm:ss", "HH:mm",
274 "yyyy-MM-dd'T'HH:mm:ss'Z'", "yyyy-MM-dd'T'HH:mm:ssZ");
275
276 /** Is this a Unix-style platform? */
277 private boolean isUnixLike = false;
278
279 /** Is this a Windows platform? */
280 private boolean isWindows = false;
281
282 /** The toolbar editor */
283 private McvToolbarEditor toolbarEditor;
284
285 /** */
286 private String userDirectory;
287
288 /** */
289 private String userPrefs;
290
291 /** */
292 private String defaultPrefs;
293
294 /**
295 * Prep as much as possible for displaying the preference window: load up
296 * icons and create some of the window features.
297 *
298 * @param idv Reference to the supreme IDV object.
299 */
300 public McIdasPreferenceManager(IntegratedDataViewer idv) {
301 super(idv);
302 AnnotationProcessor.process(this);
303 init();
304
305 for (int i = 0; i < PREF_PANELS.length; i++) {
306 URL url = getClass().getResource(PREF_PANELS[i][1]);
307 iconCache.put(PREF_PANELS[i][0], new ImageIcon(url));
308 }
309
310 setEmptyPref("idv.displaylist.template.data", DISPLAY_LIST_TEMPLATE_DATA);
311 setEmptyPref("idv.displaylist.template.nodata", TEMPLATE_NO_DATA);
312 setEmptyPref("idv.legendlabel.template.data", LEGEND_TEMPLATE_DATA);
313 setEmptyPref("idv.legendlabel.template.nodata", TEMPLATE_NO_DATA);
314 }
315
316 private boolean setEmptyPref(final String id, final String val) {
317 IdvObjectStore store = getIdv().getStore();
318 if (store.get(id, (String)null) == null) {
319 store.put(id, val);
320 return true;
321 }
322 return false;
323 }
324
325 /**
326 * Overridden so McIDAS-V can direct users to specific help sections for
327 * each preference panel.
328 */
329 @Override public void actionPerformed(ActionEvent event) {
330 String cmd = event.getActionCommand();
331 if (!GuiUtils.CMD_HELP.equals(cmd) || labelList == null) {
332 super.actionPerformed(event);
333 return;
334 }
335
336 int selectedIndex = labelList.getSelectedIndex();
337 getIdvUIManager().showHelp(PREF_PANELS[selectedIndex][2]);
338 }
339
340 public void replaceServerPrefPanel(final JPanel panel) {
341 String name = "SERVER MANAGER";
342 mainPane.add(name, panel);
343 ((CardLayout)mainPane.getLayout()).show(mainPane, name);
344 }
345
346 @EventSubscriber(eventClass=EntryStore.Event.class)
347 public void replaceServerPreferences(EntryStore.Event evt) {
348 EntryStore remoteAddeStore = ((McIDASV)getIdv()).getServerManager();
349 AddePreferences prefs = new AddePreferences(remoteAddeStore);
350 AddePrefConglomeration eww = prefs.buildPanel((McIDASV)getIdv());
351 String name = "SERVER MANAGER";
352 // mainPane.add(name, eww.getEntryPanel());
353 // ((CardLayout)mainPane.getLayout()).show(mainPane, name);
354 }
355
356 /**
357 * Add a PreferenceManager to the list of things that should be shown in
358 * the preference dialog.
359 *
360 * @param tabLabel The label (or name) of the PreferenceManager.
361 * @param description Not used.
362 * @param listener The actual PreferenceManager.
363 * @param panel The container holding all of the PreferenceManager stuff.
364 * @param data Data passed to the preference manager.
365 */
366 @Override public void add(String tabLabel, String description,
367 PreferenceManager listener, Container panel, Object data) {
368
369 // if there is an alternate name for tabLabel, find and use it.
370 if (replaceMap.containsKey(tabLabel) == true) {
371 tabLabel = replaceMap.get(tabLabel);
372 }
373
374 if (prefMap.containsKey(tabLabel) == true) {
375 return;
376 }
377
378 // figure out the last panel that was selected.
379 int selected = getIdv().getObjectStore().get(LAST_PREF_PANEL, 0);
380 if (selected < 0 || selected >= PREF_PANELS.length) {
381 logger.warn("attempted to select an invalid preference panel: {}", selected);
382 selected = 0;
383 }
384 String selectedPanel = PREF_PANELS[selected][0];
385
386 panel.setPreferredSize(null);
387
388 Msg.translateTree(panel);
389
390 managerMap.put(tabLabel, listener);
391 if (data == null) {
392 dataMap.put(tabLabel, new Hashtable());
393 } else {
394 dataMap.put(tabLabel, data);
395 }
396 prefMap.put(tabLabel, panel);
397
398 if (labelSet.add(tabLabel)) {
399 JLabel label = new JLabel();
400 label.setText(tabLabel);
401 label.setIcon(iconCache.get(tabLabel));
402 listModel.addElement(label);
403
404 labelList.setSelectedIndex(selected);
405 mainPane.add(tabLabel, panel);
406 if (selectedPanel.equals(tabLabel)) {
407 ((CardLayout)mainPane.getLayout()).show(mainPane, tabLabel);
408 }
409 }
410
411 mainPane.repaint();
412 }
413
414 /**
415 * Apply the preferences (taken straight from IDV).
416 * TODO: bug Unidata about making managers and dataList protected instead of private
417 *
418 * @return Whether or not each of the preference managers applied properly.
419 */
420 @Override public boolean apply() {
421 try {
422 for (String id : labelSet) {
423 PreferenceManager manager = managerMap.get(id);
424 manager.applyPreference(getStore(), dataMap.get(id));
425 }
426 fixDisplayListFont();
427 getStore().save();
428 return true;
429 } catch (Exception exc) {
430 LogUtil.logException("Error applying preferences", exc);
431 return false;
432 }
433 }
434
435 // For some reason the display list font can have a size of zero if your
436 // new font size didn't change after starting the prefs panel.
437 private void fixDisplayListFont() {
438 IdvObjectStore s = getStore();
439 Font f = s.get(ViewManager.PREF_DISPLAYLISTFONT, FontSelector.DEFAULT_FONT);
440 if (f.getSize() == 0) {
441 f = f.deriveFont(8f);
442 s.put(ViewManager.PREF_DISPLAYLISTFONT, f);
443 }
444 }
445
446 /**
447 * Select a list item and its corresponding panel that both live within the
448 * preference window JList.
449 *
450 * @param labelName The "name" of the JLabel within the JList.
451 */
452 public void selectListItem(String labelName) {
453 show();
454 toFront();
455
456 for (int i = 0; i < listModel.getSize(); i++) {
457 String labelText = ((JLabel)listModel.get(i)).getText();
458 if (StringUtil.stringMatch(labelText, labelName)) {
459 // persist across restarts
460 getIdv().getObjectStore().put(LAST_PREF_PANEL, i);
461 labelList.setSelectedIndex(i);
462 return;
463 }
464 }
465 }
466
467 /**
468 * Wrapper so that IDV code can still select which preference pane to show.
469 *
470 * @param tabNameToShow The name of the pane to be shown. Regular
471 * expressions are supported.
472 */
473 public void showTab(String tabNameToShow) {
474 selectListItem(tabNameToShow);
475 }
476
477 /**
478 * Handle the user clicking around.
479 *
480 * @param e The event to be handled! Use your imagination!
481 */
482 public void valueChanged(ListSelectionEvent e) {
483 if (e.getValueIsAdjusting() == false) {
484 String name = getSelectedName();
485 ((CardLayout)mainPane.getLayout()).show(mainPane, name);
486 }
487 }
488
489 /**
490 * Returns the container the corresponds to the currently selected label in
491 * the JList. Also stores the selected panel so that the next time a user
492 * tries to open the preferences they will start off in the panel they last
493 * selected.
494 *
495 * @return The current container.
496 */
497 private Container getSelectedPanel() {
498 // make sure the selected panel persists across restarts
499 getIdv().getObjectStore().put(LAST_PREF_PANEL, labelList.getSelectedIndex());
500 String key = ((JLabel)listModel.getElementAt(labelList.getSelectedIndex())).getText();
501 if (key.equals(Constants.PREF_LIST_NAV_CONTROLS)) {
502 return makeEventPanel();
503 }
504 return prefMap.get(key);
505 }
506
507 private Container getSelectedPanel(final String name) {
508 if (Constants.PREF_LIST_NAV_CONTROLS.equals(name)) {
509 return makeEventPanel();
510 } else if (prefMap.containsKey(name)) {
511 return prefMap.get(name);
512 } else {
513 return null;
514 }
515 }
516
517 /**
518 * Returns the container the corresponds to the currently selected label in
519 * the JList. Also stores the selected panel so that the next time a user
520 * tries to open the preferences they will start off in the panel they last
521 * selected.
522 *
523 * @return The current container.
524 */
525 private String getSelectedName() {
526 // make sure the selected panel persists across restarts
527 getIdv().getObjectStore().put(LAST_PREF_PANEL, labelList.getSelectedIndex());
528 String key = ((JLabel)listModel.getElementAt(labelList.getSelectedIndex())).getText();
529 return key;
530 }
531
532 /**
533 * Perform the GUI initialization for the preference dialog.
534 */
535 public void init() {
536 listModel = new DefaultListModel();
537 labelList = new JList(listModel);
538
539 labelList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
540 labelList.setCellRenderer(new IconCellRenderer());
541 labelList.addListSelectionListener(new ListSelectionListener() {
542 public void valueChanged(ListSelectionEvent e) {
543 if (e.getValueIsAdjusting() == false) {
544 String name = getSelectedName();
545 if (Constants.PREF_LIST_NAV_CONTROLS.equals(name)) {
546 mainPane.add(name, makeEventPanel());
547 mainPane.validate();
548 }
549 ((CardLayout)mainPane.getLayout()).show(mainPane, name);
550 }
551 }
552 });
553
554 listScrollPane = new JScrollPane(labelList);
555 listScrollPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
556
557 mainPane = new JPanel(new CardLayout());
558 mainPane.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
559 mainPane.addPropertyChangeListener(new PropertyChangeListener() {
560 public void propertyChange(PropertyChangeEvent e) {
561 // System.err.println("prop change: prop="+e.getPropertyName()+" old="+e.getOldValue()+" new="+e.getNewValue());
562 String p = e.getPropertyName();
563 if (!"Frame.active".equals(p) && !"ancestor".equals(p)) {
564 return;
565 }
566
567 Object v = e.getNewValue();
568 boolean okay = false;
569 if (v instanceof Boolean) {
570 okay = ((Boolean)v).booleanValue();
571 } else if (v instanceof JPanel) {
572 okay = true;
573 } else {
574 okay = false;
575 }
576
577 if (okay) {
578 if (getSelectedName().equals(Constants.PREF_LIST_NAV_CONTROLS)) {
579 mainPane.add(Constants.PREF_LIST_NAV_CONTROLS, makeEventPanel());
580 mainPane.validate();
581 ((CardLayout)mainPane.getLayout()).show(mainPane, Constants.PREF_LIST_NAV_CONTROLS);
582 }
583 }
584 }
585 });
586
587 JPanel buttons = GuiUtils.makeApplyOkHelpCancelButtons(this);
588 buttonPane = McVGuiUtils.makePrettyButtons(buttons);
589
590 contents = new JPanel();
591 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(contents);
592 contents.setLayout(layout);
593 layout.setHorizontalGroup(
594 layout.createParallelGroup(LEADING)
595 .addGroup(layout.createSequentialGroup()
596 .addComponent(listScrollPane, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
597 .addPreferredGap(RELATED)
598 .addComponent(mainPane, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
599 .addComponent(buttonPane, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
600 );
601 layout.setVerticalGroup(
602 layout.createParallelGroup(LEADING)
603 .addGroup(layout.createSequentialGroup()
604 .addGroup(layout.createParallelGroup(TRAILING)
605 .addComponent(mainPane, LEADING, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
606 .addComponent(listScrollPane, LEADING, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
607 .addPreferredGap(RELATED)
608 .addComponent(buttonPane, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE))
609 );
610 }
611
612 /**
613 * Initialize the preference dialog. Leave most of the heavy lifting to
614 * the IDV, except for creating the server manager.
615 */
616 protected void initPreferences() {
617 // General/McIDAS-V
618 addMcVPreferences();
619
620 // View/Display Window
621 addDisplayWindowPreferences();
622
623 // Toolbar/Toolbar Options
624 addToolbarPreferences();
625
626 // Available Choosers/Data Sources
627 addChooserPreferences();
628
629 // ADDE Servers
630 addServerPreferences();
631
632 // Available Displays/Display Types
633 addDisplayPreferences();
634
635 // Navigation/Navigation Controls
636 addNavigationPreferences();
637
638 // Formats & Data
639 addFormatDataPreferences();
640
641 // Advanced
642 addAdvancedPreferences();
643 }
644
645 /**
646 * Build a {@link AddePreferences} panel {@literal "around"} the
647 * server manager {@link EntryStore}.
648 *
649 * @see McIDASV#getServerManager()
650 */
651 public void addServerPreferences() {
652 EntryStore remoteAddeStore = ((McIDASV)getIdv()).getServerManager();
653 AddePreferences prefs = new AddePreferences(remoteAddeStore);
654 prefs.addPanel(this);
655 }
656
657 /**
658 * Create the navigation preference panel
659 */
660 public void addNavigationPreferences() {
661 PreferenceManager navigationManager = new PreferenceManager() {
662 public void applyPreference(XmlObjectStore theStore, Object data) {
663 // System.err.println("applying nav prefs");
664 }
665 };
666 this.add(Constants.PREF_LIST_NAV_CONTROLS, "", navigationManager, makeEventPanel(), new Hashtable());
667 }
668
669 /**
670 * Create the toolbar preference panel
671 *
672 * @param preferenceManager The preference manager
673 */
674 public void addToolbarPreferences() {
675 if (toolbarEditor == null) {
676 toolbarEditor =
677 new McvToolbarEditor((UIManager)getIdv().getIdvUIManager());
678 }
679
680 PreferenceManager toolbarManager = new PreferenceManager() {
681 public void applyPreference(XmlObjectStore s, Object d) {
682 if (toolbarEditor.anyChanges() == true) {
683 toolbarEditor.doApply();
684 UIManager mngr = (UIManager)getIdv().getIdvUIManager();
685 mngr.setCurrentToolbars(toolbarEditor);
686 }
687 }
688 };
689 this.add("Toolbar", "Toolbar icons", toolbarManager,
690 toolbarEditor.getContents(), toolbarEditor);
691 }
692
693 /**
694 * Make a checkbox preference panel
695 *
696 * @param objects Holds (Label, preference id, Boolean default value).
697 * If preference id is null then just show the label. If the entry is only length
698 * 2 (i.e., no value) then default to true.
699 * @param widgets The map to store the id to widget
700 * @param store Where to look up the preference value
701 *
702 * @return The created panel
703 */
704 @SuppressWarnings("unchecked") // idv-style.
705 public static JPanel makePrefPanel(final Object[][] objects, final Hashtable widgets, final XmlObjectStore store) {
706 List<JComponent> comps = CollectionHelpers.arrList();
707 for (int i = 0; i < objects.length; i++) {
708 final String name = (String)objects[i][0];
709 final String id = (String)objects[i][1];
710 final boolean value = ((objects[i].length > 2) ? ((Boolean) objects[i][2]).booleanValue() : true);
711
712 if (id == null) {
713 if (i > 0) {
714 comps.add(new JLabel(" "));
715 }
716 comps.add(new JLabel(name));
717 continue;
718 }
719
720 final JCheckBox cb = new JCheckBox(name, store.get(id, value));
721 cb.addPropertyChangeListener(new PropertyChangeListener() {
722 public void propertyChange(final PropertyChangeEvent e) {
723 SwingUtilities.invokeLater(new Runnable() {
724 public void run() {
725 boolean internalSel = store.get(id, value);
726
727 cb.setSelected(store.get(id, value));
728 }
729 });
730 }
731 });
732 if (objects[i].length > 3) {
733 cb.setToolTipText(objects[i][3].toString());
734 }
735 widgets.put(id, cb);
736 comps.add(cb);
737 }
738 return GuiUtils.top(GuiUtils.vbox(comps));
739 }
740
741 public void addAdvancedPreferences() {
742 Hashtable<String, Component> widgets = new Hashtable<String, Component>();
743
744 McIDASV mcv = (McIDASV)getIdv();
745
746 // Build the threads panel
747 Vector threadRenderList = new Vector();
748 for(int i = 1;i <= Runtime.getRuntime().availableProcessors();i++) {
749 threadRenderList.add(new Integer(i));
750 }
751 Integer threadRenderMax = new Integer(mcv.getMaxRenderThreadCount());
752 final JComboBox threadRenderComboBox = McVGuiUtils.makeComboBox(threadRenderList, threadRenderMax);
753 widgets.put(PREF_THREADS_RENDER, threadRenderComboBox);
754
755 Vector threadReadList = new Vector();
756 for(int i = 1; i <= 12; i++) {
757 threadReadList.add(new Integer(i));
758 }
759 Integer threadReadMax = new Integer(mcv.getMaxDataThreadCount());
760 final JComboBox threadReadComboBox = McVGuiUtils.makeComboBox(threadReadList, threadReadMax);
761 widgets.put(PREF_THREADS_DATA, threadReadComboBox);
762
763 JPanel threadsPanel = McVGuiUtils.topBottom(
764 McVGuiUtils.makeLabeledComponent("Rendering:", threadRenderComboBox),
765 McVGuiUtils.makeLabeledComponent("Reading:", threadReadComboBox),
766 Prefer.NEITHER);
767 threadsPanel.setBorder(BorderFactory.createTitledBorder("Java Threads"));
768
769 // Build the startup options panel
770 StartupManager.INSTANCE.getPlatform().setUserDirectory(
771 mcv.getObjectStore().getUserDirectory().toString());
772 StartupManager.INSTANCE.getPlatform().setAvailableMemory(
773 mcv.getStateManager().getProperty(Constants.PROP_SYSMEM, "0"));
774 JPanel smPanel = StartupManager.INSTANCE.getAdvancedPanel(true);
775 List<JPanel> stuff = Collections.singletonList(smPanel);
776
777 PreferenceManager advancedManager = new PreferenceManager() {
778 public void applyPreference(XmlObjectStore theStore, Object data) {
779 IdvPreferenceManager.applyWidgets((Hashtable)data, theStore);
780 StartupManager.INSTANCE.handleApply();
781 }
782 };
783
784 JPanel outerPanel = new JPanel();
785
786 // Outer panel layout
787 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(outerPanel);
788 outerPanel.setLayout(layout);
789 layout.setHorizontalGroup(
790 layout.createParallelGroup(LEADING)
791 .addGroup(layout.createSequentialGroup()
792 .addContainerGap()
793 .addGroup(layout.createParallelGroup(LEADING)
794 .addComponent(smPanel, TRAILING, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
795 .addComponent(threadsPanel, TRAILING, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
796 .addContainerGap())
797 );
798 layout.setVerticalGroup(
799 layout.createParallelGroup(LEADING)
800 .addGroup(layout.createSequentialGroup()
801 .addContainerGap()
802 .addComponent(smPanel, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
803 .addGap(GAP_UNRELATED)
804 .addComponent(threadsPanel, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
805 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
806 );
807
808 this.add(Constants.PREF_LIST_ADVANCED, "complicated stuff dude",
809 advancedManager, outerPanel, widgets);
810 }
811
812 /**
813 * Add in the user preference tab for the controls to show
814 */
815 protected void addDisplayPreferences() {
816 McIDASV mcv = (McIDASV)getIdv();
817 cbxToCdMap = new Hashtable<JCheckBox, ControlDescriptor>();
818 List<JPanel> compList = new ArrayList<JPanel>();
819 List<ControlDescriptor> controlDescriptors =
820 getIdv().getAllControlDescriptors();
821
822 final List<CheckboxCategoryPanel> catPanels =
823 new ArrayList<CheckboxCategoryPanel>();
824
825 final Hashtable<String, CheckboxCategoryPanel> catMap =
826 new Hashtable<String, CheckboxCategoryPanel>();
827
828 for (ControlDescriptor cd : controlDescriptors) {
829
830 final String displayCategory = cd.getDisplayCategory();
831
832 CheckboxCategoryPanel catPanel =
833 (CheckboxCategoryPanel) catMap.get(displayCategory);
834
835 if (catPanel == null) {
836 catPanel = new CheckboxCategoryPanel(displayCategory, false);
837 catPanels.add(catPanel);
838 catMap.put(displayCategory, catPanel);
839 compList.add(catPanel.getTopPanel());
840 compList.add(catPanel);
841 }
842
843 JCheckBox cbx =
844 new JCheckBox(cd.getLabel(), shouldShowControl(cd, true));
845 cbx.setToolTipText(cd.getDescription());
846 cbxToCdMap.put(cbx, cd);
847 catPanel.addItem(cbx);
848 catPanel.add(GuiUtils.inset(cbx, new Insets(0, 20, 0, 0)));
849 }
850
851 for (CheckboxCategoryPanel cbcp : catPanels) {
852 cbcp.checkVisCbx();
853 }
854
855 final JButton allOn = new JButton("All on");
856 allOn.addActionListener(new ActionListener() {
857 public void actionPerformed(ActionEvent ae) {
858 for (CheckboxCategoryPanel cbcp : catPanels) {
859 cbcp.toggleAll(true);
860 }
861 }
862 });
863 final JButton allOff = new JButton("All off");
864 allOff.addActionListener(new ActionListener() {
865 public void actionPerformed(ActionEvent ae) {
866 for (CheckboxCategoryPanel cbcp : catPanels) {
867 cbcp.toggleAll(false);
868 }
869 }
870 });
871
872 Boolean controlsAll =
873 (Boolean)mcv.getPreference(PROP_CONTROLDESCRIPTORS_ALL, Boolean.TRUE);
874 final JRadioButton useAllBtn = new JRadioButton("Use all displays",
875 controlsAll.booleanValue());
876 final JRadioButton useTheseBtn =
877 new JRadioButton("Use selected displays:",
878 !controlsAll.booleanValue());
879 GuiUtils.buttonGroup(useAllBtn, useTheseBtn);
880
881 final JPanel cbPanel = GuiUtils.top(GuiUtils.vbox(compList));
882
883 JScrollPane cbScroller = new JScrollPane(cbPanel);
884 cbScroller.getVerticalScrollBar().setUnitIncrement(10);
885 cbScroller.setPreferredSize(new Dimension(300, 300));
886
887 JComponent exportComp =
888 GuiUtils.right(GuiUtils.makeButton("Export to Plugin", this,
889 "exportControlsToPlugin"));
890
891 JComponent cbComp = GuiUtils.centerBottom(cbScroller, exportComp);
892
893 JPanel bottomPanel =
894 GuiUtils.leftCenter(
895 GuiUtils.inset(
896 GuiUtils.top(GuiUtils.vbox(allOn, allOff)),
897 4), new Msg.SkipPanel(
898 GuiUtils.hgrid(
899 Misc.newList(cbComp, GuiUtils.filler()), 0)));
900
901 JPanel controlsPanel =
902 GuiUtils.inset(GuiUtils.topCenter(GuiUtils.hbox(useAllBtn,
903 useTheseBtn), bottomPanel), 6);
904
905 GuiUtils.enableTree(cbPanel, !useAllBtn.isSelected());
906 useAllBtn.addActionListener(new ActionListener() {
907 public void actionPerformed(ActionEvent ae) {
908 GuiUtils.enableTree(cbPanel, !useAllBtn.isSelected());
909 allOn.setEnabled(!useAllBtn.isSelected());
910 allOff.setEnabled(!useAllBtn.isSelected());
911 }
912 });
913
914 useTheseBtn.addActionListener(new ActionListener() {
915 public void actionPerformed(ActionEvent ae) {
916 GuiUtils.enableTree(cbPanel, !useAllBtn.isSelected());
917 allOn.setEnabled(!useAllBtn.isSelected());
918 allOff.setEnabled(!useAllBtn.isSelected());
919 }
920 });
921
922 GuiUtils.enableTree(cbPanel, !useAllBtn.isSelected());
923
924 allOn.setEnabled(!useAllBtn.isSelected());
925
926 allOff.setEnabled(!useAllBtn.isSelected());
927
928 PreferenceManager controlsManager = new PreferenceManager() {
929 public void applyPreference(XmlObjectStore theStore, Object data) {
930 controlDescriptorsToShow = new Hashtable();
931
932 Hashtable<JCheckBox, ControlDescriptor> table = (Hashtable)data;
933
934 List<ControlDescriptor> controlDescriptors = getIdv().getAllControlDescriptors();
935
936 for (Enumeration keys = table.keys(); keys.hasMoreElements(); ) {
937 JCheckBox cbx = (JCheckBox) keys.nextElement();
938 ControlDescriptor cd = (ControlDescriptor)table.get(cbx);
939 controlDescriptorsToShow.put(cd.getControlId(), Boolean.valueOf(cbx.isSelected()));
940 }
941
942 showAllControls = useAllBtn.isSelected();
943
944 theStore.put(PROP_CONTROLDESCRIPTORS, controlDescriptorsToShow);
945 theStore.put(PROP_CONTROLDESCRIPTORS_ALL, Boolean.valueOf(showAllControls));
946 }
947 };
948
949 this.add(Constants.PREF_LIST_AVAILABLE_DISPLAYS,
950 "What displays should be available in the user interface?",
951 controlsManager, controlsPanel, cbxToCdMap);
952 }
953
954 protected void addDisplayWindowPreferences() {
955
956 Hashtable<String, JCheckBox> widgets = new Hashtable<String, JCheckBox>();
957 MapViewManager mappy = new MapViewManager(getIdv());
958
959 Object[][] legendObjects = {
960 { "Show Side Legend", MapViewManager.PREF_SHOWSIDELEGEND, Boolean.valueOf(mappy.getShowSideLegend()) },
961 { "Show Bottom Legend", MapViewManager.PREF_SHOWBOTTOMLEGEND, Boolean.valueOf(mappy.getShowBottomLegend()) }
962 };
963 JPanel legendPanel = makePrefPanel(legendObjects, widgets, getStore());
964 legendPanel.setBorder(BorderFactory.createTitledBorder("Legends"));
965
966 Object[][] navigationObjects = {
967 { "Show Earth Navigation Panel", MapViewManager.PREF_SHOWEARTHNAVPANEL, Boolean.valueOf(mappy.getShowEarthNavPanel()) },
968 { "Show Viewpoint Toolbar", MapViewManager.PREF_SHOWTOOLBAR + "perspective" },
969 { "Show Zoom/Pan Toolbar", MapViewManager.PREF_SHOWTOOLBAR + "zoompan" },
970 { "Show Undo/Redo Toolbar", MapViewManager.PREF_SHOWTOOLBAR + "undoredo" }
971 };
972 JPanel navigationPanel = makePrefPanel(navigationObjects, widgets, getStore());
973 navigationPanel.setBorder(BorderFactory.createTitledBorder("Navigation Toolbars"));
974
975 Object[][] panelObjects = {
976 { "Show Globe Background", MapViewManager.PREF_SHOWGLOBEBACKGROUND, Boolean.valueOf(getStore().get(MapViewManager.PREF_SHOWGLOBEBACKGROUND, false)) },
977 { "Show Wireframe Box", MapViewManager.PREF_WIREFRAME, Boolean.valueOf(mappy.getWireframe()) },
978 { "Show Cursor Readout", MapViewManager.PREF_SHOWCURSOR, Boolean.valueOf(mappy.getShowCursor()) },
979 { "Clip View At Box", MapViewManager.PREF_3DCLIP, Boolean.valueOf(mappy.getClipping()) },
980 { "Show Layer List in Panel", MapViewManager.PREF_SHOWDISPLAYLIST, Boolean.valueOf(mappy.getShowDisplayList()) },
981 { "Show Times In Panel", MapViewManager.PREF_ANIREADOUT, Boolean.valueOf(mappy.getAniReadout()) },
982 { "Show Map Display Scales", MapViewManager.PREF_SHOWSCALES, Boolean.valueOf(mappy.getLabelsVisible()) },
983 { "Show Transect Display Scales", MapViewManager.PREF_SHOWTRANSECTSCALES, Boolean.valueOf(mappy.getTransectLabelsVisible()) },
984 { "Show \"Please Wait\" Message", MapViewManager.PREF_WAITMSG, Boolean.valueOf(mappy.getWaitMessageVisible()) },
985 { "Reset Projection With New Data", MapViewManager.PREF_PROJ_USEFROMDATA }
986 };
987 JPanel panelPanel = makePrefPanel(panelObjects, widgets, getStore());
988 panelPanel.setBorder(BorderFactory.createTitledBorder("Panel Configuration"));
989
990 final JComponent[] globeBg =
991 GuiUtils.makeColorSwatchWidget(mappy.getGlobeBackgroundColorToUse(),
992 "Set Globe Background Color");
993 final JComponent[] bgComps =
994 GuiUtils.makeColorSwatchWidget(getStore().get(MapViewManager.PREF_BGCOLOR,
995 mappy.getBackground()), "Set Background Color");
996 final JComponent[] fgComps =
997 GuiUtils.makeColorSwatchWidget(getStore().get(MapViewManager.PREF_FGCOLOR,
998 mappy.getForeground()), "Set Foreground Color");
999 final JComponent[] border =
1000 GuiUtils.makeColorSwatchWidget(getStore().get(MapViewManager.PREF_BORDERCOLOR,
1001 Constants.MCV_BLUE_DARK), "Set Selected Panel Border Color");
1002
1003 JPanel colorPanel = GuiUtils.vbox(
1004 GuiUtils.hbox(
1005 McVGuiUtils.makeLabelRight("Globe Background:", Width.ONEHALF),
1006 GuiUtils.left(globeBg[0]),
1007 GAP_RELATED
1008 ),
1009 GuiUtils.hbox(
1010 McVGuiUtils.makeLabelRight("Background:", Width.ONEHALF),
1011 GuiUtils.left(bgComps[0]),
1012 GAP_RELATED
1013 ),
1014 GuiUtils.hbox(
1015 McVGuiUtils.makeLabelRight("Foreground:", Width.ONEHALF),
1016 GuiUtils.left(fgComps[0]),
1017 GAP_RELATED
1018 ),
1019 GuiUtils.hbox(
1020 McVGuiUtils.makeLabelRight("Selected Panel:", Width.ONEHALF),
1021 GuiUtils.left(border[0]),
1022 GAP_RELATED
1023 )
1024 );
1025
1026 colorPanel.setBorder(BorderFactory.createTitledBorder("Color Scheme"));
1027
1028 final FontSelector fontSelector = new FontSelector(FontSelector.COMBOBOX_UI, false, false);
1029 Font f = getStore().get(MapViewManager.PREF_DISPLAYLISTFONT, mappy.getDisplayListFont());
1030 fontSelector.setFont(f);
1031 final GuiUtils.ColorSwatch dlColorWidget =
1032 new GuiUtils.ColorSwatch(getStore().get(MapViewManager.PREF_DISPLAYLISTCOLOR,
1033 mappy.getDisplayListColor()), "Set Display List Color");
1034
1035 JPanel fontPanel = GuiUtils.vbox(
1036 GuiUtils.hbox(
1037 McVGuiUtils.makeLabelRight("Font:", Width.ONEHALF),
1038 GuiUtils.left(fontSelector.getComponent()),
1039 GAP_RELATED
1040 ),
1041 GuiUtils.hbox(
1042 McVGuiUtils.makeLabelRight("Color:", Width.ONEHALF),
1043 GuiUtils.left(GuiUtils.hbox(dlColorWidget, dlColorWidget.getClearButton(), GAP_RELATED)),
1044 GAP_RELATED
1045 )
1046 );
1047 fontPanel.setBorder(BorderFactory.createTitledBorder("Layer List Properties"));
1048
1049 final JComboBox projBox = new JComboBox();
1050 GuiUtils.setListData(projBox, mappy.getProjectionList().toArray());
1051 Object defaultProj = mappy.getDefaultProjection();
1052 if (defaultProj != null) projBox.setSelectedItem(defaultProj);
1053 JPanel projPanel = GuiUtils.left(projBox);
1054 projPanel.setBorder(BorderFactory.createTitledBorder("Default Projection"));
1055
1056 JPanel outerPanel = new JPanel();
1057
1058 // Outer panel layout
1059 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(outerPanel);
1060 outerPanel.setLayout(layout);
1061 layout.setHorizontalGroup(
1062 layout.createParallelGroup(LEADING)
1063 .addGroup(layout.createSequentialGroup()
1064 .addContainerGap()
1065 .addGroup(layout.createParallelGroup(LEADING)
1066 .addComponent(navigationPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1067 .addComponent(panelPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1068 .addGap(GAP_RELATED)
1069 .addGroup(layout.createParallelGroup(LEADING)
1070 .addComponent(colorPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1071 .addComponent(legendPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1072 .addComponent(fontPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1073 .addComponent(projPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1074 .addContainerGap())
1075 );
1076 layout.setVerticalGroup(
1077 layout.createParallelGroup(LEADING)
1078 .addGroup(layout.createSequentialGroup()
1079 .addContainerGap()
1080 .addGroup(layout.createParallelGroup(LEADING, false)
1081 .addComponent(navigationPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1082 .addComponent(legendPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1083 .addPreferredGap(RELATED)
1084 .addGroup(layout.createParallelGroup(LEADING, false)
1085 .addGroup(layout.createSequentialGroup()
1086 .addComponent(colorPanel, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
1087 .addPreferredGap(RELATED)
1088 .addComponent(fontPanel, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
1089 .addPreferredGap(RELATED)
1090 .addComponent(projPanel, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE))
1091 .addComponent(panelPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1092 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
1093 );
1094
1095 PreferenceManager miscManager = new PreferenceManager() {
1096 @SuppressWarnings("unchecked") // applyWidgets called the same way the IDV does it.
1097 public void applyPreference(XmlObjectStore theStore, Object data) {
1098 IdvPreferenceManager.applyWidgets((Hashtable)data, theStore);
1099 theStore.put(MapViewManager.PREF_PROJ_DFLT, projBox.getSelectedItem());
1100 theStore.put(MapViewManager.PREF_BGCOLOR, bgComps[0].getBackground());
1101 theStore.put(MapViewManager.PREF_FGCOLOR, fgComps[0].getBackground());
1102 theStore.put(MapViewManager.PREF_BORDERCOLOR, border[0].getBackground());
1103 theStore.put(MapViewManager.PREF_DISPLAYLISTFONT, fontSelector.getFont());
1104 theStore.put(MapViewManager.PREF_DISPLAYLISTCOLOR, dlColorWidget.getSwatchColor());
1105 theStore.put(MapViewManager.PREF_GLOBEBACKGROUND, globeBg[0].getBackground());
1106 ViewManager.setHighlightBorder(border[0].getBackground());
1107 }
1108 };
1109
1110 this.add(Constants.PREF_LIST_VIEW, "Display Window Preferences", miscManager, outerPanel, widgets);
1111 }
1112
1113 /**
1114 * Creates and adds the basic preference panel.
1115 */
1116 protected void addMcVPreferences() {
1117
1118 Hashtable<String, Component> widgets = new Hashtable<String, Component>();
1119 McIDASV mcv = (McIDASV)getIdv();
1120 StateManager sm = (edu.wisc.ssec.mcidasv.StateManager)mcv.getStateManager();
1121
1122 PreferenceManager basicManager = new PreferenceManager() {
1123 @SuppressWarnings("unchecked") // IDV-style call to applyWidgets.
1124 public void applyPreference(XmlObjectStore theStore, Object data) {
1125 applyWidgets((Hashtable)data, theStore);
1126 getIdv().getIdvUIManager().setDateFormat();
1127 getIdv().initCacheManager();
1128 applyEventPreferences(theStore);
1129 }
1130 };
1131
1132 boolean isPrerelease = sm.getIsPrerelease();
1133 Object[][] generalObjects = {
1134 { "Show Help Tips on start", HelpTipDialog.PREF_HELPTIPSHOW },
1135 { "Show Data Explorer on start", PREF_SHOWDASHBOARD, Boolean.TRUE },
1136 { "Check for new version and notice on start", Constants.PREF_VERSION_CHECK, Boolean.TRUE },
1137 { "Include prereleases in version check", Constants.PREF_PRERELEASE_CHECK, isPrerelease },
1138 { "Confirm before exiting", PREF_SHOWQUITCONFIRM },
1139 { "Automatically save default layout at exit", Constants.PREF_AUTO_SAVE_DEFAULT_LAYOUT, Boolean.FALSE },
1140 { "Save visibility of Data Explorer", Constants.PREF_SAVE_DASHBOARD_VIZ, Boolean.FALSE },
1141 { "Confirm removal of all data sources", PREF_CONFIRM_REMOVE_DATA, Boolean.TRUE },
1142 { "Confirm removal of all layers", PREF_CONFIRM_REMOVE_LAYERS, Boolean.TRUE },
1143 { "Confirm removal of all layers and data sources", PREF_CONFIRM_REMOVE_BOTH, Boolean.TRUE },
1144 };
1145 final IdvObjectStore store = getStore();
1146 JPanel generalPanel = makePrefPanel(generalObjects, widgets, store);
1147 generalPanel.setBorder(BorderFactory.createTitledBorder("General"));
1148
1149 // Turn what used to be a set of checkboxes into a corresponding menu selection
1150 // The options have to be checkboxes in the widget collection
1151 // That way "applyWidgets" will work as expected
1152 boolean shouldRemove = store.get(PREF_OPEN_REMOVE, false);
1153 boolean shouldMerge = store.get(PREF_OPEN_MERGE, false);
1154 final JCheckBox shouldRemoveCbx = new JCheckBox("You shouldn't see this", shouldRemove);
1155 final JCheckBox shouldMergeCbx = new JCheckBox("You shouldn't see this", shouldMerge);
1156 widgets.put(PREF_OPEN_REMOVE, shouldRemoveCbx);
1157 widgets.put(PREF_OPEN_MERGE, shouldMergeCbx);
1158
1159 final JComboBox loadComboBox = new JComboBox(loadComboOptions);
1160 loadComboBox.addActionListener(new ActionListener() {
1161 public void actionPerformed(ActionEvent e) {
1162 switch (((JComboBox)e.getSource()).getSelectedIndex()) {
1163 case 0:
1164 shouldRemoveCbx.setSelected(false);
1165 shouldMergeCbx.setSelected(false);
1166 break;
1167 case 1:
1168 shouldRemoveCbx.setSelected(true);
1169 shouldMergeCbx.setSelected(false);
1170 break;
1171 case 2:
1172 shouldRemoveCbx.setSelected(false);
1173 shouldMergeCbx.setSelected(true);
1174 break;
1175 case 3:
1176 shouldRemoveCbx.setSelected(true);
1177 shouldMergeCbx.setSelected(true);
1178 break;
1179 }
1180 }
1181 });
1182
1183 // update the bundle loading options upon visibility changes.
1184 loadComboBox.addPropertyChangeListener(new PropertyChangeListener() {
1185 public void propertyChange(final PropertyChangeEvent e) {
1186 String prop = e.getPropertyName();
1187 if (!"ancestor".equals(prop) && !"Frame.active".equals(prop)) {
1188 return;
1189 }
1190
1191 boolean remove = store.get(PREF_OPEN_REMOVE, false);
1192 boolean merge = store.get(PREF_OPEN_MERGE, false);
1193
1194 if (!remove) {
1195 if (!merge) {
1196 loadComboBox.setSelectedIndex(0);
1197 } else {
1198 loadComboBox.setSelectedIndex(2);
1199 }
1200 }
1201 else {
1202 if (!merge) {
1203 loadComboBox.setSelectedIndex(1);
1204 } else {
1205 loadComboBox.setSelectedIndex(3);
1206 }
1207 }
1208 }
1209 });
1210
1211 if (!shouldRemove) {
1212 if (!shouldMerge) {
1213 loadComboBox.setSelectedIndex(0);
1214 } else {
1215 loadComboBox.setSelectedIndex(2);
1216 }
1217 }
1218 else {
1219 if (!shouldMerge) {
1220 loadComboBox.setSelectedIndex(1);
1221 } else {
1222 loadComboBox.setSelectedIndex(3);
1223 }
1224 }
1225
1226 Object[][] bundleObjects = {
1227 { "Prompt when opening bundles", PREF_OPEN_ASK },
1228 { "Prompt for location for zipped data", PREF_ZIDV_ASK }
1229 };
1230 JPanel bundlePanelInner = makePrefPanel(bundleObjects, widgets, getStore());
1231 JPanel bundlePanel = GuiUtils.topCenter(loadComboBox, bundlePanelInner);
1232 bundlePanel.setBorder(BorderFactory.createTitledBorder("When Opening a Bundle"));
1233
1234 Object[][] layerObjects = {
1235 { "Show windows when they are created", PREF_SHOWCONTROLWINDOW },
1236 { "Use fast rendering", PREF_FAST_RENDER, Boolean.FALSE, "<html>Turn this on for better performance at the risk of having funky displays</html>" },
1237 { "Auto-select data when loading a template", IdvConstants.PREF_AUTOSELECTDATA, Boolean.FALSE, "<html>When loading a display template should the data be automatically selected</html>" },
1238 };
1239 JPanel layerPanel = makePrefPanel(layerObjects, widgets, getStore());
1240 layerPanel.setBorder(BorderFactory.createTitledBorder("Layer Controls"));
1241
1242 Object[][] layerclosedObjects = {
1243 { "Remove the display", DisplayControl.PREF_REMOVEONWINDOWCLOSE, Boolean.FALSE },
1244 { "Remove standalone displays", DisplayControl.PREF_STANDALONE_REMOVEONCLOSE, Boolean.FALSE }
1245 };
1246 JPanel layerclosedPanel = makePrefPanel(layerclosedObjects, widgets, getStore());
1247 layerclosedPanel.setBorder(BorderFactory.createTitledBorder("When Layer Control Window is Closed"));
1248
1249 JPanel outerPanel = new JPanel();
1250
1251 // Outer panel layout
1252 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(outerPanel);
1253 outerPanel.setLayout(layout);
1254 layout.setHorizontalGroup(
1255 layout.createParallelGroup(LEADING)
1256 .addGroup(layout.createSequentialGroup()
1257 .addContainerGap()
1258 .addGroup(layout.createParallelGroup(TRAILING)
1259 .addComponent(generalPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1260 .addComponent(layerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1261 .addGap(GAP_RELATED)
1262 .addGroup(layout.createParallelGroup(LEADING)
1263 .addComponent(bundlePanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1264 .addComponent(layerclosedPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1265 .addContainerGap())
1266 );
1267 layout.setVerticalGroup(
1268 layout.createParallelGroup(LEADING)
1269 .addGroup(layout.createSequentialGroup()
1270 .addContainerGap()
1271 .addGroup(layout.createParallelGroup(LEADING, false)
1272 .addComponent(bundlePanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1273 .addComponent(generalPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1274 .addPreferredGap(RELATED)
1275 .addGroup(layout.createParallelGroup(LEADING, false)
1276 .addComponent(layerclosedPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1277 .addComponent(layerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1278 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
1279 );
1280
1281 this.add(Constants.PREF_LIST_GENERAL, "General Preferences", basicManager, outerPanel, widgets);
1282 }
1283
1284 /**
1285 * <p>This determines whether the IDV should do a remove display and data
1286 * before a bundle is loaded. It returns a 2 element boolean array. The
1287 * first element is whether the open should take place at all. The second
1288 * element determines whether displays and data should be removed before
1289 * the load.</p>
1290 *
1291 * <p>Overridden by McIDAS-V so that we can ask the user whether or not we
1292 * should limit the number of new windows a bundle can create.</p>
1293 *
1294 * @param name Bundle name - may be null.
1295 *
1296 * @return Element 0: did user hit cancel; Element 1: Should remove data
1297 * and displays; Element 2: limit new windows.
1298 *
1299 * @see IdvPreferenceManager#getDoRemoveBeforeOpening(String)
1300 */
1301 @Override public boolean[] getDoRemoveBeforeOpening(String name) {
1302 IdvObjectStore store = getStore();
1303 boolean shouldAsk = store.get(PREF_OPEN_ASK, true);
1304 boolean shouldRemove = store.get(PREF_OPEN_REMOVE, false);
1305 boolean shouldMerge = store.get(PREF_OPEN_MERGE, false);
1306
1307 if (shouldAsk) {
1308 JComboBox loadComboBox = new JComboBox(loadComboOptions);
1309 JCheckBox preferenceCbx = new JCheckBox("Save as default preference", true);
1310 JCheckBox askCbx = new JCheckBox("Don't show this window again", false);
1311
1312 if (!shouldRemove) {
1313 if (!shouldMerge) {
1314 loadComboBox.setSelectedIndex(0);
1315 } else {
1316 loadComboBox.setSelectedIndex(2);
1317 }
1318 }
1319 else {
1320 if (!shouldMerge) {
1321 loadComboBox.setSelectedIndex(1);
1322 } else {
1323 loadComboBox.setSelectedIndex(3);
1324 }
1325 }
1326
1327 JPanel inner = new JPanel();
1328 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(inner);
1329 inner.setLayout(layout);
1330 layout.setHorizontalGroup(
1331 layout.createParallelGroup(LEADING)
1332 .addGroup(layout.createSequentialGroup()
1333 .addContainerGap()
1334 .addGroup(layout.createParallelGroup(LEADING)
1335 .addComponent(loadComboBox, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1336 .addComponent(preferenceCbx)
1337 .addComponent(askCbx))
1338 .addContainerGap())
1339 );
1340 layout.setVerticalGroup(
1341 layout.createParallelGroup(LEADING)
1342 .addGroup(layout.createSequentialGroup()
1343 .addContainerGap()
1344 .addComponent(loadComboBox, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
1345 .addPreferredGap(RELATED)
1346 .addComponent(preferenceCbx)
1347 .addPreferredGap(RELATED)
1348 .addComponent(askCbx)
1349 .addContainerGap())
1350 );
1351
1352 if (!GuiUtils.showOkCancelDialog(null, "Open bundle", inner, null)) {
1353 return new boolean[] { false, false, false };
1354 }
1355
1356 switch (loadComboBox.getSelectedIndex()) {
1357 case 0: // new windows
1358 shouldRemove = false;
1359 shouldMerge = false;
1360 break;
1361 case 1: // merge with existing tabs
1362 shouldRemove = true;
1363 shouldMerge = false;
1364 break;
1365 case 2: // add new tab(s) to current
1366 shouldRemove = false;
1367 shouldMerge = true;
1368 break;
1369 case 3: // replace session
1370 shouldRemove = true;
1371 shouldMerge = true;
1372 break;
1373 }
1374
1375 // Save these as default preference if the user wants to
1376 if (preferenceCbx.isSelected()) {
1377 store.put(PREF_OPEN_REMOVE, shouldRemove);
1378 store.put(PREF_OPEN_MERGE, shouldMerge);
1379 }
1380 store.put(PREF_OPEN_ASK, !askCbx.isSelected());
1381 }
1382 return new boolean[] { true, shouldRemove, shouldMerge };
1383 }
1384
1385 /**
1386 * Creates and adds the formats and data preference panel.
1387 */
1388 protected void addFormatDataPreferences() {
1389 Hashtable<String, Component> widgets = new Hashtable<String, Component>();
1390
1391 JPanel formatPanel = new JPanel();
1392 formatPanel.setBorder(BorderFactory.createTitledBorder("Formats"));
1393
1394 // Date stuff
1395 JLabel dateLabel = McVGuiUtils.makeLabelRight("Date Format:", Width.ONEHALF);
1396
1397 String dateFormat = getStore().get(PREF_DATE_FORMAT, DEFAULT_DATE_FORMAT);
1398
1399 if (!dateFormats.contains(dateFormat)) {
1400 dateFormats.add(dateFormat);
1401 }
1402
1403 final JComboBox dateComboBox = McVGuiUtils.makeComboBox(dateFormats, dateFormat, Width.DOUBLE);
1404 widgets.put(PREF_DATE_FORMAT, dateComboBox);
1405
1406 JComponent dateHelpButton = getIdv().makeHelpButton("idv.tools.preferences.dateformat");
1407
1408 JLabel dateExLabel = new JLabel("");
1409
1410 // Time stuff
1411 JLabel timeLabel = McVGuiUtils.makeLabelRight("Time Zone:", Width.ONEHALF);
1412
1413 String timeString = getStore().get(PREF_TIMEZONE, DEFAULT_TIMEZONE);
1414 String[] zoneStrings = TimeZone.getAvailableIDs();
1415 Arrays.sort(zoneStrings);
1416
1417 final JComboBox timeComboBox = McVGuiUtils.makeComboBox(zoneStrings, timeString, Width.DOUBLE);
1418 widgets.put(PREF_TIMEZONE, timeComboBox);
1419
1420 JComponent timeHelpButton = getIdv().makeHelpButton("idv.tools.preferences.dateformat");
1421
1422 JLabel timeExLabel = new JLabel("");
1423
1424 try {
1425 dateExLabel.setText("ex: " + new DateTime().toString());
1426 } catch (Exception ve) {
1427 dateExLabel.setText("Can't format date: " + ve);
1428 }
1429
1430 ObjectListener timeLabelListener = new ObjectListener(dateExLabel) {
1431 public void actionPerformed(ActionEvent ae) {
1432 JLabel label = (JLabel) theObject;
1433 String format = dateComboBox.getSelectedItem().toString();
1434 String zone = timeComboBox.getSelectedItem().toString();
1435 try {
1436 TimeZone tz = TimeZone.getTimeZone(zone);
1437 // hack to make it the DateTime default
1438 if (format.equals(DEFAULT_DATE_FORMAT)) {
1439 if (zone.equals(DEFAULT_TIMEZONE)) {
1440 format = DateTime.DEFAULT_TIME_FORMAT + "'Z'";
1441 }
1442 }
1443 label.setText("ex: " + new DateTime().formattedString(format, tz));
1444 } catch (Exception ve) {
1445 label.setText("Invalid format or time zone");
1446 LogUtil.userMessage("Invalid format or time zone");
1447 }
1448 }
1449 };
1450 dateComboBox.addActionListener(timeLabelListener);
1451 timeComboBox.addActionListener(timeLabelListener);
1452
1453 // Lat/Lon stuff
1454 JLabel latlonLabel = McVGuiUtils.makeLabelRight("Lat/Lon Format:", Width.ONEHALF);
1455
1456 String latlonFormatString = getStore().get(PREF_LATLON_FORMAT, "##0.0");
1457 JComboBox latlonComboBox = McVGuiUtils.makeComboBox(defaultLatLonFormats, latlonFormatString, Width.DOUBLE);
1458 widgets.put(PREF_LATLON_FORMAT, latlonComboBox);
1459
1460 JComponent latlonHelpButton = getIdv().makeHelpButton("idv.tools.preferences.latlonformat");
1461
1462 JLabel latlonExLabel = new JLabel("");
1463
1464 try {
1465 latlonFormat.applyPattern(latlonFormatString);
1466 latlonExLabel.setText("ex: " + latlonFormat.format(latlonValue));
1467 } catch (IllegalArgumentException iae) {
1468 latlonExLabel.setText("Bad format: " + latlonFormatString);
1469 }
1470 latlonComboBox.addActionListener(new ObjectListener(latlonExLabel) {
1471 public void actionPerformed(final ActionEvent ae) {
1472 JLabel label = (JLabel)theObject;
1473 JComboBox box = (JComboBox)ae.getSource();
1474 String pattern = box.getSelectedItem().toString();
1475 try {
1476 latlonFormat.applyPattern(pattern);
1477 label.setText("ex: " + latlonFormat.format(latlonValue));
1478 } catch (IllegalArgumentException iae) {
1479 label.setText("bad pattern: " + pattern);
1480 LogUtil.userMessage("Bad format:" + pattern);
1481 }
1482 }
1483 });
1484
1485 // Probe stuff
1486 JLabel probeLabel = McVGuiUtils.makeLabelRight("Probe Format:", Width.ONEHALF);
1487
1488 String probeFormat = getStore().get(DisplayControl.PREF_PROBEFORMAT, DisplayControl.DEFAULT_PROBEFORMAT);
1489 // List probeFormatsList = Misc.newList(DisplayControl.DEFAULT_PROBEFORMAT,
1490 // "%rawvalue% [%rawunit%]", "%value%", "%rawvalue%", "%value% <i>%unit%</i>");
1491 JComboBox probeComboBox = McVGuiUtils.makeComboBox(probeFormatsList, probeFormat, Width.DOUBLE);
1492 widgets.put(DisplayControl.PREF_PROBEFORMAT, probeComboBox);
1493
1494 JComponent probeHelpButton = getIdv().makeHelpButton("idv.tools.preferences.probeformat");
1495
1496 // Distance stuff
1497 JLabel distanceLabel = McVGuiUtils.makeLabelRight("Distance Unit:", Width.ONEHALF);
1498
1499 Unit distanceUnit = null;
1500 try {
1501 distanceUnit = ucar.visad.Util.parseUnit(getStore().get(PREF_DISTANCEUNIT, "km"));
1502 } catch (Exception exc) {}
1503 JComboBox distanceComboBox = getIdv().getDisplayConventions().makeUnitBox(distanceUnit, null);
1504 McVGuiUtils.setComponentWidth(distanceComboBox, Width.DOUBLE);
1505 widgets.put(PREF_DISTANCEUNIT, distanceComboBox);
1506
1507 // Format panel layout
1508 javax.swing.GroupLayout formatLayout = new javax.swing.GroupLayout(formatPanel);
1509 formatPanel.setLayout(formatLayout);
1510 formatLayout.setHorizontalGroup(
1511 formatLayout.createParallelGroup(LEADING)
1512 .addGroup(formatLayout.createSequentialGroup()
1513 .addContainerGap()
1514 .addGroup(formatLayout.createParallelGroup(LEADING)
1515 .addGroup(formatLayout.createSequentialGroup()
1516 .addComponent(dateLabel)
1517 .addGap(GAP_RELATED)
1518 .addComponent(dateComboBox)
1519 .addGap(GAP_RELATED)
1520 .addComponent(dateHelpButton)
1521 .addGap(GAP_RELATED)
1522 .addComponent(dateExLabel))
1523 .addGroup(formatLayout.createSequentialGroup()
1524 .addComponent(timeLabel)
1525 .addGap(GAP_RELATED)
1526 .addComponent(timeComboBox))
1527 .addGroup(formatLayout.createSequentialGroup()
1528 .addComponent(latlonLabel)
1529 .addGap(GAP_RELATED)
1530 .addComponent(latlonComboBox)
1531 .addGap(GAP_RELATED)
1532 .addComponent(latlonHelpButton)
1533 .addGap(GAP_RELATED)
1534 .addComponent(latlonExLabel))
1535 .addGroup(formatLayout.createSequentialGroup()
1536 .addComponent(probeLabel)
1537 .addGap(GAP_RELATED)
1538 .addComponent(probeComboBox)
1539 .addGap(GAP_RELATED)
1540 .addComponent(probeHelpButton))
1541 .addGroup(formatLayout.createSequentialGroup()
1542 .addComponent(distanceLabel)
1543 .addGap(GAP_RELATED)
1544 .addComponent(distanceComboBox)))
1545 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
1546 );
1547 formatLayout.setVerticalGroup(
1548 formatLayout.createParallelGroup(LEADING)
1549 .addGroup(formatLayout.createSequentialGroup()
1550 .addGroup(formatLayout.createParallelGroup(BASELINE)
1551 .addComponent(dateComboBox)
1552 .addComponent(dateLabel)
1553 .addComponent(dateHelpButton)
1554 .addComponent(dateExLabel))
1555 .addPreferredGap(RELATED)
1556 .addGroup(formatLayout.createParallelGroup(BASELINE)
1557 .addComponent(timeComboBox)
1558 .addComponent(timeLabel))
1559 .addPreferredGap(RELATED)
1560 .addGroup(formatLayout.createParallelGroup(BASELINE)
1561 .addComponent(latlonComboBox)
1562 .addComponent(latlonLabel)
1563 .addComponent(latlonHelpButton)
1564 .addComponent(latlonExLabel))
1565 .addPreferredGap(RELATED)
1566 .addGroup(formatLayout.createParallelGroup(BASELINE)
1567 .addComponent(probeComboBox)
1568 .addComponent(probeLabel)
1569 .addComponent(probeHelpButton))
1570 .addPreferredGap(RELATED)
1571 .addGroup(formatLayout.createParallelGroup(BASELINE)
1572 .addComponent(distanceComboBox)
1573 .addComponent(distanceLabel))
1574 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
1575 );
1576
1577 JPanel dataPanel = new JPanel();
1578 dataPanel.setBorder(BorderFactory.createTitledBorder("Data"));
1579
1580 // Sampling stuff
1581 JLabel sampleLabel = McVGuiUtils.makeLabelRight("Sampling Mode:", Width.ONEHALF);
1582
1583 String sampleValue = getStore().get(PREF_SAMPLINGMODE, DisplayControlImpl.WEIGHTED_AVERAGE);
1584 JRadioButton sampleWA = new JRadioButton(DisplayControlImpl.WEIGHTED_AVERAGE,
1585 sampleValue.equals(DisplayControlImpl.WEIGHTED_AVERAGE));
1586
1587 sampleWA.setToolTipText("Use a weighted average sampling");
1588 JRadioButton sampleNN = new JRadioButton(DisplayControlImpl.NEAREST_NEIGHBOR,
1589 sampleValue.equals(DisplayControlImpl.NEAREST_NEIGHBOR));
1590
1591 sampleNN.setToolTipText("Use a nearest neighbor sampling");
1592 GuiUtils.buttonGroup(sampleWA, sampleNN);
1593 widgets.put("WEIGHTED_AVERAGE", sampleWA);
1594 widgets.put("NEAREST_NEIGHBOR", sampleNN);
1595
1596 // Pressure stuff
1597 JLabel verticalLabel = McVGuiUtils.makeLabelRight("Pressure to Height:", Width.ONEHALF);
1598
1599 String verticalValue = getStore().get(PREF_VERTICALCS, DataUtil.STD_ATMOSPHERE);
1600 JRadioButton verticalSA = new JRadioButton("Standard Atmosphere", verticalValue.equals(DataUtil.STD_ATMOSPHERE));
1601 verticalSA.setToolTipText("Use a standard atmosphere height approximation");
1602 JRadioButton verticalV5D = new JRadioButton("Vis5D", verticalValue.equals(DataUtil.VIS5D_VERTICALCS));
1603 verticalV5D.setToolTipText("Use the Vis5D vertical transformation");
1604 GuiUtils.buttonGroup(verticalSA, verticalV5D);
1605 widgets.put(DataUtil.STD_ATMOSPHERE, verticalSA);
1606 widgets.put(DataUtil.VIS5D_VERTICALCS, verticalV5D);
1607
1608 // Caching stuff
1609 JLabel cacheLabel = McVGuiUtils.makeLabelRight("Caching:", Width.ONEHALF);
1610
1611 JCheckBox cacheCheckBox = new JCheckBox("Cache Data in Memory", getStore().get(PREF_DOCACHE, true));
1612 widgets.put(PREF_DOCACHE, cacheCheckBox);
1613
1614 JLabel cacheEmptyLabel = McVGuiUtils.makeLabelRight("", Width.ONEHALF);
1615
1616 JTextField cacheTextField = McVGuiUtils.makeTextField(Misc.format(getStore().get(PREF_CACHESIZE, 20.0)));
1617 JComponent cacheTextFieldComponent = GuiUtils.hbox(new JLabel("Disk Cache Size: "), cacheTextField, new JLabel(" megabytes"));
1618 widgets.put(PREF_CACHESIZE, cacheTextField);
1619
1620 // Image stuff
1621 JLabel imageLabel = McVGuiUtils.makeLabelRight("Max Image Size:", Width.ONEHALF);
1622
1623 JTextField imageField = McVGuiUtils.makeTextField(Misc.format(getStore().get(PREF_MAXIMAGESIZE, -1)));
1624 JComponent imageFieldComponent = GuiUtils.hbox(imageField, new JLabel(" pixels (-1 = no limit)"));
1625 widgets.put(PREF_MAXIMAGESIZE, imageField);
1626
1627 // Grid stuff
1628 JLabel gridLabel = McVGuiUtils.makeLabelRight("Grid Threshold:", Width.ONEHALF);
1629
1630 JTextField gridField = McVGuiUtils.makeTextField(Misc.format(getStore().get(PREF_FIELD_CACHETHRESHOLD, 1000000.)));
1631 JComponent gridFieldComponent = GuiUtils.hbox(gridField, new JLabel(" bytes (Cache grids larger than this to disk)"));
1632 widgets.put(PREF_FIELD_CACHETHRESHOLD, gridField);
1633
1634 // Data panel layout
1635 javax.swing.GroupLayout dataLayout = new javax.swing.GroupLayout(dataPanel);
1636 dataPanel.setLayout(dataLayout);
1637 dataLayout.setHorizontalGroup(
1638 dataLayout.createParallelGroup(LEADING)
1639 .addGroup(dataLayout.createSequentialGroup()
1640 .addContainerGap()
1641 .addGroup(dataLayout.createParallelGroup(LEADING)
1642 .addGroup(dataLayout.createSequentialGroup()
1643 .addComponent(sampleLabel)
1644 .addGap(GAP_RELATED)
1645 .addComponent(sampleWA)
1646 .addGap(GAP_RELATED)
1647 .addComponent(sampleNN))
1648 .addGroup(dataLayout.createSequentialGroup()
1649 .addComponent(verticalLabel)
1650 .addGap(GAP_RELATED)
1651 .addComponent(verticalSA)
1652 .addGap(GAP_RELATED)
1653 .addComponent(verticalV5D))
1654 .addGroup(dataLayout.createSequentialGroup()
1655 .addComponent(cacheLabel)
1656 .addGap(GAP_RELATED)
1657 .addComponent(cacheCheckBox))
1658 .addGroup(dataLayout.createSequentialGroup()
1659 .addComponent(cacheEmptyLabel)
1660 .addGap(GAP_RELATED)
1661 .addComponent(cacheTextFieldComponent))
1662 .addGroup(dataLayout.createSequentialGroup()
1663 .addComponent(imageLabel)
1664 .addGap(GAP_RELATED)
1665 .addComponent(imageFieldComponent))
1666 .addGroup(dataLayout.createSequentialGroup()
1667 .addComponent(gridLabel)
1668 .addGap(GAP_RELATED)
1669 .addComponent(gridFieldComponent)))
1670 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
1671 );
1672 dataLayout.setVerticalGroup(
1673 dataLayout.createParallelGroup(LEADING)
1674 .addGroup(dataLayout.createSequentialGroup()
1675 .addGroup(dataLayout.createParallelGroup(BASELINE)
1676 .addComponent(sampleLabel)
1677 .addComponent(sampleWA)
1678 .addComponent(sampleNN))
1679 .addPreferredGap(RELATED)
1680 .addGroup(dataLayout.createParallelGroup(BASELINE)
1681 .addComponent(verticalLabel)
1682 .addComponent(verticalSA)
1683 .addComponent(verticalV5D))
1684 .addPreferredGap(RELATED)
1685 .addGroup(dataLayout.createParallelGroup(BASELINE)
1686 .addComponent(cacheLabel)
1687 .addComponent(cacheCheckBox))
1688 .addPreferredGap(RELATED)
1689 .addGroup(dataLayout.createParallelGroup(BASELINE)
1690 .addComponent(cacheEmptyLabel)
1691 .addComponent(cacheTextFieldComponent))
1692 .addPreferredGap(RELATED)
1693 .addGroup(dataLayout.createParallelGroup(BASELINE)
1694 .addComponent(imageLabel)
1695 .addComponent(imageFieldComponent))
1696 .addPreferredGap(RELATED)
1697 .addGroup(dataLayout.createParallelGroup(BASELINE)
1698 .addComponent(gridLabel)
1699 .addComponent(gridFieldComponent))
1700 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
1701 );
1702
1703 JPanel outerPanel = new JPanel();
1704
1705 // Outer panel layout
1706 javax.swing.GroupLayout layout = new javax.swing.GroupLayout(outerPanel);
1707 outerPanel.setLayout(layout);
1708 layout.setHorizontalGroup(
1709 layout.createParallelGroup(LEADING)
1710 .addGroup(layout.createSequentialGroup()
1711 .addContainerGap()
1712 .addGroup(layout.createParallelGroup(LEADING)
1713 .addComponent(formatPanel, TRAILING, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
1714 .addComponent(dataPanel, TRAILING, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
1715 .addContainerGap())
1716 );
1717 layout.setVerticalGroup(
1718 layout.createParallelGroup(LEADING)
1719 .addGroup(layout.createSequentialGroup()
1720 .addContainerGap()
1721 .addComponent(formatPanel, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
1722 .addGap(GAP_UNRELATED)
1723 .addComponent(dataPanel, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
1724 .addContainerGap(DEFAULT_SIZE, Short.MAX_VALUE))
1725 );
1726
1727 PreferenceManager formatsManager = new PreferenceManager() {
1728 public void applyPreference(XmlObjectStore theStore, Object data) {
1729 IdvPreferenceManager.applyWidgets((Hashtable)data, theStore);
1730
1731 // if we ever need to add formats and data prefs, here's where
1732 // they get saved off (unless we override applyWidgets).
1733 }
1734 };
1735
1736 this.add(Constants.PREF_LIST_FORMATS_DATA, "", formatsManager, outerPanel, widgets);
1737 }
1738
1739 /**
1740 * Add in the user preference tab for the choosers to show.
1741 */
1742 protected void addChooserPreferences() {
1743 Hashtable<String, JCheckBox> choosersData = new Hashtable<String, JCheckBox>();
1744 List<JPanel> compList = new ArrayList<JPanel>();
1745
1746 Boolean choosersAll =
1747 (Boolean) getIdv().getPreference(PROP_CHOOSERS_ALL, Boolean.TRUE);
1748
1749 final List<String[]> choosers = getChooserData();
1750
1751 final List<JCheckBox> choosersList = new ArrayList<JCheckBox>();
1752
1753 final JRadioButton useAllBtn = new JRadioButton("Use all data sources",
1754 choosersAll.booleanValue());
1755 final JRadioButton useTheseBtn =
1756 new JRadioButton("Use selected data sources:",
1757 !choosersAll.booleanValue());
1758
1759 GuiUtils.buttonGroup(useAllBtn, useTheseBtn);
1760
1761 final List<CheckboxCategoryPanel> chooserPanels =
1762 new ArrayList<CheckboxCategoryPanel>();
1763
1764 final Hashtable<String, CheckboxCategoryPanel> chooserMap =
1765 new Hashtable<String, CheckboxCategoryPanel>();
1766
1767 // create the checkbox + chooser name that'll show up in the preference
1768 // panel.
1769 for (String[] cs : choosers) {
1770 final String chooserCategory = getChooserCategory(cs[1]);
1771 String chooserShortName = getChooserShortName(cs[1]);
1772
1773 CheckboxCategoryPanel chooserPanel =
1774 (CheckboxCategoryPanel) chooserMap.get(chooserCategory);
1775
1776 if (chooserPanel == null) {
1777 chooserPanel = new CheckboxCategoryPanel(chooserCategory, false);
1778 chooserPanels.add(chooserPanel);
1779 chooserMap.put(chooserCategory, chooserPanel);
1780 compList.add(chooserPanel.getTopPanel());
1781 compList.add(chooserPanel);
1782 }
1783
1784 JCheckBox cbx = new JCheckBox(chooserShortName, shouldShowChooser(cs[0], true));
1785 choosersData.put(cs[0], cbx);
1786 chooserPanel.addItem(cbx);
1787 chooserPanel.add(GuiUtils.inset(cbx, new Insets(0, 20, 0, 0)));
1788 }
1789
1790 for (CheckboxCategoryPanel cbcp : chooserPanels)
1791 cbcp.checkVisCbx();
1792
1793 // handle the user opting to enable all choosers.
1794 final JButton allOn = new JButton("All on");
1795 allOn.addActionListener(new ActionListener() {
1796 public void actionPerformed(ActionEvent ae) {
1797 for (CheckboxCategoryPanel cbcp : chooserPanels)
1798 cbcp.toggleAll(true);
1799 }
1800 });
1801
1802 // handle the user opting to disable all choosers.
1803 final JButton allOff = new JButton("All off");
1804 allOff.addActionListener(new ActionListener() {
1805 public void actionPerformed(ActionEvent ae) {
1806 for (CheckboxCategoryPanel cbcp : chooserPanels)
1807 cbcp.toggleAll(false);
1808 }
1809 });
1810
1811 final JPanel cbPanel = GuiUtils.top(GuiUtils.vbox(compList));
1812
1813 JScrollPane cbScroller = new JScrollPane(cbPanel);
1814 cbScroller.getVerticalScrollBar().setUnitIncrement(10);
1815 cbScroller.setPreferredSize(new Dimension(300, 300));
1816
1817 GuiUtils.enableTree(cbPanel, !useAllBtn.isSelected());
1818 GuiUtils.enableTree(allOn, !useAllBtn.isSelected());
1819 GuiUtils.enableTree(allOff, !useAllBtn.isSelected());
1820
1821 JPanel widgetPanel =
1822 GuiUtils.topCenter(
1823 GuiUtils.hbox(useAllBtn, useTheseBtn),
1824 GuiUtils.leftCenter(
1825 GuiUtils.inset(
1826 GuiUtils.top(GuiUtils.vbox(allOn, allOff)),
1827 4), cbScroller));
1828 JPanel choosersPanel =
1829 GuiUtils.topCenter(
1830 GuiUtils.inset(
1831 new JLabel("Note: This will take effect the next run"),
1832 4), widgetPanel);
1833 choosersPanel = GuiUtils.inset(GuiUtils.left(choosersPanel), 6);
1834 useAllBtn.addActionListener(new ActionListener() {
1835 public void actionPerformed(ActionEvent ae) {
1836 GuiUtils.enableTree(cbPanel, !useAllBtn.isSelected());
1837 GuiUtils.enableTree(allOn, !useAllBtn.isSelected());
1838 GuiUtils.enableTree(allOff, !useAllBtn.isSelected());
1839
1840 }
1841 });
1842 useTheseBtn.addActionListener(new ActionListener() {
1843 public void actionPerformed(ActionEvent ae) {
1844 GuiUtils.enableTree(cbPanel, !useAllBtn.isSelected());
1845 GuiUtils.enableTree(allOn, !useAllBtn.isSelected());
1846 GuiUtils.enableTree(allOff, !useAllBtn.isSelected());
1847 }
1848 });
1849
1850 PreferenceManager choosersManager = new PreferenceManager() {
1851 public void applyPreference(XmlObjectStore theStore, Object data) {
1852
1853 Hashtable<String, Boolean> newToShow = new Hashtable<String, Boolean>();
1854
1855 Hashtable table = (Hashtable)data;
1856 for (Enumeration keys = table.keys(); keys.hasMoreElements(); ) {
1857 String chooserId = (String) keys.nextElement();
1858 JCheckBox chooserCB = (JCheckBox) table.get(chooserId);
1859 newToShow.put(chooserId, Boolean.valueOf(chooserCB.isSelected()));
1860 }
1861
1862 choosersToShow = newToShow;
1863 theStore.put(PROP_CHOOSERS_ALL, Boolean.valueOf(useAllBtn.isSelected()));
1864 theStore.put(PROP_CHOOSERS, choosersToShow);
1865 }
1866 };
1867 this.add(Constants.PREF_LIST_DATA_CHOOSERS,
1868 "What data sources should be shown in the user interface?",
1869 choosersManager, choosersPanel, choosersData);
1870 }
1871
1872 /**
1873 * <p>Return a list that contains a bunch of arrays of two strings.</p>
1874 *
1875 * <p>The first item in one of the arrays is the chooser id, and the second
1876 * item is the "name" of the chooser. The name is formed by working through
1877 * choosers.xml and concatenating each panel's category and title.</p>
1878 *
1879 * @return A list of chooser ids and names.
1880 */
1881 private final List<String[]> getChooserData() {
1882 List<String[]> choosers = new ArrayList<String[]>();
1883 String tempString;
1884
1885 try {
1886 // get the root element so we can iterate through
1887 final String xml =
1888 IOUtil.readContents(MCV_CHOOSERS, McIdasPreferenceManager.class);
1889
1890 final Element root = XmlUtil.getRoot(xml);
1891 if (root == null)
1892 return null;
1893
1894 // grab all the children, which should be panels.
1895 final NodeList nodeList = XmlUtil.getElements(root);
1896 for (int i = 0; i < nodeList.getLength(); i++) {
1897
1898 final Element item = (Element)nodeList.item(i);
1899
1900 if (item.getTagName().equals(XmlUi.TAG_PANEL) || item.getTagName().equals("chooser")) {
1901
1902 // form the name of the chooser.
1903 final String title =
1904 XmlUtil.getAttribute(item, XmlUi.ATTR_TITLE, "");
1905
1906 final String cat =
1907 XmlUtil.getAttribute(item, XmlUi.ATTR_CATEGORY, "");
1908
1909 if (cat.equals(""))
1910 tempString = title;
1911 else
1912 tempString = cat + ">" + title;
1913
1914 final NodeList children = XmlUtil.getElements(item);
1915
1916 if (item.getTagName().equals("chooser")) {
1917 final String id =
1918 XmlUtil.getAttribute(item, XmlUi.ATTR_ID, "");
1919 String[] tmp = {id, tempString};
1920 choosers.add(tmp);
1921 }
1922 else {
1923 for (int j = 0; j < children.getLength(); j++) {
1924 final Element child = (Element)children.item(j);
1925
1926 // form the id of the chooser and add it to the list.
1927 if (child.getTagName().equals("chooser")) {
1928 final String id =
1929 XmlUtil.getAttribute(child, XmlUi.ATTR_ID, "");
1930 String[] tmp = {id, tempString};
1931 choosers.add(tmp);
1932 }
1933 }
1934 }
1935 }
1936 }
1937 } catch (Exception e) {
1938 e.printStackTrace();
1939 }
1940 return choosers;
1941 }
1942
1943 /**
1944 * Parse the full chooser name for a category
1945 * @param chooserName
1946 * @return
1947 */
1948 private String getChooserCategory(String chooserName) {
1949 String chooserCategory = "Other";
1950 int indexSep = chooserName.indexOf(">");
1951 if (indexSep >= 0) {
1952 chooserCategory = chooserName.substring(0, indexSep);
1953 }
1954 return chooserCategory;
1955 }
1956
1957 /**
1958 * Parse the full chooser name for a short name
1959 * @param chooserName
1960 * @return
1961 */
1962 private String getChooserShortName(String chooserName) {
1963 String chooserShortName = chooserName;
1964 int indexSep = chooserName.indexOf(">");
1965 if (indexSep >= 0 && chooserName.length() > indexSep + 1) {
1966 chooserShortName = chooserName.substring(indexSep + 1, chooserName.length());
1967 }
1968 return chooserShortName;
1969 }
1970
1971 public class IconCellRenderer extends DefaultListCellRenderer {
1972
1973 /**
1974 * Extends the default list cell renderer to use icons in addition to
1975 * the typical text.
1976 */
1977 public Component getListCellRendererComponent(JList list, Object value,
1978 int index, boolean isSelected, boolean cellHasFocus) {
1979
1980 super.getListCellRendererComponent(list, value, index, isSelected,
1981 cellHasFocus);
1982
1983 if (value instanceof JLabel) {
1984 setText(((JLabel)value).getText());
1985 setIcon(((JLabel)value).getIcon());
1986 }
1987
1988 return this;
1989 }
1990
1991 /**
1992 * I wear some pretty fancy pants, so you'd better believe that I'm
1993 * going to enable fancy-pants text antialiasing.
1994 *
1995 * @param g The graphics object that we'll use as a base.
1996 */
1997 protected void paintComponent(Graphics g) {
1998 Graphics2D g2d = (Graphics2D)g;
1999 g2d.setRenderingHints(getRenderingHints());
2000 super.paintComponent(g2d);
2001 }
2002 }
2003 }
2004