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 }