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 }