001/* 002 * This file is part of McIDAS-V 003 * 004 * Copyright 2007-2024 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 = new Integer(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 return selection; 1662 } 1663 1664 /** 1665 * Get the descriptor table for this chooser 1666 * 1667 * @return a Hashtable of descriptors and names 1668 */ 1669 public Hashtable getDescriptorTable() { 1670 return descriptorTable; 1671 } 1672 1673 /** 1674 * Get any extra key=value pairs that are appended to all requests. 1675 * 1676 * @param buff The buffer to append onto 1677 */ 1678 protected void appendMiscKeyValues(StringBuffer buff) { 1679 appendKeyValue(buff, PROP_COMPRESS, DEFAULT_COMPRESS); 1680 appendKeyValue(buff, PROP_PORT, getPort()); 1681 // appendKeyValue(buff, PROP_DEBUG, DEFAULT_DEBUG); 1682 appendKeyValue(buff, PROP_DEBUG, Boolean.toString(EntryStore.isAddeDebugEnabled(false))); 1683 appendKeyValue(buff, PROP_VERSION, DEFAULT_VERSION); 1684 appendKeyValue(buff, PROP_USER, getLastAddedUser()); 1685 appendKeyValue(buff, PROP_PROJ, getLastAddedProj()); 1686 } 1687 1688 /** 1689 * Return the ADDE port to use. 1690 * 1691 * <p>Overridden by McIDAS-V because {@literal "local ADDE"} requires us to 1692 * use essentially arbitrary port numbers, so for local ADDE connections 1693 * we need to use {@link EntryStore#getLocalPort()}.</p> 1694 * 1695 * @return ADDE port to use. 1696 */ 1697 @Override protected String getPort() { 1698 if (isLocalServer()) { 1699 return EntryStore.getLocalPort(); 1700 } else { 1701 return super.getPort(); 1702 } 1703 } 1704 1705 public String getLastAddedUser() { 1706 if ((lastServerUser != null) && !lastServerUser.isEmpty()) { 1707 logger.debug("getLastAddedUser: using non-default {}", lastServerUser); 1708 return lastServerUser; 1709 } else { 1710 logger.debug("getLastAddedUser: using default {}", DEFAULT_USER); 1711 return DEFAULT_USER; 1712 } 1713 } 1714 1715 public String getLastAddedProj() { 1716 if ((lastServerProj != null) && !lastServerProj.isEmpty()) { 1717 logger.debug("getLastAddedProj: using non-default {}", lastServerProj); 1718 return lastServerProj; 1719 } else { 1720 logger.debug("getLastAddedProj: using default {}", DEFAULT_PROJ); 1721 return DEFAULT_PROJ; 1722 } 1723 } 1724 1725 /** 1726 * Show the groups dialog. This method is not meant to be called 1727 * but is public by reason of implementation (or insanity). 1728 */ 1729 public void showGroups() { 1730 JPopupMenu popup = new JPopupMenu(); 1731 popup.add(new JMenuItem("Reading public datasets...")); 1732 1733 1734 List groups = readGroups(); 1735 popup.removeAll(); 1736 if ((groups == null) || (groups.isEmpty())) { 1737 popup.add(new JMenuItem("The list of public datasets is not available")); 1738 popup.show(publicButton, 0, (int) publicButton.getBounds().getHeight()); 1739 return; 1740 } 1741 1742 JMenuItem mi; 1743 for (int i = 0; i < groups.size(); i++) { 1744 final String group = groups.get(i).toString(); 1745 mi = new JMenuItem(group); 1746 mi.addActionListener(ae -> { 1747 EntryStore servManager = ((McIDASV)getIdv()).getServerManager(); 1748 1749 servManager.addEntry( 1750 new RemoteAddeEntry.Builder(lastServerName, group) 1751 .account(lastServerUser, lastServerProj) 1752 .type(strToEntryType(getDataType())) 1753 .source(EntrySource.USER) 1754 .validity(EntryValidity.VERIFIED) 1755 .build()); 1756 1757 groupSelector.setSelectedItem(group); 1758 doConnect(); 1759 }); 1760 popup.add(mi); 1761 } 1762 MenuScroller foo = new MenuScroller(popup, 125); 1763 foo.setParent(publicButton); 1764 popup.show(publicButton, 0, (int) publicButton.getBounds().getHeight()); 1765 } 1766 1767 /** 1768 * return the String id of the chosen server name 1769 * 1770 * @return the server name 1771 */ 1772 public String getServer() { 1773 AddeServer server = getAddeServer(); 1774 if (server != null) { 1775 return server.getName(); 1776 } else { 1777 return ""; 1778 } 1779 } 1780 1781 protected String getGroup() { 1782 return getGroup(false); 1783 } 1784 1785 /** 1786 * Is the group selector editable? 1787 * 1788 * @return Always returns {@code true}. 1789 */ 1790 protected boolean isGroupEditable() { 1791 return true; 1792 } 1793 1794 /** 1795 * Get the image group from the GUI. 1796 * 1797 * @return The image group. 1798 */ 1799 protected String getGroup(final boolean fromGetServer) { 1800 Object selected = groupSelector.getSelectedItem(); 1801 if (selected == null) { 1802 return null; 1803 } 1804 1805 if (selected instanceof AddeServer.Group) { 1806 AddeServer.Group group = (AddeServer.Group) selected; 1807 return group.getName(); 1808 } 1809 1810 if (selected instanceof String) { 1811 return (String)selected; 1812 } 1813 1814 String groupName = selected.toString().trim(); 1815 if (!fromGetServer && (!groupName.isEmpty())) { 1816 //Force the get in case they typed a server name 1817 getServer(); 1818 1819 AddeServer server = getAddeServer(); 1820 if (server != null) { 1821 AddeServer.Group group = 1822 getIdv().getIdvChooserManager().addAddeServerGroup( 1823 server, groupName, getGroupType()); 1824 if (!group.getActive()) { 1825 getIdv().getIdvChooserManager().activateAddeServerGroup( 1826 server, group); 1827 } 1828 //Now put the list of groups back in to the selector 1829 setGroups(); 1830 groupSelector.setSelectedItem(group); 1831 } 1832 } 1833 return groupName; 1834 } 1835 1836 /** 1837 * Get the server selector 1838 * @return The server selector 1839 */ 1840 public JComboBox getServerSelector() { 1841 if (serverSelector == null) 1842 serverSelector = super.getServerSelector(); 1843 1844 ItemListener[] ell = serverSelector.getItemListeners(); 1845 for (int i=0; i < ell.length; i++) { 1846 serverSelector.removeItemListener((ItemListener)ell[i]); 1847 } 1848 updateServers(); 1849 updateGroups(); 1850 serverSelector.addItemListener(new ItemListener() { 1851 public void itemStateChanged(ItemEvent e) { 1852 if (!ignoreStateChangedEvents) { 1853 Object selected = serverSelector.getSelectedItem(); 1854 if (selected instanceof AddeServer) { 1855 AddeServer selectedServer = (AddeServer)selected; 1856 if (selectedServer != null) { 1857 if (isSeparator(selectedServer)) { 1858 connectButton.setEnabled(false); 1859 return; 1860 } 1861 } 1862 } 1863 setState(STATE_UNCONNECTED); 1864 connectButton.setEnabled(true); 1865// setGroups(); 1866 resetDescriptorBox(); 1867 updateGroups(); 1868// System.err.println("itemStateChanged"); 1869 } 1870// else { 1871// System.out.println("Ignoring state change here..."); 1872// } 1873 } 1874 }); 1875 1876 serverSelector.getEditor().getEditorComponent().addKeyListener(new KeyListener() { 1877 public void keyTyped(final KeyEvent e) {} 1878 public void keyPressed(final KeyEvent e) {} 1879 public void keyReleased(final KeyEvent e) { 1880 JTextField field = (JTextField)serverSelector.getEditor().getEditorComponent(); 1881 boolean partialMatch = false; 1882 for (int i = 0; i < serverSelector.getItemCount(); i++) { 1883 String entry = serverSelector.getItemAt(i).toString(); 1884 if (entry.toLowerCase().startsWith(field.getText().toLowerCase())) 1885 partialMatch = true; 1886 } 1887 1888 if (!partialMatch && groupSelector != null) { 1889 logger.debug("aha! chooser=", getDataType()); 1890 ((JTextField)groupSelector.getEditor().getEditorComponent()).setText(""); 1891 } 1892 } 1893 }); 1894 1895 return serverSelector; 1896 } 1897 1898 /** 1899 * Enable or disable the GUI widgets based on what has been 1900 * selected. 1901 */ 1902 protected void enableWidgets() { 1903 synchronized (WIDGET_MUTEX) { 1904 boolean newEnabledState = (getState() == STATE_CONNECTED); 1905 for (int i = 0; i < compsThatNeedDescriptor.size(); i++) { 1906 JComponent comp = (JComponent) compsThatNeedDescriptor.get(i); 1907 if (comp.isEnabled() != newEnabledState) { 1908 GuiUtils.enableTree(comp, newEnabledState); 1909 } 1910 } 1911 if (drivercbx != null) { 1912 boolean descriptorState = newEnabledState && haveDescriptorSelected(); 1913// logger.trace("hrm set drivercbx={}", anyTimeDrivers() && descriptorState); 1914 drivercbx.setEnabled(anyTimeDrivers() && descriptorState); 1915 } 1916 } 1917 } 1918 1919 /** 1920 * Add a listener to the given combobox that will set the 1921 * state to unconnected 1922 * 1923 * @param box The box to listen to. 1924 */ 1925 protected void clearOnChange(final JComboBox box) { 1926 box.addItemListener(new ItemListener() { 1927 public void itemStateChanged(ItemEvent e) { 1928 if ( !ignoreStateChangedEvents) { 1929 setState(STATE_UNCONNECTED); 1930 GuiUtils.setListData(descriptorComboBox, new Vector()); 1931// System.err.println("clearOnChange"); 1932 } 1933// else { 1934// System.out.println("Ignoring state change in clearOnChange for: " + box.toString()); 1935// } 1936 } 1937 }); 1938 } 1939 1940 /** 1941 * Get the descriptor widget label 1942 * 1943 * @return label for the descriptor widget 1944 */ 1945 public String getDescriptorLabel() { 1946 return "Descriptor"; 1947 } 1948 1949 protected int getNumTimesToSelect() { 1950 return 5; 1951 } 1952 1953 /** 1954 * Get the default selected index for the relative times list. 1955 * 1956 * @return default index 1957 */ 1958 protected int getDefaultRelativeTimeIndex() { 1959 return 4; 1960 } 1961 1962 /** 1963 * Check the times lists 1964 */ 1965 protected void checkTimesLists() { 1966 super.checkTimesLists(); 1967 if (timesCardPanelExtra == null) { 1968 return; 1969 } 1970 if (getDoAbsoluteTimes()) { 1971 timesCardPanelExtra.show("absolute"); 1972 } else { 1973 timesCardPanelExtra.show("relative"); 1974 } 1975 } 1976 1977 /** Card panel to hold extra relative and absolute time components */ 1978 protected GuiUtils.CardLayoutPanel timesCardPanelExtra; 1979 1980 /** 1981 * Set the relative and absolute extra components. 1982 */ 1983 protected JPanel makeTimesPanel(JComponent relativeCard, JComponent absoluteCard) { 1984// JPanel timesPanel = super.makeTimesPanel(false, true); 1985 JPanel timesPanel = super.makeTimesPanel(false, true, getIdv().getUseTimeDriver()); 1986 1987 // Make a new timesPanel that has extra components tacked on the bottom, inside the tabs 1988 Component[] comps = timesPanel.getComponents(); 1989 1990// if (drivercbx != null) { 1991// drivercbx.setEnabled(anyTimeDrivers()); 1992// } 1993 1994 if ((comps.length == 1) && (comps[0] instanceof JTabbedPane)) { 1995 timesCardPanelExtra = new GuiUtils.CardLayoutPanel(); 1996 if (relativeCard == null) { 1997 relativeCard = new JPanel(); 1998 } 1999 if (absoluteCard == null) { 2000 absoluteCard = new JPanel(); 2001 } 2002 timesCardPanelExtra.add(relativeCard, "relative"); 2003 timesCardPanelExtra.add(absoluteCard, "absolute"); 2004 timesPanel = GuiUtils.centerBottom(comps[0], timesCardPanelExtra); 2005 } 2006 2007 return timesPanel; 2008 } 2009 2010 private JPanel innerPanel = new JPanel(); 2011 2012 private JLabel statusLabel = new JLabel("Status"); 2013 2014 /** 2015 * Super setStatus() takes a second string to enable "simple" mode 2016 * which highlights the required component. We don't really care 2017 * about that feature, and we don't want getStatusLabel() to 2018 * change the label background color. 2019 */ 2020 @Override 2021 public void setStatus(String statusString, String foo) { 2022 if (statusString == null) { 2023 statusString = ""; 2024 } 2025 statusLabel.setText(statusString); 2026 } 2027 2028 protected void setInnerPanel(JPanel newInnerPanel) { 2029 innerPanel = newInnerPanel; 2030 } 2031 2032 /** 2033 * Create the widget responsible for handling relative time selection. 2034 * 2035 * @return GUI widget. 2036 */ 2037 @Override public JComponent getRelativeTimesChooser() { 2038 McVTextField relativeTimesField = 2039 McVGuiUtils.makeTextFieldAllow(String.valueOf(relativeTimes), 2040 4, 2041 false, 2042 '0', '1', '2', '3', '4', '5', 2043 '6', '7','8','9'); 2044 2045 // need to keep *both* the ActionListener and DocumentListener around. 2046 // removing the ActionListener results in strange behavior when you've 2047 // accidentally cleared out the text field. 2048 relativeTimesField.setAllow(Pattern.compile("^[1-9][0-9]*$"), true); 2049// relativeTimesField.setDeny(Pattern.compile("^0$"), true); 2050 relativeTimesField.setColumns(4); 2051 relativeTimesField.addActionListener(e -> { 2052 String text = ((JTextField)e.getSource()).getText(); 2053 validateRelativeTimeInput(text); 2054 }); 2055 relativeTimesField.getDocument().addDocumentListener(new DocumentListener() { 2056 @Override public void insertUpdate(DocumentEvent e) { 2057 handleRelativeTimeChange(e); 2058 } 2059 2060 @Override public void removeUpdate(DocumentEvent e) { 2061 handleRelativeTimeChange(e); 2062 } 2063 2064 @Override public void changedUpdate(DocumentEvent e) { 2065 handleRelativeTimeChange(e); 2066 } 2067 }); 2068 relativeTimesField.setToolTipText(RELATIVE_TIMES_TOOLTIP); 2069 2070 JPanel panel = 2071 GuiUtils.topLeft(GuiUtils.label(RELATIVE_TIMES_LABEL, 2072 relativeTimesField)); 2073 JScrollPane scrollPane = new JScrollPane(panel); 2074 scrollPane.setPreferredSize(new Dimension(150, 100)); 2075 return scrollPane; 2076 } 2077 2078 /** 2079 * Validate the contents of the relative times text field. 2080 * 2081 * <p>This method overwrites {@link #relativeTimes} if {@code text} is an 2082 * integer greater than zero.</p> 2083 * 2084 * @param text Contents of the text field. 2085 */ 2086 private void validateRelativeTimeInput(String text) { 2087 try { 2088 int value = Integer.valueOf(text); 2089 if (value > 0) { 2090 relativeTimes = value; 2091 setHaveData(true); 2092 setState(STATE_CONNECTED); 2093 updateStatus(); 2094 } 2095 } catch (NumberFormatException e) { 2096 setState(STATUS_ERROR); 2097 setHaveData(false); 2098 setStatus("Please provide an integer value greater than zero."); 2099 } 2100 } 2101 2102 /** 2103 * Handle {@link DocumentListener} events for the {@link JTextField} 2104 * created by {@link #getRelativeTimesChooser()}. 2105 * 2106 * @param event Event to handle. Cannot be {@code null}. 2107 */ 2108 private void handleRelativeTimeChange(DocumentEvent event) { 2109 int len = event.getDocument().getLength(); 2110 try { 2111 String text = event.getDocument().getText(0, len); 2112 validateRelativeTimeInput(text); 2113 } catch (BadLocationException ex) { 2114 logger.warn("Could not get contents of text field!", ex); 2115 } 2116 } 2117 2118 /** 2119 * Get the relative time indices 2120 * 2121 * @return an array of indices 2122 */ 2123 @Override public int[] getRelativeTimeIndices() { 2124 int[] indices = new int[relativeTimes]; 2125 for (int i = 0; i < indices.length; i++) { 2126 indices[i] = i; 2127 } 2128 return indices; 2129 } 2130 2131 /** 2132 * Make the UI for this selector. 2133 * 2134 * Thank you NetBeans for helping with the layout! 2135 * 2136 * @return The GUI. 2137 */ 2138 protected JComponent doMakeContents() { 2139 JPanel outerPanel = new JPanel(); 2140 2141 JLabel serverLabelInner = new JLabel("Server:"); 2142 McVGuiUtils.setLabelPosition(serverLabelInner, Position.RIGHT); 2143 JPanel serverLabel = GuiUtils.leftRight(parameterButton, serverLabelInner); 2144 McVGuiUtils.setComponentWidth(serverLabel); 2145 2146 clearOnChange(serverSelector); 2147 McVGuiUtils.setComponentWidth(serverSelector, Width.TRIPLE); 2148 // McIDAS Inquiry #2146-3141 -> Changed from Width.DOUBLE to Width.TRIPLE 2149 2150 JLabel groupLabel = McVGuiUtils.makeLabelRight("Dataset:"); 2151 2152 groupSelector.setEditable(isGroupEditable()); 2153 clearOnChange(groupSelector); 2154 McVGuiUtils.setComponentWidth(groupSelector, Width.DOUBLE); 2155 2156 McVGuiUtils.setComponentWidth(connectButton, Width.DOUBLE); 2157 connectButton.setActionCommand(CMD_CONNECT); 2158 connectButton.addActionListener(this); 2159 2160 /* Set the attributes for the descriptor label and combo box, even though 2161 * they are not used here. Extending classes can add them to the panel if 2162 * necessary. 2163 */ 2164 McVGuiUtils.setComponentWidth(descriptorLabel); 2165 McVGuiUtils.setLabelPosition(descriptorLabel, Position.RIGHT); 2166 2167 // McIDAS Inquiry #2146-3141 -> Non-stanard length 2168 McVGuiUtils.setComponentWidth(descriptorComboBox, 584); 2169 2170 if (descriptorComboBox.getMinimumSize().getWidth() < ELEMENT_DOUBLE_WIDTH) { 2171 McVGuiUtils.setComponentWidth(descriptorComboBox, Width.DOUBLE); 2172 } 2173 2174 JLabel statusLabelLabel = McVGuiUtils.makeLabelRight(""); 2175 2176 statusLabel.setText("Status"); 2177 McVGuiUtils.setLabelPosition(statusLabel, Position.RIGHT); 2178 McVGuiUtils.setComponentColor(statusLabel, TextColor.STATUS); 2179 2180 JButton helpButton = McVGuiUtils.makeImageButton(ICON_HELP, "Show help"); 2181 helpButton.setActionCommand(GuiUtils.CMD_HELP); 2182 helpButton.addActionListener(this); 2183 2184 JButton refreshButton = McVGuiUtils.makeImageButton(ICON_REFRESH, "Refresh"); 2185 refreshButton.setActionCommand(GuiUtils.CMD_UPDATE); 2186 refreshButton.addActionListener(this); 2187 2188 McVGuiUtils.setComponentWidth(loadButton, Width.DOUBLE); 2189 2190 GroupLayout layout = new GroupLayout(outerPanel); 2191 outerPanel.setLayout(layout); 2192 layout.setHorizontalGroup( 2193 layout.createParallelGroup(LEADING) 2194 .addGroup(TRAILING, layout.createSequentialGroup() 2195 .addGroup(layout.createParallelGroup(TRAILING) 2196 .addGroup(layout.createSequentialGroup() 2197 .addContainerGap() 2198 .addComponent(helpButton) 2199 .addGap(GAP_RELATED) 2200 .addComponent(refreshButton) 2201 .addGap(GAP_RELATED) 2202 .addComponent(cancelButton) 2203 .addPreferredGap(RELATED) 2204 .addComponent(loadButton)) 2205 .addGroup(LEADING, layout.createSequentialGroup() 2206 .addContainerGap() 2207 .addGroup(layout.createParallelGroup(LEADING) 2208 .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE) 2209 .addGroup(layout.createSequentialGroup() 2210 .addComponent(serverLabel) 2211 .addGap(GAP_RELATED) 2212 .addComponent(serverSelector) 2213 .addGap(GAP_RELATED) 2214 .addComponent(manageButton) 2215 .addGap(GAP_RELATED) 2216 .addComponent(groupLabel) 2217 .addGap(GAP_RELATED) 2218 .addComponent(groupSelector) 2219 .addGap(GAP_RELATED) 2220 .addComponent(publicButton) 2221 .addPreferredGap(RELATED, DEFAULT_SIZE, Short.MAX_VALUE) 2222 .addComponent(connectButton)) 2223 .addGroup(layout.createSequentialGroup() 2224 .addComponent(statusLabelLabel) 2225 .addGap(GAP_RELATED) 2226 .addComponent(statusLabel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE))))) 2227 .addContainerGap()) 2228 ); 2229 layout.setVerticalGroup( 2230 layout.createParallelGroup(LEADING) 2231 .addGroup(layout.createSequentialGroup() 2232 .addContainerGap() 2233 .addGroup(layout.createParallelGroup(BASELINE) 2234 .addComponent(serverLabel) 2235 .addComponent(serverSelector) 2236 .addComponent(manageButton) 2237 .addComponent(groupLabel) 2238 .addComponent(groupSelector) 2239 .addComponent(publicButton) 2240 .addComponent(connectButton)) 2241 .addPreferredGap(UNRELATED) 2242 .addComponent(innerPanel, DEFAULT_SIZE, DEFAULT_SIZE, Short.MAX_VALUE) 2243 .addPreferredGap(UNRELATED) 2244 .addGroup(layout.createParallelGroup(BASELINE) 2245 .addComponent(statusLabelLabel) 2246 .addComponent(statusLabel)) 2247 .addPreferredGap(UNRELATED) 2248 .addGroup(layout.createParallelGroup(BASELINE) 2249 .addComponent(loadButton) 2250 .addComponent(cancelButton) 2251 .addComponent(refreshButton) 2252 .addComponent(helpButton)) 2253 .addContainerGap()) 2254 ); 2255 2256 return outerPanel; 2257 2258 } 2259 2260 public class ServerComparator implements Comparator<AddeServer> { 2261 public int compare(AddeServer server1, AddeServer server2) { 2262 return server1.getName().compareTo(server2.getName()); 2263 } 2264 } 2265 2266 public class GroupComparator implements Comparator<Group> { 2267 public int compare(Group group1, Group group2) { 2268 return group1.getName().compareTo(group2.getName()); 2269 } 2270 } 2271} 2272