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