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