/* * JBoss, Home of Professional Open Source * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors * as indicated by the @author tags. All rights reserved. * See the copyright.txt in the distribution for a * full listing of individual contributors. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ package org.jboss.as.cli.gui; import static java.awt.BorderLayout.CENTER; import static java.awt.BorderLayout.NORTH; import static java.awt.BorderLayout.SOUTH; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.beans.PropertyVetoException; import java.net.URL; import java.util.regex.Pattern; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDesktopPane; import javax.swing.JInternalFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.jboss.as.cli.CliInitializationException; import org.jboss.as.cli.CommandContext; import org.jboss.as.cli.CommandContextFactory; import org.jboss.as.cli.CommandLineException; /** * Dialog which is used to connect to server in case local vm has been chosen. In such case there is no * JMX Connection open in JConsole so this dialog is used to open dedicated one. * * @author baranowb */ public class ConnectDialog extends JInternalFrame { static final String DEFAULT_REMOTE = "remote+http://localhost:9990"; // TODO - Can this sync up with config somehow? // NOTE: CLI has no Message IDs assigned, hence Resources.getText(...); // This will probably requirean i18n static final String HINT_CONNECT = "<protocol>://<hostname>:<port> OR empty"; static final String HINT_CONNECT_BUTTON = "Connect to server CLI"; static final String TEXT_CONNECT = "Connect"; static final String TEXT_USERNAME = "Username: "; static final String TEXT_PASSWORD = "Password: "; static boolean IS_WIN; static boolean IS_GTK; static { String lafName = UIManager.getLookAndFeel().getClass().getName(); IS_GTK = lafName.equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); IS_WIN = lafName.equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"); } // private JDesktopPane desktop = new JDesktopPane(); private JTextField tfUserName, tfPassword; private JTextField tfURL; private Action actionConnect; private Color hintTextColor; private JLabel statusBar; private final JConsoleCLIPlugin plugin; private final JPanel targetDisplay; private final JDesktopPane display = new JDesktopPane(); private boolean started = false; public ConnectDialog(final JConsoleCLIPlugin jConsoleCLIPlugin, final JPanel targetDisplay) { super(); this.plugin = jConsoleCLIPlugin; this.targetDisplay = targetDisplay; this.display.add(this); setVisible(false); createHelpers(); createActions(); createContent(); this.setSize(this.getPreferredSize()); } public void start() { if(started){ return; } // to update GUI... // SwingUtilities... does not work. new Thread(new Runnable() { public void run() { inner_start(); } }).start(); } private void inner_start(){ //HACK, location needs to be set twice... targetDisplay.setVisible(false); targetDisplay.add(display); setLocation((display.getWidth() - getWidth()) / 2, (display.getHeight() - getHeight()) / 2); tfURL.setText(DEFAULT_REMOTE); try { // Bring to front of other dialogs setSelected(true); } catch (PropertyVetoException e) { } targetDisplay.setVisible(true); targetDisplay.revalidate(); targetDisplay.repaint(); setVisible(true); setLocation((display.getWidth() - getWidth()) / 2, (display.getHeight() - getHeight()) / 2); started = true; } public void stop() { this.targetDisplay.remove(this.display); this.started = false; } public boolean isStarted() { return this.started; } private void createHelpers() { hintTextColor = UIManager.getColor("Panel.background"); setDefaultCloseOperation(HIDE_ON_CLOSE); setResizable(false); } private void createActions() { actionConnect = new AbstractAction(TEXT_CONNECT) { public void actionPerformed(ActionEvent ev) { if (!isEnabled() || !isVisible()) { return; } String controller = null; String user = null; String password = null; if (tfURL.getText().length() > 0) { controller = tfURL.getText(); if (tfUserName.getText().length() > 0) { user = tfUserName.getText(); password = tfPassword.getText(); } } try { final CommandContext cmdCtx; if (user == null) { cmdCtx = CommandContextFactory.getInstance().newCommandContext(); } else { cmdCtx = CommandContextFactory.getInstance().newCommandContext(null, user, password.toCharArray()); } cmdCtx.connectController(controller); plugin.init(cmdCtx); } catch (CliInitializationException e) { statusBar.setText(e.getMessage()); e.printStackTrace(); return; } catch (NumberFormatException e) { statusBar.setText(e.getMessage()); e.printStackTrace(); return; } catch (CommandLineException e) { e.printStackTrace(); statusBar.setText(e.getMessage()); return; } setVisible(false); clearStatus(); } }; } private void createContent() { Container cp = (JComponent) getContentPane(); final JPanel urlPanel = new JPanel(new BorderLayout(0, 12)); urlPanel.setBorder(new EmptyBorder(6, 12, 12, 12)); final JPanel bottomPanel = new JPanel(new BorderLayout()); statusBar = new JLabel(" ", JLabel.CENTER); final Font normalLabelFont = statusBar.getFont(); Font boldLabelFont = normalLabelFont.deriveFont(Font.BOLD); final Font smallLabelFont = normalLabelFont.deriveFont(normalLabelFont.getSize2D() - 1); //TODO: is this fine or should it be padded like original? final URL iconURL = GuiMain.class.getResource("/icon/wildfly_logo.png"); final Image logo = Toolkit.getDefaultToolkit().getImage(iconURL); final Icon icon = new ImageIcon(logo); final JLabel mastheadLabel = new JLabel(icon); cp.add(mastheadLabel, NORTH); cp.add(urlPanel, CENTER); cp.add(bottomPanel, SOUTH); tfURL = new JTextField(); tfURL.getDocument().addDocumentListener(new UrlDocumentListener(tfURL)); tfURL.setPreferredSize(tfURL.getPreferredSize()); final JPanel tfPanel = new JPanel(new BorderLayout()); urlPanel.add(tfPanel, CENTER); tfPanel.add(tfURL, NORTH); final JLabel remoteMessageLabel = new JLabel(HINT_CONNECT); remoteMessageLabel.setFont(smallLabelFont); remoteMessageLabel.setForeground(hintTextColor); tfPanel.add(remoteMessageLabel, CENTER); final JPanel userPwdPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 0, 0)); userPwdPanel.setBorder(new EmptyBorder(12, 0, 0, 0)); // top padding int tfWidth = IS_WIN ? 12 : 8; tfUserName = new JTextField(tfWidth); JPanel lc; lc = new Labeled(TEXT_USERNAME,boldLabelFont, tfUserName); userPwdPanel.add(lc); tfPassword = new JPasswordField(tfWidth); // Heights differ, so fix here tfPassword.setPreferredSize(tfUserName.getPreferredSize()); lc = new Labeled(TEXT_PASSWORD, boldLabelFont, tfPassword); lc.setBorder(new EmptyBorder(0, 12, 0, 0)); // Left padding lc.setFont(boldLabelFont); userPwdPanel.add(lc); tfPanel.add(userPwdPanel, SOUTH); final JButton connectButton = new JButton(this.actionConnect); connectButton.setToolTipText(HINT_CONNECT_BUTTON); final JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING)); buttonPanel.setBorder(new EmptyBorder(12, 12, 2, 12)); buttonPanel.add(connectButton); bottomPanel.add(buttonPanel, NORTH); bottomPanel.add(statusBar, SOUTH); this.pack(); } private void clearStatus(){ statusBar.setText(" "); } private class UrlDocumentListener implements DocumentListener{ private static final String RX_PROTOCOL = "[A-Za-z\\-]+://"; private static final String RX_HOST = "[1-9A-Za-z\\.]+"; private static final String RX_PORT = ":\\d+"; private static final String REGEXP = "(" + RX_HOST + ")|(" + RX_HOST + RX_PORT + ")|(" + RX_PROTOCOL + RX_HOST + ")|(" + RX_PROTOCOL + RX_HOST + RX_PORT + ")"; private final JTextField textField; public UrlDocumentListener(JTextField textField) { super(); this.textField = textField; } @Override public void changedUpdate(DocumentEvent documentEvent) { } @Override public void insertUpdate(DocumentEvent documentEvent) { //documentEvent.getDocument().getText() return trash... validateURL(); } @Override public void removeUpdate(DocumentEvent documentEvent) { validateURL(); } private void validateURL(){ //more? final String text = textField.getText(); if(text == null || text.length() == 0){ clearStatus(); return; } if(Pattern.matches(REGEXP, text)){ clearStatus(); } else { statusBar.setText("Connection url is not correct."); } } } private class Labeled extends JPanel{ private final Component comp; private final JLabel leftLabel; public Labeled(final String label, final Font font, final Component toBeLabeled){ this.comp = toBeLabeled; this.leftLabel = new JLabel(label); if(font!=null) this.leftLabel.setFont(font); super.setLayout(new BorderLayout(6,6)); super.add(leftLabel,BorderLayout.WEST); super.add(comp,BorderLayout.CENTER); } } }