public void addGui(final DownloadDialog gui) {
    buildDownloadAreaInputFields();
    final JPanel dlg = new JPanel(new GridBagLayout());

    tfOsmUrl.getDocument().addDocumentListener(new OsmUrlRefresher());

    // select content on receiving focus. this seems to be the default in the
    // windows look+feel but not for others. needs invokeLater to avoid strange
    // side effects that will cancel out the newly made selection otherwise.
    tfOsmUrl.addFocusListener(new SelectAllOnFocusHandler(tfOsmUrl));
    tfOsmUrl.setLineWrap(true);
    tfOsmUrl.setBorder(latlon[0].getBorder());

    dlg.add(new JLabel(tr("min lat")), GBC.std().insets(10, 20, 5, 0));
    dlg.add(latlon[0], GBC.std().insets(0, 20, 0, 0));
    dlg.add(new JLabel(tr("min lon")), GBC.std().insets(10, 20, 5, 0));
    dlg.add(latlon[1], GBC.eol().insets(0, 20, 0, 0));
    dlg.add(new JLabel(tr("max lat")), GBC.std().insets(10, 0, 5, 0));
    dlg.add(latlon[2], GBC.std());
    dlg.add(new JLabel(tr("max lon")), GBC.std().insets(10, 0, 5, 0));
    dlg.add(latlon[3], GBC.eol());

    dlg.add(
        new JLabel(
            tr("URL from www.openstreetmap.org (you can paste an URL here to download the area)")),
        GBC.eol().insets(10, 20, 5, 0));
    dlg.add(tfOsmUrl, GBC.eop().insets(10, 0, 5, 0).fill());
    tfOsmUrl.addMouseListener(
        new MouseAdapter() {
          @Override
          public void mousePressed(MouseEvent e) {
            checkPopup(e);
          }

          @Override
          public void mouseClicked(MouseEvent e) {
            checkPopup(e);
          }

          @Override
          public void mouseReleased(MouseEvent e) {
            checkPopup(e);
          }

          private void checkPopup(MouseEvent e) {
            if (e.isPopupTrigger()) {
              OsmUrlPopup popup = new OsmUrlPopup();
              popup.show(tfOsmUrl, e.getX(), e.getY());
            }
          }
        });
    dlg.add(showUrl, GBC.eop().insets(10, 0, 5, 5));
    showUrl.setEditable(false);
    showUrl.setBackground(dlg.getBackground());
    showUrl.addFocusListener(new SelectAllOnFocusHandler(showUrl));

    gui.addDownloadAreaSelector(dlg, tr("Bounding Box"));
    this.parent = gui;
  }
Esempio n. 2
0
  @Override
  public Object getInfoComponent() {
    final DataCountVisitor counter = new DataCountVisitor();
    for (final OsmPrimitive osm : data.allPrimitives()) osm.visit(counter);
    final JPanel p = new JPanel(new GridBagLayout());
    p.add(new JLabel(tr("{0} consists of:", name)), GBC.eol());
    for (int i = 0; i < counter.normal.length; ++i) {
      String s =
          counter.normal[i]
              + " "
              + trn(counter.names[i], counter.names[i] + "s", counter.normal[i]);
      if (counter.deleted[i] > 0) s += tr(" ({0} deleted.)", counter.deleted[i]);
      p.add(
          new JLabel(s, ImageProvider.get("data", counter.names[i]), JLabel.HORIZONTAL),
          GBC.eop().insets(15, 0, 0, 0));
    }
    p.add(new JLabel(tr("API version: {0}", (data.version != null) ? data.version : tr("unset"))));

    return p;
  }
Esempio n. 3
0
  protected Collection<Command> applyCorrections(
      Map<OsmPrimitive, List<TagCorrection>> tagCorrectionsMap,
      Map<OsmPrimitive, List<RoleCorrection>> roleCorrectionMap,
      String description)
      throws UserCancelException {

    if (!tagCorrectionsMap.isEmpty() || !roleCorrectionMap.isEmpty()) {
      Collection<Command> commands = new ArrayList<Command>();
      Map<OsmPrimitive, TagCorrectionTable> tagTableMap =
          new HashMap<OsmPrimitive, TagCorrectionTable>();
      Map<OsmPrimitive, RoleCorrectionTable> roleTableMap =
          new HashMap<OsmPrimitive, RoleCorrectionTable>();

      final JPanel p = new JPanel(new GridBagLayout());

      final JMultilineLabel label1 = new JMultilineLabel(description);
      label1.setMaxWidth(600);
      p.add(label1, GBC.eop().anchor(GBC.CENTER));

      final JMultilineLabel label2 =
          new JMultilineLabel(tr("Please select which changes you want to apply."));
      label2.setMaxWidth(600);
      p.add(label2, GBC.eop().anchor(GBC.CENTER));

      for (Entry<OsmPrimitive, List<TagCorrection>> entry : tagCorrectionsMap.entrySet()) {
        final OsmPrimitive primitive = entry.getKey();
        final List<TagCorrection> tagCorrections = entry.getValue();

        if (tagCorrections.isEmpty()) {
          continue;
        }

        final JLabel propertiesLabel = new JLabel(tr("Tags of "));
        p.add(propertiesLabel, GBC.std());

        final JLabel primitiveLabel =
            new JLabel(
                primitive.getDisplayName(DefaultNameFormatter.getInstance()) + ":",
                ImageProvider.get(primitive.getDisplayType()),
                JLabel.LEFT);
        p.add(primitiveLabel, GBC.eol());

        final TagCorrectionTable table = new TagCorrectionTable(tagCorrections);
        final JScrollPane scrollPane = new JScrollPane(table);
        p.add(scrollPane, GBC.eop().fill(GBC.HORIZONTAL));

        tagTableMap.put(primitive, table);
      }

      for (Entry<OsmPrimitive, List<RoleCorrection>> entry : roleCorrectionMap.entrySet()) {
        final OsmPrimitive primitive = entry.getKey();
        final List<RoleCorrection> roleCorrections = entry.getValue();

        if (roleCorrections.isEmpty()) {
          continue;
        }

        final JLabel rolesLabel = new JLabel(tr("Roles in relations referring to"));
        p.add(rolesLabel, GBC.std());

        final JLabel primitiveLabel =
            new JLabel(
                primitive.getDisplayName(DefaultNameFormatter.getInstance()),
                ImageProvider.get(primitive.getDisplayType()),
                JLabel.LEFT);
        p.add(primitiveLabel, GBC.eol());

        final RoleCorrectionTable table = new RoleCorrectionTable(roleCorrections);
        final JScrollPane scrollPane = new JScrollPane(table);
        p.add(scrollPane, GBC.eop().fill(GBC.HORIZONTAL));

        roleTableMap.put(primitive, table);
      }

      int answer =
          JOptionPane.showOptionDialog(
              Main.parent,
              p,
              tr("Automatic tag correction"),
              JOptionPane.YES_NO_CANCEL_OPTION,
              JOptionPane.PLAIN_MESSAGE,
              null,
              applicationOptions,
              applicationOptions[0]);

      if (answer == JOptionPane.YES_OPTION) {
        for (Entry<OsmPrimitive, List<TagCorrection>> entry : tagCorrectionsMap.entrySet()) {
          List<TagCorrection> tagCorrections = entry.getValue();
          OsmPrimitive primitive = entry.getKey();

          // create the clone
          OsmPrimitive clone = null;
          if (primitive instanceof Way) {
            clone = new Way((Way) primitive);
          } else if (primitive instanceof Node) {
            clone = new Node((Node) primitive);
          } else if (primitive instanceof Relation) {
            clone = new Relation((Relation) primitive);
          } else throw new AssertionError();

          // use this structure to remember keys that have been set already so that
          // they're not dropped by a later step
          Set<String> keysChanged = new HashSet<String>();

          // apply all changes to this clone
          for (int i = 0; i < tagCorrections.size(); i++) {
            if (tagTableMap.get(primitive).getCorrectionTableModel().getApply(i)) {
              TagCorrection tagCorrection = tagCorrections.get(i);
              if (tagCorrection.isKeyChanged() && !keysChanged.contains(tagCorrection.oldKey)) {
                clone.remove(tagCorrection.oldKey);
              }
              clone.put(tagCorrection.newKey, tagCorrection.newValue);
              keysChanged.add(tagCorrection.newKey);
            }
          }

          // save the clone
          if (!keysChanged.isEmpty()) {
            commands.add(new ChangeCommand(primitive, clone));
          }
        }
        for (Entry<OsmPrimitive, List<RoleCorrection>> entry : roleCorrectionMap.entrySet()) {
          OsmPrimitive primitive = entry.getKey();
          List<RoleCorrection> roleCorrections = entry.getValue();

          for (int i = 0; i < roleCorrections.size(); i++) {
            RoleCorrection roleCorrection = roleCorrections.get(i);
            if (roleTableMap.get(primitive).getCorrectionTableModel().getApply(i)) {
              commands.add(
                  new ChangeRelationMemberRoleCommand(
                      roleCorrection.relation, roleCorrection.position, roleCorrection.newRole));
            }
          }
        }
      } else if (answer != JOptionPane.NO_OPTION) throw new UserCancelException();
      return commands;
    }

    return Collections.emptyList();
  }
Esempio n. 4
0
  public AddWMSLayerPanel() {
    JPanel wmsFetchPanel = new JPanel(new GridBagLayout());
    menuName = new JTextField(40);
    menuName.setText(tr("Unnamed WMS Layer"));
    final JTextArea serviceUrl = new JTextArea(3, 40);
    serviceUrl.setLineWrap(true);
    serviceUrl.setText("http://sample.com/wms?");
    wmsFetchPanel.add(new JLabel(tr("Menu Name")), GBC.std().insets(0, 0, 5, 0));
    wmsFetchPanel.add(menuName, GBC.eop().insets(5, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
    wmsFetchPanel.add(new JLabel(tr("Service URL")), GBC.std().insets(0, 0, 5, 0));
    JScrollPane scrollPane =
        new JScrollPane(
            serviceUrl,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
    wmsFetchPanel.add(scrollPane, GBC.eop().insets(5, 0, 0, 0));
    JButton getLayersButton = new JButton(tr("Get Layers"));
    getLayersButton.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            Cursor beforeCursor = getCursor();
            try {
              setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
              attemptGetCapabilities(serviceUrl.getText());
            } finally {
              setCursor(beforeCursor);
            }
          }
        });
    wmsFetchPanel.add(getLayersButton, GBC.eop().anchor(GridBagConstraints.EAST));

    treeRootNode = new DefaultMutableTreeNode();
    treeData = new DefaultTreeModel(treeRootNode);
    layerTree = new JTree(treeData);
    layerTree.setCellRenderer(new LayerTreeCellRenderer());
    layerTree.addTreeSelectionListener(
        new TreeSelectionListener() {

          @Override
          public void valueChanged(TreeSelectionEvent e) {
            TreePath[] selectionRows = layerTree.getSelectionPaths();
            if (selectionRows == null) {
              showBoundsButton.setEnabled(false);
              selectedLayer = null;
              return;
            }

            selectedLayers = new LinkedList<LayerDetails>();
            for (TreePath i : selectionRows) {
              Object userObject =
                  ((DefaultMutableTreeNode) i.getLastPathComponent()).getUserObject();
              if (userObject instanceof LayerDetails) {
                LayerDetails detail = (LayerDetails) userObject;
                if (!detail.isSupported()) {
                  layerTree.removeSelectionPath(i);
                  if (!previouslyShownUnsupportedCrsError) {
                    JOptionPane.showMessageDialog(
                        null,
                        tr(
                            "That layer does not support any of JOSM's projections,\n"
                                + "so you can not use it. This message will not show again."),
                        tr("WMS Error"),
                        JOptionPane.ERROR_MESSAGE);
                    previouslyShownUnsupportedCrsError = true;
                  }
                } else if (detail.ident != null) {
                  selectedLayers.add(detail);
                }
              }
            }

            if (!selectedLayers.isEmpty()) {
              resultingLayerField.setText(buildGetMapUrl());

              if (selectedLayers.size() == 1) {
                showBoundsButton.setEnabled(true);
                selectedLayer = selectedLayers.get(0);
              }
            } else {
              showBoundsButton.setEnabled(false);
              selectedLayer = null;
            }
          }
        });
    wmsFetchPanel.add(
        new JScrollPane(layerTree),
        GBC.eop().insets(5, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));

    JPanel layerManipulationButtons = new JPanel();
    showBoundsButton = new JButton(tr("Show Bounds"));
    showBoundsButton.setEnabled(false);
    showBoundsButton.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            if (selectedLayer.bounds != null) {
              SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
              mapPanel.setBoundingBox(selectedLayer.bounds);
              JOptionPane.showMessageDialog(
                  null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
            } else {
              JOptionPane.showMessageDialog(
                  null,
                  tr("No bounding box was found for this layer."),
                  tr("WMS Error"),
                  JOptionPane.ERROR_MESSAGE);
            }
          }
        });
    layerManipulationButtons.add(showBoundsButton);

    wmsFetchPanel.add(layerManipulationButtons, GBC.eol().insets(0, 0, 5, 0));
    wmsFetchPanel.add(new JLabel(tr("WMS URL")), GBC.std().insets(0, 0, 5, 0));
    resultingLayerField = new JTextArea(3, 40);
    resultingLayerField.setLineWrap(true);
    wmsFetchPanel.add(
        new JScrollPane(
            resultingLayerField,
            JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
            JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),
        GBC.eop().insets(5, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));

    add(wmsFetchPanel);
  }
Esempio n. 5
0
  public static SearchSetting showSearchDialog(SearchSetting initialValues) {
    if (initialValues == null) {
      initialValues = new SearchSetting();
    }
    // -- prepare the combo box with the search expressions
    //
    JLabel label =
        new JLabel(initialValues instanceof Filter ? tr("Filter string:") : tr("Search string:"));
    final HistoryComboBox hcbSearchString = new HistoryComboBox();
    final String tooltip = tr("Enter the search expression");
    hcbSearchString.setText(initialValues.text);
    hcbSearchString.setToolTipText(tooltip);
    // we have to reverse the history, because ComboBoxHistory will reverse it again in addElement()
    //
    List<String> searchExpressionHistory = getSearchExpressionHistory();
    Collections.reverse(searchExpressionHistory);
    hcbSearchString.setPossibleItems(searchExpressionHistory);
    hcbSearchString.setPreferredSize(new Dimension(40, hcbSearchString.getPreferredSize().height));
    label.setLabelFor(hcbSearchString);

    JRadioButton replace =
        new JRadioButton(tr("replace selection"), initialValues.mode == SearchMode.replace);
    JRadioButton add =
        new JRadioButton(tr("add to selection"), initialValues.mode == SearchMode.add);
    JRadioButton remove =
        new JRadioButton(tr("remove from selection"), initialValues.mode == SearchMode.remove);
    JRadioButton inSelection =
        new JRadioButton(tr("find in selection"), initialValues.mode == SearchMode.in_selection);
    ButtonGroup bg = new ButtonGroup();
    bg.add(replace);
    bg.add(add);
    bg.add(remove);
    bg.add(inSelection);

    final JCheckBox caseSensitive =
        new JCheckBox(tr("case sensitive"), initialValues.caseSensitive);
    JCheckBox allElements = new JCheckBox(tr("all objects"), initialValues.allElements);
    allElements.setToolTipText(tr("Also include incomplete and deleted objects in search."));
    final JRadioButton standardSearch =
        new JRadioButton(tr("standard"), !initialValues.regexSearch && !initialValues.mapCSSSearch);
    final JRadioButton regexSearch =
        new JRadioButton(tr("regular expression"), initialValues.regexSearch);
    final JRadioButton mapCSSSearch =
        new JRadioButton(tr("MapCSS selector"), initialValues.mapCSSSearch);
    final JCheckBox addOnToolbar = new JCheckBox(tr("add toolbar button"), false);
    final ButtonGroup bg2 = new ButtonGroup();
    bg2.add(standardSearch);
    bg2.add(regexSearch);
    bg2.add(mapCSSSearch);

    JPanel top = new JPanel(new GridBagLayout());
    top.add(label, GBC.std().insets(0, 0, 5, 0));
    top.add(hcbSearchString, GBC.eol().fill(GBC.HORIZONTAL));
    JPanel left = new JPanel(new GridBagLayout());
    left.add(replace, GBC.eol());
    left.add(add, GBC.eol());
    left.add(remove, GBC.eol());
    left.add(inSelection, GBC.eop());
    left.add(caseSensitive, GBC.eol());
    if (Main.pref.getBoolean("expert", false)) {
      left.add(allElements, GBC.eol());
      left.add(addOnToolbar, GBC.eop());
      left.add(standardSearch, GBC.eol());
      left.add(regexSearch, GBC.eol());
      left.add(mapCSSSearch, GBC.eol());
    }

    final JPanel right;
    right = new JPanel(new GridBagLayout());
    buildHints(right, hcbSearchString);

    final JTextComponent editorComponent = hcbSearchString.getEditorComponent();
    editorComponent
        .getDocument()
        .addDocumentListener(
            new AbstractTextComponentValidator(editorComponent) {

              @Override
              public void validate() {
                if (!isValid()) {
                  feedbackInvalid(tr("Invalid search expression"));
                } else {
                  feedbackValid(tooltip);
                }
              }

              @Override
              public boolean isValid() {
                try {
                  SearchSetting ss = new SearchSetting();
                  ss.text = hcbSearchString.getText();
                  ss.caseSensitive = caseSensitive.isSelected();
                  ss.regexSearch = regexSearch.isSelected();
                  ss.mapCSSSearch = mapCSSSearch.isSelected();
                  SearchCompiler.compile(ss);
                  return true;
                } catch (ParseError | MapCSSException e) {
                  return false;
                }
              }
            });

    final JPanel p = new JPanel(new GridBagLayout());
    p.add(top, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 5, 5, 0));
    p.add(left, GBC.std().anchor(GBC.NORTH).insets(5, 10, 10, 0));
    p.add(right, GBC.eol());
    ExtendedDialog dialog =
        new ExtendedDialog(
            Main.parent,
            initialValues instanceof Filter ? tr("Filter") : tr("Search"),
            new String[] {
              initialValues instanceof Filter ? tr("Submit filter") : tr("Start Search"),
              tr("Cancel")
            }) {
          @Override
          protected void buttonAction(int buttonIndex, ActionEvent evt) {
            if (buttonIndex == 0) {
              try {
                SearchSetting ss = new SearchSetting();
                ss.text = hcbSearchString.getText();
                ss.caseSensitive = caseSensitive.isSelected();
                ss.regexSearch = regexSearch.isSelected();
                ss.mapCSSSearch = mapCSSSearch.isSelected();
                SearchCompiler.compile(ss);
                super.buttonAction(buttonIndex, evt);
              } catch (ParseError e) {
                Main.debug(e);
                JOptionPane.showMessageDialog(
                    Main.parent,
                    tr("Search expression is not valid: \n\n {0}", e.getMessage()),
                    tr("Invalid search expression"),
                    JOptionPane.ERROR_MESSAGE);
              }
            } else {
              super.buttonAction(buttonIndex, evt);
            }
          }
        };
    dialog.setButtonIcons(new String[] {"dialogs/search", "cancel"});
    dialog.configureContextsensitiveHelp("/Action/Search", true /* show help button */);
    dialog.setContent(p);
    dialog.showDialog();
    int result = dialog.getValue();

    if (result != 1) return null;

    // User pressed OK - let's perform the search
    SearchMode mode =
        replace.isSelected()
            ? SearchAction.SearchMode.replace
            : (add.isSelected()
                ? SearchAction.SearchMode.add
                : (remove.isSelected()
                    ? SearchAction.SearchMode.remove
                    : SearchAction.SearchMode.in_selection));
    initialValues.text = hcbSearchString.getText();
    initialValues.mode = mode;
    initialValues.caseSensitive = caseSensitive.isSelected();
    initialValues.allElements = allElements.isSelected();
    initialValues.regexSearch = regexSearch.isSelected();
    initialValues.mapCSSSearch = mapCSSSearch.isSelected();

    if (addOnToolbar.isSelected()) {
      ToolbarPreferences.ActionDefinition aDef =
          new ToolbarPreferences.ActionDefinition(Main.main.menu.search);
      aDef.getParameters().put(SEARCH_EXPRESSION, initialValues);
      // Display search expression as tooltip instead of generic one
      aDef.setName(Utils.shortenString(initialValues.text, MAX_LENGTH_SEARCH_EXPRESSION_DISPLAY));
      // parametrized action definition is now composed
      ActionParser actionParser = new ToolbarPreferences.ActionParser(null);
      String res = actionParser.saveAction(aDef);

      // add custom search button to toolbar preferences
      Main.toolbar.addCustomButton(res, -1, false);
    }
    return initialValues;
  }
Esempio n. 6
0
  /** Constructs a new {@code AddWMSLayerPanel}. */
  public AddWMSLayerPanel() {

    add(new JLabel(tr("1. Enter service URL")), GBC.eol());
    add(rawUrl, GBC.eol().fill());
    rawUrl.setLineWrap(true);
    JButton getLayers = new JButton(tr("Get layers"));
    add(getLayers, GBC.eop().fill());

    add(new JLabel(tr("2. Select layers")), GBC.eol());
    add(endpoint, GBC.eol().fill());
    add(new JScrollPane(tree.getLayerTree()), GBC.eol().fill().weight(1, 100));

    showBounds.setEnabled(false);
    add(new JScrollPane(showBounds), GBC.eop().fill());

    add(new JLabel(tr("3. Select image format")), GBC.eol());
    add(formats, GBC.eol().fill());

    add(wmsInstruction = new JLabel(tr("4. Verify generated WMS URL")), GBC.eol());
    add(wmsUrl, GBC.eop().fill());
    wmsUrl.setLineWrap(true);

    add(new JLabel(tr("5. Enter name for this layer")), GBC.eol());
    add(name, GBC.eop().fill());

    getLayers.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            try {
              wms.attemptGetCapabilities(rawUrl.getText());
              tree.updateTree(wms);
              formats.setModel(new DefaultComboBoxModel(wms.getFormats().toArray()));
            } catch (MalformedURLException ex) {
              JOptionPane.showMessageDialog(
                  getParent(),
                  tr("Invalid service URL."),
                  tr("WMS Error"),
                  JOptionPane.ERROR_MESSAGE);
            } catch (IOException ex) {
              JOptionPane.showMessageDialog(
                  getParent(),
                  tr("Could not retrieve WMS layer list."),
                  tr("WMS Error"),
                  JOptionPane.ERROR_MESSAGE);
            } catch (WMSImagery.WMSGetCapabilitiesException ex) {
              JOptionPane.showMessageDialog(
                  getParent(),
                  tr("Could not parse WMS layer list."),
                  tr("WMS Error"),
                  JOptionPane.ERROR_MESSAGE);
              System.err.println("Could not parse WMS layer list. Incoming data:");
              System.err.println(ex.getIncomingData());
            }
          }
        });

    endpoint.addItemListener(
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            tree.getLayerTree().setEnabled(!endpoint.isSelected());
            showBounds.setEnabled(!endpoint.isSelected());
            wmsInstruction.setEnabled(!endpoint.isSelected());
            formats.setEnabled(!endpoint.isSelected());
            wmsUrl.setEnabled(!endpoint.isSelected());
            if (endpoint.isSelected()) {
              URL url = wms.getServiceUrl();
              if (url != null) {
                name.setText(url.getHost());
              }
            } else {
              onLayerSelectionChanged();
            }
          }
        });

    tree.getLayerTree()
        .addPropertyChangeListener(
            "selectedLayers",
            new PropertyChangeListener() {
              @Override
              public void propertyChange(PropertyChangeEvent evt) {
                onLayerSelectionChanged();
              }
            });

    formats.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            onLayerSelectionChanged();
          }
        });

    showBounds.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            if (tree.getSelectedLayers().get(0).bounds != null) {
              SlippyMapBBoxChooser mapPanel = new SlippyMapBBoxChooser();
              mapPanel.setBoundingBox(tree.getSelectedLayers().get(0).bounds);
              JOptionPane.showMessageDialog(
                  null, mapPanel, tr("Show Bounds"), JOptionPane.PLAIN_MESSAGE);
            } else {
              JOptionPane.showMessageDialog(
                  null,
                  tr("No bounding box was found for this layer."),
                  tr("WMS Error"),
                  JOptionPane.ERROR_MESSAGE);
            }
          }
        });

    registerValidableComponent(endpoint);
    registerValidableComponent(rawUrl);
    registerValidableComponent(wmsUrl);
  }