+ new project: vaadin-console-addon
authorindvdum
Sun, 15 May 2011 17:46:06 +0400
changeset 0c46bb04134cb
child 1 9b9d2f4b4ce0
+ new project: vaadin-console-addon
pom.xml
src/main/java/org/vaadin/console/Console.java
src/main/java/org/vaadin/console/ConsoleWidgetset.gwt.xml
src/main/java/org/vaadin/console/DefaultConsoleHandler.java
src/main/java/org/vaadin/console/ObjectInspector.java
src/main/java/org/vaadin/console/client/ui/TextConsole.java
src/main/java/org/vaadin/console/client/ui/TextConsoleConfig.java
src/main/java/org/vaadin/console/client/ui/TextConsoleHandler.java
src/main/java/org/vaadin/console/client/ui/VTextConsole.java
src/main/java/org/vaadin/console/public/console/styles.css
src/main/java/org/vaadin/console/sample/ConsoleSampleApplication.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/pom.xml	Sun May 15 17:46:06 2011 +0400
     1.3 @@ -0,0 +1,165 @@
     1.4 +<?xml version="1.0" encoding="utf-8"?>
     1.5 +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     1.6 +	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
     1.7 +
     1.8 +	<modelVersion>4.0.0</modelVersion>
     1.9 +
    1.10 +	<groupId>org.vaadin.addons</groupId>
    1.11 +	<artifactId>console</artifactId>
    1.12 +	<version>1.1.7-SNAPSHOT</version>
    1.13 +	<packaging>jar</packaging>
    1.14 +	<name>Vaadin Console add-on</name>
    1.15 +	<parent>
    1.16 +		<groupId>ru.bazon.think-easy-money</groupId>
    1.17 +		<artifactId>think-easy-money-all</artifactId>
    1.18 +		<version>1.0-SNAPSHOT</version>
    1.19 +	</parent>
    1.20 +
    1.21 +	<build>
    1.22 +		<plugins>
    1.23 +			<plugin>
    1.24 +				<groupId>org.apache.maven.plugins</groupId>
    1.25 +				<artifactId>maven-compiler-plugin</artifactId>
    1.26 +				<configuration>
    1.27 +					<source>1.6</source>
    1.28 +					<target>1.6</target>
    1.29 +				</configuration>
    1.30 +			</plugin>
    1.31 +
    1.32 +			<plugin>
    1.33 +				<groupId>org.apache.maven.plugins</groupId>
    1.34 +				<artifactId>maven-jar-plugin</artifactId>
    1.35 +				<version>2.3.1</version>
    1.36 +				<configuration>
    1.37 +					<archive>
    1.38 +						<index>true</index>
    1.39 +						<manifest>
    1.40 +							<addClasspath>true</addClasspath>
    1.41 +							<!--
    1.42 +								Implementation-Title and Implementation-Version come from the
    1.43 +								POM by default
    1.44 +							-->
    1.45 +							<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
    1.46 +						</manifest>
    1.47 +						<manifestEntries>
    1.48 +							<!-- Package format version - do not change -->
    1.49 +							<Vaadin-Package-Version>1</Vaadin-Package-Version>
    1.50 +
    1.51 +							<!-- Add-on specific fields to update -->
    1.52 +							<Vaadin-License-Title>Apache License 2.0</Vaadin-License-Title>
    1.53 +
    1.54 +							<!--
    1.55 +								Implementation-Title and Implementation-Version come from the
    1.56 +								POM by default
    1.57 +							-->
    1.58 +							<Implementation-Vendor>Vaadin Ltd</Implementation-Vendor>
    1.59 +							<Implementation-Title>${pom.name}</Implementation-Title>
    1.60 +							<Implementation-Version>${pom.version}</Implementation-Version>
    1.61 +
    1.62 +							<!-- Comma-separated list of widgetsets in the package -->
    1.63 +							<Vaadin-Widgetsets>org.vaadin.console.ConsoleWidgetset</Vaadin-Widgetsets>
    1.64 +						</manifestEntries>
    1.65 +					</archive>
    1.66 +				</configuration>
    1.67 +			</plugin>
    1.68 +
    1.69 +			<!-- Compiles your custom GWT components with the GWT compiler -->
    1.70 +			<!--
    1.71 +				A hosted mode browser for client-side widget debugging can be run
    1.72 +				with the goal gwt:run after uncommenting the correct line below. A
    1.73 +				remote debugger can then be connected to port 8998. Note that e.g. a
    1.74 +				Jetty server should be running with the server side parts - use the
    1.75 +				goal jetty:run .
    1.76 +			-->
    1.77 +			<plugin>
    1.78 +				<groupId>org.codehaus.mojo</groupId>
    1.79 +				<artifactId>gwt-maven-plugin</artifactId>
    1.80 +				<version>2.2.0</version>
    1.81 +				<configuration>
    1.82 +					<!-- if you don't specify any modules, the plugin will find them -->
    1.83 +					<webappDirectory>${project.build.directory}/${project.build.finalName}/VAADIN/widgetsets</webappDirectory>
    1.84 +					<!-- On Mac running Snow Leopard, add "-d32" -->
    1.85 +					<!--
    1.86 +						This causes error messages (but build works) in phase "package":
    1.87 +						two processes would use the same debug port
    1.88 +					-->
    1.89 +					<!--
    1.90 +						extraJvmArgs>-Xmx512M -Xss1024k -Xdebug
    1.91 +						-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8998</extraJvmArgs
    1.92 +					-->
    1.93 +					<extraJvmArgs>-Xmx512M -Xss1024k</extraJvmArgs>
    1.94 +					<runTarget>xsite</runTarget>
    1.95 +					<hostedWebapp>${project.build.directory}/${project.build.finalName}</hostedWebapp>
    1.96 +					<noServer>true</noServer>
    1.97 +					<port>8080</port>
    1.98 +					<soyc>false</soyc>
    1.99 +				</configuration>
   1.100 +				<executions>
   1.101 +					<execution>
   1.102 +						<goals>
   1.103 +							<goal>resources</goal>
   1.104 +							<goal>compile</goal>
   1.105 +						</goals>
   1.106 +					</execution>
   1.107 +				</executions>
   1.108 +			</plugin>
   1.109 +		</plugins>
   1.110 +
   1.111 +		<!--
   1.112 +			This is needed for the sources required by the GWT compiler to be
   1.113 +			included in the produced JARs
   1.114 +		-->
   1.115 +		<resources>
   1.116 +			<resource>
   1.117 +				<directory>src/main/java</directory>
   1.118 +			</resource>
   1.119 +			<resource>
   1.120 +				<directory>src/main/resources</directory>
   1.121 +			</resource>
   1.122 +		</resources>
   1.123 +	</build>
   1.124 +	
   1.125 +	<profiles>
   1.126 +		<profile>
   1.127 +			<id>updateWidgetset</id>
   1.128 +			<build>
   1.129 +				<plugins>
   1.130 +					<plugin>
   1.131 +						<groupId>com.vaadin</groupId>
   1.132 +						<artifactId>vaadin-maven-plugin</artifactId>
   1.133 +						<version>1.0.2</version>
   1.134 +						<executions>
   1.135 +							<execution>
   1.136 +								<configuration>
   1.137 +								</configuration>
   1.138 +								<goals>
   1.139 +									<goal>update-widgetset</goal>
   1.140 +								</goals>
   1.141 +							</execution>
   1.142 +						</executions>
   1.143 +					</plugin>
   1.144 +				</plugins>
   1.145 +			</build>
   1.146 +		</profile>
   1.147 +	</profiles>
   1.148 +
   1.149 +	<dependencies>
   1.150 +		<dependency>
   1.151 +			<groupId>com.vaadin</groupId>
   1.152 +			<artifactId>vaadin</artifactId>
   1.153 +			<version>6.6.0</version>
   1.154 +		</dependency>
   1.155 +		<dependency>
   1.156 +			<groupId>org.vaadin.addons</groupId>
   1.157 +			<artifactId>widget-rpc</artifactId>
   1.158 +			<version>1.1.3</version>
   1.159 +		</dependency>
   1.160 +		<dependency>
   1.161 +			<groupId>com.google.gwt</groupId>
   1.162 +			<artifactId>gwt-user</artifactId>
   1.163 +			<version>2.2.0</version>
   1.164 +			<scope>provided</scope>
   1.165 +		</dependency>
   1.166 +	</dependencies>
   1.167 +
   1.168 +</project>
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/main/java/org/vaadin/console/Console.java	Sun May 15 17:46:06 2011 +0400
     2.3 @@ -0,0 +1,730 @@
     2.4 +package org.vaadin.console;
     2.5 +
     2.6 +import java.io.ByteArrayOutputStream;
     2.7 +import java.io.IOException;
     2.8 +import java.io.OutputStream;
     2.9 +import java.io.PrintStream;
    2.10 +import java.io.Serializable;
    2.11 +import java.util.ArrayList;
    2.12 +import java.util.Collections;
    2.13 +import java.util.HashMap;
    2.14 +import java.util.HashSet;
    2.15 +import java.util.List;
    2.16 +import java.util.Map;
    2.17 +import java.util.Set;
    2.18 +
    2.19 +import org.vaadin.rpc.ServerSideHandler;
    2.20 +import org.vaadin.rpc.ServerSideProxy;
    2.21 +import org.vaadin.rpc.client.Method;
    2.22 +
    2.23 +import com.vaadin.terminal.PaintException;
    2.24 +import com.vaadin.terminal.PaintTarget;
    2.25 +import com.vaadin.ui.AbstractComponent;
    2.26 +import com.vaadin.ui.Component;
    2.27 +
    2.28 +/**
    2.29 + * Server side component for the VTextConsole widget.
    2.30 + *
    2.31 + * @author Sami Ekblad / Vaadin
    2.32 + *
    2.33 + */
    2.34 +@com.vaadin.ui.ClientWidget(org.vaadin.console.client.ui.VTextConsole.class)
    2.35 +public class Console extends AbstractComponent implements Component.Focusable {
    2.36 +
    2.37 +    private static final long serialVersionUID = 590258219352859644L;
    2.38 +    private Handler handler;
    2.39 +    private final HashMap<String, Command> commands = new HashMap<String, Command>();
    2.40 +    private final Config config = new Config();
    2.41 +
    2.42 +    private static final String DEFAULT_PS = "}> ";
    2.43 +    private static final String DEFAULT_GREETING = "Console ready.";
    2.44 +    private static final int DEFAULT_BUFFER = 0;
    2.45 +    private static final int DEFAULT_COLS = -1;
    2.46 +    private static final int DEFAULT_ROWS = -1;
    2.47 +    private static final boolean DEFAULT_WRAP = true;
    2.48 +    private static final int MAX_COLS = 500;
    2.49 +    private static final int MAX_ROWS = 200;
    2.50 +
    2.51 +    public boolean isWrap() {
    2.52 +        return config.wrap;
    2.53 +    }
    2.54 +
    2.55 +    public void setWrap(final boolean wrap) {
    2.56 +        config.wrap = wrap;
    2.57 +        client.call("setWrap", wrap);
    2.58 +    }
    2.59 +
    2.60 +    private final ServerSideProxy client = new ServerSideProxy(
    2.61 +            new ClientCallback());
    2.62 +
    2.63 +    /**
    2.64 +     * Inner class to handle client calls.
    2.65 +     *
    2.66 +     */
    2.67 +    public class ClientCallback implements ServerSideHandler {
    2.68 +
    2.69 +        private static final long serialVersionUID = 3992611573500588703L;
    2.70 +
    2.71 +        public void requestRepaint() {
    2.72 +            Console.this.requestRepaint();
    2.73 +        }
    2.74 +
    2.75 +        public Object[] initRequestFromClient() {
    2.76 +            return new Object[] { config.cols, config.rows,
    2.77 +                    config.maxBufferSize, config.wrap, config.greeting,
    2.78 +                    config.ps };
    2.79 +        }
    2.80 +
    2.81 +        public void callFromClient(String method, Object[] params) {
    2.82 +            // TODO Auto-generated method stub
    2.83 +
    2.84 +        }
    2.85 +
    2.86 +    }
    2.87 +
    2.88 +    /**
    2.89 +     * The tab order number of this field.
    2.90 +     */
    2.91 +    private int tabIndex = 0;
    2.92 +    @SuppressWarnings("unused")
    2.93 +    private Integer fontw;
    2.94 +    @SuppressWarnings("unused")
    2.95 +    private Integer fonth;
    2.96 +    private PrintStream printStream;
    2.97 +    private String lastSuggestInput;
    2.98 +    private List<CommandProvider> commandProviders;
    2.99 +
   2.100 +    /**
   2.101 +     * An inner class for holding the configuration data.
   2.102 +     */
   2.103 +    public static class Config implements Serializable {
   2.104 +
   2.105 +        private static final long serialVersionUID = -812601232248504108L;
   2.106 +
   2.107 +        int maxBufferSize = DEFAULT_BUFFER;
   2.108 +        int cols = DEFAULT_COLS;
   2.109 +        int rows = DEFAULT_ROWS;
   2.110 +        boolean wrap = DEFAULT_WRAP;
   2.111 +        String ps = DEFAULT_PS;
   2.112 +        String greeting = DEFAULT_GREETING;
   2.113 +
   2.114 +    }
   2.115 +
   2.116 +    /**
   2.117 +     * Console Handler interface.
   2.118 +     *
   2.119 +     * Handler provides a hook to handle various console related events and
   2.120 +     * override the default processing.
   2.121 +     *
   2.122 +     */
   2.123 +    public interface Handler extends Serializable {
   2.124 +
   2.125 +        /**
   2.126 +         * Called when user uses TAB to complete the command entered into the
   2.127 +         * Console input.
   2.128 +         *
   2.129 +         * @param console
   2.130 +         * @param lastInput
   2.131 +         * @return
   2.132 +         */
   2.133 +        Set<String> getSuggestions(Console console, String lastInput);
   2.134 +
   2.135 +        /**
   2.136 +         * Called when user has entered input to the Console and presses enter
   2.137 +         * to execute it.
   2.138 +         *
   2.139 +         * @param console
   2.140 +         * @param lastInput
   2.141 +         */
   2.142 +        void inputReceived(Console console, String lastInput);
   2.143 +
   2.144 +        /**
   2.145 +         * Handle an exception during a Command execution.
   2.146 +         *
   2.147 +         * @param console
   2.148 +         * @param e
   2.149 +         * @param cmd
   2.150 +         * @param argv
   2.151 +         */
   2.152 +        void handleException(Console console, Exception e, Command cmd,
   2.153 +                String[] argv);
   2.154 +
   2.155 +        /**
   2.156 +         * Handle situation where a command could not be found.
   2.157 +         *
   2.158 +         * @param console
   2.159 +         * @param argv
   2.160 +         */
   2.161 +        void commandNotFound(Console console, String[] argv);
   2.162 +
   2.163 +    }
   2.164 +
   2.165 +    /**
   2.166 +     * Commands that can be executed against the Component instance. They
   2.167 +     * provide convenient string to method mapping. Basically, a Command is a
   2.168 +     * method that that can be executed in Component. It can have parameters or
   2.169 +     * not.
   2.170 +     *
   2.171 +     */
   2.172 +    public interface Command extends Serializable {
   2.173 +
   2.174 +        /**
   2.175 +         * Execute a Command with arguments.
   2.176 +         *
   2.177 +         * @param console
   2.178 +         * @param argv
   2.179 +         * @return
   2.180 +         * @throws Exception
   2.181 +         */
   2.182 +        public Object execute(Console console, String[] argv) throws Exception;
   2.183 +
   2.184 +        /**
   2.185 +         * Get usage information about this command.
   2.186 +         *
   2.187 +         * @param console
   2.188 +         * @param argv
   2.189 +         * @return
   2.190 +         */
   2.191 +        public String getUsage(Console console, String[] argv);
   2.192 +    }
   2.193 +
   2.194 +    /**
   2.195 +     * Interface for providing Commands to the console. One can register a
   2.196 +     * command providers to console instead of individual commands to provide a
   2.197 +     * lot of commands.
   2.198 +     *
   2.199 +     */
   2.200 +    public interface CommandProvider extends Serializable {
   2.201 +
   2.202 +        /**
   2.203 +         * List all available command from this provider.
   2.204 +         *
   2.205 +         * @param console
   2.206 +         * @return
   2.207 +         */
   2.208 +        Set<String> getAvailableCommands(Console console);
   2.209 +
   2.210 +        /**
   2.211 +         * Get Command instance based on command name.
   2.212 +         *
   2.213 +         * @param console
   2.214 +         * @param commandName
   2.215 +         * @return
   2.216 +         */
   2.217 +        Command getCommand(Console console, String commandName);
   2.218 +
   2.219 +    }
   2.220 +
   2.221 +    public void addCommandProvider(final CommandProvider commandProvider) {
   2.222 +        if (commandProviders == null) {
   2.223 +            commandProviders = new ArrayList<CommandProvider>();
   2.224 +        }
   2.225 +        commandProviders.add(commandProvider);
   2.226 +    }
   2.227 +
   2.228 +    public void removeCommandProvider(final CommandProvider commandProvider) {
   2.229 +        if (commandProviders == null) {
   2.230 +            return;
   2.231 +        }
   2.232 +        commandProviders.remove(commandProvider);
   2.233 +    }
   2.234 +
   2.235 +    public void removeAllCommandProviders() {
   2.236 +        if (commandProviders == null) {
   2.237 +            return;
   2.238 +        }
   2.239 +        commandProviders.clear();
   2.240 +    }
   2.241 +
   2.242 +    public Console(final Console.Handler handler) {
   2.243 +        this();
   2.244 +        setHandler(handler);
   2.245 +    }
   2.246 +
   2.247 +    public Console() {
   2.248 +        setImmediate(true);
   2.249 +        setHandler(new DefaultConsoleHandler());
   2.250 +        registerCallbacks();
   2.251 +    }
   2.252 +
   2.253 +    private void registerCallbacks() {
   2.254 +        client.register("suggest", new Method() {
   2.255 +
   2.256 +            public void invoke(String methodName, Object[] params) {
   2.257 +                handleSuggest((String) params[0]);
   2.258 +            }
   2.259 +        });
   2.260 +        client.register("input", new Method() {
   2.261 +
   2.262 +            public void invoke(String methodName, Object[] params) {
   2.263 +                handleInput((String) params[0]);
   2.264 +            }
   2.265 +        });
   2.266 +
   2.267 +    }
   2.268 +
   2.269 +    @Override
   2.270 +    public void paintContent(final PaintTarget target) throws PaintException {
   2.271 +        super.paintContent(target);
   2.272 +        client.paintContent(target);
   2.273 +    }
   2.274 +
   2.275 +    @Override
   2.276 +    public void changeVariables(final Object source,
   2.277 +            final Map<String, Object> variables) {
   2.278 +        super.changeVariables(source, variables);
   2.279 +        client.changeVariables(source, variables);
   2.280 +        if (variables.containsKey("width")) {
   2.281 +            setWidth((String) variables.get("width"));
   2.282 +        }
   2.283 +        if (variables.containsKey("height")) {
   2.284 +            setHeight((String) variables.get("height"));
   2.285 +        }
   2.286 +        if (variables.containsKey("fontw")) {
   2.287 +            fontw = (Integer) variables.get("fontw");
   2.288 +        }
   2.289 +        if (variables.containsKey("fonth")) {
   2.290 +            fonth = (Integer) variables.get("fonth");
   2.291 +        }
   2.292 +        if (variables.containsKey("cols")) {
   2.293 +            config.cols = (Integer) variables.get("cols");
   2.294 +        }
   2.295 +        if (variables.containsKey("rows")) {
   2.296 +            config.rows = (Integer) variables.get("rows");
   2.297 +        }
   2.298 +    }
   2.299 +
   2.300 +    /**
   2.301 +     * Overridden to filter client-side calculation/changes and avoid loops.
   2.302 +     *
   2.303 +     */
   2.304 +    @Override
   2.305 +    public void setWidth(float width, int unit) {
   2.306 +        if (width != getWidth() || unit != getWidthUnits()) {
   2.307 +            super.setWidth(width, unit);
   2.308 +        }
   2.309 +    }
   2.310 +
   2.311 +    /**
   2.312 +     * Overridden to filter client-side calculation/changes and avoid loops.
   2.313 +     *
   2.314 +     */
   2.315 +    @Override
   2.316 +    public void setHeight(float height, int unit) {
   2.317 +        if (height != getHeight() || unit != getHeightUnits()) {
   2.318 +            super.setHeight(height, unit);
   2.319 +        }
   2.320 +    }
   2.321 +
   2.322 +    protected void handleSuggest(final String input) {
   2.323 +
   2.324 +        final boolean cancelIfNotASingleMatch = (input != null && !input
   2.325 +                .equals(lastSuggestInput));
   2.326 +        lastSuggestInput = input;
   2.327 +
   2.328 +        final Set<String> matches = handler.getSuggestions(this, input);
   2.329 +
   2.330 +        if (matches == null || matches.size() == 0) {
   2.331 +            bell();
   2.332 +            return;
   2.333 +        }
   2.334 +
   2.335 +        // Output the original
   2.336 +        final String prefix = parseCommandPrefix(input);
   2.337 +        String output = input.substring(0, input.lastIndexOf(prefix));
   2.338 +        if (matches.size() == 1) {
   2.339 +            // Output the only match
   2.340 +            output += matches.iterator().next() + " "; // append the single
   2.341 +            // match
   2.342 +        } else {
   2.343 +
   2.344 +            // We output until the common prefix
   2.345 +            StringBuilder commonPrefix = new StringBuilder(prefix);
   2.346 +            final int maxLen = matches.iterator().next().length();
   2.347 +            for (int i = prefix.length(); i < maxLen; i++) {
   2.348 +                char c = 0;
   2.349 +                boolean charMatch = true;
   2.350 +                for (final String m : matches) {
   2.351 +                    if (c == 0) {
   2.352 +                        c = m.charAt(i);
   2.353 +                    } else if (i < m.length()) {
   2.354 +                        charMatch &= m.charAt(i) == c;
   2.355 +                        if (!charMatch) {
   2.356 +                            break;
   2.357 +                        }
   2.358 +                    } else {
   2.359 +                        charMatch = false;
   2.360 +                        break;
   2.361 +                    }
   2.362 +                }
   2.363 +                if (charMatch) {
   2.364 +                    commonPrefix.append(c);
   2.365 +                }
   2.366 +            }
   2.367 +            output += commonPrefix.toString();
   2.368 +            if (prefix.equals(commonPrefix.toString())
   2.369 +                    && !cancelIfNotASingleMatch) {
   2.370 +                final StringBuffer suggestions = new StringBuffer("\n");
   2.371 +                for (final String m : matches) {
   2.372 +                    suggestions.append(" " + m);
   2.373 +                }
   2.374 +                print(suggestions.toString());
   2.375 +            } else {
   2.376 +                bell();
   2.377 +                lastSuggestInput = output; // next suggest will not beep
   2.378 +            }
   2.379 +        }
   2.380 +        prompt(output);
   2.381 +        focus();
   2.382 +
   2.383 +    }
   2.384 +
   2.385 +    public void bell() {
   2.386 +        client.call("bell");
   2.387 +    }
   2.388 +
   2.389 +    protected void handleInput(final String input) {
   2.390 +
   2.391 +        // Ask registered handler
   2.392 +        handler.inputReceived(this, input);
   2.393 +
   2.394 +    }
   2.395 +
   2.396 +    protected void parseAndExecuteCommand(final String input) {
   2.397 +        final String[] argv = parseInput(input);
   2.398 +        if (argv != null && argv.length > 0) {
   2.399 +            final Command c = getCommand(argv[0]);
   2.400 +            if (c != null) {
   2.401 +                final String result = executeCommand(c, argv);
   2.402 +                if (result != null) {
   2.403 +                    print(result);
   2.404 +                }
   2.405 +            } else {
   2.406 +                handler.commandNotFound(this, argv);
   2.407 +            }
   2.408 +        }
   2.409 +    }
   2.410 +
   2.411 +    protected String executeCommand(final Command cmd, final String[] argv) {
   2.412 +        try {
   2.413 +            final Object r = cmd.execute(this, argv);
   2.414 +            return r != null ? "" + r : null;
   2.415 +        } catch (final Exception e) {
   2.416 +            handler.handleException(this, e, cmd, argv);
   2.417 +        }
   2.418 +        return null;
   2.419 +    }
   2.420 +
   2.421 +    protected String parseCommandPrefix(final String input) {
   2.422 +        if (input == null) {
   2.423 +            return null;
   2.424 +        }
   2.425 +        if (!input.endsWith(" ")) {
   2.426 +            final String[] argv = parseInput(input);
   2.427 +            if (argv != null && argv.length > 0) {
   2.428 +                return argv[argv.length - 1];
   2.429 +            }
   2.430 +        }
   2.431 +        return "";
   2.432 +    }
   2.433 +
   2.434 +    protected static String[] parseInput(final String input) {
   2.435 +        if (input != null && !"".equals(input.trim())) {
   2.436 +            final String[] temp = input.split(" ");
   2.437 +            if (temp != null && temp.length > 0) {
   2.438 +                final List<String> parsed = new ArrayList<String>(temp.length);
   2.439 +                String current = null;
   2.440 +                for (final String element : temp) {
   2.441 +                    final int quotCount = count(element, '\"');
   2.442 +                    if (quotCount > 0 && quotCount % 2 != 0) {
   2.443 +                        // uneven number of quotes star or end combining params
   2.444 +                        if (current != null) {
   2.445 +                            parsed.add(current + " "
   2.446 +                                    + element.replaceAll("\"", "")); // end
   2.447 +                            current = null;
   2.448 +                        } else {
   2.449 +                            current = element.replaceAll("\"", ""); // start
   2.450 +                        }
   2.451 +                    } else if (current != null) {
   2.452 +                        current += " " + element.replaceAll("\"", "");
   2.453 +                    } else {
   2.454 +                        parsed.add(element.replaceAll("\"", ""));
   2.455 +                    }
   2.456 +                }
   2.457 +
   2.458 +                // TODO: actually this is not quite right: We have an open quote
   2.459 +                // somewhere. Exception maybe?
   2.460 +                if (current != null) {
   2.461 +                    parsed.add(current.replaceAll("\"", ""));
   2.462 +                }
   2.463 +                return parsed.toArray(new String[] {});
   2.464 +            }
   2.465 +        }
   2.466 +        return new String[] {};
   2.467 +    }
   2.468 +
   2.469 +    protected static int count(final String sourceString, final char lookFor) {
   2.470 +        if (sourceString == null) {
   2.471 +            return -1;
   2.472 +        }
   2.473 +        int count = 0;
   2.474 +        for (int i = 0; i < sourceString.length(); i++) {
   2.475 +            final char c = sourceString.charAt(i);
   2.476 +            if (c == lookFor) {
   2.477 +                count++;
   2.478 +            }
   2.479 +        }
   2.480 +        return count;
   2.481 +    }
   2.482 +
   2.483 +    public void print(final String output) {
   2.484 +        client.call("print", output);
   2.485 +    }
   2.486 +
   2.487 +    public String getGreeting() {
   2.488 +        return config.greeting;
   2.489 +    }
   2.490 +
   2.491 +    public String getPs() {
   2.492 +        return config.ps;
   2.493 +    }
   2.494 +
   2.495 +    public int getMaxBufferSize() {
   2.496 +        return config.maxBufferSize;
   2.497 +    }
   2.498 +
   2.499 +    public int getRows() {
   2.500 +        return config.rows;
   2.501 +    }
   2.502 +
   2.503 +    public void setGreeting(final String greeting) {
   2.504 +        config.greeting = greeting;
   2.505 +        client.call("setGreeting", greeting);
   2.506 +    }
   2.507 +
   2.508 +    public void setPs(final String ps) {
   2.509 +        config.ps = ps == null ? DEFAULT_PS : ps;
   2.510 +        client.call("setPs", config.ps);
   2.511 +    }
   2.512 +
   2.513 +    public void setMaxBufferSize(final int lines) {
   2.514 +        config.maxBufferSize = lines > 0 ? lines : 0;
   2.515 +        client.call("setMaxBufferSize", config.maxBufferSize);
   2.516 +    }
   2.517 +
   2.518 +    public void setRows(final int rows) {
   2.519 +        config.rows = rows;
   2.520 +        if (config.rows < 1) {
   2.521 +            config.rows = 1;
   2.522 +        }
   2.523 +        if (config.rows > MAX_ROWS) {
   2.524 +            config.rows = MAX_ROWS;
   2.525 +        }
   2.526 +        client.call("setRows", rows);
   2.527 +    }
   2.528 +
   2.529 +    public int getCols() {
   2.530 +        return config.cols;
   2.531 +    }
   2.532 +
   2.533 +    public void setCols(final int cols) {
   2.534 +        config.cols = cols;
   2.535 +        if (config.cols < 1) {
   2.536 +            config.cols = 1;
   2.537 +        }
   2.538 +        if (config.cols > MAX_COLS) {
   2.539 +            config.cols = MAX_COLS;
   2.540 +        }
   2.541 +        client.call("setCols", config.cols);
   2.542 +    }
   2.543 +
   2.544 +    public void prompt() {
   2.545 +        client.call("prompt");
   2.546 +    }
   2.547 +
   2.548 +    public void prompt(final String initialInput) {
   2.549 +        client.call("prompt", initialInput);
   2.550 +    }
   2.551 +
   2.552 +    public void println(final String string) {
   2.553 +        client.call("println", string);
   2.554 +    }
   2.555 +
   2.556 +    public void newLine() {
   2.557 +        client.call("newLine");
   2.558 +    }
   2.559 +
   2.560 +    public void reset() {
   2.561 +        client.call("reset");
   2.562 +    }
   2.563 +
   2.564 +    public void clear() {
   2.565 +        formFeed();
   2.566 +    }
   2.567 +
   2.568 +    public void formFeed() {
   2.569 +        client.call("ff");
   2.570 +    }
   2.571 +
   2.572 +    public void carriageReturn() {
   2.573 +        client.call("cr");
   2.574 +    }
   2.575 +
   2.576 +    public void lineFeed() {
   2.577 +        client.call("lf");
   2.578 +    }
   2.579 +
   2.580 +    public void clearCommandHistory() {
   2.581 +        client.call("clearHistory");
   2.582 +    }
   2.583 +
   2.584 +    public void clearBuffer() {
   2.585 +        client.call("clearBuffer");
   2.586 +    }
   2.587 +
   2.588 +    public void scrollToEnd() {
   2.589 +        client.call("scrollToEnd");
   2.590 +    }
   2.591 +
   2.592 +    /**
   2.593 +     * Gets the Tabulator index of this Focusable component.
   2.594 +     *
   2.595 +     * @see com.vaadin.ui.Component.Focusable#getTabIndex()
   2.596 +     */
   2.597 +    public int getTabIndex() {
   2.598 +        return tabIndex;
   2.599 +    }
   2.600 +
   2.601 +    /**
   2.602 +     * Sets the Tabulator index of this Focusable component.
   2.603 +     *
   2.604 +     * @see com.vaadin.ui.Component.Focusable#setTabIndex(int)
   2.605 +     */
   2.606 +    public void setTabIndex(final int tabIndex) {
   2.607 +        this.tabIndex = tabIndex;
   2.608 +    }
   2.609 +
   2.610 +    /**
   2.611 +     * {@inheritDoc}
   2.612 +     */
   2.613 +    @Override
   2.614 +    public void focus() {
   2.615 +        super.focus();
   2.616 +    }
   2.617 +
   2.618 +    /* PrintStream implementation for console output. */
   2.619 +
   2.620 +    public PrintStream getPrintStream() {
   2.621 +        if (printStream == null) {
   2.622 +            printStream = new PrintStream(new OutputStream() {
   2.623 +
   2.624 +                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
   2.625 +
   2.626 +                @Override
   2.627 +                public void write(final int b) throws IOException {
   2.628 +                    buffer.write(b);
   2.629 +                    // Line buffering
   2.630 +                    if (13 == b) {
   2.631 +                        flush();
   2.632 +                    }
   2.633 +                }
   2.634 +
   2.635 +                @Override
   2.636 +                public void flush() throws IOException {
   2.637 +                    super.flush();
   2.638 +                    buffer.flush();
   2.639 +                    Console.this.print(buffer.toString());
   2.640 +                    buffer.reset();
   2.641 +                }
   2.642 +            }, true);
   2.643 +        }
   2.644 +        return printStream;
   2.645 +    }
   2.646 +
   2.647 +    /* Generic command handling */
   2.648 +
   2.649 +    /**
   2.650 +     * Add a Command to this Console.
   2.651 +     *
   2.652 +     * This will override the any commands of the same name available via
   2.653 +     * {@link CommandProvider}.
   2.654 +     */
   2.655 +    public void addCommand(final String name, final Command cmd) {
   2.656 +        commands.put(name, cmd);
   2.657 +    }
   2.658 +
   2.659 +    /**
   2.660 +     * Remove a command from this console.
   2.661 +     *
   2.662 +     * This does not remove Command available from {@link CommandProvider}.
   2.663 +     *
   2.664 +     * @param cmdName
   2.665 +     */
   2.666 +    public void removeCommand(final String cmdName) {
   2.667 +        commands.remove(cmdName);
   2.668 +    }
   2.669 +
   2.670 +    /**
   2.671 +     * Get a Command by its name.
   2.672 +     *
   2.673 +     * @param cmdName
   2.674 +     * @return
   2.675 +     */
   2.676 +    public Command getCommand(final String cmdName) {
   2.677 +
   2.678 +        // Try directly registered command first
   2.679 +        Command cmd = commands.get(cmdName);
   2.680 +        if (cmd != null) {
   2.681 +            return cmd;
   2.682 +        }
   2.683 +
   2.684 +        // Ask from the providers
   2.685 +        if (commandProviders != null) {
   2.686 +            for (final CommandProvider cp : commandProviders) {
   2.687 +                cmd = cp.getCommand(this, cmdName);
   2.688 +                if (cmd != null) {
   2.689 +                    return cmd;
   2.690 +                }
   2.691 +            }
   2.692 +        }
   2.693 +
   2.694 +        // Not found
   2.695 +        return null;
   2.696 +    }
   2.697 +
   2.698 +    /**
   2.699 +     * Get the current Console Handler.
   2.700 +     *
   2.701 +     * @return
   2.702 +     */
   2.703 +    public Handler getHandler() {
   2.704 +        return handler;
   2.705 +    }
   2.706 +
   2.707 +    /**
   2.708 +     * Set the handler for this console.
   2.709 +     *
   2.710 +     * @see Handler
   2.711 +     * @param handler
   2.712 +     */
   2.713 +    public void setHandler(final Handler handler) {
   2.714 +        this.handler = handler != null ? handler : new DefaultConsoleHandler();
   2.715 +    }
   2.716 +
   2.717 +    /**
   2.718 +     * Get map of available commands in this Console.
   2.719 +     *
   2.720 +     * @return
   2.721 +     */
   2.722 +    public Set<String> getCommands() {
   2.723 +        final Set<String> res = new HashSet<String>();
   2.724 +        if (commandProviders != null) {
   2.725 +            for (final CommandProvider cp : commandProviders) {
   2.726 +                res.addAll(cp.getAvailableCommands(this));
   2.727 +            }
   2.728 +        }
   2.729 +        res.addAll(commands.keySet());
   2.730 +        return Collections.unmodifiableSet(res);
   2.731 +    }
   2.732 +
   2.733 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/main/java/org/vaadin/console/ConsoleWidgetset.gwt.xml	Sun May 15 17:46:06 2011 +0400
     3.3 @@ -0,0 +1,26 @@
     3.4 +<?xml version="1.0" encoding="UTF-8"?>
     3.5 +<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 1.7.0//EN" "http://google-web-toolkit.googlecode.com/svn/tags/1.7.0/distro-source/core/src/gwt-module.dtd">
     3.6 +<module>
     3.7 +	<inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" />
     3.8 +	
     3.9 +	
    3.10 +    <!--
    3.11 +     Uncomment the following to compile the widgetset for one browser only.
    3.12 +     This can reduce the GWT compilation time significantly when debugging.
    3.13 +     The line should be commented out before deployment to production
    3.14 +     environments.
    3.15 +      
    3.16 +     Multiple browsers can be specified for GWT 1.7 as a comma separated
    3.17 +     list. The supported user agents at the moment of writing were:
    3.18 +     ie6,ie8,gecko,gecko1_8,safari,opera
    3.19 +     
    3.20 +     The value gecko1_8 is used for Firefox 3 and later and safari is used for
    3.21 +     webkit based browsers including Google Chrome.
    3.22 +    -->
    3.23 +    <stylesheet src="console/styles.css"/>
    3.24 +    <!-- 
    3.25 +    <set-property name="user.agent" value="safari"/>
    3.26 + -->
    3.27 +
    3.28 +    <inherits name="org.vaadin.rpc.WidgetRPC" />
    3.29 +</module>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/main/java/org/vaadin/console/DefaultConsoleHandler.java	Sun May 15 17:46:06 2011 +0400
     4.3 @@ -0,0 +1,48 @@
     4.4 +package org.vaadin.console;
     4.5 +
     4.6 +import java.util.HashSet;
     4.7 +import java.util.Set;
     4.8 +
     4.9 +import org.vaadin.console.Console.Command;
    4.10 +import org.vaadin.console.Console.Handler;
    4.11 +
    4.12 +/**
    4.13 + * Default handler for console.
    4.14 + * 
    4.15 + */
    4.16 +public class DefaultConsoleHandler implements Handler {
    4.17 +
    4.18 +    private static final long serialVersionUID = 1L;
    4.19 +
    4.20 +    public void handleException(final Console console, final Exception e,
    4.21 +            final Command cmd, final String[] argv) {
    4.22 +        e.printStackTrace();
    4.23 +        console.println(e.getClass().getSimpleName() + ": " + e.getMessage());
    4.24 +    }
    4.25 +
    4.26 +    public Set<String> getSuggestions(final Console console, final String input) {
    4.27 +
    4.28 +        final String prefix = console.parseCommandPrefix(input);
    4.29 +        if (prefix != null) {
    4.30 +            final Set<String> matches = new HashSet<String>();
    4.31 +            final Set<String> cmds = console.getCommands();
    4.32 +            for (final String cmd : cmds) {
    4.33 +                if (cmd.startsWith(prefix)) {
    4.34 +                    matches.add(cmd);
    4.35 +                }
    4.36 +            }
    4.37 +            return matches;
    4.38 +        }
    4.39 +        return null;
    4.40 +    }
    4.41 +
    4.42 +    public void inputReceived(final Console console, final String lastInput) {
    4.43 +        console.parseAndExecuteCommand(lastInput);
    4.44 +        console.prompt();
    4.45 +    }
    4.46 +
    4.47 +    public void commandNotFound(final Console console, final String[] argv) {
    4.48 +        console.print("ERROR: " + argv[0] + ": command not found.");
    4.49 +    }
    4.50 +
    4.51 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/main/java/org/vaadin/console/ObjectInspector.java	Sun May 15 17:46:06 2011 +0400
     5.3 @@ -0,0 +1,420 @@
     5.4 +package org.vaadin.console;
     5.5 +
     5.6 +import java.beans.BeanInfo;
     5.7 +import java.beans.Introspector;
     5.8 +import java.beans.PropertyDescriptor;
     5.9 +import java.io.Serializable;
    5.10 +import java.lang.reflect.Field;
    5.11 +import java.lang.reflect.InvocationTargetException;
    5.12 +import java.lang.reflect.Method;
    5.13 +import java.util.ArrayList;
    5.14 +import java.util.Arrays;
    5.15 +import java.util.Collections;
    5.16 +import java.util.HashMap;
    5.17 +import java.util.HashSet;
    5.18 +import java.util.LinkedHashMap;
    5.19 +import java.util.LinkedHashSet;
    5.20 +import java.util.List;
    5.21 +import java.util.Map;
    5.22 +import java.util.Set;
    5.23 +
    5.24 +import org.vaadin.console.Console.Command;
    5.25 +
    5.26 +import com.vaadin.ui.Component;
    5.27 +
    5.28 +/**
    5.29 + * Java object inspector.
    5.30 + *
    5.31 + * With object inspector you can simply wire methods from a class as commands to
    5.32 + * the Console.
    5.33 + *
    5.34 + * @author Sami Ekblad
    5.35 + *
    5.36 + */
    5.37 +public class ObjectInspector implements Serializable, Console.CommandProvider {
    5.38 +    private static final long serialVersionUID = -5001688079827306472L;
    5.39 +    private static final List<String> OBJECT_BLACKLIST = Arrays
    5.40 +            .asList(new String[] { "equals", "class", "hashCode", "notify",
    5.41 +                    "notifyAll", "toString", "wait" });
    5.42 +    private static final List<String> VAADIN_BLACKLIST = Arrays
    5.43 +            .asList(new String[] { "addListener", "attach", "application",
    5.44 +                    "changeVariables", "childRequestedRepaint",
    5.45 +                    "componentError", "detach", "handleError", "paint",
    5.46 +                    "paintContent", "removeListener", "requestRepaint",
    5.47 +                    "requestRepaintRequests", "style", "tag" });
    5.48 +
    5.49 +    private Object theObject;
    5.50 +    private final Map<String, Caller> commands = new HashMap<String, Caller>();
    5.51 +    private Set<String> ignoredCommands = new HashSet<String>();
    5.52 +
    5.53 +    public ObjectInspector(final Object obj) {
    5.54 +
    5.55 +        // Default ignores
    5.56 +        ignoredCommands.addAll(OBJECT_BLACKLIST);
    5.57 +        if (obj instanceof Component) {
    5.58 +            ignoredCommands.addAll(VAADIN_BLACKLIST);
    5.59 +        }
    5.60 +
    5.61 +        // Create bean information
    5.62 +        setObject(obj);
    5.63 +
    5.64 +    }
    5.65 +
    5.66 +    private void setObject(final Object c) {
    5.67 +        theObject = c;
    5.68 +        listBeanPropertyCommands();
    5.69 +        listMethodCommands();
    5.70 +    }
    5.71 +
    5.72 +    public Set<String> getAvailableCommands() {
    5.73 +        final List<String> l = new ArrayList<String>();
    5.74 +        l.addAll(commands.keySet());
    5.75 +        Collections.sort(l);
    5.76 +        return new LinkedHashSet<String>(l);
    5.77 +    }
    5.78 +
    5.79 +
    5.80 +
    5.81 +    private void listMethodCommands() {
    5.82 +
    5.83 +        final Method[] methods = theObject.getClass().getMethods();
    5.84 +        for (final Method method : methods) {
    5.85 +            final Method m = method;
    5.86 +            if (!isBeanGetter(m) && !isBeanSetter(m)) {
    5.87 +
    5.88 +                String un = m.getName();
    5.89 +                if (isIgnored(un)
    5.90 +                        || !isParamTypesOkForConsole(m.getParameterTypes())) {
    5.91 +                    continue;
    5.92 +                }
    5.93 +
    5.94 +                // Make unique. Try param names first.
    5.95 +                if (commands.containsKey(un)) {
    5.96 +                    un += paramsToShortString(m.getParameterTypes());
    5.97 +                }
    5.98 +
    5.99 +                // Fallback to appending number
   5.100 +                int j = 1;
   5.101 +                while (commands.containsKey(un)) {
   5.102 +                    un = m.getName() + (j++);
   5.103 +                }
   5.104 +
   5.105 +                final Caller cmd = m.getParameterTypes().length == 0 ? new Caller(theObject,
   5.106 +                        m.getName(), null, m.getParameterTypes()) : new Caller(theObject,
   5.107 +                        null, m.getName(), m.getParameterTypes());
   5.108 +                commands.put(un, cmd);
   5.109 +            }
   5.110 +        }
   5.111 +    }
   5.112 +
   5.113 +    private String paramsToShortString(final Class<?>[] parameterTypes) {
   5.114 +        StringBuilder s = new StringBuilder();
   5.115 +        if (parameterTypes != null) {
   5.116 +            for (final Class<?> c : parameterTypes) {
   5.117 +                s.append(c.getSimpleName().substring(0, 3));
   5.118 +            }
   5.119 +        }
   5.120 +        return s.toString();
   5.121 +    }
   5.122 +
   5.123 +    private boolean isBeanSetter(final Method m) {
   5.124 +        if (m.getName().startsWith("set")) {
   5.125 +            Method setMethod = null;
   5.126 +            try {
   5.127 +                final String n = "g" + m.getName().substring(1);
   5.128 +                setMethod = m.getDeclaringClass().getMethod(n);
   5.129 +            } catch (final SecurityException e) {
   5.130 +            } catch (final NoSuchMethodException e) {
   5.131 +            }
   5.132 +            if (setMethod == null) {
   5.133 +                try {
   5.134 +                    final String n = "is" + m.getName().substring(3);
   5.135 +                    setMethod = m.getDeclaringClass().getMethod(n);
   5.136 +                } catch (final SecurityException e) {
   5.137 +                } catch (final NoSuchMethodException e) {
   5.138 +                }
   5.139 +            }
   5.140 +            return setMethod != null;
   5.141 +        }
   5.142 +        return false;
   5.143 +    }
   5.144 +
   5.145 +    private boolean isBeanGetter(final Method m) {
   5.146 +        final String n = m.getName();
   5.147 +        return (n.startsWith("is") && n.length() > 2)
   5.148 +                || (n.startsWith("get") && n.length() > 2);
   5.149 +    }
   5.150 +
   5.151 +    /**
   5.152 +     * <p>
   5.153 +     * Perform introspection on a Java Bean class to find its properties.
   5.154 +     * </p>
   5.155 +     *
   5.156 +     * <p>
   5.157 +     * Note : This version only supports introspectable bean properties and
   5.158 +     * their getter and setter methods. Stand-alone <code>is</code> and
   5.159 +     * <code>are</code> methods are not supported.
   5.160 +     * </p>
   5.161 +     *
   5.162 +     * @param beanClass
   5.163 +     *            the Java Bean class to get properties for.
   5.164 +     * @return an ordered map from property names to property descriptors
   5.165 +     */
   5.166 +    static LinkedHashMap<String, PropertyDescriptor> getPropertyDescriptors(
   5.167 +            final Class<?> beanClass) {
   5.168 +        final LinkedHashMap<String, PropertyDescriptor> pdMap = new LinkedHashMap<String, PropertyDescriptor>();
   5.169 +
   5.170 +        // Try to introspect, if it fails, we just have an empty Item
   5.171 +        try {
   5.172 +            final BeanInfo info = Introspector.getBeanInfo(beanClass);
   5.173 +            final PropertyDescriptor[] pds = info.getPropertyDescriptors();
   5.174 +
   5.175 +            // Add all the bean properties as MethodProperties to this Item
   5.176 +            for (final PropertyDescriptor pd : pds) {
   5.177 +                final Method getMethod = pd.getReadMethod();
   5.178 +                if ((getMethod != null)
   5.179 +                        && getMethod.getDeclaringClass() != Object.class) {
   5.180 +                    pdMap.put(pd.getName(), pd);
   5.181 +                }
   5.182 +            }
   5.183 +        } catch (final java.beans.IntrospectionException ignored) {
   5.184 +        }
   5.185 +
   5.186 +        return pdMap;
   5.187 +    }
   5.188 +
   5.189 +    /**
   5.190 +     * List commands for the theObject.
   5.191 +     *
   5.192 +     * @return
   5.193 +     */
   5.194 +    private void listBeanPropertyCommands() {
   5.195 +
   5.196 +        final LinkedHashMap<String, PropertyDescriptor> beanProperties = getPropertyDescriptors(theObject
   5.197 +                .getClass());
   5.198 +        // bean properties
   5.199 +        for (final PropertyDescriptor p : beanProperties.values()) {
   5.200 +
   5.201 +            // Make unique
   5.202 +            final String name = p.getName();
   5.203 +            if (isIgnored(name)) {
   5.204 +                continue;
   5.205 +            }
   5.206 +
   5.207 +            commands.put(name,
   5.208 +                    new Caller(theObject,p.getReadMethod().getName(),
   5.209 +                            p.getWriteMethod() != null ? p.getWriteMethod()
   5.210 +                                    .getName() : null,
   5.211 +                            p.getWriteMethod() != null ? p.getWriteMethod()
   5.212 +                                    .getParameterTypes() : null));
   5.213 +
   5.214 +            // beanCommands.put(un, p);
   5.215 +        }
   5.216 +    }
   5.217 +
   5.218 +    public static boolean isParamTypesOkForConsole(final Class<?>[] cls) {
   5.219 +        if (cls == null) {
   5.220 +            return true;
   5.221 +        }
   5.222 +        for (int i = 0; i < cls.length; i++) {
   5.223 +            if (!isParamTypeOkForConsole(cls[i])) {
   5.224 +                return false;
   5.225 +            }
   5.226 +        }
   5.227 +        return true;
   5.228 +    }
   5.229 +
   5.230 +    public static boolean isParamTypeOkForConsole(final Class<?> cls) {
   5.231 +        return cls.isEnum() || cls == Boolean.class || cls == boolean.class
   5.232 +                || cls == long.class || cls == Long.class || cls == int.class
   5.233 +                || cls == Integer.class || cls == byte.class
   5.234 +                || cls == Byte.class || cls == float.class
   5.235 +                || cls == Float.class || cls == double.class
   5.236 +                || cls == Double.class || cls == String.class;
   5.237 +    }
   5.238 +
   5.239 +    public boolean isIgnored(final String commandName) {
   5.240 +        return getIgnoredCommands().contains(commandName);
   5.241 +    }
   5.242 +
   5.243 +    protected static Object[] argvToParams(final String[] argv,
   5.244 +            final Class<?>[] pt) {
   5.245 +        if (pt.length != argv.length - 1) {
   5.246 +            throw new IllegalArgumentException("Invalid number of parameters");
   5.247 +        }
   5.248 +        final Object[] args = new Object[argv.length - 1];
   5.249 +        for (int j = 1; j < argv.length; j++) {
   5.250 +            if (pt[j - 1] == String.class) {
   5.251 +                args[j - 1] = argv[j];
   5.252 +            } else if (pt[j - 1] == Byte.class || pt[j - 1] == byte.class) {
   5.253 +                args[j - 1] = Byte.parseByte(argv[j]);
   5.254 +            } else if (pt[j - 1] == Character.class || pt[j - 1] == char.class) {
   5.255 +                args[j - 1] = argv[j].charAt(0);
   5.256 +            } else if (pt[j - 1] == Long.class || pt[j - 1] == long.class) {
   5.257 +                args[j - 1] = Long.parseLong(argv[j]);
   5.258 +            } else if (pt[j - 1] == Integer.class || pt[j - 1] == int.class) {
   5.259 +                args[j - 1] = Integer.parseInt(argv[j]);
   5.260 +            } else if (pt[j - 1] == Boolean.class || pt[j - 1] == boolean.class) {
   5.261 +                args[j - 1] = Boolean.parseBoolean(argv[j]);
   5.262 +            } else if (pt[j - 1] == Float.class || pt[j - 1] == float.class) {
   5.263 +                args[j - 1] = Float.parseFloat(argv[j]);
   5.264 +            } else if (pt[j - 1] == Double.class || pt[j - 1] == double.class) {
   5.265 +                args[j - 1] = Float.parseFloat(argv[j]);
   5.266 +            } else if (pt[j - 1].isEnum()) {
   5.267 +                Field e;
   5.268 +                try {
   5.269 +                    e = pt[j - 1].getDeclaredField(argv[j].toUpperCase());
   5.270 +                    args[j - 1] = e.get(null);
   5.271 +                } catch (final Exception e1) {
   5.272 +                    throw new IllegalArgumentException("Enum not found: "
   5.273 +                            + argv[j].toUpperCase(), e1);
   5.274 +                }
   5.275 +            }
   5.276 +        }
   5.277 +        return args;
   5.278 +    }
   5.279 +
   5.280 +    public Class<?>[] getCommandParams(final String method) {
   5.281 +        if (commands.containsKey(method)) {
   5.282 +            final Caller m = commands.get(method);
   5.283 +            return m.getParameterTypes() != null ? m.getParameterTypes()
   5.284 +                    : new Class<?>[] {};
   5.285 +        }
   5.286 +        return new Class<?>[] {};
   5.287 +    }
   5.288 +
   5.289 +    public void setIgnoredCommands(final Set<String> ignoredCommands) {
   5.290 +        this.ignoredCommands = ignoredCommands;
   5.291 +    }
   5.292 +
   5.293 +    public Set<String> getIgnoredCommands() {
   5.294 +        return ignoredCommands;
   5.295 +    }
   5.296 +
   5.297 +    /**
   5.298 +     * Method wrapper that serializes nicely.
   5.299 +     *
   5.300 +     */
   5.301 +    private static class Caller implements Console.Command, Serializable {
   5.302 +
   5.303 +        private static final long serialVersionUID = -810707579200844512L;
   5.304 +
   5.305 +        private final Object theObject;
   5.306 +        private final String readMethod;
   5.307 +        private final String writeMethod;
   5.308 +        private final Class<?>[] paramTypes;
   5.309 +
   5.310 +        transient private Method rm;
   5.311 +        transient private Method wm;
   5.312 +
   5.313 +        private Caller(final Object obj, final String read, final String write,
   5.314 +                final Class<?>[] params) {
   5.315 +            theObject = obj;
   5.316 +            readMethod = read;
   5.317 +            writeMethod = write;
   5.318 +            paramTypes = params;
   5.319 +        }
   5.320 +
   5.321 +        private boolean isWritable() {
   5.322 +            return writeMethod != null && paramTypes != null
   5.323 +                    && paramTypes.length > 0;
   5.324 +        }
   5.325 +
   5.326 +        public boolean isReadable() {
   5.327 +            return readMethod != null;
   5.328 +        }
   5.329 +
   5.330 +        public Object write(final Object[] params) throws SecurityException,
   5.331 +                NoSuchMethodException, IllegalArgumentException,
   5.332 +                IllegalAccessException, InvocationTargetException {
   5.333 +            if (wm == null) {
   5.334 +                wm = theObject.getClass().getMethod(writeMethod, paramTypes);
   5.335 +            }
   5.336 +            return wm.invoke(theObject, params);
   5.337 +        }
   5.338 +
   5.339 +        public Object read() throws SecurityException, NoSuchMethodException,
   5.340 +                IllegalArgumentException, IllegalAccessException,
   5.341 +                InvocationTargetException {
   5.342 +            if (rm == null) {
   5.343 +                rm = theObject.getClass().getMethod(readMethod,
   5.344 +                        new Class<?>[] {});
   5.345 +            }
   5.346 +            return rm.invoke(theObject);
   5.347 +        }
   5.348 +
   5.349 +        public Object write(final String[] argv) throws SecurityException,
   5.350 +                NoSuchMethodException, IllegalArgumentException,
   5.351 +                IllegalAccessException, InvocationTargetException {
   5.352 +            return write(parseWriteParams(argv));
   5.353 +        }
   5.354 +
   5.355 +        private Class<?>[] getParameterTypes() {
   5.356 +            return paramTypes;
   5.357 +        }
   5.358 +
   5.359 +        private Object[] parseWriteParams(final String[] argv)
   5.360 +                throws SecurityException, NoSuchMethodException {
   5.361 +            if (wm == null) {
   5.362 +                wm = theObject.getClass().getMethod(writeMethod, paramTypes);
   5.363 +            }
   5.364 +            return argvToParams(argv, wm.getParameterTypes());
   5.365 +        }
   5.366 +
   5.367 +        public Object execute(final Console console, final String[] argv)
   5.368 +                throws Exception {
   5.369 +//            public Object execute(final String[] argv) throws Exception {
   5.370 +
   5.371 +                if (argv == null || argv.length < 1) {
   5.372 +                    throw new IllegalArgumentException("Missing command");
   5.373 +                }
   5.374 +
   5.375 +                if (argv.length > 1
   5.376 +                        && !isParamTypesOkForConsole(getParameterTypes())) {
   5.377 +                    throw new IllegalArgumentException("Unsupported parameter types");
   5.378 +                }
   5.379 +
   5.380 +                if (argv.length == 1 && isReadable()) {
   5.381 +                    // Read
   5.382 +                    return read();
   5.383 +                } else if (isWritable()) {
   5.384 +                    // Write
   5.385 +                    if (isReadable()) {
   5.386 +                        write(argv);
   5.387 +                        return read(); // Return the read method instead
   5.388 +                    } else {
   5.389 +                        return write(argv); // return whatever is returned
   5.390 +                    }
   5.391 +
   5.392 +                }
   5.393 +
   5.394 +                return null;
   5.395 +            }
   5.396 +        public String getUsage(final Console console, final String[] argv) {
   5.397 +            return null;
   5.398 +        }
   5.399 +    }
   5.400 +
   5.401 +    public String getCommandUsage(final String[] argv) {
   5.402 +        return argv[0] + " " + paramsToString(getCommandParams(argv[0]));
   5.403 +    }
   5.404 +
   5.405 +    private static String paramsToString(final Class<?>[] paramTypes) {
   5.406 +        StringBuilder res = new StringBuilder();
   5.407 +        if (paramTypes != null) {
   5.408 +            for (final Class<?> paramType : paramTypes) {
   5.409 +                res.append("<" + paramType.getSimpleName() + "> ");
   5.410 +            }
   5.411 +        }
   5.412 +        return res.toString();
   5.413 +    }
   5.414 +
   5.415 +    public Set<String> getAvailableCommands(final Console console) {
   5.416 +        return getAvailableCommands();
   5.417 +    }
   5.418 +
   5.419 +    public Command getCommand(final Console console, final String commandName) {
   5.420 +        return commands.get(commandName);
   5.421 +    }
   5.422 +
   5.423 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/main/java/org/vaadin/console/client/ui/TextConsole.java	Sun May 15 17:46:06 2011 +0400
     6.3 @@ -0,0 +1,781 @@
     6.4 +package org.vaadin.console.client.ui;
     6.5 +
     6.6 +import java.util.ArrayList;
     6.7 +import java.util.List;
     6.8 +
     6.9 +import com.google.gwt.dom.client.DivElement;
    6.10 +import com.google.gwt.dom.client.Document;
    6.11 +import com.google.gwt.dom.client.Element;
    6.12 +import com.google.gwt.dom.client.InputElement;
    6.13 +import com.google.gwt.dom.client.Node;
    6.14 +import com.google.gwt.dom.client.Style.Display;
    6.15 +import com.google.gwt.dom.client.Style.Unit;
    6.16 +import com.google.gwt.dom.client.TableCellElement;
    6.17 +import com.google.gwt.dom.client.TableElement;
    6.18 +import com.google.gwt.dom.client.TableRowElement;
    6.19 +import com.google.gwt.dom.client.TableSectionElement;
    6.20 +import com.google.gwt.event.dom.client.ClickEvent;
    6.21 +import com.google.gwt.event.dom.client.ClickHandler;
    6.22 +import com.google.gwt.event.dom.client.KeyCodes;
    6.23 +import com.google.gwt.event.dom.client.KeyDownEvent;
    6.24 +import com.google.gwt.event.dom.client.KeyDownHandler;
    6.25 +import com.google.gwt.event.shared.HandlerRegistration;
    6.26 +import com.google.gwt.user.client.Timer;
    6.27 +import com.google.gwt.user.client.ui.FocusWidget;
    6.28 +import com.vaadin.terminal.gwt.client.Util;
    6.29 +
    6.30 +/**
    6.31 + * GWT Console Widget.
    6.32 + *
    6.33 + * @author Sami Ekblad / Vaadin
    6.34 + *
    6.35 + */
    6.36 +public class TextConsole extends FocusWidget {
    6.37 +
    6.38 +    /* Control characters in http://en.wikipedia.org/wiki/Control_character */
    6.39 +
    6.40 +    public static final char CTRL_BELL = 'G';
    6.41 +    public static final char CTRL_BACKSPACE = 'H';
    6.42 +    public static final char CTRL_TAB = 'I';
    6.43 +    public static final char CTRL_LINE_FEED = 'J';
    6.44 +    public static final char CTRL_FORM_FEED = 'L';
    6.45 +    public static final char CTRL_CARRIAGE_RETURN = 'M';
    6.46 +    public static final char CTRL_ESCAPE = '[';
    6.47 +    public static final char CTRL_DELETE = '?';
    6.48 +
    6.49 +    private static final char[] CTRL = { CTRL_BELL, CTRL_BACKSPACE, CTRL_TAB,
    6.50 +            CTRL_LINE_FEED, CTRL_FORM_FEED, CTRL_CARRIAGE_RETURN, CTRL_ESCAPE,
    6.51 +            CTRL_DELETE };
    6.52 +
    6.53 +    public static char getControlKey(final int kc) {
    6.54 +        for (final char c : CTRL) {
    6.55 +            if (kc == c) {
    6.56 +                return c;
    6.57 +            }
    6.58 +        }
    6.59 +        return 0;
    6.60 +    }
    6.61 +
    6.62 +    private static final String DEFAULT_TABS = "    ";
    6.63 +    private static final int BIG_NUMBER = 100000;
    6.64 +    private final DivElement term;
    6.65 +    private TextConsoleConfig config;
    6.66 +    private TextConsoleHandler handler;
    6.67 +    private final Element buffer;
    6.68 +    private final TableElement prompt;
    6.69 +    private final Element ps;
    6.70 +    private final InputElement input;
    6.71 +    private List<String> cmdHistory = new ArrayList<String>();
    6.72 +    private int cmdHistoryIndex = -1;
    6.73 +    private final HandlerRegistration clickHandler;
    6.74 +    private final HandlerRegistration keyHandler;
    6.75 +    private HandlerRegistration focusHandler;
    6.76 +    private int fontW = -1;
    6.77 +    private int fontH = -1;
    6.78 +    private int scrollbarW = -1;
    6.79 +    private int rows;
    6.80 +    private int cols;
    6.81 +    private String tabs = DEFAULT_TABS;
    6.82 +    private boolean focused;
    6.83 +    private int promptRows;
    6.84 +    private int padding;
    6.85 +    private final DivElement promptWrap;
    6.86 +    private Timer timer;
    6.87 +    private int maxBufferSize;
    6.88 +    private String cleanPs;
    6.89 +    private int paddingW;
    6.90 +
    6.91 +    public TextConsole() {
    6.92 +
    6.93 +        // Main element
    6.94 +        term = Document.get().createDivElement();
    6.95 +        term.addClassName("term");
    6.96 +        setElement(term);
    6.97 +        setTabIndex(0);
    6.98 +
    6.99 +        // Buffer
   6.100 +        buffer = Document.get().createElement("pre");
   6.101 +        buffer.addClassName("b");
   6.102 +        term.appendChild(buffer);
   6.103 +
   6.104 +        // Prompt elements
   6.105 +        promptWrap = Document.get().createDivElement();
   6.106 +        promptWrap.addClassName("pw");
   6.107 +        term.appendChild(promptWrap);
   6.108 +
   6.109 +        prompt = Document.get().createTableElement();
   6.110 +        promptWrap.appendChild(prompt);
   6.111 +        prompt.setAttribute("cellpadding", "0");
   6.112 +        prompt.setAttribute("cellspacing", "0");
   6.113 +        prompt.setAttribute("border", "0");
   6.114 +        prompt.addClassName("p");
   6.115 +
   6.116 +        final TableSectionElement tbody = Document.get().createTBodyElement();
   6.117 +        prompt.appendChild(tbody);
   6.118 +
   6.119 +        final TableRowElement tr = Document.get().createTRElement();
   6.120 +        tbody.appendChild(tr);
   6.121 +
   6.122 +        final TableCellElement psTd = Document.get().createTDElement();
   6.123 +        psTd.addClassName("psw");
   6.124 +        tr.appendChild(psTd);
   6.125 +
   6.126 +        ps = Document.get().createElement("nobr");
   6.127 +        ps.addClassName("ps");
   6.128 +        psTd.appendChild(ps);
   6.129 +
   6.130 +        final TableCellElement inputTd = Document.get().createTDElement();
   6.131 +        inputTd.addClassName("iw");
   6.132 +        tr.appendChild(inputTd);
   6.133 +
   6.134 +        input = (InputElement) Document.get().createElement("input");
   6.135 +        inputTd.appendChild(input);
   6.136 +        input.addClassName("i");
   6.137 +        input.setTabIndex(-1);
   6.138 +        input.setAttribute("spellcheck", "false");
   6.139 +
   6.140 +        config = TextConsoleConfig.newInstance();
   6.141 +
   6.142 +        setPromtActive(false);
   6.143 +
   6.144 +        clickHandler = addDomHandler(new ClickHandler() {
   6.145 +
   6.146 +            public void onClick(final ClickEvent event) {
   6.147 +                setFocus(true);
   6.148 +            }
   6.149 +        }, ClickEvent.getType());
   6.150 +
   6.151 +        keyHandler = addDomHandler(new KeyDownHandler() {
   6.152 +
   6.153 +            public void onKeyDown(final KeyDownEvent event) {
   6.154 +
   6.155 +                // (re-)show the prompt
   6.156 +                setPromtActive(true);
   6.157 +
   6.158 +                if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
   6.159 +                    event.preventDefault();
   6.160 +                    carriageReturn();
   6.161 +                } else if (event.getNativeKeyCode() == KeyCodes.KEY_UP
   6.162 +                        || event.getNativeKeyCode() == KeyCodes.KEY_DOWN) {
   6.163 +                    event.preventDefault();
   6.164 +                    handleCommandHistoryBrowse(event.getNativeKeyCode());
   6.165 +                } else if (event.getNativeKeyCode() == KeyCodes.KEY_TAB) {
   6.166 +                    event.preventDefault();
   6.167 +                    suggest();
   6.168 +                } else if (event.getNativeKeyCode() == KeyCodes.KEY_BACKSPACE
   6.169 +                        && getInputLenght() == 0) {
   6.170 +                    bell();
   6.171 +                } else if (event.getNativeEvent().getCtrlKey()) {
   6.172 +                    final char ctrlChar = getControlKey(event.getNativeKeyCode());
   6.173 +                    if (ctrlChar > 0) {
   6.174 +                        event.preventDefault();
   6.175 +                        handleControlChar(ctrlChar);
   6.176 +                    }
   6.177 +                }
   6.178 +
   6.179 +            }
   6.180 +        }, KeyDownEvent.getType());
   6.181 +
   6.182 +        updateFontDimensions();
   6.183 +    }
   6.184 +
   6.185 +    protected int getInputLenght() {
   6.186 +        final String v = input.getValue();
   6.187 +        if (v != null) {
   6.188 +            return v.length();
   6.189 +        }
   6.190 +        return -1;
   6.191 +    }
   6.192 +
   6.193 +    protected void handleControlChar(final char c) {
   6.194 +        switch (c) {
   6.195 +        case TextConsole.CTRL_BACKSPACE:
   6.196 +            backspace();
   6.197 +            break;
   6.198 +        case TextConsole.CTRL_BELL:
   6.199 +            bell();
   6.200 +            break;
   6.201 +        case TextConsole.CTRL_CARRIAGE_RETURN:
   6.202 +            carriageReturn();
   6.203 +            break;
   6.204 +        case TextConsole.CTRL_DELETE:
   6.205 +            bell(); // TODO: not supported yet
   6.206 +            break;
   6.207 +        case TextConsole.CTRL_ESCAPE:
   6.208 +            bell(); // TODO: not supported yet
   6.209 +            break;
   6.210 +        case TextConsole.CTRL_FORM_FEED:
   6.211 +            formFeed();
   6.212 +            break;
   6.213 +        case TextConsole.CTRL_LINE_FEED:
   6.214 +            lineFeed();
   6.215 +            break;
   6.216 +        case TextConsole.CTRL_TAB:
   6.217 +            tab();
   6.218 +            break;
   6.219 +
   6.220 +        default:
   6.221 +            bell();
   6.222 +            break;
   6.223 +        }
   6.224 +    }
   6.225 +
   6.226 +    protected void suggest() {
   6.227 +        // No suggest by default. Implement by subclassing.
   6.228 +    }
   6.229 +
   6.230 +    protected void handleCommandHistoryBrowse(final int i) {
   6.231 +        cmdHistoryIndex = i == KeyCodes.KEY_UP ? cmdHistoryIndex - 1
   6.232 +                : cmdHistoryIndex + 1;
   6.233 +        if (cmdHistoryIndex >= 0 && cmdHistoryIndex < cmdHistory.size()) {
   6.234 +            prompt(cmdHistory.get(cmdHistoryIndex));
   6.235 +        } else {
   6.236 +            prompt();
   6.237 +        }
   6.238 +    }
   6.239 +
   6.240 +    public String getInput() {
   6.241 +        return input.getValue();
   6.242 +    }
   6.243 +
   6.244 +    protected void setInput(final String inputText) {
   6.245 +        if (inputText != null) {
   6.246 +            input.setValue(inputText);
   6.247 +        } else {
   6.248 +            input.setValue("");
   6.249 +        }
   6.250 +        if (isFocused()) {
   6.251 +            focusPrompt();
   6.252 +        }
   6.253 +    }
   6.254 +
   6.255 +    public void lineFeed() {
   6.256 +        carriageReturn();
   6.257 +    }
   6.258 +
   6.259 +    protected void tab() {
   6.260 +        prompt(getInput() + "\t");
   6.261 +    }
   6.262 +
   6.263 +    protected void backspace() {
   6.264 +        bell();
   6.265 +    }
   6.266 +
   6.267 +    protected void carriageReturn() {
   6.268 +        setPromtActive(false);
   6.269 +        // Append newline first if not there yet
   6.270 +        if (!bufferIsEmpty() && !bufferEndsWithNewLine()) {
   6.271 +            newLine();
   6.272 +            reducePrompt(-1);
   6.273 +        }
   6.274 +        print(getCurrentPromptContent());
   6.275 +        newLine();
   6.276 +        if (promptRows > 1) {
   6.277 +            reducePrompt(-1);
   6.278 +        }
   6.279 +        String lineBuffer = getInput();
   6.280 +        lineBuffer = lineBuffer.trim();
   6.281 +        if (!"".equals(lineBuffer)) {
   6.282 +            cmdHistory.add(lineBuffer);
   6.283 +            cmdHistoryIndex = cmdHistory.size();
   6.284 +        }
   6.285 +        if (handler != null) {
   6.286 +            handler.terminalInput(this, lineBuffer);
   6.287 +        }
   6.288 +    }
   6.289 +
   6.290 +    private boolean bufferIsEmpty() {
   6.291 +        return !buffer.hasChildNodes();
   6.292 +    }
   6.293 +
   6.294 +    private void setPromtActive(final boolean active) {
   6.295 +        if (active && !isPromptActive()) {
   6.296 +            prompt.getStyle().setDisplay(Display.BLOCK);
   6.297 +        } else if (!active && isPromptActive()) {
   6.298 +            prompt.getStyle().setDisplay(Display.NONE);
   6.299 +        }
   6.300 +    }
   6.301 +
   6.302 +    private boolean isPromptActive() {
   6.303 +        return !Display.NONE.getCssName()
   6.304 +                .equals(prompt.getStyle().getDisplay());
   6.305 +    }
   6.306 +
   6.307 +    private boolean isFocused() {
   6.308 +        return focused;
   6.309 +    }
   6.310 +
   6.311 +    public void setConfig(final TextConsoleConfig cfg) {
   6.312 +        config = cfg;
   6.313 +
   6.314 +        updateFontDimensions();
   6.315 +
   6.316 +        scrollbarW = getScrollbarWidth();
   6.317 +        final String padStr = term.getStyle().getPadding();
   6.318 +        if (padStr != null && padStr.endsWith("px")) {
   6.319 +            padding = Integer
   6.320 +                    .parseInt(padStr.substring(0, padStr.length() - 2));
   6.321 +        } else {
   6.322 +            // _log("using default padding: 1x2");
   6.323 +            padding = 1;
   6.324 +            paddingW = 2;
   6.325 +        }
   6.326 +
   6.327 +        // _log("setConfig: font=" + fontW + "x" + fontH + ";scrollbar="
   6.328 +        // + scrollbarW + ";cols=" + config.getCols() + ";rows="
   6.329 +        // + config.getRows() + ";size=" + getWidth() + "x" + getHeight());
   6.330 +
   6.331 +        setPs(config.getPs());
   6.332 +        setCols(config.getCols());
   6.333 +        setRows(config.getRows());
   6.334 +        setMaxBufferSize(config.getMaxBufferSize());
   6.335 +    }
   6.336 +
   6.337 +    private void updateFontDimensions() {
   6.338 +
   6.339 +        // Test element for font size
   6.340 +        DivElement test = Document.get().createDivElement();
   6.341 +        test.setAttribute("style",
   6.342 +                "position: absolute;");
   6.343 +        test.setInnerHTML("X");
   6.344 +        term.appendChild(test);
   6.345 +
   6.346 +        fontW = test.getClientWidth();
   6.347 +        fontH = test.getClientHeight();
   6.348 +        if (fontW <= 0 || fontW > 100) {
   6.349 +            fontW = test.getOffsetWidth();
   6.350 +        }
   6.351 +        if (fontH <= 0|| fontH > 100) {
   6.352 +            fontH = test.getOffsetHeight();
   6.353 +        }
   6.354 +        if (fontW <= 0 || fontW > 100) {
   6.355 +            fontW = 1;
   6.356 +        }
   6.357 +        if (fontH <= 0|| fontH > 100) {
   6.358 +            fontH = 1;
   6.359 +        }
   6.360 +        term.removeChild(test);
   6.361 +    }
   6.362 +
   6.363 +    // Debug instrumentation. TODO: Remove.
   6.364 +//    protected void _log(final String string) {
   6.365 +//        ApplicationConnection.getConsole().log(string);
   6.366 +//    }
   6.367 +
   6.368 +    public TextConsoleConfig getConfig() {
   6.369 +        return config;
   6.370 +    }
   6.371 +
   6.372 +    private boolean bufferEndsWithNewLine() {
   6.373 +        final Node last = buffer != null ? buffer.getLastChild() : null;
   6.374 +        // _log("last node: " + (last != null ? last.getNodeName() : "<null>"));
   6.375 +        return last != null && "br".equals(last.getNodeName().toLowerCase());
   6.376 +    }
   6.377 +
   6.378 +    private Node createTextNode(final String text) {
   6.379 +        return Document.get().createTextNode(text);
   6.380 +    }
   6.381 +
   6.382 +    private Node createBr() {
   6.383 +        return Document.get().createBRElement();
   6.384 +    }
   6.385 +
   6.386 +    public void focusPrompt() {
   6.387 +        focusPrompt(-1);
   6.388 +    }
   6.389 +
   6.390 +    public void focusPrompt(final int cursorPos) {
   6.391 +        input.focus();
   6.392 +
   6.393 +        // Focus to end
   6.394 +        final String s = getInput();
   6.395 +        if (s != null && s.length() > 0) {
   6.396 +            setSelectionRange(input, s.length(), s.length());
   6.397 +        }
   6.398 +    }
   6.399 +
   6.400 +    private native void setSelectionRange(Element input, int selectionStart,
   6.401 +            int selectionEnd)/*-{
   6.402 +                             if (input.setSelectionRange) {
   6.403 +                             input.focus();
   6.404 +                             input.setSelectionRange(selectionStart, selectionEnd);
   6.405 +                             }
   6.406 +                             else if (input.createTextRange) {
   6.407 +                             var range = input.createTextRange();
   6.408 +                             range.collapse(true);
   6.409 +                             range.moveEnd('character', selectionEnd);
   6.410 +                             range.moveStart('character', selectionStart);
   6.411 +                             range.select();
   6.412 +                             }
   6.413 +                             }-*/;
   6.414 +
   6.415 +    private native int getScrollbarWidth()/*-{
   6.416 +
   6.417 +                                          var i = $doc.createElement('p');
   6.418 +                                          i.style.width = '100%';
   6.419 +                                          i.style.height = '200px';
   6.420 +                                          var o = $doc.createElement('div');
   6.421 +                                          o.style.position = 'absolute';
   6.422 +                                          o.style.top = '0px';
   6.423 +                                          o.style.left = '0px';
   6.424 +                                          o.style.visibility = 'hidden';
   6.425 +                                          o.style.width = '200px';
   6.426 +                                          o.style.height = '150px';
   6.427 +                                          o.style.overflow = 'hidden';
   6.428 +                                          o.appendChild(i);
   6.429 +                                          $doc.body.appendChild(o);
   6.430 +                                          var w1 = i.offsetWidth;
   6.431 +                                          var h1 = i.offsetHeight;
   6.432 +                                          o.style.overflow = 'scroll';
   6.433 +                                          var w2 = i.offsetWidth;
   6.434 +                                          var h2 = i.offsetHeight;
   6.435 +                                          if (w1 == w2) w2 = o.clientWidth;
   6.436 +                                          if (h1 == h2) h2 = o.clientWidth;
   6.437 +                                          $doc.body.removeChild(o);
   6.438 +                                          return w1-w2;
   6.439 +                                          }-*/;
   6.440 +
   6.441 +    public void newLine() {
   6.442 +        // _log("newline");
   6.443 +        buffer.appendChild(createBr());
   6.444 +        checkBufferLimit();
   6.445 +        reducePrompt(1);
   6.446 +    }
   6.447 +
   6.448 +    protected void setPs(final String string) {
   6.449 +        cleanPs = Util.escapeHTML(string);
   6.450 +        cleanPs = cleanPs.replaceAll(" ", "&nbsp;");
   6.451 +    }
   6.452 +
   6.453 +    public void prompt(final String inputText) {
   6.454 +        setPromtActive(true);
   6.455 +        scrollToEnd();
   6.456 +        ps.setInnerHTML(cleanPs);
   6.457 +        setInput(inputText);
   6.458 +    }
   6.459 +
   6.460 +    public void scrollToEnd() {
   6.461 +        term.setScrollTop(BIG_NUMBER);
   6.462 +    }
   6.463 +
   6.464 +    public void prompt() {
   6.465 +        prompt(null);
   6.466 +    }
   6.467 +
   6.468 +    public void print(String string) {
   6.469 +        if (isPromptActive()) {
   6.470 +            setPromtActive(false);
   6.471 +            if (!bufferIsEmpty() && !bufferEndsWithNewLine()) {
   6.472 +                newLine();
   6.473 +                reducePrompt(-1);
   6.474 +            }
   6.475 +            string = getCurrentPromptContent() + string;
   6.476 +        }
   6.477 +        final boolean doWrap = config.isWrap();
   6.478 +        // _log("print original: '" + string + "' (" + doWrap + ")");
   6.479 +        String str = string.replaceAll("\t", tabs);
   6.480 +
   6.481 +        // Continue to the last text node if available
   6.482 +        final Node last = getLastTextNode();
   6.483 +        int linesAdded = 0;
   6.484 +        if (last != null) {
   6.485 +            // _log("print append to old node: '" + last.getNodeValue() + "'");
   6.486 +            str = last.getNodeValue() + str;
   6.487 +            buffer.removeChild(last);
   6.488 +            linesAdded--;
   6.489 +        }
   6.490 +
   6.491 +        // Split by the newlines anyway
   6.492 +        int s = 0, e = str.indexOf('\n');
   6.493 +        while (e >= s) {
   6.494 +            final String line = str.substring(s, e);
   6.495 +            linesAdded += appendLine(buffer, line, doWrap ? cols : -1);
   6.496 +            buffer.appendChild(createBr());
   6.497 +            s = e + 1;
   6.498 +            e = str.indexOf('\n', s);
   6.499 +        }
   6.500 +
   6.501 +        // Print the remaining string
   6.502 +        if (s < str.length()) {
   6.503 +            linesAdded += appendLine(buffer, str.substring(s), doWrap ? cols
   6.504 +                    : -1);
   6.505 +        }
   6.506 +
   6.507 +        reducePrompt(linesAdded);
   6.508 +    }
   6.509 +
   6.510 +    private String getCurrentPromptContent() {
   6.511 +        return prompt.getInnerText() + getInput();
   6.512 +    }
   6.513 +
   6.514 +    private void reducePrompt(final int rows) {
   6.515 +        int newRows = promptRows - rows;
   6.516 +        if (newRows < 1) {
   6.517 +            newRows = 1;
   6.518 +        }
   6.519 +        // _log("prompt reduced from " + promptRows + " to " + newRows);
   6.520 +        setPromptHeight(newRows);
   6.521 +    }
   6.522 +
   6.523 +    private void setPromptHeight(final int rows) {
   6.524 +        final int min = 1;
   6.525 +        final int max = getRows();
   6.526 +        promptRows = rows < min ? min : (rows > max ? max : rows);
   6.527 +        final int newHeight = fontH * rows;
   6.528 +        // _log("Prompt height=" + newHeight);
   6.529 +        promptWrap.getStyle().setHeight(newHeight, Unit.PX);
   6.530 +    }
   6.531 +
   6.532 +    /**
   6.533 +     * Split long text based on length.
   6.534 +     *
   6.535 +     * @param parent
   6.536 +     * @param doWrap
   6.537 +     * @param str
   6.538 +     * @return
   6.539 +     */
   6.540 +    private int appendLine(final Node parent, String str, final int maxLine) {
   6.541 +        int linesAdded = 0;
   6.542 +        final boolean doWrap = maxLine > 0;
   6.543 +        if (!doWrap) {
   6.544 +            parent.appendChild(createTextNode(str));
   6.545 +            // _log("append: '" + str + "'");
   6.546 +            linesAdded++;
   6.547 +        } else {
   6.548 +            while (str.length() > maxLine) {
   6.549 +                final String piece = str.substring(0, maxLine);
   6.550 +                parent.appendChild(createTextNode(piece));
   6.551 +                parent.appendChild(createBr());
   6.552 +                linesAdded++;
   6.553 +                // _log("append: '" + piece + "'");
   6.554 +                str = str.substring(maxLine);
   6.555 +            }
   6.556 +            parent.appendChild(createTextNode(str));
   6.557 +            // _log("append rest: '" + str + "'");
   6.558 +            linesAdded++;
   6.559 +        }
   6.560 +
   6.561 +        // make sore we don't exceed the maximum buffer size
   6.562 +        checkBufferLimit();
   6.563 +
   6.564 +        return linesAdded;
   6.565 +    }
   6.566 +
   6.567 +    private void checkBufferLimit() {
   6.568 +
   6.569 +        // Buffer means only offscreen lines
   6.570 +        final int maxb = maxBufferSize + (rows - promptRows);
   6.571 +        while (getBufferSize() > maxb && buffer.hasChildNodes()) {
   6.572 +            buffer.removeChild(buffer.getFirstChild());
   6.573 +        }
   6.574 +
   6.575 +    }
   6.576 +
   6.577 +    private Node getLastTextNode() {
   6.578 +        if (buffer == null) {
   6.579 +            return null;
   6.580 +        }
   6.581 +        final Node l = buffer.getLastChild();
   6.582 +        if (l != null && l.getNodeType() == Node.TEXT_NODE) {
   6.583 +            return l;
   6.584 +        }
   6.585 +        return null;
   6.586 +    }
   6.587 +
   6.588 +    public void println(final String string) {
   6.589 +        print(string + "\n");
   6.590 +    }
   6.591 +
   6.592 +    @Override
   6.593 +    public void setHeight(final String height) {
   6.594 +        final int oldh = term.getClientHeight();
   6.595 +        super.setHeight(height);
   6.596 +        final int newh = term.getClientHeight();
   6.597 +        // _log("set height=" + height + " clientHeight="+oldh+" to "+newh);
   6.598 +        if (newh != oldh) {
   6.599 +            calculateRowsFromHeight();
   6.600 +        }
   6.601 +    }
   6.602 +
   6.603 +    protected void calculateRowsFromHeight() {
   6.604 +        final int h = term.getClientHeight() - (2 * padding);
   6.605 +        rows = h / fontH;
   6.606 +        config.setRows(rows);
   6.607 +
   6.608 +        // _log("calculateRowsFromHeight: font=" + fontW + "x" + fontH
   6.609 +        // + ";scrollbar=" + scrollbarW + ";cols=" + cols + ";rows="
   6.610 +        // + rows + ";size=" + getWidth() + "x" + getHeight());
   6.611 +
   6.612 +    }
   6.613 +
   6.614 +    protected void calculateHeightFromRows() {
   6.615 +        super.setHeight((rows * fontH) + "px");
   6.616 +
   6.617 +        // _log("calculateHeightFromRows: font=" + fontW + "x" + fontH
   6.618 +        // + ";scrollbar=" + scrollbarW + ";cols=" + cols + ";rows="
   6.619 +        // + rows + ";size=" + getWidth() + "x" + getHeight());
   6.620 +
   6.621 +    }
   6.622 +
   6.623 +    protected void calculateColsFromWidth() {
   6.624 +        final int w = term.getClientWidth();
   6.625 +        cols = (w - 2 * paddingW) / fontW;
   6.626 +        config.setCols(cols);
   6.627 +        buffer.getStyle().setWidth((cols * fontW), Unit.PX);
   6.628 +        prompt.getStyle().setWidth((cols * fontW), Unit.PX);
   6.629 +        // _log("calculateColsFromWidth: font=" + fontW + "x" + fontH
   6.630 +        // + ";scrollbar=" + scrollbarW + ";cols=" + cols + ";rows="
   6.631 +        // + rows + ";size=" + getWidth() + "x" + getHeight());
   6.632 +
   6.633 +    }
   6.634 +
   6.635 +    protected void calculateWidthFromCols() {
   6.636 +        final int w = cols * fontW;
   6.637 +        super.setWidth((w + scrollbarW) + "px");
   6.638 +        buffer.getStyle().setWidth(w, Unit.PX);
   6.639 +        prompt.getStyle().setWidth(w, Unit.PX);
   6.640 +
   6.641 +        // _log("calculateWidthFromCols: font=" + fontW + "x" + fontH
   6.642 +        // + ";scrollbar=" + scrollbarW + ";cols=" + cols + ";rows="
   6.643 +        // + rows + ";size=" + getWidth() + "x" + getHeight());
   6.644 +    }
   6.645 +
   6.646 +    @Override
   6.647 +    public void setWidth(final String width) {
   6.648 +        final int oldw = term.getClientWidth();
   6.649 +        super.setWidth(width);
   6.650 +        final int neww = term.getClientWidth();
   6.651 +        // _log("set width=" + width + " clientWidth="+oldw+" to "+neww);
   6.652 +        if (neww != oldw) {
   6.653 +            calculateColsFromWidth();
   6.654 +        }
   6.655 +    }
   6.656 +
   6.657 +    @Override
   6.658 +    public void setFocus(final boolean focused) {
   6.659 +        this.focused = focused;
   6.660 +        super.setFocus(focused);
   6.661 +        if (focused) {
   6.662 +            focusPrompt();
   6.663 +        }
   6.664 +    }
   6.665 +
   6.666 +    public void setHandler(final TextConsoleHandler handler) {
   6.667 +        this.handler = handler;
   6.668 +
   6.669 +    }
   6.670 +
   6.671 +    public void setRows(final int rows) {
   6.672 +        if (rows > 0) {
   6.673 +            this.rows = rows;
   6.674 +            calculateHeightFromRows();
   6.675 +        } else {
   6.676 +            calculateRowsFromHeight();
   6.677 +        }
   6.678 +    }
   6.679 +
   6.680 +    public int getRows() {
   6.681 +        return rows;
   6.682 +    }
   6.683 +
   6.684 +    public void setCols(final int cols) {
   6.685 +        if (cols > 0) {
   6.686 +            this.cols = cols;
   6.687 +            calculateWidthFromCols();
   6.688 +        } else {
   6.689 +            calculateColsFromWidth();
   6.690 +        }
   6.691 +    }
   6.692 +
   6.693 +    public int getCols() {
   6.694 +        return cols;
   6.695 +    }
   6.696 +
   6.697 +    public void reset() {
   6.698 +        setPromtActive(false);
   6.699 +        clearBuffer();
   6.700 +        setPromptHeight(getRows());
   6.701 +        print(config.getGreeting());
   6.702 +        prompt();
   6.703 +    }
   6.704 +
   6.705 +    public int getBufferSize() {
   6.706 +        return (buffer.getClientHeight() / fontH);
   6.707 +    }
   6.708 +
   6.709 +    public int getMaxBufferSize() {
   6.710 +        return maxBufferSize;
   6.711 +    }
   6.712 +
   6.713 +    public void setMaxBufferSize(final int maxBuffer) {
   6.714 +        maxBufferSize = maxBuffer > 0 ? maxBuffer : 0;
   6.715 +        checkBufferLimit();
   6.716 +    }
   6.717 +
   6.718 +    public void clearBuffer() {
   6.719 +        // Remove all children.
   6.720 +        while (buffer.hasChildNodes()) {
   6.721 +            buffer.removeChild(buffer.getFirstChild());
   6.722 +        }
   6.723 +    }
   6.724 +
   6.725 +    public void formFeed() {
   6.726 +        for (int i = 0; i < promptRows; i++) {
   6.727 +            newLine();
   6.728 +        }
   6.729 +        setPromptHeight(getRows());
   6.730 +        scrollToEnd();
   6.731 +
   6.732 +        checkBufferLimit();
   6.733 +    }
   6.734 +
   6.735 +    protected void clearCommandHistory() {
   6.736 +        cmdHistory = new ArrayList<String>();
   6.737 +        cmdHistoryIndex = -1;
   6.738 +    }
   6.739 +
   6.740 +    public String getHeight() {
   6.741 +        return (term.getClientHeight() - 2 * padding) + "px";
   6.742 +    }
   6.743 +
   6.744 +    public String getWidth() {
   6.745 +        return (term.getClientWidth() + scrollbarW - 2 * paddingW) + "px";
   6.746 +    }
   6.747 +
   6.748 +    protected void bell() {
   6.749 +        // Clear previous
   6.750 +        if (timer != null) {
   6.751 +            timer.cancel();
   6.752 +            timer = null;
   6.753 +            term.removeClassName("term-rev");
   6.754 +            input.removeClassName("term-rev");
   6.755 +        }
   6.756 +        // Add styles and start the timer
   6.757 +        input.addClassName("term-rev");
   6.758 +        term.addClassName("term-rev");
   6.759 +        timer = new Timer() {
   6.760 +
   6.761 +            @Override
   6.762 +            public void run() {
   6.763 +                term.removeClassName("term-rev");
   6.764 +                input.removeClassName("term-rev");
   6.765 +            }
   6.766 +        };
   6.767 +        timer.schedule(150);
   6.768 +    }
   6.769 +
   6.770 +    @Override
   6.771 +    protected void onUnload() {
   6.772 +        super.onUnload();
   6.773 +
   6.774 +        if (clickHandler != null) {
   6.775 +            clickHandler.removeHandler();
   6.776 +        }
   6.777 +        if (focusHandler != null) {
   6.778 +            focusHandler.removeHandler();
   6.779 +        }
   6.780 +        if (keyHandler != null) {
   6.781 +            keyHandler.removeHandler();
   6.782 +        }
   6.783 +    }
   6.784 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/main/java/org/vaadin/console/client/ui/TextConsoleConfig.java	Sun May 15 17:46:06 2011 +0400
     7.3 @@ -0,0 +1,62 @@
     7.4 +package org.vaadin.console.client.ui;
     7.5 +
     7.6 +import com.google.gwt.core.client.JavaScriptObject;
     7.7 +
     7.8 +public class TextConsoleConfig extends JavaScriptObject {
     7.9 +
    7.10 +    public static TextConsoleConfig newInstance() {
    7.11 +        return JavaScriptObject.createObject().cast();
    7.12 +    }
    7.13 +
    7.14 +    protected TextConsoleConfig() {
    7.15 +    }
    7.16 +
    7.17 +    public final native int getCols() /*-{
    7.18 +                                      return this.cols;
    7.19 +                                      }-*/;
    7.20 +
    7.21 +    public final native void setCols(int cols) /*-{
    7.22 +                                               this.cols = cols;
    7.23 +                                               }-*/;
    7.24 +
    7.25 +    public final native int getRows() /*-{
    7.26 +                                      return this.rows;
    7.27 +                                      }-*/;
    7.28 +
    7.29 +    public final native void setRows(int rows) /*-{
    7.30 +                                               this.rows = rows;
    7.31 +                                               }-*/;
    7.32 +
    7.33 +    public final native void setGreeting(String greeting) /*-{
    7.34 +                                                          this.greeting = greeting;
    7.35 +                                                          }-*/;
    7.36 +
    7.37 +    public final native String getGreeting() /*-{
    7.38 +                                             return this.greeting;
    7.39 +                                             }-*/;
    7.40 +
    7.41 +    public final native void setWrap(boolean w) /*-{
    7.42 +                                                this.wrap = w;
    7.43 +                                                }-*/;
    7.44 +
    7.45 +    public final native boolean isWrap() /*-{
    7.46 +                                          return this.wrap;
    7.47 +                                          }-*/;
    7.48 +
    7.49 +    public final native void setPs(String ps) /*-{
    7.50 +                                              this.ps = ps;
    7.51 +                                              }-*/;
    7.52 +
    7.53 +    public final native String getPs() /*-{
    7.54 +                                       return this.ps;
    7.55 +                                       }-*/;
    7.56 +
    7.57 +    public final native int getMaxBufferSize() /*-{
    7.58 +                                               return this.bufferRows;
    7.59 +                                               }-*/;
    7.60 +
    7.61 +    public final native void setMaxBufferSize(int rows) /*-{
    7.62 +                                                        this.bufferRows = rows;
    7.63 +                                                        }-*/;
    7.64 +
    7.65 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/main/java/org/vaadin/console/client/ui/TextConsoleHandler.java	Sun May 15 17:46:06 2011 +0400
     8.3 @@ -0,0 +1,7 @@
     8.4 +package org.vaadin.console.client.ui;
     8.5 +
     8.6 +public interface TextConsoleHandler {
     8.7 +
     8.8 +    public void terminalInput(TextConsole term, String input);
     8.9 +
    8.10 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/main/java/org/vaadin/console/client/ui/VTextConsole.java	Sun May 15 17:46:06 2011 +0400
     9.3 @@ -0,0 +1,252 @@
     9.4 +package org.vaadin.console.client.ui;
     9.5 +
     9.6 +import org.vaadin.rpc.client.ClientSideHandler;
     9.7 +import org.vaadin.rpc.client.ClientSideProxy;
     9.8 +import org.vaadin.rpc.client.ClientSideProxy.Transcation;
     9.9 +import org.vaadin.rpc.client.Method;
    9.10 +
    9.11 +import com.vaadin.terminal.gwt.client.ApplicationConnection;
    9.12 +import com.vaadin.terminal.gwt.client.Paintable;
    9.13 +import com.vaadin.terminal.gwt.client.UIDL;
    9.14 +import com.vaadin.terminal.gwt.client.Util;
    9.15 +
    9.16 +/**
    9.17 + * Vaadin client-side integration to Console GWT Widget.
    9.18 + *
    9.19 + * @author Sami Ekblad / Vaadin
    9.20 + *
    9.21 + */
    9.22 +public class VTextConsole extends TextConsole implements Paintable,
    9.23 +        TextConsoleHandler, ClientSideHandler {
    9.24 +
    9.25 +    private static final String CSS_CLASS_NAME = "v-console";
    9.26 +
    9.27 +    private final ClientSideProxy comm = new ClientSideProxy("VTextConsole",
    9.28 +            this);
    9.29 +
    9.30 +    /**
    9.31 +     * The constructor should first call super() to initialize the component and
    9.32 +     * then handle any initialization relevant to Vaadin.
    9.33 +     */
    9.34 +    public VTextConsole() {
    9.35 +        super();
    9.36 +        getElement().addClassName(CSS_CLASS_NAME);
    9.37 +        setHandler(this);
    9.38 +
    9.39 +        // Register all server-driven functions
    9.40 +        registerServerCallbacks();
    9.41 +    }
    9.42 +
    9.43 +    private void registerServerCallbacks() {
    9.44 +        comm.register("setGreeting", new Method() {
    9.45 +            public void invoke(final String methodName, final Object[] data) {
    9.46 +                getConfig().setGreeting((String) data[0]);
    9.47 +            }
    9.48 +        });
    9.49 +        comm.register("setPs", new Method() {
    9.50 +            public void invoke(final String methodName, final Object[] data) {
    9.51 +                setPs((String) data[0]);
    9.52 +            }
    9.53 +        });
    9.54 +        comm.register("setWrap", new Method() {
    9.55 +            public void invoke(final String methodName, final Object[] data) {
    9.56 +                getConfig().setWrap((Boolean) data[0]);
    9.57 +            }
    9.58 +        });
    9.59 +        comm.register("setRows", new Method() {
    9.60 +            public void invoke(final String methodName, final Object[] data) {
    9.61 +                getConfig().setRows((Integer) data[0]);
    9.62 +                setRows((Integer) data[0]);
    9.63 +            }
    9.64 +        });
    9.65 +        comm.register("setCols", new Method() {
    9.66 +            public void invoke(final String methodName, final Object[] data) {
    9.67 +                getConfig().setCols((Integer) data[0]);
    9.68 +                setCols((Integer) data[0]);
    9.69 +            }
    9.70 +        });
    9.71 +        comm.register("print", new Method() {
    9.72 +            public void invoke(final String methodName, final Object[] data) {
    9.73 +                print((String) data[0]);
    9.74 +            }
    9.75 +        });
    9.76 +        comm.register("println", new Method() {
    9.77 +            public void invoke(final String methodName, final Object[] data) {
    9.78 +                println((String) data[0]);
    9.79 +            }
    9.80 +        });
    9.81 +        comm.register("println", new Method() {
    9.82 +            public void invoke(final String methodName, final Object[] data) {
    9.83 +                println((String) data[0]);
    9.84 +            }
    9.85 +        });
    9.86 +        comm.register("prompt", new Method() {
    9.87 +            public void invoke(final String methodName, final Object[] data) {
    9.88 +                prompt((String) (data.length > 0 ? data[0] : null));
    9.89 +            }
    9.90 +        });
    9.91 +        comm.register("ff", new Method() {
    9.92 +            public void invoke(final String methodName, final Object[] data) {
    9.93 +                formFeed();
    9.94 +            }
    9.95 +        });
    9.96 +        comm.register("cr", new Method() {
    9.97 +            public void invoke(final String methodName, final Object[] data) {
    9.98 +                carriageReturn();
    9.99 +            }
   9.100 +        });
   9.101 +        comm.register("lf", new Method() {
   9.102 +            public void invoke(final String methodName, final Object[] data) {
   9.103 +                carriageReturn();
   9.104 +            }
   9.105 +        });
   9.106 +        comm.register("clearBuffer", new Method() {
   9.107 +            public void invoke(final String methodName, final Object[] data) {
   9.108 +                clearBuffer();
   9.109 +            }
   9.110 +        });
   9.111 +        comm.register("reset", new Method() {
   9.112 +            public void invoke(final String methodName, final Object[] data) {
   9.113 +                reset();
   9.114 +            }
   9.115 +        });
   9.116 +        comm.register("newLine", new Method() {
   9.117 +            public void invoke(final String methodName, final Object[] data) {
   9.118 +                newLine();
   9.119 +            }
   9.120 +        });
   9.121 +        comm.register("scrollToEnd", new Method() {
   9.122 +            public void invoke(final String methodName, final Object[] data) {
   9.123 +                scrollToEnd();
   9.124 +            }
   9.125 +        });
   9.126 +        comm.register("bell", new Method() {
   9.127 +            public void invoke(final String methodName, final Object[] data) {
   9.128 +                bell();
   9.129 +            }
   9.130 +        });
   9.131 +        comm.register("setMaxBufferSize", new Method() {
   9.132 +            public void invoke(final String methodName, final Object[] data) {
   9.133 +                getConfig().setMaxBufferSize((Integer) data[0]);
   9.134 +                setMaxBufferSize((Integer) data[0]);
   9.135 +            }
   9.136 +        });
   9.137 +        comm.register("clearHistory", new Method() {
   9.138 +            public void invoke(final String methodName, final Object[] data) {
   9.139 +                clearCommandHistory();
   9.140 +            }
   9.141 +        });
   9.142 +    }
   9.143 +
   9.144 +    /**
   9.145 +     * Called whenever an update is received from the server
   9.146 +     */
   9.147 +    public void updateFromUIDL(final UIDL serverData,
   9.148 +            final ApplicationConnection appConn) {
   9.149 +        comm.update(this,serverData, appConn);
   9.150 +
   9.151 +    }
   9.152 +
   9.153 +    private void sendSizeToServer() {
   9.154 +        if (comm.isClientInitialized()) {
   9.155 +            final Transcation tx = comm.startTx();
   9.156 +            tx.send("height", getHeight());
   9.157 +            tx.send("width", getWidth());
   9.158 +            tx.commit();
   9.159 +        }
   9.160 +
   9.161 +    }
   9.162 +
   9.163 +    public void terminalInput(final TextConsole term, final String input) {
   9.164 +        if (comm.isClientInitialized()) {
   9.165 +            comm.call("input", input);
   9.166 +        }
   9.167 +    }
   9.168 +
   9.169 +    @Override
   9.170 +    protected void calculateColsFromWidth() {
   9.171 +        final int oldCols = getCols();
   9.172 +        super.calculateColsFromWidth();
   9.173 +
   9.174 +        if (comm.isClientInitialized() && getCols() != oldCols) {
   9.175 +            final Transcation tx = comm.startTx();
   9.176 +            tx.send("cols", getCols());
   9.177 +            tx.commit();
   9.178 +        }
   9.179 +    }
   9.180 +
   9.181 +    @Override
   9.182 +    protected void calculateRowsFromHeight() {
   9.183 +        final int oldRows = getRows();
   9.184 +        super.calculateRowsFromHeight();
   9.185 +
   9.186 +        if (comm.isClientInitialized() && getRows() != oldRows) {
   9.187 +            final Transcation tx = comm.startTx();
   9.188 +            tx.send("rows", getRows());
   9.189 +            tx.commit();
   9.190 +
   9.191 +        }
   9.192 +
   9.193 +    }
   9.194 +
   9.195 +    @Override
   9.196 +    protected void calculateHeightFromRows() {
   9.197 +        super.calculateHeightFromRows();
   9.198 +        notifyPaintableSizeChange();
   9.199 +        sendSizeToServer();
   9.200 +    }
   9.201 +
   9.202 +    @Override
   9.203 +    protected void calculateWidthFromCols() {
   9.204 +        super.calculateWidthFromCols();
   9.205 +        notifyPaintableSizeChange();
   9.206 +        sendSizeToServer();
   9.207 +    }
   9.208 +
   9.209 +    private void notifyPaintableSizeChange() {
   9.210 +        Util.notifyParentOfSizeChange(this, false);
   9.211 +    }
   9.212 +
   9.213 +    @Override
   9.214 +    protected void suggest() {
   9.215 +        if (comm.isClientInitialized()) {
   9.216 +            comm.call("suggest", getInput());
   9.217 +        }
   9.218 +    }
   9.219 +
   9.220 +    @Override
   9.221 +    public void setConfig(final TextConsoleConfig cfg) {
   9.222 +        // Wrap everything to a single tx
   9.223 +        final Transcation tx = comm.startTx();
   9.224 +        super.setConfig(cfg);
   9.225 +        tx.commit();
   9.226 +    }
   9.227 +
   9.228 +    /**
   9.229 +     * Initialize the Console synchronously.
   9.230 +     *
   9.231 +     */
   9.232 +    public boolean initWidget(Object[] params) {
   9.233 +
   9.234 +        // Console configuration
   9.235 +        final TextConsoleConfig cfg = getConfig();
   9.236 +        int i = 0;
   9.237 +        cfg.setCols((Integer) params[i++]);
   9.238 +        cfg.setRows((Integer) params[i++]);
   9.239 +        cfg.setMaxBufferSize((Integer) params[i++]);
   9.240 +        cfg.setWrap((Boolean) params[i++]);
   9.241 +        cfg.setGreeting((String) params[i++]);
   9.242 +        cfg.setPs((String) params[i++]);
   9.243 +        comm.d("init: '" + cfg.getGreeting() + "';" + cfg.getCols() + "x"
   9.244 +                + cfg.getRows() + "");
   9.245 +        setConfig(cfg);
   9.246 +
   9.247 +        reset();
   9.248 +        return false; // Not an async initialization
   9.249 +    }
   9.250 +
   9.251 +    public void handleCallFromServer(String method, Object[] params) {
   9.252 +        comm.d("Unknown method called: " + method);
   9.253 +    }
   9.254 +
   9.255 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/main/java/org/vaadin/console/public/console/styles.css	Sun May 15 17:46:06 2011 +0400
    10.3 @@ -0,0 +1,70 @@
    10.4 +.term {
    10.5 +	background-color: #000;
    10.6 +	color: #f0f0f0;
    10.7 +	/* color: #33d011; */
    10.8 +	padding: 1px;
    10.9 +	padding-left: 2px;
   10.10 +	padding-right: 2px;
   10.11 +	font-family: monospace;;
   10.12 +	font-size: 10pt;
   10.13 +	overflow: scroll;
   10.14 +	overflow-x: hidden;
   10.15 +}
   10.16 +
   10.17 +.term-rev, .term input.term-rev  {
   10.18 +	background-color: #f0f0f0;
   10.19 +	color: #000;
   10.20 +}
   10.21 +
   10.22 +.term .b {
   10.23 +	margin: 0;
   10.24 +	padding: 0;	
   10.25 +}
   10.26 +
   10.27 +.term .pw {
   10.28 +	margin: 0;
   10.29 +	padding: 0;	
   10.30 +}
   10.31 +
   10.32 +.term .pw .p {
   10.33 +	border-collapse: collapse;
   10.34 +	margin: 0;
   10.35 +	padding: 0;
   10.36 +	height: 1em;	
   10.37 +}
   10.38 +
   10.39 +.term .pw .psw {
   10.40 +	margin: 0;
   10.41 +	padding: 0;	
   10.42 +	width: auto;
   10.43 +}
   10.44 +
   10.45 +.term .pw .iw {
   10.46 +	margin: 0;
   10.47 +	padding: 0;	
   10.48 +	width: 100%;
   10.49 +}
   10.50 +
   10.51 +.term .i {
   10.52 +	border: none;
   10.53 +	outline: none;
   10.54 +	border-width: 0;
   10.55 +	width: 100%;
   10.56 +	height: 1em;
   10.57 +	margin: 0;
   10.58 +	padding: 0;	
   10.59 +	font-family: monospace;;
   10.60 +	font-size: 10pt;
   10.61 +	word-wrap:break-word;
   10.62 +	background-color: #000;
   10.63 +	color: #f0f0f0;
   10.64 +}
   10.65 +
   10.66 +
   10.67 +/** Coloring sample
   10.68 +.term, .term .i {
   10.69 +    background-color: #F5F5F5 !important;
   10.70 +    color: #222222 !important;
   10.71 +}
   10.72 +
   10.73 + **/
   10.74 \ No newline at end of file
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/main/java/org/vaadin/console/sample/ConsoleSampleApplication.java	Sun May 15 17:46:06 2011 +0400
    11.3 @@ -0,0 +1,193 @@
    11.4 +package org.vaadin.console.sample;
    11.5 +
    11.6 +import java.io.IOException;
    11.7 +import java.io.InputStream;
    11.8 +import java.io.InputStreamReader;
    11.9 +import java.util.ArrayList;
   11.10 +import java.util.Arrays;
   11.11 +
   11.12 +import org.vaadin.console.Console;
   11.13 +import org.vaadin.console.Console.Command;
   11.14 +import org.vaadin.console.ObjectInspector;
   11.15 +
   11.16 +import com.vaadin.Application;
   11.17 +import com.vaadin.ui.Button;
   11.18 +import com.vaadin.ui.Button.ClickEvent;
   11.19 +import com.vaadin.ui.HorizontalLayout;
   11.20 +import com.vaadin.ui.Label;
   11.21 +import com.vaadin.ui.Panel;
   11.22 +import com.vaadin.ui.TextField;
   11.23 +import com.vaadin.ui.Window;
   11.24 +
   11.25 +public class ConsoleSampleApplication extends Application {
   11.26 +    private static final long serialVersionUID = 4009702916419936660L;
   11.27 +    protected static final String HELP = "Sample Vaadin shell. Following command are available:\n";
   11.28 +    private ObjectInspector inspector;
   11.29 +
   11.30 +    @Override
   11.31 +    public void init() {
   11.32 +        Window mainWindow = new Window("Vaadin Console Demo");
   11.33 +        setMainWindow(mainWindow);
   11.34 +
   11.35 +        Panel intro = new Panel("Vaadin Console Demo");
   11.36 +        intro
   11.37 +                .addComponent(new Label(
   11.38 +                        "This console implements a test environment for itself.<br> All methods in console class are exposed as commands in the console itself.",
   11.39 +                        Label.CONTENT_RAW));
   11.40 +        intro
   11.41 +                .addComponent(new Label(
   11.42 +                        "Type 'help' to list all available commands and 'help <command>' to get parameter help.'"));
   11.43 +
   11.44 +        // # 1
   11.45 +
   11.46 +        // Create a console
   11.47 +        final Console console = new Console();
   11.48 +        mainWindow.addComponent(console);
   11.49 +
   11.50 +        // Size and greeting
   11.51 +        console.setPs("}> ");
   11.52 +        console.setCols(80);
   11.53 +        console.setRows(24);
   11.54 +        console.setMaxBufferSize(24);
   11.55 +        console.setGreeting("Welcome to Vaadin console demo.");
   11.56 +        console.reset();
   11.57 +        console.focus();
   11.58 +
   11.59 +        // Publish the methods in the Console class itself for testing purposes.
   11.60 +        console.addCommandProvider(inspector = new ObjectInspector(console));
   11.61 +
   11.62 +        // Add help command
   11.63 +        Command helpCommand = new Console.Command() {
   11.64 +            private static final long serialVersionUID = 2838665604270727844L;
   11.65 +
   11.66 +            public String getUsage(Console console, String[] argv) {
   11.67 +                return argv[0] + " <command>";
   11.68 +            }
   11.69 +
   11.70 +            public Object execute(Console console, String[] argv)
   11.71 +                    throws Exception {
   11.72 +                if (argv.length == 2) {
   11.73 +                    Command hc = console.getCommand(argv[1]);
   11.74 +                    ArrayList<String> cmdArgv = new ArrayList<String>(Arrays
   11.75 +                            .asList(argv));
   11.76 +                    cmdArgv.remove(0);
   11.77 +                    return "Usage: "
   11.78 +                            + hc.getUsage(console, cmdArgv
   11.79 +                                    .toArray(new String[] {}));
   11.80 +                }
   11.81 +                return listAvailableCommands();
   11.82 +            }
   11.83 +        };
   11.84 +
   11.85 +        // Bind the same command with multiple names
   11.86 +        console.addCommand("help", helpCommand);
   11.87 +        console.addCommand("info", helpCommand);
   11.88 +        console.addCommand("man", helpCommand);
   11.89 +        // #
   11.90 +
   11.91 +        // # 2
   11.92 +        Command systemCommand = new Command() {
   11.93 +            private static final long serialVersionUID = -5733237166568671987L;
   11.94 +
   11.95 +            public Object execute(Console console, String[] argv)
   11.96 +                    throws Exception {
   11.97 +                Process p = Runtime.getRuntime().exec(argv);
   11.98 +                InputStream in = p.getInputStream();
   11.99 +                StringBuilder o = new StringBuilder();
  11.100 +                InputStreamReader r = new InputStreamReader(in);
  11.101 +                int c = -1;
  11.102 +                try {
  11.103 +                    while ((c = r.read()) != -1) {
  11.104 +                        o.append((char) c);
  11.105 +                    }
  11.106 +                } catch (IOException e) {
  11.107 +                    o.append("[truncated]");
  11.108 +                } finally {
  11.109 +                    if (r != null) {
  11.110 +                        r.close();
  11.111 +                    }
  11.112 +                }
  11.113 +                return o.toString();
  11.114 +            }
  11.115 +
  11.116 +            public String getUsage(Console console, String[] argv) {
  11.117 +                // TODO Auto-generated method stub
  11.118 +                return null;
  11.119 +            }
  11.120 +        };
  11.121 +
  11.122 +        // #
  11.123 +        console.addCommand("ls", systemCommand);
  11.124 +
  11.125 +        // Add sample command
  11.126 +        DummyCmd dummy = new DummyCmd();
  11.127 +        console.addCommand("dir", dummy);
  11.128 +        console.addCommand("cd", dummy);
  11.129 +        console.addCommand("mkdir", dummy);
  11.130 +        console.addCommand("rm", dummy);
  11.131 +        console.addCommand("pwd", dummy);
  11.132 +        console.addCommand("more", dummy);
  11.133 +        console.addCommand("less", dummy);
  11.134 +        console.addCommand("exit", dummy);
  11.135 +
  11.136 +        HorizontalLayout pl = new HorizontalLayout();
  11.137 +        pl.setSpacing(true);
  11.138 +        mainWindow.addComponent(pl);
  11.139 +        final TextField input = new TextField(null, "print this");
  11.140 +        pl.addComponent(input);
  11.141 +        pl.addComponent(new Button("print", new Button.ClickListener() {
  11.142 +            private static final long serialVersionUID = 1L;
  11.143 +
  11.144 +            public void buttonClick(ClickEvent event) {
  11.145 +                console.print("" + input.getValue());
  11.146 +            }
  11.147 +        }));
  11.148 +
  11.149 +        pl.addComponent(new Button("println", new Button.ClickListener() {
  11.150 +            private static final long serialVersionUID = 1L;
  11.151 +
  11.152 +            public void buttonClick(ClickEvent event) {
  11.153 +                console.println("" + input.getValue());
  11.154 +            }
  11.155 +        }));
  11.156 +
  11.157 +    }
  11.158 +
  11.159 +    protected String readToString(InputStream in) {
  11.160 +        StringBuilder o = new StringBuilder();
  11.161 +        InputStreamReader r = new InputStreamReader(in);
  11.162 +        int c = -1;
  11.163 +        try {
  11.164 +            while ((c = r.read()) != -1) {
  11.165 +                o.append((char) c);
  11.166 +            }
  11.167 +        } catch (IOException e) {
  11.168 +            o.append("[truncated]");
  11.169 +        }
  11.170 +        return o.toString();
  11.171 +    }
  11.172 +
  11.173 +    public static class DummyCmd implements Console.Command {
  11.174 +        private static final long serialVersionUID = -7725047596507450670L;
  11.175 +
  11.176 +        public Object execute(Console console, String[] argv) throws Exception {
  11.177 +            return "Sorry, this is not a real shell and '" + argv[0]
  11.178 +                    + "' is unsupported. Try 'help' instead.";
  11.179 +        }
  11.180 +
  11.181 +        public String getUsage(Console console, String[] argv) {
  11.182 +            return "Sorry, this is not a real shell and '" + argv[0]
  11.183 +                    + "' is unsupported. Try 'help' instead.";
  11.184 +        }
  11.185 +    }
  11.186 +
  11.187 +    protected String listAvailableCommands() {
  11.188 +        StringBuilder res = new StringBuilder();
  11.189 +        for (String cmd : inspector.getAvailableCommands()) {
  11.190 +            res.append(" ");
  11.191 +            res.append(cmd);
  11.192 +        }
  11.193 +        return res.toString().trim();
  11.194 +    }
  11.195 +
  11.196 +}