001 /*
002 * $Id: McVGuiUtils.java,v 1.47 2012/02/19 17:35:52 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.util;
032
033 import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.arrList;
034 import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.cast;
035 import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.newHashSet;
036
037 import static javax.swing.GroupLayout.DEFAULT_SIZE;
038 import static javax.swing.GroupLayout.PREFERRED_SIZE;
039 import static javax.swing.GroupLayout.Alignment.BASELINE;
040 import static javax.swing.GroupLayout.Alignment.LEADING;
041 import static javax.swing.LayoutStyle.ComponentPlacement.RELATED;
042
043 import java.awt.Color;
044 import java.awt.Component;
045 import java.awt.Dimension;
046 import java.awt.Font;
047 import java.awt.Graphics;
048 import java.awt.Image;
049 import java.awt.Rectangle;
050 import java.awt.event.HierarchyEvent;
051 import java.util.ArrayList;
052 import java.util.Collection;
053 import java.util.Collections;
054 import java.util.EventObject;
055 import java.util.List;
056 import java.util.Map;
057 import java.util.Map.Entry;
058 import java.util.Set;
059 import java.util.regex.Pattern;
060
061 import javax.swing.GroupLayout;
062 import javax.swing.GroupLayout.ParallelGroup;
063 import javax.swing.GroupLayout.SequentialGroup;
064 import javax.swing.ImageIcon;
065 import javax.swing.JButton;
066 import javax.swing.JComboBox;
067 import javax.swing.JComponent;
068 import javax.swing.JLabel;
069 import javax.swing.JMenuItem;
070 import javax.swing.JPanel;
071 import javax.swing.JTextField;
072 import javax.swing.SwingConstants;
073 import javax.swing.SwingUtilities;
074
075 import org.slf4j.Logger;
076 import org.slf4j.LoggerFactory;
077
078 import ucar.unidata.idv.MapViewManager;
079 import ucar.unidata.idv.ViewManager;
080 import ucar.unidata.idv.ui.IdvComponentGroup;
081 import ucar.unidata.idv.ui.IdvComponentHolder;
082 import ucar.unidata.idv.ui.IdvWindow;
083 import ucar.unidata.idv.ui.WindowInfo;
084 import ucar.unidata.ui.ComponentHolder;
085 import ucar.unidata.ui.MultiFrame;
086 import ucar.unidata.util.GuiUtils;
087
088 import edu.wisc.ssec.mcidasv.Constants;
089 import edu.wisc.ssec.mcidasv.McIDASV;
090 import edu.wisc.ssec.mcidasv.ViewManagerManager;
091 import edu.wisc.ssec.mcidasv.ui.McvComponentGroup;
092 import edu.wisc.ssec.mcidasv.ui.McvComponentHolder;
093 import edu.wisc.ssec.mcidasv.ui.UIManager;
094
095
096 public class McVGuiUtils implements Constants {
097
098 private static final Logger logger = LoggerFactory.getLogger(McVGuiUtils.class);
099
100 /**
101 * Estimated number of {@link ucar.unidata.idv.ViewManager ViewManagers}.
102 * This value is only used as a last resort ({@link McIDASV#getStaticMcv()} failing).
103 */
104 private static final int ESTIMATED_VM_COUNT = 32;
105
106 private McVGuiUtils() {}
107
108 public enum Width { HALF, SINGLE, ONEHALF, DOUBLE, TRIPLE, QUADRUPLE, DOUBLEDOUBLE }
109 public enum Position { LEFT, RIGHT, CENTER }
110 public enum Prefer { TOP, BOTTOM, NEITHER }
111 public enum TextColor { NORMAL, STATUS }
112
113 /**
114 * Use this class to create a panel with a background image
115 * @author davep
116 *
117 */
118 public static class IconPanel extends JPanel {
119 private Image img;
120
121 public IconPanel(String img) {
122 this(GuiUtils.getImageIcon(img).getImage());
123 }
124
125 public IconPanel(Image img) {
126 this.img = img;
127 Dimension size = new Dimension(img.getWidth(null), img.getHeight(null));
128 setPreferredSize(size);
129 setMinimumSize(size);
130 setMaximumSize(size);
131 setSize(size);
132 setLayout(null);
133 }
134
135 public void paintComponent(Graphics g) {
136 super.paintComponent(g);
137 g.drawImage(img, 0, 0, null);
138 }
139
140 }
141
142 /**
143 * Create a standard sized, right-justified label
144 * @param title
145 * @return
146 */
147 public static JLabel makeLabelRight(String title) {
148 return makeLabelRight(title, null);
149 }
150
151 public static JLabel makeLabelRight(String title, Width width) {
152 if (width==null) width=Width.SINGLE;
153 JLabel newLabel = new JLabel(title);
154 setComponentWidth(newLabel, width);
155 setLabelPosition(newLabel, Position.RIGHT);
156 return newLabel;
157 }
158
159 /**
160 * Create a standard sized, left-justified label
161 * @param title
162 * @return
163 */
164 public static JLabel makeLabelLeft(String title) {
165 return makeLabelLeft(title, null);
166 }
167
168 public static JLabel makeLabelLeft(String title, Width width) {
169 if (width==null) width=Width.SINGLE;
170 JLabel newLabel = new JLabel(title);
171 setComponentWidth(newLabel, width);
172 setLabelPosition(newLabel, Position.LEFT);
173 return newLabel;
174 }
175
176 /**
177 * Create a sized, labeled component
178 * @param label
179 * @param thing
180 * @return
181 */
182 public static JPanel makeLabeledComponent(String label, JComponent thing) {
183 return makeLabeledComponent(makeLabelRight(label), thing);
184 }
185
186 public static JPanel makeLabeledComponent(JLabel label, JComponent thing) {
187 return makeLabeledComponent(label, thing, Position.RIGHT);
188 }
189
190 public static JPanel makeLabeledComponent(String label, JComponent thing, Position position) {
191 return makeLabeledComponent(new JLabel(label), thing, position);
192 }
193
194 public static JPanel makeLabeledComponent(JLabel label, JComponent thing, Position position) {
195 JPanel newPanel = new JPanel();
196
197 if (position == Position.RIGHT) {
198 setComponentWidth(label);
199 setLabelPosition(label, Position.RIGHT);
200 }
201
202 GroupLayout layout = new GroupLayout(newPanel);
203 newPanel.setLayout(layout);
204 layout.setHorizontalGroup(
205 layout.createParallelGroup(LEADING)
206 .addGroup(layout.createSequentialGroup()
207 .addComponent(label)
208 .addGap(GAP_RELATED)
209 .addComponent(thing))
210 );
211 layout.setVerticalGroup(
212 layout.createParallelGroup(LEADING)
213 .addGroup(layout.createParallelGroup(BASELINE)
214 .addComponent(label)
215 .addComponent(thing))
216 );
217
218 return newPanel;
219 }
220
221 /**
222 * Create a sized, labeled component
223 * @param label
224 * @param thing
225 * @return
226 */
227 public static JPanel makeComponentLabeled(JComponent thing, String label) {
228 return makeComponentLabeled(thing, new JLabel(label));
229 }
230
231 public static JPanel makeComponentLabeled(JComponent thing, String label, Position position) {
232 return makeComponentLabeled(thing, new JLabel(label), position);
233 }
234
235 public static JPanel makeComponentLabeled(JComponent thing, JLabel label) {
236 return makeComponentLabeled(thing, label, Position.LEFT);
237 }
238
239 public static JPanel makeComponentLabeled(JComponent thing, JLabel label, Position position) {
240 JPanel newPanel = new JPanel();
241
242 if (position == Position.RIGHT) {
243 setComponentWidth(label);
244 setLabelPosition(label, Position.RIGHT);
245 }
246
247 GroupLayout layout = new GroupLayout(newPanel);
248 newPanel.setLayout(layout);
249 layout.setHorizontalGroup(
250 layout.createParallelGroup(LEADING)
251 .addGroup(layout.createSequentialGroup()
252 .addComponent(thing)
253 .addGap(GAP_RELATED)
254 .addComponent(label))
255 );
256 layout.setVerticalGroup(
257 layout.createParallelGroup(LEADING)
258 .addGroup(layout.createParallelGroup(BASELINE)
259 .addComponent(thing)
260 .addComponent(label))
261 );
262
263 return newPanel;
264 }
265
266 /**
267 * Set the width of an existing component
268 * @param existingComponent
269 */
270 public static void setComponentWidth(JComponent existingComponent) {
271 setComponentWidth(existingComponent, Width.SINGLE);
272 }
273
274 public static void setComponentWidth(JComponent existingComponent, Width width) {
275 if (width == null)
276 width = Width.SINGLE;
277
278 switch (width) {
279 case HALF:
280 setComponentWidth(existingComponent, ELEMENT_HALF_WIDTH);
281 break;
282
283 case SINGLE:
284 setComponentWidth(existingComponent, ELEMENT_WIDTH);
285 break;
286
287 case ONEHALF:
288 setComponentWidth(existingComponent, ELEMENT_ONEHALF_WIDTH);
289 break;
290
291 case DOUBLE:
292 setComponentWidth(existingComponent, ELEMENT_DOUBLE_WIDTH);
293 break;
294
295 case TRIPLE:
296 setComponentWidth(existingComponent, ELEMENT_DOUBLE_WIDTH + ELEMENT_WIDTH);
297 break;
298
299 case QUADRUPLE:
300 setComponentWidth(existingComponent, ELEMENT_DOUBLE_WIDTH + ELEMENT_DOUBLE_WIDTH);
301 break;
302
303 case DOUBLEDOUBLE:
304 setComponentWidth(existingComponent, ELEMENT_DOUBLEDOUBLE_WIDTH);
305 break;
306
307 default:
308 setComponentWidth(existingComponent, ELEMENT_WIDTH);
309 break;
310 }
311 }
312
313 /**
314 * Set the width of an existing component to a given int width
315 * @param existingComponent
316 * @param width
317 */
318 public static void setComponentWidth(JComponent existingComponent, int width) {
319 existingComponent.setMinimumSize(new Dimension(width, 24));
320 existingComponent.setMaximumSize(new Dimension(width, 24));
321 existingComponent.setPreferredSize(new Dimension(width, 24));
322 }
323
324 /**
325 * Set the component width to that of another component
326 */
327 public static void setComponentWidth(JComponent setme, JComponent getme) {
328 setComponentWidth(setme, getme, 0);
329 }
330
331 public static void setComponentWidth(JComponent setme, JComponent getme, int padding) {
332 setme.setPreferredSize(new Dimension(getme.getPreferredSize().width + padding, getme.getPreferredSize().height));
333 }
334
335 /**
336 * Set the component height to that of another component
337 */
338 public static void setComponentHeight(JComponent setme, JComponent getme) {
339 setComponentHeight(setme, getme, 0);
340 }
341
342 public static void setComponentHeight(JComponent setme, JComponent getme, int padding) {
343 setme.setPreferredSize(new Dimension(getme.getPreferredSize().width, getme.getPreferredSize().height + padding));
344 }
345
346 /**
347 * Set the label position of an existing label
348 * @param existingLabel
349 */
350 public static void setLabelPosition(JLabel existingLabel) {
351 setLabelPosition(existingLabel, Position.LEFT);
352 }
353
354 public static void setLabelPosition(JLabel existingLabel, Position position) {
355 switch (position) {
356 case LEFT:
357 existingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
358 existingLabel.setHorizontalAlignment(SwingConstants.LEFT);
359 break;
360
361 case RIGHT:
362 existingLabel.setHorizontalTextPosition(SwingConstants.RIGHT);
363 existingLabel.setHorizontalAlignment(SwingConstants.RIGHT);
364 break;
365
366 case CENTER:
367 existingLabel.setHorizontalTextPosition(SwingConstants.CENTER);
368 existingLabel.setHorizontalAlignment(SwingConstants.CENTER);
369 break;
370
371 default:
372 existingLabel.setHorizontalTextPosition(SwingConstants.LEFT);
373 existingLabel.setHorizontalAlignment(SwingConstants.LEFT);
374 break;
375 }
376 }
377
378 /**
379 * Set the bold attribute of an existing label
380 * @param existingLabel
381 * @param bold
382 */
383 public static void setLabelBold(JLabel existingLabel, boolean bold) {
384 Font f = existingLabel.getFont();
385 if (bold) {
386 existingLabel.setFont(f.deriveFont(f.getStyle() ^ Font.BOLD));
387 } else {
388 existingLabel.setFont(f.deriveFont(f.getStyle() | Font.BOLD));
389 }
390 }
391
392 /**
393 * Set the foreground color of an existing component
394 * @param existingComponent
395 */
396 public static void setComponentColor(JComponent existingComponent) {
397 setComponentColor(existingComponent, TextColor.NORMAL);
398 }
399
400 public static void setComponentColor(JComponent existingComponent, TextColor color) {
401 switch (color) {
402 case NORMAL:
403 existingComponent.setForeground(new Color(0, 0, 0));
404 break;
405
406 case STATUS:
407 existingComponent.setForeground(MCV_BLUE_DARK);
408 break;
409
410 default:
411 existingComponent.setForeground(new Color(0, 0, 0));
412 break;
413 }
414 }
415
416 /**
417 * Custom makeImageButton to ensure proper sizing and mouseborder are set
418 */
419 public static JButton makeImageButton(String iconName,
420 final Object object,
421 final String methodName,
422 final Object arg,
423 final String tooltip
424 ) {
425
426 final JButton btn = makeImageButton(iconName, tooltip);
427 return (JButton) GuiUtils.addActionListener(btn, object, methodName, arg);
428 }
429
430 /**
431 * Custom makeImageButton to ensure proper sizing and mouseborder are set
432 */
433 public static JButton makeImageButton(String iconName, String tooltip) {
434 boolean addMouseOverBorder = true;
435
436 ImageIcon imageIcon = GuiUtils.getImageIcon(iconName);
437 if (imageIcon.getIconWidth() > 22 || imageIcon.getIconHeight() > 22) {
438 Image scaledImage = imageIcon.getImage().getScaledInstance(22, 22, Image.SCALE_SMOOTH);
439 imageIcon = new ImageIcon(scaledImage);
440 }
441
442 final JButton btn = GuiUtils.getImageButton(imageIcon);
443 btn.setBackground(null);
444 btn.setContentAreaFilled(false);
445 btn.setSize(new Dimension(24, 24));
446 btn.setPreferredSize(new Dimension(24, 24));
447 btn.setMinimumSize(new Dimension(24, 24));
448 if (addMouseOverBorder) {
449 GuiUtils.makeMouseOverBorder(btn);
450 }
451 btn.setToolTipText(tooltip);
452 return btn;
453 }
454
455 /**
456 * Create a button with text and an icon
457 */
458 public static JButton makeImageTextButton(String iconName, String label) {
459 JButton newButton = new JButton(label);
460 setButtonImage(newButton, iconName);
461 return newButton;
462 }
463
464 /**
465 * Add an icon to a button... but only if the LookAndFeel supports it
466 */
467 public static void setButtonImage(JButton existingButton, String iconName) {
468 // TODO: see if this is fixed in some future Apple Java release?
469 // When using Aqua look and feel don't use icons in the buttons
470 // Messes with the button vertical sizing
471 if (existingButton.getBorder().toString().indexOf("Aqua") > 0) return;
472 ImageIcon imageIcon = GuiUtils.getImageIcon(iconName);
473 existingButton.setIcon(imageIcon);
474 }
475
476 /**
477 * Add an icon to a menu item
478 */
479 public static void setMenuImage(JMenuItem existingMenuItem, String iconName) {
480 ImageIcon imageIcon = GuiUtils.getImageIcon(iconName);
481 existingMenuItem.setIcon(imageIcon);
482 }
483
484 public static <E> JComboBox makeComboBox(final E[] items, final Object selected) {
485 return makeComboBox(CollectionHelpers.list(items), selected);
486 }
487
488 public static <E> JComboBox makeComboBox(final E[] items, final Object selected, final Width width) {
489 return makeComboBox(CollectionHelpers.list(items), selected, width);
490 }
491
492 public static JComboBox makeComboBox(final Collection<?> items, final Object selected) {
493 return makeComboBox(items, selected, null);
494 }
495
496 public static JComboBox makeComboBox(final Collection<?> items, final Object selected, final Width width) {
497 JComboBox newComboBox = getEditableBox(items, selected);
498 setComponentWidth(newComboBox, width);
499 return newComboBox;
500 }
501
502 public static void setListData(final JComboBox box, final Collection<?> items, final Object selected) {
503 box.removeAllItems();
504 if (items != null) {
505 for (Object o : items)
506 box.addItem(o);
507 }
508
509 if (selected != null && !items.contains(selected))
510 box.addItem(selected);
511 }
512
513 public static JComboBox getEditableBox(final Collection<?> items, final Object selected) {
514 JComboBox fld = new JComboBox();
515 fld.setEditable(true);
516 setListData(fld, items, selected);
517 if (selected != null) {
518 fld.setSelectedItem(selected);
519 }
520 return fld;
521 }
522
523 /**
524 * Create a standard sized text field
525 * @param value
526 * @return
527 */
528 public static JTextField makeTextField(String value) {
529 return makeTextField(value, null);
530 }
531
532 public static JTextField makeTextField(String value, Width width) {
533 JTextField newTextField = new McVTextField(value);
534 setComponentWidth(newTextField, width);
535 return newTextField;
536 }
537
538 /**
539 * Create some custom text entry widgets
540 */
541 public static McVTextField makeTextFieldLimit(String defaultString, int limit) {
542 return new McVTextField(defaultString, limit);
543 }
544
545 public static McVTextField makeTextFieldUpper(String defaultString, int limit) {
546 return new McVTextField(defaultString, limit, true);
547 }
548
549 public static McVTextField makeTextFieldAllow(String defaultString, int limit, boolean upper, String allow) {
550 McVTextField newField = new McVTextField(defaultString, limit, upper);
551 newField.setAllow(allow);
552 return newField;
553 }
554
555 public static McVTextField makeTextFieldDeny(String defaultString, int limit, boolean upper, String deny) {
556 McVTextField newField = new McVTextField(defaultString, limit, upper);
557 newField.setDeny(deny);
558 return newField;
559 }
560
561 public static McVTextField makeTextFieldAllow(String defaultString, int limit, boolean upper, char[] allow) {
562 McVTextField newField = new McVTextField(defaultString, limit, upper);
563 newField.setAllow(allow);
564 return newField;
565 }
566
567 public static McVTextField makeTextFieldDeny(String defaultString, int limit, boolean upper, char[] deny) {
568 McVTextField newField = new McVTextField(defaultString, limit, upper);
569 newField.setDeny(deny);
570 return newField;
571 }
572
573 public static McVTextField makeTextFieldAllow(String defaultString, int limit, boolean upper, Pattern allow) {
574 McVTextField newField = new McVTextField(defaultString, limit, upper);
575 newField.setAllow(allow);
576 return newField;
577 }
578
579 public static McVTextField makeTextFieldDeny(String defaultString, int limit, boolean upper, Pattern deny) {
580 McVTextField newField = new McVTextField(defaultString, limit, upper);
581 newField.setDeny(deny);
582 return newField;
583 }
584
585 /**
586 * Use GroupLayout for stacking components vertically
587 * Set center to resize vertically
588 * @param top
589 * @param center
590 * @param bottom
591 * @return
592 */
593 public static JPanel topCenterBottom(JComponent top, JComponent center, JComponent bottom) {
594 JPanel newPanel = new JPanel();
595
596 GroupLayout layout = new GroupLayout(newPanel);
597 newPanel.setLayout(layout);
598 layout.setHorizontalGroup(
599 layout.createParallelGroup(LEADING)
600 .addComponent(top, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
601 .addComponent(center, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
602 .addComponent(bottom, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
603 );
604 layout.setVerticalGroup(
605 layout.createParallelGroup(LEADING)
606 .addGroup(layout.createSequentialGroup()
607 .addComponent(top, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
608 .addPreferredGap(RELATED)
609 .addComponent(center, PREFERRED_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
610 .addPreferredGap(RELATED)
611 .addComponent(bottom, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE))
612 );
613
614 return newPanel;
615 }
616
617 /**
618 * Use GroupLayout for stacking components vertically
619 * @param top
620 * @param bottom
621 * @param which
622 * @return
623 */
624 public static JPanel topBottom(JComponent top, JComponent bottom, Prefer which) {
625 JPanel newPanel = new JPanel();
626
627 int topSize=PREFERRED_SIZE;
628 int bottomSize=PREFERRED_SIZE;
629
630 if (which == Prefer.TOP) topSize = Short.MAX_VALUE;
631 else if (which == Prefer.BOTTOM) topSize = Short.MAX_VALUE;
632
633 GroupLayout layout = new GroupLayout(newPanel);
634 newPanel.setLayout(layout);
635 layout.setHorizontalGroup(
636 layout.createParallelGroup(LEADING)
637 .addComponent(top, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
638 .addComponent(bottom, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
639 );
640 layout.setVerticalGroup(
641 layout.createParallelGroup(LEADING)
642 .addGroup(layout.createSequentialGroup()
643 .addComponent(top, PREFERRED_SIZE, DEFAULT_SIZE, topSize)
644 .addPreferredGap(RELATED)
645 .addComponent(bottom, PREFERRED_SIZE, DEFAULT_SIZE, bottomSize))
646 );
647
648 return newPanel;
649 }
650
651 /**
652 * Use GroupLayout for wrapping components to stop vertical resizing
653 * @param left
654 * @param right
655 * @return
656 */
657 public static JPanel sideBySide(JComponent left, JComponent right) {
658 return sideBySide(left, right, GAP_RELATED);
659 }
660
661 /**
662 * Use GroupLayout for wrapping components to stop vertical resizing
663 * @param left
664 * @param right
665 * @return
666 */
667 public static JPanel sideBySide(JComponent left, JComponent right, int gap) {
668 JPanel newPanel = new JPanel();
669
670 GroupLayout layout = new GroupLayout(newPanel);
671 newPanel.setLayout(layout);
672 layout.setHorizontalGroup(
673 layout.createParallelGroup(LEADING)
674 .addGroup(layout.createSequentialGroup()
675 .addComponent(left, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE)
676 .addGap(gap)
677 .addComponent(right, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))
678 );
679 layout.setVerticalGroup(
680 layout.createParallelGroup(LEADING)
681 .addGroup(layout.createSequentialGroup()
682 .addGroup(layout.createParallelGroup(LEADING)
683 .addComponent(left, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)
684 .addComponent(right, PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE)))
685 );
686
687 return newPanel;
688 }
689
690 /**
691 * Use GroupLayout for wrapping a list of components horizontally
692 */
693 public static JPanel horizontal(Component[] components) {
694 JPanel newPanel = new JPanel();
695
696 GroupLayout layout = new GroupLayout(newPanel);
697 newPanel.setLayout(layout);
698
699 SequentialGroup hGroup = layout.createSequentialGroup();
700 for (int i=0; i<components.length; i++) {
701 if (i>0) hGroup.addGap(GAP_RELATED);
702 hGroup.addComponent(components[i], DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE);
703 }
704
705 SequentialGroup vGroup = layout.createSequentialGroup();
706 ParallelGroup vInner = layout.createParallelGroup(LEADING);
707 for (int i=0; i<components.length; i++) {
708 vInner.addComponent(components[i], PREFERRED_SIZE, DEFAULT_SIZE, PREFERRED_SIZE);
709 }
710 vGroup.addGroup(vInner);
711
712 layout.setHorizontalGroup(
713 layout.createParallelGroup(LEADING).addGroup(hGroup)
714 );
715 layout.setVerticalGroup(
716 layout.createParallelGroup(LEADING).addGroup(vGroup)
717 );
718
719 return newPanel;
720 }
721
722 /**
723 * Use GroupLayout for wrapping a list of components vertically
724 */
725 public static JPanel vertical(Component[] components) {
726 JPanel newPanel = new JPanel();
727
728 GroupLayout layout = new GroupLayout(newPanel);
729 newPanel.setLayout(layout);
730
731 ParallelGroup hGroup = layout.createParallelGroup(LEADING);
732 for (int i=0; i<components.length; i++) {
733 hGroup.addComponent(components[i], DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE);
734 }
735
736 int vSize=PREFERRED_SIZE;
737
738 ParallelGroup vGroup = layout.createParallelGroup(LEADING);
739 SequentialGroup vInner = layout.createSequentialGroup();
740 for (int i=0; i<components.length; i++) {
741 if (i>0) vInner.addGap(GAP_RELATED);
742 if (i == components.length-1) vSize = Short.MAX_VALUE;
743 vInner.addComponent(components[i], PREFERRED_SIZE, DEFAULT_SIZE, vSize);
744 }
745 vGroup.addGroup(vInner);
746
747 layout.setHorizontalGroup(
748 layout.createParallelGroup(LEADING).addGroup(hGroup)
749 );
750 layout.setVerticalGroup(
751 layout.createParallelGroup(LEADING).addGroup(vGroup)
752 );
753
754 return newPanel;
755 }
756
757 /**
758 * Hack apart an IDV button panel and do a few things:
759 * - Reorder the buttons based on OS preference
760 * Windows: OK on left
761 * Mac: OK on right
762 * - Add icons when we understand the button name
763 *
764 * TODO: Revisit this? Could hamper GUI performance. But it is niiice...
765 *
766 * @param idvButtonPanel
767 * @return
768 */
769 public static JPanel makePrettyButtons(JPanel idvButtonPanel) {
770 // These are the buttons we know about
771 JButton buttonOK = null;
772 JButton buttonApply = null;
773 JButton buttonCancel = null;
774 JButton buttonHelp = null;
775 JButton buttonNew = null;
776 JButton buttonReset = null;
777 JButton buttonYes = null;
778 JButton buttonNo = null;
779
780 // These are the buttons we don't know about
781 List<JButton> buttonList = new ArrayList<JButton>();
782
783 // First pull apart the panel and see if it looks like we expect
784 Component[] comps = idvButtonPanel.getComponents();
785 for (int i=0; i<comps.length; i++) {
786 if (!(comps[i] instanceof JButton)) continue;
787 JButton button = (JButton)comps[i];
788 if ("OK".equals(button.getText())) {
789 buttonOK = makePrettyButton(button);
790 }
791 else if ("Apply".equals(button.getText())) {
792 buttonApply = makePrettyButton(button);
793 }
794 else if ("Cancel".equals(button.getText())) {
795 buttonCancel = makePrettyButton(button);
796 }
797 else if ("Help".equals(button.getText())) {
798 buttonHelp = makePrettyButton(button);
799 }
800 else if ("New".equals(button.getText())) {
801 buttonNew = makePrettyButton(button);
802 }
803 else if ("Reset".equals(button.getText())) {
804 buttonReset = makePrettyButton(button);
805 }
806 else if ("Yes".equals(button.getText())) {
807 buttonYes = makePrettyButton(button);
808 }
809 else if ("No".equals(button.getText())) {
810 buttonNo = makePrettyButton(button);
811 }
812 else {
813 buttonList.add(button);
814 }
815 }
816
817 // If we are on a Mac, this is the order (right aligned)
818 // Help, New, Reset, No, Yes, Cancel, Apply, OK
819 if (System.getProperty("os.name").indexOf("Mac OS X") >= 0) {
820 JPanel newButtonPanel = new JPanel();
821 if (buttonHelp!=null) newButtonPanel.add(buttonHelp);
822 if (buttonNew!=null) newButtonPanel.add(buttonNew);
823 if (buttonReset!=null) newButtonPanel.add(buttonReset);
824 if (buttonNo!=null) newButtonPanel.add(buttonNo);
825 if (buttonYes!=null) newButtonPanel.add(buttonYes);
826 if (buttonCancel!=null) newButtonPanel.add(buttonCancel);
827 if (buttonApply!=null) newButtonPanel.add(buttonApply);
828 if (buttonOK!=null) newButtonPanel.add(buttonOK);
829 if (buttonList.size() > 0)
830 return GuiUtils.right(GuiUtils.hbox(GuiUtils.hbox(buttonList), newButtonPanel));
831 else
832 return(GuiUtils.right(newButtonPanel));
833 }
834
835 // If we are not on a Mac, this is the order (center aligned)
836 // OK, Apply, Cancel, Yes, No, Reset, New, Help
837 if (System.getProperty("os.name").indexOf("Mac OS X") < 0) {
838 JPanel newButtonPanel = new JPanel();
839 if (buttonOK!=null) newButtonPanel.add(buttonOK);
840 if (buttonApply!=null) newButtonPanel.add(buttonApply);
841 if (buttonCancel!=null) newButtonPanel.add(buttonCancel);
842 if (buttonYes!=null) newButtonPanel.add(buttonYes);
843 if (buttonNo!=null) newButtonPanel.add(buttonNo);
844 if (buttonReset!=null) newButtonPanel.add(buttonReset);
845 if (buttonNew!=null) newButtonPanel.add(buttonNew);
846 if (buttonHelp!=null) newButtonPanel.add(buttonHelp);
847 if (buttonList.size() > 0)
848 return GuiUtils.center(GuiUtils.hbox(GuiUtils.hbox(buttonList), newButtonPanel));
849 else
850 return(GuiUtils.center(newButtonPanel));
851 }
852
853 return idvButtonPanel;
854 }
855
856 /**
857 * Take a list of buttons and make them pretty
858 *
859 * @param buttonList
860 * @return list
861 */
862 public static List makePrettyButtons(List buttonList) {
863 int size = buttonList.size();
864 List newButtons = arrList(size);
865 for (int i=0; i<size; i++) {
866 if (buttonList.get(i) instanceof JButton) {
867 newButtons.add(makePrettyButton((JButton)(buttonList.get(i))));
868 } else {
869 newButtons.add(buttonList.get(i));
870 }
871 }
872 return newButtons;
873 }
874
875 /**
876 * Convenience method to make a button based solely on its name
877 * @param name
878 * @return
879 */
880 public static JButton makePrettyButton(String name) {
881 return makePrettyButton(new JButton(name));
882 }
883
884 /**
885 * - Add icons when we understand the button name
886 *
887 * @param button
888 * @return button
889 */
890 public static JButton makePrettyButton(JButton button) {
891 McVGuiUtils.setComponentWidth(button, Width.ONEHALF);
892 if ("OK".equals(button.getText())) {
893 McVGuiUtils.setButtonImage(button, ICON_ACCEPT_SMALL);
894 }
895 else if ("Apply".equals(button.getText())) {
896 McVGuiUtils.setButtonImage(button, ICON_APPLY_SMALL);
897 }
898 else if ("Cancel".equals(button.getText())) {
899 McVGuiUtils.setButtonImage(button, ICON_CANCEL_SMALL);
900 }
901 else if ("Help".equals(button.getText())) {
902 McVGuiUtils.setButtonImage(button, ICON_HELP_SMALL);
903 }
904 else if ("New".equals(button.getText())) {
905 McVGuiUtils.setButtonImage(button, ICON_ADD_SMALL);
906 }
907 else if ("Reset".equals(button.getText())) {
908 McVGuiUtils.setButtonImage(button, ICON_UNDO_SMALL);
909 }
910 else if ("Yes".equals(button.getText())) {
911 McVGuiUtils.setButtonImage(button, ICON_ACCEPT_SMALL);
912 }
913 else if ("No".equals(button.getText())) {
914 McVGuiUtils.setButtonImage(button, ICON_CANCEL_SMALL);
915 }
916 else if ("Close".equals(button.getText())) {
917 McVGuiUtils.setButtonImage(button, ICON_CANCEL_SMALL);
918 }
919 else if ("Previous".equals(button.getText())) {
920 McVGuiUtils.setButtonImage(button, ICON_PREVIOUS_SMALL);
921 }
922 else if ("Next".equals(button.getText())) {
923 McVGuiUtils.setButtonImage(button, ICON_NEXT_SMALL);
924 }
925 else if ("Random".equals(button.getText())) {
926 McVGuiUtils.setButtonImage(button, ICON_RANDOM_SMALL);
927 }
928 else if ("Support Form".equals(button.getText())) {
929 McVGuiUtils.setButtonImage(button, ICON_SUPPORT_SMALL);
930 }
931 return button;
932 }
933
934 /**
935 * Print the hierarchy of components
936 */
937 public static void printUIComponents(JComponent parent) {
938 printUIComponents(parent, 0, 0);
939 }
940 public static void printUIComponents(JComponent parent, int index, int depth) {
941 if (parent == null) {
942 System.err.println("McVGuiUtils.printUIComponents: null parent");
943 return;
944 }
945 Component[] children = parent.getComponents();
946 int childcount = children.length;
947
948 String indent = "";
949 for (int d=0; d<depth; d++) {
950 indent += " ";
951 }
952 System.out.println(indent + index + ": " + parent);
953
954 if (childcount > 0) {
955 for (int c=0; c<childcount; c++) {
956 if (children[c] instanceof JComponent) {
957 printUIComponents((JComponent)children[c], c, depth+1);
958 }
959 }
960 }
961 }
962
963 /**
964 * Calls {@link SwingUtilities#invokeLater(Runnable)} if the current thread
965 * is not the event dispatch thread. If this thread <b>is</b> the EDT,
966 * then call {@link Runnable#run()} for {@code r}.
967 *
968 * <p>Remember, you <i>do not</i> want to execute long-running tasks in the
969 * event dispatch thread--it'll lock up the GUI.
970 *
971 * @param r Code to run in the event dispatch thread. Cannot be {@code null}.
972 */
973 public static void runOnEDT(final Runnable r) {
974 if (SwingUtilities.isEventDispatchThread()) {
975 r.run();
976 } else {
977 SwingUtilities.invokeLater(r);
978 }
979 }
980
981 // private static <E> List<E> sizedList() {
982 // McIDASV mcv = McIDASV.getStaticMcv();
983 // int viewManagerCount = ESTIMATED_VM_COUNT;
984 // if (mcv != null) {
985 // ViewManagerManager vmm = cast(mcv.getVMManager());
986 // viewManagerCount = vmm.getViewManagers().size();
987 // }
988 // return arrList(viewManagerCount);
989 // }
990
991
992 private static int getVMCount() {
993 McIDASV mcv = McIDASV.getStaticMcv();
994 int viewManagerCount = ESTIMATED_VM_COUNT;
995 if (mcv != null) {
996 ViewManagerManager vmm = cast(mcv.getVMManager());
997 viewManagerCount = vmm.getViewManagerCount();
998 }
999 return viewManagerCount;
1000 }
1001
1002 private static int getHolderCount() {
1003 McIDASV mcv = McIDASV.getStaticMcv();
1004 int holderCount = ESTIMATED_VM_COUNT;
1005 if (mcv != null) {
1006 UIManager uiManager = cast(mcv.getIdvUIManager());
1007 holderCount = uiManager.getComponentHolderCount();
1008 }
1009 return holderCount;
1010 }
1011
1012 private static int getGroupCount() {
1013 McIDASV mcv = McIDASV.getStaticMcv();
1014 int groupCount = ESTIMATED_VM_COUNT;
1015 if (mcv != null) {
1016 UIManager uiManager = cast(mcv.getIdvUIManager());
1017 groupCount = uiManager.getComponentGroupCount();
1018 }
1019 return groupCount;
1020 }
1021
1022 public static List<ViewManager> getActiveViewManagers() {
1023 IdvWindow activeWindow = IdvWindow.getActiveWindow();
1024 List<ViewManager> vms;
1025 if (activeWindow != null) {
1026 vms = getViewManagers(activeWindow);
1027 } else {
1028 vms = Collections.emptyList();
1029 }
1030 return vms;
1031 }
1032
1033 public static List<ViewManager> getAllViewManagers() {
1034 McIDASV mcv = McIDASV.getStaticMcv();
1035 List<ViewManager> vms = Collections.emptyList();
1036 if (mcv != null) {
1037 ViewManagerManager vmm = cast(mcv.getVMManager());
1038 vms = arrList(vmm.getViewManagers());
1039 }
1040 return vms;
1041 }
1042
1043 public static List<Object> getShareGroupsInWindow(final IdvWindow window) {
1044 List<ViewManager> vms = arrList(getVMCount());
1045 vms.addAll(window.getViewManagers());
1046 for (IdvComponentHolder holder : getComponentHolders(window)) {
1047 vms.addAll(holder.getViewManagers());
1048 }
1049 Set<Object> groupIds = newHashSet(vms.size());
1050 for (ViewManager vm : vms) {
1051 groupIds.add(vm.getShareGroup());
1052 }
1053 return arrList(groupIds);
1054 }
1055
1056 public static List<Object> getAllShareGroups() {
1057 List<ViewManager> vms = getAllViewManagers();
1058 Set<Object> groupIds = newHashSet(vms.size());
1059 for (ViewManager vm : vms) {
1060 groupIds.add(vm.getShareGroup());
1061 }
1062 return arrList(groupIds);
1063 }
1064
1065 public static List<ViewManager> getViewManagersInGroup(final Object sharedGroup) {
1066 List<ViewManager> allVMs = getAllViewManagers();
1067 List<ViewManager> filtered = arrList(allVMs.size());
1068 for (ViewManager vm : allVMs) {
1069 if (vm.getShareGroup().equals(sharedGroup)) {
1070 filtered.add(vm);
1071 }
1072 }
1073 return filtered;
1074 }
1075
1076 public static List<ViewManager> getViewManagers(final WindowInfo info) {
1077 List<ViewManager> vms = arrList(getVMCount());
1078 for (IdvComponentHolder holder : getComponentHolders(info)) {
1079 vms.addAll(holder.getViewManagers());
1080 }
1081 return vms;
1082 }
1083
1084 public static List<ViewManager> getViewManagers(final IdvWindow window) {
1085 List<ViewManager> vms = arrList(getVMCount());
1086 vms.addAll(window.getViewManagers());
1087 for (IdvComponentHolder holder : getComponentHolders(window)) {
1088 vms.addAll(holder.getViewManagers());
1089 }
1090 return vms;
1091 }
1092
1093 /**
1094 * @return Whether or not {@code h} contains some UI component like
1095 * the dashboard of field selector. Yes, it can happen!
1096 */
1097 public static boolean isUIHolder(final IdvComponentHolder h) {
1098 if (McvComponentHolder.TYPE_DYNAMIC_SKIN.equals(h.getType())) {
1099 return false;
1100 }
1101 return h.getViewManagers().isEmpty();
1102 }
1103
1104 /**
1105 * @return Whether or not {@code h} is a dynamic skin.
1106 */
1107 public static boolean isDynamicSkin(final IdvComponentHolder h) {
1108 return McvComponentHolder.TYPE_DYNAMIC_SKIN.equals(h.getType());
1109 }
1110
1111 /**
1112 * @return Whether or not {@code windows} has at least one dynamic
1113 * skin.
1114 */
1115 public static boolean hasDynamicSkins(final List<WindowInfo> windows) {
1116 for (WindowInfo window : windows) {
1117 for (IdvComponentHolder holder : getComponentHolders(window)) {
1118 if (isDynamicSkin(holder)) {
1119 return true;
1120 }
1121 }
1122 }
1123 return false;
1124 }
1125
1126 /**
1127 * @return The component holders within <code>windowInfo</code>.
1128 * @see #getComponentHolders(IdvComponentGroup)
1129 */
1130 public static List<IdvComponentHolder> getComponentHolders(
1131 final WindowInfo windowInfo) {
1132 Collection<Object> comps =
1133 cast(windowInfo.getPersistentComponents().values());
1134 List<IdvComponentHolder> holders = arrList(getHolderCount());
1135 for (Object comp : comps) {
1136 if (!(comp instanceof IdvComponentGroup)) {
1137 continue;
1138 }
1139 holders.addAll(getComponentHolders((IdvComponentGroup)comp));
1140 }
1141 return holders;
1142 }
1143
1144 /**
1145 * @return The component holders within {@code idvWindow}.
1146 * @see #getComponentHolders(IdvComponentGroup)
1147 */
1148 public static List<IdvComponentHolder> getComponentHolders(
1149 final IdvWindow idvWindow)
1150 {
1151 List<IdvComponentHolder> holders = arrList(getHolderCount());
1152 for (IdvComponentGroup group : (List<IdvComponentGroup>)idvWindow.getComponentGroups()) {
1153 holders.addAll(getComponentHolders(group));
1154 }
1155 return holders;
1156 }
1157
1158 /**
1159 * @return <b>Recursively</b> searches {@code group} to find any
1160 * component holders.
1161 */
1162 public static List<IdvComponentHolder> getComponentHolders(
1163 final IdvComponentGroup group)
1164 {
1165 List<IdvComponentHolder> holders = arrList(getHolderCount());
1166 List<ComponentHolder> comps = cast(group.getDisplayComponents());
1167 if (comps.isEmpty()) {
1168 return holders;
1169 }
1170 for (ComponentHolder comp : comps) {
1171 if (comp instanceof IdvComponentGroup) {
1172 holders.addAll(getComponentHolders((IdvComponentGroup)comp));
1173 } else if (comp instanceof IdvComponentHolder) {
1174 holders.add((IdvComponentHolder)comp);
1175 }
1176 }
1177 return holders;
1178 }
1179
1180 /**
1181 * @return <b>Recursively</b> searches {@code group} for any nested
1182 * component groups.
1183 */
1184 public static List<IdvComponentGroup> getComponentGroups(
1185 final IdvComponentGroup group)
1186 {
1187 List<IdvComponentGroup> groups = arrList(getGroupCount());
1188 groups.add(group);
1189
1190 List<ComponentHolder> comps = cast(group.getDisplayComponents());
1191 if (comps.isEmpty())
1192 return groups;
1193
1194 for (ComponentHolder comp : comps) {
1195 if (comp instanceof IdvComponentGroup) {
1196 groups.addAll(getComponentGroups((IdvComponentGroup)comp));
1197 }
1198 }
1199 return groups;
1200 }
1201
1202 /**
1203 * @return Component groups contained in {@code window}.
1204 * @see #getComponentGroups(IdvComponentGroup)
1205 */
1206 public static List<IdvComponentGroup> getComponentGroups(
1207 final WindowInfo window)
1208 {
1209 Collection<Object> comps = cast(window.getPersistentComponents().values());
1210 for (Object comp : comps) {
1211 if (comp instanceof IdvComponentGroup) {
1212 return getComponentGroups((IdvComponentGroup)comp);
1213 }
1214 }
1215 return Collections.emptyList();
1216 }
1217
1218 /**
1219 * @return Component groups contained in {@code windows}.
1220 * @see #getComponentGroups(IdvComponentGroup)
1221 */
1222 public static List<IdvComponentGroup> getComponentGroups(
1223 final List<WindowInfo> windows)
1224 {
1225 List<IdvComponentGroup> groups = arrList(getGroupCount());
1226 for (WindowInfo window : windows) {
1227 groups.addAll(getComponentGroups(window));
1228 }
1229 return groups;
1230 }
1231
1232 /**
1233 * @return The component group within {@code window}.
1234 */
1235 public static IdvComponentGroup getComponentGroup(final IdvWindow window) {
1236 List<IdvComponentGroup> groups = window.getComponentGroups();
1237 if (!groups.isEmpty()) {
1238 return groups.get(0);
1239 }
1240 return null;
1241 }
1242
1243 /**
1244 * @return Whether or not {@code group} contains any component
1245 * groups.
1246 */
1247 public static boolean hasNestedGroups(final IdvComponentGroup group) {
1248 List<ComponentHolder> comps = cast(group.getDisplayComponents());
1249 for (ComponentHolder comp : comps) {
1250 if (comp instanceof IdvComponentGroup) {
1251 return true;
1252 }
1253 }
1254 return false;
1255 }
1256
1257 /**
1258 * @return All active component holders in McIDAS-V.
1259 */
1260 // TODO: needs update for nested groups
1261 public static List<IdvComponentHolder> getAllComponentHolders() {
1262 List<IdvComponentHolder> holders = arrList(getHolderCount());
1263 for (IdvComponentGroup g : getAllComponentGroups()) {
1264 holders.addAll(g.getDisplayComponents());
1265 }
1266 return holders;
1267 }
1268
1269 /**
1270 * @return All active component groups in McIDAS-V.
1271 */
1272 // TODO: needs update for nested groups
1273 public static List<IdvComponentGroup> getAllComponentGroups() {
1274 List<IdvComponentGroup> groups = arrList(getGroupCount());
1275 for (IdvWindow w : getAllDisplayWindows()) {
1276 groups.addAll(w.getComponentGroups());
1277 }
1278 return groups;
1279 }
1280
1281 /**
1282 * @return All windows that contain at least one component group.
1283 */
1284 public static List<IdvWindow> getAllDisplayWindows() {
1285 List<IdvWindow> allWindows = cast(IdvWindow.getWindows());
1286 List<IdvWindow> windows = arrList(allWindows.size());
1287 for (IdvWindow w : allWindows) {
1288 if (!w.getComponentGroups().isEmpty()) {
1289 windows.add(w);
1290 }
1291 }
1292 return windows;
1293 }
1294
1295 /**
1296 * @return The component holder positioned after the active component holder.
1297 */
1298 public static IdvComponentHolder getAfterActiveHolder() {
1299 return getAfterHolder(getActiveComponentHolder());
1300 }
1301
1302 /**
1303 * @return The component holder positioned before the active component holder.
1304 */
1305 public static IdvComponentHolder getBeforeActiveHolder() {
1306 return getBeforeHolder(getActiveComponentHolder());
1307 }
1308
1309 /**
1310 * @return The active component holder in the active window.
1311 */
1312 public static IdvComponentHolder getActiveComponentHolder() {
1313 IdvWindow window = IdvWindow.getActiveWindow();
1314 McvComponentGroup group = (McvComponentGroup)getComponentGroup(window);
1315 return (IdvComponentHolder)group.getActiveComponentHolder();
1316 }
1317
1318 /**
1319 * @return The component holder positioned after {@code current}.
1320 */
1321 public static IdvComponentHolder getAfterHolder(
1322 final IdvComponentHolder current)
1323 {
1324 List<IdvComponentHolder> holders = getAllComponentHolders();
1325 int currentIndex = holders.indexOf(current);
1326 return holders.get( (currentIndex + 1) % holders.size());
1327 }
1328
1329 /**
1330 * @return The component holder positioned before {@code current}.
1331 */
1332 public static IdvComponentHolder getBeforeHolder(
1333 final IdvComponentHolder current)
1334 {
1335 List<IdvComponentHolder> holders = getAllComponentHolders();
1336 int currentIndex = holders.indexOf(current);
1337 int newidx = (currentIndex - 1) % holders.size();
1338 if (newidx == -1) {
1339 newidx = holders.size() - 1;
1340 }
1341 return holders.get(newidx);
1342 }
1343
1344 /**
1345 * @param w {@link IdvWindow} whose component groups you want (as
1346 * {@link McvComponentGroup}s).
1347 *
1348 * @return A {@link List} of {@code McvComponentGroup}s or an empty list.
1349 * If there were no {@code McvComponentGroup}s in {@code w},
1350 * <b>or</b> if {@code w} is {@code null}, an empty {@code List} is returned.
1351 */
1352 public static List<McvComponentGroup> idvGroupsToMcv(final IdvWindow w) {
1353 if (w == null) {
1354 return Collections.emptyList();
1355 }
1356 final List<IdvComponentGroup> idvLandGroups = w.getComponentGroups();
1357 final List<McvComponentGroup> groups = arrList(idvLandGroups.size());
1358 for (IdvComponentGroup group : idvLandGroups) {
1359 groups.add((McvComponentGroup)group);
1360 }
1361 return groups;
1362 }
1363
1364 public static void compGroup(final IdvComponentGroup g) {
1365 compGroup(g, 0);
1366 }
1367
1368 public static void compGroup(final IdvComponentGroup g, final int level) {
1369 p("Comp Group", level);
1370 p(" name=" + g.getName(), level);
1371 p(" id=" + g.getUniqueId(), level);
1372 p(" layout=" + g.getLayout(), level);
1373 p(" comp count=" + g.getDisplayComponents().size() + ": ", level);
1374 for (Object comp : g.getDisplayComponents()) {
1375 if (comp instanceof IdvComponentHolder) {
1376 compHolder((IdvComponentHolder)comp, level+1);
1377 } else if (comp instanceof IdvComponentGroup) {
1378 compGroup((IdvComponentGroup)comp, level+1);
1379 } else {
1380 p(" umm=" + comp.getClass().getName(), level);
1381 }
1382 }
1383 }
1384
1385 public static void compHolder(final IdvComponentHolder h, final int level) {
1386 p("Comp Holder", level);
1387 p(" cat=" + h.getCategory(), level);
1388 p(" name=" + h.getName(), level);
1389 p(" id=" + h.getUniqueId(), level);
1390 if (h.getViewManagers() == null) {
1391 System.err.println(" null vms!");
1392 return;
1393 }
1394 p(" vm count=" + h.getViewManagers().size() + ": ", level);
1395 for (ViewManager vm : (List<ViewManager>)h.getViewManagers()) {
1396 p(" " + vmType(vm) + "=" + vm.getViewDescriptor().getName(), level);
1397 }
1398 }
1399
1400 public static List<ViewManager> findvms(final List<WindowInfo> windows) {
1401 List<ViewManager> vms = new ArrayList<ViewManager>();
1402 for (WindowInfo window : windows) {
1403 for (IdvComponentHolder h : getComponentHolders(window)) {
1404 if (h.getViewManagers() != null) {
1405 vms.addAll((List<ViewManager>)h.getViewManagers());
1406 } else {
1407 System.err.println(h.getUniqueId() + " has no vms!");
1408 }
1409 }
1410 }
1411 for (ViewManager vm : vms) {
1412 System.err.println("vm=" + vm.getViewDescriptor().getName());
1413 }
1414 return vms;
1415 }
1416
1417 private static String vmType(final ViewManager vm) {
1418 if (vm instanceof MapViewManager) {
1419 if (((MapViewManager)vm).getUseGlobeDisplay()) {
1420 return "Globe";
1421 } else {
1422 return "Map";
1423 }
1424 }
1425 return "Other";
1426 }
1427
1428 private static String pad(final String str, final int pad) {
1429 char[] padding = new char[pad*2];
1430 for (int i = 0; i < pad*2; i++) {
1431 padding[i] = ' ';
1432 }
1433 return new String(padding).concat(str);
1434 }
1435
1436 private static void p(final String str, final int padding) {
1437 System.err.println(pad(str, padding));
1438 }
1439
1440 /**
1441 * Find the {@literal "bounds"} for the physical display at {@code index}.
1442 *
1443 * @param index Zero-based index of the desired physical display.
1444 *
1445 * @return Either a {@link java.awt.Rectangle} representing the display's
1446 * bounds, or {@code null} if {@code index} is invalid.
1447 */
1448 public static Rectangle getDisplayBoundsFor(final int index) {
1449 return SystemState.getDisplayBounds().get(index);
1450 }
1451
1452 /**
1453 * Tries to determine the physical display that contains the given
1454 * {@link java.awt.Rectangle}. <b>This method (currently) fails for
1455 * {@code Rectangle}s that span multiple displays!</b>
1456 *
1457 * @param rect {@code Rectangle} to test. Should not be {@code null}.
1458 *
1459 * @return Either the (zero-based) index of the physical display, or
1460 * {@code -1} if there was no match.
1461 */
1462 public static int findDisplayNumberForRectangle(final Rectangle rect) {
1463 Map<Integer, Rectangle> bounds = SystemState.getDisplayBounds();
1464 int index = -1;
1465 for (Entry<Integer, Rectangle> entry : bounds.entrySet()) {
1466 if (entry.getValue().contains(rect)) {
1467 index = entry.getKey();
1468 break;
1469 }
1470 }
1471 return index;
1472 }
1473
1474 /**
1475 * Tries to determine the physical display that contains the given
1476 * {@link java.awt.Component}. <b>This method (currently) fails for
1477 * {@code Component}s that span multiple displays!</b>
1478 *
1479 * @param comp {@code Component} to test. Should not be {@code null}.
1480 *
1481 * @return Either the (zero-based) index of the physical display, or
1482 * {@code -1} if there was no match.
1483 */
1484 public static int findDisplayNumberForComponent(final Component comp) {
1485 return findDisplayNumberForRectangle(
1486 new Rectangle(comp.getLocation(), comp.getSize()));
1487 }
1488
1489 /**
1490 * Tries to determine the physical display that contains the given
1491 * {@link ucar.unidata.ui.MultiFrame}. <b>This method (currently) fails
1492 * for {@code MultiFrame}s that span multiple displays!</b>
1493 *
1494 * @param mf {@code MultiFrame} to test. Should not be {@code null}.
1495 *
1496 * @return Either the (zero-based) index of the physical display, or
1497 * {@code -1} if there was no match.
1498 */
1499 public static int findDisplayNumberForMultiFrame(final MultiFrame mf) {
1500 return findDisplayNumberForRectangle(
1501 new Rectangle(mf.getLocation(), mf.getSize()));
1502 }
1503
1504 /**
1505 * Tries to determine the physical display that contains the rectangle
1506 * defined by the specified coordinates. <b>This method (currently) fails
1507 * for coordinates that span multiple displays!</b>
1508 *
1509 * @param x X coordinate of the upper-left corner.
1510 * @param y Y coordinate of the upper-left corner.
1511 * @param width Width of the rectangle.
1512 * @param height Height of the rectangle.
1513 *
1514 * @return Either the (zero-based) index of the physical display, or
1515 * {@code -1} if there was no match.
1516 *
1517 * @see java.awt.Rectangle#Rectangle(int, int, int, int)
1518 */
1519 public static int findDisplayNumberForCoords(final int x, final int y,
1520 final int width, final int height)
1521 {
1522 return findDisplayNumberForRectangle(
1523 new Rectangle(x, y, width, height));
1524 }
1525
1526 /**
1527 * Tries to determine which physical display contains the
1528 * {@link java.awt.Component} or {@link ucar.unidata.ui.MultiFrame} that
1529 * fired the given event. <b>This method (currently) fails for coordinates
1530 * that span multiple displays!</b>
1531 *
1532 * @param event {@code EventObject} to test. Should not be {@code null}.
1533 *
1534 * @return Either the (zero-based) index of the physical display, or
1535 * {@code -1} if there was no match.
1536 */
1537 public static int findDisplayNumberForEvent(final EventObject event) {
1538 int idx = -1;
1539 Object src = event.getSource();
1540 if (event instanceof HierarchyEvent) {
1541 src = ((HierarchyEvent)event).getChanged();
1542 }
1543 if (src != null) {
1544 if (src instanceof Component) {
1545 idx = findDisplayNumberForComponent((Component)src);
1546 } else if (src instanceof MultiFrame) {
1547 idx = findDisplayNumberForMultiFrame((MultiFrame)src);
1548 }
1549 }
1550 return idx;
1551 }
1552 }