001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2025 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 https://www.gnu.org/licenses/. 027 */ 028 029package edu.wisc.ssec.mcidasv.ui; 030 031import java.awt.BorderLayout; 032import java.awt.Color; 033import java.awt.Component; 034import java.awt.Container; 035import java.awt.Cursor; 036import java.awt.Dimension; 037import java.awt.Font; 038import java.awt.FontMetrics; 039import java.awt.Graphics; 040import java.awt.Image; 041import java.awt.Insets; 042import java.awt.Rectangle; 043import java.awt.event.ActionEvent; 044import java.awt.event.ActionListener; 045import java.awt.event.KeyAdapter; 046import java.awt.event.KeyEvent; 047import java.awt.event.KeyListener; 048import java.awt.event.MouseAdapter; 049import java.awt.event.MouseEvent; 050import java.awt.event.MouseListener; 051import java.awt.image.ImageObserver; 052import java.util.ArrayList; 053import java.util.Hashtable; 054import java.util.List; 055 056import javax.swing.BorderFactory; 057import javax.swing.BoxLayout; 058import javax.swing.ButtonGroup; 059import javax.swing.ImageIcon; 060import javax.swing.JButton; 061import javax.swing.JComponent; 062import javax.swing.JLabel; 063import javax.swing.JMenuItem; 064import javax.swing.JPanel; 065import javax.swing.JPopupMenu; 066import javax.swing.JScrollPane; 067import javax.swing.JToggleButton; 068import javax.swing.SwingConstants; 069import javax.swing.border.Border; 070import javax.swing.border.EtchedBorder; 071 072import edu.wisc.ssec.mcidasv.Constants; 073 074import org.slf4j.Logger; 075import org.slf4j.LoggerFactory; 076import ucar.unidata.idv.DisplayControl; 077import ucar.unidata.idv.IdvConstants; 078import ucar.unidata.idv.IdvManager; 079import ucar.unidata.idv.IntegratedDataViewer; 080import ucar.unidata.idv.MapViewManager; 081import ucar.unidata.idv.TransectViewManager; 082import ucar.unidata.idv.ViewManager; 083import ucar.unidata.idv.control.DisplayControlImpl; 084import ucar.unidata.idv.control.MapDisplayControl; 085import ucar.unidata.idv.ui.IdvComponentGroup; 086import ucar.unidata.idv.ui.IdvWindow; 087import ucar.unidata.idv.ui.ViewPanel; 088import ucar.unidata.ui.ComponentHolder; 089import ucar.unidata.ui.DndImageButton; 090import ucar.unidata.util.GuiUtils; 091import ucar.unidata.util.Misc; 092import ucar.unidata.util.Msg; 093import ucar.unidata.util.StringUtil; 094 095/** 096 * This class has largely been copied over wholesale from the IDV code. 097 * Merely extending was proving to be as much as a hassle as just copying it, 098 * though now we still maintain complete control over the ViewPanel, and we have 099 * an obvious point of departure for whenever the JTree is started. 100 * 101 * <p>That said, I personally recommend avoiding this class until the JTree 102 * stuff is ready to go.</p> 103 */ 104public class McIDASVViewPanel extends IdvManager implements ViewPanel { 105 106 private static final Image BUTTON_ICON = 107 GuiUtils.getImage("/auxdata/ui/icons/Selected.gif"); 108 109 private static final ImageIcon CATEGORY_OPEN_ICON = 110 GuiUtils.getImageIcon("/auxdata/ui/icons/CategoryOpen.gif"); 111 112 private static final ImageIcon CATEGORY_CLOSED_ICON = 113 GuiUtils.getImageIcon("/auxdata/ui/icons/CategoryClosed.gif"); 114 115 private static final Border BUTTON_BORDER = 116 BorderFactory.createEmptyBorder(2, 6, 2, 0); 117 118 private static final Font BUTTON_FONT = new Font("Dialog", Font.PLAIN, 11); 119 private static final Color LINE_COLOR = Color.gray; 120 private static final Font CAT_FONT = new Font("Dialog", Font.BOLD, 11); 121 122 /** The border for the header panel */ 123 public static Border headerNormal = 124 BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3, 125 0, 0, 0), BorderFactory.createMatteBorder(0, 0, 2, 0, 126 Color.black)); 127 128 /** highlight border for view infos */ 129 public static Border headerHighlight = 130 BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(3, 131 0, 0, 0), BorderFactory.createMatteBorder(0, 0, 2, 0, 132 ViewManager.borderHighlightColor)); 133 134 private static Color fgColor = Color.black; 135 private static Color onColor = null; 136 private static boolean showPopup = true; 137 private static boolean showCategories = false; 138 139 private JComponent contents; 140 141 private JPanel leftPanel; 142 143 private JPanel viewContainer; 144 145 private ButtonGroup buttonGroup = new ButtonGroup(); 146 147 private GuiUtils.CardLayoutPanel rightPanel; 148 149 private IntegratedDataViewer idv; 150 151 private enum ViewManagers { DEFAULT, GLOBE, MAP, TRANSECT }; 152 153 private Hashtable<DisplayControl, ControlInfo> controlToInfo = 154 new Hashtable<DisplayControl, ControlInfo>(); 155 156 157 private List<VMInfo> vmInfos = new ArrayList<VMInfo>(); 158 159 public McIDASVViewPanel(IntegratedDataViewer idv) { 160 super(idv); 161 162 this.idv = idv; 163 164 } 165 166 public void createUI() { 167 leftPanel = new JPanel(new BorderLayout()); 168 leftPanel.setBorder( 169 BorderFactory.createCompoundBorder( 170 BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), 171 BorderFactory.createEmptyBorder(0, 0, 0, 0))); 172 173 leftPanel.add(BorderLayout.NORTH, GuiUtils.filler(150, 1)); 174 175 viewContainer = new JPanel(); 176 viewContainer.setLayout(new BoxLayout(viewContainer, BoxLayout.Y_AXIS)); 177 178 JScrollPane viewScroll = new JScrollPane(GuiUtils.top(viewContainer)); 179 viewScroll.setBorder(null); 180 181 leftPanel.add(BorderLayout.CENTER, viewScroll); 182 183 rightPanel = new GuiUtils.CardLayoutPanel() { 184 public void show(Component comp) { 185 super.show(comp); 186 for (VMInfo vinfo : vmInfos) { 187 for (ControlInfo cinfo : vinfo.controlInfos) { 188 if (cinfo.outer == comp) { 189 cinfo.button.setSelected(true); 190 break; 191 } 192 } 193 } 194 } 195 }; 196 197 contents = GuiUtils.leftCenter(leftPanel, rightPanel); 198 Msg.translateTree(contents); 199 } 200 201 public void selectNext(boolean up) { 202 boolean gotit = false; 203 VMInfo select = null; 204 int index = 0; 205 for (int vmIdx = 0; !gotit && (vmIdx < vmInfos.size()); vmIdx++) { 206 207 VMInfo vmInfo = vmInfos.get(vmIdx); 208 209 List<ControlInfo> ctrlInfos = vmInfo.controlInfos; 210 211 for (int i = 0; i < ctrlInfos.size(); i++) { 212 ControlInfo ci = ctrlInfos.get(i); 213 214 if ( !ci.button.isSelected()) 215 continue; 216 217 if (up) { 218 if (vmInfo.getCatOpen() && (i > 0)) { 219 select = vmInfo; 220 index = i - 1; 221 } else { 222 vmIdx--; 223 while (vmIdx >= 0) { 224 VMInfo prev = vmInfos.get(vmIdx--); 225 if (prev.getCatOpen() && (prev.controlInfos.size() > 0)) { 226 select = prev; 227 index = select.controlInfos.size() - 1; 228 break; 229 } 230 } 231 } 232 } else { 233 if (vmInfo.getCatOpen() && (i < ctrlInfos.size() - 1)) { 234 select = vmInfo; 235 index = i + 1; 236 } else { 237 vmIdx++; 238 while (vmIdx < vmInfos.size()) { 239 VMInfo next = vmInfos.get(vmIdx++); 240 if (next.getCatOpen() && (next.controlInfos.size() > 0)) { 241 select = next; 242 index = 0; 243 break; 244 } 245 } 246 } 247 } 248 gotit = true; 249 break; 250 } 251 } 252 253 if ((select != null) && (index >= 0) && (index < select.controlInfos.size())) 254 select.controlInfos.get(index).button.doClick(); 255 } 256 257 public void addControlTab(DisplayControl control, boolean forceShow) { 258 if (!control.canBeDocked() || !control.shouldBeDocked()) 259 return; 260 261 //Check if there are any groups that have autoimport set 262 ViewManager viewManager = control.getViewManager(); 263 if (viewManager != null) { 264 IdvWindow window = viewManager.getDisplayWindow(); 265 if (window != null) { 266 List groups = window.getComponentGroups(); 267 for (int i = 0; i < groups.size(); i++) { 268 Object obj = groups.get(i); 269 if (obj instanceof IdvComponentGroup) { 270 if (((IdvComponentGroup) obj) 271 .tryToImportDisplayControl( 272 (DisplayControlImpl)control)) { 273 return; 274 } 275 } 276 } 277 } 278 } 279 280 ControlInfo info = controlToInfo.get(control); 281 if (info != null) 282 return; 283 284 //For now cheat a little with the cast 285 ((DisplayControlImpl)control).setMakeWindow(false); 286 287 JButton removeBtn = 288 GuiUtils.makeImageButton("/auxdata/ui/icons/Remove16.gif", 289 control, "doRemoveWithPrompt"); 290 removeBtn.setToolTipText("Remove Display Control"); 291 292 JButton expandBtn = 293 GuiUtils.makeImageButton("/auxdata/ui/icons/DownDown.gif", this, 294 "expandControl", control); 295 expandBtn.setToolTipText("Expand in the tabs"); 296 297 JButton exportBtn = 298 GuiUtils.makeImageButton("/auxdata/ui/icons/Export16.gif", this, 299 "undockControl", control); 300 exportBtn.setToolTipText("Undock control window"); 301 302 JButton propBtn = 303 GuiUtils.makeImageButton("/auxdata/ui/icons/Information16.gif", 304 control, "showProperties"); 305 propBtn.setToolTipText("Show Display Control Properties"); 306 307 DndImageButton dnd = new DndImageButton(control, "idv/display"); 308 dnd.setToolTipText("Drag and drop to a window component"); 309// JPanel buttonPanel = 310// GuiUtils.left(GuiUtils.hbox(Misc.newList(expandBtn, exportBtn, 311// propBtn, removeBtn, dnd), 4)); 312 JPanel buttonPanel = 313 GuiUtils.left(GuiUtils.hbox(Misc.newList(exportBtn, 314 propBtn, removeBtn, dnd), 4)); 315 316 buttonPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, 317 Color.lightGray.darker())); 318 319 JComponent inner = 320 (JComponent) ((DisplayControlImpl)control).getOuterContents(); 321 inner = GuiUtils.centerBottom(inner, buttonPanel); 322 JComponent outer = GuiUtils.top(inner); 323 outer.setBorder(BorderFactory.createEmptyBorder(2, 1, 0, 0)); 324 325 // the nested getVMInfo call will actually generate the jpanels that 326 // get added to viewContainer, so we'll need to signal that 327 // viewContainer needs to redraw 328 info = new ControlInfo(control, expandBtn, outer, inner, 329 getVMInfo(control.getDefaultViewManager())); 330 331 // TODO(jon): maybe viewContainer.repack!? 332 viewContainer.revalidate(); 333 334 controlToInfo.put(control, info); 335 336 GuiUtils.toggleHeavyWeightComponents(outer, false); 337 if (!getStateManager().getProperty(IdvConstants.PROP_LOADINGXML, false)) { 338 339 //A hack for now 340 if (!(control instanceof MapDisplayControl)) { 341 GuiUtils.toggleHeavyWeightComponents(outer, true); 342 GuiUtils.showComponentInTabs(outer); 343 } 344 345 } 346 } 347 348 public void expandControl(DisplayControl control) { 349 ControlInfo info = controlToInfo.get(control); 350 if (info != null) 351 info.expand(); 352 } 353 354 public void dockControl(DisplayControl control) { 355 control.setShowInTabs(true); 356 ((DisplayControlImpl)control).guiImported(); 357 addControlTab(control, true); 358 } 359 360 public void undockControl(DisplayControl control) { 361 removeControlTab(control); 362 control.setShowInTabs(false); 363 ((DisplayControlImpl)control).setMakeWindow(true); 364 ((DisplayControlImpl)control).popup(null); 365 } 366 367 public void controlMoved(DisplayControl control) { 368 removeControlTab(control); 369 addControlTab(control, true); 370 } 371 372 public void removeControlTab(DisplayControl control) { 373 ControlInfo info = controlToInfo.remove(control); 374 if (info != null) 375 info.removeDisplayControl(); 376 } 377 378 public JComponent getContents() { 379 if (contents == null) 380 createUI(); 381 382 return contents; 383 } 384 385 public void addDisplayControl(DisplayControl control) { 386 addControlTab(control, false); 387 } 388 389 public void displayControlChanged(DisplayControl control) { 390 ControlInfo info = controlToInfo.get(control); 391 if (info != null) 392 info.displayControlChanged(); 393 } 394 395 public void removeDisplayControl(DisplayControl control) { 396 removeControlTab(control); 397 } 398 399 public void addViewMenuItems(DisplayControl control, List items) { 400 if (!control.canBeDocked()) 401 return; 402 403 items.add(GuiUtils.MENU_SEPARATOR); 404 405 if (!control.shouldBeDocked()) 406 items.add(GuiUtils.makeMenuItem("Dock in Data Explorer", this, "dockControl", control)); 407 else 408 items.add(GuiUtils.makeMenuItem("Undock from Data Explorer", this, "undockControl", control)); 409 410 List groups = getIdvUIManager().getComponentGroups(); 411 List<JMenuItem> subItems = new ArrayList<JMenuItem>(); 412 for (int i = 0; i < groups.size(); i++) { 413 IdvComponentGroup group = (IdvComponentGroup)groups.get(i); 414 subItems.add(GuiUtils.makeMenuItem(group.getHierachicalName(), group, "importDisplayControl", control)); 415 } 416 417 if (subItems.size() > 0) 418 items.add(GuiUtils.makeMenu("Export to component", subItems)); 419 } 420 421 public void viewManagerAdded(ViewManager vm) { 422 // this forces the addition of the ViewManager 423 getVMInfo(vm); 424 } 425 426 public void viewManagerDestroyed(ViewManager vm) { 427 VMInfo info = findVMInfo(vm); 428 if (info != null) { 429 vmInfos.remove(info); 430 info.viewManagerDestroyed(); 431 logger.trace("destroying '{}' for '{}'", info, vm); 432// System.err.println("destroying "+info+" for "+vm); 433 } 434 } 435 436 private static final Logger logger = LoggerFactory.getLogger(McIDASVViewPanel.class); 437 438 /** 439 * Triggered upon a change in the given ViewManager. Just used so that our 440 * ControlInfo object can update its internal state. 441 * 442 * @param vm The ViewManager that's changed. 443 */ 444 public void viewManagerChanged(ViewManager vm) { 445 VMInfo info = findVMInfo(vm); 446 if (info != null) 447 info.viewManagerChanged(); 448 } 449 450 /** 451 * Initialize the button state. 452 */ 453 protected void initButtonState() { 454 if (fgColor != null) 455 return; 456 457 fgColor = Color.black; 458 459 showPopup = idv.getProperty(Constants.PROP_VP_SHOWPOPUP, false); 460 461 showCategories = idv.getProperty(Constants.PROP_VP_SHOWCATS, false); 462 } 463 464 public VMInfo getVMInfo(ViewManager vm) { 465 VMInfo info = findVMInfo(vm); 466 if (info == null) { 467 468 // oh no :( 469 if (vm instanceof MapViewManager) 470 if (((MapViewManager)vm).getUseGlobeDisplay()) 471 info = new VMInfo(vm, ViewManagers.GLOBE); 472 else 473 info = new VMInfo(vm, ViewManagers.MAP); 474 else if (vm instanceof TransectViewManager) 475 info = new VMInfo(vm, ViewManagers.TRANSECT); 476 else 477 info = new VMInfo(vm, ViewManagers.DEFAULT); 478 479 vmInfos.add(info); 480 } 481 return info; 482 } 483 484 public VMInfo findVMInfo(ViewManager vm) { 485 for (VMInfo info : vmInfos) 486 if (info.holds(vm)) 487 return info; 488 489 return null; 490 } 491 492 public class VMInfo implements ImageObserver { 493 private ViewManager viewManager; 494 495 private JButton popupButton; 496 497 private JComponent tabContents = new JPanel(new BorderLayout()); 498 499 private JPanel headerPanel; 500 501 private boolean ignore = false; 502 503 // private list of controlinfos? 504 private List<ControlInfo> controlInfos = new ArrayList<ControlInfo>(); 505 private List<JToggleButton> buttons = new ArrayList<JToggleButton>(); 506 507 //private JComponent buttonPanel; 508 509 private JComponent contents; 510 511 private JLabel viewLabel; 512 513 private JButton catToggle; 514 515 private boolean catOpen = true; 516 517 private KeyListener listener; 518 519 private List<String> categories = new ArrayList<String>(); 520 521 private ViewManagers myType = ViewManagers.DEFAULT; 522 523 public VMInfo(ViewManager vm, ViewManagers type) { 524 525 listener = new KeyAdapter() { 526 public void keyPressed(KeyEvent e) { 527 if (e.getKeyCode() == KeyEvent.VK_UP) 528 selectNext(true); 529 else if (e.getKeyCode() == KeyEvent.VK_DOWN) 530 selectNext(false); 531 } 532 }; 533 534 initButtonState(); 535 BUTTON_ICON.getWidth(this); 536 537 viewManager = vm; 538 539 ImageIcon icon = ICON_DEFAULT; 540 if (type == ViewManagers.GLOBE) 541 icon = ICON_GLOBE; 542 else if (type == ViewManagers.MAP) 543 icon = ICON_MAP; 544 else if (type == ViewManagers.TRANSECT) 545 icon = ICON_TRANSECT; 546 547 viewLabel = new JLabel(" " + getLabel()); 548 viewLabel.addMouseListener(new MouseAdapter() { 549 public void mousePressed(MouseEvent e) { 550 if (viewManager == null) 551 return; 552 553 getVMManager().setLastActiveViewManager(viewManager); 554 if (e.getClickCount() == 2) 555 viewManager.toFront(); 556 } 557 }); 558 559 catToggle = GuiUtils.getImageButton(getCatOpen() ? CATEGORY_OPEN_ICON : CATEGORY_CLOSED_ICON); 560 catToggle.addKeyListener(listener); 561 catToggle.addActionListener(new ActionListener() { 562 public void actionPerformed(ActionEvent e) { 563 setCatOpen(!getCatOpen()); 564 } 565 }); 566 567 popupButton = new JButton(icon); 568 popupButton.addKeyListener(listener); 569 popupButton.setContentAreaFilled(false); 570 popupButton.addActionListener(GuiUtils.makeActionListener(VMInfo.this, "showPopupMenu", null)); 571 popupButton.setToolTipText("Show View Menu"); 572 popupButton.setBorder(BorderFactory.createEmptyBorder()); 573 574 headerPanel = GuiUtils.leftCenter(GuiUtils.hbox( 575 GuiUtils.inset(catToggle, 1), 576 popupButton), viewLabel); 577 578 if (viewManager != null) 579 headerPanel = viewManager.makeDropPanel(headerPanel, true); 580 581 JComponent headerWrapper = GuiUtils.center(headerPanel); 582 headerPanel.setBorder(headerNormal); 583 contents = GuiUtils.topCenter(headerWrapper, tabContents); 584 viewContainer.add(contents); 585 popupButton.setHorizontalAlignment(SwingConstants.LEFT); 586 buttonsChanged(); 587 588 setCatOpen(getCatOpen()); 589 590 if (viewManager != null) 591 viewManagerChanged(); 592 } 593 594 public boolean getCatOpen() { 595 if (viewManager != null) { 596 Boolean b = 597 (Boolean)viewManager.getProperty(Constants.PROP_VP_CATOPEN); 598 if (b != null) 599 return b; 600 } 601 602 return catOpen; 603 } 604 605 public void setCatOpen(boolean v) { 606 if (viewManager != null) 607 viewManager.putProperty(Constants.PROP_VP_CATOPEN, v); 608 609 catOpen = v; 610 catToggle.setIcon(v ? CATEGORY_OPEN_ICON : CATEGORY_CLOSED_ICON); 611 tabContents.setVisible(v); 612 } 613 614 public void showPopupMenu() { 615 if (viewManager == null) 616 return; 617 618 List items = new ArrayList(); 619 viewManager.addContextMenuItems(items); 620 JPopupMenu popup = GuiUtils.makePopupMenu(items); 621 popup.show(popupButton, 0, popupButton.getHeight()); 622 } 623 624 /** 625 * Determine if this VMInfo contains a given ViewManager. 626 * 627 * @param vm The ViewManager you wish to test. 628 * 629 * @return {@code true} if this VMInfo contains {@code vm}, 630 * {@code false} otherwise. 631 */ 632 public boolean holds(ViewManager vm) { 633 return viewManager == vm; 634 } 635 636 public void removeControlInfo(ControlInfo info) { 637 int idx = controlInfos.indexOf(info); 638 if (idx == -1) 639 return; 640 641 int btnIdx = buttons.indexOf(info.button); 642 643 buttons.remove(info.button); 644 controlInfos.remove(info); 645 rightPanel.remove(info.outer); 646 647 if (info.button.isSelected() && (buttons.size() > 0)) { 648 while ((btnIdx >= buttons.size()) && (btnIdx >= 0)) 649 btnIdx--; 650 651 if (btnIdx >= 0) 652 buttons.get(btnIdx).doClick(); 653 } 654 655 GuiUtils.toggleHeavyWeightComponents(info.outer, true); 656 657 buttonsChanged(); 658 659 // hmm -- this must be for synchronization? 660 ignore = true; 661 buttonGroup.remove(info.button); 662 ignore = false; 663 664 665 for (ActionListener l : catToggle.getActionListeners()) { 666 catToggle.removeActionListener(l); 667 } 668 669 for (ActionListener l : popupButton.getActionListeners()) { 670 popupButton.removeActionListener(l); 671 } 672 673 for (MouseListener l : viewLabel.getMouseListeners()) { 674 viewLabel.removeMouseListener(l); 675 } 676 677// for (KeyListener l : catToggle.getKeyListeners()) { 678// catToggle.removeKeyListener(l); 679// } 680 catToggle.removeKeyListener(listener); 681 popupButton.removeKeyListener(listener); 682 info.button.removeKeyListener(listener); 683 684 685 686 // if there are still control infos left then we'll use those? 687 if (controlInfos.size() > 0) 688 return; 689 690 // otherwise we need to click the buttons of each remaining viewmanager? 691 for (VMInfo vm : vmInfos) 692 if (vm.controlInfos.size() > 0) 693 vm.controlInfos.get(0).button.doClick(); 694 } 695 696 public void changeControlInfo(ControlInfo info) { 697 if (!Misc.equals(info.lastCategory, info.control.getDisplayCategory())) 698 buttonsChanged(); 699 } 700 701 public void paintButton(Graphics g, ControlInfo info) { 702 g.setFont(BUTTON_FONT); 703 FontMetrics fm = g.getFontMetrics(g.getFont()); 704 705 JToggleButton btn = info.button; 706 Rectangle b = btn.getBounds(); 707 String text = info.getLabel(); 708 int y = (btn.getHeight() + fm.getHeight()) / 2 - 2; 709 int buttonWidth = BUTTON_ICON.getWidth(null); 710 int offset = 2 + buttonWidth + 4; 711 g.setColor(btn.getBackground()); 712 g.fillRect(0, 0, b.width, b.height); 713 714 if (btn.isSelected()) { 715 716 if (onColor == null) { 717 Color c = btn.getBackground(); 718 //Just go a little bit darker than the normal background 719 onColor = new Color((int) Math.max(0, 720 c.getRed() - 20), (int) Math.max(0, 721 c.getGreen() - 20), (int) Math.max(0, 722 c.getBlue() - 20)); 723 } 724 725 g.setColor(onColor); 726 g.fillRect(offset - 1, 0, b.width, b.height); 727 } 728 g.setColor(LINE_COLOR); 729 730 g.drawLine(offset - 1, b.height - 1, b.width, b.height - 1); 731 732 g.setColor(fgColor); 733 int rightSide = b.width; 734 if (btn.isSelected()) 735 rightSide = b.width - buttonWidth - 2; 736 737 int textPos = offset; 738 int textRight = textPos + fm.stringWidth(text); 739 if (textRight >= rightSide) { 740 while ((text.length() > 5) && (textRight >= rightSide)) { 741 text = text.substring(0, text.length() - 2); 742 textRight = textPos + fm.stringWidth(text + "."); 743 } 744 text = text + "."; 745 } 746 g.drawString(text, offset, y); 747 748 if (!btn.isSelected()) 749 return; 750 751 int height = BUTTON_ICON.getHeight(null); 752 g.drawImage(BUTTON_ICON, b.width - 2 - buttonWidth, b.height / 2 - height / 2, null); 753 } 754 755 public void addControlInfo(final ControlInfo info) { 756 // ugly :( 757 // why even have b? 758 //JToggleButton b = info.button = new JToggleButton(StringUtil.padRight("", 20), true) { 759 info.button = new JToggleButton(StringUtil.padRight("", 20), true) { 760 public void paint(Graphics g) { 761 paintButton(g, info); 762 } 763 }; 764 765 info.button.addKeyListener(listener); 766 info.button.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 767 info.button.setToolTipText(info.getLabel()); 768 info.button.setFont(BUTTON_FONT); 769 info.button.setForeground(fgColor); 770 info.button.setBorder(BUTTON_BORDER); 771 772 info.button.setHorizontalAlignment(SwingConstants.LEFT); 773 info.button.addActionListener(new ActionListener() { 774 public void actionPerformed(ActionEvent e) { 775 if (ignore) 776 return; 777 778 GuiUtils.toggleHeavyWeightComponents(info.outer, true); 779 rightPanel.show(info.outer); 780 } 781 }); 782 buttons.add(info.button); 783 controlInfos.add(info); 784 rightPanel.addCard(info.outer); 785 GuiUtils.toggleHeavyWeightComponents(info.outer, false); 786 info.displayControlChanged(); 787 788 if (info.control.getExpandedInTabs()) 789 info.expand(); 790 791 buttonGroup.add(info.button); 792 buttonsChanged(); 793 setCatOpen(getCatOpen()); 794 } 795 796 /** 797 * Redo the buttons 798 */ 799 private void buttonsChanged() { 800 List<JComponent> comps = new ArrayList<JComponent>(); 801 802 Hashtable<String, List<JComponent>> catMap = 803 new Hashtable<String, List<JComponent>>(); 804 805 for (ControlInfo info : controlInfos) { 806 String cat = info.control.getDisplayCategory(); 807 if (cat == null) 808 cat = "Displays"; 809 810 info.lastCategory = cat; 811 812 if (!showCategories) { 813 comps.add(info.button); 814 continue; 815 } 816 817 List<JComponent> catList = catMap.get(cat); 818 if (catList == null) { 819 if (!categories.contains(cat)) 820 categories.add(cat); 821 822 catList = new ArrayList<JComponent>(); 823 824 catMap.put(cat, catList); 825 826 JLabel catLabel = new JLabel(" " + cat); 827 828 catLabel.setFont(CAT_FONT); 829 830 catList.add(catLabel); 831 } 832 catList.add(info.button); 833 } 834 835 if (showCategories) { 836 for (String category : categories) { 837 List<JComponent> catList = catMap.get(category); 838 if (catList != null) 839 comps.addAll(catList); 840 } 841 } 842 843 if (comps.size() == 0) { 844 if (myType == ViewManagers.TRANSECT) { 845 JLabel noLbl = new JLabel("No Displays"); 846 noLbl.setFont(BUTTON_FONT); 847 JPanel inset = GuiUtils.inset(noLbl, new Insets(0, 10, 0, 0)); 848 inset.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, 849 Color.gray)); 850 comps.add(inset); 851 } else { 852 headerPanel.setVisible(false); 853 } 854 } else { 855 headerPanel.setVisible(true); 856 } 857 858 comps.add(GuiUtils.filler(10, 2)); 859 JComponent buttonPanel = GuiUtils.vbox(comps); 860 861 tabContents.removeAll(); 862 tabContents.add(BorderLayout.NORTH, buttonPanel); 863 tabContents.repaint(); 864 } 865 866 /** 867 * Handles ViewManager removal. 868 */ 869 public void viewManagerDestroyed() { 870 viewContainer.remove(contents); 871 buttons.clear(); 872 } 873 874 /** 875 * my viewmanager has changed. Update the gui. 876 */ 877 public void viewManagerChanged() { 878 viewLabel.setText(getLabel()); 879 880 if (viewManager.showHighlight()) { 881 882 headerHighlight = 883 BorderFactory.createCompoundBorder( 884 BorderFactory.createEmptyBorder(3, 0, 0, 0), 885 BorderFactory.createMatteBorder( 886 0, 0, 2, 0, 887 getStore().get( 888 ViewManager.PREF_BORDERCOLOR, Color.blue))); 889 890 headerPanel.setBorder(headerHighlight); 891 } else { 892 headerPanel.setBorder(headerNormal); 893 } 894 895 if (contents != null) 896 contents.repaint(); 897 } 898 899 /** 900 * Get the ViewManager label. If the ViewManager does not already have 901 * a valid name, a default name is created, based on the number of 902 * existing ViewManagers. 903 * 904 * @return label The ViewManager's name. 905 */ 906 public String getLabel() { 907 // nothing to query for a name? 908 if (viewManager == null) 909 return "No Display"; 910 911 // do we already have a valid name? 912 String name = viewManager.getName(); 913 if ((name != null) && (name.trim().length() > 0)) { 914 UIManager uiManager = (UIManager)idv.getIdvUIManager(); 915 ComponentHolder holder = uiManager.getViewManagerHolder(viewManager); 916 if (holder != null) 917 return holder.getName() + ">" + name; 918 else 919 return name; 920 } 921 922 // if our name was invalid, build a default one. 923 int idx = vmInfos.indexOf(this); 924 return "Default " + Constants.PANEL_NAME + " " + 925 ((idx == -1) ? vmInfos.size() : idx); 926 } 927 928 public boolean imageUpdate(Image img, int flags, int x, int y, int width, int height) { 929 if ((flags & ImageObserver.ALLBITS) == 0) 930 return true; 931 932 leftPanel.repaint(); 933 return false; 934 } 935 } 936 937 public class ControlInfo { 938 DisplayControl control; 939 JButton expandButton; 940 JComponent outer; 941 JComponent inner; 942 boolean expanded = false; 943 Dimension innerSize = new Dimension(); 944 VMInfo info; 945 JToggleButton button; 946 String lastCategory = ""; 947 String label = null; 948 949 /** 950 * ctor 951 * 952 * @param control control 953 * @param expandButton expand button 954 * @param outer outer comp 955 * @param inner inner comp 956 * @param vmInfo my vminfo 957 */ 958 public ControlInfo(DisplayControl control, JButton expandButton, 959 JComponent outer, JComponent inner, 960 VMInfo vmInfo) { 961 this.info = vmInfo; 962 this.control = control; 963 if (control.getExpandedInTabs()) 964 expanded = false; 965 966 this.expandButton = expandButton; 967 this.outer = outer; 968 this.inner = inner; 969 inner.getSize(innerSize); 970 info.addControlInfo(this); 971 this.expand(); 972 } 973 974 /** 975 * get the label for the display control 976 * 977 * @return display control label 978 */ 979 public String getLabel() { 980 if (label == null) 981 label = control.getMenuLabel(); 982 983 return label; 984 } 985 986 /** 987 * display control changed 988 */ 989 public void displayControlChanged() { 990 String tmp = label; 991 label = null; 992 getLabel(); 993 if (!Misc.equals(tmp, label) && (button != null)) { 994 button.setToolTipText(label); 995 button.repaint(); 996 } 997 info.changeControlInfo(this); 998 } 999 1000 /** 1001 * display control is removed 1002 */ 1003 public void removeDisplayControl() { 1004 info.removeControlInfo(this); 1005 } 1006 1007 /** 1008 * Expand the contents 1009 */ 1010 public void expand() { 1011 outer.removeAll(); 1012 outer.setLayout(new BorderLayout()); 1013 1014 if (!expanded) { 1015 outer.add(BorderLayout.CENTER, inner); 1016 expandButton.setIcon( 1017 GuiUtils.getImageIcon("/auxdata/ui/icons/UpUp.gif")); 1018 inner.getSize(innerSize); 1019// System.err.println("ControlInfo.expand: innerSize=" + innerSize); 1020 } else { 1021 outer.add(BorderLayout.NORTH, inner); 1022 expandButton.setIcon( 1023 GuiUtils.getImageIcon("/auxdata/ui/icons/DownDown.gif")); 1024 inner.setSize(innerSize); 1025 } 1026 1027 expanded = !expanded; 1028 control.setExpandedInTabs(expanded); 1029 1030 final Container parent = outer.getParent(); 1031 outer.invalidate(); 1032 parent.validate(); 1033 parent.doLayout(); 1034 } 1035 } 1036}