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