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.chooser.adde; 030 031import static edu.wisc.ssec.mcidasv.McIDASV.isLoopback; 032import static edu.wisc.ssec.mcidasv.servermanager.AddeEntry.DEFAULT_ACCOUNT; 033import static edu.wisc.ssec.mcidasv.servermanager.EntryTransforms.strToEntryType; 034import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.arrList; 035import static edu.wisc.ssec.mcidasv.util.CollectionHelpers.cast; 036 037import static javax.swing.GroupLayout.DEFAULT_SIZE; 038import static javax.swing.GroupLayout.Alignment.BASELINE; 039import static javax.swing.GroupLayout.Alignment.LEADING; 040import static javax.swing.GroupLayout.Alignment.TRAILING; 041import static javax.swing.LayoutStyle.ComponentPlacement.RELATED; 042import static javax.swing.LayoutStyle.ComponentPlacement.UNRELATED; 043 044import java.awt.Component; 045import java.awt.Dimension; 046import java.awt.event.ActionEvent; 047import java.awt.event.ActionListener; 048import java.awt.event.ItemEvent; 049import java.awt.event.ItemListener; 050import java.awt.event.KeyEvent; 051import java.awt.event.KeyListener; 052import java.awt.event.MouseAdapter; 053import java.awt.event.MouseEvent; 054import java.io.EOFException; 055import java.io.InputStream; 056import java.io.PrintWriter; 057import java.io.StringWriter; 058import java.io.Writer; 059import java.net.ConnectException; 060import java.net.URLConnection; 061import java.util.ArrayList; 062import java.util.Arrays; 063import java.util.Collections; 064import java.util.Comparator; 065import java.util.Enumeration; 066import java.util.HashMap; 067import java.util.Hashtable; 068import java.util.LinkedHashMap; 069import java.util.List; 070import java.util.Map; 071import java.util.Objects; 072import java.util.Vector; 073import java.util.regex.Pattern; 074 075import javax.swing.GroupLayout; 076import javax.swing.JButton; 077import javax.swing.JCheckBox; 078import javax.swing.JComboBox; 079import javax.swing.JComponent; 080import javax.swing.JLabel; 081import javax.swing.JMenu; 082import javax.swing.JMenuItem; 083import javax.swing.JPanel; 084import javax.swing.JPopupMenu; 085import javax.swing.JScrollPane; 086import javax.swing.JTabbedPane; 087import javax.swing.JTextField; 088import javax.swing.SwingUtilities; 089import javax.swing.event.DocumentEvent; 090import javax.swing.event.DocumentListener; 091import javax.swing.text.BadLocationException; 092 093import org.bushe.swing.event.annotation.AnnotationProcessor; 094import org.bushe.swing.event.annotation.EventSubscriber; 095import org.slf4j.Logger; 096import org.slf4j.LoggerFactory; 097import org.w3c.dom.Element; 098 099import ucar.unidata.idv.chooser.IdvChooser; 100import ucar.unidata.idv.chooser.IdvChooserManager; 101import ucar.unidata.idv.chooser.adde.AddeServer; 102import ucar.unidata.idv.chooser.adde.AddeServer.Group; 103import ucar.unidata.util.DatedThing; 104import ucar.unidata.util.GuiUtils; 105import ucar.unidata.util.IOUtil; 106import ucar.unidata.util.LogUtil; 107import ucar.unidata.util.Misc; 108import ucar.unidata.util.PreferenceList; 109import ucar.unidata.util.StringUtil; 110import ucar.unidata.xml.XmlObjectStore; 111 112import visad.DateTime; 113 114import edu.wisc.ssec.mcidas.adde.AddeURLException; 115import edu.wisc.ssec.mcidas.adde.DataSetInfo; 116import edu.wisc.ssec.mcidasv.Constants; 117import edu.wisc.ssec.mcidasv.McIDASV; 118import edu.wisc.ssec.mcidasv.ParameterSet; 119import edu.wisc.ssec.mcidasv.PersistenceManager; 120import edu.wisc.ssec.mcidasv.servermanager.AddeAccount; 121import edu.wisc.ssec.mcidasv.servermanager.AddeEntry; 122import edu.wisc.ssec.mcidasv.servermanager.AddeEntry.EditorAction; 123import edu.wisc.ssec.mcidasv.servermanager.AddeEntry.EntrySource; 124import edu.wisc.ssec.mcidasv.servermanager.AddeEntry.EntryType; 125import edu.wisc.ssec.mcidasv.servermanager.AddeEntry.EntryValidity; 126import edu.wisc.ssec.mcidasv.servermanager.EntryStore; 127import edu.wisc.ssec.mcidasv.servermanager.EntryTransforms; 128import edu.wisc.ssec.mcidasv.servermanager.LocalAddeEntry; 129import edu.wisc.ssec.mcidasv.servermanager.LocalEntryEditor; 130import edu.wisc.ssec.mcidasv.servermanager.RemoteAddeEntry; 131import edu.wisc.ssec.mcidasv.servermanager.RemoteEntryEditor; 132import edu.wisc.ssec.mcidasv.servermanager.TabbedAddeManager; 133import edu.wisc.ssec.mcidasv.ui.MenuScroller; 134import edu.wisc.ssec.mcidasv.ui.ParameterTree; 135import edu.wisc.ssec.mcidasv.ui.UIManager; 136import edu.wisc.ssec.mcidasv.util.CollectionHelpers; 137import edu.wisc.ssec.mcidasv.util.McVGuiUtils; 138import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Position; 139import edu.wisc.ssec.mcidasv.util.McVGuiUtils.TextColor; 140import edu.wisc.ssec.mcidasv.util.McVGuiUtils.Width; 141import edu.wisc.ssec.mcidasv.util.McVTextField; 142 143/** 144 * 145 * @version $Revision$ 146 */ 147 148public class AddeChooser extends ucar.unidata.idv.chooser.adde.AddeChooser implements Constants { 149 150 private static final long serialVersionUID = 1L; 151 152 private static final Logger logger = LoggerFactory.getLogger(AddeChooser.class); 153 154 /** Label to use with the relative times {@link JTextField}. */ 155 public static final String RELATIVE_TIMES_LABEL = "Number of times: "; 156 157 /** Tooltip for the relative times {@link JTextField}. */ 158 public static final String RELATIVE_TIMES_TOOLTIP = 159 "<html>Load the N most recent images.<br/><br/>" + 160 "Values must be integers greater than zero.</html>"; 161 162 private JComboBox serverSelector; 163 164 /** List of descriptors */ 165 private PreferenceList descList; 166 167 /** Descriptor/name hashtable */ 168 protected Hashtable descriptorTable; 169 170 /** List of available descriptors. */ 171 protected List<String> descriptorList; 172 173 /** List of comments associated with list of descriptors. */ 174 protected List<String> commentList; 175 176 /** Property for the descriptor table */ 177 public static final String DESCRIPTOR_TABLE = "DESCRIPTOR_TABLE"; 178 179 /** Archive day selector button. */ 180 protected JButton archiveDayBtn; 181 182 /** archive date */ 183 protected String archiveDay = null; 184 185 /** archive date */ 186 protected String archiveBegTime = null; 187 188 /** archive date */ 189 protected String archiveEndTime = null; 190 191 /** Button label for day and optional time range selection */ 192 protected final static String DAY_TIME_RANGE_LABEL = "Set Day/Time Range"; 193 194 /** Connect button--we need to be able to disable this */ 195 JButton connectButton = McVGuiUtils.makeImageTextButton(ICON_CONNECT_SMALL, "Connect"); 196 197 /** Parameter button--we need to be able to disable this */ 198 JButton parameterButton = 199 McVGuiUtils.makeImageButton("/edu/wisc/ssec/mcidasv/resources/icons/toolbar/document-open22.png", 200 this, "doParameters", null, "Load parameter set"); 201 202 /** Manage button */ 203 JButton manageButton = 204 McVGuiUtils.makeImageButton("/edu/wisc/ssec/mcidasv/resources/icons/toolbar/preferences-system22.png", 205 this, "doManager", null, "Manage servers"); 206 207 /** Public button--we need to draw a menu from this */ 208 protected JButton publicButton = 209 McVGuiUtils.makeImageButton("/edu/wisc/ssec/mcidasv/resources/icons/toolbar/show-layer-controls22.png", 210 this, "showGroups", null, "List public datasets"); 211 212 /** descriptor label */ 213 protected JLabel descriptorLabel = new JLabel(getDescriptorLabel()+":"); 214 215 /** A widget for the list of dataset descriptors */ 216 protected JComboBox descriptorComboBox = new JComboBox(); 217 218 /** The descriptor names */ 219 protected String[] descriptorNames; 220 221 /** Flag to keep from infinite looping */ 222 protected boolean ignoreDescriptorChange = false; 223 224 /** 225 * List of JComponent-s that depend on a descriptor being selected 226 * to be enabled 227 */ 228 protected ArrayList compsThatNeedDescriptor = new ArrayList(); 229 230 /** Selection label text */ 231 protected String LABEL_SELECT = " -- Select -- "; 232 233 /** Separator string */ 234 protected static String separator = "----------------"; 235 236 /** Name separator string */ 237 protected static String nameSeparator = " - "; 238 239 /** Reference back to the server manager */ 240 protected EntryStore serverManager; 241 242 public boolean allServersFlag; 243 244 /** Command for opening up the server manager */ 245 protected static final String CMD_MANAGER = "cmd.manager"; 246 247 private String lastBadServer = ""; 248 private String lastBadGroup = ""; 249 250 private String lastServerName = ""; 251 private String lastServerGroup = ""; 252 private String lastServerUser = ""; 253 private String lastServerProj = ""; 254 private AddeServer lastServer = new AddeServer(""); 255 256 private List<AddeServer> addeServers; 257 258 /** Used for parameter set restore */ 259 private static final String ATTR_SERVER = "server"; 260 private static final String ATTR_GROUP = "GROUP"; 261 private static final String ATTR_DESCRIPTOR = "DESCRIPTOR"; 262 private static final String ATTR_POS = "POS"; 263 private static final String ATTR_DAY = "DAY"; 264 private static final String ATTR_TIME = "TIME"; 265 private List restoreTimes = new ArrayList(); 266 public Element restoreElement; 267 private boolean shouldAddSource = false; 268 final JCheckBox cb = new JCheckBox("Add source",shouldAddSource); 269 270 /** Maps favorite type to the BundleTree that shows the Manage window for the type */ 271 private Hashtable parameterTrees = new Hashtable(); 272 273 /** Number of relative time steps to load */ 274 private int relativeTimes = 5; 275 276 /** 277 * Create an AddeChooser associated with an IdvChooser 278 * 279 * @param mgr The chooser manager 280 * @param root The chooser.xml node 281 */ 282 public AddeChooser(IdvChooserManager mgr, Element root) { 283 super(mgr, root); 284 AnnotationProcessor.process(this); 285 descriptorList = new ArrayList<String>(); 286 commentList = new ArrayList<String>(); 287 288 simpleMode = !getProperty(IdvChooser.ATTR_SHOWDETAILS, true); 289 290 loadButton = McVGuiUtils.makeImageTextButton(ICON_ACCEPT_SMALL, getLoadCommandName()); 291 loadButton.setActionCommand(getLoadCommandName()); 292 loadButton.addActionListener(this); 293 294 cancelButton = McVGuiUtils.makeImageButton(ICON_CANCEL, "Cancel"); 295 cancelButton.setActionCommand(GuiUtils.CMD_CANCEL); 296 cancelButton.addActionListener(this); 297 cancelButton.setEnabled(false); 298 299 serverSelector = getServerSelector(); 300 301 serverSelector.setToolTipText("Right click to manage servers"); 302 serverSelector.getEditor().getEditorComponent().addMouseListener( 303 new MouseAdapter() { 304 public void mouseReleased(MouseEvent e) { 305 if (!SwingUtilities.isRightMouseButton(e)) { 306 return; 307 } 308 309 AddeServer server = getAddeServer(); 310 if (server == null) { 311 return; 312 } 313 List<JMenuItem> items = new ArrayList<JMenuItem>(); 314 315 // Set the right-click behavior 316 if (isLocalServer()) { 317 items.add(GuiUtils.makeMenuItem("Manage local ADDE data", 318 AddeChooser.this, 319 "doManager", null)); 320 } 321 else { 322 items.add(GuiUtils.makeMenuItem("Manage ADDE servers", 323 AddeChooser.this, 324 "doManager", null)); 325 } 326 JPopupMenu popup = GuiUtils.makePopupMenu(items); 327 popup.show(serverSelector, e.getX(), e.getY()); 328 } 329 }); 330 serverSelector.setMaximumRowCount(16); 331 332 groupSelector.setToolTipText("Right click to manage servers"); 333 groupSelector.getEditor().getEditorComponent().addMouseListener( 334 new MouseAdapter() { 335 public void mouseReleased(MouseEvent e) { 336 if (!SwingUtilities.isRightMouseButton(e)) { 337 return; 338 } 339 340 AddeServer server = getAddeServer(); 341 if (server == null) { 342 return; 343 } 344 List<JMenuItem> items = new ArrayList<JMenuItem>(); 345 346 // Set the right-click behavior 347 if (isLocalServer()) { 348 items.add(GuiUtils.makeMenuItem("Manage local ADDE data", 349 AddeChooser.this, "doManager", null)); 350 } 351 else { 352 items.add(GuiUtils.makeMenuItem("Manage ADDE servers", 353 AddeChooser.this, "doManager", null)); 354 } 355 JPopupMenu popup = GuiUtils.makePopupMenu(items); 356 popup.show(groupSelector, e.getX(), e.getY()); 357 } 358 }); 359 groupSelector.setMaximumRowCount(16); 360 361 // serverManager = ((McIDASV)getIdv()).getServerManager(); 362 // serverManager.addManagedChooser(this); 363 addServerComp(descriptorLabel); 364 // addServerComp(descriptorComboBox); 365 366 descriptorComboBox.addItemListener(new ItemListener() { 367 @Override public void itemStateChanged(ItemEvent e) { 368 if (!ignoreDescriptorChange 369 && (e.getStateChange() == ItemEvent.SELECTED)) { 370 descriptorChanged(); 371 } 372 } 373 }); 374 375 // Update the server list and load the saved state 376 updateServerList(); 377 loadServerState(); 378 379 // Default to no parameter button unless the overriding class wants one 380 hideParameterButton(); 381 } 382 383 /** 384 * Force a reload of the available servers and groups. 385 */ 386 public void updateServerList() { 387 updateServers(); 388 updateGroups(); 389 } 390 391 /** 392 * Returns a {@link java.util.Map Map} containing {@code user} and {@code proj} 393 * keys for the given {@code server/group} combination. 394 * 395 * <p>The values are either the specific ADDE account details for 396 * {@code server/group} or {@link edu.wisc.ssec.mcidasv.servermanager.AddeEntry#DEFAULT_ACCOUNT DEFAULT_ACCOUNT} 397 * values. 398 * 399 * @param server Server name. Should not be {@code null}. 400 * @param group Group name on {@code name}. Should not be {@code null}. 401 * 402 * @return {@code Map} containing the accounting details for {@code server/group}. 403 */ 404 protected Map<String, String> getAccounting(final String server, final String group) { 405 Map<String, String> acctInfo = new HashMap<String, String>(); 406 EntryStore entryStore = ((McIDASV)getIdv()).getServerManager(); 407 String strType = this.getDataType(); 408 EntryType type = strToEntryType(strType); 409 AddeAccount acct = entryStore.getAccountingFor(server, group, type); 410 acctInfo.put("user", acct.getUsername()); 411 acctInfo.put("proj", acct.getProject()); 412 return acctInfo; 413 } 414 415 /** 416 * Returns a {@link java.util.Map Map} containing {@code user} and {@code proj} 417 * keys for the given {@code server/group} combination. 418 * 419 * <p>The values are either the specific ADDE account details for 420 * {@code server/group} or {@link edu.wisc.ssec.mcidasv.servermanager.AddeEntry#DEFAULT_ACCOUNT DEFAULT_ACCOUNT} 421 * values. 422 * 423 * @param server Server name. Should not be {@code null}. 424 * @param group Group name on {@code name}. Should not be {@code null}. 425 * 426 * @return {@code Map} containing the accounting details for {@code server/group}. 427 */ 428 protected Map<String, String> getAccounting(final AddeServer server, final String group) { 429 return getAccounting(server.getName(), group); 430 } 431 432 private List<AddeServer> getManagedServers(final String type) { 433 EntryStore entryStore = ((McIDASV)getIdv()).getServerManager(); 434 return arrList(entryStore.getIdvStyleEntries(type)); 435 } 436 437 /** 438 * Query the {@link EntryStore server manager} to determine the 439 * {@literal "format"} used by a given descriptor. 440 * 441 * @param descriptor Local ADDE descriptor to check. 442 * Value can be {@code null}. 443 * 444 * @return Either the format associated with the given {@code descriptor} 445 * or {@link LocalAddeEntry.AddeFormat#INVALID}. 446 */ 447 public LocalAddeEntry.AddeFormat getFormatFromDescriptor(String descriptor) { 448 return ((McIDASV)getIdv()).getServerManager().getLocalEntries().stream() 449 .filter(entry -> Objects.equals(descriptor, 450 entry.getDescriptor().toUpperCase())) 451 .findFirst().map(LocalAddeEntry::getFormat) 452 .orElse(LocalAddeEntry.AddeFormat.INVALID); 453 } 454 455 /** 456 * Determine whether or not the specified {@code format} requires use of 457 * the absolute times tab. 458 * 459 * <p>Thus far, only {@link LocalAddeEntry.AddeFormat#SCMI} needs this 460 * treatment.</p> 461 * 462 * @param format Local ADDE {@literal "format"} to check. 463 * 464 * @return Whether or not {@code format} should use <b>only</b> the 465 * absolute times tab. 466 */ 467 public boolean formatRequiresAbsolute(LocalAddeEntry.AddeFormat format) { 468 return format == LocalAddeEntry.AddeFormat.SCMI; 469 } 470 471 public void updateServers() { 472 Object selected = serverSelector.getSelectedItem(); 473 474 String type = getGroupType(); 475 List<AddeServer> managedServers = getManagedServers(type); 476 List<AddeServer> localList = arrList(); 477 List<AddeServer> remoteList = arrList(); 478 addeServers = CollectionHelpers.arrList(); 479 for (AddeServer server : managedServers) { 480 if (server.getIsLocal()) 481 localList.add(server); 482 else 483 remoteList.add(server); 484 } 485 486// logger.debug("{}: updateServers: local size={} contents={}", new Object[] { getDataType(), localList.size(), localList }); 487// logger.debug("{}: updateServers: remote size={} contents={}", new Object[] { getDataType(), remoteList.size(), remoteList }); 488 489 // server list doesn't need a separator if there's only remote servers 490 if (!localList.isEmpty()) { 491 addeServers.addAll(localList); 492 addeServers.add(new AddeServer(separator)); 493 } 494 Comparator<AddeServer> byServer = new ServerComparator(); 495 Collections.sort(remoteList, byServer); 496 addeServers.addAll(remoteList); 497 498 // always making this call helps to ensure the chooser stays up to date 499 // with the server manager. 500 GuiUtils.setListData(serverSelector, addeServers); 501 if (!addeServers.isEmpty()) { 502 if (selected == null || !containsServerName(addeServers, selected)) { 503 selected = serverSelector.getItemAt(0); 504// logger.debug("updateServers: selecting item at idx=0, item={} chooser={}", selected, this.getDataType()); 505 } 506 507 int index = getSelectorIndex(selected, serverSelector); 508 serverSelector.setSelectedIndex(index); 509 } 510 } 511 512 /** 513 * Searches the given {@link java.util.List List} of {@link ucar.unidata.idv.chooser.adde.AddeServer AddeServers} 514 * for {@code server}. 515 * 516 * @param servers Servers to search. {@code null} is permitted. 517 * @param server Server to search for within {@code servers}. {@code null} is permitted. 518 * 519 * @return {@code true} if {@code servers} contains {@code server} or {@code false} otherwise. 520 */ 521 protected static boolean containsServerName(final List<AddeServer> servers, final Object server) { 522 if (servers == null || server == null) { 523 return false; 524 } 525 String serverName = (server instanceof AddeServer) ? ((AddeServer)server).getName() : server.toString(); 526 for (AddeServer tmp : servers) { 527 if (tmp.getName().equals(serverName)) { 528 return true; 529 } 530 } 531 return false; 532 } 533 534 /** 535 * Searches the given {@link java.util.List List} of {@link ucar.unidata.idv.chooser.adde.AddeServer.Group Groups} 536 * for {@code group}. 537 * 538 * @param groups Groups to search. {@code null} is permitted. 539 * @param group Group to search for within {@code group}. {@code null} is permitted. 540 * 541 * @return {@code true} if {@code groups} contains {@code group} or {@code false} otherwise. 542 */ 543 protected static boolean containsGroupName(final List<Group> groups, final Object group) { 544 if (groups == null || group == null) { 545 return false; 546 } 547 String groupName = (group instanceof Group) ? ((Group)group).getName() : group.toString(); 548 for (Group tmp : groups) { 549 if (tmp.getName().equals(groupName)) { 550 return true; 551 } 552 } 553 return false; 554 } 555 556 /** 557 * Sort the groups alphabetically 558 */ 559 public void updateGroups() { 560 if (addingServer || groupSelector == null || getAddeServer() == null) 561 return; 562 563 Object selected = groupSelector.getSelectedItem(); 564 565 EntryStore servManager = ((McIDASV)getIdv()).getServerManager(); 566 567 List<Group> groups = CollectionHelpers.arrList(); 568 if (isLocalServer()) { 569 groups.addAll(servManager.getIdvStyleLocalGroups()); 570 } else { 571 String sel = null; 572 Object obj = serverSelector.getSelectedItem(); 573 if (obj instanceof String) { 574 sel = (String)obj; 575// logger.debug("updateGroups: string={} chooser={}", sel, this.getDataType()); 576 } else if (obj instanceof AddeServer) { 577 sel = ((AddeServer)obj).getName(); 578// logger.debug("updateGroups: server selection={} chooser={}", sel, this.getDataType()); 579 } else { 580 sel = obj.toString(); 581// logger.debug("updateGroups: unknown type={}; toString={}", sel.getClass().getName(), sel); 582 } 583 584 EntryType selType = strToEntryType(getGroupType()); 585 groups.addAll(servManager.getIdvStyleRemoteGroups(sel, selType)); 586 } 587// logger.trace("updateGroups: selected={} (type={}) chooser={} contents={}", new Object[] { serverSelector.getSelectedItem(), serverSelector.getSelectedItem().getClass().getName(), this.getDataType(), groups}); 588 Comparator<Group> byGroup = new GroupComparator(); 589 Collections.sort(groups, byGroup); 590 GuiUtils.setListData(groupSelector, groups); 591 if (!groups.isEmpty()) { 592 if (selected == null || !containsGroupName(groups, selected)) { 593 selected = groupSelector.getItemAt(0); 594 } 595 groupSelector.setSelectedItem(selected); 596 } 597 } 598 599 /** 600 * Load any saved server state 601 */ 602 @Override protected void loadServerState() { 603 if (addeServers == null) { 604// logger.debug("loadServerState: addeServers == null chooser={}", this.getDataType()); 605 return; 606 } 607 String[] serverState = getDefaultServerSelection(); 608 if (serverState == null) { 609// serverState = Constants.DEFAULT_SERVERSTATE; 610// logger.debug("loadServerState: serverState == null chooser={}",this.getDataType()); 611 return; 612 } 613 AddeServer server = AddeServer.findServer(addeServers, serverState[0]); 614 if (server == null) { 615// logger.debug("loadServerState: server == null chooser={}",this.getDataType()); 616 return; 617 } 618// logger.debug("loadServerState: selecting server={} chooser={}", server, this.getDataType()); 619 serverSelector.setSelectedItem(server); 620 setGroups(); 621 updateGroups(); 622 if (serverState[1] != null) { 623 Group group = new Group(getDataType(), serverState[1], serverState[1]); 624 int index = getSelectorIndex(group, groupSelector); 625 if (index >= 0) { 626// logger.debug("loadServerState: selecting index={} group={} chooser={}", new Object[] { index, group, this.getDataType() }); 627 groupSelector.setSelectedIndex(index); 628 } else { 629// logger.debug("loadServerState: group == null chooser={}", this.getDataType()); 630 } 631 } else { 632// logger.debug("loadServerState: serverState[1] == null chooser={}", this.getDataType()); 633 } 634 } 635 636 /** 637 * Decide if the server you're asking about is actually a separator 638 */ 639 protected static boolean isSeparator(AddeServer checkServer) { 640 if (checkServer != null) { 641 if (checkServer.getName().equals(separator)) { 642 return true; 643 } 644 } 645 return false; 646 } 647 648 /** 649 * Decide if the server you're asking about is local 650 */ 651 protected boolean isLocalServer() { 652 return isLocalServer(getAddeServer()); 653 } 654 655 protected static boolean isLocalServer(AddeServer checkServer) { 656 if (checkServer != null) { 657 return checkServer.getIsLocal(); 658 } 659 return false; 660 } 661 662 private void setBadServer(String name, String group) { 663 if (name == null) { 664 name = ""; 665 } 666 if (group == null) { 667 group = ""; 668 } 669 670 lastBadServer = name; 671 lastBadGroup = group; 672 } 673 674 private boolean isBadServer(String name, String group) { 675 assert lastBadServer != null; 676 assert lastBadGroup != null; 677 return lastBadServer.equals(name) && lastBadGroup.equals(group); 678 } 679 680 private void setLastServer(String name, String group, AddeServer server) { 681// logger.trace("name='{}' group='{}' server='{}' old: name='{}' group='{}' server='{}'", new Object[] { name, group, server, lastServerName, lastServerGroup, lastServer }); 682 if (name == null) { 683 name = ""; 684 } 685 if (group == null) { 686 group = ""; 687 } 688 if (server == null) { 689 server = new AddeServer(name); 690 Group addeGroup = new Group(getDataType(), group, group); 691 server.addGroup(addeGroup); 692 } 693 694 lastServerName = name; 695 lastServerGroup = group; 696 lastServer = server; 697 } 698 699 private boolean isLastServer(String name, String group) { 700 assert lastServer != null; 701 assert lastServerName != null; 702 assert lastServerGroup != null; 703 return lastServerName.equals(name) && lastServerGroup.equals(group); 704 } 705 706 @EventSubscriber(eventClass=EntryStore.Event.class) 707 public void onServerManagerDataEvent(EntryStore.Event evt) { 708 EntryStore servManager = ((McIDASV)getIdv()).getServerManager(); 709// logger.debug("onServerManagerDataEvent: evt={} server={}", evt, servManager.getLastAdded()); 710 this.updateServerList(); 711 } 712 713 @EventSubscriber(eventClass=TabbedAddeManager.Event.class) 714 public void onServerManagerWindowEvent(TabbedAddeManager.Event evt) { 715// logger.debug("onServerManagerWindowEvent: caught event bus obj"); 716 } 717 718 private boolean addingServer = false; 719 720 /** 721 * Search a given {@link JComboBox} for the index of a given object. Mostly 722 * useful for searching {@link #serverSelector} or {@link #groupSelector}. 723 * 724 * @param needle An object. {@code null} values are permitted. 725 * @param haystack {@code JComboBox} to search. {@code null} values are 726 * permitted, but return {@code -1}. 727 * 728 * @return Either the index of {@code needle} within {@code haystack}, or 729 * {@code -1} if {@code needle} could not be found (or {@code haystack} is 730 * {@code null}). 731 */ 732 protected static int getSelectorIndex(final Object needle, 733 final JComboBox haystack) 734 { 735 if (haystack == null) { 736 return -1; 737 } 738 739 String name = null; 740 if (needle instanceof AddeServer) { 741 name = ((AddeServer)needle).getName(); 742 } else if (needle instanceof Group) { 743 name = ((Group)needle).getName(); 744 } else if (needle instanceof AddeEntry) { 745 name = ((AddeEntry)needle).getAddress(); 746 } else { 747 name = needle.toString(); 748 } 749 750 if (isLoopback(name)) { 751 return 0; 752 } 753 754 for (int i = 0; i < haystack.getItemCount(); i++) { 755 Object item = haystack.getItemAt(i); 756 String tmpName; 757 if (item instanceof AddeServer) { 758 tmpName = ((AddeServer)item).getName(); 759 } else { 760 tmpName = item.toString(); 761 } 762 763 if (name.equals(tmpName)) { 764 return i; 765 } 766 } 767 return -1; 768 } 769 770 /** 771 * Get the selected AddeServer 772 * 773 * @return the server or null 774 */ 775 protected AddeServer getAddeServer() { 776 if (lastServerName != null && lastServerName.equals("unset")) { 777 return null; 778 } 779 780 Object selected = serverSelector.getSelectedItem(); 781 if ((selected != null) && (selected instanceof AddeServer)) { 782 AddeServer server = (AddeServer)selected; 783 String group = getGroup(true); 784 Map<String, String> accounting = getAccounting(server, group); 785// logger.trace("accounting: new: u='{}' p='{}' old: u='{}' p='{}'", new Object[] { accounting.get("user"), accounting.get("proj"), lastServerUser, lastServerProj }); 786 lastServerUser = accounting.get("user"); 787 lastServerProj = accounting.get("proj"); 788 setLastServer(server.getName(), group, server); 789 return (AddeServer)selected; 790 } else if ((selected != null) && (selected instanceof String)) { 791 792 EntryStore servManager = ((McIDASV)getIdv()).getServerManager(); 793 String server = (String)selected; 794 String group = getGroup(true); 795 796 if (isBadServer(server, group)) { 797// logger.trace("getAddeServer: returning null; known bad server; server={} group={}", server, group); 798 return null; 799 } 800 801 if (isLastServer(server, group)) { 802// logger.trace("getAddeServer: returning last server name; server={} group={}", server, group); 803 return lastServer; 804 } 805 806 EditorAction editorAction = EditorAction.INVALID; 807 if (!isLoopback(server)) { 808 RemoteEntryEditor editor = new RemoteEntryEditor(servManager, server, ""); 809 editor.setVisible(true); 810 editorAction = editor.getEditorAction(); 811 } else { 812 LocalEntryEditor editor = new LocalEntryEditor(servManager, group); 813 editor.setVisible(true); 814 editorAction = editor.getEditorAction(); 815 } 816 817 int servIndex = 0; 818 int groupIndex = 0; 819 820 if (editorAction != EditorAction.CANCELLED && editorAction != EditorAction.INVALID) { 821 822 List<AddeServer> added = arrList(EntryTransforms.convertMcvServers(servManager.getLastAddedByType(strToEntryType(getDataType())))); 823 AddeServer first = null; 824 if (!added.isEmpty()) { 825 first = added.get(0); 826 servIndex = getSelectorIndex(first, serverSelector); 827 setLastServer(server, group, first); 828 } 829 830 serverSelector.setSelectedIndex(servIndex); 831 groupSelector.setSelectedIndex(groupIndex); 832// logger.trace("getAddeServer: serverIdx={} groupIdx={}", servIndex, groupIndex); 833 834 return first; 835 } else { 836// logger.trace("getAddeServer: returning null due to cancel request"); 837 setBadServer(server, group); 838 return null; 839 } 840 841 842 843 } else if (selected == null) { 844// logger.trace("getAddeServer: null object in selector; returning null"); 845 } else { 846// logger.debug("getAddeServer: unknown obj type={}; toString={}", selected.getClass().getName(), selected.toString()); 847 } 848 return null; 849 } 850 851 /** 852 * A utility to add a component to the list of components that 853 * need the descriptor 854 * 855 * @param comp The component 856 * @return The component 857 */ 858 protected JComponent addDescComp(JComponent comp) { 859 compsThatNeedDescriptor.add(comp); 860 return comp; 861 } 862 863 /** 864 * Set LABEL_SELECT from elsewhere 865 */ 866 protected void setSelectString(String string) { 867 LABEL_SELECT = string; 868 } 869 870 /** 871 * Reset the descriptor stuff 872 */ 873 protected void resetDescriptorBox() { 874 ignoreDescriptorChange = true; 875 descriptorComboBox.setSelectedItem(LABEL_SELECT); 876 ignoreDescriptorChange = false; 877 } 878 879 /** 880 * Handle when the user presses the connect button 881 * 882 * @throws Exception On badness 883 */ 884 public void handleConnect() throws Exception { 885 AddeServer server = getAddeServer(); 886 if (server == null) { 887 return; 888 } 889 setState(STATE_CONNECTING); 890 connectToServer(); 891 handleUpdate(); 892 } 893 894 /** 895 * Show the user a descriptive error message in a dialog (if in foreground 896 * mode) depending on the state of {@code e}. 897 * 898 * @param e Exception to handle. Cannot be {@code null}. 899 * 900 * @throws NullPointerException if {@code e} is {@code null}. 901 * 902 * @see #handleConnectionError(String, Exception) 903 */ 904 @Override protected void handleConnectionError(Exception e) { 905 handleConnectionError("", e); 906 } 907 908 /** 909 * Show the user a descriptive error message (with optional details) in a 910 * dialog. 911 * 912 * @param details Details about the context of {@code e}. {@code null} will 913 * be treated as an empty {@code String}. 914 * @param e Exception to handle. Cannot be {@code null}. 915 * 916 * @throws NullPointerException if {@code e} is {@code null}. 917 */ 918 protected void handleConnectionError(String details, Exception e) { 919 Objects.requireNonNull(e, "Cannot handle null exception"); 920 logger.error("attempting to handle connection error", e); 921 922 if ((details != null) && !details.isEmpty()) { 923 details = details+":\n"; 924 } else { 925 details = ""; 926 } 927 928 boolean isError = true; 929 if (e.getMessage() != null) { 930 String msg = e.getMessage(); 931 int msgPos = msg.indexOf("AddeURLException:"); 932 if ((msgPos >= 0) && (msg.length() > 18)) { 933 msg = msg.substring(msgPos + 18); 934 GuiUtils.showDialog("ADDE Error", new JLabel(details+msg)); 935 } else if (msg.indexOf("Connecting to server:localhost:") >= 0) { 936 GuiUtils.showDialog("ADDE Error", new JLabel("Local server is not responding.")); 937 } else if (msg.toLowerCase().contains("unknownhostexception")) { 938 LogUtil.userErrorMessage("Could not access server: " + getServer()); 939 } else if ((e instanceof AddeURLException) || msg.toLowerCase().contains("server unable to resolve this dataset")) { 940 handleUnknownDataSetError(); 941 } else if ((msg.toLowerCase().contains("no images satisfy")) 942 || (msg.toLowerCase().contains("error generating list of files"))) 943 { 944 LogUtil.userErrorMessage("No data available for the selection"); 945 isError = false; 946 } else { 947 LogUtil.logException("Encountered a problem (server: '" + getServer()+"'):\n"+details, e); 948 } 949 } else { 950 LogUtil.userErrorMessage("Encountered a problem (server: '" + getServer() + "'):\n" + details +e); 951 } 952 953 if (isError && (getState() == STATE_CONNECTED)) { 954 setHaveData(false); 955 resetDescriptorBox(); 956 updateStatus(); 957 setState(STATE_UNCONNECTED); 958 } 959 } 960 961 /** 962 * Handle unknown data set error 963 */ 964 @Override protected void handleUnknownDataSetError() { 965 String server = getServer(); 966 String group = getGroup(); 967 Map<String, String> acct = getAccounting(server, group); 968 String user = acct.get("user"); 969 String proj = acct.get("proj"); 970 971 StringBuilder msg = new StringBuilder("Could not connect to dataset \""); 972 msg.append(getGroup()).append("\" on server \"").append(getServer()).append("\"."); 973 if (DEFAULT_ACCOUNT.getUsername().equals(user) && DEFAULT_ACCOUNT.getProject().equals(proj)) { 974 msg.append("\n\nDataset may require ADDE accounting information."); 975 } else { 976 msg.append("\n\nAccounting information:\nusername: \"") 977 .append(user).append("\"\nproject: \"").append(proj).append('"'); 978 } 979 LogUtil.userErrorMessage(msg.toString()); 980 setState(STATE_UNCONNECTED); 981 } 982 983 /** 984 * Handle the event 985 * 986 * @param ae The event 987 */ 988 public void actionPerformed(ActionEvent ae) { 989 String cmd = ae.getActionCommand(); 990 if (cmd.equals(CMD_MANAGER)) { 991 doManager(); 992 } 993 else { 994 super.actionPerformed(ae); 995 } 996 } 997 998 /** 999 * Go directly to the Server Manager 1000 */ 1001 public void doManager() { 1002// if (isLocalServer()) { 1003// ((McIDASV)getIdv()).showAddeManager(); 1004// return; 1005// } 1006 getIdv().getPreferenceManager().showTab(Constants.PREF_LIST_ADDE_SERVERS); 1007 } 1008 1009 /** 1010 * Show the parameter restore tree 1011 */ 1012 public void doParameters() { 1013 JPopupMenu popup = new JPopupMenu(); 1014 JMenuItem mi = new JMenuItem("Manage..."); 1015 mi.addActionListener(new ActionListener() { 1016 public void actionPerformed(ActionEvent ae) { 1017 System.out.println(ae); 1018 showParameterSetDialog(getParameterSetType()); 1019 } 1020 }); 1021 popup.add(mi); 1022 1023 // Add the checkbox to automatically create a data source 1024 cb.addActionListener(new ActionListener() { 1025 public void actionPerformed(ActionEvent ae) { 1026 shouldAddSource = cb.isSelected(); 1027 } 1028 }); 1029 popup.addSeparator(); 1030 popup.add(cb); 1031 1032 final PersistenceManager pm = (PersistenceManager)getIdv().getPersistenceManager(); 1033 List<ParameterSet> parameterSets = pm.getAllParameterSets(getParameterSetType()); 1034 1035 for (int i=0; i<parameterSets.size(); i++) { 1036 if (i==0) popup.addSeparator(); 1037 final ParameterSet ps = parameterSets.get(i); 1038 1039 // Parameter set at root 1040 if (ps.getCategories().size() == 0) { 1041 mi = new JMenuItem(ps.getName()); 1042 mi.addActionListener(new ActionListener() { 1043 public void actionPerformed(ActionEvent ae) { 1044 restoreParameterSet(ps.getElement()); 1045 } 1046 }); 1047 popup.add(mi); 1048 } 1049 1050 // Recurse into folders 1051 else { 1052 // Find or make the menu for the given parameter set 1053 JMenu m = getPopupSubMenuForParameterSet(popup, ps); 1054 // Create parameter set entry 1055 mi = new JMenuItem(ps.getName()); 1056 mi.addActionListener(new ActionListener() { 1057 public void actionPerformed(ActionEvent ae) { 1058 restoreParameterSet(ps.getElement()); 1059 } 1060 }); 1061 m.add(mi); 1062 } 1063 1064 } 1065 1066 popup.show(parameterButton, 0, (int) parameterButton.getBounds().getHeight()); 1067 } 1068 1069 private JMenu getPopupSubMenuForParameterSet(JPopupMenu popup, final ParameterSet ps) { 1070 List<String> menuNames = ps.getCategories(); 1071 if (menuNames.size() < 1) return null; 1072 1073 // Build the complete menu 1074 String menuName = menuNames.get(0); 1075 menuNames.remove(0); 1076 JMenu theMenu = new JMenu(); 1077 1078 // Look for the menu in popup 1079 boolean found = false; 1080 for (int i=0; i<popup.getComponentCount(); i++) { 1081 Component thisComponent = popup.getComponent(i); 1082 if (thisComponent instanceof JMenu && ((JMenu)thisComponent).getText().equals(menuName)) { 1083 theMenu = mergeMenuNames((JMenu)thisComponent, menuNames); 1084 found = true; 1085 } 1086 } 1087 1088 // Make a new menu, add the root, return the leaf 1089 if (!found) { 1090 JMenu theRoot = new JMenu(menuName); 1091 theMenu = makeMenuRecursive(theRoot, menuNames); 1092 popup.add(theRoot); 1093 } 1094 1095 return theMenu; 1096 } 1097 1098 /** 1099 * Make a new recursive menu 1100 * 1101 * @param rootMenu The root menu to add items to 1102 * @param menuNames List of string names for submenus 1103 * @return A new JMenu representing the leaf 1104 */ 1105 private JMenu makeMenuRecursive(JMenu rootMenu, List<String> menuNames) { 1106 if (menuNames.size() < 1) return rootMenu; 1107 JMenu newMenu = new JMenu(menuNames.get(0)); 1108 rootMenu.add(newMenu); 1109 menuNames.remove(0); 1110 return makeMenuRecursive(newMenu, menuNames); 1111 } 1112 1113 /** 1114 * Recurse into a menu, returning either a pointer to the designated names path 1115 * or a pointer to the leaf menu added by merging new names 1116 * 1117 * @param thisMenu The root menu to merge 1118 * @param menuNames List of string names to look for 1119 * @return A new JMenu representing the leaf matched by menuNames 1120 */ 1121 private JMenu mergeMenuNames(JMenu thisMenu, List<String> menuNames) { 1122 if (menuNames.size() < 1) return thisMenu; 1123 boolean found = false; 1124 String menuName = menuNames.get(0); 1125 for (int i=0; i<thisMenu.getItemCount(); i++) { 1126 JMenuItem mi = thisMenu.getItem(i); 1127 if (!(mi instanceof JMenu)) continue; 1128 if (mi.getText().equals(menuName)) { 1129 menuNames.remove(0); 1130 thisMenu = mergeMenuNames((JMenu)mi, menuNames); 1131 found = true; 1132 } 1133 } 1134 if (!found) { 1135 thisMenu = makeMenuRecursive(thisMenu, menuNames); 1136 } 1137 return thisMenu; 1138 } 1139 1140 /** 1141 * Return the parameter type associated with this chooser. Override! 1142 */ 1143 protected String getParameterSetType() { 1144 return "adde"; 1145 } 1146 1147 /** 1148 * Show the parameter set manager. 1149 */ 1150 private void showParameterSetDialog(final String parameterSetType) { 1151 ParameterTree tree = (ParameterTree) parameterTrees.get(parameterSetType); 1152 if (tree == null) { 1153 tree = new ParameterTree((UIManager)getIdv().getIdvUIManager() , parameterSetType); 1154 parameterTrees.put(parameterSetType, tree); 1155 } 1156 else { 1157 //DAVEP 1158 System.out.println("Should refresh the parameter tree here"); 1159 } 1160 tree.setVisible(true); 1161 } 1162 1163 /** 1164 * Clear the selected parameter set. 1165 */ 1166 protected void clearParameterSet() { 1167 restoreElement = null; 1168 restoreTimes = new ArrayList(); 1169 shouldAddSource = false; 1170 } 1171 1172 /** 1173 * Restore the selected parameter set using element attributes. 1174 * 1175 * @param restoreElement {@code Element} with the desired attributes. 1176 * {@code null} values are permitted. 1177 * 1178 * @return {@code true} if the parameter set was restored, {@code false} 1179 * otherwise. 1180 */ 1181 protected boolean restoreParameterSet(Element restoreElement) { 1182 if (restoreElement == null) return false; 1183 if (!restoreElement.getTagName().equals("default")) return false; 1184 1185 this.restoreElement = restoreElement; 1186 1187 boolean oldISCE = ignoreStateChangedEvents; 1188 ignoreStateChangedEvents = true; 1189 1190 // Restore server 1191 String server = restoreElement.getAttribute(ATTR_SERVER); 1192 if (server != null) serverSelector.setSelectedItem(new AddeServer(server)); 1193 1194 // Restore group 1195 String group = restoreElement.getAttribute(ATTR_GROUP); 1196 if (group != null) groupSelector.setSelectedItem(group); 1197 1198 // Act as though the user hit "connect" 1199 readFromServer(); 1200 1201 // Restore descriptor 1202 String descriptor = restoreElement.getAttribute(ATTR_DESCRIPTOR); 1203 if (descriptor != null) { 1204 Enumeration enumeration = descriptorTable.keys(); 1205 for (int i = 0; enumeration.hasMoreElements(); i++) { 1206 String key = enumeration.nextElement().toString(); 1207 Object val = descriptorTable.get(key); 1208 if (descriptor.equals(val)) { 1209 descriptorComboBox.setSelectedItem(val + nameSeparator + key); 1210 descriptorChanged(); 1211 break; 1212 } 1213 } 1214 } 1215 1216 // Restore date/time 1217 if (restoreElement.hasAttribute(ATTR_POS)) { 1218 setDoAbsoluteTimes(false); 1219 Integer pos = Integer.valueOf(restoreElement.getAttribute(ATTR_POS)); 1220 if (pos.intValue() >= 0) { 1221 getRelativeTimesList().setSelectedIndex(pos); 1222 } 1223 restoreTimes = new ArrayList(); 1224 } 1225 else if ((restoreElement.hasAttribute(ATTR_DAY)) && (restoreElement.hasAttribute(ATTR_TIME))) { 1226 setDoAbsoluteTimes(true); 1227 String dateStr = restoreElement.getAttribute(ATTR_DAY); 1228 String timeStr = restoreElement.getAttribute(ATTR_TIME); 1229 List dateS = StringUtil.split(dateStr, ","); 1230 List timeS = StringUtil.split(timeStr, ","); 1231 int numImages = timeS.size(); 1232 restoreTimes = new ArrayList(); 1233 try { 1234 DateTime dt = new DateTime(); 1235 dt.resetFormat(); 1236 String dtformat = dt.getFormatPattern(); 1237 for (int ix=0; ix<numImages; ix++) { 1238 DateTime restoreTime = dt.createDateTime((String)dateS.get(ix) + " " + (String)timeS.get(ix)); 1239 restoreTimes.add(restoreTime); 1240 } 1241 } catch (Exception e) { 1242 System.out.println("Exception e=" + e); 1243 return false; 1244 } 1245 } 1246 1247 System.out.println("Returning from AddeChooser.restoreParameterSet()"); 1248 1249 ignoreStateChangedEvents = oldISCE; 1250 return true; 1251 } 1252 1253 /** 1254 * Set the absolute times list. The times list can contain any of the object types 1255 * that makeDatedObjects knows how to handle, i.e., Date, visad.DateTime, DatedThing, AddeImageDescriptor, etc. 1256 * 1257 * @param times List of thinggs to put into absolute times list 1258 */ 1259 protected void setAbsoluteTimes(List times) { 1260 super.setAbsoluteTimes(times); 1261 restoreAbsoluteTimes(); 1262 } 1263 1264 protected void restoreAbsoluteTimes() { 1265 List allTimes = makeDatedObjects(super.getAbsoluteTimes()); 1266 if (restoreTimes.size() > 0 && allTimes.size() > 0) { 1267 int[] indices = new int[restoreTimes.size()]; 1268 try { 1269 DateTime rtdt; 1270 DateTime atdt; 1271 DatedThing at; 1272 for (int i = 0; i < restoreTimes.size(); i++) { 1273 rtdt = (DateTime)restoreTimes.get(i); 1274 for (int j = 0; j < allTimes.size(); j++) { 1275 at = (DatedThing)allTimes.get(j); 1276 atdt = new DateTime(at.getDate()); 1277 if (atdt.equals(rtdt)) { 1278 indices[i] = j; 1279 } 1280 } 1281 } 1282 } catch (Exception e) { 1283 System.out.println("Exception e=" + e); 1284 } 1285 setSelectedAbsoluteTimes(indices); 1286 } 1287 } 1288 1289 /** 1290 * show/hide the parameter restore button 1291 */ 1292 public void showParameterButton() { 1293 parameterButton.setVisible(true); 1294 } 1295 1296 public void hideParameterButton() { 1297 parameterButton.setVisible(false); 1298 } 1299 1300 /** 1301 * Override and simulate clicking Add Source if requested 1302 */ 1303 public void setHaveData(boolean have) { 1304 super.setHaveData(have); 1305 if (have && shouldAddSource) { 1306 // Even though setHaveData should mean we can go, we can't... wait a few jiffies 1307 Misc.runInABit(100, AddeChooser.this, "doClickLoad", null); 1308 } 1309 } 1310 1311 public void doClickLoad() { 1312 loadButton.doClick(); 1313 } 1314 1315 public void showServers() { 1316 allServersFlag = !allServersFlag; 1317 XmlObjectStore store = getIdv().getStore(); 1318 store.put(Constants.PREF_SYSTEMSERVERSIMG, allServersFlag); 1319 store.save(); 1320 updateServers(); 1321 updateGroups(); 1322 } 1323 1324 protected String getStateString() { 1325 int state = getState(); 1326 switch (state) { 1327 case STATE_CONNECTED: return "Connected to server"; 1328 case STATE_UNCONNECTED: return "Not connected to server"; 1329 case STATE_CONNECTING: return "Connecting to server"; 1330 default: return "Unknown state: " + state; 1331 } 1332 } 1333 1334 /** 1335 * Disable/enable any components that depend on the server. 1336 * Try to update the status label with what we know here. 1337 */ 1338 protected void updateStatus() { 1339 super.updateStatus(); 1340 if (getState() == STATE_CONNECTED) { 1341 lastServer = new AddeServer(""); 1342 lastServerGroup = ""; 1343 lastServerName = ""; 1344 lastServerProj = ""; 1345 lastServerUser = ""; 1346 1347 if (!haveDescriptorSelected()) { 1348 if (!usingStations() || haveStationSelected()) { 1349 // String name = getDataName().toLowerCase(); 1350 String name = getDescriptorLabel().toLowerCase(); 1351 if (StringUtil.startsWithVowel(name)) { 1352 setStatus("Please select an " + name); 1353 } else { 1354 setStatus("Please select a " + name); 1355 } 1356 } 1357 } 1358 } 1359 1360 GuiUtils.enableTree(connectButton, getState() != STATE_CONNECTING); 1361 } 1362 1363 /** 1364 * Get the data type ID 1365 * 1366 * @return the data type 1367 */ 1368 public String getDataType() { 1369 return "ANY"; 1370 } 1371 1372 /** 1373 * Check if the server is ok 1374 * 1375 * @return status code 1376 */ 1377 protected int checkIfServerIsOk() { 1378 EntryStore servManager = ((McIDASV)getIdv()).getServerManager(); 1379 if (isLocalServer() && !servManager.checkLocalServer()) { 1380 LogUtil.userErrorMessage("Local servers are stopped.\n\nLocal servers can be restarted from the 'Tools' menu:\n Tools > Manage ADDE Datasets >\nLocal Servers > Start Local Servers"); 1381 logger.info("Local servers are stopped"); 1382 return STATUS_ERROR; 1383 } 1384 try { 1385 StringBuffer buff = getUrl(REQ_TEXT); 1386 appendKeyValue(buff, PROP_FILE, FILE_PUBLICSRV); 1387 1388 // TJJ Sep 2024 1389 // Some ADDE servers return an Invalid Accounting error if they can't find a PUBLIC.SRV file 1390 // This should not result in an error, it should not imply the accounting is not valid 1391 if (buff.toString().toUpperCase().contains("PUBLIC.SRV")) { 1392 // We are requesting the PUBLIC.SRV file 1393 logger.info("bailing out early, no PUBLIC.SRV"); 1394 return STATUS_OK; 1395 } 1396 URLConnection urlc = IOUtil.getUrlConnection(buff.toString()); 1397 InputStream is = urlc.getInputStream(); 1398 is.close(); 1399 return STATUS_OK; 1400 } catch (AddeURLException ae) { 1401 String aes = ae.toString(); 1402 if (aes.indexOf("Invalid project number") >= 0 || 1403 aes.indexOf("Invalid user id") >= 0 || 1404 aes.indexOf("Accounting data") >= 0) { 1405 LogUtil.userErrorMessage("Invalid login.\n\nPlease verify your username and password."); 1406 logger.info("Invalid login"); 1407 setState(STATE_UNCONNECTED); 1408 setHaveData(false); 1409 resetDescriptorBox(); 1410 return STATUS_NEEDSLOGIN; 1411 } 1412 if (aes.indexOf("cannot run server 'txtgserv'") >= 0) { 1413 return STATUS_OK; 1414 } 1415 LogUtil.userErrorMessage("Error connecting to server " + getServer() + ":\n" + ae.getMessage()); 1416 logger.info("Error connecting to server"); 1417 setState(STATE_UNCONNECTED); 1418 setHaveData(false); 1419 resetDescriptorBox(); 1420 return STATUS_ERROR; 1421 } catch (ConnectException exc) { 1422 setState(STATE_UNCONNECTED); 1423 setHaveData(false); 1424 resetDescriptorBox(); 1425 String message = "Error connecting to server " + getServer(); 1426 String info = "Error connecting to server"; 1427 if (isLocalServer()) { 1428 if (!servManager.checkLocalServer()) { 1429 message += "\n\nLocal servers can be restarted from the 'Tools' menu:\n Tools > Manage ADDE Datasets >\n Local Servers > Start Local Servers"; 1430 info += " (Local servers are stopped)"; 1431 } 1432 else { 1433 message += "\n\nLocal servers appear to be running.\nYour firewall may be preventing access."; 1434 info += " (Local servers are running)"; 1435 } 1436 } 1437 LogUtil.userErrorMessage(message); 1438 logger.info(info); 1439 return STATUS_ERROR; 1440 } catch (EOFException exc) { 1441 setState(STATE_UNCONNECTED); 1442 setHaveData(false); 1443 resetDescriptorBox(); 1444 LogUtil.userErrorMessage("Server " + getServer() + " is not responding"); 1445 logger.info("Server is not responding"); 1446 return STATUS_ERROR; 1447 } catch (Exception exc) { 1448 setState(STATE_UNCONNECTED); 1449 setHaveData(false); 1450 resetDescriptorBox(); 1451 logException("Connecting to server: " + getServer(), exc); 1452 logger.info("Error connecting to server"); 1453 return STATUS_ERROR; 1454 } 1455 } 1456 1457 public boolean canAccessServer() { 1458 return (checkIfServerIsOk() == STATUS_OK); 1459 } 1460 1461 public Map<String, String> getAccountingInfo() { 1462 AddeServer server = getAddeServer(); 1463 Map<String, String> map = new LinkedHashMap<>(4); 1464 if (server != null) { 1465 List<AddeServer.Group> groups = cast(server.getGroups()); 1466 Map<String, String>acctInfo = getAccounting(server, groups.get(0).toString()); 1467 map.put("user", acctInfo.get("user")); 1468 map.put("proj", acctInfo.get("proj")); 1469 map.put("server", server.getName()); 1470 map.put("group", getGroup()); 1471 } else { 1472 map.put("user", RemoteAddeEntry.DEFAULT_ACCOUNT.getUsername()); 1473 map.put("proj", RemoteAddeEntry.DEFAULT_ACCOUNT.getUsername()); 1474 map.put("server", ""); 1475 map.put("group", ""); 1476 } 1477 return map; 1478 } 1479 1480 /** 1481 * Saves the currently selected server and group to a chooser-specific 1482 * preference. Preference ID is {@code PREF_SERVERSTATE+'.'+getId()}. 1483 */ 1484 @Override public void saveServerState() { 1485 String[] serverState = { getServer(), getGroup() }; 1486 getIdv().getStore().put(PREF_SERVERSTATE+'.'+getId(), serverState); 1487 getIdv().getStore().save(); 1488 } 1489 1490 /** 1491 * Connect to the server. 1492 */ 1493 protected void connectToServer() { 1494 clearParameterSet(); 1495 setDescriptors(null); 1496 setDoAbsoluteTimes(false); 1497 if (!canAccessServer()) { 1498 return; 1499 } 1500 readFromServer(); 1501 saveServerState(); 1502 ignoreStateChangedEvents = true; 1503 if (descList != null) { 1504 descList.saveState(groupSelector); 1505 } 1506 ignoreStateChangedEvents = false; 1507 } 1508 1509 /** 1510 * Do server connection stuff... override this with type-specific methods 1511 */ 1512 protected void readFromServer() { 1513 readDescriptors(); 1514 readTimes(); 1515 } 1516 1517// what the request needs to look like: 1518// adde://localhost:8112/imagedata?&PORT=112&COMPRES S=gzip&USER=idv&PROJ=0 1519// &VERSION=1&DEBUG=false&TRAC E=0&GROUP=MYDATA&DESCRIPTOR=ENTRY4&BAND=1 1520// &LATLON= 30.37139 71.74912&PLACE=CENTER&SIZE=1000 1000&UNI T=BRIT 1521// &MAG=1 1&SPAC=1&NAV=X&AUX=YES&DOC=X&POS=0 1522 1523 /** 1524 * Generate a list of image descriptors for the descriptor list. 1525 */ 1526 protected void readDescriptors() { 1527 try { 1528 StringBuffer buff = getGroupUrl(REQ_DATASETINFO, getGroup()); 1529 buff.append("&type=").append(getDataType()); 1530 logger.debug("readDesc: buff={}", buff.toString()); 1531 DataSetInfo dsinfo = new DataSetInfo(buff.toString()); 1532 1533 descriptorTable = dsinfo.getDescriptionTable(); 1534 descriptorList.clear(); 1535 commentList.clear(); 1536 descriptorList.addAll(dsinfo.getDescriptorList()); 1537 commentList.addAll(dsinfo.getCommentList()); 1538 int count = commentList.size(); 1539 String[] names = new String[count]; 1540 for (int i = 0; i < count; i++) { 1541 if (!isLocalServer()) { 1542 names[i] = descriptorList.get(i) + nameSeparator + commentList.get(i); 1543 } else { 1544 names[i] = commentList.get(i); 1545 } 1546 } 1547 logger.debug("readDesc: names={}", names); 1548 Arrays.sort(names); 1549 SwingUtilities.invokeLater(() -> { 1550 setDescriptors(names); 1551 setState(STATE_CONNECTED); 1552 }); 1553 } catch (Exception e) { 1554 handleConnectionError(e); 1555 } 1556 } 1557 1558 /** 1559 * Initialize the descriptor list from a list of names 1560 * 1561 * @param names list of names 1562 */ 1563 protected void setDescriptors(String[] names) { 1564 synchronized (WIDGET_MUTEX) { 1565 ignoreDescriptorChange = true; 1566 descriptorComboBox.removeAllItems(); 1567 descriptorNames = names; 1568 if ((names == null) || (names.length == 0)) { 1569 return; 1570 } 1571 descriptorComboBox.addItem(LABEL_SELECT); 1572 for (int j = 0; j < names.length; j++) { 1573 logger.trace("adding names[{}]='{}' to combo box", j, names[j]); 1574 descriptorComboBox.addItem(names[j]); 1575 } 1576 ignoreDescriptorChange = false; 1577 } 1578 } 1579 1580 /** 1581 * Respond to a change in the descriptor list. 1582 */ 1583 protected void descriptorChanged() { 1584 if (haveDescriptorSelected()) { 1585 LocalAddeEntry.AddeFormat format = 1586 getFormatFromDescriptor(getDescriptor()); 1587 if (formatRequiresAbsolute(format)) { 1588 setDoAbsoluteTimes(true); 1589 } 1590 readTimes(); 1591 updateStatus(); 1592 } 1593 } 1594 1595 /** 1596 * Check if a descriptor (image type) has been chosen 1597 * 1598 * @return true if an image type has been chosen 1599 */ 1600 protected boolean haveDescriptorSelected() { 1601 if (!GuiUtils.anySelected(descriptorComboBox)) { 1602 return false; 1603 } 1604 return getDescriptor() != null; 1605 } 1606 1607 /** 1608 * Get the selected descriptor. 1609 * 1610 * @return the currently selected descriptor. 1611 */ 1612 protected String getDescriptor() { 1613 return getDescriptorFromSelection(getSelectedDescriptor()); 1614 } 1615 1616 /** 1617 * Get the descriptor relating to the selection. 1618 * 1619 * @param selection String name from the widget. Can be {@code null}. 1620 * 1621 * @return Either the descriptor associated with {@code selection} or {@code null} if {@link #descriptorTable} or 1622 * {@code selection} is {@code null}. 1623 */ 1624 protected String getDescriptorFromSelection(String selection) { 1625 if (descriptorTable == null) { 1626 return null; 1627 } 1628 if (selection == null) { 1629 return null; 1630 } 1631 1632 String descriptor = null; 1633 if (!selection.contains(nameSeparator)) { 1634 descriptor = (String)descriptorTable.get(selection); 1635 } else { 1636 String[] toks = selection.split(nameSeparator, 2); 1637 String firstToken = toks[0].trim(); 1638 if (descriptorList.contains(firstToken)) { 1639 descriptor = firstToken; 1640 } else { 1641 String key = toks[1].trim(); 1642 descriptor = (String)descriptorTable.get(key); 1643 } 1644 } 1645 return descriptor; 1646 } 1647 1648 /** 1649 * Get the selected descriptor. 1650 * 1651 * @return the selected descriptor 1652 */ 1653 public String getSelectedDescriptor() { 1654 String selection = (String)descriptorComboBox.getSelectedItem(); 1655 if (selection == null) { 1656 return null; 1657 } 1658 if (selection.equals(LABEL_SELECT)) { 1659 return null; 1660 } 1661 1662 return selection; 1663 } 1664 1665 public int getSelectedIndex() { 1666 return descriptorComboBox.getSelectedIndex(); 1667 } 1668 1669 public void setBoxAtIndex(int idx) { 1670 descriptorComboBox.setSelectedIndex(idx); 1671 } 1672 1673 /** 1674 * Get the descriptor table for this chooser 1675 * 1676 * @return a Hashtable of descriptors and names 1677 */ 1678 public Hashtable getDescriptorTable() { 1679 return descriptorTable; 1680 } 1681 1682 /** 1683 * Get any extra key=value pairs that are appended to all requests. 1684 * 1685 * @param buff The buffer to append onto 1686 */ 1687 protected void appendMiscKeyValues(StringBuffer buff) { 1688 appendKeyValue(buff, PROP_COMPRESS, DEFAULT_COMPRESS); 1689 appendKeyValue(buff, PROP_PORT, getPort()); 1690 // appendKeyValue(buff, PROP_DEBUG, DEFAULT_DEBUG); 1691 appendKeyValue(buff, PROP_DEBUG, Boolean.toString(EntryStore.isAddeDebugEnabled(false))); 1692 appendKeyValue(buff, PROP_VERSION, DEFAULT_VERSION); 1693 appendKeyValue(buff, PROP_USER, getLastAddedUser()); 1694 appendKeyValue(buff, PROP_PROJ, getLastAddedProj()); 1695 } 1696 1697 /** 1698 * Return the ADDE port to use. 1699 * 1700 * <p>Overridden by McIDAS-V because {@literal "local ADDE"} requires us to 1701 * use essentially arbitrary port numbers, so for local ADDE connections 1702 * we need to use {@link EntryStore#getLocalPort()}.</p> 1703 * 1704 * @return ADDE port to use. 1705 */ 1706 @Override protected String getPort() { 1707 if (isLocalServer()) { 1708 return EntryStore.getLocalPort(); 1709 } else { 1710 return super.getPort(); 1711 } 1712 } 1713 1714 public String getLastAddedUser() { 1715 if ((lastServerUser != null) && !lastServerUser.isEmpty()) { 1716 logger.debug("getLastAddedUser: using non-default {}", lastServerUser); 1717 return lastServerUser; 1718 } else { 1719 logger.debug("getLastAddedUser: using default {}", DEFAULT_USER); 1720 return DEFAULT_USER; 1721 } 1722 } 1723 1724 public String getLastAddedProj() { 1725 if ((lastServerProj != null) && !lastServerProj.isEmpty()) { 1726 logger.debug("getLastAddedProj: using non-default {}", lastServerProj); 1727 return lastServerProj; 1728 } else { 1729 logger.debug("getLastAddedProj: using default {}", DEFAULT_PROJ); 1730 return DEFAULT_PROJ; 1731 } 1732 } 1733 1734 /** 1735 * Show the groups dialog. This method is not meant to be called 1736 * but is public by reason of implementation (or insanity). 1737 */ 1738 public void showGroups() { 1739 JPopupMenu popup = new JPopupMenu(); 1740 popup.add(new JMenuItem("Reading public datasets...")); 1741 1742 1743 List groups = readGroups(); 1744 popup.removeAll(); 1745 if ((groups == null) || (groups.isEmpty())) { 1746 popup.add(new JMenuItem("The list of public datasets is not available")); 1747 popup.show(publicButton, 0, (int) publicButton.getBounds().getHeight()); 1748 return; 1749 } 1750 1751 JMenuItem mi; 1752 for (int i = 0; i < groups.size(); i++) { 1753 final String group = groups.get(i).toString(); 1754 mi = new JMenuItem(group); 1755 mi.addActionListener(ae -> { 1756 EntryStore servManager = ((McIDASV)getIdv()).getServerManager(); 1757 1758 servManager.addEntry( 1759 new RemoteAddeEntry.Builder(lastServerName, group) 1760 .account(lastServerUser, lastServerProj) 1761 .type(strToEntryType(getDataType())) 1762 .source(EntrySource.USER) 1763 .validity(EntryValidity.VERIFIED) 1764 .build()); 1765 1766 groupSelector.setSelectedItem(group); 1767 doConnect(); 1768 }); 1769 popup.add(mi); 1770 } 1771 MenuScroller foo = new MenuScroller(popup, 125); 1772 foo.setParent(publicButton); 1773 popup.show(publicButton, 0, (int) publicButton.getBounds().getHeight()); 1774 } 1775 1776 /** 1777 * return the String id of the chosen server name 1778 * 1779 * @return the server name 1780 */ 1781 public String getServer() { 1782 AddeServer server = getAddeServer(); 1783 if (server != null) { 1784 return server.getName(); 1785 } else { 1786 return ""; 1787 } 1788 } 1789 1790 protected String getGroup() { 1791 return getGroup(false); 1792 } 1793 1794 /** 1795 * Is the group selector editable? 1796 * 1797 * @return Always returns {@code true}. 1798 */ 1799 protected boolean isGroupEditable() { 1800 return true; 1801 } 1802 1803 /** 1804 * Get the image group from the GUI. 1805 * 1806 * @return The image group. 1807 */ 1808 protected String getGroup(final boolean fromGetServer) { 1809 Object selected = groupSelector.getSelectedItem(); 1810 if (selected == null) { 1811 return null; 1812 } 1813 1814 if (selected instanceof AddeServer.Group) { 1815 AddeServer.Group group = (AddeServer.Group) selected; 1816 return group.getName(); 1817 } 1818 1819 if (selected instanceof String) { 1820 return (String)selected; 1821 } 1822 1823 String groupName = selected.toString().trim(); 1824 if (!fromGetServer && (!groupName.isEmpty())) { 1825 //Force the get in case they typed a server name 1826 getServer(); 1827 1828 AddeServer server = getAddeServer(); 1829 if (server != null) { 1830 AddeServer.Group group = 1831 getIdv().getIdvChooserManager().addAddeServerGroup( 1832 server, groupName, getGroupType()); 1833 if (!group.getActive()) { 1834 getIdv().getIdvChooserManager().activateAddeServerGroup( 1835 server, group); 1836 } 1837 //Now put the list of groups back in to the selector 1838 setGroups(); 1839 groupSelector.setSelectedItem(group); 1840 } 1841 } 1842 return groupName; 1843 } 1844 1845 /** 1846 * Get the server selector 1847 * @return The server selector 1848 */ 1849 public JComboBox getServerSelector() { 1850 if (serverSelector == null) 1851 serverSelector = super.getServerSelector(); 1852 1853 ItemListener[] ell = serverSelector.getItemListeners(); 1854 for (int i=0; i < ell.length; i++) { 1855 serverSelector.removeItemListener((ItemListener)ell[i]); 1856 } 1857 updateServers(); 1858 updateGroups(); 1859 serverSelector.addItemListener(new ItemListener() { 1860 public void itemStateChanged(ItemEvent e) { 1861 if (!ignoreStateChangedEvents) { 1862 Object selected = serverSelector.getSelectedItem(); 1863 if (selected instanceof AddeServer) { 1864 AddeServer selectedServer = (AddeServer)selected; 1865 if (selectedServer != null) { 1866 if (isSeparator(selectedServer)) { 1867 connectButton.setEnabled(false); 1868 return; 1869 } 1870 } 1871 } 1872 setState(STATE_UNCONNECTED); 1873 connectButton.setEnabled(true); 1874// setGroups(); 1875 resetDescriptorBox(); 1876 updateGroups(); 1877// System.err.println("itemStateChanged"); 1878 } 1879// else { 1880// System.out.println("Ignoring state change here..."); 1881// } 1882 } 1883 }); 1884 1885 serverSelector.getEditor().getEditorComponent().addKeyListener(new KeyListener() { 1886 public void keyTyped(final KeyEvent e) {} 1887 public void keyPressed(final KeyEvent e) {} 1888 public void keyReleased(final KeyEvent e) { 1889 JTextField field = (JTextField)serverSelector.getEditor().getEditorComponent(); 1890 boolean partialMatch = false; 1891 for (int i = 0; i < serverSelector.getItemCount(); i++) { 1892 String entry = serverSelector.getItemAt(i).toString(); 1893 if (entry.toLowerCase().startsWith(field.getText().toLowerCase())) 1894 partialMatch = true; 1895 } 1896 1897 if (!partialMatch && groupSelector != null) { 1898 logger.debug("aha! chooser=", getDataType()); 1899 ((JTextField)groupSelector.getEditor().getEditorComponent()).setText(""); 1900 } 1901 } 1902 }); 1903 1904 return serverSelector; 1905 } 1906 1907 /** 1908 * Enable or disable the GUI widgets based on what has been 1909 * selected. 1910 */ 1911 protected void enableWidgets() { 1912 synchronized (WIDGET_MUTEX) { 1913 boolean newEnabledState = (getState() == STATE_CONNECTED); 1914 for (int i = 0; i < compsThatNeedDescriptor.size(); i++) { 1915 JComponent comp = (JComponent) compsThatNeedDescriptor.get(i); 1916 if (comp.isEnabled() != newEnabledState) { 1917 GuiUtils.enableTree(comp, newEnabledState); 1918 } 1919 } 1920 if (drivercbx != null) { 1921 boolean descriptorState = newEnabledState && haveDescriptorSelected(); 1922// logger.trace("hrm set drivercbx={}", anyTimeDrivers() && descriptorState); 1923 drivercbx.setEnabled(anyTimeDrivers() && descriptorState); 1924 } 1925 } 1926 } 1927 1928 /** 1929 * Add a listener to the given combobox that will set the 1930 * state to unconnected 1931 * 1932 * @param box The box to listen to. 1933 */ 1934 protected void clearOnChange(final JComboBox box) { 1935 box.addItemListener(new ItemListener() { 1936 public void itemStateChanged(ItemEvent e) { 1937 if ( !ignoreStateChangedEvents) { 1938 setState(STATE_UNCONNECTED); 1939 GuiUtils.setListData(descriptorComboBox, new Vector()); 1940// System.err.println("clearOnChange"); 1941 } 1942// else { 1943// System.out.println("Ignoring state change in clearOnChange for: " + box.toString()); 1944// } 1945 } 1946 }); 1947 } 1948 1949 /** 1950 * Get the descriptor widget label 1951 * 1952 * @return label for the descriptor widget 1953 */ 1954 public String getDescriptorLabel() { 1955 return "Descriptor"; 1956 } 1957 1958 protected int getNumTimesToSelect() { 1959 return 5; 1960 } 1961 1962 /** 1963 * Get the default selected index for the relative times list. 1964 * 1965 * @return default index 1966 */ 1967 protected int getDefaultRelativeTimeIndex() { 1968 return 4; 1969 } 1970 1971 /** 1972 * Check the times lists 1973 */ 1974 protected void checkTimesLists() { 1975 super.checkTimesLists(); 1976 if (timesCardPanelExtra == null) { 1977 return; 1978 } 1979 if (getDoAbsoluteTimes()) { 1980 timesCardPanelExtra.show("absolute"); 1981 } else { 1982 timesCardPanelExtra.show("relative"); 1983 } 1984 } 1985 1986 /** Card panel to hold extra relative and absolute time components */ 1987 protected GuiUtils.CardLayoutPanel timesCardPanelExtra; 1988 1989 /** 1990 * Set the relative and absolute extra components. 1991 */ 1992 protected JPanel makeTimesPanel(JComponent relativeCard, JComponent absoluteCard) { 1993// JPanel timesPanel = super.makeTimesPanel(false, true); 1994 JPanel timesPanel = super.makeTimesPanel(false, true, getIdv().getUseTimeDriver()); 1995 1996 // Make a new timesPanel that has extra components tacked on the bottom, inside the tabs 1997 Component[] comps = timesPanel.getComponents(); 1998 1999// if (drivercbx != null) { 2000// drivercbx.setEnabled(anyTimeDrivers()); 2001// } 2002 2003 if ((comps.length == 1) && (comps[0] instanceof JTabbedPane)) { 2004 timesCardPanelExtra = new GuiUtils.CardLayoutPanel(); 2005 if (relativeCard == null) { 2006 relativeCard = new JPanel(); 2007 } 2008 if (absoluteCard == null) { 2009 absoluteCard = new JPanel(); 2010 } 2011 timesCardPanelExtra.add(relativeCard, "relative"); 2012 timesCardPanelExtra.add(absoluteCard, "absolute"); 2013 timesPanel = GuiUtils.centerBottom(comps[0], timesCardPanelExtra); 2014 } 2015 2016 return timesPanel; 2017 } 2018 2019 private JPanel innerPanel = new JPanel(); 2020 2021 private JLabel statusLabel = new JLabel("Status"); 2022 2023 /** 2024 * Super setStatus() takes a second string to enable "simple" mode 2025 * which highlights the required component. We don't really care 2026 * about that feature, and we don't want getStatusLabel() to 2027 * change the label background color. 2028 */ 2029 @Override 2030 public void setStatus(String statusString, String foo) { 2031 if (statusString == null) { 2032 statusString = ""; 2033 } 2034 statusLabel.setText(statusString); 2035 } 2036 2037 protected void setInnerPanel(JPanel newInnerPanel) { 2038 innerPanel = newInnerPanel; 2039 } 2040 2041 /** 2042 * Create the widget responsible for handling relative time selection. 2043 * 2044 * @return GUI widget. 2045 */ 2046 @Override public JComponent getRelativeTimesChooser() { 2047 McVTextField relativeTimesField = 2048 McVGuiUtils.makeTextFieldAllow(String.valueOf(relativeTimes), 2049 4, 2050 false, 2051 '0', '1', '2', '3', '4', '5', 2052 '6', '7','8','9'); 2053 2054 // need to keep *both* the ActionListener and DocumentListener around. 2055 // removing the ActionListener results in strange behavior when you've 2056 // accidentally cleared out the text field. 2057 relativeTimesField.setAllow(Pattern.compile("^[1-9][0-9]*$"), true); 2058// relativeTimesField.setDeny(Pattern.compile("^0$"), true); 2059 relativeTimesField.setColumns(4); 2060 relativeTimesField.addActionListener(e -> { 2061 String text = ((JTextField)e.getSource()).getText(); 2062 validateRelativeTimeInput(text); 2063 }); 2064 relativeTimesField.getDocument().addDocumentListener(new DocumentListener() { 2065 @Override public void insertUpdate(DocumentEvent e) { 2066 handleRelativeTimeChange(e); 2067 } 2068 2069 @Override public void removeUpdate(DocumentEvent e) { 2070 handleRelativeTimeChange(e); 2071 } 2072 2073 @Override public void changedUpdate(DocumentEvent e) { 2074 handleRelativeTimeChange(e); 2075 } 2076 }); 2077 relativeTimesField.setToolTipText(RELATIVE_TIMES_TOOLTIP); 2078 2079 JPanel panel = 2080 GuiUtils.topLeft(GuiUtils.label(RELATIVE_TIMES_LABEL, 2081 relativeTimesField)); 2082 JScrollPane scrollPane = new JScrollPane(panel); 2083 scrollPane.setPreferredSize(new Dimension(150, 100)); 2084 return scrollPane; 2085 } 2086 2087 /** 2088 * Validate the contents of the relative times text field. 2089 * 2090 * <p>This method overwrites {@link #relativeTimes} if {@code text} is an 2091 * integer greater than zero.</p> 2092 * 2093 * @param text Contents of the text field. 2094 */ 2095 private void validateRelativeTimeInput(String text) { 2096 try { 2097 int value = Integer.valueOf(text); 2098 if (value > 0) { 2099 relativeTimes = value; 2100 setHaveData(true); 2101 setState(STATE_CONNECTED); 2102 updateStatus(); 2103 } 2104 } catch (NumberFormatException e) { 2105 setState(STATUS_ERROR); 2106 setHaveData(false); 2107 setStatus("Please provide an integer value greater than zero."); 2108 } 2109 } 2110 2111 /** 2112 * Handle {@link DocumentListener} events for the {@link JTextField} 2113 * created by {@link #getRelativeTimesChooser()}. 2114 * 2115 * @param event Event to handle. Cannot be {@code null}. 2116 */ 2117 private void handleRelativeTimeChange(DocumentEvent event) { 2118 int len = event.getDocument().getLength(); 2119 try { 2120 String text = event.getDocument().getText(0, len); 2121 validateRelativeTimeInput(text); 2122 } catch (BadLocationException ex) { 2123 logger.warn("Could not get contents of text field!", ex); 2124 } 2125 } 2126 2127 /** 2128 * Get the relative time indices 2129 * 2130 * @return an array of indices 2131 */ 2132 @Override public int[] getRelativeTimeIndices() { 2133 int[] indices = new int[relativeTimes]; 2134 for (int i = 0; i < indices.length; i++) { 2135 indices[i] = i; 2136 } 2137 return indices; 2138 } 2139 2140 /** 2141 * Make the UI for this selector. 2142 * 2143 * Thank you NetBeans for helping with the layout! 2144 * 2145 * @return The GUI. 2146 */ 2147 protected JComponent doMakeContents() { 2148 JPanel outerPanel = new JPanel(); 2149 2150 JLabel serverLabelInner = new JLabel("Server:"); 2151 McVGuiUtils.setLabelPosition(serverLabelInner, Position.RIGHT); 2152 JPanel serverLabel = GuiUtils.leftRight(parameterButton, serverLabelInner); 2153 McVGuiUtils.setComponentWidth(serverLabel); 2154 2155 clearOnChange(serverSelector); 2156 McVGuiUtils.setComponentWidth(serverSelector, Width.TRIPLE); 2157 // McIDAS Inquiry #2146-3141 -> Changed from Width.DOUBLE to Width.TRIPLE 2158 2159 JLabel groupLabel = McVGuiUtils.makeLabelRight("Dataset:"); 2160 2161 groupSelector.setEditable(isGroupEditable()); 2162 clearOnChange(groupSelector); 2163 McVGuiUtils.setComponentWidth(groupSelector, Width.DOUBLE); 2164 2165 McVGuiUtils.setComponentWidth(connectButton, Width.DOUBLE); 2166 connectButton.setActionCommand(CMD_CONNECT); 2167 connectButton.addActionListener(this); 2168 2169 /* Set the attributes for the descriptor label and combo box, even though 2170 * they are not used here. Extending classes can add them to the panel if 2171 * necessary. 2172 */ 2173 McVGuiUtils.setComponentWidth(descriptorLabel); 2174 McVGuiUtils.setLabelPosition(descriptorLabel, Position.RIGHT); 2175 2176 // McIDAS Inquiry #2146-3141 -> Non-stanard length 2177 McVGuiUtils.setComponentWidth(descriptorComboBox, 584); 2178 2179 if (descriptorComboBox.getMinimumSize().getWidth() < ELEMENT_DOUBLE_WIDTH) { 2180 McVGuiUtils.setComponentWidth(descriptorComboBox, Width.DOUBLE); 2181 } 2182 2183 JLabel statusLabelLabel = McVGuiUtils.makeLabelRight(""); 2184 2185 statusLabel.setText("Status"); 2186 McVGuiUtils.setLabelPosition(statusLabel, Position.RIGHT); 2187 McVGuiUtils.setComponentColor(statusLabel, TextColor.STATUS); 2188 2189 JButton helpButton = McVGuiUtils.makeImageButton(ICON_HELP, "Show help"); 2190 helpButton.setActionCommand(GuiUtils.CMD_HELP); 2191 helpButton.addActionListener(this); 2192 2193 JButton refreshButton = McVGuiUtils.makeImageButton(ICON_REFRESH, "Refresh"); 2194 refreshButton.setActionCommand(GuiUtils.CMD_UPDATE); 2195 refreshButton.addActionListener(this); 2196 2197 McVGuiUtils.setComponentWidth(loadButton, Width.DOUBLE); 2198 2199 GroupLayout layout = new GroupLayout(outerPanel); 2200 outerPanel.setLayout(layout); 2201 layout.setHorizontalGroup( 2202 layout.createParallelGroup(LEADING) 2203 .addGroup(TRAILING, layout.createSequentialGroup() 2204 .addGroup(layout.createParallelGroup(TRAILING) 2205 .addGroup(layout.createSequentialGroup() 2206 .addContainerGap() 2207 .addComponent(helpButton) 2208 .addGap(GAP_RELATED) 2209 .addComponent(refreshButton) 2210 .addGap(GAP_RELATED) 2211 .addComponent(cancelButton) 2212 .addPreferredGap(RELATED) 2213 .addComponent(loadButton)) 2214 .addGroup(LEADING, layout.createSequentialGroup() 2215 .addContainerGap() 2216 .addGroup(layout.createParallelGroup(LEADING) 2217 .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE) 2218 .addGroup(layout.createSequentialGroup() 2219 .addComponent(serverLabel) 2220 .addGap(GAP_RELATED) 2221 .addComponent(serverSelector) 2222 .addGap(GAP_RELATED) 2223 .addComponent(manageButton) 2224 .addGap(GAP_RELATED) 2225 .addComponent(groupLabel) 2226 .addGap(GAP_RELATED) 2227 .addComponent(groupSelector) 2228 .addGap(GAP_RELATED) 2229 .addComponent(publicButton) 2230 .addPreferredGap(RELATED, DEFAULT_SIZE, Short.MAX_VALUE) 2231 .addComponent(connectButton)) 2232 .addGroup(layout.createSequentialGroup() 2233 .addComponent(statusLabelLabel) 2234 .addGap(GAP_RELATED) 2235 .addComponent(statusLabel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))))) 2236 .addContainerGap()) 2237 ); 2238 layout.setVerticalGroup( 2239 layout.createParallelGroup(LEADING) 2240 .addGroup(layout.createSequentialGroup() 2241 .addContainerGap() 2242 .addGroup(layout.createParallelGroup(BASELINE) 2243 .addComponent(serverLabel) 2244 .addComponent(serverSelector) 2245 .addComponent(manageButton) 2246 .addComponent(groupLabel) 2247 .addComponent(groupSelector) 2248 .addComponent(publicButton) 2249 .addComponent(connectButton)) 2250 .addPreferredGap(UNRELATED) 2251 .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE) 2252 .addPreferredGap(UNRELATED) 2253 .addGroup(layout.createParallelGroup(BASELINE) 2254 .addComponent(statusLabelLabel) 2255 .addComponent(statusLabel)) 2256 .addPreferredGap(UNRELATED) 2257 .addGroup(layout.createParallelGroup(BASELINE) 2258 .addComponent(loadButton) 2259 .addComponent(cancelButton) 2260 .addComponent(refreshButton) 2261 .addComponent(helpButton)) 2262 .addContainerGap()) 2263 ); 2264 2265 return outerPanel; 2266 2267 } 2268 2269 public class ServerComparator implements Comparator<AddeServer> { 2270 public int compare(AddeServer server1, AddeServer server2) { 2271 return server1.getName().compareTo(server2.getName()); 2272 } 2273 } 2274 2275 public class GroupComparator implements Comparator<Group> { 2276 public int compare(Group group1, Group group2) { 2277 return group1.getName().compareTo(group2.getName()); 2278 } 2279 } 2280} 2281