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