diff options
author | Artur Signell <artur@vaadin.com> | 2012-08-13 18:34:33 +0300 |
---|---|---|
committer | Artur Signell <artur@vaadin.com> | 2012-08-13 19:18:33 +0300 |
commit | e85d933b25cc3c5cc85eb7eb4b13b950fd8e1569 (patch) | |
tree | 9ab6f13f7188cab44bbd979b1cf620f15328a03f /src | |
parent | 14dd4d0b28c76eb994b181a4570f3adec53342e6 (diff) | |
download | vaadin-framework-e85d933b25cc3c5cc85eb7eb4b13b950fd8e1569.tar.gz vaadin-framework-e85d933b25cc3c5cc85eb7eb4b13b950fd8e1569.zip |
Moved server files to a server src folder (#9299)
Diffstat (limited to 'src')
408 files changed, 0 insertions, 107042 deletions
diff --git a/src/com/vaadin/Application.java b/src/com/vaadin/Application.java deleted file mode 100644 index 1d31410185..0000000000 --- a/src/com/vaadin/Application.java +++ /dev/null @@ -1,2426 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin; - -import java.io.IOException; -import java.io.Serializable; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.net.SocketException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.EventListener; -import java.util.EventObject; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.LinkedList; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.vaadin.annotations.EagerInit; -import com.vaadin.annotations.Theme; -import com.vaadin.annotations.Widgetset; -import com.vaadin.data.util.converter.Converter; -import com.vaadin.data.util.converter.ConverterFactory; -import com.vaadin.data.util.converter.DefaultConverterFactory; -import com.vaadin.event.EventRouter; -import com.vaadin.service.ApplicationContext; -import com.vaadin.terminal.AbstractErrorMessage; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.CombinedRequest; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedRequest.BrowserDetails; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; -import com.vaadin.terminal.gwt.server.BootstrapFragmentResponse; -import com.vaadin.terminal.gwt.server.BootstrapListener; -import com.vaadin.terminal.gwt.server.BootstrapPageResponse; -import com.vaadin.terminal.gwt.server.BootstrapResponse; -import com.vaadin.terminal.gwt.server.ChangeVariablesErrorEvent; -import com.vaadin.terminal.gwt.server.ClientConnector; -import com.vaadin.terminal.gwt.server.WebApplicationContext; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.AbstractComponent; -import com.vaadin.ui.AbstractField; -import com.vaadin.ui.Root; -import com.vaadin.ui.Table; -import com.vaadin.ui.Window; - -/** - * <p> - * Base class required for all Vaadin applications. This class provides all the - * basic services required by Vaadin. These services allow external discovery - * and manipulation of the user, {@link com.vaadin.ui.Window windows} and - * themes, and starting and stopping the application. - * </p> - * - * <p> - * As mentioned, all Vaadin applications must inherit this class. However, this - * is almost all of what one needs to do to create a fully functional - * application. The only thing a class inheriting the <code>Application</code> - * needs to do is implement the <code>init</code> method where it creates the - * windows it needs to perform its function. Note that all applications must - * have at least one window: the main window. The first unnamed window - * constructed by an application automatically becomes the main window which - * behaves just like other windows with one exception: when accessing windows - * using URLs the main window corresponds to the application URL whereas other - * windows correspond to a URL gotten by catenating the window's name to the - * application URL. - * </p> - * - * <p> - * See the class <code>com.vaadin.demo.HelloWorld</code> for a simple example of - * a fully working application. - * </p> - * - * <p> - * <strong>Window access.</strong> <code>Application</code> provides methods to - * list, add and remove the windows it contains. - * </p> - * - * <p> - * <strong>Execution control.</strong> This class includes method to start and - * finish the execution of the application. Being finished means basically that - * no windows will be available from the application anymore. - * </p> - * - * <p> - * <strong>Theme selection.</strong> The theme selection process allows a theme - * to be specified at three different levels. When a window's theme needs to be - * found out, the window itself is queried for a preferred theme. If the window - * does not prefer a specific theme, the application containing the window is - * queried. If neither the application prefers a theme, the default theme for - * the {@link com.vaadin.terminal.Terminal terminal} is used. The terminal - * always defines a default theme. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Application implements Terminal.ErrorListener, Serializable { - - /** - * The name of the parameter that is by default used in e.g. web.xml to - * define the name of the default {@link Root} class. - */ - public static final String ROOT_PARAMETER = "root"; - - private static final Method BOOTSTRAP_FRAGMENT_METHOD = ReflectTools - .findMethod(BootstrapListener.class, "modifyBootstrapFragment", - BootstrapFragmentResponse.class); - private static final Method BOOTSTRAP_PAGE_METHOD = ReflectTools - .findMethod(BootstrapListener.class, "modifyBootstrapPage", - BootstrapPageResponse.class); - - /** - * A special application designed to help migrating applications from Vaadin - * 6 to Vaadin 7. The legacy application supports setting a main window, - * adding additional browser level windows and defining the theme for the - * entire application. - * - * @deprecated This class is only intended to ease migration and should not - * be used for new projects. - * - * @since 7.0 - */ - @Deprecated - public static class LegacyApplication extends Application { - /** - * Ignore initial / and then get everything up to the next / - */ - private static final Pattern WINDOW_NAME_PATTERN = Pattern - .compile("^/?([^/]+).*"); - - private Root.LegacyWindow mainWindow; - private String theme; - - private Map<String, Root.LegacyWindow> legacyRootNames = new HashMap<String, Root.LegacyWindow>(); - - /** - * Sets the main window of this application. Setting window as a main - * window of this application also adds the window to this application. - * - * @param mainWindow - * the root to set as the default window - */ - public void setMainWindow(Root.LegacyWindow mainWindow) { - if (this.mainWindow != null) { - throw new IllegalStateException( - "mainWindow has already been set"); - } - if (mainWindow.getApplication() == null) { - mainWindow.setApplication(this); - } else if (mainWindow.getApplication() != this) { - throw new IllegalStateException( - "mainWindow is attached to another application"); - } - this.mainWindow = mainWindow; - } - - /** - * Gets the mainWindow of the application. - * - * <p> - * The main window is the window attached to the application URL ( - * {@link #getURL()}) and thus which is show by default to the user. - * </p> - * <p> - * Note that each application must have at least one main window. - * </p> - * - * @return the root used as the default window - */ - public Root.LegacyWindow getMainWindow() { - return mainWindow; - } - - /** - * This implementation simulates the way of finding a window for a - * request by extracting a window name from the requested path and - * passes that name to {@link #getWindow(String)}. - * - * {@inheritDoc} - * - * @see #getWindow(String) - * @see Application#getRoot(WrappedRequest) - */ - - @Override - public Root.LegacyWindow getRoot(WrappedRequest request) { - String pathInfo = request.getRequestPathInfo(); - String name = null; - if (pathInfo != null && pathInfo.length() > 0) { - Matcher matcher = WINDOW_NAME_PATTERN.matcher(pathInfo); - if (matcher.matches()) { - // Skip the initial slash - name = matcher.group(1); - } - } - Root.LegacyWindow window = getWindow(name); - if (window != null) { - return window; - } - return mainWindow; - } - - /** - * Sets the application's theme. - * <p> - * Note that this theme can be overridden for a specific root with - * {@link Application#getThemeForRoot(Root)}. Setting theme to be - * <code>null</code> selects the default theme. For the available theme - * names, see the contents of the VAADIN/themes directory. - * </p> - * - * @param theme - * the new theme for this application. - */ - public void setTheme(String theme) { - this.theme = theme; - } - - /** - * Gets the application's theme. The application's theme is the default - * theme used by all the roots for which a theme is not explicitly - * defined. If the application theme is not explicitly set, - * <code>null</code> is returned. - * - * @return the name of the application's theme. - */ - public String getTheme() { - return theme; - } - - /** - * This implementation returns the theme that has been set using - * {@link #setTheme(String)} - * <p> - * {@inheritDoc} - */ - - @Override - public String getThemeForRoot(Root root) { - return theme; - } - - /** - * <p> - * Gets a root by name. Returns <code>null</code> if the application is - * not running or it does not contain a window corresponding to the - * name. - * </p> - * - * @param name - * the name of the requested window - * @return a root corresponding to the name, or <code>null</code> to use - * the default window - */ - public Root.LegacyWindow getWindow(String name) { - return legacyRootNames.get(name); - } - - /** - * Counter to get unique names for windows with no explicit name - */ - private int namelessRootIndex = 0; - - /** - * Adds a new browser level window to this application. Please note that - * Root doesn't have a name that is used in the URL - to add a named - * window you should instead use {@link #addWindow(Root, String)} - * - * @param root - * the root window to add to the application - * @return returns the name that has been assigned to the window - * - * @see #addWindow(Root, String) - */ - public void addWindow(Root.LegacyWindow root) { - if (root.getName() == null) { - String name = Integer.toString(namelessRootIndex++); - root.setName(name); - } - - legacyRootNames.put(root.getName(), root); - root.setApplication(this); - } - - /** - * Removes the specified window from the application. This also removes - * all name mappings for the window (see - * {@link #addWindow(Root, String) and #getWindowName(Root)}. - * - * <p> - * Note that removing window from the application does not close the - * browser window - the window is only removed from the server-side. - * </p> - * - * @param root - * the root to remove - */ - public void removeWindow(Root.LegacyWindow root) { - for (Entry<String, Root.LegacyWindow> entry : legacyRootNames - .entrySet()) { - if (entry.getValue() == root) { - legacyRootNames.remove(entry.getKey()); - } - } - } - - /** - * Gets the set of windows contained by the application. - * - * <p> - * Note that the returned set of windows can not be modified. - * </p> - * - * @return the unmodifiable collection of windows. - */ - public Collection<Root.LegacyWindow> getWindows() { - return Collections.unmodifiableCollection(legacyRootNames.values()); - } - } - - /** - * An event sent to {@link #start(ApplicationStartEvent)} when a new - * Application is being started. - * - * @since 7.0 - */ - public static class ApplicationStartEvent implements Serializable { - private final URL applicationUrl; - - private final Properties applicationProperties; - - private final ApplicationContext context; - - private final boolean productionMode; - - /** - * @param applicationUrl - * the URL the application should respond to. - * @param applicationProperties - * the Application properties as specified by the deployment - * configuration. - * @param context - * the context application will be running in. - * @param productionMode - * flag indicating whether the application is running in - * production mode. - */ - public ApplicationStartEvent(URL applicationUrl, - Properties applicationProperties, ApplicationContext context, - boolean productionMode) { - this.applicationUrl = applicationUrl; - this.applicationProperties = applicationProperties; - this.context = context; - this.productionMode = productionMode; - } - - /** - * Gets the URL the application should respond to. - * - * @return the URL the application should respond to or - * <code>null</code> if the URL is not defined. - * - * @see Application#getURL() - */ - public URL getApplicationUrl() { - return applicationUrl; - } - - /** - * Gets the Application properties as specified by the deployment - * configuration. - * - * @return the properties configured for the applciation. - * - * @see Application#getProperty(String) - */ - public Properties getApplicationProperties() { - return applicationProperties; - } - - /** - * Gets the context application will be running in. - * - * @return the context application will be running in. - * - * @see Application#getContext() - */ - public ApplicationContext getContext() { - return context; - } - - /** - * Checks whether the application is running in production mode. - * - * @return <code>true</code> if in production mode, else - * <code>false</code> - * - * @see Application#isProductionMode() - */ - public boolean isProductionMode() { - return productionMode; - } - } - - private final static Logger logger = Logger.getLogger(Application.class - .getName()); - - /** - * Application context the application is running in. - */ - private ApplicationContext context; - - /** - * The current user or <code>null</code> if no user has logged in. - */ - private Object user; - - /** - * The application's URL. - */ - private URL applicationUrl; - - /** - * Application status. - */ - private volatile boolean applicationIsRunning = false; - - /** - * Application properties. - */ - private Properties properties; - - /** - * Default locale of the application. - */ - private Locale locale; - - /** - * List of listeners listening user changes. - */ - private LinkedList<UserChangeListener> userChangeListeners = null; - - /** - * Application resource mapping: key <-> resource. - */ - private final Hashtable<ApplicationResource, String> resourceKeyMap = new Hashtable<ApplicationResource, String>(); - - private final Hashtable<String, ApplicationResource> keyResourceMap = new Hashtable<String, ApplicationResource>(); - - private long lastResourceKeyNumber = 0; - - /** - * URL where the user is redirected to on application close, or null if - * application is just closed without redirection. - */ - private String logoutURL = null; - - /** - * The default SystemMessages (read-only). Change by overriding - * getSystemMessages() and returning CustomizedSystemMessages - */ - private static final SystemMessages DEFAULT_SYSTEM_MESSAGES = new SystemMessages(); - - /** - * Application wide error handler which is used by default if an error is - * left unhandled. - */ - private Terminal.ErrorListener errorHandler = this; - - /** - * The converter factory that is used to provide default converters for the - * application. - */ - private ConverterFactory converterFactory = new DefaultConverterFactory(); - - private LinkedList<RequestHandler> requestHandlers = new LinkedList<RequestHandler>(); - - private int nextRootId = 0; - private Map<Integer, Root> roots = new HashMap<Integer, Root>(); - - private boolean productionMode = true; - - private final Map<String, Integer> retainOnRefreshRoots = new HashMap<String, Integer>(); - - private final EventRouter eventRouter = new EventRouter(); - - /** - * Keeps track of which roots have been inited. - * <p> - * TODO Investigate whether this might be derived from the different states - * in getRootForRrequest. - * </p> - */ - private Set<Integer> initedRoots = new HashSet<Integer>(); - - /** - * Gets the user of the application. - * - * <p> - * Vaadin doesn't define of use user object in any way - it only provides - * this getter and setter methods for convenience. The user is any object - * that has been stored to the application with {@link #setUser(Object)}. - * </p> - * - * @return the User of the application. - */ - public Object getUser() { - return user; - } - - /** - * <p> - * Sets the user of the application instance. An application instance may - * have a user associated to it. This can be set in login procedure or - * application initialization. - * </p> - * <p> - * A component performing the user login procedure can assign the user - * property of the application and make the user object available to other - * components of the application. - * </p> - * <p> - * Vaadin doesn't define of use user object in any way - it only provides - * getter and setter methods for convenience. The user reference stored to - * the application can be read with {@link #getUser()}. - * </p> - * - * @param user - * the new user. - */ - public void setUser(Object user) { - final Object prevUser = this.user; - if (user == prevUser || (user != null && user.equals(prevUser))) { - return; - } - - this.user = user; - if (userChangeListeners != null) { - final Object[] listeners = userChangeListeners.toArray(); - final UserChangeEvent event = new UserChangeEvent(this, user, - prevUser); - for (int i = 0; i < listeners.length; i++) { - ((UserChangeListener) listeners[i]) - .applicationUserChanged(event); - } - } - } - - /** - * Gets the URL of the application. - * - * <p> - * This is the URL what can be entered to a browser window to start the - * application. Navigating to the application URL shows the main window ( - * {@link #getMainWindow()}) of the application. Note that the main window - * can also be shown by navigating to the window url ( - * {@link com.vaadin.ui.Window#getURL()}). - * </p> - * - * @return the application's URL. - */ - public URL getURL() { - return applicationUrl; - } - - /** - * Ends the Application. - * - * <p> - * In effect this will cause the application stop returning any windows when - * asked. When the application is closed, its state is removed from the - * session and the browser window is redirected to the application logout - * url set with {@link #setLogoutURL(String)}. If the logout url has not - * been set, the browser window is reloaded and the application is - * restarted. - * </p> - * . - */ - public void close() { - applicationIsRunning = false; - } - - /** - * Starts the application on the given URL. - * - * <p> - * This method is called by Vaadin framework when a user navigates to the - * application. After this call the application corresponds to the given URL - * and it will return windows when asked for them. There is no need to call - * this method directly. - * </p> - * - * <p> - * Application properties are defined by servlet configuration object - * {@link javax.servlet.ServletConfig} and they are overridden by - * context-wide initialization parameters - * {@link javax.servlet.ServletContext}. - * </p> - * - * @param event - * the application start event containing details required for - * starting the application. - * - */ - public void start(ApplicationStartEvent event) { - applicationUrl = event.getApplicationUrl(); - productionMode = event.isProductionMode(); - properties = event.getApplicationProperties(); - context = event.getContext(); - init(); - applicationIsRunning = true; - } - - /** - * Tests if the application is running or if it has been finished. - * - * <p> - * Application starts running when its - * {@link #start(URL, Properties, ApplicationContext)} method has been - * called and stops when the {@link #close()} is called. - * </p> - * - * @return <code>true</code> if the application is running, - * <code>false</code> if not. - */ - public boolean isRunning() { - return applicationIsRunning; - } - - /** - * <p> - * Main initializer of the application. The <code>init</code> method is - * called by the framework when the application is started, and it should - * perform whatever initialization operations the application needs. - * </p> - */ - public void init() { - // Default implementation does nothing - } - - /** - * Returns an enumeration of all the names in this application. - * - * <p> - * See {@link #start(URL, Properties, ApplicationContext)} how properties - * are defined. - * </p> - * - * @return an enumeration of all the keys in this property list, including - * the keys in the default property list. - * - */ - public Enumeration<?> getPropertyNames() { - return properties.propertyNames(); - } - - /** - * Searches for the property with the specified name in this application. - * This method returns <code>null</code> if the property is not found. - * - * See {@link #start(URL, Properties, ApplicationContext)} how properties - * are defined. - * - * @param name - * the name of the property. - * @return the value in this property list with the specified key value. - */ - public String getProperty(String name) { - return properties.getProperty(name); - } - - /** - * Adds new resource to the application. The resource can be accessed by the - * user of the application. - * - * @param resource - * the resource to add. - */ - public void addResource(ApplicationResource resource) { - - // Check if the resource is already mapped - if (resourceKeyMap.containsKey(resource)) { - return; - } - - // Generate key - final String key = String.valueOf(++lastResourceKeyNumber); - - // Add the resource to mappings - resourceKeyMap.put(resource, key); - keyResourceMap.put(key, resource); - } - - /** - * Removes the resource from the application. - * - * @param resource - * the resource to remove. - */ - public void removeResource(ApplicationResource resource) { - final Object key = resourceKeyMap.get(resource); - if (key != null) { - resourceKeyMap.remove(resource); - keyResourceMap.remove(key); - } - } - - /** - * Gets the relative uri of the resource. This method is intended to be - * called only be the terminal implementation. - * - * This method can only be called from within the processing of a UIDL - * request, not from a background thread. - * - * @param resource - * the resource to get relative location. - * @return the relative uri of the resource or null if called in a - * background thread - * - * @deprecated this method is intended to be used by the terminal only. It - * may be removed or moved in the future. - */ - @Deprecated - public String getRelativeLocation(ApplicationResource resource) { - - // Gets the key - final String key = resourceKeyMap.get(resource); - - // If the resource is not registered, return null - if (key == null) { - return null; - } - - return context.generateApplicationResourceURL(resource, key); - } - - /** - * Gets the default locale for this application. - * - * By default this is the preferred locale of the user using the - * application. In most cases it is read from the browser defaults. - * - * @return the locale of this application. - */ - public Locale getLocale() { - if (locale != null) { - return locale; - } - return Locale.getDefault(); - } - - /** - * Sets the default locale for this application. - * - * By default this is the preferred locale of the user using the - * application. In most cases it is read from the browser defaults. - * - * @param locale - * the Locale object. - * - */ - public void setLocale(Locale locale) { - this.locale = locale; - } - - /** - * <p> - * An event that characterizes a change in the current selection. - * </p> - * Application user change event sent when the setUser is called to change - * the current user of the application. - * - * @version - * @VERSION@ - * @since 3.0 - */ - public class UserChangeEvent extends java.util.EventObject { - - /** - * New user of the application. - */ - private final Object newUser; - - /** - * Previous user of the application. - */ - private final Object prevUser; - - /** - * Constructor for user change event. - * - * @param source - * the application source. - * @param newUser - * the new User. - * @param prevUser - * the previous User. - */ - public UserChangeEvent(Application source, Object newUser, - Object prevUser) { - super(source); - this.newUser = newUser; - this.prevUser = prevUser; - } - - /** - * Gets the new user of the application. - * - * @return the new User. - */ - public Object getNewUser() { - return newUser; - } - - /** - * Gets the previous user of the application. - * - * @return the previous Vaadin user, if user has not changed ever on - * application it returns <code>null</code> - */ - public Object getPreviousUser() { - return prevUser; - } - - /** - * Gets the application where the user change occurred. - * - * @return the Application. - */ - public Application getApplication() { - return (Application) getSource(); - } - } - - /** - * The <code>UserChangeListener</code> interface for listening application - * user changes. - * - * @version - * @VERSION@ - * @since 3.0 - */ - public interface UserChangeListener extends EventListener, Serializable { - - /** - * The <code>applicationUserChanged</code> method Invoked when the - * application user has changed. - * - * @param event - * the change event. - */ - public void applicationUserChanged(Application.UserChangeEvent event); - } - - /** - * Adds the user change listener. - * - * This allows one to get notification each time {@link #setUser(Object)} is - * called. - * - * @param listener - * the user change listener to add. - */ - public void addListener(UserChangeListener listener) { - if (userChangeListeners == null) { - userChangeListeners = new LinkedList<UserChangeListener>(); - } - userChangeListeners.add(listener); - } - - /** - * Removes the user change listener. - * - * @param listener - * the user change listener to remove. - */ - public void removeListener(UserChangeListener listener) { - if (userChangeListeners == null) { - return; - } - userChangeListeners.remove(listener); - if (userChangeListeners.isEmpty()) { - userChangeListeners = null; - } - } - - /** - * Window detach event. - * - * This event is sent each time a window is removed from the application - * with {@link com.vaadin.Application#removeWindow(Window)}. - */ - public class WindowDetachEvent extends EventObject { - - private final Window window; - - /** - * Creates a event. - * - * @param window - * the Detached window. - */ - public WindowDetachEvent(Window window) { - super(Application.this); - this.window = window; - } - - /** - * Gets the detached window. - * - * @return the detached window. - */ - public Window getWindow() { - return window; - } - - /** - * Gets the application from which the window was detached. - * - * @return the Application. - */ - public Application getApplication() { - return (Application) getSource(); - } - } - - /** - * Window attach event. - * - * This event is sent each time a window is attached tothe application with - * {@link com.vaadin.Application#addWindow(Window)}. - */ - public class WindowAttachEvent extends EventObject { - - private final Window window; - - /** - * Creates a event. - * - * @param window - * the Attached window. - */ - public WindowAttachEvent(Window window) { - super(Application.this); - this.window = window; - } - - /** - * Gets the attached window. - * - * @return the attached window. - */ - public Window getWindow() { - return window; - } - - /** - * Gets the application to which the window was attached. - * - * @return the Application. - */ - public Application getApplication() { - return (Application) getSource(); - } - } - - /** - * Window attach listener interface. - */ - public interface WindowAttachListener extends Serializable { - - /** - * Window attached - * - * @param event - * the window attach event. - */ - public void windowAttached(WindowAttachEvent event); - } - - /** - * Window detach listener interface. - */ - public interface WindowDetachListener extends Serializable { - - /** - * Window detached. - * - * @param event - * the window detach event. - */ - public void windowDetached(WindowDetachEvent event); - } - - /** - * Returns the URL user is redirected to on application close. If the URL is - * <code>null</code>, the application is closed normally as defined by the - * application running environment. - * <p> - * Desktop application just closes the application window and - * web-application redirects the browser to application main URL. - * </p> - * - * @return the URL. - */ - public String getLogoutURL() { - return logoutURL; - } - - /** - * Sets the URL user is redirected to on application close. If the URL is - * <code>null</code>, the application is closed normally as defined by the - * application running environment: Desktop application just closes the - * application window and web-application redirects the browser to - * application main URL. - * - * @param logoutURL - * the logoutURL to set. - */ - public void setLogoutURL(String logoutURL) { - this.logoutURL = logoutURL; - } - - /** - * Gets the SystemMessages for this application. SystemMessages are used to - * notify the user of various critical situations that can occur, such as - * session expiration, client/server out of sync, and internal server error. - * - * You can customize the messages by "overriding" this method and returning - * {@link CustomizedSystemMessages}. To "override" this method, re-implement - * this method in your application (the class that extends - * {@link Application}). Even though overriding static methods is not - * possible in Java, Vaadin selects to call the static method from the - * subclass instead of the original {@link #getSystemMessages()} if such a - * method exists. - * - * @return the SystemMessages for this application - */ - public static SystemMessages getSystemMessages() { - return DEFAULT_SYSTEM_MESSAGES; - } - - /** - * <p> - * Invoked by the terminal on any exception that occurs in application and - * is thrown by the <code>setVariable</code> to the terminal. The default - * implementation sets the exceptions as <code>ComponentErrors</code> to the - * component that initiated the exception and prints stack trace to standard - * error stream. - * </p> - * <p> - * You can safely override this method in your application in order to - * direct the errors to some other destination (for example log). - * </p> - * - * @param event - * the change event. - * @see com.vaadin.terminal.Terminal.ErrorListener#terminalError(com.vaadin.terminal.Terminal.ErrorEvent) - */ - - @Override - public void terminalError(Terminal.ErrorEvent event) { - final Throwable t = event.getThrowable(); - if (t instanceof SocketException) { - // Most likely client browser closed socket - getLogger().info( - "SocketException in CommunicationManager." - + " Most likely client (browser) closed socket."); - return; - } - - // Finds the original source of the error/exception - Object owner = null; - if (event instanceof VariableOwner.ErrorEvent) { - owner = ((VariableOwner.ErrorEvent) event).getVariableOwner(); - } else if (event instanceof ChangeVariablesErrorEvent) { - owner = ((ChangeVariablesErrorEvent) event).getComponent(); - } - - // Shows the error in AbstractComponent - if (owner instanceof AbstractComponent) { - ((AbstractComponent) owner).setComponentError(AbstractErrorMessage - .getErrorMessageForException(t)); - } - - // also print the error on console - getLogger().log(Level.SEVERE, "Terminal error:", t); - } - - /** - * Gets the application context. - * <p> - * The application context is the environment where the application is - * running in. The actual implementation class of may contains quite a lot - * more functionality than defined in the {@link ApplicationContext} - * interface. - * </p> - * <p> - * By default, when you are deploying your application to a servlet - * container, the implementation class is {@link WebApplicationContext} - - * you can safely cast to this class and use the methods from there. When - * you are deploying your application as a portlet, context implementation - * is {@link PortletApplicationContext}. - * </p> - * - * @return the application context. - */ - public ApplicationContext getContext() { - return context; - } - - /** - * Override this method to return correct version number of your - * Application. Version information is delivered for example to Testing - * Tools test results. By default this returns a string "NONVERSIONED". - * - * @return version string - */ - public String getVersion() { - return "NONVERSIONED"; - } - - /** - * Gets the application error handler. - * - * The default error handler is the application itself. - * - * @return Application error handler - */ - public Terminal.ErrorListener getErrorHandler() { - return errorHandler; - } - - /** - * Sets the application error handler. - * - * The default error handler is the application itself. By overriding this, - * you can redirect the error messages to your selected target (log for - * example). - * - * @param errorHandler - */ - public void setErrorHandler(Terminal.ErrorListener errorHandler) { - this.errorHandler = errorHandler; - } - - /** - * Gets the {@link ConverterFactory} used to locate a suitable - * {@link Converter} for fields in the application. - * - * See {@link #setConverterFactory(ConverterFactory)} for more details - * - * @return The converter factory used in the application - */ - public ConverterFactory getConverterFactory() { - return converterFactory; - } - - /** - * Sets the {@link ConverterFactory} used to locate a suitable - * {@link Converter} for fields in the application. - * <p> - * The {@link ConverterFactory} is used to find a suitable converter when - * binding data to a UI component and the data type does not match the UI - * component type, e.g. binding a Double to a TextField (which is based on a - * String). - * </p> - * <p> - * The {@link Converter} for an individual field can be overridden using - * {@link AbstractField#setConverter(Converter)} and for individual property - * ids in a {@link Table} using - * {@link Table#setConverter(Object, Converter)}. - * </p> - * <p> - * The converter factory must never be set to null. - * - * @param converterFactory - * The converter factory used in the application - */ - public void setConverterFactory(ConverterFactory converterFactory) { - this.converterFactory = converterFactory; - } - - /** - * Contains the system messages used to notify the user about various - * critical situations that can occur. - * <p> - * Customize by overriding the static - * {@link Application#getSystemMessages()} and returning - * {@link CustomizedSystemMessages}. - * </p> - * <p> - * The defaults defined in this class are: - * <ul> - * <li><b>sessionExpiredURL</b> = null</li> - * <li><b>sessionExpiredNotificationEnabled</b> = true</li> - * <li><b>sessionExpiredCaption</b> = ""</li> - * <li><b>sessionExpiredMessage</b> = - * "Take note of any unsaved data, and <u>click here</u> to continue."</li> - * <li><b>communicationErrorURL</b> = null</li> - * <li><b>communicationErrorNotificationEnabled</b> = true</li> - * <li><b>communicationErrorCaption</b> = "Communication problem"</li> - * <li><b>communicationErrorMessage</b> = - * "Take note of any unsaved data, and <u>click here</u> to continue."</li> - * <li><b>internalErrorURL</b> = null</li> - * <li><b>internalErrorNotificationEnabled</b> = true</li> - * <li><b>internalErrorCaption</b> = "Internal error"</li> - * <li><b>internalErrorMessage</b> = "Please notify the administrator.<br/> - * Take note of any unsaved data, and <u>click here</u> to continue."</li> - * <li><b>outOfSyncURL</b> = null</li> - * <li><b>outOfSyncNotificationEnabled</b> = true</li> - * <li><b>outOfSyncCaption</b> = "Out of sync"</li> - * <li><b>outOfSyncMessage</b> = "Something has caused us to be out of sync - * with the server.<br/> - * Take note of any unsaved data, and <u>click here</u> to re-sync."</li> - * <li><b>cookiesDisabledURL</b> = null</li> - * <li><b>cookiesDisabledNotificationEnabled</b> = true</li> - * <li><b>cookiesDisabledCaption</b> = "Cookies disabled"</li> - * <li><b>cookiesDisabledMessage</b> = "This application requires cookies to - * function.<br/> - * Please enable cookies in your browser and <u>click here</u> to try again. - * </li> - * </ul> - * </p> - * - */ - public static class SystemMessages implements Serializable { - protected String sessionExpiredURL = null; - protected boolean sessionExpiredNotificationEnabled = true; - protected String sessionExpiredCaption = "Session Expired"; - protected String sessionExpiredMessage = "Take note of any unsaved data, and <u>click here</u> to continue."; - - protected String communicationErrorURL = null; - protected boolean communicationErrorNotificationEnabled = true; - protected String communicationErrorCaption = "Communication problem"; - protected String communicationErrorMessage = "Take note of any unsaved data, and <u>click here</u> to continue."; - - protected String authenticationErrorURL = null; - protected boolean authenticationErrorNotificationEnabled = true; - protected String authenticationErrorCaption = "Authentication problem"; - protected String authenticationErrorMessage = "Take note of any unsaved data, and <u>click here</u> to continue."; - - protected String internalErrorURL = null; - protected boolean internalErrorNotificationEnabled = true; - protected String internalErrorCaption = "Internal error"; - protected String internalErrorMessage = "Please notify the administrator.<br/>Take note of any unsaved data, and <u>click here</u> to continue."; - - protected String outOfSyncURL = null; - protected boolean outOfSyncNotificationEnabled = true; - protected String outOfSyncCaption = "Out of sync"; - protected String outOfSyncMessage = "Something has caused us to be out of sync with the server.<br/>Take note of any unsaved data, and <u>click here</u> to re-sync."; - - protected String cookiesDisabledURL = null; - protected boolean cookiesDisabledNotificationEnabled = true; - protected String cookiesDisabledCaption = "Cookies disabled"; - protected String cookiesDisabledMessage = "This application requires cookies to function.<br/>Please enable cookies in your browser and <u>click here</u> to try again."; - - /** - * Use {@link CustomizedSystemMessages} to customize - */ - private SystemMessages() { - - } - - /** - * @return null to indicate that the application will be restarted after - * session expired message has been shown. - */ - public String getSessionExpiredURL() { - return sessionExpiredURL; - } - - /** - * @return true to show session expiration message. - */ - public boolean isSessionExpiredNotificationEnabled() { - return sessionExpiredNotificationEnabled; - } - - /** - * @return "" to show no caption. - */ - public String getSessionExpiredCaption() { - return (sessionExpiredNotificationEnabled ? sessionExpiredCaption - : null); - } - - /** - * @return - * "Take note of any unsaved data, and <u>click here</u> to continue." - */ - public String getSessionExpiredMessage() { - return (sessionExpiredNotificationEnabled ? sessionExpiredMessage - : null); - } - - /** - * @return null to reload the application after communication error - * message. - */ - public String getCommunicationErrorURL() { - return communicationErrorURL; - } - - /** - * @return true to show the communication error message. - */ - public boolean isCommunicationErrorNotificationEnabled() { - return communicationErrorNotificationEnabled; - } - - /** - * @return "Communication problem" - */ - public String getCommunicationErrorCaption() { - return (communicationErrorNotificationEnabled ? communicationErrorCaption - : null); - } - - /** - * @return - * "Take note of any unsaved data, and <u>click here</u> to continue." - */ - public String getCommunicationErrorMessage() { - return (communicationErrorNotificationEnabled ? communicationErrorMessage - : null); - } - - /** - * @return null to reload the application after authentication error - * message. - */ - public String getAuthenticationErrorURL() { - return authenticationErrorURL; - } - - /** - * @return true to show the authentication error message. - */ - public boolean isAuthenticationErrorNotificationEnabled() { - return authenticationErrorNotificationEnabled; - } - - /** - * @return "Authentication problem" - */ - public String getAuthenticationErrorCaption() { - return (authenticationErrorNotificationEnabled ? authenticationErrorCaption - : null); - } - - /** - * @return - * "Take note of any unsaved data, and <u>click here</u> to continue." - */ - public String getAuthenticationErrorMessage() { - return (authenticationErrorNotificationEnabled ? authenticationErrorMessage - : null); - } - - /** - * @return null to reload the current URL after internal error message - * has been shown. - */ - public String getInternalErrorURL() { - return internalErrorURL; - } - - /** - * @return true to enable showing of internal error message. - */ - public boolean isInternalErrorNotificationEnabled() { - return internalErrorNotificationEnabled; - } - - /** - * @return "Internal error" - */ - public String getInternalErrorCaption() { - return (internalErrorNotificationEnabled ? internalErrorCaption - : null); - } - - /** - * @return "Please notify the administrator.<br/> - * Take note of any unsaved data, and <u>click here</u> to - * continue." - */ - public String getInternalErrorMessage() { - return (internalErrorNotificationEnabled ? internalErrorMessage - : null); - } - - /** - * @return null to reload the application after out of sync message. - */ - public String getOutOfSyncURL() { - return outOfSyncURL; - } - - /** - * @return true to enable showing out of sync message - */ - public boolean isOutOfSyncNotificationEnabled() { - return outOfSyncNotificationEnabled; - } - - /** - * @return "Out of sync" - */ - public String getOutOfSyncCaption() { - return (outOfSyncNotificationEnabled ? outOfSyncCaption : null); - } - - /** - * @return "Something has caused us to be out of sync with the server.<br/> - * Take note of any unsaved data, and <u>click here</u> to - * re-sync." - */ - public String getOutOfSyncMessage() { - return (outOfSyncNotificationEnabled ? outOfSyncMessage : null); - } - - /** - * Returns the URL the user should be redirected to after dismissing the - * "you have to enable your cookies" message. Typically null. - * - * @return A URL the user should be redirected to after dismissing the - * message or null to reload the current URL. - */ - public String getCookiesDisabledURL() { - return cookiesDisabledURL; - } - - /** - * Determines if "cookies disabled" messages should be shown to the end - * user or not. If the notification is disabled the user will be - * immediately redirected to the URL returned by - * {@link #getCookiesDisabledURL()}. - * - * @return true to show "cookies disabled" messages to the end user, - * false to redirect to the given URL directly - */ - public boolean isCookiesDisabledNotificationEnabled() { - return cookiesDisabledNotificationEnabled; - } - - /** - * Returns the caption of the message shown to the user when cookies are - * disabled in the browser. - * - * @return The caption of the "cookies disabled" message - */ - public String getCookiesDisabledCaption() { - return (cookiesDisabledNotificationEnabled ? cookiesDisabledCaption - : null); - } - - /** - * Returns the message shown to the user when cookies are disabled in - * the browser. - * - * @return The "cookies disabled" message - */ - public String getCookiesDisabledMessage() { - return (cookiesDisabledNotificationEnabled ? cookiesDisabledMessage - : null); - } - - } - - /** - * Contains the system messages used to notify the user about various - * critical situations that can occur. - * <p> - * Vaadin gets the SystemMessages from your application by calling a static - * getSystemMessages() method. By default the - * Application.getSystemMessages() is used. You can customize this by - * defining a static MyApplication.getSystemMessages() and returning - * CustomizedSystemMessages. Note that getSystemMessages() is static - - * changing the system messages will by default change the message for all - * users of the application. - * </p> - * <p> - * The default behavior is to show a notification, and restart the - * application the the user clicks the message. <br/> - * Instead of restarting the application, you can set a specific URL that - * the user is taken to.<br/> - * Setting both caption and message to null will restart the application (or - * go to the specified URL) without displaying a notification. - * set*NotificationEnabled(false) will achieve the same thing. - * </p> - * <p> - * The situations are: - * <li>Session expired: the user session has expired, usually due to - * inactivity.</li> - * <li>Communication error: the client failed to contact the server, or the - * server returned and invalid response.</li> - * <li>Internal error: unhandled critical server error (e.g out of memory, - * database crash) - * <li>Out of sync: the client is not in sync with the server. E.g the user - * opens two windows showing the same application, but the application does - * not support this and uses the same Window instance. When the user makes - * changes in one of the windows - the other window is no longer in sync, - * and (for instance) pressing a button that is no longer present in the UI - * will cause a out-of-sync -situation. - * </p> - */ - - public static class CustomizedSystemMessages extends SystemMessages - implements Serializable { - - /** - * Sets the URL to go to when the session has expired. - * - * @param sessionExpiredURL - * the URL to go to, or null to reload current - */ - public void setSessionExpiredURL(String sessionExpiredURL) { - this.sessionExpiredURL = sessionExpiredURL; - } - - /** - * Enables or disables the notification. If disabled, the set URL (or - * current) is loaded directly when next transaction between server and - * client happens. - * - * @param sessionExpiredNotificationEnabled - * true = enabled, false = disabled - */ - public void setSessionExpiredNotificationEnabled( - boolean sessionExpiredNotificationEnabled) { - this.sessionExpiredNotificationEnabled = sessionExpiredNotificationEnabled; - } - - /** - * Sets the caption of the notification. Set to null for no caption. If - * both caption and message are null, client automatically forwards to - * sessionExpiredUrl after timeout timer expires. Timer uses value read - * from HTTPSession.getMaxInactiveInterval() - * - * @param sessionExpiredCaption - * the caption - */ - public void setSessionExpiredCaption(String sessionExpiredCaption) { - this.sessionExpiredCaption = sessionExpiredCaption; - } - - /** - * Sets the message of the notification. Set to null for no message. If - * both caption and message are null, client automatically forwards to - * sessionExpiredUrl after timeout timer expires. Timer uses value read - * from HTTPSession.getMaxInactiveInterval() - * - * @param sessionExpiredMessage - * the message - */ - public void setSessionExpiredMessage(String sessionExpiredMessage) { - this.sessionExpiredMessage = sessionExpiredMessage; - } - - /** - * Sets the URL to go to when there is a authentication error. - * - * @param authenticationErrorURL - * the URL to go to, or null to reload current - */ - public void setAuthenticationErrorURL(String authenticationErrorURL) { - this.authenticationErrorURL = authenticationErrorURL; - } - - /** - * Enables or disables the notification. If disabled, the set URL (or - * current) is loaded directly. - * - * @param authenticationErrorNotificationEnabled - * true = enabled, false = disabled - */ - public void setAuthenticationErrorNotificationEnabled( - boolean authenticationErrorNotificationEnabled) { - this.authenticationErrorNotificationEnabled = authenticationErrorNotificationEnabled; - } - - /** - * Sets the caption of the notification. Set to null for no caption. If - * both caption and message is null, the notification is disabled; - * - * @param authenticationErrorCaption - * the caption - */ - public void setAuthenticationErrorCaption( - String authenticationErrorCaption) { - this.authenticationErrorCaption = authenticationErrorCaption; - } - - /** - * Sets the message of the notification. Set to null for no message. If - * both caption and message is null, the notification is disabled; - * - * @param authenticationErrorMessage - * the message - */ - public void setAuthenticationErrorMessage( - String authenticationErrorMessage) { - this.authenticationErrorMessage = authenticationErrorMessage; - } - - /** - * Sets the URL to go to when there is a communication error. - * - * @param communicationErrorURL - * the URL to go to, or null to reload current - */ - public void setCommunicationErrorURL(String communicationErrorURL) { - this.communicationErrorURL = communicationErrorURL; - } - - /** - * Enables or disables the notification. If disabled, the set URL (or - * current) is loaded directly. - * - * @param communicationErrorNotificationEnabled - * true = enabled, false = disabled - */ - public void setCommunicationErrorNotificationEnabled( - boolean communicationErrorNotificationEnabled) { - this.communicationErrorNotificationEnabled = communicationErrorNotificationEnabled; - } - - /** - * Sets the caption of the notification. Set to null for no caption. If - * both caption and message is null, the notification is disabled; - * - * @param communicationErrorCaption - * the caption - */ - public void setCommunicationErrorCaption( - String communicationErrorCaption) { - this.communicationErrorCaption = communicationErrorCaption; - } - - /** - * Sets the message of the notification. Set to null for no message. If - * both caption and message is null, the notification is disabled; - * - * @param communicationErrorMessage - * the message - */ - public void setCommunicationErrorMessage( - String communicationErrorMessage) { - this.communicationErrorMessage = communicationErrorMessage; - } - - /** - * Sets the URL to go to when an internal error occurs. - * - * @param internalErrorURL - * the URL to go to, or null to reload current - */ - public void setInternalErrorURL(String internalErrorURL) { - this.internalErrorURL = internalErrorURL; - } - - /** - * Enables or disables the notification. If disabled, the set URL (or - * current) is loaded directly. - * - * @param internalErrorNotificationEnabled - * true = enabled, false = disabled - */ - public void setInternalErrorNotificationEnabled( - boolean internalErrorNotificationEnabled) { - this.internalErrorNotificationEnabled = internalErrorNotificationEnabled; - } - - /** - * Sets the caption of the notification. Set to null for no caption. If - * both caption and message is null, the notification is disabled; - * - * @param internalErrorCaption - * the caption - */ - public void setInternalErrorCaption(String internalErrorCaption) { - this.internalErrorCaption = internalErrorCaption; - } - - /** - * Sets the message of the notification. Set to null for no message. If - * both caption and message is null, the notification is disabled; - * - * @param internalErrorMessage - * the message - */ - public void setInternalErrorMessage(String internalErrorMessage) { - this.internalErrorMessage = internalErrorMessage; - } - - /** - * Sets the URL to go to when the client is out-of-sync. - * - * @param outOfSyncURL - * the URL to go to, or null to reload current - */ - public void setOutOfSyncURL(String outOfSyncURL) { - this.outOfSyncURL = outOfSyncURL; - } - - /** - * Enables or disables the notification. If disabled, the set URL (or - * current) is loaded directly. - * - * @param outOfSyncNotificationEnabled - * true = enabled, false = disabled - */ - public void setOutOfSyncNotificationEnabled( - boolean outOfSyncNotificationEnabled) { - this.outOfSyncNotificationEnabled = outOfSyncNotificationEnabled; - } - - /** - * Sets the caption of the notification. Set to null for no caption. If - * both caption and message is null, the notification is disabled; - * - * @param outOfSyncCaption - * the caption - */ - public void setOutOfSyncCaption(String outOfSyncCaption) { - this.outOfSyncCaption = outOfSyncCaption; - } - - /** - * Sets the message of the notification. Set to null for no message. If - * both caption and message is null, the notification is disabled; - * - * @param outOfSyncMessage - * the message - */ - public void setOutOfSyncMessage(String outOfSyncMessage) { - this.outOfSyncMessage = outOfSyncMessage; - } - - /** - * Sets the URL to redirect to when the browser has cookies disabled. - * - * @param cookiesDisabledURL - * the URL to redirect to, or null to reload the current URL - */ - public void setCookiesDisabledURL(String cookiesDisabledURL) { - this.cookiesDisabledURL = cookiesDisabledURL; - } - - /** - * Enables or disables the notification for "cookies disabled" messages. - * If disabled, the URL returned by {@link #getCookiesDisabledURL()} is - * loaded directly. - * - * @param cookiesDisabledNotificationEnabled - * true to enable "cookies disabled" messages, false - * otherwise - */ - public void setCookiesDisabledNotificationEnabled( - boolean cookiesDisabledNotificationEnabled) { - this.cookiesDisabledNotificationEnabled = cookiesDisabledNotificationEnabled; - } - - /** - * Sets the caption of the "cookies disabled" notification. Set to null - * for no caption. If both caption and message is null, the notification - * is disabled. - * - * @param cookiesDisabledCaption - * the caption for the "cookies disabled" notification - */ - public void setCookiesDisabledCaption(String cookiesDisabledCaption) { - this.cookiesDisabledCaption = cookiesDisabledCaption; - } - - /** - * Sets the message of the "cookies disabled" notification. Set to null - * for no message. If both caption and message is null, the notification - * is disabled. - * - * @param cookiesDisabledMessage - * the message for the "cookies disabled" notification - */ - public void setCookiesDisabledMessage(String cookiesDisabledMessage) { - this.cookiesDisabledMessage = cookiesDisabledMessage; - } - - } - - /** - * Application error is an error message defined on the application level. - * - * When an error occurs on the application level, this error message type - * should be used. This indicates that the problem is caused by the - * application - not by the user. - */ - public class ApplicationError implements Terminal.ErrorEvent { - private final Throwable throwable; - - public ApplicationError(Throwable throwable) { - this.throwable = throwable; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - } - - /** - * Gets a root for a request for which no root is already known. This method - * is called when the framework processes a request that does not originate - * from an existing root instance. This typically happens when a host page - * is requested. - * - * <p> - * Subclasses of Application may override this method to provide custom - * logic for choosing how to create a suitable root or for picking an - * already created root. If an existing root is picked, care should be taken - * to avoid keeping the same root open in multiple browser windows, as that - * will cause the states to go out of sync. - * </p> - * - * <p> - * If {@link BrowserDetails} are required to create a Root, the - * implementation can throw a {@link RootRequiresMoreInformationException} - * exception. In this case, the framework will instruct the browser to send - * the additional details, whereupon this method is invoked again with the - * browser details present in the wrapped request. Throwing the exception if - * the browser details are already available is not supported. - * </p> - * - * <p> - * The default implementation in {@link Application} creates a new instance - * of the Root class returned by {@link #getRootClassName(WrappedRequest)}, - * which in turn uses the {@value #ROOT_PARAMETER} parameter from web.xml. - * If {@link DeploymentConfiguration#getClassLoader()} for the request - * returns a {@link ClassLoader}, it is used for loading the Root class. - * Otherwise the {@link ClassLoader} used to load this class is used. - * </p> - * - * @param request - * the wrapped request for which a root is needed - * @return a root instance to use for the request - * @throws RootRequiresMoreInformationException - * may be thrown by an implementation to indicate that - * {@link BrowserDetails} are required to create a root - * - * @see #getRootClassName(WrappedRequest) - * @see Root - * @see RootRequiresMoreInformationException - * @see WrappedRequest#getBrowserDetails() - * - * @since 7.0 - */ - protected Root getRoot(WrappedRequest request) - throws RootRequiresMoreInformationException { - String rootClassName = getRootClassName(request); - try { - ClassLoader classLoader = request.getDeploymentConfiguration() - .getClassLoader(); - if (classLoader == null) { - classLoader = getClass().getClassLoader(); - } - Class<? extends Root> rootClass = Class.forName(rootClassName, - true, classLoader).asSubclass(Root.class); - try { - Root root = rootClass.newInstance(); - return root; - } catch (Exception e) { - throw new RuntimeException("Could not instantiate root class " - + rootClassName, e); - } - } catch (ClassNotFoundException e) { - throw new RuntimeException("Could not load root class " - + rootClassName, e); - } - } - - /** - * Provides the name of the <code>Root</code> class that should be used for - * a request. The class must have an accessible no-args constructor. - * <p> - * The default implementation uses the {@value #ROOT_PARAMETER} parameter - * from web.xml. - * </p> - * <p> - * This method is mainly used by the default implementation of - * {@link #getRoot(WrappedRequest)}. If you override that method with your - * own functionality, the results of this method might not be used. - * </p> - * - * @param request - * the request for which a new root is required - * @return the name of the root class to use - * - * @since 7.0 - */ - protected String getRootClassName(WrappedRequest request) { - Object rootClassNameObj = properties.get(ROOT_PARAMETER); - if (rootClassNameObj instanceof String) { - return (String) rootClassNameObj; - } else { - throw new RuntimeException("No " + ROOT_PARAMETER - + " defined in web.xml"); - } - } - - /** - * Finds the theme to use for a specific root. If no specific theme is - * required, <code>null</code> is returned. - * - * TODO Tell what the default implementation does once it does something. - * - * @param root - * the root to get a theme for - * @return the name of the theme, or <code>null</code> if the default theme - * should be used - * - * @since 7.0 - */ - public String getThemeForRoot(Root root) { - Theme rootTheme = getAnnotationFor(root.getClass(), Theme.class); - if (rootTheme != null) { - return rootTheme.value(); - } else { - return null; - } - } - - /** - * Finds the widgetset to use for a specific root. If no specific widgetset - * is required, <code>null</code> is returned. - * - * TODO Tell what the default implementation does once it does something. - * - * @param root - * the root to get a widgetset for - * @return the name of the widgetset, or <code>null</code> if the default - * widgetset should be used - * - * @since 7.0 - */ - public String getWidgetsetForRoot(Root root) { - Widgetset rootWidgetset = getAnnotationFor(root.getClass(), - Widgetset.class); - if (rootWidgetset != null) { - return rootWidgetset.value(); - } else { - return null; - } - } - - /** - * Helper to get an annotation for a class. If the annotation is not present - * on the target class, it's superclasses and implemented interfaces are - * also searched for the annotation. - * - * @param type - * the target class from which the annotation should be found - * @param annotationType - * the annotation type to look for - * @return an annotation of the given type, or <code>null</code> if the - * annotation is not present on the class - */ - private static <T extends Annotation> T getAnnotationFor(Class<?> type, - Class<T> annotationType) { - // Find from the class hierarchy - Class<?> currentType = type; - while (currentType != Object.class) { - T annotation = currentType.getAnnotation(annotationType); - if (annotation != null) { - return annotation; - } else { - currentType = currentType.getSuperclass(); - } - } - - // Find from an implemented interface - for (Class<?> iface : type.getInterfaces()) { - T annotation = iface.getAnnotation(annotationType); - if (annotation != null) { - return annotation; - } - } - - return null; - } - - /** - * Handles a request by passing it to each registered {@link RequestHandler} - * in turn until one produces a response. This method is used for requests - * that have not been handled by any specific functionality in the terminal - * implementation (e.g. {@link AbstractApplicationServlet}). - * <p> - * The request handlers are invoked in the revere order in which they were - * added to the application until a response has been produced. This means - * that the most recently added handler is used first and the first request - * handler that was added to the application is invoked towards the end - * unless any previous handler has already produced a response. - * </p> - * - * @param request - * the wrapped request to get information from - * @param response - * the response to which data can be written - * @return returns <code>true</code> if a {@link RequestHandler} has - * produced a response and <code>false</code> if no response has - * been written. - * @throws IOException - * - * @see #addRequestHandler(RequestHandler) - * @see RequestHandler - * - * @since 7.0 - */ - public boolean handleRequest(WrappedRequest request, - WrappedResponse response) throws IOException { - // Use a copy to avoid ConcurrentModificationException - for (RequestHandler handler : new ArrayList<RequestHandler>( - requestHandlers)) { - if (handler.handleRequest(this, request, response)) { - return true; - } - } - // If not handled - return false; - } - - /** - * Adds a request handler to this application. Request handlers can be added - * to provide responses to requests that are not handled by the default - * functionality of the framework. - * <p> - * Handlers are called in reverse order of addition, so the most recently - * added handler will be called first. - * </p> - * - * @param handler - * the request handler to add - * - * @see #handleRequest(WrappedRequest, WrappedResponse) - * @see #removeRequestHandler(RequestHandler) - * - * @since 7.0 - */ - public void addRequestHandler(RequestHandler handler) { - requestHandlers.addFirst(handler); - } - - /** - * Removes a request handler from the application. - * - * @param handler - * the request handler to remove - * - * @since 7.0 - */ - public void removeRequestHandler(RequestHandler handler) { - requestHandlers.remove(handler); - } - - /** - * Gets the request handlers that are registered to the application. The - * iteration order of the returned collection is the same as the order in - * which the request handlers will be invoked when a request is handled. - * - * @return a collection of request handlers, with the iteration order - * according to the order they would be invoked - * - * @see #handleRequest(WrappedRequest, WrappedResponse) - * @see #addRequestHandler(RequestHandler) - * @see #removeRequestHandler(RequestHandler) - * - * @since 7.0 - */ - public Collection<RequestHandler> getRequestHandlers() { - return Collections.unmodifiableCollection(requestHandlers); - } - - /** - * Find an application resource with a given key. - * - * @param key - * The key of the resource - * @return The application resource corresponding to the provided key, or - * <code>null</code> if no resource is registered for the key - * - * @since 7.0 - */ - public ApplicationResource getResource(String key) { - return keyResourceMap.get(key); - } - - /** - * Thread local for keeping track of currently used application instance - * - * @since 7.0 - */ - private static final ThreadLocal<Application> currentApplication = new ThreadLocal<Application>(); - - private boolean rootPreserved = false; - - /** - * Gets the currently used application. The current application is - * automatically defined when processing requests to the server. In other - * cases, (e.g. from background threads), the current application is not - * automatically defined. - * - * @return the current application instance if available, otherwise - * <code>null</code> - * - * @see #setCurrent(Application) - * - * @since 7.0 - */ - public static Application getCurrent() { - return currentApplication.get(); - } - - /** - * Sets the thread local for the current application. This method is used by - * the framework to set the current application whenever a new request is - * processed and it is cleared when the request has been processed. - * <p> - * The application developer can also use this method to define the current - * application outside the normal request handling, e.g. when initiating - * custom background threads. - * </p> - * - * @param application - * - * @see #getCurrent() - * @see ThreadLocal - * - * @since 7.0 - */ - public static void setCurrent(Application application) { - currentApplication.set(application); - } - - /** - * Check whether this application is in production mode. If an application - * is in production mode, certain debugging facilities are not available. - * - * @return the status of the production mode flag - * - * @since 7.0 - */ - public boolean isProductionMode() { - return productionMode; - } - - /** - * Finds the {@link Root} to which a particular request belongs. If the - * request originates from an existing Root, that root is returned. In other - * cases, the method attempts to create and initialize a new root and might - * throw a {@link RootRequiresMoreInformationException} if all required - * information is not available. - * <p> - * Please note that this method can also return a newly created - * <code>Root</code> which has not yet been initialized. You can use - * {@link #isRootInitPending(int)} with the root's id ( - * {@link Root#getRootId()} to check whether the initialization is still - * pending. - * </p> - * - * @param request - * the request for which a root is desired - * @return a root belonging to the request - * @throws RootRequiresMoreInformationException - * if no existing root could be found and creating a new root - * requires additional information from the browser - * - * @see #getRoot(WrappedRequest) - * @see RootRequiresMoreInformationException - * - * @since 7.0 - */ - public Root getRootForRequest(WrappedRequest request) - throws RootRequiresMoreInformationException { - Root root = Root.getCurrent(); - if (root != null) { - return root; - } - Integer rootId = getRootId(request); - - synchronized (this) { - BrowserDetails browserDetails = request.getBrowserDetails(); - boolean hasBrowserDetails = browserDetails != null - && browserDetails.getUriFragment() != null; - - root = roots.get(rootId); - - if (root == null && isRootPreserved()) { - // Check for a known root - if (!retainOnRefreshRoots.isEmpty()) { - - Integer retainedRootId; - if (!hasBrowserDetails) { - throw new RootRequiresMoreInformationException(); - } else { - String windowName = browserDetails.getWindowName(); - retainedRootId = retainOnRefreshRoots.get(windowName); - } - - if (retainedRootId != null) { - rootId = retainedRootId; - root = roots.get(rootId); - } - } - } - - if (root == null) { - // Throws exception if root can not yet be created - root = getRoot(request); - - // Initialize some fields for a newly created root - if (root.getApplication() == null) { - root.setApplication(this); - } - if (root.getRootId() < 0) { - - if (rootId == null) { - // Get the next id if none defined - rootId = Integer.valueOf(nextRootId++); - } - root.setRootId(rootId.intValue()); - roots.put(rootId, root); - } - } - - // Set thread local here so it is available in init - Root.setCurrent(root); - - if (!initedRoots.contains(rootId)) { - boolean initRequiresBrowserDetails = isRootPreserved() - || !root.getClass() - .isAnnotationPresent(EagerInit.class); - if (!initRequiresBrowserDetails || hasBrowserDetails) { - root.doInit(request); - - // Remember that this root has been initialized - initedRoots.add(rootId); - - // init() might turn on preserve so do this afterwards - if (isRootPreserved()) { - // Remember this root - String windowName = request.getBrowserDetails() - .getWindowName(); - retainOnRefreshRoots.put(windowName, rootId); - } - } - } - } // end synchronized block - - return root; - } - - /** - * Internal helper to finds the root id for a request. - * - * @param request - * the request to get the root id for - * @return a root id, or <code>null</code> if no root id is defined - * - * @since 7.0 - */ - private static Integer getRootId(WrappedRequest request) { - if (request instanceof CombinedRequest) { - // Combined requests has the rootid parameter in the second request - CombinedRequest combinedRequest = (CombinedRequest) request; - request = combinedRequest.getSecondRequest(); - } - String rootIdString = request - .getParameter(ApplicationConnection.ROOT_ID_PARAMETER); - Integer rootId = rootIdString == null ? null - : new Integer(rootIdString); - return rootId; - } - - /** - * Sets whether the same Root state should be reused if the framework can - * detect that the application is opened in a browser window where it has - * previously been open. The framework attempts to discover this by checking - * the value of window.name in the browser. - * <p> - * NOTE that you should avoid turning this feature on/off on-the-fly when - * the UI is already shown, as it might not be retained as intended. - * </p> - * - * @param rootPreserved - * <code>true</code>if the same Root instance should be reused - * e.g. when the browser window is refreshed. - */ - public void setRootPreserved(boolean rootPreserved) { - this.rootPreserved = rootPreserved; - if (!rootPreserved) { - retainOnRefreshRoots.clear(); - } - } - - /** - * Checks whether the same Root state should be reused if the framework can - * detect that the application is opened in a browser window where it has - * previously been open. The framework attempts to discover this by checking - * the value of window.name in the browser. - * - * @return <code>true</code>if the same Root instance should be reused e.g. - * when the browser window is refreshed. - */ - public boolean isRootPreserved() { - return rootPreserved; - } - - /** - * Checks whether there's a pending initialization for the root with the - * given id. - * - * @param rootId - * root id to check for - * @return <code>true</code> of the initialization is pending, - * <code>false</code> if the root id is not registered or if the - * root has already been initialized - * - * @see #getRootForRequest(WrappedRequest) - */ - public boolean isRootInitPending(int rootId) { - return !initedRoots.contains(Integer.valueOf(rootId)); - } - - /** - * Gets all the roots of this application. This includes roots that have - * been requested but not yet initialized. Please note, that roots are not - * automatically removed e.g. if the browser window is closed and that there - * is no way to manually remove a root. Inactive roots will thus not be - * released for GC until the entire application is released when the session - * has timed out (unless there are dangling references). Improved support - * for releasing unused roots is planned for an upcoming alpha release of - * Vaadin 7. - * - * @return a collection of roots belonging to this application - * - * @since 7.0 - */ - public Collection<Root> getRoots() { - return Collections.unmodifiableCollection(roots.values()); - } - - private int connectorIdSequence = 0; - - /** - * Generate an id for the given Connector. Connectors must not call this - * method more than once, the first time they need an id. - * - * @param connector - * A connector that has not yet been assigned an id. - * @return A new id for the connector - */ - public String createConnectorId(ClientConnector connector) { - return String.valueOf(connectorIdSequence++); - } - - private static final Logger getLogger() { - return Logger.getLogger(Application.class.getName()); - } - - /** - * Returns a Root with the given id. - * <p> - * This is meant for framework internal use. - * </p> - * - * @param rootId - * The root id - * @return The root with the given id or null if not found - */ - public Root getRootById(int rootId) { - return roots.get(rootId); - } - - public void addBootstrapListener(BootstrapListener listener) { - eventRouter.addListener(BootstrapFragmentResponse.class, listener, - BOOTSTRAP_FRAGMENT_METHOD); - eventRouter.addListener(BootstrapPageResponse.class, listener, - BOOTSTRAP_PAGE_METHOD); - } - - public void removeBootstrapListener(BootstrapListener listener) { - eventRouter.removeListener(BootstrapFragmentResponse.class, listener, - BOOTSTRAP_FRAGMENT_METHOD); - eventRouter.removeListener(BootstrapPageResponse.class, listener, - BOOTSTRAP_PAGE_METHOD); - } - - public void modifyBootstrapResponse(BootstrapResponse response) { - eventRouter.fireEvent(response); - } -} diff --git a/src/com/vaadin/RootRequiresMoreInformationException.java b/src/com/vaadin/RootRequiresMoreInformationException.java deleted file mode 100644 index ed0fa41437..0000000000 --- a/src/com/vaadin/RootRequiresMoreInformationException.java +++ /dev/null @@ -1,25 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin; - -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedRequest.BrowserDetails; - -/** - * Exception that is thrown to indicate that creating or initializing the root - * requires information detailed from the web browser ({@link BrowserDetails}) - * to be present. - * - * This exception may not be thrown if that information is already present in - * the current WrappedRequest. - * - * @see Application#getRoot(WrappedRequest) - * @see WrappedRequest#getBrowserDetails() - * - * @since 7.0 - */ -public class RootRequiresMoreInformationException extends Exception { - // Nothing of interest here -} diff --git a/src/com/vaadin/Vaadin.gwt.xml b/src/com/vaadin/Vaadin.gwt.xml deleted file mode 100644 index 07d7c941e6..0000000000 --- a/src/com/vaadin/Vaadin.gwt.xml +++ /dev/null @@ -1,85 +0,0 @@ -<module> - <!-- This GWT module inherits all Vaadin client side functionality modules. - This is the module you want to inherit in your client side project to be - able to use com.vaadin.* classes. --> - - <!-- Hint for WidgetSetBuilder not to automatically update the file --> - <!-- WS Compiler: manually edited --> - - <inherits name="com.google.gwt.user.User" /> - - <inherits name="com.google.gwt.http.HTTP" /> - - <inherits name="com.google.gwt.json.JSON" /> - - <inherits name="com.vaadin.terminal.gwt.VaadinBrowserSpecificOverrides" /> - - <source path="terminal/gwt/client" /> - <source path="shared" /> - - <!-- Use own Scheduler implementation to be able to track if commands are - running --> - <replace-with class="com.vaadin.terminal.gwt.client.VSchedulerImpl"> - <when-type-is class="com.google.gwt.core.client.impl.SchedulerImpl" /> - </replace-with> - - <!-- Generators for serializators for classes used in communication between - server and client --> - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.SerializerMapGenerator"> - <when-type-is - class="com.vaadin.terminal.gwt.client.communication.SerializerMap" /> - </generate-with> - - <replace-with class="com.vaadin.terminal.gwt.client.VDebugConsole"> - <when-type-is class="com.vaadin.terminal.gwt.client.Console" /> - </replace-with> - - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.EagerWidgetMapGenerator"> - <when-type-is class="com.vaadin.terminal.gwt.client.WidgetMap" /> - </generate-with> - - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.AcceptCriteriaFactoryGenerator"> - <when-type-is - class="com.vaadin.terminal.gwt.client.ui.dd.VAcceptCriterionFactory" /> - </generate-with> - - <!-- Generate client side proxies for client to server RPC interfaces --> - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyGenerator"> - <when-type-assignable - class="com.vaadin.shared.communication.ServerRpc" /> - </generate-with> - - <!-- Generate client side proxies for client to server RPC interfaces --> - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.RpcProxyCreatorGenerator"> - <when-type-assignable - class="com.vaadin.terminal.gwt.client.communication.RpcProxy.RpcProxyCreator" /> - </generate-with> - - <!-- Generate client side RPC manager for server to client RPC --> - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.GeneratedRpcMethodProviderGenerator"> - <when-type-assignable - class="com.vaadin.terminal.gwt.client.communication.GeneratedRpcMethodProvider" /> - </generate-with> - - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.ConnectorWidgetFactoryGenerator"> - <when-type-assignable - class="com.vaadin.terminal.gwt.client.ui.ConnectorWidgetFactory" /> - </generate-with> - - <generate-with - class="com.vaadin.terminal.gwt.widgetsetutils.ConnectorStateFactoryGenerator"> - <when-type-assignable - class="com.vaadin.terminal.gwt.client.ui.ConnectorStateFactory" /> - </generate-with> - - <!-- Use the new cross site linker to get a nocache.js without document.write --> - <add-linker name="xsiframe" /> - -</module> diff --git a/src/com/vaadin/Version.java b/src/com/vaadin/Version.java deleted file mode 100644 index eb6d73e7e0..0000000000 --- a/src/com/vaadin/Version.java +++ /dev/null @@ -1,74 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin; - -import java.io.Serializable; - -public class Version implements Serializable { - /** - * The version number of this release. For example "6.2.0". Always in the - * format "major.minor.revision[.build]". The build part is optional. All of - * major, minor, revision must be integers. - */ - private static final String VERSION; - /** - * Major version number. For example 6 in 6.2.0. - */ - private static final int VERSION_MAJOR; - - /** - * Minor version number. For example 2 in 6.2.0. - */ - private static final int VERSION_MINOR; - - /** - * Version revision number. For example 0 in 6.2.0. - */ - private static final int VERSION_REVISION; - - /** - * Build identifier. For example "nightly-20091123-c9963" in - * 6.2.0.nightly-20091123-c9963. - */ - private static final String VERSION_BUILD; - - /* Initialize version numbers from string replaced by build-script. */ - static { - if ("@VERSION@".equals("@" + "VERSION" + "@")) { - VERSION = "9.9.9.INTERNAL-DEBUG-BUILD"; - } else { - VERSION = "@VERSION@"; - } - final String[] digits = VERSION.split("\\.", 4); - VERSION_MAJOR = Integer.parseInt(digits[0]); - VERSION_MINOR = Integer.parseInt(digits[1]); - VERSION_REVISION = Integer.parseInt(digits[2]); - if (digits.length == 4) { - VERSION_BUILD = digits[3]; - } else { - VERSION_BUILD = ""; - } - } - - public static String getFullVersion() { - return VERSION; - } - - public static int getMajorVersion() { - return VERSION_MAJOR; - } - - public static int getMinorVersion() { - return VERSION_MINOR; - } - - public static int getRevision() { - return VERSION_REVISION; - } - - public static String getBuildIdentifier() { - return VERSION_BUILD; - } - -} diff --git a/src/com/vaadin/annotations/AutoGenerated.java b/src/com/vaadin/annotations/AutoGenerated.java deleted file mode 100644 index 72c9b62a91..0000000000 --- a/src/com/vaadin/annotations/AutoGenerated.java +++ /dev/null @@ -1,18 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.annotations; - -/** - * Marker annotation for automatically generated code elements. - * - * These elements may be modified or removed by code generation. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.0 - */ -public @interface AutoGenerated { - -} diff --git a/src/com/vaadin/annotations/EagerInit.java b/src/com/vaadin/annotations/EagerInit.java deleted file mode 100644 index c7c2702d2a..0000000000 --- a/src/com/vaadin/annotations/EagerInit.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.ui.Root; - -/** - * Indicates that the init method in a Root class can be called before full - * browser details ({@link WrappedRequest#getBrowserDetails()}) are available. - * This will make the UI appear more quickly, as ensuring the availability of - * this information typically requires an additional round trip to the client. - * - * @see Root#init(com.vaadin.terminal.WrappedRequest) - * @see WrappedRequest#getBrowserDetails() - * - * @since 7.0 - * - */ -@Target(ElementType.TYPE) -@Retention(RetentionPolicy.RUNTIME) -public @interface EagerInit { - // No values -} diff --git a/src/com/vaadin/annotations/JavaScript.java b/src/com/vaadin/annotations/JavaScript.java deleted file mode 100644 index 357bcc3649..0000000000 --- a/src/com/vaadin/annotations/JavaScript.java +++ /dev/null @@ -1,41 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.vaadin.terminal.gwt.server.ClientConnector; - -/** - * If this annotation is present on a {@link ClientConnector} class, the - * framework ensures the referenced JavaScript files are loaded before the init - * method for the corresponding client-side connector is invoked. - * <p> - * Absolute URLs including protocol and host are used as is on the client-side. - * Relative urls are mapped to APP/CONNECTOR/[url] which are by default served - * from the classpath relative to the class where the annotation is defined. - * <p> - * Example: {@code @JavaScript( "http://host.com/file1.js", "file2.js"})} on the - * class com.example.MyConnector would load the file http://host.com/file1.js as - * is and file2.js from /com/example/file2.js on the server's classpath using - * the ClassLoader that was used to load com.example.MyConnector. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface JavaScript { - /** - * JavaScript files to load before initializing the client-side connector. - * - * @return an array of JavaScript file urls - */ - public String[] value(); -} diff --git a/src/com/vaadin/annotations/StyleSheet.java b/src/com/vaadin/annotations/StyleSheet.java deleted file mode 100644 index d082cb8d30..0000000000 --- a/src/com/vaadin/annotations/StyleSheet.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.vaadin.terminal.gwt.server.ClientConnector; - -/** - * If this annotation is present on a {@link ClientConnector} class, the - * framework ensures the referenced style sheets are loaded before the init - * method for the corresponding client-side connector is invoked. - * <p> - * Example: {@code @StyleSheet( "http://host.com/file1.css", "file2.css"})} on - * the class com.example.MyConnector would load the file - * http://host.com/file1.css as is and file2.css from /com/example/file2.css on - * the server's classpath using the ClassLoader that was used to load - * com.example.MyConnector. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface StyleSheet { - /** - * Style sheets to load before initializing the client-side connector. - * - * @return an array of style sheet urls - */ - public String[] value(); -} diff --git a/src/com/vaadin/annotations/Theme.java b/src/com/vaadin/annotations/Theme.java deleted file mode 100644 index 7c62b07741..0000000000 --- a/src/com/vaadin/annotations/Theme.java +++ /dev/null @@ -1,24 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.vaadin.ui.Root; - -/** - * Defines a specific theme for a {@link Root}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface Theme { - /** - * @return simple name of the theme - */ - public String value(); -} diff --git a/src/com/vaadin/annotations/Widgetset.java b/src/com/vaadin/annotations/Widgetset.java deleted file mode 100644 index 99113f73f9..0000000000 --- a/src/com/vaadin/annotations/Widgetset.java +++ /dev/null @@ -1,25 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.annotations; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.vaadin.ui.Root; - -/** - * Defines a specific theme for a {@link Root}. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface Widgetset { - /** - * @return name of the widgetset - */ - public String value(); - -} diff --git a/src/com/vaadin/annotations/package.html b/src/com/vaadin/annotations/package.html deleted file mode 100644 index d789e9b5df..0000000000 --- a/src/com/vaadin/annotations/package.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -</head> - -<body bgcolor="white"> - -<p>Contains annotations used in Vaadin. Note that some annotations -are also found in other packages e.g., {@link com.vaadin.ui.ClientWidget}.</p> - -</body> -</html> diff --git a/src/com/vaadin/data/Buffered.java b/src/com/vaadin/data/Buffered.java deleted file mode 100644 index 1387cb965b..0000000000 --- a/src/com/vaadin/data/Buffered.java +++ /dev/null @@ -1,280 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data; - -import java.io.Serializable; - -import com.vaadin.data.Validator.InvalidValueException; - -/** - * <p> - * Defines the interface to commit and discard changes to an object, supporting - * read-through and write-through modes. - * </p> - * - * <p> - * <i>Read-through mode</i> means that the value read from the buffered object - * is constantly up to date with the data source. <i>Write-through</i> mode - * means that all changes to the object are immediately updated to the data - * source. - * </p> - * - * <p> - * Since these modes are independent, their combinations may result in some - * behaviour that may sound surprising. - * </p> - * - * <p> - * For example, if a <code>Buffered</code> object is in read-through mode but - * not in write-through mode, the result is an object whose value is updated - * directly from the data source only if it's not locally modified. If the value - * is locally modified, retrieving the value from the object would result in a - * value that is different than the one stored in the data source, even though - * the object is in read-through mode. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Buffered extends Serializable { - - /** - * Updates all changes since the previous commit to the data source. The - * value stored in the object will always be updated into the data source - * when <code>commit</code> is called. - * - * @throws SourceException - * if the operation fails because of an exception is thrown by - * the data source. The cause is included in the exception. - * @throws InvalidValueException - * if the operation fails because validation is enabled and the - * values do not validate - */ - public void commit() throws SourceException, InvalidValueException; - - /** - * Discards all changes since last commit. The object updates its value from - * the data source. - * - * @throws SourceException - * if the operation fails because of an exception is thrown by - * the data source. The cause is included in the exception. - */ - public void discard() throws SourceException; - - /** - * Tests if the object is in write-through mode. If the object is in - * write-through mode, all modifications to it will result in - * <code>commit</code> being called after the modification. - * - * @return <code>true</code> if the object is in write-through mode, - * <code>false</code> if it's not. - * @deprecated Use {@link #setBuffered(boolean)} instead. Note that - * setReadThrough(true), setWriteThrough(true) equals - * setBuffered(false) - */ - @Deprecated - public boolean isWriteThrough(); - - /** - * Sets the object's write-through mode to the specified status. When - * switching the write-through mode on, the <code>commit</code> operation - * will be performed. - * - * @param writeThrough - * Boolean value to indicate if the object should be in - * write-through mode after the call. - * @throws SourceException - * If the operation fails because of an exception is thrown by - * the data source. - * @throws InvalidValueException - * If the implicit commit operation fails because of a - * validation error. - * - * @deprecated Use {@link #setBuffered(boolean)} instead. Note that - * setReadThrough(true), setWriteThrough(true) equals - * setBuffered(false) - */ - @Deprecated - public void setWriteThrough(boolean writeThrough) throws SourceException, - InvalidValueException; - - /** - * Tests if the object is in read-through mode. If the object is in - * read-through mode, retrieving its value will result in the value being - * first updated from the data source to the object. - * <p> - * The only exception to this rule is that when the object is not in - * write-through mode and it's buffer contains a modified value, the value - * retrieved from the object will be the locally modified value in the - * buffer which may differ from the value in the data source. - * </p> - * - * @return <code>true</code> if the object is in read-through mode, - * <code>false</code> if it's not. - * @deprecated Use {@link #isBuffered(boolean)} instead. Note that - * setReadThrough(true), setWriteThrough(true) equals - * setBuffered(false) - */ - @Deprecated - public boolean isReadThrough(); - - /** - * Sets the object's read-through mode to the specified status. When - * switching read-through mode on, the object's value is updated from the - * data source. - * - * @param readThrough - * Boolean value to indicate if the object should be in - * read-through mode after the call. - * - * @throws SourceException - * If the operation fails because of an exception is thrown by - * the data source. The cause is included in the exception. - * @deprecated Use {@link #setBuffered(boolean)} instead. Note that - * setReadThrough(true), setWriteThrough(true) equals - * setBuffered(false) - */ - @Deprecated - public void setReadThrough(boolean readThrough) throws SourceException; - - /** - * Sets the object's buffered mode to the specified status. - * <p> - * When the object is in buffered mode, an internal buffer will be used to - * store changes until {@link #commit()} is called. Calling - * {@link #discard()} will revert the internal buffer to the value of the - * data source. - * </p> - * <p> - * This is an easier way to use {@link #setReadThrough(boolean)} and - * {@link #setWriteThrough(boolean)} and not as error prone. Changing - * buffered mode will change both the read through and write through state - * of the object. - * </p> - * <p> - * Mixing calls to {@link #setBuffered(boolean)}/{@link #isBuffered()} and - * {@link #setReadThrough(boolean)}/{@link #isReadThrough()} or - * {@link #setWriteThrough(boolean)}/{@link #isWriteThrough()} is generally - * a bad idea. - * </p> - * - * @param buffered - * true if buffered mode should be turned on, false otherwise - * @since 7.0 - */ - public void setBuffered(boolean buffered); - - /** - * Checks the buffered mode of this Object. - * <p> - * This method only returns true if both read and write buffering is used. - * </p> - * - * @return true if buffered mode is on, false otherwise - * @since 7.0 - */ - public boolean isBuffered(); - - /** - * Tests if the value stored in the object has been modified since it was - * last updated from the data source. - * - * @return <code>true</code> if the value in the object has been modified - * since the last data source update, <code>false</code> if not. - */ - public boolean isModified(); - - /** - * An exception that signals that one or more exceptions occurred while a - * buffered object tried to access its data source or if there is a problem - * in processing a data source. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - @SuppressWarnings("serial") - public class SourceException extends RuntimeException implements - Serializable { - - /** Source class implementing the buffered interface */ - private final Buffered source; - - /** Original cause of the source exception */ - private Throwable[] causes = {}; - - /** - * Creates a source exception that does not include a cause. - * - * @param source - * the source object implementing the Buffered interface. - */ - public SourceException(Buffered source) { - this.source = source; - } - - /** - * Creates a source exception from a cause exception. - * - * @param source - * the source object implementing the Buffered interface. - * @param cause - * the original cause for this exception. - */ - public SourceException(Buffered source, Throwable cause) { - this.source = source; - causes = new Throwable[] { cause }; - } - - /** - * Creates a source exception from multiple causes. - * - * @param source - * the source object implementing the Buffered interface. - * @param causes - * the original causes for this exception. - */ - public SourceException(Buffered source, Throwable[] causes) { - this.source = source; - this.causes = causes; - } - - /** - * Gets the cause of the exception. - * - * @return The (first) cause for the exception, null if no cause. - */ - @Override - public final Throwable getCause() { - if (causes.length == 0) { - return null; - } - return causes[0]; - } - - /** - * Gets all the causes for this exception. - * - * @return throwables that caused this exception - */ - public final Throwable[] getCauses() { - return causes; - } - - /** - * Gets a source of the exception. - * - * @return the Buffered object which generated this exception. - */ - public Buffered getSource() { - return source; - } - - } -} diff --git a/src/com/vaadin/data/BufferedValidatable.java b/src/com/vaadin/data/BufferedValidatable.java deleted file mode 100644 index ce1d44fce6..0000000000 --- a/src/com/vaadin/data/BufferedValidatable.java +++ /dev/null @@ -1,35 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data; - -import java.io.Serializable; - -/** - * <p> - * This interface defines the combination of <code>Validatable</code> and - * <code>Buffered</code> interfaces. The combination of the interfaces defines - * if the invalid data is committed to datasource. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface BufferedValidatable extends Buffered, Validatable, - Serializable { - - /** - * Tests if the invalid data is committed to datasource. The default is - * <code>false</code>. - */ - public boolean isInvalidCommitted(); - - /** - * Sets if the invalid data should be committed to datasource. The default - * is <code>false</code>. - */ - public void setInvalidCommitted(boolean isCommitted); -} diff --git a/src/com/vaadin/data/Collapsible.java b/src/com/vaadin/data/Collapsible.java deleted file mode 100644 index 06c96b7ea7..0000000000 --- a/src/com/vaadin/data/Collapsible.java +++ /dev/null @@ -1,68 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data; - -import com.vaadin.data.Container.Hierarchical; -import com.vaadin.data.Container.Ordered; - -/** - * Container needed by large lazy loading hierarchies displayed e.g. in - * TreeTable. - * <p> - * Container of this type gets notified when a subtree is opened/closed in a - * component displaying its content. This allows container to lazy load subtrees - * and release memory when a sub-tree is no longer displayed. - * <p> - * Methods from {@link Container.Ordered} (and from {@linkContainer.Indexed} if - * implemented) are expected to work as in "preorder" of the currently visible - * hierarchy. This means for example that the return value of size method - * changes when subtree is collapsed/expanded. In other words items in collapsed - * sub trees should be "ignored" by container when the container is accessed - * with methods introduced in {@link Container.Ordered} or - * {@linkContainer.Indexed}. From the accessors point of view, items in - * collapsed subtrees don't exist. - * <p> - * - */ -public interface Collapsible extends Hierarchical, Ordered { - - /** - * <p> - * Collapsing the {@link Item} indicated by <code>itemId</code> hides all - * children, and their respective children, from the {@link Container}. - * </p> - * - * <p> - * If called on a leaf {@link Item}, this method does nothing. - * </p> - * - * @param itemId - * the identifier of the collapsed {@link Item} - * @param collapsed - * <code>true</code> if you want to collapse the children below - * this {@link Item}. <code>false</code> if you want to - * uncollapse the children. - */ - public void setCollapsed(Object itemId, boolean collapsed); - - /** - * <p> - * Checks whether the {@link Item}, identified by <code>itemId</code> is - * collapsed or not. - * </p> - * - * <p> - * If an {@link Item} is "collapsed" its children are not included in - * methods used to list Items in this container. - * </p> - * - * @param itemId - * The {@link Item}'s identifier that is to be checked. - * @return <code>true</code> iff the {@link Item} identified by - * <code>itemId</code> is currently collapsed, otherwise - * <code>false</code>. - */ - public boolean isCollapsed(Object itemId); - -} diff --git a/src/com/vaadin/data/Container.java b/src/com/vaadin/data/Container.java deleted file mode 100644 index f4c0ed9794..0000000000 --- a/src/com/vaadin/data/Container.java +++ /dev/null @@ -1,1105 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data; - -import java.io.Serializable; -import java.util.Collection; - -import com.vaadin.data.util.filter.SimpleStringFilter; -import com.vaadin.data.util.filter.UnsupportedFilterException; - -/** - * <p> - * A specialized set of identified Items. Basically the Container is a set of - * {@link Item}s, but it imposes certain constraints on its contents. These - * constraints state the following: - * </p> - * - * <ul> - * <li>All Items in the Container must have the same number of Properties. - * <li>All Items in the Container must have the same Property ID's (see - * {@link Item#getItemPropertyIds()}). - * <li>All Properties in the Items corresponding to the same Property ID must - * have the same data type. - * <li>All Items within a container are uniquely identified by their non-null - * IDs. - * </ul> - * - * <p> - * The Container can be visualized as a representation of a relational database - * table. Each Item in the Container represents a row in the table, and all - * cells in a column (identified by a Property ID) have the same data type. Note - * that as with the cells in a database table, no Property in a Container may be - * empty, though they may contain <code>null</code> values. - * </p> - * - * <p> - * Note that though uniquely identified, the Items in a Container are not - * necessarily {@link Container.Ordered ordered} or {@link Container.Indexed - * indexed}. - * </p> - * - * <p> - * Containers can derive Item ID's from the item properties or use other, - * container specific or user specified identifiers. - * </p> - * - * <p> - * If a container is {@link Filterable filtered} or {@link Sortable sorted}, - * most of the the methods of the container interface and its subinterfaces - * (container size, {@link #containsId(Object)}, iteration and indices etc.) - * relate to the filtered and sorted view, not to the full container contents. - * See individual method javadoc for exceptions to this (adding and removing - * items). - * </p> - * - * <p> - * <img src=doc-files/Container_full.gif> - * </p> - * - * <p> - * The Container interface is split to several subinterfaces so that a class can - * implement only the ones it needs. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Container extends Serializable { - - /** - * Gets the {@link Item} with the given Item ID from the Container. If the - * Container does not contain the requested Item, <code>null</code> is - * returned. - * - * Containers should not return Items that are filtered out. - * - * @param itemId - * ID of the {@link Item} to retrieve - * @return the {@link Item} with the given ID or <code>null</code> if the - * Item is not found in the Container - */ - public Item getItem(Object itemId); - - /** - * Gets the ID's of all Properties stored in the Container. The ID's cannot - * be modified through the returned collection. - * - * @return unmodifiable collection of Property IDs - */ - public Collection<?> getContainerPropertyIds(); - - /** - * Gets the ID's of all visible (after filtering and sorting) Items stored - * in the Container. The ID's cannot be modified through the returned - * collection. - * - * If the container is {@link Ordered}, the collection returned by this - * method should follow that order. If the container is {@link Sortable}, - * the items should be in the sorted order. - * - * Calling this method for large lazy containers can be an expensive - * operation and should be avoided when practical. - * - * @return unmodifiable collection of Item IDs - */ - public Collection<?> getItemIds(); - - /** - * Gets the Property identified by the given itemId and propertyId from the - * Container. If the Container does not contain the item or it is filtered - * out, or the Container does not have the Property, <code>null</code> is - * returned. - * - * @param itemId - * ID of the visible Item which contains the Property - * @param propertyId - * ID of the Property to retrieve - * @return Property with the given ID or <code>null</code> - */ - public Property<?> getContainerProperty(Object itemId, Object propertyId); - - /** - * Gets the data type of all Properties identified by the given Property ID. - * - * @param propertyId - * ID identifying the Properties - * @return data type of the Properties - */ - public Class<?> getType(Object propertyId); - - /** - * Gets the number of visible Items in the Container. - * - * Filtering can hide items so that they will not be visible through the - * container API. - * - * @return number of Items in the Container - */ - public int size(); - - /** - * Tests if the Container contains the specified Item. - * - * Filtering can hide items so that they will not be visible through the - * container API, and this method should respect visibility of items (i.e. - * only indicate visible items as being in the container) if feasible for - * the container. - * - * @param itemId - * ID the of Item to be tested - * @return boolean indicating if the Container holds the specified Item - */ - public boolean containsId(Object itemId); - - /** - * Creates a new Item with the given ID in the Container. - * - * <p> - * The new Item is returned, and it is ready to have its Properties - * modified. Returns <code>null</code> if the operation fails or the - * Container already contains a Item with the given ID. - * </p> - * - * <p> - * This functionality is optional. - * </p> - * - * @param itemId - * ID of the Item to be created - * @return Created new Item, or <code>null</code> in case of a failure - * @throws UnsupportedOperationException - * if adding an item with an explicit item ID is not supported - * by the container - */ - public Item addItem(Object itemId) throws UnsupportedOperationException; - - /** - * Creates a new Item into the Container, and assign it an automatic ID. - * - * <p> - * The new ID is returned, or <code>null</code> if the operation fails. - * After a successful call you can use the {@link #getItem(Object ItemId) - * <code>getItem</code>}method to fetch the Item. - * </p> - * - * <p> - * This functionality is optional. - * </p> - * - * @return ID of the newly created Item, or <code>null</code> in case of a - * failure - * @throws UnsupportedOperationException - * if adding an item without an explicit item ID is not - * supported by the container - */ - public Object addItem() throws UnsupportedOperationException; - - /** - * Removes the Item identified by <code>ItemId</code> from the Container. - * - * <p> - * Containers that support filtering should also allow removing an item that - * is currently filtered out. - * </p> - * - * <p> - * This functionality is optional. - * </p> - * - * @param itemId - * ID of the Item to remove - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the container does not support removing individual items - */ - public boolean removeItem(Object itemId) - throws UnsupportedOperationException; - - /** - * Adds a new Property to all Items in the Container. The Property ID, data - * type and default value of the new Property are given as parameters. - * - * This functionality is optional. - * - * @param propertyId - * ID of the Property - * @param type - * Data type of the new Property - * @param defaultValue - * The value all created Properties are initialized to - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the container does not support explicitly adding container - * properties - */ - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException; - - /** - * Removes a Property specified by the given Property ID from the Container. - * Note that the Property will be removed from all Items in the Container. - * - * This functionality is optional. - * - * @param propertyId - * ID of the Property to remove - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the container does not support removing container - * properties - */ - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException; - - /** - * Removes all Items from the Container. - * - * <p> - * Note that Property ID and type information is preserved. This - * functionality is optional. - * </p> - * - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the container does not support removing all items - */ - public boolean removeAllItems() throws UnsupportedOperationException; - - /** - * Interface for Container classes whose {@link Item}s can be traversed in - * order. - * - * <p> - * If the container is filtered or sorted, the traversal applies to the - * filtered and sorted view. - * </p> - * <p> - * The <code>addItemAfter()</code> methods should apply filters to the added - * item after inserting it, possibly hiding it immediately. If the container - * is being sorted, they may add items at the correct sorted position - * instead of the given position. See also {@link Filterable} and - * {@link Sortable} for more information. - * </p> - */ - public interface Ordered extends Container { - - /** - * Gets the ID of the Item following the Item that corresponds to - * <code>itemId</code>. If the given Item is the last or not found in - * the Container, <code>null</code> is returned. - * - * @param itemId - * ID of a visible Item in the Container - * @return ID of the next visible Item or <code>null</code> - */ - public Object nextItemId(Object itemId); - - /** - * Gets the ID of the Item preceding the Item that corresponds to - * <code>itemId</code>. If the given Item is the first or not found in - * the Container, <code>null</code> is returned. - * - * @param itemId - * ID of a visible Item in the Container - * @return ID of the previous visible Item or <code>null</code> - */ - public Object prevItemId(Object itemId); - - /** - * Gets the ID of the first Item in the Container. - * - * @return ID of the first visible Item in the Container - */ - public Object firstItemId(); - - /** - * Gets the ID of the last Item in the Container.. - * - * @return ID of the last visible Item in the Container - */ - public Object lastItemId(); - - /** - * Tests if the Item corresponding to the given Item ID is the first - * Item in the Container. - * - * @param itemId - * ID of an Item in the Container - * @return <code>true</code> if the Item is first visible item in the - * Container, <code>false</code> if not - */ - public boolean isFirstId(Object itemId); - - /** - * Tests if the Item corresponding to the given Item ID is the last Item - * in the Container. - * - * @return <code>true</code> if the Item is last visible item in the - * Container, <code>false</code> if not - */ - public boolean isLastId(Object itemId); - - /** - * Adds a new item after the given item. - * <p> - * Adding an item after null item adds the item as first item of the - * ordered container. - * </p> - * - * @see Ordered Ordered: adding items in filtered or sorted containers - * - * @param previousItemId - * Id of the visible item in ordered container after which to - * insert the new item. - * @return item id the the created new item or null if the operation - * fails. - * @throws UnsupportedOperationException - * if the operation is not supported by the container - */ - public Object addItemAfter(Object previousItemId) - throws UnsupportedOperationException; - - /** - * Adds a new item after the given item. - * <p> - * Adding an item after null item adds the item as first item of the - * ordered container. - * </p> - * - * @see Ordered Ordered: adding items in filtered or sorted containers - * - * @param previousItemId - * Id of the visible item in ordered container after which to - * insert the new item. - * @param newItemId - * Id of the new item to be added. - * @return new item or null if the operation fails. - * @throws UnsupportedOperationException - * if the operation is not supported by the container - */ - public Item addItemAfter(Object previousItemId, Object newItemId) - throws UnsupportedOperationException; - - } - - /** - * Interface for Container classes whose {@link Item}s can be sorted. - * <p> - * When an {@link Ordered} or {@link Indexed} container is sorted, all - * relevant operations of these interfaces should only use the filtered and - * sorted contents and the filtered indices to the container. Indices or - * item identifiers in the public API refer to the visible view unless - * otherwise stated. However, the <code>addItem*()</code> methods may add - * items that will be filtered out after addition or moved to another - * position based on sorting. - * </p> - * <p> - * How sorting is performed when a {@link Hierarchical} container implements - * {@link Sortable} is implementation specific and should be documented in - * the implementing class. However, the recommended approach is sorting the - * roots and the sets of children of each item separately. - * </p> - * <p> - * Depending on the container type, sorting a container may permanently - * change the internal order of items in the container. - * </p> - */ - public interface Sortable extends Ordered { - - /** - * Sort method. - * - * Sorts the container items. - * - * Sorting a container can irreversibly change the order of its items or - * only change the order temporarily, depending on the container. - * - * @param propertyId - * Array of container property IDs, whose values are used to - * sort the items in container as primary, secondary, ... - * sorting criterion. All of the item IDs must be in the - * collection returned by - * {@link #getSortableContainerPropertyIds()} - * @param ascending - * Array of sorting order flags corresponding to each - * property ID used in sorting. If this array is shorter than - * propertyId array, ascending order is assumed for items - * where the order is not specified. Use <code>true</code> to - * sort in ascending order, <code>false</code> to use - * descending order. - */ - void sort(Object[] propertyId, boolean[] ascending); - - /** - * Gets the container property IDs which can be used to sort the items. - * - * @return the IDs of the properties that can be used for sorting the - * container - */ - Collection<?> getSortableContainerPropertyIds(); - - } - - /** - * Interface for Container classes whose {@link Item}s can be accessed by - * their position in the container. - * <p> - * If the container is filtered or sorted, all indices refer to the filtered - * and sorted view. However, the <code>addItemAt()</code> methods may add - * items that will be filtered out after addition or moved to another - * position based on sorting. - * </p> - */ - public interface Indexed extends Ordered { - - /** - * Gets the index of the Item corresponding to the itemId. The following - * is <code>true</code> for the returned index: 0 <= index < size(), or - * index = -1 if there is no visible item with that id in the container. - * - * @param itemId - * ID of an Item in the Container - * @return index of the Item, or -1 if (the filtered and sorted view of) - * the Container does not include the Item - */ - public int indexOfId(Object itemId); - - /** - * Gets the ID of an Item by an index number. - * - * @param index - * Index of the requested id in (the filtered and sorted view - * of) the Container - * @return ID of the Item in the given index - */ - public Object getIdByIndex(int index); - - /** - * Adds a new item at given index (in the filtered view). - * <p> - * The indices of the item currently in the given position and all the - * following items are incremented. - * </p> - * <p> - * This method should apply filters to the added item after inserting - * it, possibly hiding it immediately. If the container is being sorted, - * the item may be added at the correct sorted position instead of the - * given position. See {@link Indexed}, {@link Ordered}, - * {@link Filterable} and {@link Sortable} for more information. - * </p> - * - * @param index - * Index (in the filtered and sorted view) to add the new - * item. - * @return item id of the created item or null if the operation fails. - * @throws UnsupportedOperationException - * if the operation is not supported by the container - */ - public Object addItemAt(int index) throws UnsupportedOperationException; - - /** - * Adds a new item at given index (in the filtered view). - * <p> - * The indexes of the item currently in the given position and all the - * following items are incremented. - * </p> - * <p> - * This method should apply filters to the added item after inserting - * it, possibly hiding it immediately. If the container is being sorted, - * the item may be added at the correct sorted position instead of the - * given position. See {@link Indexed}, {@link Filterable} and - * {@link Sortable} for more information. - * </p> - * - * @param index - * Index (in the filtered and sorted view) at which to add - * the new item. - * @param newItemId - * Id of the new item to be added. - * @return new {@link Item} or null if the operation fails. - * @throws UnsupportedOperationException - * if the operation is not supported by the container - */ - public Item addItemAt(int index, Object newItemId) - throws UnsupportedOperationException; - - } - - /** - * <p> - * Interface for <code>Container</code> classes whose Items can be arranged - * hierarchically. This means that the Items in the container belong in a - * tree-like structure, with the following quirks: - * </p> - * - * <ul> - * <li>The Item structure may have more than one root elements - * <li>The Items in the hierarchy can be declared explicitly to be able or - * unable to have children. - * </ul> - */ - public interface Hierarchical extends Container { - - /** - * Gets the IDs of all Items that are children of the specified Item. - * The returned collection is unmodifiable. - * - * @param itemId - * ID of the Item whose children the caller is interested in - * @return An unmodifiable {@link java.util.Collection collection} - * containing the IDs of all other Items that are children in - * the container hierarchy - */ - public Collection<?> getChildren(Object itemId); - - /** - * Gets the ID of the parent Item of the specified Item. - * - * @param itemId - * ID of the Item whose parent the caller wishes to find out. - * @return the ID of the parent Item. Will be <code>null</code> if the - * specified Item is a root element. - */ - public Object getParent(Object itemId); - - /** - * Gets the IDs of all Items in the container that don't have a parent. - * Such items are called <code>root</code> Items. The returned - * collection is unmodifiable. - * - * @return An unmodifiable {@link java.util.Collection collection} - * containing IDs of all root elements of the container - */ - public Collection<?> rootItemIds(); - - /** - * <p> - * Sets the parent of an Item. The new parent item must exist and be - * able to have children. ( - * <code>{@link #areChildrenAllowed(Object)} == true</code> ). It is - * also possible to detach a node from the hierarchy (and thus make it - * root) by setting the parent <code>null</code>. - * </p> - * - * <p> - * This operation is optional. - * </p> - * - * @param itemId - * ID of the item to be set as the child of the Item - * identified with <code>newParentId</code> - * @param newParentId - * ID of the Item that's to be the new parent of the Item - * identified with <code>itemId</code> - * @return <code>true</code> if the operation succeeded, - * <code>false</code> if not - */ - public boolean setParent(Object itemId, Object newParentId) - throws UnsupportedOperationException; - - /** - * Tests if the Item with given ID can have children. - * - * @param itemId - * ID of the Item in the container whose child capability is - * to be tested - * @return <code>true</code> if the specified Item exists in the - * Container and it can have children, <code>false</code> if - * it's not found from the container or it can't have children. - */ - public boolean areChildrenAllowed(Object itemId); - - /** - * <p> - * Sets the given Item's capability to have children. If the Item - * identified with <code>itemId</code> already has children and - * <code>{@link #areChildrenAllowed(Object)}</code> is false this method - * fails and <code>false</code> is returned. - * </p> - * <p> - * The children must be first explicitly removed with - * {@link #setParent(Object itemId, Object newParentId)}or - * {@link com.vaadin.data.Container#removeItem(Object itemId)}. - * </p> - * - * <p> - * This operation is optional. If it is not implemented, the method - * always returns <code>false</code>. - * </p> - * - * @param itemId - * ID of the Item in the container whose child capability is - * to be set - * @param areChildrenAllowed - * boolean value specifying if the Item can have children or - * not - * @return <code>true</code> if the operation succeeded, - * <code>false</code> if not - */ - public boolean setChildrenAllowed(Object itemId, - boolean areChildrenAllowed) - throws UnsupportedOperationException; - - /** - * Tests if the Item specified with <code>itemId</code> is a root Item. - * The hierarchical container can have more than one root and must have - * at least one unless it is empty. The {@link #getParent(Object itemId)} - * method always returns <code>null</code> for root Items. - * - * @param itemId - * ID of the Item whose root status is to be tested - * @return <code>true</code> if the specified Item is a root, - * <code>false</code> if not - */ - public boolean isRoot(Object itemId); - - /** - * <p> - * Tests if the Item specified with <code>itemId</code> has child Items - * or if it is a leaf. The {@link #getChildren(Object itemId)} method - * always returns <code>null</code> for leaf Items. - * </p> - * - * <p> - * Note that being a leaf does not imply whether or not an Item is - * allowed to have children. - * </p> - * . - * - * @param itemId - * ID of the Item to be tested - * @return <code>true</code> if the specified Item has children, - * <code>false</code> if not (is a leaf) - */ - public boolean hasChildren(Object itemId); - - /** - * <p> - * Removes the Item identified by <code>ItemId</code> from the - * Container. - * </p> - * - * <p> - * Note that this does not remove any children the item might have. - * </p> - * - * @param itemId - * ID of the Item to remove - * @return <code>true</code> if the operation succeeded, - * <code>false</code> if not - */ - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException; - } - - /** - * Interface that is implemented by containers which allow reducing their - * visible contents based on a set of filters. This interface has been - * renamed from {@link Filterable}, and implementing the new - * {@link Filterable} instead of or in addition to {@link SimpleFilterable} - * is recommended. This interface might be removed in future Vaadin - * versions. - * <p> - * When a set of filters are set, only items that match all the filters are - * included in the visible contents of the container. Still new items that - * do not match filters can be added to the container. Multiple filters can - * be added and the container remembers the state of the filters. When - * multiple filters are added, all filters must match for an item to be - * visible in the container. - * </p> - * <p> - * When an {@link Ordered} or {@link Indexed} container is filtered, all - * operations of these interfaces should only use the filtered contents and - * the filtered indices to the container. - * </p> - * <p> - * How filtering is performed when a {@link Hierarchical} container - * implements {@link SimpleFilterable} is implementation specific and should - * be documented in the implementing class. - * </p> - * <p> - * Adding items (if supported) to a filtered {@link Ordered} or - * {@link Indexed} container should insert them immediately after the - * indicated visible item. The unfiltered position of items added at index - * 0, at index {@link com.vaadin.data.Container#size()} or at an undefined - * position is up to the implementation. - * </p> - * <p> - * The functionality of SimpleFilterable can be implemented using the - * {@link Filterable} API and {@link SimpleStringFilter}. - * </p> - * - * @since 5.0 (renamed from Filterable to SimpleFilterable in 6.6) - */ - public interface SimpleFilterable extends Container, Serializable { - - /** - * Add a filter for given property. - * - * The API {@link Filterable#addContainerFilter(Filter)} is recommended - * instead of this method. A {@link SimpleStringFilter} can be used with - * the new API to implement the old string filtering functionality. - * - * The filter accepts items for which toString() of the value of the - * given property contains or starts with given filterString. Other - * items are not visible in the container when filtered. - * - * If a container has multiple filters, only items accepted by all - * filters are visible. - * - * @param propertyId - * Property for which the filter is applied to. - * @param filterString - * String that must match the value of the property - * @param ignoreCase - * Determine if the casing can be ignored when comparing - * strings. - * @param onlyMatchPrefix - * Only match prefixes; no other matches are included. - */ - public void addContainerFilter(Object propertyId, String filterString, - boolean ignoreCase, boolean onlyMatchPrefix); - - /** - * Remove all filters from all properties. - */ - public void removeAllContainerFilters(); - - /** - * Remove all filters from the given property. - * - * @param propertyId - * for which to remove filters - */ - public void removeContainerFilters(Object propertyId); - } - - /** - * Filter interface for container filtering. - * - * If a filter does not support in-memory filtering, - * {@link #passesFilter(Item)} should throw - * {@link UnsupportedOperationException}. - * - * Lazy containers must be able to map filters to their internal - * representation (e.g. SQL or JPA 2.0 Criteria). - * - * An {@link UnsupportedFilterException} can be thrown by the container if a - * particular filter is not supported by the container. - * - * An {@link Filter} should implement {@link #equals(Object)} and - * {@link #hashCode()} correctly to avoid duplicate filter registrations - * etc. - * - * @see Filterable - * - * @since 6.6 - */ - public interface Filter extends Serializable { - - /** - * Check if an item passes the filter (in-memory filtering). - * - * @param itemId - * identifier of the item being filtered; may be null when - * the item is being added to the container - * @param item - * the item being filtered - * @return true if the item is accepted by this filter - * @throws UnsupportedOperationException - * if the filter cannot be used for in-memory filtering - */ - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedOperationException; - - /** - * Check if a change in the value of a property can affect the filtering - * result. May always return true, at the cost of performance. - * - * If the filter cannot determine whether it may depend on the property - * or not, should return true. - * - * @param propertyId - * @return true if the filtering result may/does change based on changes - * to the property identified by propertyId - */ - public boolean appliesToProperty(Object propertyId); - - } - - /** - * Interface that is implemented by containers which allow reducing their - * visible contents based on a set of filters. - * <p> - * When a set of filters are set, only items that match all the filters are - * included in the visible contents of the container. Still new items that - * do not match filters can be added to the container. Multiple filters can - * be added and the container remembers the state of the filters. When - * multiple filters are added, all filters must match for an item to be - * visible in the container. - * </p> - * <p> - * When an {@link Ordered} or {@link Indexed} container is filtered, all - * operations of these interfaces should only use the filtered and sorted - * contents and the filtered indices to the container. Indices or item - * identifiers in the public API refer to the visible view unless otherwise - * stated. However, the <code>addItem*()</code> methods may add items that - * will be filtered out after addition or moved to another position based on - * sorting. - * </p> - * <p> - * How filtering is performed when a {@link Hierarchical} container - * implements {@link Filterable} is implementation specific and should be - * documented in the implementing class. - * </p> - * <p> - * Adding items (if supported) to a filtered {@link Ordered} or - * {@link Indexed} container should insert them immediately after the - * indicated visible item. However, the unfiltered position of items added - * at index 0, at index {@link com.vaadin.data.Container#size()} or at an - * undefined position is up to the implementation. - * </p> - * - * <p> - * This API replaces the old Filterable interface, renamed to - * {@link SimpleFilterable} in Vaadin 6.6. - * </p> - * - * @since 6.6 - */ - public interface Filterable extends Container, Serializable { - /** - * Adds a filter for the container. - * - * If a container has multiple filters, only items accepted by all - * filters are visible. - * - * @throws UnsupportedFilterException - * if the filter is not supported by the container - */ - public void addContainerFilter(Filter filter) - throws UnsupportedFilterException; - - /** - * Removes a filter from the container. - * - * This requires that the equals() method considers the filters as - * equivalent (same instance or properly implemented equals() method). - */ - public void removeContainerFilter(Filter filter); - - /** - * Remove all active filters from the container. - */ - public void removeAllContainerFilters(); - - } - - /** - * Interface implemented by viewer classes capable of using a Container as a - * data source. - */ - public interface Viewer extends Serializable { - - /** - * Sets the Container that serves as the data source of the viewer. - * - * @param newDataSource - * The new data source Item - */ - public void setContainerDataSource(Container newDataSource); - - /** - * Gets the Container serving as the data source of the viewer. - * - * @return data source Container - */ - public Container getContainerDataSource(); - - } - - /** - * <p> - * Interface implemented by the editor classes supporting editing the - * Container. Implementing this interface means that the Container serving - * as the data source of the editor can be modified through it. - * </p> - * <p> - * Note that not implementing the <code>Container.Editor</code> interface - * does not restrict the class from editing the Container contents - * internally. - * </p> - */ - public interface Editor extends Container.Viewer, Serializable { - - } - - /* Contents change event */ - - /** - * An <code>Event</code> object specifying the Container whose Item set has - * changed (items added, removed or reordered). - * - * A simple property value change is not an item set change. - */ - public interface ItemSetChangeEvent extends Serializable { - - /** - * Gets the Property where the event occurred. - * - * @return source of the event - */ - public Container getContainer(); - } - - /** - * Container Item set change listener interface. - * - * An item set change refers to addition, removal or reordering of items in - * the container. A simple property value change is not an item set change. - */ - public interface ItemSetChangeListener extends Serializable { - - /** - * Lets the listener know a Containers visible (filtered and/or sorted, - * if applicable) Item set has changed. - * - * @param event - * change event text - */ - public void containerItemSetChange(Container.ItemSetChangeEvent event); - } - - /** - * The interface for adding and removing <code>ItemSetChangeEvent</code> - * listeners. By implementing this interface a class explicitly announces - * that it will generate a <code>ItemSetChangeEvent</code> when its contents - * are modified. - * - * An item set change refers to addition, removal or reordering of items in - * the container. A simple property value change is not an item set change. - * - * <p> - * Note: The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - */ - public interface ItemSetChangeNotifier extends Serializable { - - /** - * Adds an Item set change listener for the object. - * - * @param listener - * listener to be added - */ - public void addListener(Container.ItemSetChangeListener listener); - - /** - * Removes the Item set change listener from the object. - * - * @param listener - * listener to be removed - */ - public void removeListener(Container.ItemSetChangeListener listener); - } - - /* Property set change event */ - - /** - * An <code>Event</code> object specifying the Container whose Property set - * has changed. - * - * A property set change means the addition, removal or other structural - * changes to the properties of a container. Changes concerning the set of - * items in the container and their property values are not property set - * changes. - */ - public interface PropertySetChangeEvent extends Serializable { - - /** - * Retrieves the Container whose contents have been modified. - * - * @return Source Container of the event. - */ - public Container getContainer(); - } - - /** - * The listener interface for receiving <code>PropertySetChangeEvent</code> - * objects. - * - * A property set change means the addition, removal or other structural - * change of the properties (supported property IDs) of a container. Changes - * concerning the set of items in the container and their property values - * are not property set changes. - */ - public interface PropertySetChangeListener extends Serializable { - - /** - * Notifies this listener that the set of property IDs supported by the - * Container has changed. - * - * @param event - * Change event. - */ - public void containerPropertySetChange( - Container.PropertySetChangeEvent event); - } - - /** - * <p> - * The interface for adding and removing <code>PropertySetChangeEvent</code> - * listeners. By implementing this interface a class explicitly announces - * that it will generate a <code>PropertySetChangeEvent</code> when the set - * of property IDs supported by the container is modified. - * </p> - * - * <p> - * A property set change means the addition, removal or other structural - * changes to the properties of a container. Changes concerning the set of - * items in the container and their property values are not property set - * changes. - * </p> - * - * <p> - * Note that the general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - */ - public interface PropertySetChangeNotifier extends Serializable { - - /** - * Registers a new Property set change listener for this Container. - * - * @param listener - * The new Listener to be registered - */ - public void addListener(Container.PropertySetChangeListener listener); - - /** - * Removes a previously registered Property set change listener. - * - * @param listener - * Listener to be removed - */ - public void removeListener(Container.PropertySetChangeListener listener); - } -} diff --git a/src/com/vaadin/data/Item.java b/src/com/vaadin/data/Item.java deleted file mode 100644 index 98b95aecff..0000000000 --- a/src/com/vaadin/data/Item.java +++ /dev/null @@ -1,180 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data; - -import java.io.Serializable; -import java.util.Collection; - -/** - * <p> - * Provides a mechanism for handling a set of Properties, each associated to a - * locally unique non-null identifier. The interface is split into subinterfaces - * to enable a class to implement only the functionalities it needs. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Item extends Serializable { - - /** - * Gets the Property corresponding to the given Property ID stored in the - * Item. If the Item does not contain the Property, <code>null</code> is - * returned. - * - * @param id - * identifier of the Property to get - * @return the Property with the given ID or <code>null</code> - */ - public Property<?> getItemProperty(Object id); - - /** - * Gets the collection of IDs of all Properties stored in the Item. - * - * @return unmodifiable collection containing IDs of the Properties stored - * the Item - */ - public Collection<?> getItemPropertyIds(); - - /** - * Tries to add a new Property into the Item. - * - * <p> - * This functionality is optional. - * </p> - * - * @param id - * ID of the new Property - * @param property - * the Property to be added and associated with the id - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the operation is not supported. - */ - public boolean addItemProperty(Object id, Property property) - throws UnsupportedOperationException; - - /** - * Removes the Property identified by ID from the Item. - * - * <p> - * This functionality is optional. - * </p> - * - * @param id - * ID of the Property to be removed - * @return <code>true</code> if the operation succeeded - * @throws UnsupportedOperationException - * if the operation is not supported. <code>false</code> if not - */ - public boolean removeItemProperty(Object id) - throws UnsupportedOperationException; - - /** - * Interface implemented by viewer classes capable of using an Item as a - * data source. - */ - public interface Viewer extends Serializable { - - /** - * Sets the Item that serves as the data source of the viewer. - * - * @param newDataSource - * The new data source Item - */ - public void setItemDataSource(Item newDataSource); - - /** - * Gets the Item serving as the data source of the viewer. - * - * @return data source Item - */ - public Item getItemDataSource(); - } - - /** - * Interface implemented by the <code>Editor</code> classes capable of - * editing the Item. Implementing this interface means that the Item serving - * as the data source of the editor can be modified through it. - * <p> - * Note : Not implementing the <code>Item.Editor</code> interface does not - * restrict the class from editing the contents of an internally. - * </p> - */ - public interface Editor extends Item.Viewer, Serializable { - - } - - /* Property set change event */ - - /** - * An <code>Event</code> object specifying the Item whose contents has been - * changed through the <code>Property</code> interface. - * <p> - * Note: The values stored in the Properties may change without triggering - * this event. - * </p> - */ - public interface PropertySetChangeEvent extends Serializable { - - /** - * Retrieves the Item whose contents has been modified. - * - * @return source Item of the event - */ - public Item getItem(); - } - - /** - * The listener interface for receiving <code>PropertySetChangeEvent</code> - * objects. - */ - public interface PropertySetChangeListener extends Serializable { - - /** - * Notifies this listener that the Item's property set has changed. - * - * @param event - * Property set change event object - */ - public void itemPropertySetChange(Item.PropertySetChangeEvent event); - } - - /** - * The interface for adding and removing <code>PropertySetChangeEvent</code> - * listeners. By implementing this interface a class explicitly announces - * that it will generate a <code>PropertySetChangeEvent</code> when its - * Property set is modified. - * <p> - * Note : The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - */ - public interface PropertySetChangeNotifier extends Serializable { - - /** - * Registers a new property set change listener for this Item. - * - * @param listener - * The new Listener to be registered. - */ - public void addListener(Item.PropertySetChangeListener listener); - - /** - * Removes a previously registered property set change listener. - * - * @param listener - * Listener to be removed. - */ - public void removeListener(Item.PropertySetChangeListener listener); - } -} diff --git a/src/com/vaadin/data/Property.java b/src/com/vaadin/data/Property.java deleted file mode 100644 index 9fab642381..0000000000 --- a/src/com/vaadin/data/Property.java +++ /dev/null @@ -1,402 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data; - -import java.io.Serializable; - -/** - * <p> - * The <code>Property</code> is a simple data object that contains one typed - * value. This interface contains methods to inspect and modify the stored value - * and its type, and the object's read-only state. - * </p> - * - * <p> - * The <code>Property</code> also defines the events - * <code>ReadOnlyStatusChangeEvent</code> and <code>ValueChangeEvent</code>, and - * the associated <code>listener</code> and <code>notifier</code> interfaces. - * </p> - * - * <p> - * The <code>Property.Viewer</code> interface should be used to attach the - * Property to an external data source. This way the value in the data source - * can be inspected using the <code>Property</code> interface. - * </p> - * - * <p> - * The <code>Property.editor</code> interface should be implemented if the value - * needs to be changed through the implementing class. - * </p> - * - * @param T - * type of values of the property - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Property<T> extends Serializable { - - /** - * Gets the value stored in the Property. The returned object is compatible - * with the class returned by getType(). - * - * @return the value stored in the Property - */ - public T getValue(); - - /** - * Sets the value of the Property. - * <p> - * Implementing this functionality is optional. If the functionality is - * missing, one should declare the Property to be in read-only mode and - * throw <code>Property.ReadOnlyException</code> in this function. - * </p> - * - * Note : Since Vaadin 7.0, setting the value of a non-String property as a - * String is no longer supported. - * - * @param newValue - * New value of the Property. This should be assignable to the - * type returned by getType - * - * @throws Property.ReadOnlyException - * if the object is in read-only mode - */ - public void setValue(Object newValue) throws Property.ReadOnlyException; - - /** - * Returns the type of the Property. The methods <code>getValue</code> and - * <code>setValue</code> must be compatible with this type: one must be able - * to safely cast the value returned from <code>getValue</code> to the given - * type and pass any variable assignable to this type as an argument to - * <code>setValue</code>. - * - * @return type of the Property - */ - public Class<? extends T> getType(); - - /** - * Tests if the Property is in read-only mode. In read-only mode calls to - * the method <code>setValue</code> will throw - * <code>ReadOnlyException</code> and will not modify the value of the - * Property. - * - * @return <code>true</code> if the Property is in read-only mode, - * <code>false</code> if it's not - */ - public boolean isReadOnly(); - - /** - * Sets the Property's read-only mode to the specified status. - * - * This functionality is optional, but all properties must implement the - * <code>isReadOnly</code> mode query correctly. - * - * @param newStatus - * new read-only status of the Property - */ - public void setReadOnly(boolean newStatus); - - /** - * A Property that is capable of handle a transaction that can end in commit - * or rollback. - * - * Note that this does not refer to e.g. database transactions but rather - * two-phase commit that allows resetting old field values on a form etc. if - * the commit of one of the properties fails after others have already been - * committed. If - * - * @param <T> - * The type of the property - * @author Vaadin Ltd - * @version @version@ - * @since 7.0 - */ - public interface Transactional<T> extends Property<T> { - - /** - * Starts a transaction. - * - * <p> - * If the value is set during a transaction the value must not replace - * the original value until {@link #commit()} is called. Still, - * {@link #getValue()} must return the current value set in the - * transaction. Calling {@link #rollback()} while in a transaction must - * rollback the value to what it was before the transaction started. - * </p> - * <p> - * {@link ValueChangeEvent}s must not be emitted for internal value - * changes during a transaction. If the value changes as a result of - * {@link #commit()}, a {@link ValueChangeEvent} should be emitted. - * </p> - */ - public void startTransaction(); - - /** - * Commits and ends the transaction that is in progress. - * <p> - * If the value is changed as a result of this operation, a - * {@link ValueChangeEvent} is emitted if such are supported. - * <p> - * This method has no effect if there is no transaction is in progress. - * <p> - * This method must never throw an exception. - */ - public void commit(); - - /** - * Aborts and rolls back the transaction that is in progress. - * <p> - * The value is reset to the value before the transaction started. No - * {@link ValueChangeEvent} is emitted as a result of this. - * <p> - * This method has no effect if there is no transaction is in progress. - * <p> - * This method must never throw an exception. - */ - public void rollback(); - } - - /** - * <code>Exception</code> object that signals that a requested Property - * modification failed because it's in read-only mode. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - @SuppressWarnings("serial") - public class ReadOnlyException extends RuntimeException { - - /** - * Constructs a new <code>ReadOnlyException</code> without a detail - * message. - */ - public ReadOnlyException() { - } - - /** - * Constructs a new <code>ReadOnlyException</code> with the specified - * detail message. - * - * @param msg - * the detail message - */ - public ReadOnlyException(String msg) { - super(msg); - } - } - - /** - * Interface implemented by the viewer classes capable of using a Property - * as a data source. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface Viewer extends Serializable { - - /** - * Sets the Property that serves as the data source of the viewer. - * - * @param newDataSource - * the new data source Property - */ - public void setPropertyDataSource(Property newDataSource); - - /** - * Gets the Property serving as the data source of the viewer. - * - * @return the Property serving as the viewers data source - */ - public Property getPropertyDataSource(); - } - - /** - * Interface implemented by the editor classes capable of editing the - * Property. - * <p> - * Implementing this interface means that the Property serving as the data - * source of the editor can be modified through the editor. It does not - * restrict the editor from editing the Property internally, though if the - * Property is in a read-only mode, attempts to modify it will result in the - * <code>ReadOnlyException</code> being thrown. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface Editor extends Property.Viewer, Serializable { - - } - - /* Value change event */ - - /** - * An <code>Event</code> object specifying the Property whose value has been - * changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ValueChangeEvent extends Serializable { - - /** - * Retrieves the Property that has been modified. - * - * @return source Property of the event - */ - public Property getProperty(); - } - - /** - * The <code>listener</code> interface for receiving - * <code>ValueChangeEvent</code> objects. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ValueChangeListener extends Serializable { - - /** - * Notifies this listener that the Property's value has changed. - * - * @param event - * value change event object - */ - public void valueChange(Property.ValueChangeEvent event); - } - - /** - * The interface for adding and removing <code>ValueChangeEvent</code> - * listeners. If a Property wishes to allow other objects to receive - * <code>ValueChangeEvent</code> generated by it, it must implement this - * interface. - * <p> - * Note : The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ValueChangeNotifier extends Serializable { - - /** - * Registers a new value change listener for this Property. - * - * @param listener - * the new Listener to be registered - */ - public void addListener(Property.ValueChangeListener listener); - - /** - * Removes a previously registered value change listener. - * - * @param listener - * listener to be removed - */ - public void removeListener(Property.ValueChangeListener listener); - } - - /* ReadOnly Status change event */ - - /** - * An <code>Event</code> object specifying the Property whose read-only - * status has been changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ReadOnlyStatusChangeEvent extends Serializable { - - /** - * Property whose read-only state has changed. - * - * @return source Property of the event. - */ - public Property getProperty(); - } - - /** - * The listener interface for receiving - * <code>ReadOnlyStatusChangeEvent</code> objects. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ReadOnlyStatusChangeListener extends Serializable { - - /** - * Notifies this listener that a Property's read-only status has - * changed. - * - * @param event - * Read-only status change event object - */ - public void readOnlyStatusChange( - Property.ReadOnlyStatusChangeEvent event); - } - - /** - * The interface for adding and removing - * <code>ReadOnlyStatusChangeEvent</code> listeners. If a Property wishes to - * allow other objects to receive <code>ReadOnlyStatusChangeEvent</code> - * generated by it, it must implement this interface. - * <p> - * Note : The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ReadOnlyStatusChangeNotifier extends Serializable { - - /** - * Registers a new read-only status change listener for this Property. - * - * @param listener - * the new Listener to be registered - */ - public void addListener(Property.ReadOnlyStatusChangeListener listener); - - /** - * Removes a previously registered read-only status change listener. - * - * @param listener - * listener to be removed - */ - public void removeListener( - Property.ReadOnlyStatusChangeListener listener); - } -} diff --git a/src/com/vaadin/data/Validatable.java b/src/com/vaadin/data/Validatable.java deleted file mode 100644 index 4a7a0fda10..0000000000 --- a/src/com/vaadin/data/Validatable.java +++ /dev/null @@ -1,110 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data; - -import java.io.Serializable; -import java.util.Collection; - -/** - * <p> - * Interface for validatable objects. Defines methods to verify if the object's - * value is valid or not, and to add, remove and list registered validators of - * the object. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - * @see com.vaadin.data.Validator - */ -public interface Validatable extends Serializable { - - /** - * <p> - * Adds a new validator for this object. The validator's - * {@link Validator#validate(Object)} method is activated every time the - * object's value needs to be verified, that is, when the {@link #isValid()} - * method is called. This usually happens when the object's value changes. - * </p> - * - * @param validator - * the new validator - */ - void addValidator(Validator validator); - - /** - * <p> - * Removes a previously registered validator from the object. The specified - * validator is removed from the object and its <code>validate</code> method - * is no longer called in {@link #isValid()}. - * </p> - * - * @param validator - * the validator to remove - */ - void removeValidator(Validator validator); - - /** - * <p> - * Lists all validators currently registered for the object. If no - * validators are registered, returns <code>null</code>. - * </p> - * - * @return collection of validators or <code>null</code> - */ - public Collection<Validator> getValidators(); - - /** - * <p> - * Tests the current value of the object against all registered validators. - * The registered validators are iterated and for each the - * {@link Validator#validate(Object)} method is called. If any validator - * throws the {@link Validator.InvalidValueException} this method returns - * <code>false</code>. - * </p> - * - * @return <code>true</code> if the registered validators concur that the - * value is valid, <code>false</code> otherwise - */ - public boolean isValid(); - - /** - * <p> - * Checks the validity of the validatable. If the validatable is valid this - * method should do nothing, and if it's not valid, it should throw - * <code>Validator.InvalidValueException</code> - * </p> - * - * @throws Validator.InvalidValueException - * if the value is not valid - */ - public void validate() throws Validator.InvalidValueException; - - /** - * <p> - * Checks the validabtable object accept invalid values.The default value is - * <code>true</code>. - * </p> - * - */ - public boolean isInvalidAllowed(); - - /** - * <p> - * Should the validabtable object accept invalid values. Supporting this - * configuration possibility is optional. By default invalid values are - * allowed. - * </p> - * - * @param invalidValueAllowed - * - * @throws UnsupportedOperationException - * if the setInvalidAllowed is not supported. - */ - public void setInvalidAllowed(boolean invalidValueAllowed) - throws UnsupportedOperationException; - -} diff --git a/src/com/vaadin/data/Validator.java b/src/com/vaadin/data/Validator.java deleted file mode 100644 index 768a02babe..0000000000 --- a/src/com/vaadin/data/Validator.java +++ /dev/null @@ -1,175 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data; - -import java.io.Serializable; - -import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; - -/** - * Interface that implements a method for validating if an {@link Object} is - * valid or not. - * <p> - * Implementors of this class can be added to any - * {@link com.vaadin.data.Validatable Validatable} implementor to verify its - * value. - * </p> - * <p> - * {@link #validate(Object)} can be used to check if a value is valid. An - * {@link InvalidValueException} with an appropriate validation error message is - * thrown if the value is not valid. - * </p> - * <p> - * Validators must not have any side effects. - * </p> - * <p> - * Since Vaadin 7, the method isValid(Object) does not exist in the interface - - * {@link #validate(Object)} should be used instead, and the exception caught - * where applicable. Concrete classes implementing {@link Validator} can still - * internally implement and use isValid(Object) for convenience or to ease - * migration from earlier Vaadin versions. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Validator extends Serializable { - - /** - * Checks the given value against this validator. If the value is valid the - * method does nothing. If the value is invalid, an - * {@link InvalidValueException} is thrown. - * - * @param value - * the value to check - * @throws Validator.InvalidValueException - * if the value is invalid - */ - public void validate(Object value) throws Validator.InvalidValueException; - - /** - * Exception that is thrown by a {@link Validator} when a value is invalid. - * - * <p> - * The default implementation of InvalidValueException does not support HTML - * in error messages. To enable HTML support, override - * {@link #getHtmlMessage()} and use the subclass in validators. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - @SuppressWarnings("serial") - public class InvalidValueException extends RuntimeException { - - /** - * Array of one or more validation errors that are causing this - * validation error. - */ - private InvalidValueException[] causes = null; - - /** - * Constructs a new {@code InvalidValueException} with the specified - * message. - * - * @param message - * The detail message of the problem. - */ - public InvalidValueException(String message) { - this(message, new InvalidValueException[] {}); - } - - /** - * Constructs a new {@code InvalidValueException} with a set of causing - * validation exceptions. The causing validation exceptions are included - * when the exception is painted to the client. - * - * @param message - * The detail message of the problem. - * @param causes - * One or more {@code InvalidValueException}s that caused - * this exception. - */ - public InvalidValueException(String message, - InvalidValueException[] causes) { - super(message); - if (causes == null) { - throw new NullPointerException( - "Possible causes array must not be null"); - } - - this.causes = causes; - } - - /** - * Check if the error message should be hidden. - * - * An empty (null or "") message is invisible unless it contains nested - * exceptions that are visible. - * - * @return true if the error message should be hidden, false otherwise - */ - public boolean isInvisible() { - String msg = getMessage(); - if (msg != null && msg.length() > 0) { - return false; - } - if (causes != null) { - for (int i = 0; i < causes.length; i++) { - if (!causes[i].isInvisible()) { - return false; - } - } - } - return true; - } - - /** - * Returns the message of the error in HTML. - * - * Note that this API may change in future versions. - */ - public String getHtmlMessage() { - return AbstractApplicationServlet - .safeEscapeForHtml(getLocalizedMessage()); - } - - /** - * Returns the {@code InvalidValueExceptions} that caused this - * exception. - * - * @return An array containing the {@code InvalidValueExceptions} that - * caused this exception. Returns an empty array if this - * exception was not caused by other exceptions. - */ - public InvalidValueException[] getCauses() { - return causes; - } - - } - - /** - * A specific type of {@link InvalidValueException} that indicates that - * validation failed because the value was empty. What empty means is up to - * the thrower. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.3.0 - */ - @SuppressWarnings("serial") - public class EmptyValueException extends Validator.InvalidValueException { - - public EmptyValueException(String message) { - super(message); - } - - } -} diff --git a/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java b/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java deleted file mode 100644 index b8efa5b1e4..0000000000 --- a/src/com/vaadin/data/fieldgroup/BeanFieldGroup.java +++ /dev/null @@ -1,157 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.fieldgroup; - -import java.lang.reflect.Method; - -import com.vaadin.data.Item; -import com.vaadin.data.util.BeanItem; -import com.vaadin.data.validator.BeanValidator; -import com.vaadin.ui.Field; - -public class BeanFieldGroup<T> extends FieldGroup { - - private Class<T> beanType; - - private static Boolean beanValidationImplementationAvailable = null; - - public BeanFieldGroup(Class<T> beanType) { - this.beanType = beanType; - } - - @Override - protected Class<?> getPropertyType(Object propertyId) { - if (getItemDataSource() != null) { - return super.getPropertyType(propertyId); - } else { - // Data source not set so we need to figure out the type manually - /* - * toString should never really be needed as propertyId should be of - * form "fieldName" or "fieldName.subField[.subField2]" but the - * method declaration comes from parent. - */ - java.lang.reflect.Field f; - try { - f = getField(beanType, propertyId.toString()); - return f.getType(); - } catch (SecurityException e) { - throw new BindException("Cannot determine type of propertyId '" - + propertyId + "'.", e); - } catch (NoSuchFieldException e) { - throw new BindException("Cannot determine type of propertyId '" - + propertyId + "'. The propertyId was not found in " - + beanType.getName(), e); - } - } - } - - private static java.lang.reflect.Field getField(Class<?> cls, - String propertyId) throws SecurityException, NoSuchFieldException { - if (propertyId.contains(".")) { - String[] parts = propertyId.split("\\.", 2); - // Get the type of the field in the "cls" class - java.lang.reflect.Field field1 = getField(cls, parts[0]); - // Find the rest from the sub type - return getField(field1.getType(), parts[1]); - } else { - try { - // Try to find the field directly in the given class - java.lang.reflect.Field field1 = cls - .getDeclaredField(propertyId); - return field1; - } catch (NoSuchFieldError e) { - // Try super classes until we reach Object - Class<?> superClass = cls.getSuperclass(); - if (superClass != Object.class) { - return getField(superClass, propertyId); - } else { - throw e; - } - } - } - } - - /** - * Helper method for setting the data source directly using a bean. This - * method wraps the bean in a {@link BeanItem} and calls - * {@link #setItemDataSource(Item)}. - * - * @param bean - * The bean to use as data source. - */ - public void setItemDataSource(T bean) { - setItemDataSource(new BeanItem(bean)); - } - - @Override - public void setItemDataSource(Item item) { - if (!(item instanceof BeanItem)) { - throw new RuntimeException(getClass().getSimpleName() - + " only supports BeanItems as item data source"); - } - super.setItemDataSource(item); - } - - @Override - public BeanItem<T> getItemDataSource() { - return (BeanItem<T>) super.getItemDataSource(); - } - - @Override - public void bind(Field field, Object propertyId) { - if (getItemDataSource() != null) { - // The data source is set so the property must be found in the item. - // If it is not we try to add it. - try { - getItemProperty(propertyId); - } catch (BindException e) { - // Not found, try to add a nested property; - // BeanItem property ids are always strings so this is safe - getItemDataSource().addNestedProperty((String) propertyId); - } - } - - super.bind(field, propertyId); - } - - @Override - protected void configureField(Field<?> field) { - super.configureField(field); - // Add Bean validators if there are annotations - if (isBeanValidationImplementationAvailable()) { - BeanValidator validator = new BeanValidator(beanType, - getPropertyId(field).toString()); - field.addValidator(validator); - if (field.getLocale() != null) { - validator.setLocale(field.getLocale()); - } - } - } - - /** - * Checks whether a bean validation implementation (e.g. Hibernate Validator - * or Apache Bean Validation) is available. - * - * TODO move this method to some more generic location - * - * @return true if a JSR-303 bean validation implementation is available - */ - protected static boolean isBeanValidationImplementationAvailable() { - if (beanValidationImplementationAvailable != null) { - return beanValidationImplementationAvailable; - } - try { - Class<?> validationClass = Class - .forName("javax.validation.Validation"); - Method buildFactoryMethod = validationClass - .getMethod("buildDefaultValidatorFactory"); - Object factory = buildFactoryMethod.invoke(null); - beanValidationImplementationAvailable = (factory != null); - } catch (Exception e) { - // no bean validation implementation available - beanValidationImplementationAvailable = false; - } - return beanValidationImplementationAvailable; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/data/fieldgroup/Caption.java b/src/com/vaadin/data/fieldgroup/Caption.java deleted file mode 100644 index b990b720cd..0000000000 --- a/src/com/vaadin/data/fieldgroup/Caption.java +++ /dev/null @@ -1,15 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.fieldgroup; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface Caption { - String value(); -} diff --git a/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java b/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java deleted file mode 100644 index be0db328f2..0000000000 --- a/src/com/vaadin/data/fieldgroup/DefaultFieldGroupFieldFactory.java +++ /dev/null @@ -1,157 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.fieldgroup; - -import java.util.EnumSet; - -import com.vaadin.data.Item; -import com.vaadin.data.fieldgroup.FieldGroup.BindException; -import com.vaadin.ui.AbstractSelect; -import com.vaadin.ui.AbstractTextField; -import com.vaadin.ui.CheckBox; -import com.vaadin.ui.ComboBox; -import com.vaadin.ui.Field; -import com.vaadin.ui.ListSelect; -import com.vaadin.ui.NativeSelect; -import com.vaadin.ui.OptionGroup; -import com.vaadin.ui.RichTextArea; -import com.vaadin.ui.Table; -import com.vaadin.ui.TextField; - -public class DefaultFieldGroupFieldFactory implements FieldGroupFieldFactory { - - public static final Object CAPTION_PROPERTY_ID = "Caption"; - - @Override - public <T extends Field> T createField(Class<?> type, Class<T> fieldType) { - if (Enum.class.isAssignableFrom(type)) { - return createEnumField(type, fieldType); - } else if (Boolean.class.isAssignableFrom(type) - || boolean.class.isAssignableFrom(type)) { - return createBooleanField(fieldType); - } - if (AbstractTextField.class.isAssignableFrom(fieldType)) { - return fieldType.cast(createAbstractTextField(fieldType - .asSubclass(AbstractTextField.class))); - } else if (fieldType == RichTextArea.class) { - return fieldType.cast(createRichTextArea()); - } - return createDefaultField(type, fieldType); - } - - protected RichTextArea createRichTextArea() { - RichTextArea rta = new RichTextArea(); - rta.setImmediate(true); - - return rta; - } - - private <T extends Field> T createEnumField(Class<?> type, - Class<T> fieldType) { - if (AbstractSelect.class.isAssignableFrom(fieldType)) { - AbstractSelect s = createCompatibleSelect((Class<? extends AbstractSelect>) fieldType); - populateWithEnumData(s, (Class<? extends Enum>) type); - return (T) s; - } - - return null; - } - - protected AbstractSelect createCompatibleSelect( - Class<? extends AbstractSelect> fieldType) { - AbstractSelect select; - if (fieldType.isAssignableFrom(ListSelect.class)) { - select = new ListSelect(); - select.setMultiSelect(false); - } else if (fieldType.isAssignableFrom(NativeSelect.class)) { - select = new NativeSelect(); - } else if (fieldType.isAssignableFrom(OptionGroup.class)) { - select = new OptionGroup(); - select.setMultiSelect(false); - } else if (fieldType.isAssignableFrom(Table.class)) { - Table t = new Table(); - t.setSelectable(true); - select = t; - } else { - select = new ComboBox(null); - } - select.setImmediate(true); - select.setNullSelectionAllowed(false); - - return select; - } - - protected <T extends Field> T createBooleanField(Class<T> fieldType) { - if (fieldType.isAssignableFrom(CheckBox.class)) { - CheckBox cb = new CheckBox(null); - cb.setImmediate(true); - return (T) cb; - } else if (AbstractTextField.class.isAssignableFrom(fieldType)) { - return (T) createAbstractTextField((Class<? extends AbstractTextField>) fieldType); - } - - return null; - } - - protected <T extends AbstractTextField> T createAbstractTextField( - Class<T> fieldType) { - if (fieldType == AbstractTextField.class) { - fieldType = (Class<T>) TextField.class; - } - try { - T field = fieldType.newInstance(); - field.setImmediate(true); - return field; - } catch (Exception e) { - throw new BindException("Could not create a field of type " - + fieldType, e); - } - } - - /** - * Fallback when no specific field has been created. Typically returns a - * TextField. - * - * @param <T> - * The type of field to create - * @param type - * The type of data that should be edited - * @param fieldType - * The type of field to create - * @return A field capable of editing the data or null if no field could be - * created - */ - protected <T extends Field> T createDefaultField(Class<?> type, - Class<T> fieldType) { - if (fieldType.isAssignableFrom(TextField.class)) { - return fieldType.cast(createAbstractTextField(TextField.class)); - } - return null; - } - - /** - * Populates the given select with all the enums in the given {@link Enum} - * class. Uses {@link Enum}.toString() for caption. - * - * @param select - * The select to populate - * @param enumClass - * The Enum class to use - */ - protected void populateWithEnumData(AbstractSelect select, - Class<? extends Enum> enumClass) { - select.removeAllItems(); - for (Object p : select.getContainerPropertyIds()) { - select.removeContainerProperty(p); - } - select.addContainerProperty(CAPTION_PROPERTY_ID, String.class, ""); - select.setItemCaptionPropertyId(CAPTION_PROPERTY_ID); - @SuppressWarnings("unchecked") - EnumSet<?> enumSet = EnumSet.allOf(enumClass); - for (Object r : enumSet) { - Item newItem = select.addItem(r); - newItem.getItemProperty(CAPTION_PROPERTY_ID).setValue(r.toString()); - } - } -} diff --git a/src/com/vaadin/data/fieldgroup/FieldGroup.java b/src/com/vaadin/data/fieldgroup/FieldGroup.java deleted file mode 100644 index 3df19f5bc9..0000000000 --- a/src/com/vaadin/data/fieldgroup/FieldGroup.java +++ /dev/null @@ -1,978 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.fieldgroup; - -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.logging.Logger; - -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.data.Validator.InvalidValueException; -import com.vaadin.data.util.TransactionalPropertyWrapper; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.DefaultFieldFactory; -import com.vaadin.ui.Field; -import com.vaadin.ui.Form; - -/** - * FieldGroup provides an easy way of binding fields to data and handling - * commits of these fields. - * <p> - * The functionality of FieldGroup is similar to {@link Form} but - * {@link FieldGroup} does not handle layouts in any way. The typical use case - * is to create a layout outside the FieldGroup and then use FieldGroup to bind - * the fields to a data source. - * </p> - * <p> - * {@link FieldGroup} is not a UI component so it cannot be added to a layout. - * Using the buildAndBind methods {@link FieldGroup} can create fields for you - * using a FieldGroupFieldFactory but you still have to add them to the correct - * position in your layout. - * </p> - * - * @author Vaadin Ltd - * @version @version@ - * @since 7.0 - */ -public class FieldGroup implements Serializable { - - private static final Logger logger = Logger.getLogger(FieldGroup.class - .getName()); - - private Item itemDataSource; - private boolean buffered = true; - - private boolean enabled = true; - private boolean readOnly = false; - - private HashMap<Object, Field<?>> propertyIdToField = new HashMap<Object, Field<?>>(); - private LinkedHashMap<Field<?>, Object> fieldToPropertyId = new LinkedHashMap<Field<?>, Object>(); - private List<CommitHandler> commitHandlers = new ArrayList<CommitHandler>(); - - /** - * The field factory used by builder methods. - */ - private FieldGroupFieldFactory fieldFactory = new DefaultFieldGroupFieldFactory(); - - /** - * Constructs a field binder. Use {@link #setItemDataSource(Item)} to set a - * data source for the field binder. - * - */ - public FieldGroup() { - - } - - /** - * Constructs a field binder that uses the given data source. - * - * @param itemDataSource - * The data source to bind the fields to - */ - public FieldGroup(Item itemDataSource) { - setItemDataSource(itemDataSource); - } - - /** - * Updates the item that is used by this FieldBinder. Rebinds all fields to - * the properties in the new item. - * - * @param itemDataSource - * The new item to use - */ - public void setItemDataSource(Item itemDataSource) { - this.itemDataSource = itemDataSource; - - for (Field<?> f : fieldToPropertyId.keySet()) { - bind(f, fieldToPropertyId.get(f)); - } - } - - /** - * Gets the item used by this FieldBinder. Note that you must call - * {@link #commit()} for the item to be updated unless buffered mode has - * been switched off. - * - * @see #setBuffered(boolean) - * @see #commit() - * - * @return The item used by this FieldBinder - */ - public Item getItemDataSource() { - return itemDataSource; - } - - /** - * Checks the buffered mode for the bound fields. - * <p> - * - * @see #setBuffered(boolean) for more details on buffered mode - * - * @see Field#isBuffered() - * @return true if buffered mode is on, false otherwise - * - */ - public boolean isBuffered() { - return buffered; - } - - /** - * Sets the buffered mode for the bound fields. - * <p> - * When buffered mode is on the item will not be updated until - * {@link #commit()} is called. If buffered mode is off the item will be - * updated once the fields are updated. - * </p> - * <p> - * The default is to use buffered mode. - * </p> - * - * @see Field#setBuffered(boolean) - * @param buffered - * true to turn on buffered mode, false otherwise - */ - public void setBuffered(boolean buffered) { - if (buffered == this.buffered) { - return; - } - - this.buffered = buffered; - for (Field<?> field : getFields()) { - field.setBuffered(buffered); - } - } - - /** - * Returns the enabled status for the fields. - * <p> - * Note that this will not accurately represent the enabled status of all - * fields if you change the enabled status of the fields through some other - * method than {@link #setEnabled(boolean)}. - * - * @return true if the fields are enabled, false otherwise - */ - public boolean isEnabled() { - return enabled; - } - - /** - * Updates the enabled state of all bound fields. - * - * @param fieldsEnabled - * true to enable all bound fields, false to disable them - */ - public void setEnabled(boolean fieldsEnabled) { - enabled = fieldsEnabled; - for (Field<?> field : getFields()) { - field.setEnabled(fieldsEnabled); - } - } - - /** - * Returns the read only status for the fields. - * <p> - * Note that this will not accurately represent the read only status of all - * fields if you change the read only status of the fields through some - * other method than {@link #setReadOnly(boolean)}. - * - * @return true if the fields are set to read only, false otherwise - */ - public boolean isReadOnly() { - return readOnly; - } - - /** - * Updates the read only state of all bound fields. - * - * @param fieldsReadOnly - * true to set all bound fields to read only, false to set them - * to read write - */ - public void setReadOnly(boolean fieldsReadOnly) { - readOnly = fieldsReadOnly; - } - - /** - * Returns a collection of all fields that have been bound. - * <p> - * The fields are not returned in any specific order. - * </p> - * - * @return A collection with all bound Fields - */ - public Collection<Field<?>> getFields() { - return fieldToPropertyId.keySet(); - } - - /** - * Binds the field with the given propertyId from the current item. If an - * item has not been set then the binding is postponed until the item is set - * using {@link #setItemDataSource(Item)}. - * <p> - * This method also adds validators when applicable. - * </p> - * - * @param field - * The field to bind - * @param propertyId - * The propertyId to bind to the field - * @throws BindException - * If the property id is already bound to another field by this - * field binder - */ - public void bind(Field<?> field, Object propertyId) throws BindException { - if (propertyIdToField.containsKey(propertyId) - && propertyIdToField.get(propertyId) != field) { - throw new BindException("Property id " + propertyId - + " is already bound to another field"); - } - fieldToPropertyId.put(field, propertyId); - propertyIdToField.put(propertyId, field); - if (itemDataSource == null) { - // Will be bound when data source is set - return; - } - - field.setPropertyDataSource(wrapInTransactionalProperty(getItemProperty(propertyId))); - configureField(field); - } - - private <T> Property.Transactional<T> wrapInTransactionalProperty( - Property<T> itemProperty) { - return new TransactionalPropertyWrapper<T>(itemProperty); - } - - /** - * Gets the property with the given property id from the item. - * - * @param propertyId - * The id if the property to find - * @return The property with the given id from the item - * @throws BindException - * If the property was not found in the item or no item has been - * set - */ - protected Property<?> getItemProperty(Object propertyId) - throws BindException { - Item item = getItemDataSource(); - if (item == null) { - throw new BindException("Could not lookup property with id " - + propertyId + " as no item has been set"); - } - Property<?> p = item.getItemProperty(propertyId); - if (p == null) { - throw new BindException("A property with id " + propertyId - + " was not found in the item"); - } - return p; - } - - /** - * Detaches the field from its property id and removes it from this - * FieldBinder. - * <p> - * Note that the field is not detached from its property data source if it - * is no longer connected to the same property id it was bound to using this - * FieldBinder. - * - * @param field - * The field to detach - * @throws BindException - * If the field is not bound by this field binder or not bound - * to the correct property id - */ - public void unbind(Field<?> field) throws BindException { - Object propertyId = fieldToPropertyId.get(field); - if (propertyId == null) { - throw new BindException( - "The given field is not part of this FieldBinder"); - } - - Property fieldDataSource = field.getPropertyDataSource(); - if (fieldDataSource instanceof TransactionalPropertyWrapper) { - fieldDataSource = ((TransactionalPropertyWrapper) fieldDataSource) - .getWrappedProperty(); - } - if (fieldDataSource == getItemProperty(propertyId)) { - field.setPropertyDataSource(null); - } - fieldToPropertyId.remove(field); - propertyIdToField.remove(propertyId); - } - - /** - * Configures a field with the settings set for this FieldBinder. - * <p> - * By default this updates the buffered, read only and enabled state of the - * field. Also adds validators when applicable. - * - * @param field - * The field to update - */ - protected void configureField(Field<?> field) { - field.setBuffered(isBuffered()); - - field.setEnabled(isEnabled()); - field.setReadOnly(isReadOnly()); - } - - /** - * Gets the type of the property with the given property id. - * - * @param propertyId - * The propertyId. Must be find - * @return The type of the property - */ - protected Class<?> getPropertyType(Object propertyId) throws BindException { - if (getItemDataSource() == null) { - throw new BindException( - "Property type for '" - + propertyId - + "' could not be determined. No item data source has been set."); - } - Property<?> p = getItemDataSource().getItemProperty(propertyId); - if (p == null) { - throw new BindException( - "Property type for '" - + propertyId - + "' could not be determined. No property with that id was found."); - } - - return p.getType(); - } - - /** - * Returns a collection of all property ids that have been bound to fields. - * <p> - * Note that this will return property ids even before the item has been - * set. In that case it returns the property ids that will be bound once the - * item is set. - * </p> - * <p> - * No guarantee is given for the order of the property ids - * </p> - * - * @return A collection of bound property ids - */ - public Collection<Object> getBoundPropertyIds() { - return Collections.unmodifiableCollection(propertyIdToField.keySet()); - } - - /** - * Returns a collection of all property ids that exist in the item set using - * {@link #setItemDataSource(Item)} but have not been bound to fields. - * <p> - * Will always return an empty collection before an item has been set using - * {@link #setItemDataSource(Item)}. - * </p> - * <p> - * No guarantee is given for the order of the property ids - * </p> - * - * @return A collection of property ids that have not been bound to fields - */ - public Collection<Object> getUnboundPropertyIds() { - if (getItemDataSource() == null) { - return new ArrayList<Object>(); - } - List<Object> unboundPropertyIds = new ArrayList<Object>(); - unboundPropertyIds.addAll(getItemDataSource().getItemPropertyIds()); - unboundPropertyIds.removeAll(propertyIdToField.keySet()); - return unboundPropertyIds; - } - - /** - * Commits all changes done to the bound fields. - * <p> - * Calls all {@link CommitHandler}s before and after committing the field - * changes to the item data source. The whole commit is aborted and state is - * restored to what it was before commit was called if any - * {@link CommitHandler} throws a CommitException or there is a problem - * committing the fields - * - * @throws CommitException - * If the commit was aborted - */ - public void commit() throws CommitException { - if (!isBuffered()) { - // Not using buffered mode, nothing to do - return; - } - for (Field<?> f : fieldToPropertyId.keySet()) { - ((Property.Transactional<?>) f.getPropertyDataSource()) - .startTransaction(); - } - try { - firePreCommitEvent(); - // Commit the field values to the properties - for (Field<?> f : fieldToPropertyId.keySet()) { - f.commit(); - } - firePostCommitEvent(); - - // Commit the properties - for (Field<?> f : fieldToPropertyId.keySet()) { - ((Property.Transactional<?>) f.getPropertyDataSource()) - .commit(); - } - - } catch (Exception e) { - for (Field<?> f : fieldToPropertyId.keySet()) { - try { - ((Property.Transactional<?>) f.getPropertyDataSource()) - .rollback(); - } catch (Exception rollbackException) { - // FIXME: What to do ? - } - } - - throw new CommitException("Commit failed", e); - } - - } - - /** - * Sends a preCommit event to all registered commit handlers - * - * @throws CommitException - * If the commit should be aborted - */ - private void firePreCommitEvent() throws CommitException { - CommitHandler[] handlers = commitHandlers - .toArray(new CommitHandler[commitHandlers.size()]); - - for (CommitHandler handler : handlers) { - handler.preCommit(new CommitEvent(this)); - } - } - - /** - * Sends a postCommit event to all registered commit handlers - * - * @throws CommitException - * If the commit should be aborted - */ - private void firePostCommitEvent() throws CommitException { - CommitHandler[] handlers = commitHandlers - .toArray(new CommitHandler[commitHandlers.size()]); - - for (CommitHandler handler : handlers) { - handler.postCommit(new CommitEvent(this)); - } - } - - /** - * Discards all changes done to the bound fields. - * <p> - * Only has effect if buffered mode is used. - * - */ - public void discard() { - for (Field<?> f : fieldToPropertyId.keySet()) { - try { - f.discard(); - } catch (Exception e) { - // TODO: handle exception - // What can we do if discard fails other than try to discard all - // other fields? - } - } - } - - /** - * Returns the field that is bound to the given property id - * - * @param propertyId - * The property id to use to lookup the field - * @return The field that is bound to the property id or null if no field is - * bound to that property id - */ - public Field<?> getField(Object propertyId) { - return propertyIdToField.get(propertyId); - } - - /** - * Returns the property id that is bound to the given field - * - * @param field - * The field to use to lookup the property id - * @return The property id that is bound to the field or null if the field - * is not bound to any property id by this FieldBinder - */ - public Object getPropertyId(Field<?> field) { - return fieldToPropertyId.get(field); - } - - /** - * Adds a commit handler. - * <p> - * The commit handler is called before the field values are committed to the - * item ( {@link CommitHandler#preCommit(CommitEvent)}) and after the item - * has been updated ({@link CommitHandler#postCommit(CommitEvent)}). If a - * {@link CommitHandler} throws a CommitException the whole commit is - * aborted and the fields retain their old values. - * - * @param commitHandler - * The commit handler to add - */ - public void addCommitHandler(CommitHandler commitHandler) { - commitHandlers.add(commitHandler); - } - - /** - * Removes the given commit handler. - * - * @see #addCommitHandler(CommitHandler) - * - * @param commitHandler - * The commit handler to remove - */ - public void removeCommitHandler(CommitHandler commitHandler) { - commitHandlers.remove(commitHandler); - } - - /** - * Returns a list of all commit handlers for this {@link FieldGroup}. - * <p> - * Use {@link #addCommitHandler(CommitHandler)} and - * {@link #removeCommitHandler(CommitHandler)} to register or unregister a - * commit handler. - * - * @return A collection of commit handlers - */ - protected Collection<CommitHandler> getCommitHandlers() { - return Collections.unmodifiableCollection(commitHandlers); - } - - /** - * CommitHandlers are used by {@link FieldGroup#commit()} as part of the - * commit transactions. CommitHandlers can perform custom operations as part - * of the commit and cause the commit to be aborted by throwing a - * {@link CommitException}. - */ - public interface CommitHandler extends Serializable { - /** - * Called before changes are committed to the field and the item is - * updated. - * <p> - * Throw a {@link CommitException} to abort the commit. - * - * @param commitEvent - * An event containing information regarding the commit - * @throws CommitException - * if the commit should be aborted - */ - public void preCommit(CommitEvent commitEvent) throws CommitException; - - /** - * Called after changes are committed to the fields and the item is - * updated.. - * <p> - * Throw a {@link CommitException} to abort the commit. - * - * @param commitEvent - * An event containing information regarding the commit - * @throws CommitException - * if the commit should be aborted - */ - public void postCommit(CommitEvent commitEvent) throws CommitException; - } - - /** - * FIXME javadoc - * - */ - public static class CommitEvent implements Serializable { - private FieldGroup fieldBinder; - - private CommitEvent(FieldGroup fieldBinder) { - this.fieldBinder = fieldBinder; - } - - /** - * Returns the field binder that this commit relates to - * - * @return The FieldBinder that is being committed. - */ - public FieldGroup getFieldBinder() { - return fieldBinder; - } - - } - - /** - * Checks the validity of the bound fields. - * <p> - * Call the {@link Field#validate()} for the fields to get the individual - * error messages. - * - * @return true if all bound fields are valid, false otherwise. - */ - public boolean isValid() { - try { - for (Field<?> field : getFields()) { - field.validate(); - } - return true; - } catch (InvalidValueException e) { - return false; - } - } - - /** - * Checks if any bound field has been modified. - * - * @return true if at least on field has been modified, false otherwise - */ - public boolean isModified() { - for (Field<?> field : getFields()) { - if (field.isModified()) { - return true; - } - } - return false; - } - - /** - * Gets the field factory for the {@link FieldGroup}. The field factory is - * only used when {@link FieldGroup} creates a new field. - * - * @return The field factory in use - * - */ - public FieldGroupFieldFactory getFieldFactory() { - return fieldFactory; - } - - /** - * Sets the field factory for the {@link FieldGroup}. The field factory is - * only used when {@link FieldGroup} creates a new field. - * - * @param fieldFactory - * The field factory to use - */ - public void setFieldFactory(FieldGroupFieldFactory fieldFactory) { - this.fieldFactory = fieldFactory; - } - - /** - * Binds member fields found in the given object. - * <p> - * This method processes all (Java) member fields whose type extends - * {@link Field} and that can be mapped to a property id. Property id - * mapping is done based on the field name or on a @{@link PropertyId} - * annotation on the field. All non-null fields for which a property id can - * be determined are bound to the property id. - * </p> - * <p> - * For example: - * - * <pre> - * public class MyForm extends VerticalLayout { - * private TextField firstName = new TextField("First name"); - * @PropertyId("last") - * private TextField lastName = new TextField("Last name"); - * private TextField age = new TextField("Age"); ... } - * - * MyForm myForm = new MyForm(); - * ... - * fieldGroup.bindMemberFields(myForm); - * </pre> - * - * </p> - * This binds the firstName TextField to a "firstName" property in the item, - * lastName TextField to a "last" property and the age TextField to a "age" - * property. - * - * @param objectWithMemberFields - * The object that contains (Java) member fields to bind - * @throws BindException - * If there is a problem binding a field - */ - public void bindMemberFields(Object objectWithMemberFields) - throws BindException { - buildAndBindMemberFields(objectWithMemberFields, false); - } - - /** - * Binds member fields found in the given object and builds member fields - * that have not been initialized. - * <p> - * This method processes all (Java) member fields whose type extends - * {@link Field} and that can be mapped to a property id. Property id - * mapping is done based on the field name or on a @{@link PropertyId} - * annotation on the field. Fields that are not initialized (null) are built - * using the field factory. All non-null fields for which a property id can - * be determined are bound to the property id. - * </p> - * <p> - * For example: - * - * <pre> - * public class MyForm extends VerticalLayout { - * private TextField firstName = new TextField("First name"); - * @PropertyId("last") - * private TextField lastName = new TextField("Last name"); - * private TextField age; - * - * MyForm myForm = new MyForm(); - * ... - * fieldGroup.buildAndBindMemberFields(myForm); - * </pre> - * - * </p> - * <p> - * This binds the firstName TextField to a "firstName" property in the item, - * lastName TextField to a "last" property and builds an age TextField using - * the field factory and then binds it to the "age" property. - * </p> - * - * @param objectWithMemberFields - * The object that contains (Java) member fields to build and - * bind - * @throws BindException - * If there is a problem binding or building a field - */ - public void buildAndBindMemberFields(Object objectWithMemberFields) - throws BindException { - buildAndBindMemberFields(objectWithMemberFields, true); - } - - /** - * Binds member fields found in the given object and optionally builds - * member fields that have not been initialized. - * <p> - * This method processes all (Java) member fields whose type extends - * {@link Field} and that can be mapped to a property id. Property id - * mapping is done based on the field name or on a @{@link PropertyId} - * annotation on the field. Fields that are not initialized (null) are built - * using the field factory is buildFields is true. All non-null fields for - * which a property id can be determined are bound to the property id. - * </p> - * - * @param objectWithMemberFields - * The object that contains (Java) member fields to build and - * bind - * @throws BindException - * If there is a problem binding or building a field - */ - protected void buildAndBindMemberFields(Object objectWithMemberFields, - boolean buildFields) throws BindException { - Class<?> objectClass = objectWithMemberFields.getClass(); - - for (java.lang.reflect.Field memberField : objectClass - .getDeclaredFields()) { - - if (!Field.class.isAssignableFrom(memberField.getType())) { - // Process next field - continue; - } - - PropertyId propertyIdAnnotation = memberField - .getAnnotation(PropertyId.class); - - Class<? extends Field> fieldType = (Class<? extends Field>) memberField - .getType(); - - Object propertyId = null; - if (propertyIdAnnotation != null) { - // @PropertyId(propertyId) always overrides property id - propertyId = propertyIdAnnotation.value(); - } else { - propertyId = memberField.getName(); - } - - // Ensure that the property id exists - Class<?> propertyType; - - try { - propertyType = getPropertyType(propertyId); - } catch (BindException e) { - // Property id was not found, skip this field - continue; - } - - Field<?> field; - try { - // Get the field from the object - field = (Field<?>) ReflectTools.getJavaFieldValue( - objectWithMemberFields, memberField); - } catch (Exception e) { - // If we cannot determine the value, just skip the field and try - // the next one - continue; - } - - if (field == null && buildFields) { - Caption captionAnnotation = memberField - .getAnnotation(Caption.class); - String caption; - if (captionAnnotation != null) { - caption = captionAnnotation.value(); - } else { - caption = DefaultFieldFactory - .createCaptionByPropertyId(propertyId); - } - - // Create the component (Field) - field = build(caption, propertyType, fieldType); - - // Store it in the field - try { - ReflectTools.setJavaFieldValue(objectWithMemberFields, - memberField, field); - } catch (IllegalArgumentException e) { - throw new BindException("Could not assign value to field '" - + memberField.getName() + "'", e); - } catch (IllegalAccessException e) { - throw new BindException("Could not assign value to field '" - + memberField.getName() + "'", e); - } catch (InvocationTargetException e) { - throw new BindException("Could not assign value to field '" - + memberField.getName() + "'", e); - } - } - - if (field != null) { - // Bind it to the property id - bind(field, propertyId); - } - } - } - - public static class CommitException extends Exception { - - public CommitException() { - super(); - // TODO Auto-generated constructor stub - } - - public CommitException(String message, Throwable cause) { - super(message, cause); - // TODO Auto-generated constructor stub - } - - public CommitException(String message) { - super(message); - // TODO Auto-generated constructor stub - } - - public CommitException(Throwable cause) { - super(cause); - // TODO Auto-generated constructor stub - } - - } - - public static class BindException extends RuntimeException { - - public BindException(String message) { - super(message); - } - - public BindException(String message, Throwable t) { - super(message, t); - } - - } - - /** - * Builds a field and binds it to the given property id using the field - * binder. - * - * @param propertyId - * The property id to bind to. Must be present in the field - * finder. - * @throws BindException - * If there is a problem while building or binding - * @return The created and bound field - */ - public Field<?> buildAndBind(Object propertyId) throws BindException { - String caption = DefaultFieldFactory - .createCaptionByPropertyId(propertyId); - return buildAndBind(caption, propertyId); - } - - /** - * Builds a field using the given caption and binds it to the given property - * id using the field binder. - * - * @param caption - * The caption for the field - * @param propertyId - * The property id to bind to. Must be present in the field - * finder. - * @throws BindException - * If there is a problem while building or binding - * @return The created and bound field. Can be any type of {@link Field}. - */ - public Field<?> buildAndBind(String caption, Object propertyId) - throws BindException { - Class<?> type = getPropertyType(propertyId); - return buildAndBind(caption, propertyId, Field.class); - - } - - /** - * Builds a field using the given caption and binds it to the given property - * id using the field binder. Ensures the new field is of the given type. - * - * @param caption - * The caption for the field - * @param propertyId - * The property id to bind to. Must be present in the field - * finder. - * @throws BindException - * If the field could not be created - * @return The created and bound field. Can be any type of {@link Field}. - */ - - public <T extends Field> T buildAndBind(String caption, Object propertyId, - Class<T> fieldType) throws BindException { - Class<?> type = getPropertyType(propertyId); - - T field = build(caption, type, fieldType); - bind(field, propertyId); - - return field; - } - - /** - * Creates a field based on the given data type. - * <p> - * The data type is the type that we want to edit using the field. The field - * type is the type of field we want to create, can be {@link Field} if any - * Field is good. - * </p> - * - * @param caption - * The caption for the new field - * @param dataType - * The data model type that we want to edit using the field - * @param fieldType - * The type of field that we want to create - * @return A Field capable of editing the given type - * @throws BindException - * If the field could not be created - */ - protected <T extends Field> T build(String caption, Class<?> dataType, - Class<T> fieldType) throws BindException { - T field = getFieldFactory().createField(dataType, fieldType); - if (field == null) { - throw new BindException("Unable to build a field of type " - + fieldType.getName() + " for editing " - + dataType.getName()); - } - - field.setCaption(caption); - return field; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java b/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java deleted file mode 100644 index 80c012cbdc..0000000000 --- a/src/com/vaadin/data/fieldgroup/FieldGroupFieldFactory.java +++ /dev/null @@ -1,31 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.fieldgroup; - -import java.io.Serializable; - -import com.vaadin.ui.Field; - -/** - * Factory interface for creating new Field-instances based on the data type - * that should be edited. - * - * @author Vaadin Ltd. - * @version @version@ - * @since 7.0 - */ -public interface FieldGroupFieldFactory extends Serializable { - /** - * Creates a field based on the data type that we want to edit - * - * @param dataType - * The type that we want to edit using the field - * @param fieldType - * The type of field we want to create. If set to {@link Field} - * then any type of field is accepted - * @return A field that can be assigned to the given fieldType and that is - * capable of editing the given type of data - */ - <T extends Field> T createField(Class<?> dataType, Class<T> fieldType); -} diff --git a/src/com/vaadin/data/fieldgroup/PropertyId.java b/src/com/vaadin/data/fieldgroup/PropertyId.java deleted file mode 100644 index 268047401d..0000000000 --- a/src/com/vaadin/data/fieldgroup/PropertyId.java +++ /dev/null @@ -1,15 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.fieldgroup; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ ElementType.FIELD }) -@Retention(RetentionPolicy.RUNTIME) -public @interface PropertyId { - String value(); -} diff --git a/src/com/vaadin/data/package.html b/src/com/vaadin/data/package.html deleted file mode 100644 index a14ea1ac88..0000000000 --- a/src/com/vaadin/data/package.html +++ /dev/null @@ -1,49 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -</head> - -<body bgcolor="white"> - -<p>Contains interfaces for the data layer, mainly for binding typed -data and data collections to components, and for validating data.</p> - -<h2>Data binding</h2> - -<p>The package contains a three-tiered structure for typed data -objects and collections of them:</p> - -<ul> - <li>A {@link com.vaadin.data.Property Property} represents a - single, typed data value. - - <li>An {@link com.vaadin.data.Item Item} embodies a set of <i>Properties</i>. - A locally unique (inside the {@link com.vaadin.data.Item Item}) - Property identifier corresponds to each Property inside the Item.</li> - <li>A {@link com.vaadin.data.Container Container} contains a set - of Items, each corresponding to a locally unique Item identifier. Note - that Container imposes a few restrictions on the data stored in it, see - {@link com.vaadin.data.Container Container} for further information.</li> -</ul> - -<p>For more information on the data model, see the <a - href="http://vaadin.com/book/-/page/datamodel.html">Data model -chapter</a> in Book of Vaadin.</p> - -<h2>Buffering</h2> - -<p>A {@link com.vaadin.data.Buffered Buffered} implementor is able -to track and buffer changes and commit or discard them later.</p> - -<h2>Validation</h2> - -<p>{@link com.vaadin.data.Validator Validator} implementations are -used to validate data, typically the value of a {@link -com.vaadin.ui.Field Field}. One or more {@link com.vaadin.data.Validator -Validators} can be added to a {@link com.vaadin.data.Validatable -Validatable} implementor and then used to validate the value of the -Validatable. </p> - -<!-- Put @see and @since tags down here. --> -</body> -</html> diff --git a/src/com/vaadin/data/util/AbstractBeanContainer.java b/src/com/vaadin/data/util/AbstractBeanContainer.java deleted file mode 100644 index 2f428d2cb6..0000000000 --- a/src/com/vaadin/data/util/AbstractBeanContainer.java +++ /dev/null @@ -1,856 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.io.Serializable; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import com.vaadin.data.Container; -import com.vaadin.data.Container.Filterable; -import com.vaadin.data.Container.PropertySetChangeNotifier; -import com.vaadin.data.Container.SimpleFilterable; -import com.vaadin.data.Container.Sortable; -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.data.Property.ValueChangeEvent; -import com.vaadin.data.Property.ValueChangeListener; -import com.vaadin.data.Property.ValueChangeNotifier; -import com.vaadin.data.util.MethodProperty.MethodException; -import com.vaadin.data.util.filter.SimpleStringFilter; -import com.vaadin.data.util.filter.UnsupportedFilterException; - -/** - * An abstract base class for in-memory containers for JavaBeans. - * - * <p> - * The properties of the container are determined automatically by introspecting - * the used JavaBean class and explicitly adding or removing properties is not - * supported. Only beans of the same type can be added to the container. - * </p> - * - * <p> - * Subclasses should implement any public methods adding items to the container, - * typically calling the protected methods {@link #addItem(Object, Object)}, - * {@link #addItemAfter(Object, Object, Object)} and - * {@link #addItemAt(int, Object, Object)}. - * </p> - * - * @param <IDTYPE> - * The type of the item identifier - * @param <BEANTYPE> - * The type of the Bean - * - * @since 6.5 - */ -public abstract class AbstractBeanContainer<IDTYPE, BEANTYPE> extends - AbstractInMemoryContainer<IDTYPE, String, BeanItem<BEANTYPE>> implements - Filterable, SimpleFilterable, Sortable, ValueChangeListener, - PropertySetChangeNotifier { - - /** - * Resolver that maps beans to their (item) identifiers, removing the need - * to explicitly specify item identifiers when there is no need to customize - * this. - * - * Note that beans can also be added with an explicit id even if a resolver - * has been set. - * - * @param <IDTYPE> - * @param <BEANTYPE> - * - * @since 6.5 - */ - public static interface BeanIdResolver<IDTYPE, BEANTYPE> extends - Serializable { - /** - * Return the item identifier for a bean. - * - * @param bean - * @return - */ - public IDTYPE getIdForBean(BEANTYPE bean); - } - - /** - * A item identifier resolver that returns the value of a bean property. - * - * The bean must have a getter for the property, and the getter must return - * an object of type IDTYPE. - */ - protected class PropertyBasedBeanIdResolver implements - BeanIdResolver<IDTYPE, BEANTYPE> { - - private final Object propertyId; - - public PropertyBasedBeanIdResolver(Object propertyId) { - if (propertyId == null) { - throw new IllegalArgumentException( - "Property identifier must not be null"); - } - this.propertyId = propertyId; - } - - @Override - @SuppressWarnings("unchecked") - public IDTYPE getIdForBean(BEANTYPE bean) - throws IllegalArgumentException { - VaadinPropertyDescriptor<BEANTYPE> pd = model.get(propertyId); - if (null == pd) { - throw new IllegalStateException("Property " + propertyId - + " not found"); - } - try { - Property<IDTYPE> property = (Property<IDTYPE>) pd - .createProperty(bean); - return property.getValue(); - } catch (MethodException e) { - throw new IllegalArgumentException(e); - } - } - - } - - /** - * The resolver that finds the item ID for a bean, or null not to use - * automatic resolving. - * - * Methods that add a bean without specifying an ID must not be called if no - * resolver has been set. - */ - private BeanIdResolver<IDTYPE, BEANTYPE> beanIdResolver = null; - - /** - * Maps all item ids in the container (including filtered) to their - * corresponding BeanItem. - */ - private final Map<IDTYPE, BeanItem<BEANTYPE>> itemIdToItem = new HashMap<IDTYPE, BeanItem<BEANTYPE>>(); - - /** - * The type of the beans in the container. - */ - private final Class<? super BEANTYPE> type; - - /** - * A description of the properties found in beans of type {@link #type}. - * Determines the property ids that are present in the container. - */ - private LinkedHashMap<String, VaadinPropertyDescriptor<BEANTYPE>> model; - - /** - * Constructs a {@code AbstractBeanContainer} for beans of the given type. - * - * @param type - * the type of the beans that will be added to the container. - * @throws IllegalArgumentException - * If {@code type} is null - */ - protected AbstractBeanContainer(Class<? super BEANTYPE> type) { - if (type == null) { - throw new IllegalArgumentException( - "The bean type passed to AbstractBeanContainer must not be null"); - } - this.type = type; - model = BeanItem.getPropertyDescriptors((Class<BEANTYPE>) type); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getType(java.lang.Object) - */ - @Override - public Class<?> getType(Object propertyId) { - return model.get(propertyId).getPropertyType(); - } - - /** - * Create a BeanItem for a bean using pre-parsed bean metadata (based on - * {@link #getBeanType()}). - * - * @param bean - * @return created {@link BeanItem} or null if bean is null - */ - protected BeanItem<BEANTYPE> createBeanItem(BEANTYPE bean) { - return bean == null ? null : new BeanItem<BEANTYPE>(bean, model); - } - - /** - * Returns the type of beans this Container can contain. - * - * This comes from the bean type constructor parameter, and bean metadata - * (including container properties) is based on this. - * - * @return - */ - public Class<? super BEANTYPE> getBeanType() { - return type; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getContainerPropertyIds() - */ - @Override - public Collection<String> getContainerPropertyIds() { - return model.keySet(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeAllItems() - */ - @Override - public boolean removeAllItems() { - int origSize = size(); - - internalRemoveAllItems(); - - // detach listeners from all Items - for (Item item : itemIdToItem.values()) { - removeAllValueChangeListeners(item); - } - itemIdToItem.clear(); - - // fire event only if the visible view changed, regardless of whether - // filtered out items were removed or not - if (origSize != 0) { - fireItemSetChange(); - } - - return true; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getItem(java.lang.Object) - */ - @Override - public BeanItem<BEANTYPE> getItem(Object itemId) { - // TODO return only if visible? - return getUnfilteredItem(itemId); - } - - @Override - protected BeanItem<BEANTYPE> getUnfilteredItem(Object itemId) { - return itemIdToItem.get(itemId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getItemIds() - */ - @Override - @SuppressWarnings("unchecked") - public List<IDTYPE> getItemIds() { - return (List<IDTYPE>) super.getItemIds(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getContainerProperty(java.lang.Object, - * java.lang.Object) - */ - @Override - public Property<?> getContainerProperty(Object itemId, Object propertyId) { - Item item = getItem(itemId); - if (item == null) { - return null; - } - return item.getItemProperty(propertyId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeItem(java.lang.Object) - */ - @Override - public boolean removeItem(Object itemId) { - // TODO should also remove items that are filtered out - int origSize = size(); - Item item = getItem(itemId); - int position = indexOfId(itemId); - - if (internalRemoveItem(itemId)) { - // detach listeners from Item - removeAllValueChangeListeners(item); - - // remove item - itemIdToItem.remove(itemId); - - // fire event only if the visible view changed, regardless of - // whether filtered out items were removed or not - if (size() != origSize) { - fireItemRemoved(position, itemId); - } - - return true; - } else { - return false; - } - } - - /** - * Re-filter the container when one of the monitored properties changes. - */ - @Override - public void valueChange(ValueChangeEvent event) { - // if a property that is used in a filter is changed, refresh filtering - filterAll(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.Container.Filterable#addContainerFilter(java.lang.Object, - * java.lang.String, boolean, boolean) - */ - @Override - public void addContainerFilter(Object propertyId, String filterString, - boolean ignoreCase, boolean onlyMatchPrefix) { - try { - addFilter(new SimpleStringFilter(propertyId, filterString, - ignoreCase, onlyMatchPrefix)); - } catch (UnsupportedFilterException e) { - // the filter instance created here is always valid for in-memory - // containers - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Filterable#removeAllContainerFilters() - */ - @Override - public void removeAllContainerFilters() { - if (!getFilters().isEmpty()) { - for (Item item : itemIdToItem.values()) { - removeAllValueChangeListeners(item); - } - removeAllFilters(); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.Container.Filterable#removeContainerFilters(java.lang - * .Object) - */ - @Override - public void removeContainerFilters(Object propertyId) { - Collection<Filter> removedFilters = super.removeFilters(propertyId); - if (!removedFilters.isEmpty()) { - // stop listening to change events for the property - for (Item item : itemIdToItem.values()) { - removeValueChangeListener(item, propertyId); - } - } - } - - @Override - public void addContainerFilter(Filter filter) - throws UnsupportedFilterException { - addFilter(filter); - } - - @Override - public void removeContainerFilter(Filter filter) { - removeFilter(filter); - } - - /** - * Make this container listen to the given property provided it notifies - * when its value changes. - * - * @param item - * The {@link Item} that contains the property - * @param propertyId - * The id of the property - */ - private void addValueChangeListener(Item item, Object propertyId) { - Property<?> property = item.getItemProperty(propertyId); - if (property instanceof ValueChangeNotifier) { - // avoid multiple notifications for the same property if - // multiple filters are in use - ValueChangeNotifier notifier = (ValueChangeNotifier) property; - notifier.removeListener(this); - notifier.addListener(this); - } - } - - /** - * Remove this container as a listener for the given property. - * - * @param item - * The {@link Item} that contains the property - * @param propertyId - * The id of the property - */ - private void removeValueChangeListener(Item item, Object propertyId) { - Property<?> property = item.getItemProperty(propertyId); - if (property instanceof ValueChangeNotifier) { - ((ValueChangeNotifier) property).removeListener(this); - } - } - - /** - * Remove this contains as a listener for all the properties in the given - * {@link Item}. - * - * @param item - * The {@link Item} that contains the properties - */ - private void removeAllValueChangeListeners(Item item) { - for (Object propertyId : item.getItemPropertyIds()) { - removeValueChangeListener(item, propertyId); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Sortable#getSortableContainerPropertyIds() - */ - @Override - public Collection<?> getSortableContainerPropertyIds() { - return getSortablePropertyIds(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Sortable#sort(java.lang.Object[], - * boolean[]) - */ - @Override - public void sort(Object[] propertyId, boolean[] ascending) { - sortContainer(propertyId, ascending); - } - - @Override - public ItemSorter getItemSorter() { - return super.getItemSorter(); - } - - @Override - public void setItemSorter(ItemSorter itemSorter) { - super.setItemSorter(itemSorter); - } - - @Override - protected void registerNewItem(int position, IDTYPE itemId, - BeanItem<BEANTYPE> item) { - itemIdToItem.put(itemId, item); - - // add listeners to be able to update filtering on property - // changes - for (Filter filter : getFilters()) { - for (String propertyId : getContainerPropertyIds()) { - if (filter.appliesToProperty(propertyId)) { - // addValueChangeListener avoids adding duplicates - addValueChangeListener(item, propertyId); - } - } - } - } - - /** - * Check that a bean can be added to the container (is of the correct type - * for the container). - * - * @param bean - * @return - */ - private boolean validateBean(BEANTYPE bean) { - return bean != null && getBeanType().isAssignableFrom(bean.getClass()); - } - - /** - * Adds the bean to the Container. - * - * Note: the behavior of this method changed in Vaadin 6.6 - now items are - * added at the very end of the unfiltered container and not after the last - * visible item if filtering is used. - * - * @see com.vaadin.data.Container#addItem(Object) - */ - protected BeanItem<BEANTYPE> addItem(IDTYPE itemId, BEANTYPE bean) { - if (!validateBean(bean)) { - return null; - } - return internalAddItemAtEnd(itemId, createBeanItem(bean), true); - } - - /** - * Adds the bean after the given bean. - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(Object, Object) - */ - protected BeanItem<BEANTYPE> addItemAfter(IDTYPE previousItemId, - IDTYPE newItemId, BEANTYPE bean) { - if (!validateBean(bean)) { - return null; - } - return internalAddItemAfter(previousItemId, newItemId, - createBeanItem(bean), true); - } - - /** - * Adds a new bean at the given index. - * - * The bean is used both as the item contents and as the item identifier. - * - * @param index - * Index at which the bean should be added. - * @param newItemId - * The item id for the bean to add to the container. - * @param bean - * The bean to add to the container. - * - * @return Returns the new BeanItem or null if the operation fails. - */ - protected BeanItem<BEANTYPE> addItemAt(int index, IDTYPE newItemId, - BEANTYPE bean) { - if (!validateBean(bean)) { - return null; - } - return internalAddItemAt(index, newItemId, createBeanItem(bean), true); - } - - /** - * Adds a bean to the container using the bean item id resolver to find its - * identifier. - * - * A bean id resolver must be set before calling this method. - * - * @see #addItem(Object, Object) - * - * @param bean - * the bean to add - * @return BeanItem<BEANTYPE> item added or null - * @throws IllegalStateException - * if no bean identifier resolver has been set - * @throws IllegalArgumentException - * if an identifier cannot be resolved for the bean - */ - protected BeanItem<BEANTYPE> addBean(BEANTYPE bean) - throws IllegalStateException, IllegalArgumentException { - if (bean == null) { - return null; - } - IDTYPE itemId = resolveBeanId(bean); - if (itemId == null) { - throw new IllegalArgumentException( - "Resolved identifier for a bean must not be null"); - } - return addItem(itemId, bean); - } - - /** - * Adds a bean to the container after a specified item identifier, using the - * bean item id resolver to find its identifier. - * - * A bean id resolver must be set before calling this method. - * - * @see #addItemAfter(Object, Object, Object) - * - * @param previousItemId - * the identifier of the bean after which this bean should be - * added, null to add to the beginning - * @param bean - * the bean to add - * @return BeanItem<BEANTYPE> item added or null - * @throws IllegalStateException - * if no bean identifier resolver has been set - * @throws IllegalArgumentException - * if an identifier cannot be resolved for the bean - */ - protected BeanItem<BEANTYPE> addBeanAfter(IDTYPE previousItemId, - BEANTYPE bean) throws IllegalStateException, - IllegalArgumentException { - if (bean == null) { - return null; - } - IDTYPE itemId = resolveBeanId(bean); - if (itemId == null) { - throw new IllegalArgumentException( - "Resolved identifier for a bean must not be null"); - } - return addItemAfter(previousItemId, itemId, bean); - } - - /** - * Adds a bean at a specified (filtered view) position in the container - * using the bean item id resolver to find its identifier. - * - * A bean id resolver must be set before calling this method. - * - * @see #addItemAfter(Object, Object, Object) - * - * @param index - * the index (in the filtered view) at which to add the item - * @param bean - * the bean to add - * @return BeanItem<BEANTYPE> item added or null - * @throws IllegalStateException - * if no bean identifier resolver has been set - * @throws IllegalArgumentException - * if an identifier cannot be resolved for the bean - */ - protected BeanItem<BEANTYPE> addBeanAt(int index, BEANTYPE bean) - throws IllegalStateException, IllegalArgumentException { - if (bean == null) { - return null; - } - IDTYPE itemId = resolveBeanId(bean); - if (itemId == null) { - throw new IllegalArgumentException( - "Resolved identifier for a bean must not be null"); - } - return addItemAt(index, itemId, bean); - } - - /** - * Adds all the beans from a {@link Collection} in one operation using the - * bean item identifier resolver. More efficient than adding them one by - * one. - * - * A bean id resolver must be set before calling this method. - * - * Note: the behavior of this method changed in Vaadin 6.6 - now items are - * added at the very end of the unfiltered container and not after the last - * visible item if filtering is used. - * - * @param collection - * The collection of beans to add. Must not be null. - * @throws IllegalStateException - * if no bean identifier resolver has been set - * @throws IllegalArgumentException - * if the resolver returns a null itemId for one of the beans in - * the collection - */ - protected void addAll(Collection<? extends BEANTYPE> collection) - throws IllegalStateException, IllegalArgumentException { - boolean modified = false; - for (BEANTYPE bean : collection) { - // TODO skipping invalid beans - should not allow them in javadoc? - if (bean == null - || !getBeanType().isAssignableFrom(bean.getClass())) { - continue; - } - IDTYPE itemId = resolveBeanId(bean); - if (itemId == null) { - throw new IllegalArgumentException( - "Resolved identifier for a bean must not be null"); - } - - if (internalAddItemAtEnd(itemId, createBeanItem(bean), false) != null) { - modified = true; - } - } - - if (modified) { - // Filter the contents when all items have been added - if (isFiltered()) { - filterAll(); - } else { - fireItemSetChange(); - } - } - } - - /** - * Use the bean resolver to get the identifier for a bean. - * - * @param bean - * @return resolved bean identifier, null if could not be resolved - * @throws IllegalStateException - * if no bean resolver is set - */ - protected IDTYPE resolveBeanId(BEANTYPE bean) { - if (beanIdResolver == null) { - throw new IllegalStateException( - "Bean item identifier resolver is required."); - } - return beanIdResolver.getIdForBean(bean); - } - - /** - * Sets the resolver that finds the item id for a bean, or null not to use - * automatic resolving. - * - * Methods that add a bean without specifying an id must not be called if no - * resolver has been set. - * - * Note that methods taking an explicit id can be used whether a resolver - * has been defined or not. - * - * @param beanIdResolver - * to use or null to disable automatic id resolution - */ - protected void setBeanIdResolver( - BeanIdResolver<IDTYPE, BEANTYPE> beanIdResolver) { - this.beanIdResolver = beanIdResolver; - } - - /** - * Returns the resolver that finds the item ID for a bean. - * - * @return resolver used or null if automatic item id resolving is disabled - */ - public BeanIdResolver<IDTYPE, BEANTYPE> getBeanIdResolver() { - return beanIdResolver; - } - - /** - * Create an item identifier resolver using a named bean property. - * - * @param propertyId - * property identifier, which must map to a getter in BEANTYPE - * @return created resolver - */ - protected BeanIdResolver<IDTYPE, BEANTYPE> createBeanPropertyResolver( - Object propertyId) { - return new PropertyBasedBeanIdResolver(propertyId); - } - - @Override - public void addListener(Container.PropertySetChangeListener listener) { - super.addListener(listener); - } - - @Override - public void removeListener(Container.PropertySetChangeListener listener) { - super.removeListener(listener); - } - - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Use addNestedContainerProperty(String) to add container properties to a " - + getClass().getSimpleName()); - } - - /** - * Adds a property for the container and all its items. - * - * Primarily for internal use, may change in future versions. - * - * @param propertyId - * @param propertyDescriptor - * @return true if the property was added - */ - protected final boolean addContainerProperty(String propertyId, - VaadinPropertyDescriptor<BEANTYPE> propertyDescriptor) { - if (null == propertyId || null == propertyDescriptor) { - return false; - } - - // Fails if the Property is already present - if (model.containsKey(propertyId)) { - return false; - } - - model.put(propertyId, propertyDescriptor); - for (BeanItem<BEANTYPE> item : itemIdToItem.values()) { - item.addItemProperty(propertyId, - propertyDescriptor.createProperty(item.getBean())); - } - - // Sends a change event - fireContainerPropertySetChange(); - - return true; - } - - /** - * Adds a nested container property for the container, e.g. - * "manager.address.street". - * - * All intermediate getters must exist and must return non-null values when - * the property value is accessed. - * - * @see NestedMethodProperty - * - * @param propertyId - * @return true if the property was added - */ - public boolean addNestedContainerProperty(String propertyId) { - return addContainerProperty(propertyId, new NestedPropertyDescriptor( - propertyId, type)); - } - - /** - * Adds a nested container properties for all sub-properties of a named - * property to the container. The named property itself is removed from the - * model as its subproperties are added. - * - * All intermediate getters must exist and must return non-null values when - * the property value is accessed. - * - * @see NestedMethodProperty - * @see #addNestedContainerProperty(String) - * - * @param propertyId - */ - @SuppressWarnings("unchecked") - public void addNestedContainerBean(String propertyId) { - Class<?> propertyType = getType(propertyId); - LinkedHashMap<String, VaadinPropertyDescriptor<Object>> pds = BeanItem - .getPropertyDescriptors((Class<Object>) propertyType); - for (String subPropertyId : pds.keySet()) { - String qualifiedPropertyId = propertyId + "." + subPropertyId; - NestedPropertyDescriptor<BEANTYPE> pd = new NestedPropertyDescriptor<BEANTYPE>( - qualifiedPropertyId, (Class<BEANTYPE>) type); - model.put(qualifiedPropertyId, pd); - model.remove(propertyId); - for (BeanItem<BEANTYPE> item : itemIdToItem.values()) { - item.addItemProperty(propertyId, - pd.createProperty(item.getBean())); - item.removeItemProperty(propertyId); - } - } - - // Sends a change event - fireContainerPropertySetChange(); - } - - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - // Fails if the Property is not present - if (!model.containsKey(propertyId)) { - return false; - } - - // Removes the Property to Property list and types - model.remove(propertyId); - - // If remove the Property from all Items - for (final Iterator<IDTYPE> i = getAllItemIds().iterator(); i.hasNext();) { - getUnfilteredItem(i.next()).removeItemProperty(propertyId); - } - - // Sends a change event - fireContainerPropertySetChange(); - - return true; - } - -} diff --git a/src/com/vaadin/data/util/AbstractContainer.java b/src/com/vaadin/data/util/AbstractContainer.java deleted file mode 100644 index 7d96c2d757..0000000000 --- a/src/com/vaadin/data/util/AbstractContainer.java +++ /dev/null @@ -1,251 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.EventObject; -import java.util.LinkedList; - -import com.vaadin.data.Container; - -/** - * Abstract container class that manages event listeners and sending events to - * them ({@link PropertySetChangeNotifier}, {@link ItemSetChangeNotifier}). - * - * Note that this class provides the internal implementations for both types of - * events and notifiers as protected methods, but does not implement the - * {@link PropertySetChangeNotifier} and {@link ItemSetChangeNotifier} - * interfaces directly. This way, subclasses can choose not to implement them. - * Subclasses implementing those interfaces should also override the - * corresponding {@link #addListener()} and {@link #removeListener()} methods to - * make them public. - * - * @since 6.6 - */ -public abstract class AbstractContainer implements Container { - - /** - * List of all Property set change event listeners. - */ - private Collection<Container.PropertySetChangeListener> propertySetChangeListeners = null; - - /** - * List of all container Item set change event listeners. - */ - private Collection<Container.ItemSetChangeListener> itemSetChangeListeners = null; - - /** - * An <code>event</code> object specifying the container whose Property set - * has changed. - * - * This class does not provide information about which properties were - * concerned by the change, but subclasses can provide additional - * information about the changes. - */ - protected static class BasePropertySetChangeEvent extends EventObject - implements Container.PropertySetChangeEvent, Serializable { - - protected BasePropertySetChangeEvent(Container source) { - super(source); - } - - @Override - public Container getContainer() { - return (Container) getSource(); - } - } - - /** - * An <code>event</code> object specifying the container whose Item set has - * changed. - * - * This class does not provide information about the exact changes - * performed, but subclasses can add provide additional information about - * the changes. - */ - protected static class BaseItemSetChangeEvent extends EventObject implements - Container.ItemSetChangeEvent, Serializable { - - protected BaseItemSetChangeEvent(Container source) { - super(source); - } - - @Override - public Container getContainer() { - return (Container) getSource(); - } - } - - // PropertySetChangeNotifier - - /** - * Implementation of the corresponding method in - * {@link PropertySetChangeNotifier}, override with the corresponding public - * method and implement the interface to use this. - * - * @see PropertySetChangeNotifier#addListener(com.vaadin.data.Container.PropertySetChangeListener) - */ - protected void addListener(Container.PropertySetChangeListener listener) { - if (getPropertySetChangeListeners() == null) { - setPropertySetChangeListeners(new LinkedList<Container.PropertySetChangeListener>()); - } - getPropertySetChangeListeners().add(listener); - } - - /** - * Implementation of the corresponding method in - * {@link PropertySetChangeNotifier}, override with the corresponding public - * method and implement the interface to use this. - * - * @see PropertySetChangeNotifier#removeListener(com.vaadin.data.Container. - * PropertySetChangeListener) - */ - protected void removeListener(Container.PropertySetChangeListener listener) { - if (getPropertySetChangeListeners() != null) { - getPropertySetChangeListeners().remove(listener); - } - } - - // ItemSetChangeNotifier - - /** - * Implementation of the corresponding method in - * {@link ItemSetChangeNotifier}, override with the corresponding public - * method and implement the interface to use this. - * - * @see ItemSetChangeNotifier#addListener(com.vaadin.data.Container.ItemSetChangeListener) - */ - protected void addListener(Container.ItemSetChangeListener listener) { - if (getItemSetChangeListeners() == null) { - setItemSetChangeListeners(new LinkedList<Container.ItemSetChangeListener>()); - } - getItemSetChangeListeners().add(listener); - } - - /** - * Implementation of the corresponding method in - * {@link ItemSetChangeNotifier}, override with the corresponding public - * method and implement the interface to use this. - * - * @see ItemSetChangeNotifier#removeListener(com.vaadin.data.Container.ItemSetChangeListener) - */ - protected void removeListener(Container.ItemSetChangeListener listener) { - if (getItemSetChangeListeners() != null) { - getItemSetChangeListeners().remove(listener); - } - } - - /** - * Sends a simple Property set change event to all interested listeners. - */ - protected void fireContainerPropertySetChange() { - fireContainerPropertySetChange(new BasePropertySetChangeEvent(this)); - } - - /** - * Sends a Property set change event to all interested listeners. - * - * Use {@link #fireContainerPropertySetChange()} instead of this method - * unless additional information about the exact changes is available and - * should be included in the event. - * - * @param event - * the property change event to send, optionally with additional - * information - */ - protected void fireContainerPropertySetChange( - Container.PropertySetChangeEvent event) { - if (getPropertySetChangeListeners() != null) { - final Object[] l = getPropertySetChangeListeners().toArray(); - for (int i = 0; i < l.length; i++) { - ((Container.PropertySetChangeListener) l[i]) - .containerPropertySetChange(event); - } - } - } - - /** - * Sends a simple Item set change event to all interested listeners, - * indicating that anything in the contents may have changed (items added, - * removed etc.). - */ - protected void fireItemSetChange() { - fireItemSetChange(new BaseItemSetChangeEvent(this)); - } - - /** - * Sends an Item set change event to all registered interested listeners. - * - * @param event - * the item set change event to send, optionally with additional - * information - */ - protected void fireItemSetChange(ItemSetChangeEvent event) { - if (getItemSetChangeListeners() != null) { - final Object[] l = getItemSetChangeListeners().toArray(); - for (int i = 0; i < l.length; i++) { - ((Container.ItemSetChangeListener) l[i]) - .containerItemSetChange(event); - } - } - } - - /** - * Sets the property set change listener collection. For internal use only. - * - * @param propertySetChangeListeners - */ - protected void setPropertySetChangeListeners( - Collection<Container.PropertySetChangeListener> propertySetChangeListeners) { - this.propertySetChangeListeners = propertySetChangeListeners; - } - - /** - * Returns the property set change listener collection. For internal use - * only. - */ - protected Collection<Container.PropertySetChangeListener> getPropertySetChangeListeners() { - return propertySetChangeListeners; - } - - /** - * Sets the item set change listener collection. For internal use only. - * - * @param itemSetChangeListeners - */ - protected void setItemSetChangeListeners( - Collection<Container.ItemSetChangeListener> itemSetChangeListeners) { - this.itemSetChangeListeners = itemSetChangeListeners; - } - - /** - * Returns the item set change listener collection. For internal use only. - */ - protected Collection<Container.ItemSetChangeListener> getItemSetChangeListeners() { - return itemSetChangeListeners; - } - - public Collection<?> getListeners(Class<?> eventType) { - if (Container.PropertySetChangeEvent.class.isAssignableFrom(eventType)) { - if (propertySetChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(propertySetChangeListeners); - } - } else if (Container.ItemSetChangeEvent.class - .isAssignableFrom(eventType)) { - if (itemSetChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(itemSetChangeListeners); - } - } - - return Collections.EMPTY_LIST; - } -} diff --git a/src/com/vaadin/data/util/AbstractInMemoryContainer.java b/src/com/vaadin/data/util/AbstractInMemoryContainer.java deleted file mode 100644 index b7832756f2..0000000000 --- a/src/com/vaadin/data/util/AbstractInMemoryContainer.java +++ /dev/null @@ -1,941 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; - -import com.vaadin.data.Container; -import com.vaadin.data.Container.ItemSetChangeNotifier; -import com.vaadin.data.Item; -import com.vaadin.data.util.filter.SimpleStringFilter; -import com.vaadin.data.util.filter.UnsupportedFilterException; - -/** - * Abstract {@link Container} class that handles common functionality for - * in-memory containers. Concrete in-memory container classes can either inherit - * this class, inherit {@link AbstractContainer}, or implement the - * {@link Container} interface directly. - * - * Adding and removing items (if desired) must be implemented in subclasses by - * overriding the appropriate add*Item() and remove*Item() and removeAllItems() - * methods, calling the corresponding - * {@link #internalAddItemAfter(Object, Object, Item)}, - * {@link #internalAddItemAt(int, Object, Item)}, - * {@link #internalAddItemAtEnd(Object, Item, boolean)}, - * {@link #internalRemoveItem(Object)} and {@link #internalRemoveAllItems()} - * methods. - * - * By default, adding and removing container properties is not supported, and - * subclasses need to implement {@link #getContainerPropertyIds()}. Optionally, - * subclasses can override {@link #addContainerProperty(Object, Class, Object)} - * and {@link #removeContainerProperty(Object)} to implement them. - * - * Features: - * <ul> - * <li> {@link Container.Ordered} - * <li> {@link Container.Indexed} - * <li> {@link Filterable} and {@link SimpleFilterable} (internal implementation, - * does not implement the interface directly) - * <li> {@link Sortable} (internal implementation, does not implement the - * interface directly) - * </ul> - * - * To implement {@link Sortable}, subclasses need to implement - * {@link #getSortablePropertyIds()} and call the superclass method - * {@link #sortContainer(Object[], boolean[])} in the method - * <code>sort(Object[], boolean[])</code>. - * - * To implement {@link Filterable}, subclasses need to implement the methods - * {@link Filterable#addContainerFilter(com.vaadin.data.Container.Filter)} - * (calling {@link #addFilter(Filter)}), - * {@link Filterable#removeAllContainerFilters()} (calling - * {@link #removeAllFilters()}) and - * {@link Filterable#removeContainerFilter(com.vaadin.data.Container.Filter)} - * (calling {@link #removeFilter(com.vaadin.data.Container.Filter)}). - * - * To implement {@link SimpleFilterable}, subclasses also need to implement the - * methods - * {@link SimpleFilterable#addContainerFilter(Object, String, boolean, boolean)} - * and {@link SimpleFilterable#removeContainerFilters(Object)} calling - * {@link #addFilter(com.vaadin.data.Container.Filter)} and - * {@link #removeFilters(Object)} respectively. - * - * @param <ITEMIDTYPE> - * the class of item identifiers in the container, use Object if can - * be any class - * @param <PROPERTYIDCLASS> - * the class of property identifiers for the items in the container, - * use Object if can be any class - * @param <ITEMCLASS> - * the (base) class of the Item instances in the container, use - * {@link Item} if unknown - * - * @since 6.6 - */ -public abstract class AbstractInMemoryContainer<ITEMIDTYPE, PROPERTYIDCLASS, ITEMCLASS extends Item> - extends AbstractContainer implements ItemSetChangeNotifier, - Container.Indexed { - - /** - * An ordered {@link List} of all item identifiers in the container, - * including those that have been filtered out. - * - * Must not be null. - */ - private List<ITEMIDTYPE> allItemIds; - - /** - * An ordered {@link List} of item identifiers in the container after - * filtering, excluding those that have been filtered out. - * - * This is what the external API of the {@link Container} interface and its - * subinterfaces shows (e.g. {@link #size()}, {@link #nextItemId(Object)}). - * - * If null, the full item id list is used instead. - */ - private List<ITEMIDTYPE> filteredItemIds; - - /** - * Filters that are applied to the container to limit the items visible in - * it - */ - private Set<Filter> filters = new HashSet<Filter>(); - - /** - * The item sorter which is used for sorting the container. - */ - private ItemSorter itemSorter = new DefaultItemSorter(); - - // Constructors - - /** - * Constructor for an abstract in-memory container. - */ - protected AbstractInMemoryContainer() { - setAllItemIds(new ListSet<ITEMIDTYPE>()); - } - - // Container interface methods with more specific return class - - // default implementation, can be overridden - @Override - public ITEMCLASS getItem(Object itemId) { - if (containsId(itemId)) { - return getUnfilteredItem(itemId); - } else { - return null; - } - } - - /** - * Get an item even if filtered out. - * - * For internal use only. - * - * @param itemId - * @return - */ - protected abstract ITEMCLASS getUnfilteredItem(Object itemId); - - // cannot override getContainerPropertyIds() and getItemIds(): if subclass - // uses Object as ITEMIDCLASS or PROPERTYIDCLASS, Collection<Object> cannot - // be cast to Collection<MyInterface> - - // public abstract Collection<PROPERTYIDCLASS> getContainerPropertyIds(); - // public abstract Collection<ITEMIDCLASS> getItemIds(); - - // Container interface method implementations - - @Override - public int size() { - return getVisibleItemIds().size(); - } - - @Override - public boolean containsId(Object itemId) { - // only look at visible items after filtering - if (itemId == null) { - return false; - } else { - return getVisibleItemIds().contains(itemId); - } - } - - @Override - public List<?> getItemIds() { - return Collections.unmodifiableList(getVisibleItemIds()); - } - - // Container.Ordered - - @Override - public ITEMIDTYPE nextItemId(Object itemId) { - int index = indexOfId(itemId); - if (index >= 0 && index < size() - 1) { - return getIdByIndex(index + 1); - } else { - // out of bounds - return null; - } - } - - @Override - public ITEMIDTYPE prevItemId(Object itemId) { - int index = indexOfId(itemId); - if (index > 0) { - return getIdByIndex(index - 1); - } else { - // out of bounds - return null; - } - } - - @Override - public ITEMIDTYPE firstItemId() { - if (size() > 0) { - return getIdByIndex(0); - } else { - return null; - } - } - - @Override - public ITEMIDTYPE lastItemId() { - if (size() > 0) { - return getIdByIndex(size() - 1); - } else { - return null; - } - } - - @Override - public boolean isFirstId(Object itemId) { - if (itemId == null) { - return false; - } - return itemId.equals(firstItemId()); - } - - @Override - public boolean isLastId(Object itemId) { - if (itemId == null) { - return false; - } - return itemId.equals(lastItemId()); - } - - // Container.Indexed - - @Override - public ITEMIDTYPE getIdByIndex(int index) { - return getVisibleItemIds().get(index); - } - - @Override - public int indexOfId(Object itemId) { - return getVisibleItemIds().indexOf(itemId); - } - - // methods that are unsupported by default, override to support - - @Override - public Object addItemAt(int index) throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Adding items not supported. Override the relevant addItem*() methods if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public Item addItemAt(int index, Object newItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Adding items not supported. Override the relevant addItem*() methods if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public Object addItemAfter(Object previousItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Adding items not supported. Override the relevant addItem*() methods if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public Item addItemAfter(Object previousItemId, Object newItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Adding items not supported. Override the relevant addItem*() methods if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public Item addItem(Object itemId) throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Adding items not supported. Override the relevant addItem*() methods if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public Object addItem() throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Adding items not supported. Override the relevant addItem*() methods if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Removing items not supported. Override the removeItem() method if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public boolean removeAllItems() throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Removing items not supported. Override the removeAllItems() method if required as specified in AbstractInMemoryContainer javadoc."); - } - - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Adding container properties not supported. Override the addContainerProperty() method if required."); - } - - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Removing container properties not supported. Override the addContainerProperty() method if required."); - } - - // ItemSetChangeNotifier - - @Override - public void addListener(Container.ItemSetChangeListener listener) { - super.addListener(listener); - } - - @Override - public void removeListener(Container.ItemSetChangeListener listener) { - super.removeListener(listener); - } - - // internal methods - - // Filtering support - - /** - * Filter the view to recreate the visible item list from the unfiltered - * items, and send a notification if the set of visible items changed in any - * way. - */ - protected void filterAll() { - if (doFilterContainer(!getFilters().isEmpty())) { - fireItemSetChange(); - } - } - - /** - * Filters the data in the container and updates internal data structures. - * This method should reset any internal data structures and then repopulate - * them so {@link #getItemIds()} and other methods only return the filtered - * items. - * - * @param hasFilters - * true if filters has been set for the container, false - * otherwise - * @return true if the item set has changed as a result of the filtering - */ - protected boolean doFilterContainer(boolean hasFilters) { - if (!hasFilters) { - boolean changed = getAllItemIds().size() != getVisibleItemIds() - .size(); - setFilteredItemIds(null); - return changed; - } - - // Reset filtered list - List<ITEMIDTYPE> originalFilteredItemIds = getFilteredItemIds(); - boolean wasUnfiltered = false; - if (originalFilteredItemIds == null) { - originalFilteredItemIds = Collections.emptyList(); - wasUnfiltered = true; - } - setFilteredItemIds(new ListSet<ITEMIDTYPE>()); - - // Filter - boolean equal = true; - Iterator<ITEMIDTYPE> origIt = originalFilteredItemIds.iterator(); - for (final Iterator<ITEMIDTYPE> i = getAllItemIds().iterator(); i - .hasNext();) { - final ITEMIDTYPE id = i.next(); - if (passesFilters(id)) { - // filtered list comes from the full list, can use == - equal = equal && origIt.hasNext() && origIt.next() == id; - getFilteredItemIds().add(id); - } - } - - return (wasUnfiltered && !getAllItemIds().isEmpty()) || !equal - || origIt.hasNext(); - } - - /** - * Checks if the given itemId passes the filters set for the container. The - * caller should make sure the itemId exists in the container. For - * non-existing itemIds the behavior is undefined. - * - * @param itemId - * An itemId that exists in the container. - * @return true if the itemId passes all filters or no filters are set, - * false otherwise. - */ - protected boolean passesFilters(Object itemId) { - ITEMCLASS item = getUnfilteredItem(itemId); - if (getFilters().isEmpty()) { - return true; - } - final Iterator<Filter> i = getFilters().iterator(); - while (i.hasNext()) { - final Filter f = i.next(); - if (!f.passesFilter(itemId, item)) { - return false; - } - } - return true; - } - - /** - * Adds a container filter and re-filter the view. - * - * The filter must implement Filter and its sub-filters (if any) must also - * be in-memory filterable. - * - * This can be used to implement - * {@link Filterable#addContainerFilter(com.vaadin.data.Container.Filter)} - * and optionally also - * {@link SimpleFilterable#addContainerFilter(Object, String, boolean, boolean)} - * (with {@link SimpleStringFilter}). - * - * Note that in some cases, incompatible filters cannot be detected when - * added and an {@link UnsupportedFilterException} may occur when performing - * filtering. - * - * @throws UnsupportedFilterException - * if the filter is detected as not supported by the container - */ - protected void addFilter(Filter filter) throws UnsupportedFilterException { - getFilters().add(filter); - filterAll(); - } - - /** - * Remove a specific container filter and re-filter the view (if necessary). - * - * This can be used to implement - * {@link Filterable#removeContainerFilter(com.vaadin.data.Container.Filter)} - * . - */ - protected void removeFilter(Filter filter) { - for (Iterator<Filter> iterator = getFilters().iterator(); iterator - .hasNext();) { - Filter f = iterator.next(); - if (f.equals(filter)) { - iterator.remove(); - filterAll(); - return; - } - } - } - - /** - * Remove all container filters for all properties and re-filter the view. - * - * This can be used to implement - * {@link Filterable#removeAllContainerFilters()}. - */ - protected void removeAllFilters() { - if (getFilters().isEmpty()) { - return; - } - getFilters().clear(); - filterAll(); - } - - /** - * Checks if there is a filter that applies to a given property. - * - * @param propertyId - * @return true if there is an active filter for the property - */ - protected boolean isPropertyFiltered(Object propertyId) { - if (getFilters().isEmpty() || propertyId == null) { - return false; - } - final Iterator<Filter> i = getFilters().iterator(); - while (i.hasNext()) { - final Filter f = i.next(); - if (f.appliesToProperty(propertyId)) { - return true; - } - } - return false; - } - - /** - * Remove all container filters for a given property identifier and - * re-filter the view. This also removes filters applying to multiple - * properties including the one identified by propertyId. - * - * This can be used to implement - * {@link Filterable#removeContainerFilters(Object)}. - * - * @param propertyId - * @return Collection<Filter> removed filters - */ - protected Collection<Filter> removeFilters(Object propertyId) { - if (getFilters().isEmpty() || propertyId == null) { - return Collections.emptyList(); - } - List<Filter> removedFilters = new LinkedList<Filter>(); - for (Iterator<Filter> iterator = getFilters().iterator(); iterator - .hasNext();) { - Filter f = iterator.next(); - if (f.appliesToProperty(propertyId)) { - removedFilters.add(f); - iterator.remove(); - } - } - if (!removedFilters.isEmpty()) { - filterAll(); - return removedFilters; - } - return Collections.emptyList(); - } - - // sorting - - /** - * Returns the ItemSorter used for comparing items in a sort. See - * {@link #setItemSorter(ItemSorter)} for more information. - * - * @return The ItemSorter used for comparing two items in a sort. - */ - protected ItemSorter getItemSorter() { - return itemSorter; - } - - /** - * Sets the ItemSorter used for comparing items in a sort. The - * {@link ItemSorter#compare(Object, Object)} method is called with item ids - * to perform the sorting. A default ItemSorter is used if this is not - * explicitly set. - * - * @param itemSorter - * The ItemSorter used for comparing two items in a sort (not - * null). - */ - protected void setItemSorter(ItemSorter itemSorter) { - this.itemSorter = itemSorter; - } - - /** - * Sort base implementation to be used to implement {@link Sortable}. - * - * Subclasses should call this from a public - * {@link #sort(Object[], boolean[])} method when implementing Sortable. - * - * @see com.vaadin.data.Container.Sortable#sort(java.lang.Object[], - * boolean[]) - */ - protected void sortContainer(Object[] propertyId, boolean[] ascending) { - if (!(this instanceof Sortable)) { - throw new UnsupportedOperationException( - "Cannot sort a Container that does not implement Sortable"); - } - - // Set up the item sorter for the sort operation - getItemSorter().setSortProperties((Sortable) this, propertyId, - ascending); - - // Perform the actual sort - doSort(); - - // Post sort updates - if (isFiltered()) { - filterAll(); - } else { - fireItemSetChange(); - } - - } - - /** - * Perform the sorting of the data structures in the container. This is - * invoked when the <code>itemSorter</code> has been prepared for the sort - * operation. Typically this method calls - * <code>Collections.sort(aCollection, getItemSorter())</code> on all arrays - * (containing item ids) that need to be sorted. - * - */ - protected void doSort() { - Collections.sort(getAllItemIds(), getItemSorter()); - } - - /** - * Returns the sortable property identifiers for the container. Can be used - * to implement {@link Sortable#getSortableContainerPropertyIds()}. - */ - protected Collection<?> getSortablePropertyIds() { - LinkedList<Object> sortables = new LinkedList<Object>(); - for (Object propertyId : getContainerPropertyIds()) { - Class<?> propertyType = getType(propertyId); - if (Comparable.class.isAssignableFrom(propertyType) - || propertyType.isPrimitive()) { - sortables.add(propertyId); - } - } - return sortables; - } - - // removing items - - /** - * Removes all items from the internal data structures of this class. This - * can be used to implement {@link #removeAllItems()} in subclasses. - * - * No notification is sent, the caller has to fire a suitable item set - * change notification. - */ - protected void internalRemoveAllItems() { - // Removes all Items - getAllItemIds().clear(); - if (isFiltered()) { - getFilteredItemIds().clear(); - } - } - - /** - * Removes a single item from the internal data structures of this class. - * This can be used to implement {@link #removeItem(Object)} in subclasses. - * - * No notification is sent, the caller has to fire a suitable item set - * change notification. - * - * @param itemId - * the identifier of the item to remove - * @return true if an item was successfully removed, false if failed to - * remove or no such item - */ - protected boolean internalRemoveItem(Object itemId) { - if (itemId == null) { - return false; - } - - boolean result = getAllItemIds().remove(itemId); - if (result && isFiltered()) { - getFilteredItemIds().remove(itemId); - } - - return result; - } - - // adding items - - /** - * Adds the bean to all internal data structures at the given position. - * Fails if an item with itemId is already in the container. Returns a the - * item if it was added successfully, null otherwise. - * - * <p> - * Caller should initiate filtering after calling this method. - * </p> - * - * For internal use only - subclasses should use - * {@link #internalAddItemAtEnd(Object, Item, boolean)}, - * {@link #internalAddItemAt(int, Object, Item, boolean)} and - * {@link #internalAddItemAfter(Object, Object, Item, boolean)} instead. - * - * @param position - * The position at which the item should be inserted in the - * unfiltered collection of items - * @param itemId - * The item identifier for the item to insert - * @param item - * The item to insert - * - * @return ITEMCLASS if the item was added successfully, null otherwise - */ - private ITEMCLASS internalAddAt(int position, ITEMIDTYPE itemId, - ITEMCLASS item) { - if (position < 0 || position > getAllItemIds().size() || itemId == null - || item == null) { - return null; - } - // Make sure that the item has not been added previously - if (getAllItemIds().contains(itemId)) { - return null; - } - - // "filteredList" will be updated in filterAll() which should be invoked - // by the caller after calling this method. - getAllItemIds().add(position, itemId); - registerNewItem(position, itemId, item); - - return item; - } - - /** - * Add an item at the end of the container, and perform filtering if - * necessary. An event is fired if the filtered view changes. - * - * @param newItemId - * @param item - * new item to add - * @param filter - * true to perform filtering and send event after adding the - * item, false to skip these operations for batch inserts - if - * false, caller needs to make sure these operations are - * performed at the end of the batch - * @return item added or null if no item was added - */ - protected ITEMCLASS internalAddItemAtEnd(ITEMIDTYPE newItemId, - ITEMCLASS item, boolean filter) { - ITEMCLASS newItem = internalAddAt(getAllItemIds().size(), newItemId, - item); - if (newItem != null && filter) { - // TODO filter only this item, use fireItemAdded() - filterAll(); - if (!isFiltered()) { - // TODO hack: does not detect change in filterAll() in this case - fireItemAdded(indexOfId(newItemId), newItemId, item); - } - } - return newItem; - } - - /** - * Add an item after a given (visible) item, and perform filtering. An event - * is fired if the filtered view changes. - * - * The new item is added at the beginning if previousItemId is null. - * - * @param previousItemId - * item id of a visible item after which to add the new item, or - * null to add at the beginning - * @param newItemId - * @param item - * new item to add - * @param filter - * true to perform filtering and send event after adding the - * item, false to skip these operations for batch inserts - if - * false, caller needs to make sure these operations are - * performed at the end of the batch - * @return item added or null if no item was added - */ - protected ITEMCLASS internalAddItemAfter(ITEMIDTYPE previousItemId, - ITEMIDTYPE newItemId, ITEMCLASS item, boolean filter) { - // only add if the previous item is visible - ITEMCLASS newItem = null; - if (previousItemId == null) { - newItem = internalAddAt(0, newItemId, item); - } else if (containsId(previousItemId)) { - newItem = internalAddAt( - getAllItemIds().indexOf(previousItemId) + 1, newItemId, - item); - } - if (newItem != null && filter) { - // TODO filter only this item, use fireItemAdded() - filterAll(); - if (!isFiltered()) { - // TODO hack: does not detect change in filterAll() in this case - fireItemAdded(indexOfId(newItemId), newItemId, item); - } - } - return newItem; - } - - /** - * Add an item at a given (visible after filtering) item index, and perform - * filtering. An event is fired if the filtered view changes. - * - * @param index - * position where to add the item (visible/view index) - * @param newItemId - * @param item - * new item to add - * @param filter - * true to perform filtering and send event after adding the - * item, false to skip these operations for batch inserts - if - * false, caller needs to make sure these operations are - * performed at the end of the batch - * @return item added or null if no item was added - */ - protected ITEMCLASS internalAddItemAt(int index, ITEMIDTYPE newItemId, - ITEMCLASS item, boolean filter) { - if (index < 0 || index > size()) { - return null; - } else if (index == 0) { - // add before any item, visible or not - return internalAddItemAfter(null, newItemId, item, filter); - } else { - // if index==size(), adds immediately after last visible item - return internalAddItemAfter(getIdByIndex(index - 1), newItemId, - item, filter); - } - } - - /** - * Registers a new item as having been added to the container. This can - * involve storing the item or any relevant information about it in internal - * container-specific collections if necessary, as well as registering - * listeners etc. - * - * The full identifier list in {@link AbstractInMemoryContainer} has already - * been updated to reflect the new item when this method is called. - * - * @param position - * @param itemId - * @param item - */ - protected void registerNewItem(int position, ITEMIDTYPE itemId, - ITEMCLASS item) { - } - - // item set change notifications - - /** - * Notify item set change listeners that an item has been added to the - * container. - * - * Unless subclasses specify otherwise, the default notification indicates a - * full refresh. - * - * @param postion - * position of the added item in the view (if visible) - * @param itemId - * id of the added item - * @param item - * the added item - */ - protected void fireItemAdded(int position, ITEMIDTYPE itemId, ITEMCLASS item) { - fireItemSetChange(); - } - - /** - * Notify item set change listeners that an item has been removed from the - * container. - * - * Unless subclasses specify otherwise, the default notification indicates a - * full refresh. - * - * @param postion - * position of the removed item in the view prior to removal (if - * was visible) - * @param itemId - * id of the removed item, of type {@link Object} to satisfy - * {@link Container#removeItem(Object)} API - */ - protected void fireItemRemoved(int position, Object itemId) { - fireItemSetChange(); - } - - // visible and filtered item identifier lists - - /** - * Returns the internal list of visible item identifiers after filtering. - * - * For internal use only. - */ - protected List<ITEMIDTYPE> getVisibleItemIds() { - if (isFiltered()) { - return getFilteredItemIds(); - } else { - return getAllItemIds(); - } - } - - /** - * Returns true is the container has active filters. - * - * @return true if the container is currently filtered - */ - protected boolean isFiltered() { - return filteredItemIds != null; - } - - /** - * Internal helper method to set the internal list of filtered item - * identifiers. Should not be used outside this class except for - * implementing clone(), may disappear from future versions. - * - * @param filteredItemIds - */ - @Deprecated - protected void setFilteredItemIds(List<ITEMIDTYPE> filteredItemIds) { - this.filteredItemIds = filteredItemIds; - } - - /** - * Internal helper method to get the internal list of filtered item - * identifiers. Should not be used outside this class except for - * implementing clone(), may disappear from future versions - use - * {@link #getVisibleItemIds()} in other contexts. - * - * @return List<ITEMIDTYPE> - */ - protected List<ITEMIDTYPE> getFilteredItemIds() { - return filteredItemIds; - } - - /** - * Internal helper method to set the internal list of all item identifiers. - * Should not be used outside this class except for implementing clone(), - * may disappear from future versions. - * - * @param allItemIds - */ - @Deprecated - protected void setAllItemIds(List<ITEMIDTYPE> allItemIds) { - this.allItemIds = allItemIds; - } - - /** - * Internal helper method to get the internal list of all item identifiers. - * Avoid using this method outside this class, may disappear in future - * versions. - * - * @return List<ITEMIDTYPE> - */ - protected List<ITEMIDTYPE> getAllItemIds() { - return allItemIds; - } - - /** - * Set the internal collection of filters without performing filtering. - * - * This method is mostly for internal use, use - * {@link #addFilter(com.vaadin.data.Container.Filter)} and - * <code>remove*Filter*</code> (which also re-filter the container) instead - * when possible. - * - * @param filters - */ - protected void setFilters(Set<Filter> filters) { - this.filters = filters; - } - - /** - * Returns the internal collection of filters. The returned collection - * should not be modified by callers outside this class. - * - * @return Set<Filter> - */ - protected Set<Filter> getFilters() { - return filters; - } - -} diff --git a/src/com/vaadin/data/util/AbstractProperty.java b/src/com/vaadin/data/util/AbstractProperty.java deleted file mode 100644 index 373a8dfd58..0000000000 --- a/src/com/vaadin/data/util/AbstractProperty.java +++ /dev/null @@ -1,226 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedList; - -import com.vaadin.data.Property; - -/** - * Abstract base class for {@link Property} implementations. - * - * Handles listener management for {@link ValueChangeListener}s and - * {@link ReadOnlyStatusChangeListener}s. - * - * @since 6.6 - */ -public abstract class AbstractProperty<T> implements Property<T>, - Property.ValueChangeNotifier, Property.ReadOnlyStatusChangeNotifier { - - /** - * List of listeners who are interested in the read-only status changes of - * the Property - */ - private LinkedList<ReadOnlyStatusChangeListener> readOnlyStatusChangeListeners = null; - - /** - * List of listeners who are interested in the value changes of the Property - */ - private LinkedList<ValueChangeListener> valueChangeListeners = null; - - /** - * Is the Property read-only? - */ - private boolean readOnly; - - /** - * {@inheritDoc} - * - * Override for additional restrictions on what is considered a read-only - * property. - */ - @Override - public boolean isReadOnly() { - return readOnly; - } - - @Override - public void setReadOnly(boolean newStatus) { - boolean oldStatus = isReadOnly(); - readOnly = newStatus; - if (oldStatus != isReadOnly()) { - fireReadOnlyStatusChange(); - } - } - - /** - * Returns the value of the <code>Property</code> in human readable textual - * format. - * - * @return String representation of the value stored in the Property - * @deprecated use {@link #getValue()} instead and possibly toString on that - */ - @Deprecated - @Override - public String toString() { - throw new UnsupportedOperationException( - "Use Property.getValue() instead of " + getClass() - + ".toString()"); - } - - /* Events */ - - /** - * An <code>Event</code> object specifying the Property whose read-only - * status has been changed. - */ - protected static class ReadOnlyStatusChangeEvent extends - java.util.EventObject implements Property.ReadOnlyStatusChangeEvent { - - /** - * Constructs a new read-only status change event for this object. - * - * @param source - * source object of the event. - */ - protected ReadOnlyStatusChangeEvent(Property source) { - super(source); - } - - /** - * Gets the Property whose read-only state has changed. - * - * @return source Property of the event. - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - - } - - /** - * Registers a new read-only status change listener for this Property. - * - * @param listener - * the new Listener to be registered. - */ - @Override - public void addListener(Property.ReadOnlyStatusChangeListener listener) { - if (readOnlyStatusChangeListeners == null) { - readOnlyStatusChangeListeners = new LinkedList<ReadOnlyStatusChangeListener>(); - } - readOnlyStatusChangeListeners.add(listener); - } - - /** - * Removes a previously registered read-only status change listener. - * - * @param listener - * the listener to be removed. - */ - @Override - public void removeListener(Property.ReadOnlyStatusChangeListener listener) { - if (readOnlyStatusChangeListeners != null) { - readOnlyStatusChangeListeners.remove(listener); - } - } - - /** - * Sends a read only status change event to all registered listeners. - */ - protected void fireReadOnlyStatusChange() { - if (readOnlyStatusChangeListeners != null) { - final Object[] l = readOnlyStatusChangeListeners.toArray(); - final Property.ReadOnlyStatusChangeEvent event = new ReadOnlyStatusChangeEvent( - this); - for (int i = 0; i < l.length; i++) { - ((Property.ReadOnlyStatusChangeListener) l[i]) - .readOnlyStatusChange(event); - } - } - } - - /** - * An <code>Event</code> object specifying the Property whose value has been - * changed. - */ - private static class ValueChangeEvent extends java.util.EventObject - implements Property.ValueChangeEvent { - - /** - * Constructs a new value change event for this object. - * - * @param source - * source object of the event. - */ - protected ValueChangeEvent(Property source) { - super(source); - } - - /** - * Gets the Property whose value has changed. - * - * @return source Property of the event. - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - - } - - @Override - public void addListener(ValueChangeListener listener) { - if (valueChangeListeners == null) { - valueChangeListeners = new LinkedList<ValueChangeListener>(); - } - valueChangeListeners.add(listener); - - } - - @Override - public void removeListener(ValueChangeListener listener) { - if (valueChangeListeners != null) { - valueChangeListeners.remove(listener); - } - - } - - /** - * Sends a value change event to all registered listeners. - */ - protected void fireValueChange() { - if (valueChangeListeners != null) { - final Object[] l = valueChangeListeners.toArray(); - final Property.ValueChangeEvent event = new ValueChangeEvent(this); - for (int i = 0; i < l.length; i++) { - ((Property.ValueChangeListener) l[i]).valueChange(event); - } - } - } - - public Collection<?> getListeners(Class<?> eventType) { - if (Property.ValueChangeEvent.class.isAssignableFrom(eventType)) { - if (valueChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections.unmodifiableCollection(valueChangeListeners); - } - } else if (Property.ReadOnlyStatusChangeEvent.class - .isAssignableFrom(eventType)) { - if (readOnlyStatusChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(readOnlyStatusChangeListeners); - } - } - - return Collections.EMPTY_LIST; - } - -} diff --git a/src/com/vaadin/data/util/BeanContainer.java b/src/com/vaadin/data/util/BeanContainer.java deleted file mode 100644 index bc1ee3c39e..0000000000 --- a/src/com/vaadin/data/util/BeanContainer.java +++ /dev/null @@ -1,168 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.util.Collection; - -/** - * An in-memory container for JavaBeans. - * - * <p> - * The properties of the container are determined automatically by introspecting - * the used JavaBean class. Only beans of the same type can be added to the - * container. - * </p> - * - * <p> - * In BeanContainer (unlike {@link BeanItemContainer}), the item IDs do not have - * to be the beans themselves. The container can be used either with explicit - * item IDs or the item IDs can be generated when adding beans. - * </p> - * - * <p> - * To use explicit item IDs, use the methods {@link #addItem(Object, Object)}, - * {@link #addItemAfter(Object, Object, Object)} and - * {@link #addItemAt(int, Object, Object)}. - * </p> - * - * <p> - * If a bean id resolver is set using - * {@link #setBeanIdResolver(com.vaadin.data.util.AbstractBeanContainer.BeanIdResolver)} - * or {@link #setBeanIdProperty(Object)}, the methods {@link #addBean(Object)}, - * {@link #addBeanAfter(Object, Object)}, {@link #addBeanAt(int, Object)} and - * {@link #addAll(java.util.Collection)} can be used to add items to the - * container. If one of these methods is called, the resolver is used to - * generate an identifier for the item (must not return null). - * </p> - * - * <p> - * Note that explicit item identifiers can also be used when a resolver has been - * set by calling the addItem*() methods - the resolver is only used when adding - * beans using the addBean*() or {@link #addAll(Collection)} methods. - * </p> - * - * <p> - * It is not possible to add additional properties to the container and nested - * bean properties are not supported. - * </p> - * - * @param <IDTYPE> - * The type of the item identifier - * @param <BEANTYPE> - * The type of the Bean - * - * @see AbstractBeanContainer - * @see BeanItemContainer - * - * @since 6.5 - */ -public class BeanContainer<IDTYPE, BEANTYPE> extends - AbstractBeanContainer<IDTYPE, BEANTYPE> { - - public BeanContainer(Class<? super BEANTYPE> type) { - super(type); - } - - /** - * Adds the bean to the Container. - * - * @see com.vaadin.data.Container#addItem(Object) - */ - @Override - public BeanItem<BEANTYPE> addItem(IDTYPE itemId, BEANTYPE bean) { - if (itemId != null && bean != null) { - return super.addItem(itemId, bean); - } else { - return null; - } - } - - /** - * Adds the bean after the given item id. - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(Object, Object) - */ - @Override - public BeanItem<BEANTYPE> addItemAfter(IDTYPE previousItemId, - IDTYPE newItemId, BEANTYPE bean) { - if (newItemId != null && bean != null) { - return super.addItemAfter(previousItemId, newItemId, bean); - } else { - return null; - } - } - - /** - * Adds a new bean at the given index. - * - * The bean is used both as the item contents and as the item identifier. - * - * @param index - * Index at which the bean should be added. - * @param newItemId - * The item id for the bean to add to the container. - * @param bean - * The bean to add to the container. - * - * @return Returns the new BeanItem or null if the operation fails. - */ - @Override - public BeanItem<BEANTYPE> addItemAt(int index, IDTYPE newItemId, - BEANTYPE bean) { - if (newItemId != null && bean != null) { - return super.addItemAt(index, newItemId, bean); - } else { - return null; - } - } - - // automatic item id resolution - - /** - * Sets the bean id resolver to use a property of the beans as the - * identifier. - * - * @param propertyId - * the identifier of the property to use to find item identifiers - */ - public void setBeanIdProperty(Object propertyId) { - setBeanIdResolver(createBeanPropertyResolver(propertyId)); - } - - @Override - // overridden to make public - public void setBeanIdResolver( - BeanIdResolver<IDTYPE, BEANTYPE> beanIdResolver) { - super.setBeanIdResolver(beanIdResolver); - } - - @Override - // overridden to make public - public BeanItem<BEANTYPE> addBean(BEANTYPE bean) - throws IllegalStateException, IllegalArgumentException { - return super.addBean(bean); - } - - @Override - // overridden to make public - public BeanItem<BEANTYPE> addBeanAfter(IDTYPE previousItemId, BEANTYPE bean) - throws IllegalStateException, IllegalArgumentException { - return super.addBeanAfter(previousItemId, bean); - } - - @Override - // overridden to make public - public BeanItem<BEANTYPE> addBeanAt(int index, BEANTYPE bean) - throws IllegalStateException, IllegalArgumentException { - return super.addBeanAt(index, bean); - } - - @Override - // overridden to make public - public void addAll(Collection<? extends BEANTYPE> collection) - throws IllegalStateException { - super.addAll(collection); - } - -} diff --git a/src/com/vaadin/data/util/BeanItem.java b/src/com/vaadin/data/util/BeanItem.java deleted file mode 100644 index 94439471f5..0000000000 --- a/src/com/vaadin/data/util/BeanItem.java +++ /dev/null @@ -1,269 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -/** - * A wrapper class for adding the Item interface to any Java Bean. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class BeanItem<BT> extends PropertysetItem { - - /** - * The bean which this Item is based on. - */ - private final BT bean; - - /** - * <p> - * Creates a new instance of <code>BeanItem</code> and adds all properties - * of a Java Bean to it. The properties are identified by their respective - * bean names. - * </p> - * - * <p> - * Note : This version only supports introspectable bean properties and - * their getter and setter methods. Stand-alone <code>is</code> and - * <code>are</code> methods are not supported. - * </p> - * - * @param bean - * the Java Bean to copy properties from. - * - */ - public BeanItem(BT bean) { - this(bean, getPropertyDescriptors((Class<BT>) bean.getClass())); - } - - /** - * <p> - * Creates a new instance of <code>BeanItem</code> using a pre-computed set - * of properties. The properties are identified by their respective bean - * names. - * </p> - * - * @param bean - * the Java Bean to copy properties from. - * @param propertyDescriptors - * pre-computed property descriptors - */ - BeanItem(BT bean, - Map<String, VaadinPropertyDescriptor<BT>> propertyDescriptors) { - - this.bean = bean; - - for (VaadinPropertyDescriptor<BT> pd : propertyDescriptors.values()) { - addItemProperty(pd.getName(), pd.createProperty(bean)); - } - } - - /** - * <p> - * Creates a new instance of <code>BeanItem</code> and adds all listed - * properties of a Java Bean to it - in specified order. The properties are - * identified by their respective bean names. - * </p> - * - * <p> - * Note : This version only supports introspectable bean properties and - * their getter and setter methods. Stand-alone <code>is</code> and - * <code>are</code> methods are not supported. - * </p> - * - * @param bean - * the Java Bean to copy properties from. - * @param propertyIds - * id of the property. - */ - public BeanItem(BT bean, Collection<?> propertyIds) { - - this.bean = bean; - - // Create bean information - LinkedHashMap<String, VaadinPropertyDescriptor<BT>> pds = getPropertyDescriptors((Class<BT>) bean - .getClass()); - - // Add all the bean properties as MethodProperties to this Item - for (Object id : propertyIds) { - VaadinPropertyDescriptor<BT> pd = pds.get(id); - if (pd != null) { - addItemProperty(pd.getName(), pd.createProperty(bean)); - } - } - - } - - /** - * <p> - * Creates a new instance of <code>BeanItem</code> and adds all listed - * properties of a Java Bean to it - in specified order. The properties are - * identified by their respective bean names. - * </p> - * - * <p> - * Note : This version only supports introspectable bean properties and - * their getter and setter methods. Stand-alone <code>is</code> and - * <code>are</code> methods are not supported. - * </p> - * - * @param bean - * the Java Bean to copy properties from. - * @param propertyIds - * ids of the properties. - */ - public BeanItem(BT bean, String[] propertyIds) { - this(bean, Arrays.asList(propertyIds)); - } - - /** - * <p> - * Perform introspection on a Java Bean class to find its properties. - * </p> - * - * <p> - * Note : This version only supports introspectable bean properties and - * their getter and setter methods. Stand-alone <code>is</code> and - * <code>are</code> methods are not supported. - * </p> - * - * @param beanClass - * the Java Bean class to get properties for. - * @return an ordered map from property names to property descriptors - */ - static <BT> LinkedHashMap<String, VaadinPropertyDescriptor<BT>> getPropertyDescriptors( - final Class<BT> beanClass) { - final LinkedHashMap<String, VaadinPropertyDescriptor<BT>> pdMap = new LinkedHashMap<String, VaadinPropertyDescriptor<BT>>(); - - // Try to introspect, if it fails, we just have an empty Item - try { - List<PropertyDescriptor> propertyDescriptors = getBeanPropertyDescriptor(beanClass); - - // Add all the bean properties as MethodProperties to this Item - // later entries on the list overwrite earlier ones - for (PropertyDescriptor pd : propertyDescriptors) { - final Method getMethod = pd.getReadMethod(); - if ((getMethod != null) - && getMethod.getDeclaringClass() != Object.class) { - VaadinPropertyDescriptor<BT> vaadinPropertyDescriptor = new MethodPropertyDescriptor<BT>( - pd.getName(), pd.getPropertyType(), - pd.getReadMethod(), pd.getWriteMethod()); - pdMap.put(pd.getName(), vaadinPropertyDescriptor); - } - } - } catch (final java.beans.IntrospectionException ignored) { - } - - return pdMap; - } - - /** - * Returns the property descriptors of a class or an interface. - * - * For an interface, superinterfaces are also iterated as Introspector does - * not take them into account (Oracle Java bug 4275879), but in that case, - * both the setter and the getter for a property must be in the same - * interface and should not be overridden in subinterfaces for the discovery - * to work correctly. - * - * For interfaces, the iteration is depth first and the properties of - * superinterfaces are returned before those of their subinterfaces. - * - * @param beanClass - * @return - * @throws IntrospectionException - */ - private static List<PropertyDescriptor> getBeanPropertyDescriptor( - final Class<?> beanClass) throws IntrospectionException { - // Oracle bug 4275879: Introspector does not consider superinterfaces of - // an interface - if (beanClass.isInterface()) { - List<PropertyDescriptor> propertyDescriptors = new ArrayList<PropertyDescriptor>(); - - for (Class<?> cls : beanClass.getInterfaces()) { - propertyDescriptors.addAll(getBeanPropertyDescriptor(cls)); - } - - BeanInfo info = Introspector.getBeanInfo(beanClass); - propertyDescriptors.addAll(Arrays.asList(info - .getPropertyDescriptors())); - - return propertyDescriptors; - } else { - BeanInfo info = Introspector.getBeanInfo(beanClass); - return Arrays.asList(info.getPropertyDescriptors()); - } - } - - /** - * Expands nested bean properties by replacing a top-level property with - * some or all of its sub-properties. The expansion is not recursive. - * - * @param propertyId - * property id for the property whose sub-properties are to be - * expanded, - * @param subPropertyIds - * sub-properties to expand, all sub-properties are expanded if - * not specified - */ - public void expandProperty(String propertyId, String... subPropertyIds) { - Set<String> subPropertySet = new HashSet<String>( - Arrays.asList(subPropertyIds)); - - if (0 == subPropertyIds.length) { - // Enumerate all sub-properties - Class<?> propertyType = getItemProperty(propertyId).getType(); - Map<String, ?> pds = getPropertyDescriptors(propertyType); - subPropertySet.addAll(pds.keySet()); - } - - for (String subproperty : subPropertySet) { - String qualifiedPropertyId = propertyId + "." + subproperty; - addNestedProperty(qualifiedPropertyId); - } - - removeItemProperty(propertyId); - } - - /** - * Adds a nested property to the item. - * - * @param nestedPropertyId - * property id to add. This property must not exist in the item - * already and must of of form "field1.field2" where field2 is a - * field in the object referenced to by field1 - */ - public void addNestedProperty(String nestedPropertyId) { - addItemProperty(nestedPropertyId, new NestedMethodProperty<Object>( - getBean(), nestedPropertyId)); - } - - /** - * Gets the underlying JavaBean object. - * - * @return the bean object. - */ - public BT getBean() { - return bean; - } - -} diff --git a/src/com/vaadin/data/util/BeanItemContainer.java b/src/com/vaadin/data/util/BeanItemContainer.java deleted file mode 100644 index dc4deaebdc..0000000000 --- a/src/com/vaadin/data/util/BeanItemContainer.java +++ /dev/null @@ -1,241 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.util.Collection; - -/** - * An in-memory container for JavaBeans. - * - * <p> - * The properties of the container are determined automatically by introspecting - * the used JavaBean class. Only beans of the same type can be added to the - * container. - * </p> - * - * <p> - * BeanItemContainer uses the beans themselves as identifiers. The - * {@link Object#hashCode()} of a bean is used when storing and looking up beans - * so it must not change during the lifetime of the bean (it should not depend - * on any part of the bean that can be modified). Typically this restricts the - * implementation of {@link Object#equals(Object)} as well in order for it to - * fulfill the contract between {@code equals()} and {@code hashCode()}. - * </p> - * - * <p> - * To add items to the container, use the methods {@link #addBean(Object)}, - * {@link #addBeanAfter(Object, Object)} and {@link #addBeanAt(int, Object)}. - * Also {@link #addItem(Object)}, {@link #addItemAfter(Object, Object)} and - * {@link #addItemAt(int, Object)} can be used as synonyms for them. - * </p> - * - * <p> - * It is not possible to add additional properties to the container and nested - * bean properties are not supported. - * </p> - * - * @param <BEANTYPE> - * The type of the Bean - * - * @since 5.4 - */ -@SuppressWarnings("serial") -public class BeanItemContainer<BEANTYPE> extends - AbstractBeanContainer<BEANTYPE, BEANTYPE> { - - /** - * Bean identity resolver that returns the bean itself as its item - * identifier. - * - * This corresponds to the old behavior of {@link BeanItemContainer}, and - * requires suitable (identity-based) equals() and hashCode() methods on the - * beans. - * - * @param <BT> - * - * @since 6.5 - */ - private static class IdentityBeanIdResolver<BT> implements - BeanIdResolver<BT, BT> { - - @Override - public BT getIdForBean(BT bean) { - return bean; - } - - } - - /** - * Constructs a {@code BeanItemContainer} for beans of the given type. - * - * @param type - * the type of the beans that will be added to the container. - * @throws IllegalArgumentException - * If {@code type} is null - */ - public BeanItemContainer(Class<? super BEANTYPE> type) - throws IllegalArgumentException { - super(type); - super.setBeanIdResolver(new IdentityBeanIdResolver<BEANTYPE>()); - } - - /** - * Constructs a {@code BeanItemContainer} and adds the given beans to it. - * The collection must not be empty. - * {@link BeanItemContainer#BeanItemContainer(Class)} can be used for - * creating an initially empty {@code BeanItemContainer}. - * - * Note that when using this constructor, the actual class of the first item - * in the collection is used to determine the bean properties supported by - * the container instance, and only beans of that class or its subclasses - * can be added to the collection. If this is problematic or empty - * collections need to be supported, use {@link #BeanItemContainer(Class)} - * and {@link #addAll(Collection)} instead. - * - * @param collection - * a non empty {@link Collection} of beans. - * @throws IllegalArgumentException - * If the collection is null or empty. - * - * @deprecated use {@link #BeanItemContainer(Class, Collection)} instead - */ - @SuppressWarnings("unchecked") - @Deprecated - public BeanItemContainer(Collection<? extends BEANTYPE> collection) - throws IllegalArgumentException { - // must assume the class is BT - // the class information is erased by the compiler - this((Class<BEANTYPE>) getBeanClassForCollection(collection), - collection); - } - - /** - * Internal helper method to support the deprecated {@link Collection} - * container. - * - * @param <BT> - * @param collection - * @return - * @throws IllegalArgumentException - */ - @SuppressWarnings("unchecked") - @Deprecated - private static <BT> Class<? extends BT> getBeanClassForCollection( - Collection<? extends BT> collection) - throws IllegalArgumentException { - if (collection == null || collection.isEmpty()) { - throw new IllegalArgumentException( - "The collection passed to BeanItemContainer constructor must not be null or empty. Use the other BeanItemContainer constructor."); - } - return (Class<? extends BT>) collection.iterator().next().getClass(); - } - - /** - * Constructs a {@code BeanItemContainer} and adds the given beans to it. - * - * @param type - * the type of the beans that will be added to the container. - * @param collection - * a {@link Collection} of beans (can be empty or null). - * @throws IllegalArgumentException - * If {@code type} is null - */ - public BeanItemContainer(Class<? super BEANTYPE> type, - Collection<? extends BEANTYPE> collection) - throws IllegalArgumentException { - super(type); - super.setBeanIdResolver(new IdentityBeanIdResolver<BEANTYPE>()); - - if (collection != null) { - addAll(collection); - } - } - - /** - * Adds all the beans from a {@link Collection} in one go. More efficient - * than adding them one by one. - * - * @param collection - * The collection of beans to add. Must not be null. - */ - @Override - public void addAll(Collection<? extends BEANTYPE> collection) { - super.addAll(collection); - } - - /** - * Adds the bean after the given bean. - * - * The bean is used both as the item contents and as the item identifier. - * - * @param previousItemId - * the bean (of type BT) after which to add newItemId - * @param newItemId - * the bean (of type BT) to add (not null) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(Object, Object) - */ - @Override - @SuppressWarnings("unchecked") - public BeanItem<BEANTYPE> addItemAfter(Object previousItemId, - Object newItemId) throws IllegalArgumentException { - return super.addBeanAfter((BEANTYPE) previousItemId, - (BEANTYPE) newItemId); - } - - /** - * Adds a new bean at the given index. - * - * The bean is used both as the item contents and as the item identifier. - * - * @param index - * Index at which the bean should be added. - * @param newItemId - * The bean to add to the container. - * @return Returns the new BeanItem or null if the operation fails. - */ - @Override - @SuppressWarnings("unchecked") - public BeanItem<BEANTYPE> addItemAt(int index, Object newItemId) - throws IllegalArgumentException { - return super.addBeanAt(index, (BEANTYPE) newItemId); - } - - /** - * Adds the bean to the Container. - * - * The bean is used both as the item contents and as the item identifier. - * - * @see com.vaadin.data.Container#addItem(Object) - */ - @Override - @SuppressWarnings("unchecked") - public BeanItem<BEANTYPE> addItem(Object itemId) { - return super.addBean((BEANTYPE) itemId); - } - - /** - * Adds the bean to the Container. - * - * The bean is used both as the item contents and as the item identifier. - * - * @see com.vaadin.data.Container#addItem(Object) - */ - @Override - public BeanItem<BEANTYPE> addBean(BEANTYPE bean) { - return addItem(bean); - } - - /** - * Unsupported in BeanItemContainer. - */ - @Override - protected void setBeanIdResolver( - AbstractBeanContainer.BeanIdResolver<BEANTYPE, BEANTYPE> beanIdResolver) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "BeanItemContainer always uses an IdentityBeanIdResolver"); - } - -} diff --git a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java b/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java deleted file mode 100644 index 717ce834cf..0000000000 --- a/src/com/vaadin/data/util/ContainerHierarchicalWrapper.java +++ /dev/null @@ -1,792 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * <p> - * A wrapper class for adding external hierarchy to containers not implementing - * the {@link com.vaadin.data.Container.Hierarchical} interface. - * </p> - * - * <p> - * If the wrapped container is changed directly (that is, not through the - * wrapper), and does not implement Container.ItemSetChangeNotifier and/or - * Container.PropertySetChangeNotifier the hierarchy information must be updated - * with the {@link #updateHierarchicalWrapper()} method. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ContainerHierarchicalWrapper implements Container.Hierarchical, - Container.ItemSetChangeNotifier, Container.PropertySetChangeNotifier { - - /** The wrapped container */ - private final Container container; - - /** Set of IDs of those contained Items that can't have children. */ - private HashSet<Object> noChildrenAllowed = null; - - /** Mapping from Item ID to parent Item ID */ - private Hashtable<Object, Object> parent = null; - - /** Mapping from Item ID to a list of child IDs */ - private Hashtable<Object, LinkedList<Object>> children = null; - - /** List that contains all root elements of the container. */ - private LinkedHashSet<Object> roots = null; - - /** Is the wrapped container hierarchical by itself ? */ - private boolean hierarchical; - - /** - * A comparator that sorts the listed items before other items. Otherwise, - * the order is undefined. - */ - private static class ListedItemsFirstComparator implements - Comparator<Object>, Serializable { - private final Collection<?> itemIds; - - private ListedItemsFirstComparator(Collection<?> itemIds) { - this.itemIds = itemIds; - } - - @Override - public int compare(Object o1, Object o2) { - if (o1.equals(o2)) { - return 0; - } - for (Object id : itemIds) { - if (id == o1) { - return -1; - } else if (id == o2) { - return 1; - } - } - return 0; - } - }; - - /** - * Constructs a new hierarchical wrapper for an existing Container. Works - * even if the to-be-wrapped container already implements the - * <code>Container.Hierarchical</code> interface. - * - * @param toBeWrapped - * the container that needs to be accessed hierarchically - * @see #updateHierarchicalWrapper() - */ - public ContainerHierarchicalWrapper(Container toBeWrapped) { - - container = toBeWrapped; - hierarchical = container instanceof Container.Hierarchical; - - // Check arguments - if (container == null) { - throw new NullPointerException("Null can not be wrapped"); - } - - // Create initial order if needed - if (!hierarchical) { - noChildrenAllowed = new HashSet<Object>(); - parent = new Hashtable<Object, Object>(); - children = new Hashtable<Object, LinkedList<Object>>(); - roots = new LinkedHashSet<Object>(container.getItemIds()); - } - - updateHierarchicalWrapper(); - - } - - /** - * Updates the wrapper's internal hierarchy data to include all Items in the - * underlying container. If the contents of the wrapped container change - * without the wrapper's knowledge, this method needs to be called to update - * the hierarchy information of the Items. - */ - public void updateHierarchicalWrapper() { - - if (!hierarchical) { - - // Recreate hierarchy and data structures if missing - if (noChildrenAllowed == null || parent == null || children == null - || roots == null) { - noChildrenAllowed = new HashSet<Object>(); - parent = new Hashtable<Object, Object>(); - children = new Hashtable<Object, LinkedList<Object>>(); - roots = new LinkedHashSet<Object>(container.getItemIds()); - } - - // Check that the hierarchy is up-to-date - else { - - // ensure order of root and child lists is same as in wrapped - // container - Collection<?> itemIds = container.getItemIds(); - Comparator<Object> basedOnOrderFromWrappedContainer = new ListedItemsFirstComparator( - itemIds); - - // Calculate the set of all items in the hierarchy - final HashSet<Object> s = new HashSet<Object>(); - s.addAll(parent.keySet()); - s.addAll(children.keySet()); - s.addAll(roots); - - // Remove unnecessary items - for (final Iterator<Object> i = s.iterator(); i.hasNext();) { - final Object id = i.next(); - if (!container.containsId(id)) { - removeFromHierarchyWrapper(id); - } - } - - // Add all the missing items - final Collection<?> ids = container.getItemIds(); - for (final Iterator<?> i = ids.iterator(); i.hasNext();) { - final Object id = i.next(); - if (!s.contains(id)) { - addToHierarchyWrapper(id); - s.add(id); - } - } - - Object[] array = roots.toArray(); - Arrays.sort(array, basedOnOrderFromWrappedContainer); - roots = new LinkedHashSet<Object>(); - for (int i = 0; i < array.length; i++) { - roots.add(array[i]); - } - for (Object object : children.keySet()) { - LinkedList<Object> object2 = children.get(object); - Collections.sort(object2, basedOnOrderFromWrappedContainer); - } - - } - } - } - - /** - * Removes the specified Item from the wrapper's internal hierarchy - * structure. - * <p> - * Note : The Item is not removed from the underlying Container. - * </p> - * - * @param itemId - * the ID of the item to remove from the hierarchy. - */ - private void removeFromHierarchyWrapper(Object itemId) { - - LinkedList<Object> oprhanedChildren = children.remove(itemId); - if (oprhanedChildren != null) { - for (Object object : oprhanedChildren) { - // make orphaned children root nodes - setParent(object, null); - } - } - - roots.remove(itemId); - final Object p = parent.get(itemId); - if (p != null) { - final LinkedList<Object> c = children.get(p); - if (c != null) { - c.remove(itemId); - } - } - parent.remove(itemId); - noChildrenAllowed.remove(itemId); - } - - /** - * Adds the specified Item specified to the internal hierarchy structure. - * The new item is added as a root Item. The underlying container is not - * modified. - * - * @param itemId - * the ID of the item to add to the hierarchy. - */ - private void addToHierarchyWrapper(Object itemId) { - roots.add(itemId); - - } - - /* - * Can the specified Item have any children? Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public boolean areChildrenAllowed(Object itemId) { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container) - .areChildrenAllowed(itemId); - } - - if (noChildrenAllowed.contains(itemId)) { - return false; - } - - return containsId(itemId); - } - - /* - * Gets the IDs of the children of the specified Item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> getChildren(Object itemId) { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container).getChildren(itemId); - } - - final Collection<?> c = children.get(itemId); - if (c == null) { - return null; - } - return Collections.unmodifiableCollection(c); - } - - /* - * Gets the ID of the parent of the specified Item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Object getParent(Object itemId) { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container).getParent(itemId); - } - - return parent.get(itemId); - } - - /* - * Is the Item corresponding to the given ID a leaf node? Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean hasChildren(Object itemId) { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container).hasChildren(itemId); - } - - LinkedList<Object> list = children.get(itemId); - return (list != null && !list.isEmpty()); - } - - /* - * Is the Item corresponding to the given ID a root node? Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean isRoot(Object itemId) { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container).isRoot(itemId); - } - - if (parent.containsKey(itemId)) { - return false; - } - - return containsId(itemId); - } - - /* - * Gets the IDs of the root elements in the container. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> rootItemIds() { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container).rootItemIds(); - } - - return Collections.unmodifiableCollection(roots); - } - - /** - * <p> - * Sets the given Item's capability to have children. If the Item identified - * with the itemId already has children and the areChildrenAllowed is false - * this method fails and <code>false</code> is returned; the children must - * be first explicitly removed with - * {@link #setParent(Object itemId, Object newParentId)} or - * {@link com.vaadin.data.Container#removeItem(Object itemId)}. - * </p> - * - * @param itemId - * the ID of the Item in the container whose child capability is - * to be set. - * @param childrenAllowed - * the boolean value specifying if the Item can have children or - * not. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean setChildrenAllowed(Object itemId, boolean childrenAllowed) { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container).setChildrenAllowed( - itemId, childrenAllowed); - } - - // Check that the item is in the container - if (!containsId(itemId)) { - return false; - } - - // Update status - if (childrenAllowed) { - noChildrenAllowed.remove(itemId); - } else { - noChildrenAllowed.add(itemId); - } - - return true; - } - - /** - * <p> - * Sets the parent of an Item. The new parent item must exist and be able to - * have children. (<code>canHaveChildren(newParentId) == true</code>). It is - * also possible to detach a node from the hierarchy (and thus make it root) - * by setting the parent <code>null</code>. - * </p> - * - * @param itemId - * the ID of the item to be set as the child of the Item - * identified with newParentId. - * @param newParentId - * the ID of the Item that's to be the new parent of the Item - * identified with itemId. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean setParent(Object itemId, Object newParentId) { - - // If the wrapped container implements the method directly, use it - if (hierarchical) { - return ((Container.Hierarchical) container).setParent(itemId, - newParentId); - } - - // Check that the item is in the container - if (!containsId(itemId)) { - return false; - } - - // Get the old parent - final Object oldParentId = parent.get(itemId); - - // Check if no change is necessary - if ((newParentId == null && oldParentId == null) - || (newParentId != null && newParentId.equals(oldParentId))) { - return true; - } - - // Making root - if (newParentId == null) { - - // Remove from old parents children list - final LinkedList<Object> l = children.get(oldParentId); - if (l != null) { - l.remove(itemId); - if (l.isEmpty()) { - children.remove(itemId); - } - } - - // Add to be a root - roots.add(itemId); - - // Update parent - parent.remove(itemId); - - return true; - } - - // Check that the new parent exists in container and can have - // children - if (!containsId(newParentId) || noChildrenAllowed.contains(newParentId)) { - return false; - } - - // Check that setting parent doesn't result to a loop - Object o = newParentId; - while (o != null && !o.equals(itemId)) { - o = parent.get(o); - } - if (o != null) { - return false; - } - - // Update parent - parent.put(itemId, newParentId); - LinkedList<Object> pcl = children.get(newParentId); - if (pcl == null) { - pcl = new LinkedList<Object>(); - children.put(newParentId, pcl); - } - pcl.add(itemId); - - // Remove from old parent or root - if (oldParentId == null) { - roots.remove(itemId); - } else { - final LinkedList<Object> l = children.get(oldParentId); - if (l != null) { - l.remove(itemId); - if (l.isEmpty()) { - children.remove(oldParentId); - } - } - } - - return true; - } - - /** - * Creates a new Item into the Container, assigns it an automatic ID, and - * adds it to the hierarchy. - * - * @return the autogenerated ID of the new Item or <code>null</code> if the - * operation failed - * @throws UnsupportedOperationException - * if the addItem is not supported. - */ - @Override - public Object addItem() throws UnsupportedOperationException { - - final Object id = container.addItem(); - if (!hierarchical && id != null) { - addToHierarchyWrapper(id); - } - return id; - } - - /** - * Adds a new Item by its ID to the underlying container and to the - * hierarchy. - * - * @param itemId - * the ID of the Item to be created. - * @return the added Item or <code>null</code> if the operation failed. - * @throws UnsupportedOperationException - * if the addItem is not supported. - */ - @Override - public Item addItem(Object itemId) throws UnsupportedOperationException { - - // Null ids are not accepted - if (itemId == null) { - throw new NullPointerException("Container item id can not be null"); - } - - final Item item = container.addItem(itemId); - if (!hierarchical && item != null) { - addToHierarchyWrapper(itemId); - } - return item; - } - - /** - * Removes all items from the underlying container and from the hierarcy. - * - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the removeAllItems is not supported. - */ - @Override - public boolean removeAllItems() throws UnsupportedOperationException { - - final boolean success = container.removeAllItems(); - - if (!hierarchical && success) { - roots.clear(); - parent.clear(); - children.clear(); - noChildrenAllowed.clear(); - } - return success; - } - - /** - * Removes an Item specified by the itemId from the underlying container and - * from the hierarchy. - * - * @param itemId - * the ID of the Item to be removed. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the removeItem is not supported. - */ - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - - final boolean success = container.removeItem(itemId); - - if (!hierarchical && success) { - removeFromHierarchyWrapper(itemId); - } - - return success; - } - - /** - * Removes the Item identified by given itemId and all its children. - * - * @see #removeItem(Object) - * @param itemId - * the identifier of the Item to be removed - * @return true if the operation succeeded - */ - public boolean removeItemRecursively(Object itemId) { - return HierarchicalContainer.removeItemRecursively(this, itemId); - } - - /** - * Adds a new Property to all Items in the Container. - * - * @param propertyId - * the ID of the new Property. - * @param type - * the Data type of the new Property. - * @param defaultValue - * the value all created Properties are initialized to. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the addContainerProperty is not supported. - */ - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - - return container.addContainerProperty(propertyId, type, defaultValue); - } - - /** - * Removes the specified Property from the underlying container and from the - * hierarchy. - * <p> - * Note : The Property will be removed from all Items in the Container. - * </p> - * - * @param propertyId - * the ID of the Property to remove. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the removeContainerProperty is not supported. - */ - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - return container.removeContainerProperty(propertyId); - } - - /* - * Does the container contain the specified Item? Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean containsId(Object itemId) { - return container.containsId(itemId); - } - - /* - * Gets the specified Item from the container. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public Item getItem(Object itemId) { - return container.getItem(itemId); - } - - /* - * Gets the ID's of all Items stored in the Container Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> getItemIds() { - return container.getItemIds(); - } - - /* - * Gets the Property identified by the given itemId and propertyId from the - * Container Don't add a JavaDoc comment here, we use the default - * documentation from implemented interface. - */ - @Override - public Property<?> getContainerProperty(Object itemId, Object propertyId) { - return container.getContainerProperty(itemId, propertyId); - } - - /* - * Gets the ID's of all Properties stored in the Container Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> getContainerPropertyIds() { - return container.getContainerPropertyIds(); - } - - /* - * Gets the data type of all Properties identified by the given Property ID. - * Don't add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public Class<?> getType(Object propertyId) { - return container.getType(propertyId); - } - - /* - * Gets the number of Items in the Container. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public int size() { - return container.size(); - } - - /* - * Registers a new Item set change listener for this Container. Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void addListener(Container.ItemSetChangeListener listener) { - if (container instanceof Container.ItemSetChangeNotifier) { - ((Container.ItemSetChangeNotifier) container) - .addListener(new PiggybackListener(listener)); - } - } - - /* - * Removes a Item set change listener from the object. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void removeListener(Container.ItemSetChangeListener listener) { - if (container instanceof Container.ItemSetChangeNotifier) { - ((Container.ItemSetChangeNotifier) container) - .removeListener(new PiggybackListener(listener)); - } - } - - /* - * Registers a new Property set change listener for this Container. Don't - * add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public void addListener(Container.PropertySetChangeListener listener) { - if (container instanceof Container.PropertySetChangeNotifier) { - ((Container.PropertySetChangeNotifier) container) - .addListener(new PiggybackListener(listener)); - } - } - - /* - * Removes a Property set change listener from the object. Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void removeListener(Container.PropertySetChangeListener listener) { - if (container instanceof Container.PropertySetChangeNotifier) { - ((Container.PropertySetChangeNotifier) container) - .removeListener(new PiggybackListener(listener)); - } - } - - /** - * This listener 'piggybacks' on the real listener in order to update the - * wrapper when needed. It proxies equals() and hashCode() to the real - * listener so that the correct listener gets removed. - * - */ - private class PiggybackListener implements - Container.PropertySetChangeListener, - Container.ItemSetChangeListener { - - Object listener; - - public PiggybackListener(Object realListener) { - listener = realListener; - } - - @Override - public void containerItemSetChange(ItemSetChangeEvent event) { - updateHierarchicalWrapper(); - ((Container.ItemSetChangeListener) listener) - .containerItemSetChange(event); - - } - - @Override - public void containerPropertySetChange(PropertySetChangeEvent event) { - updateHierarchicalWrapper(); - ((Container.PropertySetChangeListener) listener) - .containerPropertySetChange(event); - - } - - @Override - public boolean equals(Object obj) { - return obj == listener || (obj != null && obj.equals(listener)); - } - - @Override - public int hashCode() { - return listener.hashCode(); - } - - } -} diff --git a/src/com/vaadin/data/util/ContainerOrderedWrapper.java b/src/com/vaadin/data/util/ContainerOrderedWrapper.java deleted file mode 100644 index d3d6f88d3e..0000000000 --- a/src/com/vaadin/data/util/ContainerOrderedWrapper.java +++ /dev/null @@ -1,644 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.util.Collection; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedList; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * <p> - * A wrapper class for adding external ordering to containers not implementing - * the {@link com.vaadin.data.Container.Ordered} interface. - * </p> - * - * <p> - * If the wrapped container is changed directly (that is, not through the - * wrapper), and does not implement Container.ItemSetChangeNotifier and/or - * Container.PropertySetChangeNotifier the hierarchy information must be updated - * with the {@link #updateOrderWrapper()} method. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ContainerOrderedWrapper implements Container.Ordered, - Container.ItemSetChangeNotifier, Container.PropertySetChangeNotifier { - - /** - * The wrapped container - */ - private final Container container; - - /** - * Ordering information, ie. the mapping from Item ID to the next item ID - */ - private Hashtable<Object, Object> next; - - /** - * Reverse ordering information for convenience and performance reasons. - */ - private Hashtable<Object, Object> prev; - - /** - * ID of the first Item in the container. - */ - private Object first; - - /** - * ID of the last Item in the container. - */ - private Object last; - - /** - * Is the wrapped container ordered by itself, ie. does it implement the - * Container.Ordered interface by itself? If it does, this class will use - * the methods of the underlying container directly. - */ - private boolean ordered = false; - - /** - * The last known size of the wrapped container. Used to check whether items - * have been added or removed to the wrapped container, when the wrapped - * container does not send ItemSetChangeEvents. - */ - private int lastKnownSize = -1; - - /** - * Constructs a new ordered wrapper for an existing Container. Works even if - * the to-be-wrapped container already implements the Container.Ordered - * interface. - * - * @param toBeWrapped - * the container whose contents need to be ordered. - */ - public ContainerOrderedWrapper(Container toBeWrapped) { - - container = toBeWrapped; - ordered = container instanceof Container.Ordered; - - // Checks arguments - if (container == null) { - throw new NullPointerException("Null can not be wrapped"); - } - - // Creates initial order if needed - updateOrderWrapper(); - } - - /** - * Removes the specified Item from the wrapper's internal hierarchy - * structure. - * <p> - * Note : The Item is not removed from the underlying Container. - * </p> - * - * @param id - * the ID of the Item to be removed from the ordering. - */ - private void removeFromOrderWrapper(Object id) { - if (id != null) { - final Object pid = prev.get(id); - final Object nid = next.get(id); - if (first.equals(id)) { - first = nid; - } - if (last.equals(id)) { - first = pid; - } - if (nid != null) { - prev.put(nid, pid); - } - if (pid != null) { - next.put(pid, nid); - } - next.remove(id); - prev.remove(id); - } - } - - /** - * Registers the specified Item to the last position in the wrapper's - * internal ordering. The underlying container is not modified. - * - * @param id - * the ID of the Item to be added to the ordering. - */ - private void addToOrderWrapper(Object id) { - - // Adds the if to tail - if (last != null) { - next.put(last, id); - prev.put(id, last); - last = id; - } else { - first = last = id; - } - } - - /** - * Registers the specified Item after the specified itemId in the wrapper's - * internal ordering. The underlying container is not modified. Given item - * id must be in the container, or must be null. - * - * @param id - * the ID of the Item to be added to the ordering. - * @param previousItemId - * the Id of the previous item. - */ - private void addToOrderWrapper(Object id, Object previousItemId) { - - if (last == previousItemId || last == null) { - addToOrderWrapper(id); - } else { - if (previousItemId == null) { - next.put(id, first); - prev.put(first, id); - first = id; - } else { - prev.put(id, previousItemId); - next.put(id, next.get(previousItemId)); - prev.put(next.get(previousItemId), id); - next.put(previousItemId, id); - } - } - } - - /** - * Updates the wrapper's internal ordering information to include all Items - * in the underlying container. - * <p> - * Note : If the contents of the wrapped container change without the - * wrapper's knowledge, this method needs to be called to update the - * ordering information of the Items. - * </p> - */ - public void updateOrderWrapper() { - - if (!ordered) { - - final Collection<?> ids = container.getItemIds(); - - // Recreates ordering if some parts of it are missing - if (next == null || first == null || last == null || prev != null) { - first = null; - last = null; - next = new Hashtable<Object, Object>(); - prev = new Hashtable<Object, Object>(); - } - - // Filter out all the missing items - final LinkedList<?> l = new LinkedList<Object>(next.keySet()); - for (final Iterator<?> i = l.iterator(); i.hasNext();) { - final Object id = i.next(); - if (!container.containsId(id)) { - removeFromOrderWrapper(id); - } - } - - // Adds missing items - for (final Iterator<?> i = ids.iterator(); i.hasNext();) { - final Object id = i.next(); - if (!next.containsKey(id)) { - addToOrderWrapper(id); - } - } - } - } - - /* - * Gets the first item stored in the ordered container Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Object firstItemId() { - if (ordered) { - return ((Container.Ordered) container).firstItemId(); - } - return first; - } - - /* - * Tests if the given item is the first item in the container Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean isFirstId(Object itemId) { - if (ordered) { - return ((Container.Ordered) container).isFirstId(itemId); - } - return first != null && first.equals(itemId); - } - - /* - * Tests if the given item is the last item in the container Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean isLastId(Object itemId) { - if (ordered) { - return ((Container.Ordered) container).isLastId(itemId); - } - return last != null && last.equals(itemId); - } - - /* - * Gets the last item stored in the ordered container Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Object lastItemId() { - if (ordered) { - return ((Container.Ordered) container).lastItemId(); - } - return last; - } - - /* - * Gets the item that is next from the specified item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Object nextItemId(Object itemId) { - if (ordered) { - return ((Container.Ordered) container).nextItemId(itemId); - } - if (itemId == null) { - return null; - } - return next.get(itemId); - } - - /* - * Gets the item that is previous from the specified item. Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Object prevItemId(Object itemId) { - if (ordered) { - return ((Container.Ordered) container).prevItemId(itemId); - } - if (itemId == null) { - return null; - } - return prev.get(itemId); - } - - /** - * Registers a new Property to all Items in the Container. - * - * @param propertyId - * the ID of the new Property. - * @param type - * the Data type of the new Property. - * @param defaultValue - * the value all created Properties are initialized to. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - - return container.addContainerProperty(propertyId, type, defaultValue); - } - - /** - * Creates a new Item into the Container, assigns it an automatic ID, and - * adds it to the ordering. - * - * @return the autogenerated ID of the new Item or <code>null</code> if the - * operation failed - * @throws UnsupportedOperationException - * if the addItem is not supported. - */ - @Override - public Object addItem() throws UnsupportedOperationException { - - final Object id = container.addItem(); - if (!ordered && id != null) { - addToOrderWrapper(id); - } - return id; - } - - /** - * Registers a new Item by its ID to the underlying container and to the - * ordering. - * - * @param itemId - * the ID of the Item to be created. - * @return the added Item or <code>null</code> if the operation failed - * @throws UnsupportedOperationException - * if the addItem is not supported. - */ - @Override - public Item addItem(Object itemId) throws UnsupportedOperationException { - final Item item = container.addItem(itemId); - if (!ordered && item != null) { - addToOrderWrapper(itemId); - } - return item; - } - - /** - * Removes all items from the underlying container and from the ordering. - * - * @return <code>true</code> if the operation succeeded, otherwise - * <code>false</code> - * @throws UnsupportedOperationException - * if the removeAllItems is not supported. - */ - @Override - public boolean removeAllItems() throws UnsupportedOperationException { - final boolean success = container.removeAllItems(); - if (!ordered && success) { - first = last = null; - next.clear(); - prev.clear(); - } - return success; - } - - /** - * Removes an Item specified by the itemId from the underlying container and - * from the ordering. - * - * @param itemId - * the ID of the Item to be removed. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the removeItem is not supported. - */ - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - - final boolean success = container.removeItem(itemId); - if (!ordered && success) { - removeFromOrderWrapper(itemId); - } - return success; - } - - /** - * Removes the specified Property from the underlying container and from the - * ordering. - * <p> - * Note : The Property will be removed from all the Items in the Container. - * </p> - * - * @param propertyId - * the ID of the Property to remove. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - * @throws UnsupportedOperationException - * if the removeContainerProperty is not supported. - */ - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - return container.removeContainerProperty(propertyId); - } - - /* - * Does the container contain the specified Item? Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean containsId(Object itemId) { - return container.containsId(itemId); - } - - /* - * Gets the specified Item from the container. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public Item getItem(Object itemId) { - return container.getItem(itemId); - } - - /* - * Gets the ID's of all Items stored in the Container Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> getItemIds() { - return container.getItemIds(); - } - - /* - * Gets the Property identified by the given itemId and propertyId from the - * Container Don't add a JavaDoc comment here, we use the default - * documentation from implemented interface. - */ - @Override - public Property<?> getContainerProperty(Object itemId, Object propertyId) { - return container.getContainerProperty(itemId, propertyId); - } - - /* - * Gets the ID's of all Properties stored in the Container Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> getContainerPropertyIds() { - return container.getContainerPropertyIds(); - } - - /* - * Gets the data type of all Properties identified by the given Property ID. - * Don't add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public Class<?> getType(Object propertyId) { - return container.getType(propertyId); - } - - /* - * Gets the number of Items in the Container. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public int size() { - int newSize = container.size(); - if (lastKnownSize != -1 && newSize != lastKnownSize - && !(container instanceof Container.ItemSetChangeNotifier)) { - // Update the internal cache when the size of the container changes - // and the container is incapable of sending ItemSetChangeEvents - updateOrderWrapper(); - } - lastKnownSize = newSize; - return newSize; - } - - /* - * Registers a new Item set change listener for this Container. Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void addListener(Container.ItemSetChangeListener listener) { - if (container instanceof Container.ItemSetChangeNotifier) { - ((Container.ItemSetChangeNotifier) container) - .addListener(new PiggybackListener(listener)); - } - } - - /* - * Removes a Item set change listener from the object. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void removeListener(Container.ItemSetChangeListener listener) { - if (container instanceof Container.ItemSetChangeNotifier) { - ((Container.ItemSetChangeNotifier) container) - .removeListener(new PiggybackListener(listener)); - } - } - - /* - * Registers a new Property set change listener for this Container. Don't - * add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public void addListener(Container.PropertySetChangeListener listener) { - if (container instanceof Container.PropertySetChangeNotifier) { - ((Container.PropertySetChangeNotifier) container) - .addListener(new PiggybackListener(listener)); - } - } - - /* - * Removes a Property set change listener from the object. Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void removeListener(Container.PropertySetChangeListener listener) { - if (container instanceof Container.PropertySetChangeNotifier) { - ((Container.PropertySetChangeNotifier) container) - .removeListener(new PiggybackListener(listener)); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object, - * java.lang.Object) - */ - @Override - public Item addItemAfter(Object previousItemId, Object newItemId) - throws UnsupportedOperationException { - - // If the previous item is not in the container, fail - if (previousItemId != null && !containsId(previousItemId)) { - return null; - } - - // Adds the item to container - final Item item = container.addItem(newItemId); - - // Puts the new item to its correct place - if (!ordered && item != null) { - addToOrderWrapper(newItemId, previousItemId); - } - - return item; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object) - */ - @Override - public Object addItemAfter(Object previousItemId) - throws UnsupportedOperationException { - - // If the previous item is not in the container, fail - if (previousItemId != null && !containsId(previousItemId)) { - return null; - } - - // Adds the item to container - final Object id = container.addItem(); - - // Puts the new item to its correct place - if (!ordered && id != null) { - addToOrderWrapper(id, previousItemId); - } - - return id; - } - - /** - * This listener 'piggybacks' on the real listener in order to update the - * wrapper when needed. It proxies equals() and hashCode() to the real - * listener so that the correct listener gets removed. - * - */ - private class PiggybackListener implements - Container.PropertySetChangeListener, - Container.ItemSetChangeListener { - - Object listener; - - public PiggybackListener(Object realListener) { - listener = realListener; - } - - @Override - public void containerItemSetChange(ItemSetChangeEvent event) { - updateOrderWrapper(); - ((Container.ItemSetChangeListener) listener) - .containerItemSetChange(event); - - } - - @Override - public void containerPropertySetChange(PropertySetChangeEvent event) { - updateOrderWrapper(); - ((Container.PropertySetChangeListener) listener) - .containerPropertySetChange(event); - - } - - @Override - public boolean equals(Object obj) { - return obj == listener || (obj != null && obj.equals(listener)); - } - - @Override - public int hashCode() { - return listener.hashCode(); - } - - } - -} diff --git a/src/com/vaadin/data/util/DefaultItemSorter.java b/src/com/vaadin/data/util/DefaultItemSorter.java deleted file mode 100644 index 81b15ebd4f..0000000000 --- a/src/com/vaadin/data/util/DefaultItemSorter.java +++ /dev/null @@ -1,210 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.List; - -import com.vaadin.data.Container; -import com.vaadin.data.Container.Sortable; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * Provides a default implementation of an ItemSorter. The - * <code>DefaultItemSorter</code> adheres to the - * {@link Sortable#sort(Object[], boolean[])} rules and sorts the container - * according to the properties given using - * {@link #setSortProperties(Sortable, Object[], boolean[])}. - * <p> - * A Comparator is used for comparing the individual <code>Property</code> - * values. The comparator can be set using the constructor. If no comparator is - * provided a default comparator is used. - * - */ -public class DefaultItemSorter implements ItemSorter { - - private java.lang.Object[] sortPropertyIds; - private boolean[] sortDirections; - private Container container; - private Comparator<Object> propertyValueComparator; - - /** - * Constructs a DefaultItemSorter using the default <code>Comparator</code> - * for comparing <code>Property</code>values. - * - */ - public DefaultItemSorter() { - this(new DefaultPropertyValueComparator()); - } - - /** - * Constructs a DefaultItemSorter which uses the <code>Comparator</code> - * indicated by the <code>propertyValueComparator</code> parameter for - * comparing <code>Property</code>values. - * - * @param propertyValueComparator - * The comparator to use when comparing individual - * <code>Property</code> values - */ - public DefaultItemSorter(Comparator<Object> propertyValueComparator) { - this.propertyValueComparator = propertyValueComparator; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.ItemSorter#compare(java.lang.Object, - * java.lang.Object) - */ - @Override - public int compare(Object o1, Object o2) { - Item item1 = container.getItem(o1); - Item item2 = container.getItem(o2); - - /* - * Items can be null if the container is filtered. Null is considered - * "less" than not-null. - */ - if (item1 == null) { - if (item2 == null) { - return 0; - } else { - return 1; - } - } else if (item2 == null) { - return -1; - } - - for (int i = 0; i < sortPropertyIds.length; i++) { - - int result = compareProperty(sortPropertyIds[i], sortDirections[i], - item1, item2); - - // If order can be decided - if (result != 0) { - return result; - } - - } - - return 0; - } - - /** - * Compares the property indicated by <code>propertyId</code> in the items - * indicated by <code>item1</code> and <code>item2</code> for order. Returns - * a negative integer, zero, or a positive integer as the property value in - * the first item is less than, equal to, or greater than the property value - * in the second item. If the <code>sortDirection</code> is false the - * returned value is negated. - * <p> - * The comparator set for this <code>DefaultItemSorter</code> is used for - * comparing the two property values. - * - * @param propertyId - * The property id for the property that is used for comparison. - * @param sortDirection - * The direction of the sort. A false value negates the result. - * @param item1 - * The first item to compare. - * @param item2 - * The second item to compare. - * @return a negative, zero, or positive integer if the property value in - * the first item is less than, equal to, or greater than the - * property value in the second item. Negated if - * {@code sortDirection} is false. - */ - protected int compareProperty(Object propertyId, boolean sortDirection, - Item item1, Item item2) { - - // Get the properties to compare - final Property<?> property1 = item1.getItemProperty(propertyId); - final Property<?> property2 = item2.getItemProperty(propertyId); - - // Get the values to compare - final Object value1 = (property1 == null) ? null : property1.getValue(); - final Object value2 = (property2 == null) ? null : property2.getValue(); - - // Result of the comparison - int r = 0; - if (sortDirection) { - r = propertyValueComparator.compare(value1, value2); - } else { - r = propertyValueComparator.compare(value2, value1); - } - - return r; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.ItemSorter#setSortProperties(com.vaadin.data.Container - * .Sortable, java.lang.Object[], boolean[]) - */ - @Override - public void setSortProperties(Container.Sortable container, - Object[] propertyId, boolean[] ascending) { - this.container = container; - - // Removes any non-sortable property ids - final List<Object> ids = new ArrayList<Object>(); - final List<Boolean> orders = new ArrayList<Boolean>(); - final Collection<?> sortable = container - .getSortableContainerPropertyIds(); - for (int i = 0; i < propertyId.length; i++) { - if (sortable.contains(propertyId[i])) { - ids.add(propertyId[i]); - orders.add(Boolean.valueOf(i < ascending.length ? ascending[i] - : true)); - } - } - - sortPropertyIds = ids.toArray(); - sortDirections = new boolean[orders.size()]; - for (int i = 0; i < sortDirections.length; i++) { - sortDirections[i] = (orders.get(i)).booleanValue(); - } - - } - - /** - * Provides a default comparator used for comparing {@link Property} values. - * The <code>DefaultPropertyValueComparator</code> assumes all objects it - * compares can be cast to Comparable. - * - */ - public static class DefaultPropertyValueComparator implements - Comparator<Object>, Serializable { - - @Override - @SuppressWarnings("unchecked") - public int compare(Object o1, Object o2) { - int r = 0; - // Normal non-null comparison - if (o1 != null && o2 != null) { - // Assume the objects can be cast to Comparable, throw - // ClassCastException otherwise. - r = ((Comparable<Object>) o1).compareTo(o2); - } else if (o1 == o2) { - // Objects are equal if both are null - r = 0; - } else { - if (o1 == null) { - r = -1; // null is less than non-null - } else { - r = 1; // non-null is greater than null - } - } - - return r; - } - } - -} diff --git a/src/com/vaadin/data/util/FilesystemContainer.java b/src/com/vaadin/data/util/FilesystemContainer.java deleted file mode 100644 index cdfeb57e14..0000000000 --- a/src/com/vaadin/data/util/FilesystemContainer.java +++ /dev/null @@ -1,918 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.service.FileTypeResolver; -import com.vaadin.terminal.Resource; - -/** - * A hierarchical container wrapper for a filesystem. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class FilesystemContainer implements Container.Hierarchical { - - /** - * String identifier of a file's "name" property. - */ - public static String PROPERTY_NAME = "Name"; - - /** - * String identifier of a file's "size" property. - */ - public static String PROPERTY_SIZE = "Size"; - - /** - * String identifier of a file's "icon" property. - */ - public static String PROPERTY_ICON = "Icon"; - - /** - * String identifier of a file's "last modified" property. - */ - public static String PROPERTY_LASTMODIFIED = "Last Modified"; - - /** - * List of the string identifiers for the available properties. - */ - public static Collection<String> FILE_PROPERTIES; - - private final static Method FILEITEM_LASTMODIFIED; - - private final static Method FILEITEM_NAME; - - private final static Method FILEITEM_ICON; - - private final static Method FILEITEM_SIZE; - - static { - - FILE_PROPERTIES = new ArrayList<String>(); - FILE_PROPERTIES.add(PROPERTY_NAME); - FILE_PROPERTIES.add(PROPERTY_ICON); - FILE_PROPERTIES.add(PROPERTY_SIZE); - FILE_PROPERTIES.add(PROPERTY_LASTMODIFIED); - FILE_PROPERTIES = Collections.unmodifiableCollection(FILE_PROPERTIES); - try { - FILEITEM_LASTMODIFIED = FileItem.class.getMethod("lastModified", - new Class[] {}); - FILEITEM_NAME = FileItem.class.getMethod("getName", new Class[] {}); - FILEITEM_ICON = FileItem.class.getMethod("getIcon", new Class[] {}); - FILEITEM_SIZE = FileItem.class.getMethod("getSize", new Class[] {}); - } catch (final NoSuchMethodException e) { - throw new RuntimeException( - "Internal error finding methods in FilesystemContainer"); - } - } - - private File[] roots = new File[] {}; - - private FilenameFilter filter = null; - - private boolean recursive = true; - - /** - * Constructs a new <code>FileSystemContainer</code> with the specified file - * as the root of the filesystem. The files are included recursively. - * - * @param root - * the root file for the new file-system container. Null values - * are ignored. - */ - public FilesystemContainer(File root) { - if (root != null) { - roots = new File[] { root }; - } - } - - /** - * Constructs a new <code>FileSystemContainer</code> with the specified file - * as the root of the filesystem. The files are included recursively. - * - * @param root - * the root file for the new file-system container. - * @param recursive - * should the container recursively contain subdirectories. - */ - public FilesystemContainer(File root, boolean recursive) { - this(root); - setRecursive(recursive); - } - - /** - * Constructs a new <code>FileSystemContainer</code> with the specified file - * as the root of the filesystem. - * - * @param root - * the root file for the new file-system container. - * @param extension - * the Filename extension (w/o separator) to limit the files in - * container. - * @param recursive - * should the container recursively contain subdirectories. - */ - public FilesystemContainer(File root, String extension, boolean recursive) { - this(root); - this.setFilter(extension); - setRecursive(recursive); - } - - /** - * Constructs a new <code>FileSystemContainer</code> with the specified root - * and recursivity status. - * - * @param root - * the root file for the new file-system container. - * @param filter - * the Filename filter to limit the files in container. - * @param recursive - * should the container recursively contain subdirectories. - */ - public FilesystemContainer(File root, FilenameFilter filter, - boolean recursive) { - this(root); - this.setFilter(filter); - setRecursive(recursive); - } - - /** - * Adds new root file directory. Adds a file to be included as root file - * directory in the <code>FilesystemContainer</code>. - * - * @param root - * the File to be added as root directory. Null values are - * ignored. - */ - public void addRoot(File root) { - if (root != null) { - final File[] newRoots = new File[roots.length + 1]; - for (int i = 0; i < roots.length; i++) { - newRoots[i] = roots[i]; - } - newRoots[roots.length] = root; - roots = newRoots; - } - } - - /** - * Tests if the specified Item in the container may have children. Since a - * <code>FileSystemContainer</code> contains files and directories, this - * method returns <code>true</code> for directory Items only. - * - * @param itemId - * the id of the item. - * @return <code>true</code> if the specified Item is a directory, - * <code>false</code> otherwise. - */ - @Override - public boolean areChildrenAllowed(Object itemId) { - return itemId instanceof File && ((File) itemId).canRead() - && ((File) itemId).isDirectory(); - } - - /* - * Gets the ID's of all Items who are children of the specified Item. Don't - * add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public Collection<File> getChildren(Object itemId) { - - if (!(itemId instanceof File)) { - return Collections.unmodifiableCollection(new LinkedList<File>()); - } - File[] f; - if (filter != null) { - f = ((File) itemId).listFiles(filter); - } else { - f = ((File) itemId).listFiles(); - } - - if (f == null) { - return Collections.unmodifiableCollection(new LinkedList<File>()); - } - - final List<File> l = Arrays.asList(f); - Collections.sort(l); - - return Collections.unmodifiableCollection(l); - } - - /* - * Gets the parent item of the specified Item. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public Object getParent(Object itemId) { - - if (!(itemId instanceof File)) { - return null; - } - return ((File) itemId).getParentFile(); - } - - /* - * Tests if the specified Item has any children. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public boolean hasChildren(Object itemId) { - - if (!(itemId instanceof File)) { - return false; - } - String[] l; - if (filter != null) { - l = ((File) itemId).list(filter); - } else { - l = ((File) itemId).list(); - } - return (l != null) && (l.length > 0); - } - - /* - * Tests if the specified Item is the root of the filesystem. Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean isRoot(Object itemId) { - - if (!(itemId instanceof File)) { - return false; - } - for (int i = 0; i < roots.length; i++) { - if (roots[i].equals(itemId)) { - return true; - } - } - return false; - } - - /* - * Gets the ID's of all root Items in the container. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<File> rootItemIds() { - - File[] f; - - // in single root case we use children - if (roots.length == 1) { - if (filter != null) { - f = roots[0].listFiles(filter); - } else { - f = roots[0].listFiles(); - } - } else { - f = roots; - } - - if (f == null) { - return Collections.unmodifiableCollection(new LinkedList<File>()); - } - - final List<File> l = Arrays.asList(f); - Collections.sort(l); - - return Collections.unmodifiableCollection(l); - } - - /** - * Returns <code>false</code> when conversion from files to directories is - * not supported. - * - * @param itemId - * the ID of the item. - * @param areChildrenAllowed - * the boolean value specifying if the Item can have children or - * not. - * @return <code>true</code> if the operaton is successful otherwise - * <code>false</code>. - * @throws UnsupportedOperationException - * if the setChildrenAllowed is not supported. - */ - @Override - public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) - throws UnsupportedOperationException { - - throw new UnsupportedOperationException( - "Conversion file to/from directory is not supported"); - } - - /** - * Returns <code>false</code> when moving files around in the filesystem is - * not supported. - * - * @param itemId - * the ID of the item. - * @param newParentId - * the ID of the Item that's to be the new parent of the Item - * identified with itemId. - * @return <code>true</code> if the operation is successful otherwise - * <code>false</code>. - * @throws UnsupportedOperationException - * if the setParent is not supported. - */ - @Override - public boolean setParent(Object itemId, Object newParentId) - throws UnsupportedOperationException { - - throw new UnsupportedOperationException("File moving is not supported"); - } - - /* - * Tests if the filesystem contains the specified Item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean containsId(Object itemId) { - - if (!(itemId instanceof File)) { - return false; - } - boolean val = false; - - // Try to match all roots - for (int i = 0; i < roots.length; i++) { - try { - val |= ((File) itemId).getCanonicalPath().startsWith( - roots[i].getCanonicalPath()); - } catch (final IOException e) { - // Exception ignored - } - - } - if (val && filter != null) { - val &= filter.accept(((File) itemId).getParentFile(), - ((File) itemId).getName()); - } - return val; - } - - /* - * Gets the specified Item from the filesystem. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public Item getItem(Object itemId) { - - if (!(itemId instanceof File)) { - return null; - } - return new FileItem((File) itemId); - } - - /** - * Internal recursive method to add the files under the specified directory - * to the collection. - * - * @param col - * the collection where the found items are added - * @param f - * the root file where to start adding files - */ - private void addItemIds(Collection<File> col, File f) { - File[] l; - if (filter != null) { - l = f.listFiles(filter); - } else { - l = f.listFiles(); - } - if (l == null) { - // File.listFiles returns null if File does not exist or if there - // was an IO error (permission denied) - return; - } - final List<File> ll = Arrays.asList(l); - Collections.sort(ll); - - for (final Iterator<File> i = ll.iterator(); i.hasNext();) { - final File lf = i.next(); - col.add(lf); - if (lf.isDirectory()) { - addItemIds(col, lf); - } - } - } - - /* - * Gets the IDs of Items in the filesystem. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public Collection<File> getItemIds() { - - if (recursive) { - final Collection<File> col = new ArrayList<File>(); - for (int i = 0; i < roots.length; i++) { - addItemIds(col, roots[i]); - } - return Collections.unmodifiableCollection(col); - } else { - File[] f; - if (roots.length == 1) { - if (filter != null) { - f = roots[0].listFiles(filter); - } else { - f = roots[0].listFiles(); - } - } else { - f = roots; - } - - if (f == null) { - return Collections - .unmodifiableCollection(new LinkedList<File>()); - } - - final List<File> l = Arrays.asList(f); - Collections.sort(l); - return Collections.unmodifiableCollection(l); - } - - } - - /** - * Gets the specified property of the specified file Item. The available - * file properties are "Name", "Size" and "Last Modified". If propertyId is - * not one of those, <code>null</code> is returned. - * - * @param itemId - * the ID of the file whose property is requested. - * @param propertyId - * the property's ID. - * @return the requested property's value, or <code>null</code> - */ - @Override - public Property<?> getContainerProperty(Object itemId, Object propertyId) { - - if (!(itemId instanceof File)) { - return null; - } - - if (propertyId.equals(PROPERTY_NAME)) { - return new MethodProperty<Object>(getType(propertyId), - new FileItem((File) itemId), FILEITEM_NAME, null); - } - - if (propertyId.equals(PROPERTY_ICON)) { - return new MethodProperty<Object>(getType(propertyId), - new FileItem((File) itemId), FILEITEM_ICON, null); - } - - if (propertyId.equals(PROPERTY_SIZE)) { - return new MethodProperty<Object>(getType(propertyId), - new FileItem((File) itemId), FILEITEM_SIZE, null); - } - - if (propertyId.equals(PROPERTY_LASTMODIFIED)) { - return new MethodProperty<Object>(getType(propertyId), - new FileItem((File) itemId), FILEITEM_LASTMODIFIED, null); - } - - return null; - } - - /** - * Gets the collection of available file properties. - * - * @return Unmodifiable collection containing all available file properties. - */ - @Override - public Collection<String> getContainerPropertyIds() { - return FILE_PROPERTIES; - } - - /** - * Gets the specified property's data type. "Name" is a <code>String</code>, - * "Size" is a <code>Long</code>, "Last Modified" is a <code>Date</code>. If - * propertyId is not one of those, <code>null</code> is returned. - * - * @param propertyId - * the ID of the property whose type is requested. - * @return data type of the requested property, or <code>null</code> - */ - @Override - public Class<?> getType(Object propertyId) { - - if (propertyId.equals(PROPERTY_NAME)) { - return String.class; - } - if (propertyId.equals(PROPERTY_ICON)) { - return Resource.class; - } - if (propertyId.equals(PROPERTY_SIZE)) { - return Long.class; - } - if (propertyId.equals(PROPERTY_LASTMODIFIED)) { - return Date.class; - } - return null; - } - - /** - * Internal method to recursively calculate the number of files under a root - * directory. - * - * @param f - * the root to start counting from. - */ - private int getFileCounts(File f) { - File[] l; - if (filter != null) { - l = f.listFiles(filter); - } else { - l = f.listFiles(); - } - - if (l == null) { - return 0; - } - int ret = l.length; - for (int i = 0; i < l.length; i++) { - if (l[i].isDirectory()) { - ret += getFileCounts(l[i]); - } - } - return ret; - } - - /** - * Gets the number of Items in the container. In effect, this is the - * combined amount of files and directories. - * - * @return Number of Items in the container. - */ - @Override - public int size() { - - if (recursive) { - int counts = 0; - for (int i = 0; i < roots.length; i++) { - counts += getFileCounts(roots[i]); - } - return counts; - } else { - File[] f; - if (roots.length == 1) { - if (filter != null) { - f = roots[0].listFiles(filter); - } else { - f = roots[0].listFiles(); - } - } else { - f = roots; - } - - if (f == null) { - return 0; - } - return f.length; - } - } - - /** - * A Item wrapper for files in a filesystem. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class FileItem implements Item { - - /** - * The wrapped file. - */ - private final File file; - - /** - * Constructs a FileItem from a existing file. - */ - private FileItem(File file) { - this.file = file; - } - - /* - * Gets the specified property of this file. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public Property<?> getItemProperty(Object id) { - return getContainerProperty(file, id); - } - - /* - * Gets the IDs of all properties available for this item Don't add a - * JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public Collection<String> getItemPropertyIds() { - return getContainerPropertyIds(); - } - - /** - * Calculates a integer hash-code for the Property that's unique inside - * the Item containing the Property. Two different Properties inside the - * same Item contained in the same list always have different - * hash-codes, though Properties in different Items may have identical - * hash-codes. - * - * @return A locally unique hash-code as integer - */ - @Override - public int hashCode() { - return file.hashCode() ^ FilesystemContainer.this.hashCode(); - } - - /** - * Tests if the given object is the same as the this object. Two - * Properties got from an Item with the same ID are equal. - * - * @param obj - * an object to compare with this object. - * @return <code>true</code> if the given object is the same as this - * object, <code>false</code> if not - */ - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof FileItem)) { - return false; - } - final FileItem fi = (FileItem) obj; - return fi.getHost() == getHost() && fi.file.equals(file); - } - - /** - * Gets the host of this file. - */ - private FilesystemContainer getHost() { - return FilesystemContainer.this; - } - - /** - * Gets the last modified date of this file. - * - * @return Date - */ - public Date lastModified() { - return new Date(file.lastModified()); - } - - /** - * Gets the name of this file. - * - * @return file name of this file. - */ - public String getName() { - return file.getName(); - } - - /** - * Gets the icon of this file. - * - * @return the icon of this file. - */ - public Resource getIcon() { - return FileTypeResolver.getIcon(file); - } - - /** - * Gets the size of this file. - * - * @return size - */ - public long getSize() { - if (file.isDirectory()) { - return 0; - } - return file.length(); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - if ("".equals(file.getName())) { - return file.getAbsolutePath(); - } - return file.getName(); - } - - /** - * Filesystem container does not support adding new properties. - * - * @see com.vaadin.data.Item#addItemProperty(Object, Property) - */ - @Override - public boolean addItemProperty(Object id, Property property) - throws UnsupportedOperationException { - throw new UnsupportedOperationException("Filesystem container " - + "does not support adding new properties"); - } - - /** - * Filesystem container does not support removing properties. - * - * @see com.vaadin.data.Item#removeItemProperty(Object) - */ - @Override - public boolean removeItemProperty(Object id) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Filesystem container does not support property removal"); - } - - } - - /** - * Generic file extension filter for displaying only files having certain - * extension. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class FileExtensionFilter implements FilenameFilter, Serializable { - - private final String filter; - - /** - * Constructs a new FileExtensionFilter using given extension. - * - * @param fileExtension - * the File extension without the separator (dot). - */ - public FileExtensionFilter(String fileExtension) { - filter = "." + fileExtension; - } - - /** - * Allows only files with the extension and directories. - * - * @see java.io.FilenameFilter#accept(File, String) - */ - @Override - public boolean accept(File dir, String name) { - if (name.endsWith(filter)) { - return true; - } - return new File(dir, name).isDirectory(); - } - - } - - /** - * Returns the file filter used to limit the files in this container. - * - * @return Used filter instance or null if no filter is assigned. - */ - public FilenameFilter getFilter() { - return filter; - } - - /** - * Sets the file filter used to limit the files in this container. - * - * @param filter - * The filter to set. <code>null</code> disables filtering. - */ - public void setFilter(FilenameFilter filter) { - this.filter = filter; - } - - /** - * Sets the file filter used to limit the files in this container. - * - * @param extension - * the Filename extension (w/o separator) to limit the files in - * container. - */ - public void setFilter(String extension) { - filter = new FileExtensionFilter(extension); - } - - /** - * Is this container recursive filesystem. - * - * @return <code>true</code> if container is recursive, <code>false</code> - * otherwise. - */ - public boolean isRecursive() { - return recursive; - } - - /** - * Sets the container recursive property. Set this to false to limit the - * files directly under the root file. - * <p> - * Note : This is meaningful only if the root really is a directory. - * </p> - * - * @param recursive - * the New value for recursive property. - */ - public void setRecursive(boolean recursive) { - this.recursive = recursive; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addContainerProperty(java.lang.Object, - * java.lang.Class, java.lang.Object) - */ - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "File system container does not support this operation"); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addItem() - */ - @Override - public Object addItem() throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "File system container does not support this operation"); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addItem(java.lang.Object) - */ - @Override - public Item addItem(Object itemId) throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "File system container does not support this operation"); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeAllItems() - */ - @Override - public boolean removeAllItems() throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "File system container does not support this operation"); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeItem(java.lang.Object) - */ - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "File system container does not support this operation"); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeContainerProperty(java.lang.Object ) - */ - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "File system container does not support this operation"); - } -} diff --git a/src/com/vaadin/data/util/HierarchicalContainer.java b/src/com/vaadin/data/util/HierarchicalContainer.java deleted file mode 100644 index 06ab77c0e7..0000000000 --- a/src/com/vaadin/data/util/HierarchicalContainer.java +++ /dev/null @@ -1,814 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.Set; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; - -/** - * A specialized Container whose contents can be accessed like it was a - * tree-like structure. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class HierarchicalContainer extends IndexedContainer implements - Container.Hierarchical { - - /** - * Set of IDs of those contained Items that can't have children. - */ - private final HashSet<Object> noChildrenAllowed = new HashSet<Object>(); - - /** - * Mapping from Item ID to parent Item ID. - */ - private final HashMap<Object, Object> parent = new HashMap<Object, Object>(); - - /** - * Mapping from Item ID to parent Item ID for items included in the filtered - * container. - */ - private HashMap<Object, Object> filteredParent = null; - - /** - * Mapping from Item ID to a list of child IDs. - */ - private final HashMap<Object, LinkedList<Object>> children = new HashMap<Object, LinkedList<Object>>(); - - /** - * Mapping from Item ID to a list of child IDs when filtered - */ - private HashMap<Object, LinkedList<Object>> filteredChildren = null; - - /** - * List that contains all root elements of the container. - */ - private final LinkedList<Object> roots = new LinkedList<Object>(); - - /** - * List that contains all filtered root elements of the container. - */ - private LinkedList<Object> filteredRoots = null; - - /** - * Determines how filtering of the container is done. - */ - private boolean includeParentsWhenFiltering = true; - - private boolean contentChangedEventsDisabled = false; - - private boolean contentsChangedEventPending; - - /* - * Can the specified Item have any children? Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public boolean areChildrenAllowed(Object itemId) { - if (noChildrenAllowed.contains(itemId)) { - return false; - } - return containsId(itemId); - } - - /* - * Gets the IDs of the children of the specified Item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> getChildren(Object itemId) { - LinkedList<Object> c; - - if (filteredChildren != null) { - c = filteredChildren.get(itemId); - } else { - c = children.get(itemId); - } - - if (c == null) { - return null; - } - return Collections.unmodifiableCollection(c); - } - - /* - * Gets the ID of the parent of the specified Item. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Object getParent(Object itemId) { - if (filteredParent != null) { - return filteredParent.get(itemId); - } - return parent.get(itemId); - } - - /* - * Is the Item corresponding to the given ID a leaf node? Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean hasChildren(Object itemId) { - if (filteredChildren != null) { - return filteredChildren.containsKey(itemId); - } else { - return children.containsKey(itemId); - } - } - - /* - * Is the Item corresponding to the given ID a root node? Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public boolean isRoot(Object itemId) { - // If the container is filtered the itemId must be among filteredRoots - // to be a root. - if (filteredRoots != null) { - if (!filteredRoots.contains(itemId)) { - return false; - } - } else { - // Container is not filtered - if (parent.containsKey(itemId)) { - return false; - } - } - - return containsId(itemId); - } - - /* - * Gets the IDs of the root elements in the container. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public Collection<?> rootItemIds() { - if (filteredRoots != null) { - return Collections.unmodifiableCollection(filteredRoots); - } else { - return Collections.unmodifiableCollection(roots); - } - } - - /** - * <p> - * Sets the given Item's capability to have children. If the Item identified - * with the itemId already has children and the areChildrenAllowed is false - * this method fails and <code>false</code> is returned; the children must - * be first explicitly removed with - * {@link #setParent(Object itemId, Object newParentId)} or - * {@link com.vaadin.data.Container#removeItem(Object itemId)}. - * </p> - * - * @param itemId - * the ID of the Item in the container whose child capability is - * to be set. - * @param childrenAllowed - * the boolean value specifying if the Item can have children or - * not. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean setChildrenAllowed(Object itemId, boolean childrenAllowed) { - - // Checks that the item is in the container - if (!containsId(itemId)) { - return false; - } - - // Updates status - if (childrenAllowed) { - noChildrenAllowed.remove(itemId); - } else { - noChildrenAllowed.add(itemId); - } - - return true; - } - - /** - * <p> - * Sets the parent of an Item. The new parent item must exist and be able to - * have children. (<code>canHaveChildren(newParentId) == true</code>). It is - * also possible to detach a node from the hierarchy (and thus make it root) - * by setting the parent <code>null</code>. - * </p> - * - * @param itemId - * the ID of the item to be set as the child of the Item - * identified with newParentId. - * @param newParentId - * the ID of the Item that's to be the new parent of the Item - * identified with itemId. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean setParent(Object itemId, Object newParentId) { - - // Checks that the item is in the container - if (!containsId(itemId)) { - return false; - } - - // Gets the old parent - final Object oldParentId = parent.get(itemId); - - // Checks if no change is necessary - if ((newParentId == null && oldParentId == null) - || ((newParentId != null) && newParentId.equals(oldParentId))) { - return true; - } - - // Making root? - if (newParentId == null) { - // The itemId should become a root so we need to - // - Remove it from the old parent's children list - // - Add it as a root - // - Remove it from the item -> parent list (parent is null for - // roots) - - // Removes from old parents children list - final LinkedList<Object> l = children.get(oldParentId); - if (l != null) { - l.remove(itemId); - if (l.isEmpty()) { - children.remove(oldParentId); - } - - } - - // Add to be a root - roots.add(itemId); - - // Updates parent - parent.remove(itemId); - - if (hasFilters()) { - // Refilter the container if setParent is called when filters - // are applied. Changing parent can change what is included in - // the filtered version (if includeParentsWhenFiltering==true). - doFilterContainer(hasFilters()); - } - - fireItemSetChange(); - - return true; - } - - // We get here when the item should not become a root and we need to - // - Verify the new parent exists and can have children - // - Check that the new parent is not a child of the selected itemId - // - Updated the item -> parent mapping to point to the new parent - // - Remove the item from the roots list if it was a root - // - Remove the item from the old parent's children list if it was not a - // root - - // Checks that the new parent exists in container and can have - // children - if (!containsId(newParentId) || noChildrenAllowed.contains(newParentId)) { - return false; - } - - // Checks that setting parent doesn't result to a loop - Object o = newParentId; - while (o != null && !o.equals(itemId)) { - o = parent.get(o); - } - if (o != null) { - return false; - } - - // Updates parent - parent.put(itemId, newParentId); - LinkedList<Object> pcl = children.get(newParentId); - if (pcl == null) { - // Create an empty list for holding children if one were not - // previously created - pcl = new LinkedList<Object>(); - children.put(newParentId, pcl); - } - pcl.add(itemId); - - // Removes from old parent or root - if (oldParentId == null) { - roots.remove(itemId); - } else { - final LinkedList<Object> l = children.get(oldParentId); - if (l != null) { - l.remove(itemId); - if (l.isEmpty()) { - children.remove(oldParentId); - } - } - } - - if (hasFilters()) { - // Refilter the container if setParent is called when filters - // are applied. Changing parent can change what is included in - // the filtered version (if includeParentsWhenFiltering==true). - doFilterContainer(hasFilters()); - } - - fireItemSetChange(); - - return true; - } - - private boolean hasFilters() { - return (filteredRoots != null); - } - - /** - * Moves a node (an Item) in the container immediately after a sibling node. - * The two nodes must have the same parent in the container. - * - * @param itemId - * the identifier of the moved node (Item) - * @param siblingId - * the identifier of the reference node (Item), after which the - * other node will be located - */ - public void moveAfterSibling(Object itemId, Object siblingId) { - Object parent2 = getParent(itemId); - LinkedList<Object> childrenList; - if (parent2 == null) { - childrenList = roots; - } else { - childrenList = children.get(parent2); - } - if (siblingId == null) { - childrenList.remove(itemId); - childrenList.addFirst(itemId); - - } else { - int oldIndex = childrenList.indexOf(itemId); - int indexOfSibling = childrenList.indexOf(siblingId); - if (indexOfSibling != -1 && oldIndex != -1) { - int newIndex; - if (oldIndex > indexOfSibling) { - newIndex = indexOfSibling + 1; - } else { - newIndex = indexOfSibling; - } - childrenList.remove(oldIndex); - childrenList.add(newIndex, itemId); - } else { - throw new IllegalArgumentException( - "Given identifiers no not have the same parent."); - } - } - fireItemSetChange(); - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#addItem() - */ - @Override - public Object addItem() { - disableContentsChangeEvents(); - final Object itemId = super.addItem(); - if (itemId == null) { - return null; - } - - if (!roots.contains(itemId)) { - roots.add(itemId); - if (filteredRoots != null) { - if (passesFilters(itemId)) { - filteredRoots.add(itemId); - } - } - } - enableAndFireContentsChangeEvents(); - return itemId; - } - - @Override - protected void fireItemSetChange( - com.vaadin.data.Container.ItemSetChangeEvent event) { - if (contentsChangeEventsOn()) { - super.fireItemSetChange(event); - } else { - contentsChangedEventPending = true; - } - } - - private boolean contentsChangeEventsOn() { - return !contentChangedEventsDisabled; - } - - private void disableContentsChangeEvents() { - contentChangedEventsDisabled = true; - } - - private void enableAndFireContentsChangeEvents() { - contentChangedEventsDisabled = false; - if (contentsChangedEventPending) { - fireItemSetChange(); - } - contentsChangedEventPending = false; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#addItem(java.lang.Object) - */ - @Override - public Item addItem(Object itemId) { - disableContentsChangeEvents(); - final Item item = super.addItem(itemId); - if (item == null) { - return null; - } - - roots.add(itemId); - - if (filteredRoots != null) { - if (passesFilters(itemId)) { - filteredRoots.add(itemId); - } - } - enableAndFireContentsChangeEvents(); - return item; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#removeAllItems() - */ - @Override - public boolean removeAllItems() { - disableContentsChangeEvents(); - final boolean success = super.removeAllItems(); - - if (success) { - roots.clear(); - parent.clear(); - children.clear(); - noChildrenAllowed.clear(); - if (filteredRoots != null) { - filteredRoots = null; - } - if (filteredChildren != null) { - filteredChildren = null; - } - if (filteredParent != null) { - filteredParent = null; - } - } - enableAndFireContentsChangeEvents(); - return success; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#removeItem(java.lang.Object ) - */ - @Override - public boolean removeItem(Object itemId) { - disableContentsChangeEvents(); - final boolean success = super.removeItem(itemId); - - if (success) { - // Remove from roots if this was a root - if (roots.remove(itemId)) { - - // If filtering is enabled we might need to remove it from the - // filtered list also - if (filteredRoots != null) { - filteredRoots.remove(itemId); - } - } - - // Clear the children list. Old children will now become root nodes - LinkedList<Object> childNodeIds = children.remove(itemId); - if (childNodeIds != null) { - if (filteredChildren != null) { - filteredChildren.remove(itemId); - } - for (Object childId : childNodeIds) { - setParent(childId, null); - } - } - - // Parent of the item that we are removing will contain the item id - // in its children list - final Object parentItemId = parent.get(itemId); - if (parentItemId != null) { - final LinkedList<Object> c = children.get(parentItemId); - if (c != null) { - c.remove(itemId); - - if (c.isEmpty()) { - children.remove(parentItemId); - } - - // Found in the children list so might also be in the - // filteredChildren list - if (filteredChildren != null) { - LinkedList<Object> f = filteredChildren - .get(parentItemId); - if (f != null) { - f.remove(itemId); - if (f.isEmpty()) { - filteredChildren.remove(parentItemId); - } - } - } - } - } - parent.remove(itemId); - if (filteredParent != null) { - // Item id no longer has a parent as the item id is not in the - // container. - filteredParent.remove(itemId); - } - noChildrenAllowed.remove(itemId); - } - - enableAndFireContentsChangeEvents(); - - return success; - } - - /** - * Removes the Item identified by given itemId and all its children. - * - * @see #removeItem(Object) - * @param itemId - * the identifier of the Item to be removed - * @return true if the operation succeeded - */ - public boolean removeItemRecursively(Object itemId) { - disableContentsChangeEvents(); - boolean removeItemRecursively = removeItemRecursively(this, itemId); - enableAndFireContentsChangeEvents(); - return removeItemRecursively; - } - - /** - * Removes the Item identified by given itemId and all its children from the - * given Container. - * - * @param container - * the container where the item is to be removed - * @param itemId - * the identifier of the Item to be removed - * @return true if the operation succeeded - */ - public static boolean removeItemRecursively( - Container.Hierarchical container, Object itemId) { - boolean success = true; - Collection<?> children2 = container.getChildren(itemId); - if (children2 != null) { - Object[] array = children2.toArray(); - for (int i = 0; i < array.length; i++) { - boolean removeItemRecursively = removeItemRecursively( - container, array[i]); - if (!removeItemRecursively) { - success = false; - } - } - } - // remove the root of subtree if children where succesfully removed - if (success) { - success = container.removeItem(itemId); - } - return success; - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#doSort() - */ - @Override - protected void doSort() { - super.doSort(); - - Collections.sort(roots, getItemSorter()); - for (LinkedList<Object> childList : children.values()) { - Collections.sort(childList, getItemSorter()); - } - } - - /** - * Used to control how filtering works. @see - * {@link #setIncludeParentsWhenFiltering(boolean)} for more information. - * - * @return true if all parents for items that match the filter are included - * when filtering, false if only the matching items are included - */ - public boolean isIncludeParentsWhenFiltering() { - return includeParentsWhenFiltering; - } - - /** - * Controls how the filtering of the container works. Set this to true to - * make filtering include parents for all matched items in addition to the - * items themselves. Setting this to false causes the filtering to only - * include the matching items and make items with excluded parents into root - * items. - * - * @param includeParentsWhenFiltering - * true to include all parents for items that match the filter, - * false to only include the matching items - */ - public void setIncludeParentsWhenFiltering( - boolean includeParentsWhenFiltering) { - this.includeParentsWhenFiltering = includeParentsWhenFiltering; - if (filteredRoots != null) { - // Currently filtered so needs to be re-filtered - doFilterContainer(true); - } - } - - /* - * Overridden to provide filtering for root & children items. - * - * (non-Javadoc) - * - * @see com.vaadin.data.util.IndexedContainer#updateContainerFiltering() - */ - @Override - protected boolean doFilterContainer(boolean hasFilters) { - if (!hasFilters) { - // All filters removed - filteredRoots = null; - filteredChildren = null; - filteredParent = null; - - return super.doFilterContainer(hasFilters); - } - - // Reset data structures - filteredRoots = new LinkedList<Object>(); - filteredChildren = new HashMap<Object, LinkedList<Object>>(); - filteredParent = new HashMap<Object, Object>(); - - if (includeParentsWhenFiltering) { - // Filter so that parents for items that match the filter are also - // included - HashSet<Object> includedItems = new HashSet<Object>(); - for (Object rootId : roots) { - if (filterIncludingParents(rootId, includedItems)) { - filteredRoots.add(rootId); - addFilteredChildrenRecursively(rootId, includedItems); - } - } - // includedItemIds now contains all the item ids that should be - // included. Filter IndexedContainer based on this - filterOverride = includedItems; - super.doFilterContainer(hasFilters); - filterOverride = null; - - return true; - } else { - // Filter by including all items that pass the filter and make items - // with no parent new root items - - // Filter IndexedContainer first so getItemIds return the items that - // match - super.doFilterContainer(hasFilters); - - LinkedHashSet<Object> filteredItemIds = new LinkedHashSet<Object>( - getItemIds()); - - for (Object itemId : filteredItemIds) { - Object itemParent = parent.get(itemId); - if (itemParent == null || !filteredItemIds.contains(itemParent)) { - // Parent is not included or this was a root, in both cases - // this should be a filtered root - filteredRoots.add(itemId); - } else { - // Parent is included. Add this to the children list (create - // it first if necessary) - addFilteredChild(itemParent, itemId); - } - } - - return true; - } - } - - /** - * Adds the given childItemId as a filteredChildren for the parentItemId and - * sets it filteredParent. - * - * @param parentItemId - * @param childItemId - */ - private void addFilteredChild(Object parentItemId, Object childItemId) { - LinkedList<Object> parentToChildrenList = filteredChildren - .get(parentItemId); - if (parentToChildrenList == null) { - parentToChildrenList = new LinkedList<Object>(); - filteredChildren.put(parentItemId, parentToChildrenList); - } - filteredParent.put(childItemId, parentItemId); - parentToChildrenList.add(childItemId); - - } - - /** - * Recursively adds all items in the includedItems list to the - * filteredChildren map in the same order as they are in the children map. - * Starts from parentItemId and recurses down as long as child items that - * should be included are found. - * - * @param parentItemId - * The item id to start recurse from. Not added to a - * filteredChildren list - * @param includedItems - * Set containing the item ids for the items that should be - * included in the filteredChildren map - */ - private void addFilteredChildrenRecursively(Object parentItemId, - HashSet<Object> includedItems) { - LinkedList<Object> childList = children.get(parentItemId); - if (childList == null) { - return; - } - - for (Object childItemId : childList) { - if (includedItems.contains(childItemId)) { - addFilteredChild(parentItemId, childItemId); - addFilteredChildrenRecursively(childItemId, includedItems); - } - } - } - - /** - * Scans the itemId and all its children for which items should be included - * when filtering. All items which passes the filters are included. - * Additionally all items that have a child node that should be included are - * also themselves included. - * - * @param itemId - * @param includedItems - * @return true if the itemId should be included in the filtered container. - */ - private boolean filterIncludingParents(Object itemId, - HashSet<Object> includedItems) { - boolean toBeIncluded = passesFilters(itemId); - - LinkedList<Object> childList = children.get(itemId); - if (childList != null) { - for (Object childItemId : children.get(itemId)) { - toBeIncluded |= filterIncludingParents(childItemId, - includedItems); - } - } - - if (toBeIncluded) { - includedItems.add(itemId); - } - return toBeIncluded; - } - - private Set<Object> filterOverride = null; - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.IndexedContainer#passesFilters(java.lang.Object) - */ - @Override - protected boolean passesFilters(Object itemId) { - if (filterOverride != null) { - return filterOverride.contains(itemId); - } else { - return super.passesFilters(itemId); - } - } -} diff --git a/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapper.java b/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapper.java deleted file mode 100644 index 172dc0dd4f..0000000000 --- a/src/com/vaadin/data/util/HierarchicalContainerOrderedWrapper.java +++ /dev/null @@ -1,70 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.util.Collection; - -import com.vaadin.data.Container.Hierarchical; - -/** - * A wrapper class for adding external ordering to containers not implementing - * the {@link com.vaadin.data.Container.Ordered} interface while retaining - * {@link Hierarchical} features. - * - * @see ContainerOrderedWrapper - */ -@SuppressWarnings({ "serial" }) -public class HierarchicalContainerOrderedWrapper extends - ContainerOrderedWrapper implements Hierarchical { - - private Hierarchical hierarchical; - - public HierarchicalContainerOrderedWrapper(Hierarchical toBeWrapped) { - super(toBeWrapped); - hierarchical = toBeWrapped; - } - - @Override - public boolean areChildrenAllowed(Object itemId) { - return hierarchical.areChildrenAllowed(itemId); - } - - @Override - public Collection<?> getChildren(Object itemId) { - return hierarchical.getChildren(itemId); - } - - @Override - public Object getParent(Object itemId) { - return hierarchical.getParent(itemId); - } - - @Override - public boolean hasChildren(Object itemId) { - return hierarchical.hasChildren(itemId); - } - - @Override - public boolean isRoot(Object itemId) { - return hierarchical.isRoot(itemId); - } - - @Override - public Collection<?> rootItemIds() { - return hierarchical.rootItemIds(); - } - - @Override - public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) - throws UnsupportedOperationException { - return hierarchical.setChildrenAllowed(itemId, areChildrenAllowed); - } - - @Override - public boolean setParent(Object itemId, Object newParentId) - throws UnsupportedOperationException { - return hierarchical.setParent(itemId, newParentId); - } - -} diff --git a/src/com/vaadin/data/util/IndexedContainer.java b/src/com/vaadin/data/util/IndexedContainer.java deleted file mode 100644 index b95b2c4de8..0000000000 --- a/src/com/vaadin/data/util/IndexedContainer.java +++ /dev/null @@ -1,1109 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EventObject; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.data.util.filter.SimpleStringFilter; -import com.vaadin.data.util.filter.UnsupportedFilterException; - -/** - * An implementation of the <code>{@link Container.Indexed}</code> interface - * with all important features.</p> - * - * Features: - * <ul> - * <li> {@link Container.Indexed} - * <li> {@link Container.Ordered} - * <li> {@link Container.Sortable} - * <li> {@link Container.Filterable} - * <li> {@link Cloneable} (deprecated, might be removed in the future) - * <li>Sends all needed events on content changes. - * </ul> - * - * @see com.vaadin.data.Container - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - -@SuppressWarnings("serial") -// item type is really IndexedContainerItem, but using Item not to show it in -// public API -public class IndexedContainer extends - AbstractInMemoryContainer<Object, Object, Item> implements - Container.PropertySetChangeNotifier, Property.ValueChangeNotifier, - Container.Sortable, Cloneable, Container.Filterable, - Container.SimpleFilterable { - - /* Internal structure */ - - /** - * Linked list of ordered Property IDs. - */ - private ArrayList<Object> propertyIds = new ArrayList<Object>(); - - /** - * Property ID to type mapping. - */ - private Hashtable<Object, Class<?>> types = new Hashtable<Object, Class<?>>(); - - /** - * Hash of Items, where each Item is implemented as a mapping from Property - * ID to Property value. - */ - private Hashtable<Object, Map<Object, Object>> items = new Hashtable<Object, Map<Object, Object>>(); - - /** - * Set of properties that are read-only. - */ - private HashSet<Property<?>> readOnlyProperties = new HashSet<Property<?>>(); - - /** - * List of all Property value change event listeners listening all the - * properties. - */ - private LinkedList<Property.ValueChangeListener> propertyValueChangeListeners = null; - - /** - * Data structure containing all listeners interested in changes to single - * Properties. The data structure is a hashtable mapping Property IDs to a - * hashtable that maps Item IDs to a linked list of listeners listening - * Property identified by given Property ID and Item ID. - */ - private Hashtable<Object, Map<Object, List<Property.ValueChangeListener>>> singlePropertyValueChangeListeners = null; - - private HashMap<Object, Object> defaultPropertyValues; - - private int nextGeneratedItemId = 1; - - /* Container constructors */ - - public IndexedContainer() { - super(); - } - - public IndexedContainer(Collection<?> itemIds) { - this(); - if (items != null) { - for (final Iterator<?> i = itemIds.iterator(); i.hasNext();) { - Object itemId = i.next(); - internalAddItemAtEnd(itemId, new IndexedContainerItem(itemId), - false); - } - filterAll(); - } - } - - /* Container methods */ - - @Override - protected Item getUnfilteredItem(Object itemId) { - if (itemId != null && items.containsKey(itemId)) { - return new IndexedContainerItem(itemId); - } - return null; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getContainerPropertyIds() - */ - @Override - public Collection<?> getContainerPropertyIds() { - return Collections.unmodifiableCollection(propertyIds); - } - - /** - * Gets the type of a Property stored in the list. - * - * @param id - * the ID of the Property. - * @return Type of the requested Property - */ - @Override - public Class<?> getType(Object propertyId) { - return types.get(propertyId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getContainerProperty(java.lang.Object, - * java.lang.Object) - */ - @Override - public Property<?> getContainerProperty(Object itemId, Object propertyId) { - if (!containsId(itemId)) { - return null; - } - - return new IndexedContainerProperty(itemId, propertyId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addContainerProperty(java.lang.Object, - * java.lang.Class, java.lang.Object) - */ - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) { - - // Fails, if nulls are given - if (propertyId == null || type == null) { - return false; - } - - // Fails if the Property is already present - if (propertyIds.contains(propertyId)) { - return false; - } - - // Adds the Property to Property list and types - propertyIds.add(propertyId); - types.put(propertyId, type); - - // If default value is given, set it - if (defaultValue != null) { - // for existing rows - for (final Iterator<?> i = getAllItemIds().iterator(); i.hasNext();) { - getItem(i.next()).getItemProperty(propertyId).setValue( - defaultValue); - } - // store for next rows - if (defaultPropertyValues == null) { - defaultPropertyValues = new HashMap<Object, Object>(); - } - defaultPropertyValues.put(propertyId, defaultValue); - } - - // Sends a change event - fireContainerPropertySetChange(); - - return true; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeAllItems() - */ - @Override - public boolean removeAllItems() { - int origSize = size(); - - internalRemoveAllItems(); - - items.clear(); - - // fire event only if the visible view changed, regardless of whether - // filtered out items were removed or not - if (origSize != 0) { - // Sends a change event - fireItemSetChange(); - } - - return true; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addItem() - */ - @Override - public Object addItem() { - - // Creates a new id - final Object id = generateId(); - - // Adds the Item into container - addItem(id); - - return id; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addItem(java.lang.Object) - */ - @Override - public Item addItem(Object itemId) { - Item item = internalAddItemAtEnd(itemId, new IndexedContainerItem( - itemId), false); - if (!isFiltered()) { - // always the last item - fireItemAdded(size() - 1, itemId, item); - } else if (passesFilters(itemId) && !containsId(itemId)) { - getFilteredItemIds().add(itemId); - // always the last item - fireItemAdded(size() - 1, itemId, item); - } - return item; - } - - /** - * Helper method to add default values for items if available - * - * @param t - * data table of added item - */ - private void addDefaultValues(Hashtable<Object, Object> t) { - if (defaultPropertyValues != null) { - for (Object key : defaultPropertyValues.keySet()) { - t.put(key, defaultPropertyValues.get(key)); - } - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeItem(java.lang.Object) - */ - @Override - public boolean removeItem(Object itemId) { - if (itemId == null || items.remove(itemId) == null) { - return false; - } - int origSize = size(); - int position = indexOfId(itemId); - if (internalRemoveItem(itemId)) { - // fire event only if the visible view changed, regardless of - // whether filtered out items were removed or not - if (size() != origSize) { - fireItemRemoved(position, itemId); - } - - return true; - } else { - return false; - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeContainerProperty(java.lang.Object ) - */ - @Override - public boolean removeContainerProperty(Object propertyId) { - - // Fails if the Property is not present - if (!propertyIds.contains(propertyId)) { - return false; - } - - // Removes the Property to Property list and types - propertyIds.remove(propertyId); - types.remove(propertyId); - if (defaultPropertyValues != null) { - defaultPropertyValues.remove(propertyId); - } - - // If remove the Property from all Items - for (final Iterator<Object> i = getAllItemIds().iterator(); i.hasNext();) { - items.get(i.next()).remove(propertyId); - } - - // Sends a change event - fireContainerPropertySetChange(); - - return true; - } - - /* Container.Ordered methods */ - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object, - * java.lang.Object) - */ - @Override - public Item addItemAfter(Object previousItemId, Object newItemId) { - return internalAddItemAfter(previousItemId, newItemId, - new IndexedContainerItem(newItemId), true); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object) - */ - @Override - public Object addItemAfter(Object previousItemId) { - - // Creates a new id - final Object id = generateId(); - - if (addItemAfter(previousItemId, id) != null) { - return id; - } else { - return null; - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Indexed#addItemAt(int, java.lang.Object) - */ - @Override - public Item addItemAt(int index, Object newItemId) { - return internalAddItemAt(index, newItemId, new IndexedContainerItem( - newItemId), true); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Indexed#addItemAt(int) - */ - @Override - public Object addItemAt(int index) { - - // Creates a new id - final Object id = generateId(); - - // Adds the Item into container - addItemAt(index, id); - - return id; - } - - /** - * Generates an unique identifier for use as an item id. Guarantees that the - * generated id is not currently used as an id. - * - * @return - */ - private Serializable generateId() { - Serializable id; - do { - id = Integer.valueOf(nextGeneratedItemId++); - } while (items.containsKey(id)); - - return id; - } - - @Override - protected void registerNewItem(int index, Object newItemId, Item item) { - Hashtable<Object, Object> t = new Hashtable<Object, Object>(); - items.put(newItemId, t); - addDefaultValues(t); - } - - /* Event notifiers */ - - /** - * An <code>event</code> object specifying the list whose Item set has - * changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class ItemSetChangeEvent extends BaseItemSetChangeEvent { - - private final int addedItemIndex; - - private ItemSetChangeEvent(IndexedContainer source, int addedItemIndex) { - super(source); - this.addedItemIndex = addedItemIndex; - } - - /** - * Iff one item is added, gives its index. - * - * @return -1 if either multiple items are changed or some other change - * than add is done. - */ - public int getAddedItemIndex() { - return addedItemIndex; - } - - } - - /** - * An <code>event</code> object specifying the Property in a list whose - * value has changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - private static class PropertyValueChangeEvent extends EventObject implements - Property.ValueChangeEvent, Serializable { - - private PropertyValueChangeEvent(Property source) { - super(source); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property.ValueChangeEvent#getProperty() - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - - } - - @Override - public void addListener(Container.PropertySetChangeListener listener) { - super.addListener(listener); - } - - @Override - public void removeListener(Container.PropertySetChangeListener listener) { - super.removeListener(listener); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property.ValueChangeNotifier#addListener(com. - * vaadin.data.Property.ValueChangeListener) - */ - @Override - public void addListener(Property.ValueChangeListener listener) { - if (propertyValueChangeListeners == null) { - propertyValueChangeListeners = new LinkedList<Property.ValueChangeListener>(); - } - propertyValueChangeListeners.add(listener); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property.ValueChangeNotifier#removeListener(com - * .vaadin.data.Property.ValueChangeListener) - */ - @Override - public void removeListener(Property.ValueChangeListener listener) { - if (propertyValueChangeListeners != null) { - propertyValueChangeListeners.remove(listener); - } - } - - /** - * Sends a Property value change event to all interested listeners. - * - * @param source - * the IndexedContainerProperty object. - */ - private void firePropertyValueChange(IndexedContainerProperty source) { - - // Sends event to listeners listening all value changes - if (propertyValueChangeListeners != null) { - final Object[] l = propertyValueChangeListeners.toArray(); - final Property.ValueChangeEvent event = new IndexedContainer.PropertyValueChangeEvent( - source); - for (int i = 0; i < l.length; i++) { - ((Property.ValueChangeListener) l[i]).valueChange(event); - } - } - - // Sends event to single property value change listeners - if (singlePropertyValueChangeListeners != null) { - final Map<Object, List<Property.ValueChangeListener>> propertySetToListenerListMap = singlePropertyValueChangeListeners - .get(source.propertyId); - if (propertySetToListenerListMap != null) { - final List<Property.ValueChangeListener> listenerList = propertySetToListenerListMap - .get(source.itemId); - if (listenerList != null) { - final Property.ValueChangeEvent event = new IndexedContainer.PropertyValueChangeEvent( - source); - Object[] listeners = listenerList.toArray(); - for (int i = 0; i < listeners.length; i++) { - ((Property.ValueChangeListener) listeners[i]) - .valueChange(event); - } - } - } - } - - } - - @Override - public Collection<?> getListeners(Class<?> eventType) { - if (Property.ValueChangeEvent.class.isAssignableFrom(eventType)) { - if (propertyValueChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(propertyValueChangeListeners); - } - } - return super.getListeners(eventType); - } - - @Override - protected void fireItemAdded(int position, Object itemId, Item item) { - if (position >= 0) { - fireItemSetChange(new IndexedContainer.ItemSetChangeEvent(this, - position)); - } - } - - @Override - protected void fireItemSetChange() { - fireItemSetChange(new IndexedContainer.ItemSetChangeEvent(this, -1)); - } - - /** - * Adds new single Property change listener. - * - * @param propertyId - * the ID of the Property to add. - * @param itemId - * the ID of the Item . - * @param listener - * the listener to be added. - */ - private void addSinglePropertyChangeListener(Object propertyId, - Object itemId, Property.ValueChangeListener listener) { - if (listener != null) { - if (singlePropertyValueChangeListeners == null) { - singlePropertyValueChangeListeners = new Hashtable<Object, Map<Object, List<Property.ValueChangeListener>>>(); - } - Map<Object, List<Property.ValueChangeListener>> propertySetToListenerListMap = singlePropertyValueChangeListeners - .get(propertyId); - if (propertySetToListenerListMap == null) { - propertySetToListenerListMap = new Hashtable<Object, List<Property.ValueChangeListener>>(); - singlePropertyValueChangeListeners.put(propertyId, - propertySetToListenerListMap); - } - List<Property.ValueChangeListener> listenerList = propertySetToListenerListMap - .get(itemId); - if (listenerList == null) { - listenerList = new LinkedList<Property.ValueChangeListener>(); - propertySetToListenerListMap.put(itemId, listenerList); - } - listenerList.add(listener); - } - } - - /** - * Removes a previously registered single Property change listener. - * - * @param propertyId - * the ID of the Property to remove. - * @param itemId - * the ID of the Item. - * @param listener - * the listener to be removed. - */ - private void removeSinglePropertyChangeListener(Object propertyId, - Object itemId, Property.ValueChangeListener listener) { - if (listener != null && singlePropertyValueChangeListeners != null) { - final Map<Object, List<Property.ValueChangeListener>> propertySetToListenerListMap = singlePropertyValueChangeListeners - .get(propertyId); - if (propertySetToListenerListMap != null) { - final List<Property.ValueChangeListener> listenerList = propertySetToListenerListMap - .get(itemId); - if (listenerList != null) { - listenerList.remove(listener); - if (listenerList.isEmpty()) { - propertySetToListenerListMap.remove(itemId); - } - } - if (propertySetToListenerListMap.isEmpty()) { - singlePropertyValueChangeListeners.remove(propertyId); - } - } - if (singlePropertyValueChangeListeners.isEmpty()) { - singlePropertyValueChangeListeners = null; - } - } - } - - /* Internal Item and Property implementations */ - - /* - * A class implementing the com.vaadin.data.Item interface to be contained - * in the list. - * - * @author Vaadin Ltd. - * - * @version @VERSION@ - * - * @since 3.0 - */ - class IndexedContainerItem implements Item { - - /** - * Item ID in the host container for this Item. - */ - private final Object itemId; - - /** - * Constructs a new ListItem instance and connects it to a host - * container. - * - * @param itemId - * the Item ID of the new Item. - */ - private IndexedContainerItem(Object itemId) { - - // Gets the item contents from the host - if (itemId == null) { - throw new NullPointerException(); - } - this.itemId = itemId; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Item#getItemProperty(java.lang.Object) - */ - @Override - public Property<?> getItemProperty(Object id) { - return new IndexedContainerProperty(itemId, id); - } - - @Override - public Collection<?> getItemPropertyIds() { - return Collections.unmodifiableCollection(propertyIds); - } - - /** - * Gets the <code>String</code> representation of the contents of the - * Item. The format of the string is a space separated catenation of the - * <code>String</code> representations of the values of the Properties - * contained by the Item. - * - * @return <code>String</code> representation of the Item contents - */ - @Override - public String toString() { - String retValue = ""; - - for (final Iterator<?> i = propertyIds.iterator(); i.hasNext();) { - final Object propertyId = i.next(); - retValue += getItemProperty(propertyId).getValue(); - if (i.hasNext()) { - retValue += " "; - } - } - - return retValue; - } - - /** - * Calculates a integer hash-code for the Item that's unique inside the - * list. Two Items inside the same list have always different - * hash-codes, though Items in different lists may have identical - * hash-codes. - * - * @return A locally unique hash-code as integer - */ - @Override - public int hashCode() { - return itemId.hashCode(); - } - - /** - * Tests if the given object is the same as the this object. Two Items - * got from a list container with the same ID are equal. - * - * @param obj - * an object to compare with this object - * @return <code>true</code> if the given object is the same as this - * object, <code>false</code> if not - */ - @Override - public boolean equals(Object obj) { - if (obj == null - || !obj.getClass().equals(IndexedContainerItem.class)) { - return false; - } - final IndexedContainerItem li = (IndexedContainerItem) obj; - return getHost() == li.getHost() && itemId.equals(li.itemId); - } - - private IndexedContainer getHost() { - return IndexedContainer.this; - } - - /** - * IndexedContainerItem does not support adding new properties. Add - * properties at container level. See - * {@link IndexedContainer#addContainerProperty(Object, Class, Object)} - * - * @see com.vaadin.data.Item#addProperty(Object, Property) - */ - @Override - public boolean addItemProperty(Object id, Property property) - throws UnsupportedOperationException { - throw new UnsupportedOperationException("Indexed container item " - + "does not support adding new properties"); - } - - /** - * Indexed container does not support removing properties. Remove - * properties at container level. See - * {@link IndexedContainer#removeContainerProperty(Object)} - * - * @see com.vaadin.data.Item#removeProperty(Object) - */ - @Override - public boolean removeItemProperty(Object id) - throws UnsupportedOperationException { - throw new UnsupportedOperationException( - "Indexed container item does not support property removal"); - } - - } - - /** - * A class implementing the {@link Property} interface to be contained in - * the {@link IndexedContainerItem} contained in the - * {@link IndexedContainer}. - * - * @author Vaadin Ltd. - * - * @version - * @VERSION@ - * @since 3.0 - */ - private class IndexedContainerProperty implements Property<Object>, - Property.ValueChangeNotifier { - - /** - * ID of the Item, where this property resides. - */ - private final Object itemId; - - /** - * Id of the Property. - */ - private final Object propertyId; - - /** - * Constructs a new {@link IndexedContainerProperty} object. - * - * @param itemId - * the ID of the Item to connect the new Property to. - * @param propertyId - * the Property ID of the new Property. - * @param host - * the list that contains the Item to contain the new - * Property. - */ - private IndexedContainerProperty(Object itemId, Object propertyId) { - if (itemId == null || propertyId == null) { - // Null ids are not accepted - throw new NullPointerException( - "Container item or property ids can not be null"); - } - this.propertyId = propertyId; - this.itemId = itemId; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getType() - */ - @Override - public Class<?> getType() { - return types.get(propertyId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getValue() - */ - @Override - public Object getValue() { - return items.get(itemId).get(propertyId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#isReadOnly() - */ - @Override - public boolean isReadOnly() { - return readOnlyProperties.contains(this); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#setReadOnly(boolean) - */ - @Override - public void setReadOnly(boolean newStatus) { - if (newStatus) { - readOnlyProperties.add(this); - } else { - readOnlyProperties.remove(this); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#setValue(java.lang.Object) - */ - @Override - public void setValue(Object newValue) throws Property.ReadOnlyException { - // Gets the Property set - final Map<Object, Object> propertySet = items.get(itemId); - - // Support null values on all types - if (newValue == null) { - propertySet.remove(propertyId); - } else if (getType().isAssignableFrom(newValue.getClass())) { - propertySet.put(propertyId, newValue); - } else { - throw new IllegalArgumentException( - "Value is of invalid type, got " - + newValue.getClass().getName() + " but " - + getType().getName() + " was expected"); - } - - // update the container filtering if this property is being filtered - if (isPropertyFiltered(propertyId)) { - filterAll(); - } - - firePropertyValueChange(this); - } - - /** - * Returns the value of the Property in human readable textual format. - * The return value should be assignable to the <code>setValue</code> - * method if the Property is not in read-only mode. - * - * @return <code>String</code> representation of the value stored in the - * Property - * @deprecated use {@link #getValue()} instead and possibly toString on - * that - */ - @Deprecated - @Override - public String toString() { - throw new UnsupportedOperationException( - "Use Property.getValue() instead of IndexedContainerProperty.toString()"); - } - - /** - * Calculates a integer hash-code for the Property that's unique inside - * the Item containing the Property. Two different Properties inside the - * same Item contained in the same list always have different - * hash-codes, though Properties in different Items may have identical - * hash-codes. - * - * @return A locally unique hash-code as integer - */ - @Override - public int hashCode() { - return itemId.hashCode() ^ propertyId.hashCode(); - } - - /** - * Tests if the given object is the same as the this object. Two - * Properties got from an Item with the same ID are equal. - * - * @param obj - * an object to compare with this object - * @return <code>true</code> if the given object is the same as this - * object, <code>false</code> if not - */ - @Override - public boolean equals(Object obj) { - if (obj == null - || !obj.getClass().equals(IndexedContainerProperty.class)) { - return false; - } - final IndexedContainerProperty lp = (IndexedContainerProperty) obj; - return lp.getHost() == getHost() - && lp.propertyId.equals(propertyId) - && lp.itemId.equals(itemId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property.ValueChangeNotifier#addListener( - * com.vaadin.data.Property.ValueChangeListener) - */ - @Override - public void addListener(Property.ValueChangeListener listener) { - addSinglePropertyChangeListener(propertyId, itemId, listener); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property.ValueChangeNotifier#removeListener - * (com.vaadin.data.Property.ValueChangeListener) - */ - @Override - public void removeListener(Property.ValueChangeListener listener) { - removeSinglePropertyChangeListener(propertyId, itemId, listener); - } - - private IndexedContainer getHost() { - return IndexedContainer.this; - } - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Sortable#sort(java.lang.Object[], - * boolean[]) - */ - @Override - public void sort(Object[] propertyId, boolean[] ascending) { - sortContainer(propertyId, ascending); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Sortable#getSortableContainerPropertyIds - * () - */ - @Override - public Collection<?> getSortableContainerPropertyIds() { - return getSortablePropertyIds(); - } - - @Override - public ItemSorter getItemSorter() { - return super.getItemSorter(); - } - - @Override - public void setItemSorter(ItemSorter itemSorter) { - super.setItemSorter(itemSorter); - } - - /** - * Supports cloning of the IndexedContainer cleanly. - * - * @throws CloneNotSupportedException - * if an object cannot be cloned. . - * - * @deprecated cloning support might be removed from IndexedContainer in the - * future - */ - @Deprecated - @Override - public Object clone() throws CloneNotSupportedException { - - // Creates the clone - final IndexedContainer nc = new IndexedContainer(); - - // Clone the shallow properties - nc.setAllItemIds(getAllItemIds() != null ? (ListSet<Object>) ((ListSet<Object>) getAllItemIds()) - .clone() : null); - nc.setItemSetChangeListeners(getItemSetChangeListeners() != null ? new LinkedList<Container.ItemSetChangeListener>( - getItemSetChangeListeners()) : null); - nc.propertyIds = propertyIds != null ? (ArrayList<Object>) propertyIds - .clone() : null; - nc.setPropertySetChangeListeners(getPropertySetChangeListeners() != null ? new LinkedList<Container.PropertySetChangeListener>( - getPropertySetChangeListeners()) : null); - nc.propertyValueChangeListeners = propertyValueChangeListeners != null ? (LinkedList<Property.ValueChangeListener>) propertyValueChangeListeners - .clone() : null; - nc.readOnlyProperties = readOnlyProperties != null ? (HashSet<Property<?>>) readOnlyProperties - .clone() : null; - nc.singlePropertyValueChangeListeners = singlePropertyValueChangeListeners != null ? (Hashtable<Object, Map<Object, List<Property.ValueChangeListener>>>) singlePropertyValueChangeListeners - .clone() : null; - - nc.types = types != null ? (Hashtable<Object, Class<?>>) types.clone() - : null; - - nc.setFilters((HashSet<Filter>) ((HashSet<Filter>) getFilters()) - .clone()); - - nc.setFilteredItemIds(getFilteredItemIds() == null ? null - : (ListSet<Object>) ((ListSet<Object>) getFilteredItemIds()) - .clone()); - - // Clone property-values - if (items == null) { - nc.items = null; - } else { - nc.items = new Hashtable<Object, Map<Object, Object>>(); - for (final Iterator<?> i = items.keySet().iterator(); i.hasNext();) { - final Object id = i.next(); - final Hashtable<Object, Object> it = (Hashtable<Object, Object>) items - .get(id); - nc.items.put(id, (Map<Object, Object>) it.clone()); - } - } - - return nc; - } - - @Override - public void addContainerFilter(Object propertyId, String filterString, - boolean ignoreCase, boolean onlyMatchPrefix) { - try { - addFilter(new SimpleStringFilter(propertyId, filterString, - ignoreCase, onlyMatchPrefix)); - } catch (UnsupportedFilterException e) { - // the filter instance created here is always valid for in-memory - // containers - } - } - - @Override - public void removeAllContainerFilters() { - removeAllFilters(); - } - - @Override - public void removeContainerFilters(Object propertyId) { - removeFilters(propertyId); - } - - @Override - public void addContainerFilter(Filter filter) - throws UnsupportedFilterException { - addFilter(filter); - } - - @Override - public void removeContainerFilter(Filter filter) { - removeFilter(filter); - } - -} diff --git a/src/com/vaadin/data/util/ItemSorter.java b/src/com/vaadin/data/util/ItemSorter.java deleted file mode 100644 index 4399dbe292..0000000000 --- a/src/com/vaadin/data/util/ItemSorter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.io.Serializable; -import java.util.Comparator; - -import com.vaadin.data.Container; -import com.vaadin.data.Container.Sortable; - -/** - * An item comparator which is compatible with the {@link Sortable} interface. - * The <code>ItemSorter</code> interface can be used in <code>Sortable</code> - * implementations to provide a custom sorting method. - */ -public interface ItemSorter extends Comparator<Object>, Cloneable, Serializable { - - /** - * Sets the parameters for an upcoming sort operation. The parameters - * determine what container to sort and how the <code>ItemSorter</code> - * sorts the container. - * - * @param container - * The container that will be sorted. The container must contain - * the propertyIds given in the <code>propertyId</code> - * parameter. - * @param propertyId - * The property ids used for sorting. The property ids must exist - * in the container and should only be used if they are also - * sortable, i.e include in the collection returned by - * <code>container.getSortableContainerPropertyIds()</code>. See - * {@link Sortable#sort(Object[], boolean[])} for more - * information. - * @param ascending - * Sorting order flags for each property id. See - * {@link Sortable#sort(Object[], boolean[])} for more - * information. - */ - void setSortProperties(Container.Sortable container, Object[] propertyId, - boolean[] ascending); - - /** - * Compares its two arguments for order. Returns a negative integer, zero, - * or a positive integer as the first argument is less than, equal to, or - * greater than the second. - * <p> - * The parameters for the <code>ItemSorter</code> <code>compare()</code> - * method must always be item ids which exist in the container set using - * {@link #setSortProperties(Sortable, Object[], boolean[])}. - * - * @see Comparator#compare(Object, Object) - */ - @Override - int compare(Object itemId1, Object itemId2); - -} diff --git a/src/com/vaadin/data/util/ListSet.java b/src/com/vaadin/data/util/ListSet.java deleted file mode 100644 index b71cc46898..0000000000 --- a/src/com/vaadin/data/util/ListSet.java +++ /dev/null @@ -1,264 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; - -/** - * ListSet is an internal Vaadin class which implements a combination of a List - * and a Set. The main purpose of this class is to provide a list with a fast - * {@link #contains(Object)} method. Each inserted object must by unique (as - * specified by {@link #equals(Object)}). The {@link #set(int, Object)} method - * allows duplicates because of the way {@link Collections#sort(java.util.List)} - * works. - * - * This class is subject to change and should not be used outside Vaadin core. - */ -public class ListSet<E> extends ArrayList<E> { - private HashSet<E> itemSet = null; - - /** - * Contains a map from an element to the number of duplicates it has. Used - * to temporarily allow duplicates in the list. - */ - private HashMap<E, Integer> duplicates = new HashMap<E, Integer>(); - - public ListSet() { - super(); - itemSet = new HashSet<E>(); - } - - public ListSet(Collection<? extends E> c) { - super(c); - itemSet = new HashSet<E>(c.size()); - itemSet.addAll(c); - } - - public ListSet(int initialCapacity) { - super(initialCapacity); - itemSet = new HashSet<E>(initialCapacity); - } - - // Delegate contains operations to the set - @Override - public boolean contains(Object o) { - return itemSet.contains(o); - } - - @Override - public boolean containsAll(Collection<?> c) { - return itemSet.containsAll(c); - } - - // Methods for updating the set when the list is updated. - @Override - public boolean add(E e) { - if (contains(e)) { - // Duplicates are not allowed - return false; - } - - if (super.add(e)) { - itemSet.add(e); - return true; - } else { - return false; - } - }; - - /** - * Works as java.util.ArrayList#add(int, java.lang.Object) but returns - * immediately if the element is already in the ListSet. - */ - @Override - public void add(int index, E element) { - if (contains(element)) { - // Duplicates are not allowed - return; - } - - super.add(index, element); - itemSet.add(element); - } - - @Override - public boolean addAll(Collection<? extends E> c) { - boolean modified = false; - Iterator<? extends E> i = c.iterator(); - while (i.hasNext()) { - E e = i.next(); - if (contains(e)) { - continue; - } - - if (add(e)) { - itemSet.add(e); - modified = true; - } - } - return modified; - } - - @Override - public boolean addAll(int index, Collection<? extends E> c) { - ensureCapacity(size() + c.size()); - - boolean modified = false; - Iterator<? extends E> i = c.iterator(); - while (i.hasNext()) { - E e = i.next(); - if (contains(e)) { - continue; - } - - add(index++, e); - itemSet.add(e); - modified = true; - } - - return modified; - } - - @Override - public void clear() { - super.clear(); - itemSet.clear(); - } - - @Override - public int indexOf(Object o) { - if (!contains(o)) { - return -1; - } - - return super.indexOf(o); - } - - @Override - public int lastIndexOf(Object o) { - if (!contains(o)) { - return -1; - } - - return super.lastIndexOf(o); - } - - @Override - public E remove(int index) { - E e = super.remove(index); - - if (e != null) { - itemSet.remove(e); - } - - return e; - } - - @Override - public boolean remove(Object o) { - if (super.remove(o)) { - itemSet.remove(o); - return true; - } else { - return false; - } - } - - @Override - protected void removeRange(int fromIndex, int toIndex) { - HashSet<E> toRemove = new HashSet<E>(); - for (int idx = fromIndex; idx < toIndex; idx++) { - toRemove.add(get(idx)); - } - super.removeRange(fromIndex, toIndex); - itemSet.removeAll(toRemove); - } - - @Override - public E set(int index, E element) { - if (contains(element)) { - // Element already exist in the list - if (get(index) == element) { - // At the same position, nothing to be done - return element; - } else { - // Adding at another position. We assume this is a sort - // operation and temporarily allow it. - - // We could just remove (null) the old element and keep the list - // unique. This would require finding the index of the old - // element (indexOf(element)) which is not a fast operation in a - // list. So we instead allow duplicates temporarily. - addDuplicate(element); - } - } - - E old = super.set(index, element); - removeFromSet(old); - itemSet.add(element); - - return old; - } - - /** - * Removes "e" from the set if it no longer exists in the list. - * - * @param e - */ - private void removeFromSet(E e) { - Integer dupl = duplicates.get(e); - if (dupl != null) { - // A duplicate was present so we only decrement the duplicate count - // and continue - if (dupl == 1) { - // This is what always should happen. A sort sets the items one - // by one, temporarily breaking the uniqueness requirement. - duplicates.remove(e); - } else { - duplicates.put(e, dupl - 1); - } - } else { - // The "old" value is no longer in the list. - itemSet.remove(e); - } - - } - - /** - * Marks the "element" can be found more than once from the list. Allowed in - * {@link #set(int, Object)} to make sorting work. - * - * @param element - */ - private void addDuplicate(E element) { - Integer nr = duplicates.get(element); - if (nr == null) { - nr = 1; - } else { - nr++; - } - - /* - * Store the number of duplicates of this element so we know later on if - * we should remove an element from the set or if it was a duplicate (in - * removeFromSet) - */ - duplicates.put(element, nr); - - } - - @SuppressWarnings("unchecked") - @Override - public Object clone() { - ListSet<E> v = (ListSet<E>) super.clone(); - v.itemSet = new HashSet<E>(itemSet); - return v; - } - -} diff --git a/src/com/vaadin/data/util/MethodProperty.java b/src/com/vaadin/data/util/MethodProperty.java deleted file mode 100644 index 0c64d90481..0000000000 --- a/src/com/vaadin/data/util/MethodProperty.java +++ /dev/null @@ -1,784 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.data.Property; -import com.vaadin.util.SerializerHelper; - -/** - * <p> - * Proxy class for creating Properties from pairs of getter and setter methods - * of a Bean property. An instance of this class can be thought as having been - * attached to a field of an object. Accessing the object through the Property - * interface directly manipulates the underlying field. - * </p> - * - * <p> - * It's assumed that the return value returned by the getter method is - * assignable to the type of the property, and the setter method parameter is - * assignable to that value. - * </p> - * - * <p> - * A valid getter method must always be available, but instance of this class - * can be constructed with a <code>null</code> setter method in which case the - * resulting MethodProperty is read-only. - * </p> - * - * <p> - * MethodProperty implements Property.ValueChangeNotifier, but does not - * automatically know whether or not the getter method will actually return a - * new value - value change listeners are always notified when setValue is - * called, without verifying what the getter returns. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class MethodProperty<T> extends AbstractProperty<T> { - - /** - * The object that includes the property the MethodProperty is bound to. - */ - private transient Object instance; - - /** - * Argument arrays for the getter and setter methods. - */ - private transient Object[] setArgs, getArgs; - - /** - * The getter and setter methods. - */ - private transient Method setMethod, getMethod; - - /** - * Index of the new value in the argument list for the setter method. If the - * setter method requires several parameters, this index tells which one is - * the actual value to change. - */ - private int setArgumentIndex; - - /** - * Type of the property. - */ - private transient Class<? extends T> type; - - /* Special serialization to handle method references */ - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - SerializerHelper.writeClass(out, type); - out.writeObject(instance); - out.writeObject(setArgs); - out.writeObject(getArgs); - if (setMethod != null) { - out.writeObject(setMethod.getName()); - SerializerHelper - .writeClassArray(out, setMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - } - if (getMethod != null) { - out.writeObject(getMethod.getName()); - SerializerHelper - .writeClassArray(out, getMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - } - }; - - /* Special serialization to handle method references */ - private void readObject(java.io.ObjectInputStream in) throws IOException, - ClassNotFoundException { - in.defaultReadObject(); - try { - @SuppressWarnings("unchecked") - // business assumption; type parameters not checked at runtime - Class<T> class1 = (Class<T>) SerializerHelper.readClass(in); - type = class1; - instance = in.readObject(); - setArgs = (Object[]) in.readObject(); - getArgs = (Object[]) in.readObject(); - String name = (String) in.readObject(); - Class<?>[] paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { - setMethod = instance.getClass().getMethod(name, paramTypes); - } else { - setMethod = null; - } - - name = (String) in.readObject(); - paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { - getMethod = instance.getClass().getMethod(name, paramTypes); - } else { - getMethod = null; - } - } catch (SecurityException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } catch (NoSuchMethodException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } - }; - - /** - * <p> - * Creates a new instance of <code>MethodProperty</code> from a named bean - * property. This constructor takes an object and the name of a bean - * property and initializes itself with the accessor methods for the - * property. - * </p> - * <p> - * The getter method of a <code>MethodProperty</code> instantiated with this - * constructor will be called with no arguments, and the setter method with - * only the new value as the sole argument. - * </p> - * - * <p> - * If the setter method is unavailable, the resulting - * <code>MethodProperty</code> will be read-only, otherwise it will be - * read-write. - * </p> - * - * <p> - * Method names are constructed from the bean property by adding - * get/is/are/set prefix and capitalising the first character in the name of - * the given bean property. - * </p> - * - * @param instance - * the object that includes the property. - * @param beanPropertyName - * the name of the property to bind to. - */ - @SuppressWarnings("unchecked") - public MethodProperty(Object instance, String beanPropertyName) { - - final Class<?> beanClass = instance.getClass(); - - // Assure that the first letter is upper cased (it is a common - // mistake to write firstName, not FirstName). - if (Character.isLowerCase(beanPropertyName.charAt(0))) { - final char[] buf = beanPropertyName.toCharArray(); - buf[0] = Character.toUpperCase(buf[0]); - beanPropertyName = new String(buf); - } - - // Find the get method - getMethod = null; - try { - getMethod = initGetterMethod(beanPropertyName, beanClass); - } catch (final java.lang.NoSuchMethodException ignored) { - throw new MethodException(this, "Bean property " + beanPropertyName - + " can not be found"); - } - - // In case the get method is found, resolve the type - Class<?> returnType = getMethod.getReturnType(); - - // Finds the set method - setMethod = null; - try { - setMethod = beanClass.getMethod("set" + beanPropertyName, - new Class[] { returnType }); - } catch (final java.lang.NoSuchMethodException skipped) { - } - - // Gets the return type from get method - if (returnType.isPrimitive()) { - type = (Class<T>) convertPrimitiveType(returnType); - if (type.isPrimitive()) { - throw new MethodException(this, "Bean property " - + beanPropertyName - + " getter return type must not be void"); - } - } else { - type = (Class<T>) returnType; - } - - setArguments(new Object[] {}, new Object[] { null }, 0); - this.instance = instance; - } - - /** - * <p> - * Creates a new instance of <code>MethodProperty</code> from named getter - * and setter methods. The getter method of a <code>MethodProperty</code> - * instantiated with this constructor will be called with no arguments, and - * the setter method with only the new value as the sole argument. - * </p> - * - * <p> - * If the setter method is <code>null</code>, the resulting - * <code>MethodProperty</code> will be read-only, otherwise it will be - * read-write. - * </p> - * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethodName - * the name of the getter method. - * @param setMethodName - * the name of the setter method. - * - */ - public MethodProperty(Class<? extends T> type, Object instance, - String getMethodName, String setMethodName) { - this(type, instance, getMethodName, setMethodName, new Object[] {}, - new Object[] { null }, 0); - } - - /** - * <p> - * Creates a new instance of <code>MethodProperty</code> with the getter and - * setter methods. The getter method of a <code>MethodProperty</code> - * instantiated with this constructor will be called with no arguments, and - * the setter method with only the new value as the sole argument. - * </p> - * - * <p> - * If the setter method is <code>null</code>, the resulting - * <code>MethodProperty</code> will be read-only, otherwise it will be - * read-write. - * </p> - * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethod - * the getter method. - * @param setMethod - * the setter method. - */ - public MethodProperty(Class<? extends T> type, Object instance, - Method getMethod, Method setMethod) { - this(type, instance, getMethod, setMethod, new Object[] {}, - new Object[] { null }, 0); - } - - /** - * <p> - * Creates a new instance of <code>MethodProperty</code> from named getter - * and setter methods and argument lists. The getter method of a - * <code>MethodProperty</code> instantiated with this constructor will be - * called with the getArgs as arguments. The setArgs will be used as the - * arguments for the setter method, though the argument indexed by the - * setArgumentIndex will be replaced with the argument passed to the - * {@link #setValue(Object newValue)} method. - * </p> - * - * <p> - * For example, if the <code>setArgs</code> contains <code>A</code>, - * <code>B</code> and <code>C</code>, and <code>setArgumentIndex = - * 1</code>, the call <code>methodProperty.setValue(X)</code> would result - * in the setter method to be called with the parameter set of - * <code>{A, X, C}</code> - * </p> - * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethodName - * the name of the getter method. - * @param setMethodName - * the name of the setter method. - * @param getArgs - * the fixed argument list to be passed to the getter method. - * @param setArgs - * the fixed argument list to be passed to the setter method. - * @param setArgumentIndex - * the index of the argument in <code>setArgs</code> to be - * replaced with <code>newValue</code> when - * {@link #setValue(Object newValue)} is called. - */ - @SuppressWarnings("unchecked") - public MethodProperty(Class<? extends T> type, Object instance, - String getMethodName, String setMethodName, Object[] getArgs, - Object[] setArgs, int setArgumentIndex) { - - // Check the setargs and setargs index - if (setMethodName != null && setArgs == null) { - throw new IndexOutOfBoundsException("The setArgs can not be null"); - } - if (setMethodName != null - && (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length)) { - throw new IndexOutOfBoundsException( - "The setArgumentIndex must be >= 0 and < setArgs.length"); - } - - // Set type - this.type = type; - - // Find set and get -methods - final Method[] m = instance.getClass().getMethods(); - - // Finds get method - boolean found = false; - for (int i = 0; i < m.length; i++) { - - // Tests the name of the get Method - if (!m[i].getName().equals(getMethodName)) { - - // name does not match, try next method - continue; - } - - // Tests return type - if (!type.equals(m[i].getReturnType())) { - continue; - } - - // Tests the parameter types - final Class<?>[] c = m[i].getParameterTypes(); - if (c.length != getArgs.length) { - - // not the right amount of parameters, try next method - continue; - } - int j = 0; - while (j < c.length) { - if (getArgs[j] != null - && !c[j].isAssignableFrom(getArgs[j].getClass())) { - - // parameter type does not match, try next method - break; - } - j++; - } - if (j == c.length) { - - // all paramteters matched - if (found == true) { - throw new MethodException(this, - "Could not uniquely identify " + getMethodName - + "-method"); - } else { - found = true; - getMethod = m[i]; - } - } - } - if (found != true) { - throw new MethodException(this, "Could not find " + getMethodName - + "-method"); - } - - // Finds set method - if (setMethodName != null) { - - // Finds setMethod - found = false; - for (int i = 0; i < m.length; i++) { - - // Checks name - if (!m[i].getName().equals(setMethodName)) { - - // name does not match, try next method - continue; - } - - // Checks parameter compatibility - final Class<?>[] c = m[i].getParameterTypes(); - if (c.length != setArgs.length) { - - // not the right amount of parameters, try next method - continue; - } - int j = 0; - while (j < c.length) { - if (setArgs[j] != null - && !c[j].isAssignableFrom(setArgs[j].getClass())) { - - // parameter type does not match, try next method - break; - } else if (j == setArgumentIndex && !c[j].equals(type)) { - - // Property type is not the same as setArg type - break; - } - j++; - } - if (j == c.length) { - - // all parameters match - if (found == true) { - throw new MethodException(this, - "Could not identify unique " + setMethodName - + "-method"); - } else { - found = true; - setMethod = m[i]; - } - } - } - if (found != true) { - throw new MethodException(this, "Could not identify " - + setMethodName + "-method"); - } - } - - // Gets the return type from get method - this.type = (Class<T>) convertPrimitiveType(type); - - setArguments(getArgs, setArgs, setArgumentIndex); - this.instance = instance; - } - - /** - * <p> - * Creates a new instance of <code>MethodProperty</code> from the getter and - * setter methods, and argument lists. - * </p> - * <p> - * This constructor behaves exactly like - * {@link #MethodProperty(Class type, Object instance, String getMethodName, String setMethodName, Object [] getArgs, Object [] setArgs, int setArgumentIndex)} - * except that instead of names of the getter and setter methods this - * constructor is given the actual methods themselves. - * </p> - * - * @param type - * the type of the property. - * @param instance - * the object that includes the property. - * @param getMethod - * the getter method. - * @param setMethod - * the setter method. - * @param getArgs - * the fixed argument list to be passed to the getter method. - * @param setArgs - * the fixed argument list to be passed to the setter method. - * @param setArgumentIndex - * the index of the argument in <code>setArgs</code> to be - * replaced with <code>newValue</code> when - * {@link #setValue(Object newValue)} is called. - */ - @SuppressWarnings("unchecked") - // cannot use "Class<? extends T>" because of automatic primitive type - // conversions - public MethodProperty(Class<?> type, Object instance, Method getMethod, - Method setMethod, Object[] getArgs, Object[] setArgs, - int setArgumentIndex) { - - if (getMethod == null) { - throw new MethodException(this, - "Property GET-method cannot not be null: " + type); - } - - if (setMethod != null) { - if (setArgs == null) { - throw new IndexOutOfBoundsException( - "The setArgs can not be null"); - } - if (setArgumentIndex < 0 || setArgumentIndex >= setArgs.length) { - throw new IndexOutOfBoundsException( - "The setArgumentIndex must be >= 0 and < setArgs.length"); - } - } - - // Gets the return type from get method - Class<? extends T> convertedType = (Class<? extends T>) convertPrimitiveType(type); - - this.getMethod = getMethod; - this.setMethod = setMethod; - setArguments(getArgs, setArgs, setArgumentIndex); - this.instance = instance; - this.type = convertedType; - } - - /** - * Find a getter method for a property (getXyz(), isXyz() or areXyz()). - * - * @param propertyName - * name of the property - * @param beanClass - * class in which to look for the getter methods - * @return Method - * @throws NoSuchMethodException - * if no getter found - */ - static Method initGetterMethod(String propertyName, final Class<?> beanClass) - throws NoSuchMethodException { - propertyName = propertyName.substring(0, 1).toUpperCase() - + propertyName.substring(1); - - Method getMethod = null; - try { - getMethod = beanClass.getMethod("get" + propertyName, - new Class[] {}); - } catch (final java.lang.NoSuchMethodException ignored) { - try { - getMethod = beanClass.getMethod("is" + propertyName, - new Class[] {}); - } catch (final java.lang.NoSuchMethodException ignoredAsWell) { - getMethod = beanClass.getMethod("are" + propertyName, - new Class[] {}); - } - } - return getMethod; - } - - static Class<?> convertPrimitiveType(Class<?> type) { - // Gets the return type from get method - if (type.isPrimitive()) { - if (type.equals(Boolean.TYPE)) { - type = Boolean.class; - } else if (type.equals(Integer.TYPE)) { - type = Integer.class; - } else if (type.equals(Float.TYPE)) { - type = Float.class; - } else if (type.equals(Double.TYPE)) { - type = Double.class; - } else if (type.equals(Byte.TYPE)) { - type = Byte.class; - } else if (type.equals(Character.TYPE)) { - type = Character.class; - } else if (type.equals(Short.TYPE)) { - type = Short.class; - } else if (type.equals(Long.TYPE)) { - type = Long.class; - } - } - return type; - } - - /** - * Returns the type of the Property. The methods <code>getValue</code> and - * <code>setValue</code> must be compatible with this type: one must be able - * to safely cast the value returned from <code>getValue</code> to the given - * type and pass any variable assignable to this type as an argument to - * <code>setValue</code>. - * - * @return type of the Property - */ - @Override - public final Class<? extends T> getType() { - return type; - } - - /** - * Tests if the object is in read-only mode. In read-only mode calls to - * <code>setValue</code> will throw <code>ReadOnlyException</code> and will - * not modify the value of the Property. - * - * @return <code>true</code> if the object is in read-only mode, - * <code>false</code> if it's not - */ - @Override - public boolean isReadOnly() { - return super.isReadOnly() || (setMethod == null); - } - - /** - * Gets the value stored in the Property. The value is resolved by calling - * the specified getter method with the argument specified at instantiation. - * - * @return the value of the Property - */ - @Override - public T getValue() { - try { - return (T) getMethod.invoke(instance, getArgs); - } catch (final Throwable e) { - throw new MethodException(this, e); - } - } - - /** - * <p> - * Sets the setter method and getter method argument lists. - * </p> - * - * @param getArgs - * the fixed argument list to be passed to the getter method. - * @param setArgs - * the fixed argument list to be passed to the setter method. - * @param setArgumentIndex - * the index of the argument in <code>setArgs</code> to be - * replaced with <code>newValue</code> when - * {@link #setValue(Object newValue)} is called. - */ - public void setArguments(Object[] getArgs, Object[] setArgs, - int setArgumentIndex) { - this.getArgs = new Object[getArgs.length]; - for (int i = 0; i < getArgs.length; i++) { - this.getArgs[i] = getArgs[i]; - } - this.setArgs = new Object[setArgs.length]; - for (int i = 0; i < setArgs.length; i++) { - this.setArgs[i] = setArgs[i]; - } - this.setArgumentIndex = setArgumentIndex; - } - - /** - * Sets the value of the property. - * - * Note that since Vaadin 7, no conversions are performed and the value must - * be of the correct type. - * - * @param newValue - * the New value of the property. - * @throws <code>Property.ReadOnlyException</code> if the object is in - * read-only mode. - * @see #invokeSetMethod(Object) - */ - @Override - @SuppressWarnings("unchecked") - public void setValue(Object newValue) throws Property.ReadOnlyException { - - // Checks the mode - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - // Checks the type of the value - if (newValue != null && !type.isAssignableFrom(newValue.getClass())) { - throw new IllegalArgumentException( - "Invalid value type for ObjectProperty."); - } - - invokeSetMethod((T) newValue); - fireValueChange(); - } - - /** - * Internal method to actually call the setter method of the wrapped - * property. - * - * @param value - */ - protected void invokeSetMethod(T value) { - - try { - // Construct a temporary argument array only if needed - if (setArgs.length == 1) { - setMethod.invoke(instance, new Object[] { value }); - } else { - - // Sets the value to argument array - final Object[] args = new Object[setArgs.length]; - for (int i = 0; i < setArgs.length; i++) { - args[i] = (i == setArgumentIndex) ? value : setArgs[i]; - } - setMethod.invoke(instance, args); - } - } catch (final InvocationTargetException e) { - final Throwable targetException = e.getTargetException(); - throw new MethodException(this, targetException); - } catch (final Exception e) { - throw new MethodException(this, e); - } - } - - /** - * <code>Exception</code> object that signals that there were problems - * calling or finding the specified getter or setter methods of the - * property. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - @SuppressWarnings("rawtypes") - // Exceptions cannot be parameterized, ever. - public static class MethodException extends RuntimeException { - - /** - * The method property from which the exception originates from - */ - private final Property property; - - /** - * Cause of the method exception - */ - private Throwable cause; - - /** - * Constructs a new <code>MethodException</code> with the specified - * detail message. - * - * @param property - * the property. - * @param msg - * the detail message. - */ - public MethodException(Property property, String msg) { - super(msg); - this.property = property; - } - - /** - * Constructs a new <code>MethodException</code> from another exception. - * - * @param property - * the property. - * @param cause - * the cause of the exception. - */ - public MethodException(Property property, Throwable cause) { - this.property = property; - this.cause = cause; - } - - /** - * @see java.lang.Throwable#getCause() - */ - @Override - public Throwable getCause() { - return cause; - } - - /** - * Gets the method property this exception originates from. - * - * @return MethodProperty or null if not a valid MethodProperty - */ - public MethodProperty getMethodProperty() { - return (property instanceof MethodProperty) ? (MethodProperty) property - : null; - } - - /** - * Gets the method property this exception originates from. - * - * @return Property from which the exception originates - */ - public Property getProperty() { - return property; - } - } - - /** - * Sends a value change event to all registered listeners. - * - * Public for backwards compatibility, visibility may be reduced in future - * versions. - */ - @Override - public void fireValueChange() { - super.fireValueChange(); - } - - private static final Logger getLogger() { - return Logger.getLogger(MethodProperty.class.getName()); - } -} diff --git a/src/com/vaadin/data/util/MethodPropertyDescriptor.java b/src/com/vaadin/data/util/MethodPropertyDescriptor.java deleted file mode 100644 index a2a76ec6cf..0000000000 --- a/src/com/vaadin/data/util/MethodPropertyDescriptor.java +++ /dev/null @@ -1,134 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.data.Property; -import com.vaadin.util.SerializerHelper; - -/** - * Property descriptor that is able to create simple {@link MethodProperty} - * instances for a bean, using given accessors. - * - * @param <BT> - * bean type - * - * @since 6.6 - */ -public class MethodPropertyDescriptor<BT> implements - VaadinPropertyDescriptor<BT> { - - private final String name; - private Class<?> propertyType; - private transient Method readMethod; - private transient Method writeMethod; - - /** - * Creates a property descriptor that can create MethodProperty instances to - * access the underlying bean property. - * - * @param name - * of the property - * @param propertyType - * type (class) of the property - * @param readMethod - * getter {@link Method} for the property - * @param writeMethod - * setter {@link Method} for the property or null if read-only - * property - */ - public MethodPropertyDescriptor(String name, Class<?> propertyType, - Method readMethod, Method writeMethod) { - this.name = name; - this.propertyType = propertyType; - this.readMethod = readMethod; - this.writeMethod = writeMethod; - } - - /* Special serialization to handle method references */ - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - SerializerHelper.writeClass(out, propertyType); - - if (writeMethod != null) { - out.writeObject(writeMethod.getName()); - SerializerHelper.writeClass(out, writeMethod.getDeclaringClass()); - SerializerHelper.writeClassArray(out, - writeMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - out.writeObject(null); - } - - if (readMethod != null) { - out.writeObject(readMethod.getName()); - SerializerHelper.writeClass(out, readMethod.getDeclaringClass()); - SerializerHelper.writeClassArray(out, - readMethod.getParameterTypes()); - } else { - out.writeObject(null); - out.writeObject(null); - out.writeObject(null); - } - } - - /* Special serialization to handle method references */ - private void readObject(java.io.ObjectInputStream in) throws IOException, - ClassNotFoundException { - in.defaultReadObject(); - try { - @SuppressWarnings("unchecked") - // business assumption; type parameters not checked at runtime - Class<BT> class1 = (Class<BT>) SerializerHelper.readClass(in); - propertyType = class1; - - String name = (String) in.readObject(); - Class<?> writeMethodClass = SerializerHelper.readClass(in); - Class<?>[] paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { - writeMethod = writeMethodClass.getMethod(name, paramTypes); - } else { - writeMethod = null; - } - - name = (String) in.readObject(); - Class<?> readMethodClass = SerializerHelper.readClass(in); - paramTypes = SerializerHelper.readClassArray(in); - if (name != null) { - readMethod = readMethodClass.getMethod(name, paramTypes); - } else { - readMethod = null; - } - } catch (SecurityException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } catch (NoSuchMethodException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } - }; - - @Override - public String getName() { - return name; - } - - @Override - public Class<?> getPropertyType() { - return propertyType; - } - - @Override - public Property<?> createProperty(Object bean) { - return new MethodProperty<Object>(propertyType, bean, readMethod, - writeMethod); - } - - private static final Logger getLogger() { - return Logger.getLogger(MethodPropertyDescriptor.class.getName()); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/data/util/NestedMethodProperty.java b/src/com/vaadin/data/util/NestedMethodProperty.java deleted file mode 100644 index 9bff38456d..0000000000 --- a/src/com/vaadin/data/util/NestedMethodProperty.java +++ /dev/null @@ -1,257 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.vaadin.data.Property; -import com.vaadin.data.util.MethodProperty.MethodException; - -/** - * Nested accessor based property for a bean. - * - * The property is specified in the dotted notation, e.g. "address.street", and - * can contain multiple levels of nesting. - * - * When accessing the property value, all intermediate getters must return - * non-null values. - * - * @see MethodProperty - * - * @since 6.6 - */ -public class NestedMethodProperty<T> extends AbstractProperty<T> { - - // needed for de-serialization - private String propertyName; - - // chain of getter methods - private transient List<Method> getMethods; - /** - * The setter method. - */ - private transient Method setMethod; - - /** - * Bean instance used as a starting point for accessing the property value. - */ - private Object instance; - - private Class<? extends T> type; - - /* Special serialization to handle method references */ - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - // getMethods and setMethod are reconstructed on read based on - // propertyName - } - - /* Special serialization to handle method references */ - private void readObject(java.io.ObjectInputStream in) throws IOException, - ClassNotFoundException { - in.defaultReadObject(); - - initialize(instance.getClass(), propertyName); - } - - /** - * Constructs a nested method property for a given object instance. The - * property name is a dot separated string pointing to a nested property, - * e.g. "manager.address.street". - * - * @param instance - * top-level bean to which the property applies - * @param propertyName - * dot separated nested property name - * @throws IllegalArgumentException - * if the property name is invalid - */ - public NestedMethodProperty(Object instance, String propertyName) { - this.instance = instance; - initialize(instance.getClass(), propertyName); - } - - /** - * For internal use to deduce property type etc. without a bean instance. - * Calling {@link #setValue(Object)} or {@link #getValue()} on properties - * constructed this way is not supported. - * - * @param instanceClass - * class of the top-level bean - * @param propertyName - */ - NestedMethodProperty(Class<?> instanceClass, String propertyName) { - instance = null; - initialize(instanceClass, propertyName); - } - - /** - * Initializes most of the internal fields based on the top-level bean - * instance and property name (dot-separated string). - * - * @param beanClass - * class of the top-level bean to which the property applies - * @param propertyName - * dot separated nested property name - * @throws IllegalArgumentException - * if the property name is invalid - */ - private void initialize(Class<?> beanClass, String propertyName) - throws IllegalArgumentException { - - List<Method> getMethods = new ArrayList<Method>(); - - String lastSimplePropertyName = propertyName; - Class<?> lastClass = beanClass; - - // first top-level property, then go deeper in a loop - Class<?> propertyClass = beanClass; - String[] simplePropertyNames = propertyName.split("\\."); - if (propertyName.endsWith(".") || 0 == simplePropertyNames.length) { - throw new IllegalArgumentException("Invalid property name '" - + propertyName + "'"); - } - for (int i = 0; i < simplePropertyNames.length; i++) { - String simplePropertyName = simplePropertyNames[i].trim(); - if (simplePropertyName.length() > 0) { - lastSimplePropertyName = simplePropertyName; - lastClass = propertyClass; - try { - Method getter = MethodProperty.initGetterMethod( - simplePropertyName, propertyClass); - propertyClass = getter.getReturnType(); - getMethods.add(getter); - } catch (final java.lang.NoSuchMethodException e) { - throw new IllegalArgumentException("Bean property '" - + simplePropertyName + "' not found", e); - } - } else { - throw new IllegalArgumentException( - "Empty or invalid bean property identifier in '" - + propertyName + "'"); - } - } - - // In case the get method is found, resolve the type - Method lastGetMethod = getMethods.get(getMethods.size() - 1); - Class<?> type = lastGetMethod.getReturnType(); - - // Finds the set method - Method setMethod = null; - try { - // Assure that the first letter is upper cased (it is a common - // mistake to write firstName, not FirstName). - if (Character.isLowerCase(lastSimplePropertyName.charAt(0))) { - final char[] buf = lastSimplePropertyName.toCharArray(); - buf[0] = Character.toUpperCase(buf[0]); - lastSimplePropertyName = new String(buf); - } - - setMethod = lastClass.getMethod("set" + lastSimplePropertyName, - new Class[] { type }); - } catch (final NoSuchMethodException skipped) { - } - - this.type = (Class<? extends T>) MethodProperty - .convertPrimitiveType(type); - this.propertyName = propertyName; - this.getMethods = getMethods; - this.setMethod = setMethod; - } - - @Override - public Class<? extends T> getType() { - return type; - } - - @Override - public boolean isReadOnly() { - return super.isReadOnly() || (null == setMethod); - } - - /** - * Gets the value stored in the Property. The value is resolved by calling - * the specified getter method with the argument specified at instantiation. - * - * @return the value of the Property - */ - @Override - public T getValue() { - try { - Object object = instance; - for (Method m : getMethods) { - object = m.invoke(object); - } - return (T) object; - } catch (final Throwable e) { - throw new MethodException(this, e); - } - } - - /** - * Sets the value of the property. The new value must be assignable to the - * type of this property. - * - * @param newValue - * the New value of the property. - * @throws <code>Property.ReadOnlyException</code> if the object is in - * read-only mode. - * @see #invokeSetMethod(Object) - */ - @Override - public void setValue(Object newValue) throws ReadOnlyException { - // Checks the mode - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - // Checks the type of the value - if (newValue != null && !type.isAssignableFrom(newValue.getClass())) { - throw new IllegalArgumentException( - "Invalid value type for NestedMethodProperty."); - } - - invokeSetMethod((T) newValue); - fireValueChange(); - } - - /** - * Internal method to actually call the setter method of the wrapped - * property. - * - * @param value - */ - protected void invokeSetMethod(T value) { - try { - Object object = instance; - for (int i = 0; i < getMethods.size() - 1; i++) { - object = getMethods.get(i).invoke(object); - } - setMethod.invoke(object, new Object[] { value }); - } catch (final InvocationTargetException e) { - throw new MethodException(this, e.getTargetException()); - } catch (final Exception e) { - throw new MethodException(this, e); - } - } - - /** - * Returns an unmodifiable list of getter methods to call in sequence to get - * the property value. - * - * This API may change in future versions. - * - * @return unmodifiable list of getter methods corresponding to each segment - * of the property name - */ - protected List<Method> getGetMethods() { - return Collections.unmodifiableList(getMethods); - } - -} diff --git a/src/com/vaadin/data/util/NestedPropertyDescriptor.java b/src/com/vaadin/data/util/NestedPropertyDescriptor.java deleted file mode 100644 index b67b425d1d..0000000000 --- a/src/com/vaadin/data/util/NestedPropertyDescriptor.java +++ /dev/null @@ -1,60 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import com.vaadin.data.Property; - -/** - * Property descriptor that is able to create nested property instances for a - * bean. - * - * The property is specified in the dotted notation, e.g. "address.street", and - * can contain multiple levels of nesting. - * - * @param <BT> - * bean type - * - * @since 6.6 - */ -public class NestedPropertyDescriptor<BT> implements - VaadinPropertyDescriptor<BT> { - - private final String name; - private final Class<?> propertyType; - - /** - * Creates a property descriptor that can create MethodProperty instances to - * access the underlying bean property. - * - * @param name - * of the property in a dotted path format, e.g. "address.street" - * @param beanType - * type (class) of the top-level bean - * @throws IllegalArgumentException - * if the property name is invalid - */ - public NestedPropertyDescriptor(String name, Class<BT> beanType) - throws IllegalArgumentException { - this.name = name; - NestedMethodProperty<?> property = new NestedMethodProperty<Object>( - beanType, name); - this.propertyType = property.getType(); - } - - @Override - public String getName() { - return name; - } - - @Override - public Class<?> getPropertyType() { - return propertyType; - } - - @Override - public Property<?> createProperty(BT bean) { - return new NestedMethodProperty<Object>(bean, name); - } - -} diff --git a/src/com/vaadin/data/util/ObjectProperty.java b/src/com/vaadin/data/util/ObjectProperty.java deleted file mode 100644 index cb85b44c2a..0000000000 --- a/src/com/vaadin/data/util/ObjectProperty.java +++ /dev/null @@ -1,141 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import com.vaadin.data.Property; - -/** - * A simple data object containing one typed value. This class is a - * straightforward implementation of the the {@link com.vaadin.data.Property} - * interface. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ObjectProperty<T> extends AbstractProperty<T> { - - /** - * The value contained by the Property. - */ - private T value; - - /** - * Data type of the Property's value. - */ - private final Class<T> type; - - /** - * Creates a new instance of ObjectProperty with the given value. The type - * of the property is automatically initialized to be the type of the given - * value. - * - * @param value - * the Initial value of the Property. - */ - @SuppressWarnings("unchecked") - // the cast is safe, because an object of type T has class Class<T> - public ObjectProperty(T value) { - this(value, (Class<T>) value.getClass()); - } - - /** - * Creates a new instance of ObjectProperty with the given value and type. - * - * Since Vaadin 7, only values of the correct type are accepted, and no - * automatic conversions are performed. - * - * @param value - * the Initial value of the Property. - * @param type - * the type of the value. The value must be assignable to given - * type. - */ - public ObjectProperty(T value, Class<T> type) { - - // Set the values - this.type = type; - setValue(value); - } - - /** - * Creates a new instance of ObjectProperty with the given value, type and - * read-only mode status. - * - * Since Vaadin 7, only the correct type of values is accepted, see - * {@link #ObjectProperty(Object, Class)}. - * - * @param value - * the Initial value of the property. - * @param type - * the type of the value. <code>value</code> must be assignable - * to this type. - * @param readOnly - * Sets the read-only mode. - */ - public ObjectProperty(T value, Class<T> type, boolean readOnly) { - this(value, type); - setReadOnly(readOnly); - } - - /** - * Returns the type of the ObjectProperty. The methods <code>getValue</code> - * and <code>setValue</code> must be compatible with this type: one must be - * able to safely cast the value returned from <code>getValue</code> to the - * given type and pass any variable assignable to this type as an argument - * to <code>setValue</code>. - * - * @return type of the Property - */ - @Override - public final Class<T> getType() { - return type; - } - - /** - * Gets the value stored in the Property. - * - * @return the value stored in the Property - */ - @Override - public T getValue() { - return value; - } - - /** - * Sets the value of the property. - * - * Note that since Vaadin 7, no conversions are performed and the value must - * be of the correct type. - * - * @param newValue - * the New value of the property. - * @throws <code>Property.ReadOnlyException</code> if the object is in - * read-only mode - */ - @Override - @SuppressWarnings("unchecked") - public void setValue(Object newValue) throws Property.ReadOnlyException { - - // Checks the mode - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - // Checks the type of the value - if (newValue != null && !type.isAssignableFrom(newValue.getClass())) { - throw new IllegalArgumentException("Invalid value type " - + newValue.getClass().getName() - + " for ObjectProperty of type " + type.getName() + "."); - } - - // the cast is safe after an isAssignableFrom check - this.value = (T) newValue; - - fireValueChange(); - } -} diff --git a/src/com/vaadin/data/util/PropertyFormatter.java b/src/com/vaadin/data/util/PropertyFormatter.java deleted file mode 100644 index 3d65726309..0000000000 --- a/src/com/vaadin/data/util/PropertyFormatter.java +++ /dev/null @@ -1,245 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import com.vaadin.data.Property; -import com.vaadin.data.util.converter.Converter; - -/** - * Formatting proxy for a {@link Property}. - * - * <p> - * This class can be used to implement formatting for any type of Property - * datasources. The idea is to connect this as proxy between UI component and - * the original datasource. - * </p> - * - * <p> - * For example <code> - * <pre>textfield.setPropertyDataSource(new PropertyFormatter(property) { - public String format(Object value) { - return ((Double) value).toString() + "000000000"; - } - - public Object parse(String formattedValue) throws Exception { - return Double.parseDouble(formattedValue); - } - - });</pre></code> adds formatter for Double-typed property that extends - * standard "1.0" notation with more zeroes. - * </p> - * - * @param T - * type of the underlying property (a PropertyFormatter is always a - * Property<String>) - * - * @deprecated Since 7.0 replaced by {@link Converter} - * @author Vaadin Ltd. - * @since 5.3.0 - */ -@SuppressWarnings("serial") -@Deprecated -public abstract class PropertyFormatter<T> extends AbstractProperty<String> - implements Property.Viewer, Property.ValueChangeListener, - Property.ReadOnlyStatusChangeListener { - - /** Datasource that stores the actual value. */ - Property<T> dataSource; - - /** - * Construct a new {@code PropertyFormatter} that is not connected to any - * data source. Call {@link #setPropertyDataSource(Property)} later on to - * attach it to a property. - * - */ - protected PropertyFormatter() { - } - - /** - * Construct a new formatter that is connected to given data source. Calls - * {@link #format(Object)} which can be a problem if the formatter has not - * yet been initialized. - * - * @param propertyDataSource - * to connect this property to. - */ - public PropertyFormatter(Property<T> propertyDataSource) { - - setPropertyDataSource(propertyDataSource); - } - - /** - * Gets the current data source of the formatter, if any. - * - * @return the current data source as a Property, or <code>null</code> if - * none defined. - */ - @Override - public Property<T> getPropertyDataSource() { - return dataSource; - } - - /** - * Sets the specified Property as the data source for the formatter. - * - * - * <p> - * Remember that new data sources getValue() must return objects that are - * compatible with parse() and format() methods. - * </p> - * - * @param newDataSource - * the new data source Property. - */ - @Override - public void setPropertyDataSource(Property newDataSource) { - - boolean readOnly = false; - String prevValue = null; - - if (dataSource != null) { - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource) - .removeListener(this); - } - if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .removeListener(this); - } - readOnly = isReadOnly(); - prevValue = getValue(); - } - - dataSource = newDataSource; - - if (dataSource != null) { - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource).addListener(this); - } - if (dataSource instanceof Property.ReadOnlyStatusChangeListener) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .addListener(this); - } - } - - if (isReadOnly() != readOnly) { - fireReadOnlyStatusChange(); - } - String newVal = getValue(); - if ((prevValue == null && newVal != null) - || (prevValue != null && !prevValue.equals(newVal))) { - fireValueChange(); - } - } - - /* Documented in the interface */ - @Override - public Class<String> getType() { - return String.class; - } - - /** - * Get the formatted value. - * - * @return If the datasource returns null, this is null. Otherwise this is - * String given by format(). - */ - @Override - public String getValue() { - T value = dataSource == null ? null : dataSource.getValue(); - if (value == null) { - return null; - } - return format(value); - } - - /** Reflects the read-only status of the datasource. */ - @Override - public boolean isReadOnly() { - return dataSource == null ? false : dataSource.isReadOnly(); - } - - /** - * This method must be implemented to format the values received from - * DataSource. - * - * @param value - * Value object got from the datasource. This is guaranteed to be - * non-null and of the type compatible with getType() of the - * datasource. - * @return - */ - abstract public String format(T value); - - /** - * Parse string and convert it to format compatible with datasource. - * - * The method is required to assure that parse(format(x)) equals x. - * - * @param formattedValue - * This is guaranteed to be non-null string. - * @return Non-null value compatible with datasource. - * @throws Exception - * Any type of exception can be thrown to indicate that the - * conversion was not succesful. - */ - abstract public T parse(String formattedValue) throws Exception; - - /** - * Sets the Property's read-only mode to the specified status. - * - * @param newStatus - * the new read-only status of the Property. - */ - @Override - public void setReadOnly(boolean newStatus) { - if (dataSource != null) { - dataSource.setReadOnly(newStatus); - } - } - - @Override - public void setValue(Object newValue) throws ReadOnlyException { - if (dataSource == null) { - return; - } - if (newValue == null) { - if (dataSource.getValue() != null) { - dataSource.setValue(null); - fireValueChange(); - } - } else { - try { - dataSource.setValue(parse(newValue.toString())); - if (!newValue.equals(getValue())) { - fireValueChange(); - } - } catch (Exception e) { - throw new IllegalArgumentException("Could not parse value", e); - } - } - } - - /** - * Listens for changes in the datasource. - * - * This should not be called directly. - */ - @Override - public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) { - fireValueChange(); - } - - /** - * Listens for changes in the datasource. - * - * This should not be called directly. - */ - @Override - public void readOnlyStatusChange( - com.vaadin.data.Property.ReadOnlyStatusChangeEvent event) { - fireReadOnlyStatusChange(); - } - -} diff --git a/src/com/vaadin/data/util/PropertysetItem.java b/src/com/vaadin/data/util/PropertysetItem.java deleted file mode 100644 index 22f2da75b2..0000000000 --- a/src/com/vaadin/data/util/PropertysetItem.java +++ /dev/null @@ -1,340 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.util.Collection; -import java.util.Collections; -import java.util.EventObject; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; - -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * Class for handling a set of identified Properties. The elements contained in - * a </code>MapItem</code> can be referenced using locally unique identifiers. - * The class supports listeners who are interested in changes to the Property - * set managed by the class. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class PropertysetItem implements Item, Item.PropertySetChangeNotifier, - Cloneable { - - /* Private representation of the item */ - - /** - * Mapping from property id to property. - */ - private HashMap<Object, Property<?>> map = new HashMap<Object, Property<?>>(); - - /** - * List of all property ids to maintain the order. - */ - private LinkedList<Object> list = new LinkedList<Object>(); - - /** - * List of property set modification listeners. - */ - private LinkedList<Item.PropertySetChangeListener> propertySetChangeListeners = null; - - /* Item methods */ - - /** - * Gets the Property corresponding to the given Property ID stored in the - * Item. If the Item does not contain the Property, <code>null</code> is - * returned. - * - * @param id - * the identifier of the Property to get. - * @return the Property with the given ID or <code>null</code> - */ - @Override - public Property<?> getItemProperty(Object id) { - return map.get(id); - } - - /** - * Gets the collection of IDs of all Properties stored in the Item. - * - * @return unmodifiable collection containing IDs of the Properties stored - * the Item - */ - @Override - public Collection<?> getItemPropertyIds() { - return Collections.unmodifiableCollection(list); - } - - /* Item.Managed methods */ - - /** - * Removes the Property identified by ID from the Item. This functionality - * is optional. If the method is not implemented, the method always returns - * <code>false</code>. - * - * @param id - * the ID of the Property to be removed. - * @return <code>true</code> if the operation succeeded <code>false</code> - * if not - */ - @Override - public boolean removeItemProperty(Object id) { - - // Cant remove missing properties - if (map.remove(id) == null) { - return false; - } - list.remove(id); - - // Send change events - fireItemPropertySetChange(); - - return true; - } - - /** - * Tries to add a new Property into the Item. - * - * @param id - * the ID of the new Property. - * @param property - * the Property to be added and associated with the id. - * @return <code>true</code> if the operation succeeded, <code>false</code> - * if not - */ - @Override - public boolean addItemProperty(Object id, Property property) { - - // Null ids are not accepted - if (id == null) { - throw new NullPointerException("Item property id can not be null"); - } - - // Cant add a property twice - if (map.containsKey(id)) { - return false; - } - - // Put the property to map - map.put(id, property); - list.add(id); - - // Send event - fireItemPropertySetChange(); - - return true; - } - - /** - * Gets the <code>String</code> representation of the contents of the Item. - * The format of the string is a space separated catenation of the - * <code>String</code> representations of the Properties contained by the - * Item. - * - * @return <code>String</code> representation of the Item contents - */ - @Override - public String toString() { - String retValue = ""; - - for (final Iterator<?> i = getItemPropertyIds().iterator(); i.hasNext();) { - final Object propertyId = i.next(); - retValue += getItemProperty(propertyId).getValue(); - if (i.hasNext()) { - retValue += " "; - } - } - - return retValue; - } - - /* Notifiers */ - - /** - * An <code>event</code> object specifying an Item whose Property set has - * changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - private static class PropertySetChangeEvent extends EventObject implements - Item.PropertySetChangeEvent { - - private PropertySetChangeEvent(Item source) { - super(source); - } - - /** - * Gets the Item whose Property set has changed. - * - * @return source object of the event as an <code>Item</code> - */ - @Override - public Item getItem() { - return (Item) getSource(); - } - } - - /** - * Registers a new property set change listener for this Item. - * - * @param listener - * the new Listener to be registered. - */ - @Override - public void addListener(Item.PropertySetChangeListener listener) { - if (propertySetChangeListeners == null) { - propertySetChangeListeners = new LinkedList<PropertySetChangeListener>(); - } - propertySetChangeListeners.add(listener); - } - - /** - * Removes a previously registered property set change listener. - * - * @param listener - * the Listener to be removed. - */ - @Override - public void removeListener(Item.PropertySetChangeListener listener) { - if (propertySetChangeListeners != null) { - propertySetChangeListeners.remove(listener); - } - } - - /** - * Sends a Property set change event to all interested listeners. - */ - private void fireItemPropertySetChange() { - if (propertySetChangeListeners != null) { - final Object[] l = propertySetChangeListeners.toArray(); - final Item.PropertySetChangeEvent event = new PropertysetItem.PropertySetChangeEvent( - this); - for (int i = 0; i < l.length; i++) { - ((Item.PropertySetChangeListener) l[i]) - .itemPropertySetChange(event); - } - } - } - - public Collection<?> getListeners(Class<?> eventType) { - if (Item.PropertySetChangeEvent.class.isAssignableFrom(eventType)) { - if (propertySetChangeListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(propertySetChangeListeners); - } - } - - return Collections.EMPTY_LIST; - } - - /** - * Creates and returns a copy of this object. - * <p> - * The method <code>clone</code> performs a shallow copy of the - * <code>PropertysetItem</code>. - * </p> - * <p> - * Note : All arrays are considered to implement the interface Cloneable. - * Otherwise, this method creates a new instance of the class of this object - * and initializes all its fields with exactly the contents of the - * corresponding fields of this object, as if by assignment, the contents of - * the fields are not themselves cloned. Thus, this method performs a - * "shallow copy" of this object, not a "deep copy" operation. - * </p> - * - * @throws CloneNotSupportedException - * if the object's class does not support the Cloneable - * interface. - * - * @see java.lang.Object#clone() - */ - @Override - public Object clone() throws CloneNotSupportedException { - - final PropertysetItem npsi = new PropertysetItem(); - - npsi.list = list != null ? (LinkedList<Object>) list.clone() : null; - npsi.propertySetChangeListeners = propertySetChangeListeners != null ? (LinkedList<PropertySetChangeListener>) propertySetChangeListeners - .clone() : null; - npsi.map = (HashMap<Object, Property<?>>) map.clone(); - - return npsi; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - @Override - public boolean equals(Object obj) { - - if (obj == null || !(obj instanceof PropertysetItem)) { - return false; - } - - final PropertysetItem other = (PropertysetItem) obj; - - if (other.list != list) { - if (other.list == null) { - return false; - } - if (!other.list.equals(list)) { - return false; - } - } - if (other.map != map) { - if (other.map == null) { - return false; - } - if (!other.map.equals(map)) { - return false; - } - } - if (other.propertySetChangeListeners != propertySetChangeListeners) { - boolean thisEmpty = (propertySetChangeListeners == null || propertySetChangeListeners - .isEmpty()); - boolean otherEmpty = (other.propertySetChangeListeners == null || other.propertySetChangeListeners - .isEmpty()); - if (thisEmpty && otherEmpty) { - return true; - } - if (otherEmpty) { - return false; - } - if (!other.propertySetChangeListeners - .equals(propertySetChangeListeners)) { - return false; - } - } - - return true; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - - return (list == null ? 0 : list.hashCode()) - ^ (map == null ? 0 : map.hashCode()) - ^ ((propertySetChangeListeners == null || propertySetChangeListeners - .isEmpty()) ? 0 : propertySetChangeListeners.hashCode()); - } -} diff --git a/src/com/vaadin/data/util/QueryContainer.java b/src/com/vaadin/data/util/QueryContainer.java deleted file mode 100644 index dc7c883a7e..0000000000 --- a/src/com/vaadin/data/util/QueryContainer.java +++ /dev/null @@ -1,675 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * <p> - * The <code>QueryContainer</code> is the specialized form of Container which is - * Ordered and Indexed. This is used to represent the contents of relational - * database tables accessed through the JDBC Connection in the Vaadin Table. - * This creates Items based on the queryStatement provided to the container. - * </p> - * - * <p> - * The <code>QueryContainer</code> can be visualized as a representation of a - * relational database table.Each Item in the container represents the row - * fetched by the query.All cells in a column have same data type and the data - * type information is retrieved from the metadata of the resultset. - * </p> - * - * <p> - * Note : If data in the tables gets modified, Container will not get reflected - * with the updates, we have to explicity invoke QueryContainer.refresh method. - * {@link com.vaadin.data.util.QueryContainer#refresh() refresh()} - * </p> - * - * @see com.vaadin.data.Container - * - * @author Vaadin Ltd. - * @version - * @since 4.0 - * - * @deprecated will be removed in the future, use the SQLContainer add-on - */ - -@Deprecated -@SuppressWarnings("serial") -public class QueryContainer implements Container, Container.Ordered, - Container.Indexed { - - // default ResultSet type - public static final int DEFAULT_RESULTSET_TYPE = ResultSet.TYPE_SCROLL_INSENSITIVE; - - // default ResultSet concurrency - public static final int DEFAULT_RESULTSET_CONCURRENCY = ResultSet.CONCUR_READ_ONLY; - - private int resultSetType = DEFAULT_RESULTSET_TYPE; - - private int resultSetConcurrency = DEFAULT_RESULTSET_CONCURRENCY; - - private final String queryStatement; - - private final Connection connection; - - private ResultSet result; - - private Collection<String> propertyIds; - - private final HashMap<String, Class<?>> propertyTypes = new HashMap<String, Class<?>>(); - - private int size = -1; - - private Statement statement; - - /** - * Constructs new <code>QueryContainer</code> with the specified - * <code>queryStatement</code>. - * - * @param queryStatement - * Database query - * @param connection - * Connection object - * @param resultSetType - * @param resultSetConcurrency - * @throws SQLException - * when database operation fails - */ - public QueryContainer(String queryStatement, Connection connection, - int resultSetType, int resultSetConcurrency) throws SQLException { - this.queryStatement = queryStatement; - this.connection = connection; - this.resultSetType = resultSetType; - this.resultSetConcurrency = resultSetConcurrency; - init(); - } - - /** - * Constructs new <code>QueryContainer</code> with the specified - * queryStatement using the default resultset type and default resultset - * concurrency. - * - * @param queryStatement - * Database query - * @param connection - * Connection object - * @see QueryContainer#DEFAULT_RESULTSET_TYPE - * @see QueryContainer#DEFAULT_RESULTSET_CONCURRENCY - * @throws SQLException - * when database operation fails - */ - public QueryContainer(String queryStatement, Connection connection) - throws SQLException { - this(queryStatement, connection, DEFAULT_RESULTSET_TYPE, - DEFAULT_RESULTSET_CONCURRENCY); - } - - /** - * Fills the Container with the items and properties. Invoked by the - * constructor. - * - * @throws SQLException - * when parameter initialization fails. - * @see QueryContainer#QueryContainer(String, Connection, int, int). - */ - private void init() throws SQLException { - refresh(); - ResultSetMetaData metadata; - metadata = result.getMetaData(); - final int count = metadata.getColumnCount(); - final ArrayList<String> list = new ArrayList<String>(count); - for (int i = 1; i <= count; i++) { - final String columnName = metadata.getColumnName(i); - list.add(columnName); - final Property<?> p = getContainerProperty(new Integer(1), - columnName); - propertyTypes.put(columnName, - p == null ? Object.class : p.getType()); - } - propertyIds = Collections.unmodifiableCollection(list); - } - - /** - * <p> - * Restores items in the container. This method will update the latest data - * to the container. - * </p> - * Note: This method should be used to update the container with the latest - * items. - * - * @throws SQLException - * when database operation fails - * - */ - - public void refresh() throws SQLException { - close(); - statement = connection.createStatement(resultSetType, - resultSetConcurrency); - result = statement.executeQuery(queryStatement); - result.last(); - size = result.getRow(); - } - - /** - * Releases and nullifies the <code>statement</code>. - * - * @throws SQLException - * when database operation fails - */ - - public void close() throws SQLException { - if (statement != null) { - statement.close(); - } - statement = null; - } - - /** - * Gets the Item with the given Item ID from the Container. - * - * @param id - * ID of the Item to retrieve - * @return Item Id. - */ - - @Override - public Item getItem(Object id) { - return new Row(id); - } - - /** - * Gets the collection of propertyId from the Container. - * - * @return Collection of Property ID. - */ - - @Override - public Collection<String> getContainerPropertyIds() { - return propertyIds; - } - - /** - * Gets an collection of all the item IDs in the container. - * - * @return collection of Item IDs - */ - @Override - public Collection<?> getItemIds() { - final Collection<Integer> c = new ArrayList<Integer>(size); - for (int i = 1; i <= size; i++) { - c.add(new Integer(i)); - } - return c; - } - - /** - * Gets the property identified by the given itemId and propertyId from the - * container. If the container does not contain the property - * <code>null</code> is returned. - * - * @param itemId - * ID of the Item which contains the Property - * @param propertyId - * ID of the Property to retrieve - * - * @return Property with the given ID if exists; <code>null</code> - * otherwise. - */ - - @Override - public synchronized Property<?> getContainerProperty(Object itemId, - Object propertyId) { - if (!(itemId instanceof Integer && propertyId instanceof String)) { - return null; - } - Object value; - try { - result.absolute(((Integer) itemId).intValue()); - value = result.getObject((String) propertyId); - } catch (final Exception e) { - return null; - } - - // Handle also null values from the database - return new ObjectProperty<Object>(value != null ? value - : new String("")); - } - - /** - * Gets the data type of all properties identified by the given type ID. - * - * @param id - * ID identifying the Properties - * - * @return data type of the Properties - */ - - @Override - public Class<?> getType(Object id) { - return propertyTypes.get(id); - } - - /** - * Gets the number of items in the container. - * - * @return the number of items in the container. - */ - @Override - public int size() { - return size; - } - - /** - * Tests if the list contains the specified Item. - * - * @param id - * ID the of Item to be tested. - * @return <code>true</code> if given id is in the container; - * <code>false</code> otherwise. - */ - @Override - public boolean containsId(Object id) { - if (!(id instanceof Integer)) { - return false; - } - final int i = ((Integer) id).intValue(); - if (i < 1) { - return false; - } - if (i > size) { - return false; - } - return true; - } - - /** - * Creates new Item with the given ID into the Container. - * - * @param itemId - * ID of the Item to be created. - * - * @return Created new Item, or <code>null</code> if it fails. - * - * @throws UnsupportedOperationException - * if the addItem method is not supported. - */ - @Override - public Item addItem(Object itemId) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Creates a new Item into the Container, and assign it an ID. - * - * @return ID of the newly created Item, or <code>null</code> if it fails. - * @throws UnsupportedOperationException - * if the addItem method is not supported. - */ - @Override - public Object addItem() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Removes the Item identified by ItemId from the Container. - * - * @param itemId - * ID of the Item to remove. - * @return <code>true</code> if the operation succeeded; <code>false</code> - * otherwise. - * @throws UnsupportedOperationException - * if the removeItem method is not supported. - */ - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Adds new Property to all Items in the Container. - * - * @param propertyId - * ID of the Property - * @param type - * Data type of the new Property - * @param defaultValue - * The value all created Properties are initialized to. - * @return <code>true</code> if the operation succeeded; <code>false</code> - * otherwise. - * @throws UnsupportedOperationException - * if the addContainerProperty method is not supported. - */ - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Removes a Property specified by the given Property ID from the Container. - * - * @param propertyId - * ID of the Property to remove - * @return <code>true</code> if the operation succeeded; <code>false</code> - * otherwise. - * @throws UnsupportedOperationException - * if the removeContainerProperty method is not supported. - */ - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Removes all Items from the Container. - * - * @return <code>true</code> if the operation succeeded; <code>false</code> - * otherwise. - * @throws UnsupportedOperationException - * if the removeAllItems method is not supported. - */ - @Override - public boolean removeAllItems() throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Adds new item after the given item. - * - * @param previousItemId - * Id of the previous item in ordered container. - * @param newItemId - * Id of the new item to be added. - * @return Returns new item or <code>null</code> if the operation fails. - * @throws UnsupportedOperationException - * if the addItemAfter method is not supported. - */ - @Override - public Item addItemAfter(Object previousItemId, Object newItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Adds new item after the given item. - * - * @param previousItemId - * Id of the previous item in ordered container. - * @return Returns item id created new item or <code>null</code> if the - * operation fails. - * @throws UnsupportedOperationException - * if the addItemAfter method is not supported. - */ - @Override - public Object addItemAfter(Object previousItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Returns id of first item in the Container. - * - * @return ID of the first Item in the list. - */ - @Override - public Object firstItemId() { - if (size < 1) { - return null; - } - return new Integer(1); - } - - /** - * Returns <code>true</code> if given id is first id at first index. - * - * @param id - * ID of an Item in the Container. - */ - @Override - public boolean isFirstId(Object id) { - return size > 0 && (id instanceof Integer) - && ((Integer) id).intValue() == 1; - } - - /** - * Returns <code>true</code> if given id is last id at last index. - * - * @param id - * ID of an Item in the Container - * - */ - @Override - public boolean isLastId(Object id) { - return size > 0 && (id instanceof Integer) - && ((Integer) id).intValue() == size; - } - - /** - * Returns id of last item in the Container. - * - * @return ID of the last Item. - */ - @Override - public Object lastItemId() { - if (size < 1) { - return null; - } - return new Integer(size); - } - - /** - * Returns id of next item in container at next index. - * - * @param id - * ID of an Item in the Container. - * @return ID of the next Item or null. - */ - @Override - public Object nextItemId(Object id) { - if (size < 1 || !(id instanceof Integer)) { - return null; - } - final int i = ((Integer) id).intValue(); - if (i >= size) { - return null; - } - return new Integer(i + 1); - } - - /** - * Returns id of previous item in container at previous index. - * - * @param id - * ID of an Item in the Container. - * @return ID of the previous Item or null. - */ - @Override - public Object prevItemId(Object id) { - if (size < 1 || !(id instanceof Integer)) { - return null; - } - final int i = ((Integer) id).intValue(); - if (i <= 1) { - return null; - } - return new Integer(i - 1); - } - - /** - * The <code>Row</code> class implements methods of Item. - * - * @author Vaadin Ltd. - * @version - * @since 4.0 - */ - class Row implements Item { - - Object id; - - private Row(Object rowId) { - id = rowId; - } - - /** - * Adds the item property. - * - * @param id - * ID of the new Property. - * @param property - * Property to be added and associated with ID. - * @return <code>true</code> if the operation succeeded; - * <code>false</code> otherwise. - * @throws UnsupportedOperationException - * if the addItemProperty method is not supported. - */ - @Override - public boolean addItemProperty(Object id, Property property) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Gets the property corresponding to the given property ID stored in - * the Item. - * - * @param propertyId - * identifier of the Property to get - * @return the Property with the given ID or <code>null</code> - */ - @Override - public Property<?> getItemProperty(Object propertyId) { - return getContainerProperty(id, propertyId); - } - - /** - * Gets the collection of property IDs stored in the Item. - * - * @return unmodifiable collection containing IDs of the Properties - * stored the Item. - */ - @Override - public Collection<String> getItemPropertyIds() { - return propertyIds; - } - - /** - * Removes given item property. - * - * @param id - * ID of the Property to be removed. - * @return <code>true</code> if the item property is removed; - * <code>false</code> otherwise. - * @throws UnsupportedOperationException - * if the removeItemProperty is not supported. - */ - @Override - public boolean removeItemProperty(Object id) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - } - - /** - * Closes the statement. - * - * @see #close() - */ - @Override - public void finalize() { - try { - close(); - } catch (final SQLException ignored) { - - } - } - - /** - * Adds the given item at the position of given index. - * - * @param index - * Index to add the new item. - * @param newItemId - * Id of the new item to be added. - * @return new item or <code>null</code> if the operation fails. - * @throws UnsupportedOperationException - * if the addItemAt is not supported. - */ - @Override - public Item addItemAt(int index, Object newItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Adds item at the position of provided index in the container. - * - * @param index - * Index to add the new item. - * @return item id created new item or <code>null</code> if the operation - * fails. - * - * @throws UnsupportedOperationException - * if the addItemAt is not supported. - */ - - @Override - public Object addItemAt(int index) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Gets the Index id in the container. - * - * @param index - * Index Id. - * @return ID in the given index. - */ - @Override - public Object getIdByIndex(int index) { - if (size < 1 || index < 0 || index >= size) { - return null; - } - return new Integer(index + 1); - } - - /** - * Gets the index of the Item corresponding to id in the container. - * - * @param id - * ID of an Item in the Container - * @return index of the Item, or -1 if the Container does not include the - * Item - */ - - @Override - public int indexOfId(Object id) { - if (size < 1 || !(id instanceof Integer)) { - return -1; - } - final int i = ((Integer) id).intValue(); - if (i >= size || i < 1) { - return -1; - } - return i - 1; - } - -} diff --git a/src/com/vaadin/data/util/TextFileProperty.java b/src/com/vaadin/data/util/TextFileProperty.java deleted file mode 100644 index 598b721a9c..0000000000 --- a/src/com/vaadin/data/util/TextFileProperty.java +++ /dev/null @@ -1,144 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.Charset; - -/** - * Property implementation for wrapping a text file. - * - * Supports reading and writing of a File from/to String. - * - * {@link ValueChangeListener}s are supported, but only fire when - * setValue(Object) is explicitly called. {@link ReadOnlyStatusChangeListener}s - * are supported but only fire when setReadOnly(boolean) is explicitly called. - * - */ -@SuppressWarnings("serial") -public class TextFileProperty extends AbstractProperty<String> { - - private File file; - private Charset charset = null; - - /** - * Wrap given file with property interface. - * - * Setting the file to null works, but getValue() will return null. - * - * @param file - * File to be wrapped. - */ - public TextFileProperty(File file) { - this.file = file; - } - - /** - * Wrap the given file with the property interface and specify character - * set. - * - * Setting the file to null works, but getValue() will return null. - * - * @param file - * File to be wrapped. - * @param charset - * Charset to be used for reading and writing the file. - */ - public TextFileProperty(File file, Charset charset) { - this.file = file; - this.charset = charset; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getType() - */ - @Override - public Class<String> getType() { - return String.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#getValue() - */ - @Override - public String getValue() { - if (file == null) { - return null; - } - try { - FileInputStream fis = new FileInputStream(file); - InputStreamReader isr = charset == null ? new InputStreamReader(fis) - : new InputStreamReader(fis, charset); - BufferedReader r = new BufferedReader(isr); - StringBuilder b = new StringBuilder(); - char buf[] = new char[8 * 1024]; - int len; - while ((len = r.read(buf)) != -1) { - b.append(buf, 0, len); - } - r.close(); - isr.close(); - fis.close(); - return b.toString(); - } catch (FileNotFoundException e) { - return null; - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#isReadOnly() - */ - @Override - public boolean isReadOnly() { - return file == null || super.isReadOnly() || !file.canWrite(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Property#setValue(java.lang.Object) - */ - @Override - public void setValue(Object newValue) throws ReadOnlyException { - if (isReadOnly()) { - throw new ReadOnlyException(); - } - if (file == null) { - return; - } - - try { - FileOutputStream fos = new FileOutputStream(file); - OutputStreamWriter osw = charset == null ? new OutputStreamWriter( - fos) : new OutputStreamWriter(fos, charset); - BufferedWriter w = new BufferedWriter(osw); - w.append(newValue.toString()); - w.flush(); - w.close(); - osw.close(); - fos.close(); - fireValueChange(); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - -} diff --git a/src/com/vaadin/data/util/TransactionalPropertyWrapper.java b/src/com/vaadin/data/util/TransactionalPropertyWrapper.java deleted file mode 100644 index d042bfaac2..0000000000 --- a/src/com/vaadin/data/util/TransactionalPropertyWrapper.java +++ /dev/null @@ -1,114 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import com.vaadin.data.Property; -import com.vaadin.data.Property.ValueChangeEvent; -import com.vaadin.data.Property.ValueChangeNotifier; - -/** - * Wrapper class that helps implement two-phase commit for a non-transactional - * property. - * - * When accessing the property through the wrapper, getting and setting the - * property value take place immediately. However, the wrapper keeps track of - * the old value of the property so that it can be set for the property in case - * of a roll-back. This can result in the underlying property value changing - * multiple times (first based on modifications made by the application, then - * back upon roll-back). - * - * Value change events on the {@link TransactionalPropertyWrapper} are only - * fired at the end of a successful transaction, whereas listeners attached to - * the underlying property may receive multiple value change events. - * - * @see com.vaadin.data.Property.Transactional - * - * @author Vaadin Ltd - * @version @version@ - * @since 7.0 - * - * @param <T> - */ -public class TransactionalPropertyWrapper<T> extends AbstractProperty<T> - implements ValueChangeNotifier, Property.Transactional<T> { - - private Property<T> wrappedProperty; - private boolean inTransaction = false; - private boolean valueChangePending; - private T valueBeforeTransaction; - - public TransactionalPropertyWrapper(Property<T> wrappedProperty) { - this.wrappedProperty = wrappedProperty; - if (wrappedProperty instanceof ValueChangeNotifier) { - ((ValueChangeNotifier) wrappedProperty) - .addListener(new ValueChangeListener() { - - @Override - public void valueChange(ValueChangeEvent event) { - fireValueChange(); - } - }); - } - } - - @Override - public Class getType() { - return wrappedProperty.getType(); - } - - @Override - public T getValue() { - return wrappedProperty.getValue(); - } - - @Override - public void setValue(Object newValue) throws ReadOnlyException { - // Causes a value change to be sent to this listener which in turn fires - // a new value change event for this property - wrappedProperty.setValue(newValue); - } - - @Override - public void startTransaction() { - inTransaction = true; - valueBeforeTransaction = getValue(); - } - - @Override - public void commit() { - endTransaction(); - } - - @Override - public void rollback() { - try { - wrappedProperty.setValue(valueBeforeTransaction); - } finally { - valueChangePending = false; - endTransaction(); - } - } - - protected void endTransaction() { - inTransaction = false; - valueBeforeTransaction = null; - if (valueChangePending) { - fireValueChange(); - } - } - - @Override - protected void fireValueChange() { - if (inTransaction) { - valueChangePending = true; - } else { - super.fireValueChange(); - } - } - - public Property<T> getWrappedProperty() { - return wrappedProperty; - } - -} diff --git a/src/com/vaadin/data/util/VaadinPropertyDescriptor.java b/src/com/vaadin/data/util/VaadinPropertyDescriptor.java deleted file mode 100644 index ee1e525540..0000000000 --- a/src/com/vaadin/data/util/VaadinPropertyDescriptor.java +++ /dev/null @@ -1,43 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util; - -import java.io.Serializable; - -import com.vaadin.data.Property; - -/** - * Property descriptor that can create a property instance for a bean. - * - * Used by {@link BeanItem} and {@link AbstractBeanContainer} to keep track of - * the set of properties of items. - * - * @param <BT> - * bean type - * - * @since 6.6 - */ -public interface VaadinPropertyDescriptor<BT> extends Serializable { - /** - * Returns the name of the property. - * - * @return - */ - public String getName(); - - /** - * Returns the type of the property. - * - * @return Class<?> - */ - public Class<?> getPropertyType(); - - /** - * Creates a new {@link Property} instance for this property for a bean. - * - * @param bean - * @return - */ - public Property<?> createProperty(BT bean); -} diff --git a/src/com/vaadin/data/util/converter/Converter.java b/src/com/vaadin/data/util/converter/Converter.java deleted file mode 100644 index b8c15e8cdc..0000000000 --- a/src/com/vaadin/data/util/converter/Converter.java +++ /dev/null @@ -1,159 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.io.Serializable; -import java.util.Locale; - -/** - * Interface that implements conversion between a model and a presentation type. - * <p> - * Typically {@link #convertToPresentation(Object, Locale)} and - * {@link #convertToModel(Object, Locale)} should be symmetric so that chaining - * these together returns the original result for all input but this is not a - * requirement. - * </p> - * <p> - * Converters must not have any side effects (never update UI from inside a - * converter). - * </p> - * <p> - * All Converters must be stateless and thread safe. - * </p> - * <p> - * If conversion of a value fails, a {@link ConversionException} is thrown. - * </p> - * - * @param <MODEL> - * The model type. Must be compatible with what - * {@link #getModelType()} returns. - * @param <PRESENTATION> - * The presentation type. Must be compatible with what - * {@link #getPresentationType()} returns. - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 7.0 - */ -public interface Converter<PRESENTATION, MODEL> extends Serializable { - - /** - * Converts the given value from target type to source type. - * <p> - * A converter can optionally use locale to do the conversion. - * </p> - * A converter should in most cases be symmetric so chaining - * {@link #convertToPresentation(Object, Locale)} and - * {@link #convertToModel(Object, Locale)} should return the original value. - * - * @param value - * The value to convert, compatible with the target type. Can be - * null - * @param locale - * The locale to use for conversion. Can be null. - * @return The converted value compatible with the source type - * @throws ConversionException - * If the value could not be converted - */ - public MODEL convertToModel(PRESENTATION value, Locale locale) - throws ConversionException; - - /** - * Converts the given value from source type to target type. - * <p> - * A converter can optionally use locale to do the conversion. - * </p> - * A converter should in most cases be symmetric so chaining - * {@link #convertToPresentation(Object, Locale)} and - * {@link #convertToModel(Object, Locale)} should return the original value. - * - * @param value - * The value to convert, compatible with the target type. Can be - * null - * @param locale - * The locale to use for conversion. Can be null. - * @return The converted value compatible with the source type - * @throws ConversionException - * If the value could not be converted - */ - public PRESENTATION convertToPresentation(MODEL value, Locale locale) - throws ConversionException; - - /** - * The source type of the converter. - * - * Values of this type can be passed to - * {@link #convertToPresentation(Object, Locale)}. - * - * @return The source type - */ - public Class<MODEL> getModelType(); - - /** - * The target type of the converter. - * - * Values of this type can be passed to - * {@link #convertToModel(Object, Locale)}. - * - * @return The target type - */ - public Class<PRESENTATION> getPresentationType(); - - /** - * An exception that signals that the value passed to - * {@link Converter#convertToPresentation(Object, Locale)} or - * {@link Converter#convertToModel(Object, Locale)} could not be converted. - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ - public static class ConversionException extends RuntimeException { - - /** - * Constructs a new <code>ConversionException</code> without a detail - * message. - */ - public ConversionException() { - } - - /** - * Constructs a new <code>ConversionException</code> with the specified - * detail message. - * - * @param msg - * the detail message - */ - public ConversionException(String msg) { - super(msg); - } - - /** - * Constructs a new {@code ConversionException} with the specified - * cause. - * - * @param cause - * The cause of the the exception - */ - public ConversionException(Throwable cause) { - super(cause); - } - - /** - * Constructs a new <code>ConversionException</code> with the specified - * detail message and cause. - * - * @param message - * the detail message - * @param cause - * The cause of the the exception - */ - public ConversionException(String message, Throwable cause) { - super(message, cause); - } - } - -} diff --git a/src/com/vaadin/data/util/converter/ConverterFactory.java b/src/com/vaadin/data/util/converter/ConverterFactory.java deleted file mode 100644 index ed4ab41ac0..0000000000 --- a/src/com/vaadin/data/util/converter/ConverterFactory.java +++ /dev/null @@ -1,23 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.io.Serializable; - -/** - * Factory interface for providing Converters based on a presentation type and a - * model type. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 7.0 - * - */ -public interface ConverterFactory extends Serializable { - public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> createConverter( - Class<PRESENTATION> presentationType, Class<MODEL> modelType); - -} diff --git a/src/com/vaadin/data/util/converter/ConverterUtil.java b/src/com/vaadin/data/util/converter/ConverterUtil.java deleted file mode 100644 index 7011496ed7..0000000000 --- a/src/com/vaadin/data/util/converter/ConverterUtil.java +++ /dev/null @@ -1,168 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.converter; - -import java.io.Serializable; -import java.util.Locale; - -import com.vaadin.Application; - -public class ConverterUtil implements Serializable { - - /** - * Finds a converter that can convert from the given presentation type to - * the given model type and back. Uses the given application to find a - * {@link ConverterFactory} or, if application is null, uses the - * {@link Application#getCurrent()}. - * - * @param <PRESENTATIONTYPE> - * The presentation type - * @param <MODELTYPE> - * The model type - * @param presentationType - * The presentation type - * @param modelType - * The model type - * @param application - * The application to use to find a ConverterFactory or null to - * use the current application - * @return A Converter capable of converting between the given types or null - * if no converter was found - */ - public static <PRESENTATIONTYPE, MODELTYPE> Converter<PRESENTATIONTYPE, MODELTYPE> getConverter( - Class<PRESENTATIONTYPE> presentationType, - Class<MODELTYPE> modelType, Application application) { - Converter<PRESENTATIONTYPE, MODELTYPE> converter = null; - if (application == null) { - application = Application.getCurrent(); - } - - if (application != null) { - ConverterFactory factory = application.getConverterFactory(); - converter = factory.createConverter(presentationType, modelType); - } - return converter; - - } - - /** - * Convert the given value from the data source type to the UI type. - * - * @param modelValue - * The model value to convert - * @param presentationType - * The type of the presentation value - * @param converter - * The converter to (try to) use - * @param locale - * The locale to use for conversion - * @param <PRESENTATIONTYPE> - * Presentation type - * - * @return The converted value, compatible with the presentation type, or - * the original value if its type is compatible and no converter is - * set. - * @throws Converter.ConversionException - * if there is no converter and the type is not compatible with - * the model type. - */ - @SuppressWarnings("unchecked") - public static <PRESENTATIONTYPE, MODELTYPE> PRESENTATIONTYPE convertFromModel( - MODELTYPE modelValue, - Class<? extends PRESENTATIONTYPE> presentationType, - Converter<PRESENTATIONTYPE, MODELTYPE> converter, Locale locale) - throws Converter.ConversionException { - if (converter != null) { - return converter.convertToPresentation(modelValue, locale); - } - if (modelValue == null) { - return null; - } - - if (presentationType.isAssignableFrom(modelValue.getClass())) { - return (PRESENTATIONTYPE) modelValue; - } else { - throw new Converter.ConversionException( - "Unable to convert value of type " - + modelValue.getClass().getName() - + " to presentation type " - + presentationType - + ". No converter is set and the types are not compatible."); - } - } - - /** - * @param <MODELTYPE> - * @param <PRESENTATIONTYPE> - * @param presentationValue - * @param modelType - * @param converter - * @param locale - * @return - * @throws Converter.ConversionException - */ - public static <MODELTYPE, PRESENTATIONTYPE> MODELTYPE convertToModel( - PRESENTATIONTYPE presentationValue, Class<MODELTYPE> modelType, - Converter<PRESENTATIONTYPE, MODELTYPE> converter, Locale locale) - throws Converter.ConversionException { - if (converter != null) { - /* - * If there is a converter, always use it. It must convert or throw - * an exception. - */ - return converter.convertToModel(presentationValue, locale); - } - - if (presentationValue == null) { - // Null should always be passed through the converter but if there - // is no converter we can safely return null - return null; - } - - if (modelType == null) { - // No model type, return original value - return (MODELTYPE) presentationValue; - } else if (modelType.isAssignableFrom(presentationValue.getClass())) { - // presentation type directly compatible with model type - return modelType.cast(presentationValue); - } else { - throw new Converter.ConversionException( - "Unable to convert value of type " - + presentationValue.getClass().getName() - + " to model type " - + modelType - + ". No converter is set and the types are not compatible."); - } - - } - - /** - * Checks if the given converter can handle conversion between the given - * presentation and model type - * - * @param converter - * The converter to check - * @param presentationType - * The presentation type - * @param modelType - * The model type - * @return true if the converter supports conversion between the given - * presentation and model type, false otherwise - */ - public static boolean canConverterHandle(Converter<?, ?> converter, - Class<?> presentationType, Class<?> modelType) { - if (converter == null) { - return false; - } - - if (!modelType.isAssignableFrom(converter.getModelType())) { - return false; - } - if (!presentationType.isAssignableFrom(converter.getPresentationType())) { - return false; - } - - return true; - } -} diff --git a/src/com/vaadin/data/util/converter/DateToLongConverter.java b/src/com/vaadin/data/util/converter/DateToLongConverter.java deleted file mode 100644 index aeba38aa1f..0000000000 --- a/src/com/vaadin/data/util/converter/DateToLongConverter.java +++ /dev/null @@ -1,72 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.util.Date; -import java.util.Locale; - -/** - * A converter that converts from {@link Long} to {@link Date} and back. - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class DateToLongConverter implements Converter<Date, Long> { - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, - * java.util.Locale) - */ - @Override - public Long convertToModel(Date value, Locale locale) { - if (value == null) { - return null; - } - - return value.getTime(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public Date convertToPresentation(Long value, Locale locale) { - if (value == null) { - return null; - } - - return new Date(value); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getModelType() - */ - @Override - public Class<Long> getModelType() { - return Long.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class<Date> getPresentationType() { - return Date.class; - } - -} diff --git a/src/com/vaadin/data/util/converter/DefaultConverterFactory.java b/src/com/vaadin/data/util/converter/DefaultConverterFactory.java deleted file mode 100644 index afb95d81ed..0000000000 --- a/src/com/vaadin/data/util/converter/DefaultConverterFactory.java +++ /dev/null @@ -1,101 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.util.Date; -import java.util.logging.Logger; - -import com.vaadin.Application; - -/** - * Default implementation of {@link ConverterFactory}. Provides converters for - * standard types like {@link String}, {@link Double} and {@link Date}. </p> - * <p> - * Custom converters can be provided by extending this class and using - * {@link Application#setConverterFactory(ConverterFactory)}. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class DefaultConverterFactory implements ConverterFactory { - - private final static Logger log = Logger - .getLogger(DefaultConverterFactory.class.getName()); - - @Override - public <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> createConverter( - Class<PRESENTATION> presentationType, Class<MODEL> modelType) { - Converter<PRESENTATION, MODEL> converter = findConverter( - presentationType, modelType); - if (converter != null) { - log.finest(getClass().getName() + " created a " - + converter.getClass()); - return converter; - } - - // Try to find a reverse converter - Converter<MODEL, PRESENTATION> reverseConverter = findConverter( - modelType, presentationType); - if (reverseConverter != null) { - log.finest(getClass().getName() + " created a reverse " - + reverseConverter.getClass()); - return new ReverseConverter<PRESENTATION, MODEL>(reverseConverter); - } - - log.finest(getClass().getName() + " could not find a converter for " - + presentationType.getName() + " to " + modelType.getName() - + " conversion"); - return null; - - } - - protected <PRESENTATION, MODEL> Converter<PRESENTATION, MODEL> findConverter( - Class<PRESENTATION> presentationType, Class<MODEL> modelType) { - if (presentationType == String.class) { - // TextField converters and more - Converter<PRESENTATION, MODEL> converter = (Converter<PRESENTATION, MODEL>) createStringConverter(modelType); - if (converter != null) { - return converter; - } - } else if (presentationType == Date.class) { - // DateField converters and more - Converter<PRESENTATION, MODEL> converter = (Converter<PRESENTATION, MODEL>) createDateConverter(modelType); - if (converter != null) { - return converter; - } - } - - return null; - - } - - protected Converter<Date, ?> createDateConverter(Class<?> sourceType) { - if (Long.class.isAssignableFrom(sourceType)) { - return new DateToLongConverter(); - } else { - return null; - } - } - - protected Converter<String, ?> createStringConverter(Class<?> sourceType) { - if (Double.class.isAssignableFrom(sourceType)) { - return new StringToDoubleConverter(); - } else if (Integer.class.isAssignableFrom(sourceType)) { - return new StringToIntegerConverter(); - } else if (Boolean.class.isAssignableFrom(sourceType)) { - return new StringToBooleanConverter(); - } else if (Number.class.isAssignableFrom(sourceType)) { - return new StringToNumberConverter(); - } else if (Date.class.isAssignableFrom(sourceType)) { - return new StringToDateConverter(); - } else { - return null; - } - } - -} diff --git a/src/com/vaadin/data/util/converter/ReverseConverter.java b/src/com/vaadin/data/util/converter/ReverseConverter.java deleted file mode 100644 index fa1bb5daf1..0000000000 --- a/src/com/vaadin/data/util/converter/ReverseConverter.java +++ /dev/null @@ -1,84 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.util.Locale; - -/** - * A converter that wraps another {@link Converter} and reverses source and - * target types. - * - * @param <MODEL> - * The source type - * @param <PRESENTATION> - * The target type - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class ReverseConverter<PRESENTATION, MODEL> implements - Converter<PRESENTATION, MODEL> { - - private Converter<MODEL, PRESENTATION> realConverter; - - /** - * Creates a converter from source to target based on a converter that - * converts from target to source. - * - * @param converter - * The converter to use in a reverse fashion - */ - public ReverseConverter(Converter<MODEL, PRESENTATION> converter) { - this.realConverter = converter; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#convertToModel(java - * .lang.Object, java.util.Locale) - */ - @Override - public MODEL convertToModel(PRESENTATION value, Locale locale) - throws com.vaadin.data.util.converter.Converter.ConversionException { - return realConverter.convertToPresentation(value, locale); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public PRESENTATION convertToPresentation(MODEL value, Locale locale) - throws com.vaadin.data.util.converter.Converter.ConversionException { - return realConverter.convertToModel(value, locale); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getSourceType() - */ - @Override - public Class<MODEL> getModelType() { - return realConverter.getPresentationType(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getTargetType() - */ - @Override - public Class<PRESENTATION> getPresentationType() { - return realConverter.getModelType(); - } - -} diff --git a/src/com/vaadin/data/util/converter/StringToBooleanConverter.java b/src/com/vaadin/data/util/converter/StringToBooleanConverter.java deleted file mode 100644 index 999f575dc4..0000000000 --- a/src/com/vaadin/data/util/converter/StringToBooleanConverter.java +++ /dev/null @@ -1,108 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.util.Locale; - -/** - * A converter that converts from {@link String} to {@link Boolean} and back. - * The String representation is given by Boolean.toString(). - * <p> - * Leading and trailing white spaces are ignored when converting from a String. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class StringToBooleanConverter implements Converter<String, Boolean> { - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, - * java.util.Locale) - */ - @Override - public Boolean convertToModel(String value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - if (getTrueString().equals(value)) { - return true; - } else if (getFalseString().equals(value)) { - return false; - } else { - throw new ConversionException("Cannot convert " + value + " to " - + getModelType().getName()); - } - } - - /** - * Gets the string representation for true. Default is "true". - * - * @return the string representation for true - */ - protected String getTrueString() { - return Boolean.TRUE.toString(); - } - - /** - * Gets the string representation for false. Default is "false". - * - * @return the string representation for false - */ - protected String getFalseString() { - return Boolean.FALSE.toString(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public String convertToPresentation(Boolean value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - if (value) { - return getTrueString(); - } else { - return getFalseString(); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getModelType() - */ - @Override - public Class<Boolean> getModelType() { - return Boolean.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class<String> getPresentationType() { - return String.class; - } - -} diff --git a/src/com/vaadin/data/util/converter/StringToDateConverter.java b/src/com/vaadin/data/util/converter/StringToDateConverter.java deleted file mode 100644 index 487b02b2aa..0000000000 --- a/src/com/vaadin/data/util/converter/StringToDateConverter.java +++ /dev/null @@ -1,112 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.text.DateFormat; -import java.text.ParsePosition; -import java.util.Date; -import java.util.Locale; - -/** - * A converter that converts from {@link Date} to {@link String} and back. Uses - * the given locale and {@link DateFormat} for formatting and parsing. - * <p> - * Leading and trailing white spaces are ignored when converting from a String. - * </p> - * <p> - * Override and overwrite {@link #getFormat(Locale)} to use a different format. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class StringToDateConverter implements Converter<String, Date> { - - /** - * Returns the format used by {@link #convertToPresentation(Date, Locale)} - * and {@link #convertToModel(String, Locale)}. - * - * @param locale - * The locale to use - * @return A DateFormat instance - */ - protected DateFormat getFormat(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - - DateFormat f = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, - DateFormat.MEDIUM, locale); - f.setLenient(false); - return f; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, - * java.util.Locale) - */ - @Override - public Date convertToModel(String value, Locale locale) - throws com.vaadin.data.util.converter.Converter.ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - ParsePosition parsePosition = new ParsePosition(0); - Date parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - - return parsedValue; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public String convertToPresentation(Date value, Locale locale) - throws com.vaadin.data.util.converter.Converter.ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getModelType() - */ - @Override - public Class<Date> getModelType() { - return Date.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class<String> getPresentationType() { - return String.class; - } - -} diff --git a/src/com/vaadin/data/util/converter/StringToDoubleConverter.java b/src/com/vaadin/data/util/converter/StringToDoubleConverter.java deleted file mode 100644 index 251f91855b..0000000000 --- a/src/com/vaadin/data/util/converter/StringToDoubleConverter.java +++ /dev/null @@ -1,107 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.text.NumberFormat; -import java.text.ParsePosition; -import java.util.Locale; - -/** - * A converter that converts from {@link String} to {@link Double} and back. - * Uses the given locale and a {@link NumberFormat} instance for formatting and - * parsing. - * <p> - * Leading and trailing white spaces are ignored when converting from a String. - * </p> - * <p> - * Override and overwrite {@link #getFormat(Locale)} to use a different format. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class StringToDoubleConverter implements Converter<String, Double> { - - /** - * Returns the format used by {@link #convertToPresentation(Double, Locale)} - * and {@link #convertToModel(String, Locale)}. - * - * @param locale - * The locale to use - * @return A NumberFormat instance - */ - protected NumberFormat getFormat(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - - return NumberFormat.getNumberInstance(locale); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, - * java.util.Locale) - */ - @Override - public Double convertToModel(String value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - ParsePosition parsePosition = new ParsePosition(0); - Number parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - return parsedValue.doubleValue(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public String convertToPresentation(Double value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getModelType() - */ - @Override - public Class<Double> getModelType() { - return Double.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class<String> getPresentationType() { - return String.class; - } -} diff --git a/src/com/vaadin/data/util/converter/StringToIntegerConverter.java b/src/com/vaadin/data/util/converter/StringToIntegerConverter.java deleted file mode 100644 index 950f01c6ab..0000000000 --- a/src/com/vaadin/data/util/converter/StringToIntegerConverter.java +++ /dev/null @@ -1,88 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.text.NumberFormat; -import java.text.ParsePosition; -import java.util.Locale; - -/** - * A converter that converts from {@link String} to {@link Integer} and back. - * Uses the given locale and a {@link NumberFormat} instance for formatting and - * parsing. - * <p> - * Override and overwrite {@link #getFormat(Locale)} to use a different format. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class StringToIntegerConverter implements Converter<String, Integer> { - - /** - * Returns the format used by - * {@link #convertToPresentation(Integer, Locale)} and - * {@link #convertToModel(String, Locale)}. - * - * @param locale - * The locale to use - * @return A NumberFormat instance - */ - protected NumberFormat getFormat(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - return NumberFormat.getIntegerInstance(locale); - } - - @Override - public Integer convertToModel(String value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - // Parse and detect errors. If the full string was not used, it is - // an error. - ParsePosition parsePosition = new ParsePosition(0); - Number parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - - if (parsedValue == null) { - // Convert "" to null - return null; - } - return parsedValue.intValue(); - } - - @Override - public String convertToPresentation(Integer value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); - } - - @Override - public Class<Integer> getModelType() { - return Integer.class; - } - - @Override - public Class<String> getPresentationType() { - return String.class; - } - -} diff --git a/src/com/vaadin/data/util/converter/StringToNumberConverter.java b/src/com/vaadin/data/util/converter/StringToNumberConverter.java deleted file mode 100644 index 42699a326a..0000000000 --- a/src/com/vaadin/data/util/converter/StringToNumberConverter.java +++ /dev/null @@ -1,111 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.util.converter; - -import java.text.NumberFormat; -import java.text.ParsePosition; -import java.util.Locale; - -/** - * A converter that converts from {@link Number} to {@link String} and back. - * Uses the given locale and {@link NumberFormat} for formatting and parsing. - * <p> - * Override and overwrite {@link #getFormat(Locale)} to use a different format. - * </p> - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 7.0 - */ -public class StringToNumberConverter implements Converter<String, Number> { - - /** - * Returns the format used by {@link #convertToPresentation(Number, Locale)} - * and {@link #convertToModel(String, Locale)}. - * - * @param locale - * The locale to use - * @return A NumberFormat instance - */ - protected NumberFormat getFormat(Locale locale) { - if (locale == null) { - locale = Locale.getDefault(); - } - - return NumberFormat.getNumberInstance(locale); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToModel(java.lang.Object, - * java.util.Locale) - */ - @Override - public Number convertToModel(String value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - // Remove leading and trailing white space - value = value.trim(); - - // Parse and detect errors. If the full string was not used, it is - // an error. - ParsePosition parsePosition = new ParsePosition(0); - Number parsedValue = getFormat(locale).parse(value, parsePosition); - if (parsePosition.getIndex() != value.length()) { - throw new ConversionException("Could not convert '" + value - + "' to " + getModelType().getName()); - } - - if (parsedValue == null) { - // Convert "" to null - return null; - } - return parsedValue; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.converter.Converter#convertToPresentation(java.lang - * .Object, java.util.Locale) - */ - @Override - public String convertToPresentation(Number value, Locale locale) - throws ConversionException { - if (value == null) { - return null; - } - - return getFormat(locale).format(value); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getModelType() - */ - @Override - public Class<Number> getModelType() { - return Number.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.converter.Converter#getPresentationType() - */ - @Override - public Class<String> getPresentationType() { - return String.class; - } - -} diff --git a/src/com/vaadin/data/util/filter/AbstractJunctionFilter.java b/src/com/vaadin/data/util/filter/AbstractJunctionFilter.java deleted file mode 100644 index 482b10120c..0000000000 --- a/src/com/vaadin/data/util/filter/AbstractJunctionFilter.java +++ /dev/null @@ -1,76 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; - -import com.vaadin.data.Container.Filter; - -/** - * Abstract base class for filters that are composed of multiple sub-filters. - * - * The method {@link #appliesToProperty(Object)} is provided to help - * implementing {@link Filter} for in-memory filters. - * - * @since 6.6 - */ -public abstract class AbstractJunctionFilter implements Filter { - - protected final Collection<Filter> filters; - - public AbstractJunctionFilter(Filter... filters) { - this.filters = Collections.unmodifiableCollection(Arrays - .asList(filters)); - } - - /** - * Returns an unmodifiable collection of the sub-filters of this composite - * filter. - * - * @return - */ - public Collection<Filter> getFilters() { - return filters; - } - - /** - * Returns true if a change in the named property may affect the filtering - * result. If some of the sub-filters are not in-memory filters, true is - * returned. - * - * By default, all sub-filters are iterated to check if any of them applies. - * If there are no sub-filters, false is returned - override in subclasses - * to change this behavior. - */ - @Override - public boolean appliesToProperty(Object propertyId) { - for (Filter filter : getFilters()) { - if (filter.appliesToProperty(propertyId)) { - return true; - } - } - return false; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !getClass().equals(obj.getClass())) { - return false; - } - AbstractJunctionFilter other = (AbstractJunctionFilter) obj; - // contents comparison with equals() - return Arrays.equals(filters.toArray(), other.filters.toArray()); - } - - @Override - public int hashCode() { - int hash = getFilters().size(); - for (Filter filter : filters) { - hash = (hash << 1) ^ filter.hashCode(); - } - return hash; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/data/util/filter/And.java b/src/com/vaadin/data/util/filter/And.java deleted file mode 100644 index ca6c35aba7..0000000000 --- a/src/com/vaadin/data/util/filter/And.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; - -/** - * A compound {@link Filter} that accepts an item if all of its filters accept - * the item. - * - * If no filters are given, the filter should accept all items. - * - * This filter also directly supports in-memory filtering when all sub-filters - * do so. - * - * @see Or - * - * @since 6.6 - */ -public final class And extends AbstractJunctionFilter { - - /** - * - * @param filters - * filters of which the And filter will be composed - */ - public And(Filter... filters) { - super(filters); - } - - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedFilterException { - for (Filter filter : getFilters()) { - if (!filter.passesFilter(itemId, item)) { - return false; - } - } - return true; - } - -} diff --git a/src/com/vaadin/data/util/filter/Between.java b/src/com/vaadin/data/util/filter/Between.java deleted file mode 100644 index b00a74d13d..0000000000 --- a/src/com/vaadin/data/util/filter/Between.java +++ /dev/null @@ -1,74 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; - -public class Between implements Filter { - - private final Object propertyId; - private final Comparable startValue; - private final Comparable endValue; - - public Between(Object propertyId, Comparable startValue, Comparable endValue) { - this.propertyId = propertyId; - this.startValue = startValue; - this.endValue = endValue; - } - - public Object getPropertyId() { - return propertyId; - } - - public Comparable<?> getStartValue() { - return startValue; - } - - public Comparable<?> getEndValue() { - return endValue; - } - - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedOperationException { - Object value = item.getItemProperty(getPropertyId()).getValue(); - if (value instanceof Comparable) { - Comparable cval = (Comparable) value; - return cval.compareTo(getStartValue()) >= 0 - && cval.compareTo(getEndValue()) <= 0; - } - return false; - } - - @Override - public boolean appliesToProperty(Object propertyId) { - return getPropertyId() != null && getPropertyId().equals(propertyId); - } - - @Override - public int hashCode() { - return getPropertyId().hashCode() + getStartValue().hashCode() - + getEndValue().hashCode(); - } - - @Override - public boolean equals(Object obj) { - // Only objects of the same class can be equal - if (!getClass().equals(obj.getClass())) { - return false; - } - final Between o = (Between) obj; - - // Checks the properties one by one - boolean propertyIdEqual = (null != getPropertyId()) ? getPropertyId() - .equals(o.getPropertyId()) : null == o.getPropertyId(); - boolean startValueEqual = (null != getStartValue()) ? getStartValue() - .equals(o.getStartValue()) : null == o.getStartValue(); - boolean endValueEqual = (null != getEndValue()) ? getEndValue().equals( - o.getEndValue()) : null == o.getEndValue(); - return propertyIdEqual && startValueEqual && endValueEqual; - - } -} diff --git a/src/com/vaadin/data/util/filter/Compare.java b/src/com/vaadin/data/util/filter/Compare.java deleted file mode 100644 index 4091f5b922..0000000000 --- a/src/com/vaadin/data/util/filter/Compare.java +++ /dev/null @@ -1,327 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * Simple container filter comparing an item property value against a given - * constant value. Use the nested classes {@link Equal}, {@link Greater}, - * {@link Less}, {@link GreaterOrEqual} and {@link LessOrEqual} instead of this - * class directly. - * - * This filter also directly supports in-memory filtering. - * - * The reference and actual values must implement {@link Comparable} and the - * class of the actual property value must be assignable from the class of the - * reference value. - * - * @since 6.6 - */ -public abstract class Compare implements Filter { - - public enum Operation { - EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL - }; - - private final Object propertyId; - private final Operation operation; - private final Object value; - - /** - * A {@link Compare} filter that accepts items for which the identified - * property value is equal to <code>value</code>. - * - * For in-memory filters, equals() is used for the comparison. For other - * containers, the comparison implementation is container dependent and may - * use e.g. database comparison operations. - * - * @since 6.6 - */ - public static final class Equal extends Compare { - /** - * Construct a filter that accepts items for which the identified - * property value is equal to <code>value</code>. - * - * For in-memory filters, equals() is used for the comparison. For other - * containers, the comparison implementation is container dependent and - * may use e.g. database comparison operations. - * - * @param propertyId - * the identifier of the property whose value to compare - * against value, not null - * @param value - * the value to compare against - null values may or may not - * be supported depending on the container - */ - public Equal(Object propertyId, Object value) { - super(propertyId, value, Operation.EQUAL); - } - } - - /** - * A {@link Compare} filter that accepts items for which the identified - * property value is greater than <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} and - * {@link Comparable#compareTo(Object)} is used for the comparison. For - * other containers, the comparison implementation is container dependent - * and may use e.g. database comparison operations. - * - * @since 6.6 - */ - public static final class Greater extends Compare { - /** - * Construct a filter that accepts items for which the identified - * property value is greater than <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} - * and {@link Comparable#compareTo(Object)} is used for the comparison. - * For other containers, the comparison implementation is container - * dependent and may use e.g. database comparison operations. - * - * @param propertyId - * the identifier of the property whose value to compare - * against value, not null - * @param value - * the value to compare against - null values may or may not - * be supported depending on the container - */ - public Greater(Object propertyId, Object value) { - super(propertyId, value, Operation.GREATER); - } - } - - /** - * A {@link Compare} filter that accepts items for which the identified - * property value is less than <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} and - * {@link Comparable#compareTo(Object)} is used for the comparison. For - * other containers, the comparison implementation is container dependent - * and may use e.g. database comparison operations. - * - * @since 6.6 - */ - public static final class Less extends Compare { - /** - * Construct a filter that accepts items for which the identified - * property value is less than <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} - * and {@link Comparable#compareTo(Object)} is used for the comparison. - * For other containers, the comparison implementation is container - * dependent and may use e.g. database comparison operations. - * - * @param propertyId - * the identifier of the property whose value to compare - * against value, not null - * @param value - * the value to compare against - null values may or may not - * be supported depending on the container - */ - public Less(Object propertyId, Object value) { - super(propertyId, value, Operation.LESS); - } - } - - /** - * A {@link Compare} filter that accepts items for which the identified - * property value is greater than or equal to <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} and - * {@link Comparable#compareTo(Object)} is used for the comparison. For - * other containers, the comparison implementation is container dependent - * and may use e.g. database comparison operations. - * - * @since 6.6 - */ - public static final class GreaterOrEqual extends Compare { - /** - * Construct a filter that accepts items for which the identified - * property value is greater than or equal to <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} - * and {@link Comparable#compareTo(Object)} is used for the comparison. - * For other containers, the comparison implementation is container - * dependent and may use e.g. database comparison operations. - * - * @param propertyId - * the identifier of the property whose value to compare - * against value, not null - * @param value - * the value to compare against - null values may or may not - * be supported depending on the container - */ - public GreaterOrEqual(Object propertyId, Object value) { - super(propertyId, value, Operation.GREATER_OR_EQUAL); - } - } - - /** - * A {@link Compare} filter that accepts items for which the identified - * property value is less than or equal to <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} and - * {@link Comparable#compareTo(Object)} is used for the comparison. For - * other containers, the comparison implementation is container dependent - * and may use e.g. database comparison operations. - * - * @since 6.6 - */ - public static final class LessOrEqual extends Compare { - /** - * Construct a filter that accepts items for which the identified - * property value is less than or equal to <code>value</code>. - * - * For in-memory filters, the values must implement {@link Comparable} - * and {@link Comparable#compareTo(Object)} is used for the comparison. - * For other containers, the comparison implementation is container - * dependent and may use e.g. database comparison operations. - * - * @param propertyId - * the identifier of the property whose value to compare - * against value, not null - * @param value - * the value to compare against - null values may or may not - * be supported depending on the container - */ - public LessOrEqual(Object propertyId, Object value) { - super(propertyId, value, Operation.LESS_OR_EQUAL); - } - } - - /** - * Constructor for a {@link Compare} filter that compares the value of an - * item property with the given constant <code>value</code>. - * - * This constructor is intended to be used by the nested static classes only - * ({@link Equal}, {@link Greater}, {@link Less}, {@link GreaterOrEqual}, - * {@link LessOrEqual}). - * - * For in-memory filtering, comparisons except EQUAL require that the values - * implement {@link Comparable} and {@link Comparable#compareTo(Object)} is - * used for the comparison. The equality comparison is performed using - * {@link Object#equals(Object)}. - * - * For other containers, the comparison implementation is container - * dependent and may use e.g. database comparison operations. Therefore, the - * behavior of comparisons might differ in some cases between in-memory and - * other containers. - * - * @param propertyId - * the identifier of the property whose value to compare against - * value, not null - * @param value - * the value to compare against - null values may or may not be - * supported depending on the container - * @param operation - * the comparison {@link Operation} to use - */ - Compare(Object propertyId, Object value, Operation operation) { - this.propertyId = propertyId; - this.value = value; - this.operation = operation; - } - - @Override - public boolean passesFilter(Object itemId, Item item) { - final Property<?> p = item.getItemProperty(getPropertyId()); - if (null == p) { - return false; - } - Object value = p.getValue(); - switch (getOperation()) { - case EQUAL: - return (null == this.value) ? (null == value) : this.value - .equals(value); - case GREATER: - return compareValue(value) > 0; - case LESS: - return compareValue(value) < 0; - case GREATER_OR_EQUAL: - return compareValue(value) >= 0; - case LESS_OR_EQUAL: - return compareValue(value) <= 0; - } - // all cases should have been processed above - return false; - } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - protected int compareValue(Object value1) { - if (null == value) { - return null == value1 ? 0 : -1; - } else if (null == value1) { - return 1; - } else if (getValue() instanceof Comparable - && value1.getClass().isAssignableFrom(getValue().getClass())) { - return -((Comparable) getValue()).compareTo(value1); - } - throw new IllegalArgumentException("Could not compare the arguments: " - + value1 + ", " + getValue()); - } - - @Override - public boolean appliesToProperty(Object propertyId) { - return getPropertyId().equals(propertyId); - } - - @Override - public boolean equals(Object obj) { - - // Only objects of the same class can be equal - if (!getClass().equals(obj.getClass())) { - return false; - } - final Compare o = (Compare) obj; - - // Checks the properties one by one - if (getPropertyId() != o.getPropertyId() && null != o.getPropertyId() - && !o.getPropertyId().equals(getPropertyId())) { - return false; - } - if (getOperation() != o.getOperation()) { - return false; - } - return (null == getValue()) ? null == o.getValue() : getValue().equals( - o.getValue()); - } - - @Override - public int hashCode() { - return (null != getPropertyId() ? getPropertyId().hashCode() : 0) - ^ (null != getValue() ? getValue().hashCode() : 0); - } - - /** - * Returns the property id of the property to compare against the fixed - * value. - * - * @return property id (not null) - */ - public Object getPropertyId() { - return propertyId; - } - - /** - * Returns the comparison operation. - * - * @return {@link Operation} - */ - public Operation getOperation() { - return operation; - } - - /** - * Returns the value to compare the property against. - * - * @return comparison reference value - */ - public Object getValue() { - return value; - } -} diff --git a/src/com/vaadin/data/util/filter/IsNull.java b/src/com/vaadin/data/util/filter/IsNull.java deleted file mode 100644 index 3faf4153ee..0000000000 --- a/src/com/vaadin/data/util/filter/IsNull.java +++ /dev/null @@ -1,79 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * Simple container filter checking whether an item property value is null. - * - * This filter also directly supports in-memory filtering. - * - * @since 6.6 - */ -public final class IsNull implements Filter { - - private final Object propertyId; - - /** - * Constructor for a filter that compares the value of an item property with - * null. - * - * For in-memory filtering, a simple == check is performed. For other - * containers, the comparison implementation is container dependent but - * should correspond to the in-memory null check. - * - * @param propertyId - * the identifier (not null) of the property whose value to check - */ - public IsNull(Object propertyId) { - this.propertyId = propertyId; - } - - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedOperationException { - final Property<?> p = item.getItemProperty(getPropertyId()); - if (null == p) { - return false; - } - return null == p.getValue(); - } - - @Override - public boolean appliesToProperty(Object propertyId) { - return getPropertyId().equals(propertyId); - } - - @Override - public boolean equals(Object obj) { - // Only objects of the same class can be equal - if (!getClass().equals(obj.getClass())) { - return false; - } - final IsNull o = (IsNull) obj; - - // Checks the properties one by one - return (null != getPropertyId()) ? getPropertyId().equals( - o.getPropertyId()) : null == o.getPropertyId(); - } - - @Override - public int hashCode() { - return (null != getPropertyId() ? getPropertyId().hashCode() : 0); - } - - /** - * Returns the property id of the property tested by the filter, not null - * for valid filters. - * - * @return property id (not null) - */ - public Object getPropertyId() { - return propertyId; - } - -} diff --git a/src/com/vaadin/data/util/filter/Like.java b/src/com/vaadin/data/util/filter/Like.java deleted file mode 100644 index 3dcc48e809..0000000000 --- a/src/com/vaadin/data/util/filter/Like.java +++ /dev/null @@ -1,83 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; - -public class Like implements Filter { - private final Object propertyId; - private final String value; - private boolean caseSensitive; - - public Like(String propertyId, String value) { - this(propertyId, value, true); - } - - public Like(String propertyId, String value, boolean caseSensitive) { - this.propertyId = propertyId; - this.value = value; - setCaseSensitive(caseSensitive); - } - - public Object getPropertyId() { - return propertyId; - } - - public String getValue() { - return value; - } - - public void setCaseSensitive(boolean caseSensitive) { - this.caseSensitive = caseSensitive; - } - - public boolean isCaseSensitive() { - return caseSensitive; - } - - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedOperationException { - if (!item.getItemProperty(getPropertyId()).getType() - .isAssignableFrom(String.class)) { - // We can only handle strings - return false; - } - String colValue = (String) item.getItemProperty(getPropertyId()) - .getValue(); - - String pattern = getValue().replace("%", ".*"); - if (isCaseSensitive()) { - return colValue.matches(pattern); - } - return colValue.toUpperCase().matches(pattern.toUpperCase()); - } - - @Override - public boolean appliesToProperty(Object propertyId) { - return getPropertyId() != null && getPropertyId().equals(propertyId); - } - - @Override - public int hashCode() { - return getPropertyId().hashCode() + getValue().hashCode(); - } - - @Override - public boolean equals(Object obj) { - // Only objects of the same class can be equal - if (!getClass().equals(obj.getClass())) { - return false; - } - final Like o = (Like) obj; - - // Checks the properties one by one - boolean propertyIdEqual = (null != getPropertyId()) ? getPropertyId() - .equals(o.getPropertyId()) : null == o.getPropertyId(); - boolean valueEqual = (null != getValue()) ? getValue().equals( - o.getValue()) : null == o.getValue(); - return propertyIdEqual && valueEqual; - } -} diff --git a/src/com/vaadin/data/util/filter/Not.java b/src/com/vaadin/data/util/filter/Not.java deleted file mode 100644 index bbfc9ca86a..0000000000 --- a/src/com/vaadin/data/util/filter/Not.java +++ /dev/null @@ -1,70 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; - -/** - * Negating filter that accepts the items rejected by another filter. - * - * This filter directly supports in-memory filtering when the negated filter - * does so. - * - * @since 6.6 - */ -public final class Not implements Filter { - private final Filter filter; - - /** - * Constructs a filter that negates a filter. - * - * @param filter - * {@link Filter} to negate, not-null - */ - public Not(Filter filter) { - this.filter = filter; - } - - /** - * Returns the negated filter. - * - * @return Filter - */ - public Filter getFilter() { - return filter; - } - - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedOperationException { - return !filter.passesFilter(itemId, item); - } - - /** - * Returns true if a change in the named property may affect the filtering - * result. Return value is the same as {@link #appliesToProperty(Object)} - * for the negated filter. - * - * @return boolean - */ - @Override - public boolean appliesToProperty(Object propertyId) { - return filter.appliesToProperty(propertyId); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !getClass().equals(obj.getClass())) { - return false; - } - return filter.equals(((Not) obj).getFilter()); - } - - @Override - public int hashCode() { - return filter.hashCode(); - } - -} diff --git a/src/com/vaadin/data/util/filter/Or.java b/src/com/vaadin/data/util/filter/Or.java deleted file mode 100644 index b60074f7e3..0000000000 --- a/src/com/vaadin/data/util/filter/Or.java +++ /dev/null @@ -1,63 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; - -/** - * A compound {@link Filter} that accepts an item if any of its filters accept - * the item. - * - * If no filters are given, the filter should reject all items. - * - * This filter also directly supports in-memory filtering when all sub-filters - * do so. - * - * @see And - * - * @since 6.6 - */ -public final class Or extends AbstractJunctionFilter { - - /** - * - * @param filters - * filters of which the Or filter will be composed - */ - public Or(Filter... filters) { - super(filters); - } - - @Override - public boolean passesFilter(Object itemId, Item item) - throws UnsupportedFilterException { - for (Filter filter : getFilters()) { - if (filter.passesFilter(itemId, item)) { - return true; - } - } - return false; - } - - /** - * Returns true if a change in the named property may affect the filtering - * result. If some of the sub-filters are not in-memory filters, true is - * returned. - * - * By default, all sub-filters are iterated to check if any of them applies. - * If there are no sub-filters, true is returned as an empty Or rejects all - * items. - */ - @Override - public boolean appliesToProperty(Object propertyId) { - if (getFilters().isEmpty()) { - // empty Or filters out everything - return true; - } else { - return super.appliesToProperty(propertyId); - } - } - -} diff --git a/src/com/vaadin/data/util/filter/SimpleStringFilter.java b/src/com/vaadin/data/util/filter/SimpleStringFilter.java deleted file mode 100644 index f98b2c02b4..0000000000 --- a/src/com/vaadin/data/util/filter/SimpleStringFilter.java +++ /dev/null @@ -1,152 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * Simple string filter for matching items that start with or contain a - * specified string. The matching can be case-sensitive or case-insensitive. - * - * This filter also directly supports in-memory filtering. When performing - * in-memory filtering, values of other types are converted using toString(), - * but other (lazy container) implementations do not need to perform such - * conversions and might not support values of different types. - * - * Note that this filter is modeled after the pre-6.6 filtering mechanisms, and - * might not be very efficient e.g. for database filtering. - * - * TODO this might still change - * - * @since 6.6 - */ -public final class SimpleStringFilter implements Filter { - - final Object propertyId; - final String filterString; - final boolean ignoreCase; - final boolean onlyMatchPrefix; - - public SimpleStringFilter(Object propertyId, String filterString, - boolean ignoreCase, boolean onlyMatchPrefix) { - this.propertyId = propertyId; - this.filterString = ignoreCase ? filterString.toLowerCase() - : filterString; - this.ignoreCase = ignoreCase; - this.onlyMatchPrefix = onlyMatchPrefix; - } - - @Override - public boolean passesFilter(Object itemId, Item item) { - final Property<?> p = item.getItemProperty(propertyId); - if (p == null) { - return false; - } - Object propertyValue = p.getValue(); - if (propertyValue == null) { - return false; - } - final String value = ignoreCase ? propertyValue.toString() - .toLowerCase() : propertyValue.toString(); - if (onlyMatchPrefix) { - if (!value.startsWith(filterString)) { - return false; - } - } else { - if (!value.contains(filterString)) { - return false; - } - } - return true; - } - - @Override - public boolean appliesToProperty(Object propertyId) { - return this.propertyId.equals(propertyId); - } - - @Override - public boolean equals(Object obj) { - - // Only ones of the objects of the same class can be equal - if (!(obj instanceof SimpleStringFilter)) { - return false; - } - final SimpleStringFilter o = (SimpleStringFilter) obj; - - // Checks the properties one by one - if (propertyId != o.propertyId && o.propertyId != null - && !o.propertyId.equals(propertyId)) { - return false; - } - if (filterString != o.filterString && o.filterString != null - && !o.filterString.equals(filterString)) { - return false; - } - if (ignoreCase != o.ignoreCase) { - return false; - } - if (onlyMatchPrefix != o.onlyMatchPrefix) { - return false; - } - - return true; - } - - @Override - public int hashCode() { - return (propertyId != null ? propertyId.hashCode() : 0) - ^ (filterString != null ? filterString.hashCode() : 0); - } - - /** - * Returns the property identifier to which this filter applies. - * - * @return property id - */ - public Object getPropertyId() { - return propertyId; - } - - /** - * Returns the filter string. - * - * Note: this method is intended only for implementations of lazy string - * filters and may change in the future. - * - * @return filter string given to the constructor - */ - public String getFilterString() { - return filterString; - } - - /** - * Returns whether the filter is case-insensitive or case-sensitive. - * - * Note: this method is intended only for implementations of lazy string - * filters and may change in the future. - * - * @return true if performing case-insensitive filtering, false for - * case-sensitive - */ - public boolean isIgnoreCase() { - return ignoreCase; - } - - /** - * Returns true if the filter only applies to the beginning of the value - * string, false for any location in the value. - * - * Note: this method is intended only for implementations of lazy string - * filters and may change in the future. - * - * @return true if checking for matches at the beginning of the value only, - * false if matching any part of value - */ - public boolean isOnlyMatchPrefix() { - return onlyMatchPrefix; - } -} diff --git a/src/com/vaadin/data/util/filter/UnsupportedFilterException.java b/src/com/vaadin/data/util/filter/UnsupportedFilterException.java deleted file mode 100644 index c09cc474e9..0000000000 --- a/src/com/vaadin/data/util/filter/UnsupportedFilterException.java +++ /dev/null @@ -1,35 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.filter; - -import java.io.Serializable; - -/** - * Exception for cases where a container does not support a specific type of - * filters. - * - * If possible, this should be thrown already when adding a filter to a - * container. If a problem is not detected at that point, an - * {@link UnsupportedOperationException} can be throws when attempting to - * perform filtering. - * - * @since 6.6 - */ -public class UnsupportedFilterException extends RuntimeException implements - Serializable { - public UnsupportedFilterException() { - } - - public UnsupportedFilterException(String message) { - super(message); - } - - public UnsupportedFilterException(Exception cause) { - super(cause); - } - - public UnsupportedFilterException(String message, Exception cause) { - super(message, cause); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/data/util/package.html b/src/com/vaadin/data/util/package.html deleted file mode 100644 index 07e3acde9e..0000000000 --- a/src/com/vaadin/data/util/package.html +++ /dev/null @@ -1,18 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> - -</head> - -<body bgcolor="white"> - -<p>Provides implementations of Property, Item and Container -interfaces, and utilities for the data layer.</p> - -<p>Various Property, Item and Container implementations are provided -in this package. Each implementation can have its own sets of -constraints on the data it encapsulates and on how the implementation -can be used. See the class javadocs for more information.</p> - -</body> -</html> diff --git a/src/com/vaadin/data/util/sqlcontainer/CacheFlushNotifier.java b/src/com/vaadin/data/util/sqlcontainer/CacheFlushNotifier.java deleted file mode 100644 index 788966048d..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/CacheFlushNotifier.java +++ /dev/null @@ -1,92 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.Serializable; -import java.lang.ref.ReferenceQueue; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.List; - -import com.vaadin.data.util.sqlcontainer.query.FreeformQuery; -import com.vaadin.data.util.sqlcontainer.query.QueryDelegate; -import com.vaadin.data.util.sqlcontainer.query.TableQuery; - -/** - * CacheFlushNotifier is a simple static notification mechanism to inform other - * SQLContainers that the contents of their caches may have become stale. - */ -class CacheFlushNotifier implements Serializable { - /* - * SQLContainer instance reference list and dead reference queue. Used for - * the cache flush notification feature. - */ - private static List<WeakReference<SQLContainer>> allInstances = new ArrayList<WeakReference<SQLContainer>>(); - private static ReferenceQueue<SQLContainer> deadInstances = new ReferenceQueue<SQLContainer>(); - - /** - * Adds the given SQLContainer to the cache flush notification receiver list - * - * @param c - * Container to add - */ - public static void addInstance(SQLContainer c) { - removeDeadReferences(); - if (c != null) { - allInstances.add(new WeakReference<SQLContainer>(c, deadInstances)); - } - } - - /** - * Removes dead references from instance list - */ - private static void removeDeadReferences() { - java.lang.ref.Reference<? extends SQLContainer> dead = deadInstances - .poll(); - while (dead != null) { - allInstances.remove(dead); - dead = deadInstances.poll(); - } - } - - /** - * Iterates through the instances and notifies containers which are - * connected to the same table or are using the same query string. - * - * @param c - * SQLContainer that issued the cache flush notification - */ - public static void notifyOfCacheFlush(SQLContainer c) { - removeDeadReferences(); - for (WeakReference<SQLContainer> wr : allInstances) { - if (wr.get() != null) { - SQLContainer wrc = wr.get(); - if (wrc == null) { - continue; - } - /* - * If the reference points to the container sending the - * notification, do nothing. - */ - if (wrc.equals(c)) { - continue; - } - /* Compare QueryDelegate types and tableName/queryString */ - QueryDelegate wrQd = wrc.getQueryDelegate(); - QueryDelegate qd = c.getQueryDelegate(); - if (wrQd instanceof TableQuery - && qd instanceof TableQuery - && ((TableQuery) wrQd).getTableName().equals( - ((TableQuery) qd).getTableName())) { - wrc.refresh(); - } else if (wrQd instanceof FreeformQuery - && qd instanceof FreeformQuery - && ((FreeformQuery) wrQd).getQueryString().equals( - ((FreeformQuery) qd).getQueryString())) { - wrc.refresh(); - } - } - } - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/CacheMap.java b/src/com/vaadin/data/util/sqlcontainer/CacheMap.java deleted file mode 100644 index 839fceb3c2..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/CacheMap.java +++ /dev/null @@ -1,31 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.util.LinkedHashMap; -import java.util.Map; - -/** - * CacheMap extends LinkedHashMap, adding the possibility to adjust maximum - * number of items. In SQLContainer this is used for RowItem -cache. Cache size - * will be two times the page length parameter of the container. - */ -class CacheMap<K, V> extends LinkedHashMap<K, V> { - private static final long serialVersionUID = 679999766473555231L; - private int cacheLimit = SQLContainer.CACHE_RATIO - * SQLContainer.DEFAULT_PAGE_LENGTH; - - @Override - protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { - return size() > cacheLimit; - } - - void setCacheLimit(int limit) { - cacheLimit = limit > 0 ? limit : SQLContainer.DEFAULT_PAGE_LENGTH; - } - - int getCacheLimit() { - return cacheLimit; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java b/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java deleted file mode 100644 index 168bce1880..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/ColumnProperty.java +++ /dev/null @@ -1,248 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.sql.Date; -import java.sql.Time; -import java.sql.Timestamp; - -import com.vaadin.data.Property; - -/** - * ColumnProperty represents the value of one column in a RowItem. In addition - * to the value, ColumnProperty also contains some basic column attributes such - * as nullability status, read-only status and data type. - * - * Note that depending on the QueryDelegate in use this does not necessarily map - * into an actual column in a database table. - */ -final public class ColumnProperty implements Property { - private static final long serialVersionUID = -3694463129581802457L; - - private RowItem owner; - - private String propertyId; - - private boolean readOnly; - private boolean allowReadOnlyChange = true; - private boolean nullable = true; - - private Object value; - private Object changedValue; - private Class<?> type; - - private boolean modified; - - private boolean versionColumn; - - /** - * Prevent instantiation without required parameters. - */ - @SuppressWarnings("unused") - private ColumnProperty() { - } - - public ColumnProperty(String propertyId, boolean readOnly, - boolean allowReadOnlyChange, boolean nullable, Object value, - Class<?> type) { - if (propertyId == null) { - throw new IllegalArgumentException("Properties must be named."); - } - if (type == null) { - throw new IllegalArgumentException("Property type must be set."); - } - this.propertyId = propertyId; - this.type = type; - this.value = value; - - this.allowReadOnlyChange = allowReadOnlyChange; - this.nullable = nullable; - this.readOnly = readOnly; - } - - @Override - public Object getValue() { - if (isModified()) { - return changedValue; - } - return value; - } - - @Override - public void setValue(Object newValue) throws ReadOnlyException { - if (newValue == null && !nullable) { - throw new NotNullableException( - "Null values are not allowed for this property."); - } - if (readOnly) { - throw new ReadOnlyException( - "Cannot set value for read-only property."); - } - - /* Check if this property is a date property. */ - boolean isDateProperty = Time.class.equals(getType()) - || Date.class.equals(getType()) - || Timestamp.class.equals(getType()); - - if (newValue != null) { - /* Handle SQL dates, times and Timestamps given as java.util.Date */ - if (isDateProperty) { - /* - * Try to get the millisecond value from the new value of this - * property. Possible type to convert from is java.util.Date. - */ - long millis = 0; - if (newValue instanceof java.util.Date) { - millis = ((java.util.Date) newValue).getTime(); - /* - * Create the new object based on the millisecond value, - * according to the type of this property. - */ - if (Time.class.equals(getType())) { - newValue = new Time(millis); - } else if (Date.class.equals(getType())) { - newValue = new Date(millis); - } else if (Timestamp.class.equals(getType())) { - newValue = new Timestamp(millis); - } - } - } - - if (!getType().isAssignableFrom(newValue.getClass())) { - throw new IllegalArgumentException( - "Illegal value type for ColumnProperty"); - } - - /* - * If the value to be set is the same that has already been set, do - * not set it again. - */ - if (isValueAlreadySet(newValue)) { - return; - } - } - - /* Set the new value and notify container of the change. */ - changedValue = newValue; - modified = true; - owner.getContainer().itemChangeNotification(owner); - } - - private boolean isValueAlreadySet(Object newValue) { - Object referenceValue = isModified() ? changedValue : value; - - return (isNullable() && newValue == null && referenceValue == null) - || newValue.equals(referenceValue); - } - - @Override - public Class<?> getType() { - return type; - } - - @Override - public boolean isReadOnly() { - return readOnly; - } - - public boolean isReadOnlyChangeAllowed() { - return allowReadOnlyChange; - } - - @Override - public void setReadOnly(boolean newStatus) { - if (allowReadOnlyChange) { - readOnly = newStatus; - } - } - - public String getPropertyId() { - return propertyId; - } - - /** - * Returns the value of the Property in human readable textual format. - * - * @see java.lang.Object#toString() - * @deprecated get the string representation from the value - */ - @Deprecated - @Override - public String toString() { - throw new UnsupportedOperationException( - "Use ColumnProperty.getValue() instead of ColumnProperty.toString()"); - } - - public void setOwner(RowItem owner) { - if (owner == null) { - throw new IllegalArgumentException("Owner can not be set to null."); - } - if (this.owner != null) { - throw new IllegalStateException( - "ColumnProperties can only be bound once."); - } - this.owner = owner; - } - - public boolean isModified() { - return modified; - } - - public boolean isVersionColumn() { - return versionColumn; - } - - public void setVersionColumn(boolean versionColumn) { - this.versionColumn = versionColumn; - } - - public boolean isNullable() { - return nullable; - } - - /** - * An exception that signals that a <code>null</code> value was passed to - * the <code>setValue</code> method, but the value of this property can not - * be set to <code>null</code>. - */ - @SuppressWarnings("serial") - public class NotNullableException extends RuntimeException { - - /** - * Constructs a new <code>NotNullableException</code> without a detail - * message. - */ - public NotNullableException() { - } - - /** - * Constructs a new <code>NotNullableException</code> with the specified - * detail message. - * - * @param msg - * the detail message - */ - public NotNullableException(String msg) { - super(msg); - } - - /** - * Constructs a new <code>NotNullableException</code> from another - * exception. - * - * @param cause - * The cause of the failure - */ - public NotNullableException(Throwable cause) { - super(cause); - } - } - - public void commit() { - if (isModified()) { - modified = false; - value = changedValue; - } - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java b/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java deleted file mode 100644 index adfd439ac8..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/OptimisticLockException.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import com.vaadin.data.util.sqlcontainer.query.TableQuery; - -/** - * An OptimisticLockException is thrown when trying to update or delete a row - * that has been changed since last read from the database. - * - * OptimisticLockException is a runtime exception because optimistic locking is - * turned off by default, and as such will never be thrown in a default - * configuration. In order to turn on optimistic locking, you need to specify - * the version column in your TableQuery instance. - * - * @see TableQuery#setVersionColumn(String) - * - * @author Jonatan Kronqvist / Vaadin Ltd - */ -public class OptimisticLockException extends RuntimeException { - - private final RowId rowId; - - public OptimisticLockException(RowId rowId) { - super(); - this.rowId = rowId; - } - - public OptimisticLockException(String msg, RowId rowId) { - super(msg); - this.rowId = rowId; - } - - public RowId getRowId() { - return rowId; - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/ReadOnlyRowId.java b/src/com/vaadin/data/util/sqlcontainer/ReadOnlyRowId.java deleted file mode 100644 index c73ffce63a..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/ReadOnlyRowId.java +++ /dev/null @@ -1,31 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -public class ReadOnlyRowId extends RowId { - private static final long serialVersionUID = -2626764781642012467L; - private final Integer rowNum; - - public ReadOnlyRowId(int rowNum) { - super(); - this.rowNum = rowNum; - } - - @Override - public int hashCode() { - return rowNum.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof ReadOnlyRowId)) { - return false; - } - return rowNum.equals(((ReadOnlyRowId) obj).rowNum); - } - - public int getRowNum() { - return rowNum; - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/Reference.java b/src/com/vaadin/data/util/sqlcontainer/Reference.java deleted file mode 100644 index dea1aa87c0..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/Reference.java +++ /dev/null @@ -1,56 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.Serializable; - -/** - * The reference class represents a simple [usually foreign key] reference to - * another SQLContainer. Actual foreign key reference in the database is not - * required, but it is recommended to make sure that certain constraints are - * followed. - */ -@SuppressWarnings("serial") -class Reference implements Serializable { - - /** - * The SQLContainer that this reference points to. - */ - private SQLContainer referencedContainer; - - /** - * The column ID/name in the referencing SQLContainer that contains the key - * used for the reference. - */ - private String referencingColumn; - - /** - * The column ID/name in the referenced SQLContainer that contains the key - * used for the reference. - */ - private String referencedColumn; - - /** - * Constructs a new reference to be used within the SQLContainer to - * reference another SQLContainer. - */ - Reference(SQLContainer referencedContainer, String referencingColumn, - String referencedColumn) { - this.referencedContainer = referencedContainer; - this.referencingColumn = referencingColumn; - this.referencedColumn = referencedColumn; - } - - SQLContainer getReferencedContainer() { - return referencedContainer; - } - - String getReferencingColumn() { - return referencingColumn; - } - - String getReferencedColumn() { - return referencedColumn; - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/RowId.java b/src/com/vaadin/data/util/sqlcontainer/RowId.java deleted file mode 100644 index 925325134a..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/RowId.java +++ /dev/null @@ -1,81 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.Serializable; - -/** - * RowId represents identifiers of a single database result set row. - * - * The data structure of a RowId is an Object array which contains the values of - * the primary key columns of the identified row. This allows easy equals() - * -comparison of RowItems. - */ -public class RowId implements Serializable { - private static final long serialVersionUID = -3161778404698901258L; - protected Object[] id; - - /** - * Prevent instantiation without required parameters. - */ - protected RowId() { - } - - public RowId(Object[] id) { - if (id == null) { - throw new IllegalArgumentException("id parameter must not be null!"); - } - this.id = id; - } - - public Object[] getId() { - return id; - } - - @Override - public int hashCode() { - int result = 31; - if (id != null) { - for (Object o : id) { - if (o != null) { - result += o.hashCode(); - } - } - } - return result; - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof RowId)) { - return false; - } - Object[] compId = ((RowId) obj).getId(); - if (id == null && compId == null) { - return true; - } - if (id.length != compId.length) { - return false; - } - for (int i = 0; i < id.length; i++) { - if ((id[i] == null && compId[i] != null) - || (id[i] != null && !id[i].equals(compId[i]))) { - return false; - } - } - return true; - } - - @Override - public String toString() { - StringBuffer s = new StringBuffer(); - for (int i = 0; i < id.length; i++) { - s.append(id[i]); - if (i < id.length - 1) { - s.append("/"); - } - } - return s.toString(); - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/RowItem.java b/src/com/vaadin/data/util/sqlcontainer/RowItem.java deleted file mode 100644 index d613a06b63..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/RowItem.java +++ /dev/null @@ -1,133 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; - -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * RowItem represents one row of a result set obtained from a QueryDelegate. - * - * Note that depending on the QueryDelegate in use this does not necessarily map - * into an actual row in a database table. - */ -public final class RowItem implements Item { - private static final long serialVersionUID = -6228966439127951408L; - private SQLContainer container; - private RowId id; - private Collection<ColumnProperty> properties; - - /** - * Prevent instantiation without required parameters. - */ - @SuppressWarnings("unused") - private RowItem() { - } - - public RowItem(SQLContainer container, RowId id, - Collection<ColumnProperty> properties) { - if (container == null) { - throw new IllegalArgumentException("Container cannot be null."); - } - if (id == null) { - throw new IllegalArgumentException("Row ID cannot be null."); - } - this.container = container; - this.properties = properties; - /* Set this RowItem as owner to the properties */ - if (properties != null) { - for (ColumnProperty p : properties) { - p.setOwner(this); - } - } - this.id = id; - } - - @Override - public Property<?> getItemProperty(Object id) { - if (id instanceof String && id != null) { - for (ColumnProperty cp : properties) { - if (id.equals(cp.getPropertyId())) { - return cp; - } - } - } - return null; - } - - @Override - public Collection<?> getItemPropertyIds() { - Collection<String> ids = new ArrayList<String>(properties.size()); - for (ColumnProperty cp : properties) { - ids.add(cp.getPropertyId()); - } - return Collections.unmodifiableCollection(ids); - } - - /** - * Adding properties is not supported. Properties are generated by - * SQLContainer. - */ - @Override - public boolean addItemProperty(Object id, Property property) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Removing properties is not supported. Properties are generated by - * SQLContainer. - */ - @Override - public boolean removeItemProperty(Object id) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - public RowId getId() { - return id; - } - - public SQLContainer getContainer() { - return container; - } - - public boolean isModified() { - if (properties != null) { - for (ColumnProperty p : properties) { - if (p.isModified()) { - return true; - } - } - } - return false; - } - - @Override - public String toString() { - StringBuffer s = new StringBuffer(); - s.append("ID:"); - s.append(getId().toString()); - for (Object propId : getItemPropertyIds()) { - s.append("|"); - s.append(propId.toString()); - s.append(":"); - Object value = getItemProperty(propId).getValue(); - s.append((null != value) ? value.toString() : null); - } - return s.toString(); - } - - public void commit() { - if (properties != null) { - for (ColumnProperty p : properties) { - p.commit(); - } - } - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java b/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java deleted file mode 100644 index 5827390723..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/SQLContainer.java +++ /dev/null @@ -1,1716 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.IOException; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.ConcurrentModificationException; -import java.util.Date; -import java.util.EventObject; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.data.util.filter.Compare.Equal; -import com.vaadin.data.util.filter.Like; -import com.vaadin.data.util.filter.UnsupportedFilterException; -import com.vaadin.data.util.sqlcontainer.query.OrderBy; -import com.vaadin.data.util.sqlcontainer.query.QueryDelegate; -import com.vaadin.data.util.sqlcontainer.query.QueryDelegate.RowIdChangeListener; -import com.vaadin.data.util.sqlcontainer.query.TableQuery; -import com.vaadin.data.util.sqlcontainer.query.generator.MSSQLGenerator; -import com.vaadin.data.util.sqlcontainer.query.generator.OracleGenerator; - -public class SQLContainer implements Container, Container.Filterable, - Container.Indexed, Container.Sortable, Container.ItemSetChangeNotifier { - - /** Query delegate */ - private QueryDelegate delegate; - /** Auto commit mode, default = false */ - private boolean autoCommit = false; - - /** Page length = number of items contained in one page */ - private int pageLength = DEFAULT_PAGE_LENGTH; - public static final int DEFAULT_PAGE_LENGTH = 100; - - /** Number of items to cache = CACHE_RATIO x pageLength */ - public static final int CACHE_RATIO = 2; - - /** Item and index caches */ - private final Map<Integer, RowId> itemIndexes = new HashMap<Integer, RowId>(); - private final CacheMap<RowId, RowItem> cachedItems = new CacheMap<RowId, RowItem>(); - - /** Container properties = column names, data types and statuses */ - private final List<String> propertyIds = new ArrayList<String>(); - private final Map<String, Class<?>> propertyTypes = new HashMap<String, Class<?>>(); - private final Map<String, Boolean> propertyReadOnly = new HashMap<String, Boolean>(); - private final Map<String, Boolean> propertyNullable = new HashMap<String, Boolean>(); - - /** Filters (WHERE) and sorters (ORDER BY) */ - private final List<Filter> filters = new ArrayList<Filter>(); - private final List<OrderBy> sorters = new ArrayList<OrderBy>(); - - /** - * Total number of items available in the data source using the current - * query, filters and sorters. - */ - private int size; - - /** - * Size updating logic. Do not update size from data source if it has been - * updated in the last sizeValidMilliSeconds milliseconds. - */ - private final int sizeValidMilliSeconds = 10000; - private boolean sizeDirty = true; - private Date sizeUpdated = new Date(); - - /** Starting row number of the currently fetched page */ - private int currentOffset; - - /** ItemSetChangeListeners */ - private LinkedList<Container.ItemSetChangeListener> itemSetChangeListeners; - - /** Temporary storage for modified items and items to be removed and added */ - private final Map<RowId, RowItem> removedItems = new HashMap<RowId, RowItem>(); - private final List<RowItem> addedItems = new ArrayList<RowItem>(); - private final List<RowItem> modifiedItems = new ArrayList<RowItem>(); - - /** List of references to other SQLContainers */ - private final Map<SQLContainer, Reference> references = new HashMap<SQLContainer, Reference>(); - - /** Cache flush notification system enabled. Disabled by default. */ - private boolean notificationsEnabled; - - /** - * Prevent instantiation without a QueryDelegate. - */ - @SuppressWarnings("unused") - private SQLContainer() { - } - - /** - * Creates and initializes SQLContainer using the given QueryDelegate - * - * @param delegate - * QueryDelegate implementation - * @throws SQLException - */ - public SQLContainer(QueryDelegate delegate) throws SQLException { - if (delegate == null) { - throw new IllegalArgumentException( - "QueryDelegate must not be null."); - } - this.delegate = delegate; - getPropertyIds(); - cachedItems.setCacheLimit(CACHE_RATIO * getPageLength()); - } - - /**************************************/ - /** Methods from interface Container **/ - /**************************************/ - - /** - * Note! If auto commit mode is enabled, this method will still return the - * temporary row ID assigned for the item. Implement - * QueryDelegate.RowIdChangeListener to receive the actual Row ID value - * after the addition has been committed. - * - * {@inheritDoc} - */ - - @Override - public Object addItem() throws UnsupportedOperationException { - Object emptyKey[] = new Object[delegate.getPrimaryKeyColumns().size()]; - RowId itemId = new TemporaryRowId(emptyKey); - // Create new empty column properties for the row item. - List<ColumnProperty> itemProperties = new ArrayList<ColumnProperty>(); - for (String propertyId : propertyIds) { - /* Default settings for new item properties. */ - itemProperties - .add(new ColumnProperty(propertyId, propertyReadOnly - .get(propertyId), - !propertyReadOnly.get(propertyId), propertyNullable - .get(propertyId), null, getType(propertyId))); - } - RowItem newRowItem = new RowItem(this, itemId, itemProperties); - - if (autoCommit) { - /* Add and commit instantly */ - try { - if (delegate instanceof TableQuery) { - itemId = ((TableQuery) delegate) - .storeRowImmediately(newRowItem); - } else { - delegate.beginTransaction(); - delegate.storeRow(newRowItem); - delegate.commit(); - } - refresh(); - if (notificationsEnabled) { - CacheFlushNotifier.notifyOfCacheFlush(this); - } - getLogger().log(Level.FINER, "Row added to DB..."); - return itemId; - } catch (SQLException e) { - getLogger().log(Level.WARNING, - "Failed to add row to DB. Rolling back.", e); - try { - delegate.rollback(); - } catch (SQLException ee) { - getLogger().log(Level.SEVERE, - "Failed to roll back row addition", e); - } - return null; - } - } else { - addedItems.add(newRowItem); - fireContentsChange(); - return itemId; - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#containsId(java.lang.Object) - */ - - @Override - public boolean containsId(Object itemId) { - if (itemId == null) { - return false; - } - - if (cachedItems.containsKey(itemId)) { - return true; - } else { - for (RowItem item : addedItems) { - if (item.getId().equals(itemId)) { - return itemPassesFilters(item); - } - } - } - if (removedItems.containsKey(itemId)) { - return false; - } - - if (itemId instanceof ReadOnlyRowId) { - int rowNum = ((ReadOnlyRowId) itemId).getRowNum(); - return rowNum >= 0 && rowNum < size; - } - - if (itemId instanceof RowId && !(itemId instanceof TemporaryRowId)) { - try { - return delegate.containsRowWithKey(((RowId) itemId).getId()); - } catch (Exception e) { - /* Query failed, just return false. */ - getLogger().log(Level.WARNING, "containsId query failed", e); - } - } - return false; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getContainerProperty(java.lang.Object, - * java.lang.Object) - */ - - @Override - public Property<?> getContainerProperty(Object itemId, Object propertyId) { - Item item = getItem(itemId); - if (item == null) { - return null; - } - return item.getItemProperty(propertyId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getContainerPropertyIds() - */ - - @Override - public Collection<?> getContainerPropertyIds() { - return Collections.unmodifiableCollection(propertyIds); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getItem(java.lang.Object) - */ - - @Override - public Item getItem(Object itemId) { - if (!cachedItems.containsKey(itemId)) { - int index = indexOfId(itemId); - if (index >= size) { - // The index is in the added items - int offset = index - size; - RowItem item = addedItems.get(offset); - if (itemPassesFilters(item)) { - return item; - } else { - return null; - } - } else { - // load the item into cache - updateOffsetAndCache(index); - } - } - return cachedItems.get(itemId); - } - - /** - * Bypasses in-memory filtering to return items that are cached in memory. - * <em>NOTE</em>: This does not bypass database-level filtering. - * - * @param itemId - * the id of the item to retrieve. - * @return the item represented by itemId. - */ - public Item getItemUnfiltered(Object itemId) { - if (!cachedItems.containsKey(itemId)) { - for (RowItem item : addedItems) { - if (item.getId().equals(itemId)) { - return item; - } - } - } - return cachedItems.get(itemId); - } - - /** - * NOTE! Do not use this method if in any way avoidable. This method doesn't - * (and cannot) use lazy loading, which means that all rows in the database - * will be loaded into memory. - * - * {@inheritDoc} - */ - - @Override - public Collection<?> getItemIds() { - updateCount(); - ArrayList<RowId> ids = new ArrayList<RowId>(); - ResultSet rs = null; - try { - // Load ALL rows :( - delegate.beginTransaction(); - rs = delegate.getResults(0, 0); - List<String> pKeys = delegate.getPrimaryKeyColumns(); - while (rs.next()) { - RowId id = null; - if (pKeys.isEmpty()) { - /* Create a read only itemId */ - id = new ReadOnlyRowId(rs.getRow()); - } else { - /* Generate itemId for the row based on primary key(s) */ - Object[] itemId = new Object[pKeys.size()]; - for (int i = 0; i < pKeys.size(); i++) { - itemId[i] = rs.getObject(pKeys.get(i)); - } - id = new RowId(itemId); - } - if (id != null && !removedItems.containsKey(id)) { - ids.add(id); - } - } - rs.getStatement().close(); - rs.close(); - delegate.commit(); - } catch (SQLException e) { - getLogger().log(Level.WARNING, - "getItemIds() failed, rolling back.", e); - try { - delegate.rollback(); - } catch (SQLException e1) { - getLogger().log(Level.SEVERE, "Failed to roll back state", e1); - } - try { - rs.getStatement().close(); - rs.close(); - } catch (SQLException e1) { - getLogger().log(Level.WARNING, "Closing session failed", e1); - } - throw new RuntimeException("Failed to fetch item indexes.", e); - } - for (RowItem item : getFilteredAddedItems()) { - ids.add(item.getId()); - } - return Collections.unmodifiableCollection(ids); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#getType(java.lang.Object) - */ - - @Override - public Class<?> getType(Object propertyId) { - if (!propertyIds.contains(propertyId)) { - return null; - } - return propertyTypes.get(propertyId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#size() - */ - - @Override - public int size() { - updateCount(); - return size + sizeOfAddedItems() - removedItems.size(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeItem(java.lang.Object) - */ - - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - if (!containsId(itemId)) { - return false; - } - for (RowItem item : addedItems) { - if (item.getId().equals(itemId)) { - addedItems.remove(item); - fireContentsChange(); - return true; - } - } - - if (autoCommit) { - /* Remove and commit instantly. */ - Item i = getItem(itemId); - if (i == null) { - return false; - } - try { - delegate.beginTransaction(); - boolean success = delegate.removeRow((RowItem) i); - delegate.commit(); - refresh(); - if (notificationsEnabled) { - CacheFlushNotifier.notifyOfCacheFlush(this); - } - if (success) { - getLogger().log(Level.FINER, "Row removed from DB..."); - } - return success; - } catch (SQLException e) { - getLogger().log(Level.WARNING, - "Failed to remove row, rolling back", e); - try { - delegate.rollback(); - } catch (SQLException ee) { - /* Nothing can be done here */ - getLogger().log(Level.SEVERE, - "Failed to rollback row removal", ee); - } - return false; - } catch (OptimisticLockException e) { - getLogger().log(Level.WARNING, - "Failed to remove row, rolling back", e); - try { - delegate.rollback(); - } catch (SQLException ee) { - /* Nothing can be done here */ - getLogger().log(Level.SEVERE, - "Failed to rollback row removal", ee); - } - throw e; - } - } else { - removedItems.put((RowId) itemId, (RowItem) getItem(itemId)); - cachedItems.remove(itemId); - refresh(); - return true; - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeAllItems() - */ - - @Override - public boolean removeAllItems() throws UnsupportedOperationException { - if (autoCommit) { - /* Remove and commit instantly. */ - try { - delegate.beginTransaction(); - boolean success = true; - for (Object id : getItemIds()) { - if (!delegate.removeRow((RowItem) getItem(id))) { - success = false; - } - } - if (success) { - delegate.commit(); - getLogger().log(Level.FINER, "All rows removed from DB..."); - refresh(); - if (notificationsEnabled) { - CacheFlushNotifier.notifyOfCacheFlush(this); - } - } else { - delegate.rollback(); - } - return success; - } catch (SQLException e) { - getLogger().log(Level.WARNING, - "removeAllItems() failed, rolling back", e); - try { - delegate.rollback(); - } catch (SQLException ee) { - /* Nothing can be done here */ - getLogger().log(Level.SEVERE, "Failed to roll back", ee); - } - return false; - } catch (OptimisticLockException e) { - getLogger().log(Level.WARNING, - "removeAllItems() failed, rolling back", e); - try { - delegate.rollback(); - } catch (SQLException ee) { - /* Nothing can be done here */ - getLogger().log(Level.SEVERE, "Failed to roll back", ee); - } - throw e; - } - } else { - for (Object id : getItemIds()) { - removedItems.put((RowId) id, (RowItem) getItem(id)); - cachedItems.remove(id); - } - refresh(); - return true; - } - } - - /*************************************************/ - /** Methods from interface Container.Filterable **/ - /*************************************************/ - - /** - * {@inheritDoc} - */ - - @Override - public void addContainerFilter(Filter filter) - throws UnsupportedFilterException { - // filter.setCaseSensitive(!ignoreCase); - - filters.add(filter); - refresh(); - } - - /** - * {@inheritDoc} - */ - - @Override - public void removeContainerFilter(Filter filter) { - filters.remove(filter); - refresh(); - } - - /** - * {@inheritDoc} - */ - public void addContainerFilter(Object propertyId, String filterString, - boolean ignoreCase, boolean onlyMatchPrefix) { - if (propertyId == null || !propertyIds.contains(propertyId)) { - return; - } - - /* Generate Filter -object */ - String likeStr = onlyMatchPrefix ? filterString + "%" : "%" - + filterString + "%"; - Like like = new Like(propertyId.toString(), likeStr); - like.setCaseSensitive(!ignoreCase); - filters.add(like); - refresh(); - } - - /** - * {@inheritDoc} - */ - public void removeContainerFilters(Object propertyId) { - ArrayList<Filter> toRemove = new ArrayList<Filter>(); - for (Filter f : filters) { - if (f.appliesToProperty(propertyId)) { - toRemove.add(f); - } - } - filters.removeAll(toRemove); - refresh(); - } - - /** - * {@inheritDoc} - */ - - @Override - public void removeAllContainerFilters() { - filters.clear(); - refresh(); - } - - /**********************************************/ - /** Methods from interface Container.Indexed **/ - /**********************************************/ - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Indexed#indexOfId(java.lang.Object) - */ - - @Override - public int indexOfId(Object itemId) { - // First check if the id is in the added items - for (int ix = 0; ix < addedItems.size(); ix++) { - RowItem item = addedItems.get(ix); - if (item.getId().equals(itemId)) { - if (itemPassesFilters(item)) { - updateCount(); - return size + ix; - } else { - return -1; - } - } - } - - if (!containsId(itemId)) { - return -1; - } - if (cachedItems.isEmpty()) { - getPage(); - } - int size = size(); - boolean wrappedAround = false; - while (!wrappedAround) { - for (Integer i : itemIndexes.keySet()) { - if (itemIndexes.get(i).equals(itemId)) { - return i; - } - } - // load in the next page. - int nextIndex = (currentOffset / (pageLength * CACHE_RATIO) + 1) - * (pageLength * CACHE_RATIO); - if (nextIndex >= size) { - // Container wrapped around, start from index 0. - wrappedAround = true; - nextIndex = 0; - } - updateOffsetAndCache(nextIndex); - } - return -1; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Indexed#getIdByIndex(int) - */ - - @Override - public Object getIdByIndex(int index) { - if (index < 0 || index > size() - 1) { - return null; - } - if (index < size) { - if (itemIndexes.keySet().contains(index)) { - return itemIndexes.get(index); - } - updateOffsetAndCache(index); - return itemIndexes.get(index); - } else { - // The index is in the added items - int offset = index - size; - return addedItems.get(offset).getId(); - } - } - - /**********************************************/ - /** Methods from interface Container.Ordered **/ - /**********************************************/ - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#nextItemId(java.lang.Object) - */ - - @Override - public Object nextItemId(Object itemId) { - return getIdByIndex(indexOfId(itemId) + 1); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#prevItemId(java.lang.Object) - */ - - @Override - public Object prevItemId(Object itemId) { - return getIdByIndex(indexOfId(itemId) - 1); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#firstItemId() - */ - - @Override - public Object firstItemId() { - updateCount(); - if (size == 0) { - if (addedItems.isEmpty()) { - return null; - } else { - int ix = -1; - do { - ix++; - } while (!itemPassesFilters(addedItems.get(ix)) - && ix < addedItems.size()); - if (ix < addedItems.size()) { - return addedItems.get(ix).getId(); - } - } - } - if (!itemIndexes.containsKey(0)) { - updateOffsetAndCache(0); - } - return itemIndexes.get(0); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#lastItemId() - */ - - @Override - public Object lastItemId() { - if (addedItems.isEmpty()) { - int lastIx = size() - 1; - if (!itemIndexes.containsKey(lastIx)) { - updateOffsetAndCache(size - 1); - } - return itemIndexes.get(lastIx); - } else { - int ix = addedItems.size(); - do { - ix--; - } while (!itemPassesFilters(addedItems.get(ix)) && ix >= 0); - if (ix >= 0) { - return addedItems.get(ix).getId(); - } else { - return null; - } - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#isFirstId(java.lang.Object) - */ - - @Override - public boolean isFirstId(Object itemId) { - return firstItemId().equals(itemId); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#isLastId(java.lang.Object) - */ - - @Override - public boolean isLastId(Object itemId) { - return lastItemId().equals(itemId); - } - - /***********************************************/ - /** Methods from interface Container.Sortable **/ - /***********************************************/ - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Sortable#sort(java.lang.Object[], - * boolean[]) - */ - - @Override - public void sort(Object[] propertyId, boolean[] ascending) { - sorters.clear(); - if (propertyId == null || propertyId.length == 0) { - refresh(); - return; - } - /* Generate OrderBy -objects */ - boolean asc = true; - for (int i = 0; i < propertyId.length; i++) { - /* Check that the property id is valid */ - if (propertyId[i] instanceof String - && propertyIds.contains(propertyId[i])) { - try { - asc = ascending[i]; - } catch (Exception e) { - getLogger().log(Level.WARNING, "", e); - } - sorters.add(new OrderBy((String) propertyId[i], asc)); - } - } - refresh(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Sortable#getSortableContainerPropertyIds() - */ - - @Override - public Collection<?> getSortableContainerPropertyIds() { - return getContainerPropertyIds(); - } - - /**************************************/ - /** Methods specific to SQLContainer **/ - /**************************************/ - - /** - * Refreshes the container - clears all caches and resets size and offset. - * Does NOT remove sorting or filtering rules! - */ - public void refresh() { - sizeDirty = true; - currentOffset = 0; - cachedItems.clear(); - itemIndexes.clear(); - fireContentsChange(); - } - - /** - * Returns modify state of the container. - * - * @return true if contents of this container have been modified - */ - public boolean isModified() { - return !removedItems.isEmpty() || !addedItems.isEmpty() - || !modifiedItems.isEmpty(); - } - - /** - * Set auto commit mode enabled or disabled. Auto commit mode means that all - * changes made to items of this container will be immediately written to - * the underlying data source. - * - * @param autoCommitEnabled - * true to enable auto commit mode - */ - public void setAutoCommit(boolean autoCommitEnabled) { - autoCommit = autoCommitEnabled; - } - - /** - * Returns status of the auto commit mode. - * - * @return true if auto commit mode is enabled - */ - public boolean isAutoCommit() { - return autoCommit; - } - - /** - * Returns the currently set page length. - * - * @return current page length - */ - public int getPageLength() { - return pageLength; - } - - /** - * Sets the page length used in lazy fetching of items from the data source. - * Also resets the cache size to match the new page length. - * - * As a side effect the container will be refreshed. - * - * @param pageLength - * new page length - */ - public void setPageLength(int pageLength) { - setPageLengthInternal(pageLength); - refresh(); - } - - /** - * Sets the page length internally, without refreshing the container. - * - * @param pageLength - * the new page length - */ - private void setPageLengthInternal(int pageLength) { - this.pageLength = pageLength > 0 ? pageLength : DEFAULT_PAGE_LENGTH; - cachedItems.setCacheLimit(CACHE_RATIO * getPageLength()); - } - - /** - * Adds the given OrderBy to this container and refreshes the container - * contents with the new sorting rules. - * - * Note that orderBy.getColumn() must return a column name that exists in - * this container. - * - * @param orderBy - * OrderBy to be added to the container sorting rules - */ - public void addOrderBy(OrderBy orderBy) { - if (orderBy == null) { - return; - } - if (!propertyIds.contains(orderBy.getColumn())) { - throw new IllegalArgumentException( - "The column given for sorting does not exist in this container."); - } - sorters.add(orderBy); - refresh(); - } - - /** - * Commits all the changes, additions and removals made to the items of this - * container. - * - * @throws UnsupportedOperationException - * @throws SQLException - */ - public void commit() throws UnsupportedOperationException, SQLException { - try { - getLogger().log(Level.FINER, - "Commiting changes through delegate..."); - delegate.beginTransaction(); - /* Perform buffered deletions */ - for (RowItem item : removedItems.values()) { - if (!delegate.removeRow(item)) { - throw new SQLException("Removal failed for row with ID: " - + item.getId()); - } - } - /* Perform buffered modifications */ - for (RowItem item : modifiedItems) { - if (delegate.storeRow(item) > 0) { - /* - * Also reset the modified state in the item in case it is - * reused e.g. in a form. - */ - item.commit(); - } else { - delegate.rollback(); - refresh(); - throw new ConcurrentModificationException( - "Item with the ID '" + item.getId() - + "' has been externally modified."); - } - } - /* Perform buffered additions */ - for (RowItem item : addedItems) { - delegate.storeRow(item); - } - delegate.commit(); - removedItems.clear(); - addedItems.clear(); - modifiedItems.clear(); - refresh(); - if (notificationsEnabled) { - CacheFlushNotifier.notifyOfCacheFlush(this); - } - } catch (SQLException e) { - delegate.rollback(); - throw e; - } catch (OptimisticLockException e) { - delegate.rollback(); - throw e; - } - } - - /** - * Rolls back all the changes, additions and removals made to the items of - * this container. - * - * @throws UnsupportedOperationException - * @throws SQLException - */ - public void rollback() throws UnsupportedOperationException, SQLException { - getLogger().log(Level.FINE, "Rolling back changes..."); - removedItems.clear(); - addedItems.clear(); - modifiedItems.clear(); - refresh(); - } - - /** - * Notifies this container that a property in the given item has been - * modified. The change will be buffered or made instantaneously depending - * on auto commit mode. - * - * @param changedItem - * item that has a modified property - */ - void itemChangeNotification(RowItem changedItem) { - if (autoCommit) { - try { - delegate.beginTransaction(); - if (delegate.storeRow(changedItem) == 0) { - delegate.rollback(); - refresh(); - throw new ConcurrentModificationException( - "Item with the ID '" + changedItem.getId() - + "' has been externally modified."); - } - delegate.commit(); - if (notificationsEnabled) { - CacheFlushNotifier.notifyOfCacheFlush(this); - } - getLogger().log(Level.FINER, "Row updated to DB..."); - } catch (SQLException e) { - getLogger().log(Level.WARNING, - "itemChangeNotification failed, rolling back...", e); - try { - delegate.rollback(); - } catch (SQLException ee) { - /* Nothing can be done here */ - getLogger().log(Level.SEVERE, "Rollback failed", e); - } - throw new RuntimeException(e); - } - } else { - if (!(changedItem.getId() instanceof TemporaryRowId) - && !modifiedItems.contains(changedItem)) { - modifiedItems.add(changedItem); - } - } - } - - /** - * Determines a new offset for updating the row cache. The offset is - * calculated from the given index, and will be fixed to match the start of - * a page, based on the value of pageLength. - * - * @param index - * Index of the item that was requested, but not found in cache - */ - private void updateOffsetAndCache(int index) { - if (itemIndexes.containsKey(index)) { - return; - } - currentOffset = (index / (pageLength * CACHE_RATIO)) - * (pageLength * CACHE_RATIO); - if (currentOffset < 0) { - currentOffset = 0; - } - getPage(); - } - - /** - * Fetches new count of rows from the data source, if needed. - */ - private void updateCount() { - if (!sizeDirty - && new Date().getTime() < sizeUpdated.getTime() - + sizeValidMilliSeconds) { - return; - } - try { - try { - delegate.setFilters(filters); - } catch (UnsupportedOperationException e) { - getLogger().log(Level.FINE, - "The query delegate doesn't support filtering", e); - } - try { - delegate.setOrderBy(sorters); - } catch (UnsupportedOperationException e) { - getLogger().log(Level.FINE, - "The query delegate doesn't support filtering", e); - } - int newSize = delegate.getCount(); - if (newSize != size) { - size = newSize; - refresh(); - } - sizeUpdated = new Date(); - sizeDirty = false; - getLogger().log(Level.FINER, - "Updated row count. New count is: " + size); - } catch (SQLException e) { - throw new RuntimeException("Failed to update item set size.", e); - } - } - - /** - * Fetches property id's (column names and their types) from the data - * source. - * - * @throws SQLException - */ - private void getPropertyIds() throws SQLException { - propertyIds.clear(); - propertyTypes.clear(); - delegate.setFilters(null); - delegate.setOrderBy(null); - ResultSet rs = null; - ResultSetMetaData rsmd = null; - try { - delegate.beginTransaction(); - rs = delegate.getResults(0, 1); - boolean resultExists = rs.next(); - rsmd = rs.getMetaData(); - Class<?> type = null; - for (int i = 1; i <= rsmd.getColumnCount(); i++) { - if (!isColumnIdentifierValid(rsmd.getColumnLabel(i))) { - continue; - } - String colName = rsmd.getColumnLabel(i); - /* - * Make sure not to add the same colName twice. This can easily - * happen if the SQL query joins many tables with an ID column. - */ - if (!propertyIds.contains(colName)) { - propertyIds.add(colName); - } - /* Try to determine the column's JDBC class by all means. */ - if (resultExists && rs.getObject(i) != null) { - type = rs.getObject(i).getClass(); - } else { - try { - type = Class.forName(rsmd.getColumnClassName(i)); - } catch (Exception e) { - getLogger().log(Level.WARNING, "Class not found", e); - /* On failure revert to Object and hope for the best. */ - type = Object.class; - } - } - /* - * Determine read only and nullability status of the column. A - * column is read only if it is reported as either read only or - * auto increment by the database, and also it is set as the - * version column in a TableQuery delegate. - */ - boolean readOnly = rsmd.isAutoIncrement(i) - || rsmd.isReadOnly(i); - if (delegate instanceof TableQuery - && rsmd.getColumnLabel(i).equals( - ((TableQuery) delegate).getVersionColumn())) { - readOnly = true; - } - propertyReadOnly.put(colName, readOnly); - propertyNullable.put(colName, - rsmd.isNullable(i) == ResultSetMetaData.columnNullable); - propertyTypes.put(colName, type); - } - rs.getStatement().close(); - rs.close(); - delegate.commit(); - getLogger().log(Level.FINER, "Property IDs fetched."); - } catch (SQLException e) { - getLogger().log(Level.WARNING, - "Failed to fetch property ids, rolling back", e); - try { - delegate.rollback(); - } catch (SQLException e1) { - getLogger().log(Level.SEVERE, "Failed to roll back", e1); - } - try { - if (rs != null) { - if (rs.getStatement() != null) { - rs.getStatement().close(); - } - rs.close(); - } - } catch (SQLException e1) { - getLogger().log(Level.WARNING, "Failed to close session", e1); - } - throw e; - } - } - - /** - * Fetches a page from the data source based on the values of pageLenght and - * currentOffset. Also updates the set of primary keys, used in - * identification of RowItems. - */ - private void getPage() { - updateCount(); - ResultSet rs = null; - ResultSetMetaData rsmd = null; - cachedItems.clear(); - itemIndexes.clear(); - try { - try { - delegate.setOrderBy(sorters); - } catch (UnsupportedOperationException e) { - /* The query delegate doesn't support sorting. */ - /* No need to do anything. */ - getLogger().log(Level.FINE, - "The query delegate doesn't support sorting", e); - } - delegate.beginTransaction(); - rs = delegate.getResults(currentOffset, pageLength * CACHE_RATIO); - rsmd = rs.getMetaData(); - List<String> pKeys = delegate.getPrimaryKeyColumns(); - // } - /* Create new items and column properties */ - ColumnProperty cp = null; - int rowCount = currentOffset; - if (!delegate.implementationRespectsPagingLimits()) { - rowCount = currentOffset = 0; - setPageLengthInternal(size); - } - while (rs.next()) { - List<ColumnProperty> itemProperties = new ArrayList<ColumnProperty>(); - /* Generate row itemId based on primary key(s) */ - Object[] itemId = new Object[pKeys.size()]; - for (int i = 0; i < pKeys.size(); i++) { - itemId[i] = rs.getObject(pKeys.get(i)); - } - RowId id = null; - if (pKeys.isEmpty()) { - id = new ReadOnlyRowId(rs.getRow()); - } else { - id = new RowId(itemId); - } - List<String> propertiesToAdd = new ArrayList<String>( - propertyIds); - if (!removedItems.containsKey(id)) { - for (int i = 1; i <= rsmd.getColumnCount(); i++) { - if (!isColumnIdentifierValid(rsmd.getColumnLabel(i))) { - continue; - } - String colName = rsmd.getColumnLabel(i); - Object value = rs.getObject(i); - Class<?> type = value != null ? value.getClass() - : Object.class; - if (value == null) { - for (String propName : propertyTypes.keySet()) { - if (propName.equals(rsmd.getColumnLabel(i))) { - type = propertyTypes.get(propName); - break; - } - } - } - /* - * In case there are more than one column with the same - * name, add only the first one. This can easily happen - * if you join many tables where each table has an ID - * column. - */ - if (propertiesToAdd.contains(colName)) { - cp = new ColumnProperty(colName, - propertyReadOnly.get(colName), - !propertyReadOnly.get(colName), - propertyNullable.get(colName), value, type); - itemProperties.add(cp); - propertiesToAdd.remove(colName); - } - } - /* Cache item */ - itemIndexes.put(rowCount, id); - - // if an item with the id is contained in the modified - // cache, then use this record and add it to the cached - // items. Otherwise create a new item - int modifiedIndex = indexInModifiedCache(id); - if (modifiedIndex != -1) { - cachedItems.put(id, modifiedItems.get(modifiedIndex)); - } else { - cachedItems.put(id, new RowItem(this, id, - itemProperties)); - } - - rowCount++; - } - } - rs.getStatement().close(); - rs.close(); - delegate.commit(); - getLogger().log( - Level.FINER, - "Fetched " + pageLength * CACHE_RATIO - + " rows starting from " + currentOffset); - } catch (SQLException e) { - getLogger().log(Level.WARNING, - "Failed to fetch rows, rolling back", e); - try { - delegate.rollback(); - } catch (SQLException e1) { - getLogger().log(Level.SEVERE, "Failed to roll back", e1); - } - try { - if (rs != null) { - if (rs.getStatement() != null) { - rs.getStatement().close(); - rs.close(); - } - } - } catch (SQLException e1) { - getLogger().log(Level.WARNING, "Failed to close session", e1); - } - throw new RuntimeException("Failed to fetch page.", e); - } - } - - /** - * Returns the index of the item with the given itemId for the modified - * cache. - * - * @param itemId - * @return the index of the item with the itemId in the modified cache. Or - * -1 if not found. - */ - private int indexInModifiedCache(Object itemId) { - for (int ix = 0; ix < modifiedItems.size(); ix++) { - RowItem item = modifiedItems.get(ix); - if (item.getId().equals(itemId)) { - return ix; - } - } - return -1; - } - - private int sizeOfAddedItems() { - return getFilteredAddedItems().size(); - } - - private List<RowItem> getFilteredAddedItems() { - ArrayList<RowItem> filtered = new ArrayList<RowItem>(addedItems); - if (filters != null && !filters.isEmpty()) { - for (RowItem item : addedItems) { - if (!itemPassesFilters(item)) { - filtered.remove(item); - } - } - } - return filtered; - } - - private boolean itemPassesFilters(RowItem item) { - for (Filter filter : filters) { - if (!filter.passesFilter(item.getId(), item)) { - return false; - } - } - return true; - } - - /** - * Checks is the given column identifier valid to be used with SQLContainer. - * Currently the only non-valid identifier is "rownum" when MSSQL or Oracle - * is used. This is due to the way the SELECT queries are constructed in - * order to implement paging in these databases. - * - * @param identifier - * Column identifier - * @return true if the identifier is valid - */ - private boolean isColumnIdentifierValid(String identifier) { - if (identifier.equalsIgnoreCase("rownum") - && delegate instanceof TableQuery) { - TableQuery tq = (TableQuery) delegate; - if (tq.getSqlGenerator() instanceof MSSQLGenerator - || tq.getSqlGenerator() instanceof OracleGenerator) { - return false; - } - } - return true; - } - - /** - * Returns the QueryDelegate set for this SQLContainer. - * - * @return current querydelegate - */ - protected QueryDelegate getQueryDelegate() { - return delegate; - } - - /************************************/ - /** UNSUPPORTED CONTAINER FEATURES **/ - /************************************/ - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addContainerProperty(java.lang.Object, - * java.lang.Class, java.lang.Object) - */ - - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeContainerProperty(java.lang.Object) - */ - - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#addItem(java.lang.Object) - */ - - @Override - public Item addItem(Object itemId) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object, - * java.lang.Object) - */ - - @Override - public Item addItemAfter(Object previousItemId, Object newItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Indexed#addItemAt(int, java.lang.Object) - */ - - @Override - public Item addItemAt(int index, Object newItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Indexed#addItemAt(int) - */ - - @Override - public Object addItemAt(int index) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object) - */ - - @Override - public Object addItemAfter(Object previousItemId) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /******************************************/ - /** ITEMSETCHANGENOTIFIER IMPLEMENTATION **/ - /******************************************/ - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.Container.ItemSetChangeNotifier#addListener(com.vaadin - * .data.Container.ItemSetChangeListener) - */ - - @Override - public void addListener(Container.ItemSetChangeListener listener) { - if (itemSetChangeListeners == null) { - itemSetChangeListeners = new LinkedList<Container.ItemSetChangeListener>(); - } - itemSetChangeListeners.add(listener); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.Container.ItemSetChangeNotifier#removeListener(com.vaadin - * .data.Container.ItemSetChangeListener) - */ - - @Override - public void removeListener(Container.ItemSetChangeListener listener) { - if (itemSetChangeListeners != null) { - itemSetChangeListeners.remove(listener); - } - } - - protected void fireContentsChange() { - if (itemSetChangeListeners != null) { - final Object[] l = itemSetChangeListeners.toArray(); - final Container.ItemSetChangeEvent event = new SQLContainer.ItemSetChangeEvent( - this); - for (int i = 0; i < l.length; i++) { - ((Container.ItemSetChangeListener) l[i]) - .containerItemSetChange(event); - } - } - } - - /** - * Simple ItemSetChangeEvent implementation. - */ - @SuppressWarnings("serial") - public static class ItemSetChangeEvent extends EventObject implements - Container.ItemSetChangeEvent { - - private ItemSetChangeEvent(SQLContainer source) { - super(source); - } - - @Override - public Container getContainer() { - return (Container) getSource(); - } - } - - /**************************************************/ - /** ROWIDCHANGELISTENER PASSING TO QUERYDELEGATE **/ - /**************************************************/ - - /** - * Adds a RowIdChangeListener to the QueryDelegate - * - * @param listener - */ - public void addListener(RowIdChangeListener listener) { - if (delegate instanceof QueryDelegate.RowIdChangeNotifier) { - ((QueryDelegate.RowIdChangeNotifier) delegate) - .addListener(listener); - } - } - - /** - * Removes a RowIdChangeListener from the QueryDelegate - * - * @param listener - */ - public void removeListener(RowIdChangeListener listener) { - if (delegate instanceof QueryDelegate.RowIdChangeNotifier) { - ((QueryDelegate.RowIdChangeNotifier) delegate) - .removeListener(listener); - } - } - - /** - * Calling this will enable this SQLContainer to send and receive cache - * flush notifications for its lifetime. - */ - public void enableCacheFlushNotifications() { - if (!notificationsEnabled) { - notificationsEnabled = true; - CacheFlushNotifier.addInstance(this); - } - } - - /******************************************/ - /** Referencing mechanism implementation **/ - /******************************************/ - - /** - * Adds a new reference to the given SQLContainer. In addition to the - * container you must provide the column (property) names used for the - * reference in both this and the referenced SQLContainer. - * - * Note that multiple references pointing to the same SQLContainer are not - * supported. - * - * @param refdCont - * Target SQLContainer of the new reference - * @param refingCol - * Column (property) name in this container storing the (foreign - * key) reference - * @param refdCol - * Column (property) name in the referenced container storing the - * referenced key - */ - public void addReference(SQLContainer refdCont, String refingCol, - String refdCol) { - if (refdCont == null) { - throw new IllegalArgumentException( - "Referenced SQLContainer can not be null."); - } - if (!getContainerPropertyIds().contains(refingCol)) { - throw new IllegalArgumentException( - "Given referencing column name is invalid." - + " Please ensure that this container" - + " contains a property ID named: " + refingCol); - } - if (!refdCont.getContainerPropertyIds().contains(refdCol)) { - throw new IllegalArgumentException( - "Given referenced column name is invalid." - + " Please ensure that the referenced container" - + " contains a property ID named: " + refdCol); - } - if (references.keySet().contains(refdCont)) { - throw new IllegalArgumentException( - "An SQLContainer instance can only be referenced once."); - } - references.put(refdCont, new Reference(refdCont, refingCol, refdCol)); - } - - /** - * Removes the reference pointing to the given SQLContainer. - * - * @param refdCont - * Target SQLContainer of the reference - * @return true if successful, false if the reference did not exist - */ - public boolean removeReference(SQLContainer refdCont) { - if (refdCont == null) { - throw new IllegalArgumentException( - "Referenced SQLContainer can not be null."); - } - return references.remove(refdCont) == null ? false : true; - } - - /** - * Sets the referenced item. The referencing column of the item in this - * container is updated accordingly. - * - * @param itemId - * Item Id of the reference source (from this container) - * @param refdItemId - * Item Id of the reference target (from referenced container) - * @param refdCont - * Target SQLContainer of the reference - * @return true if the referenced item was successfully set, false on - * failure - */ - public boolean setReferencedItem(Object itemId, Object refdItemId, - SQLContainer refdCont) { - if (refdCont == null) { - throw new IllegalArgumentException( - "Referenced SQLContainer can not be null."); - } - Reference r = references.get(refdCont); - if (r == null) { - throw new IllegalArgumentException( - "Reference to the given SQLContainer not defined."); - } - try { - getContainerProperty(itemId, r.getReferencingColumn()).setValue( - refdCont.getContainerProperty(refdItemId, - r.getReferencedColumn())); - return true; - } catch (Exception e) { - getLogger() - .log(Level.WARNING, "Setting referenced item failed.", e); - return false; - } - } - - /** - * Fetches the Item Id of the referenced item from the target SQLContainer. - * - * @param itemId - * Item Id of the reference source (from this container) - * @param refdCont - * Target SQLContainer of the reference - * @return Item Id of the referenced item, or null if not found - */ - public Object getReferencedItemId(Object itemId, SQLContainer refdCont) { - if (refdCont == null) { - throw new IllegalArgumentException( - "Referenced SQLContainer can not be null."); - } - Reference r = references.get(refdCont); - if (r == null) { - throw new IllegalArgumentException( - "Reference to the given SQLContainer not defined."); - } - Object refKey = getContainerProperty(itemId, r.getReferencingColumn()) - .getValue(); - - refdCont.removeAllContainerFilters(); - refdCont.addContainerFilter(new Equal(r.getReferencedColumn(), refKey)); - Object toReturn = refdCont.firstItemId(); - refdCont.removeAllContainerFilters(); - return toReturn; - } - - /** - * Fetches the referenced item from the target SQLContainer. - * - * @param itemId - * Item Id of the reference source (from this container) - * @param refdCont - * Target SQLContainer of the reference - * @return The referenced item, or null if not found - */ - public Item getReferencedItem(Object itemId, SQLContainer refdCont) { - return refdCont.getItem(getReferencedItemId(itemId, refdCont)); - } - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - } - - private void readObject(java.io.ObjectInputStream in) throws IOException, - ClassNotFoundException { - in.defaultReadObject(); - if (notificationsEnabled) { - /* - * Register instance with CacheFlushNotifier after de-serialization - * if notifications are enabled - */ - CacheFlushNotifier.addInstance(this); - } - } - - private static final Logger getLogger() { - return Logger.getLogger(SQLContainer.class.getName()); - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/SQLUtil.java b/src/com/vaadin/data/util/sqlcontainer/SQLUtil.java deleted file mode 100644 index 4a48dbf499..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/SQLUtil.java +++ /dev/null @@ -1,36 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -import java.io.Serializable; - -public class SQLUtil implements Serializable { - /** - * Escapes different special characters in strings that are passed to SQL. - * Replaces the following: - * - * <list> <li>' is replaced with ''</li> <li>\x00 is removed</li> <li>\ is - * replaced with \\</li> <li>" is replaced with \"</li> <li> - * \x1a is removed</li> </list> - * - * Also note! The escaping done here may or may not be enough to prevent any - * and all SQL injections so it is recommended to check user input before - * giving it to the SQLContainer/TableQuery. - * - * @param constant - * @return \\\'\' - */ - public static String escapeSQL(String constant) { - if (constant == null) { - return null; - } - String fixedConstant = constant; - fixedConstant = fixedConstant.replaceAll("\\\\x00", ""); - fixedConstant = fixedConstant.replaceAll("\\\\x1a", ""); - fixedConstant = fixedConstant.replaceAll("'", "''"); - fixedConstant = fixedConstant.replaceAll("\\\\", "\\\\\\\\"); - fixedConstant = fixedConstant.replaceAll("\\\"", "\\\\\""); - return fixedConstant; - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/TemporaryRowId.java b/src/com/vaadin/data/util/sqlcontainer/TemporaryRowId.java deleted file mode 100644 index b4bca75a2a..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/TemporaryRowId.java +++ /dev/null @@ -1,32 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer; - -public class TemporaryRowId extends RowId { - private static final long serialVersionUID = -641983830469018329L; - - public TemporaryRowId(Object[] id) { - super(id); - } - - @Override - public int hashCode() { - return id.hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj == null || !(obj instanceof TemporaryRowId)) { - return false; - } - Object[] compId = ((TemporaryRowId) obj).getId(); - return id.equals(compId); - } - - @Override - public String toString() { - return "Temporary row id"; - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/connection/J2EEConnectionPool.java b/src/com/vaadin/data/util/sqlcontainer/connection/J2EEConnectionPool.java deleted file mode 100644 index 9aa4f7c4be..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/connection/J2EEConnectionPool.java +++ /dev/null @@ -1,72 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.connection; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.naming.InitialContext; -import javax.naming.NamingException; -import javax.sql.DataSource; - -public class J2EEConnectionPool implements JDBCConnectionPool { - - private String dataSourceJndiName; - - private DataSource dataSource = null; - - public J2EEConnectionPool(DataSource dataSource) { - this.dataSource = dataSource; - } - - public J2EEConnectionPool(String dataSourceJndiName) { - this.dataSourceJndiName = dataSourceJndiName; - } - - @Override - public Connection reserveConnection() throws SQLException { - Connection conn = getDataSource().getConnection(); - conn.setAutoCommit(false); - - return conn; - } - - private DataSource getDataSource() throws SQLException { - if (dataSource == null) { - dataSource = lookupDataSource(); - } - return dataSource; - } - - private DataSource lookupDataSource() throws SQLException { - try { - InitialContext ic = new InitialContext(); - return (DataSource) ic.lookup(dataSourceJndiName); - } catch (NamingException e) { - throw new SQLException( - "NamingException - Cannot connect to the database. Cause: " - + e.getMessage()); - } - } - - @Override - public void releaseConnection(Connection conn) { - if (conn != null) { - try { - conn.close(); - } catch (SQLException e) { - Logger.getLogger(J2EEConnectionPool.class.getName()).log( - Level.FINE, "Could not release SQL connection", e); - } - } - } - - @Override - public void destroy() { - dataSource = null; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/data/util/sqlcontainer/connection/JDBCConnectionPool.java b/src/com/vaadin/data/util/sqlcontainer/connection/JDBCConnectionPool.java deleted file mode 100644 index cf12461588..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/connection/JDBCConnectionPool.java +++ /dev/null @@ -1,41 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.connection; - -import java.io.Serializable; -import java.sql.Connection; -import java.sql.SQLException; - -/** - * Interface for implementing connection pools to be used with SQLContainer. - */ -public interface JDBCConnectionPool extends Serializable { - /** - * Retrieves a connection. - * - * @return a usable connection to the database - * @throws SQLException - */ - public Connection reserveConnection() throws SQLException; - - /** - * Releases a connection that was retrieved earlier. - * - * Note that depending on implementation, the transaction possibly open in - * the connection may or may not be rolled back. - * - * @param conn - * Connection to be released - */ - public void releaseConnection(Connection conn); - - /** - * Destroys the connection pool: close() is called an all the connections in - * the pool, whether available or reserved. - * - * This method was added to fix PostgreSQL -related issues with connections - * that were left hanging 'idle'. - */ - public void destroy(); -} diff --git a/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPool.java b/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPool.java deleted file mode 100644 index 21760014b9..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/connection/SimpleJDBCConnectionPool.java +++ /dev/null @@ -1,168 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.connection; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.HashSet; -import java.util.Set; - -/** - * Simple implementation of the JDBCConnectionPool interface. Handles loading - * the JDBC driver, setting up the connections and ensuring they are still - * usable upon release. - */ -@SuppressWarnings("serial") -public class SimpleJDBCConnectionPool implements JDBCConnectionPool { - - private int initialConnections = 5; - private int maxConnections = 20; - - private String driverName; - private String connectionUri; - private String userName; - private String password; - - private transient Set<Connection> availableConnections; - private transient Set<Connection> reservedConnections; - - private boolean initialized; - - public SimpleJDBCConnectionPool(String driverName, String connectionUri, - String userName, String password) throws SQLException { - if (driverName == null) { - throw new IllegalArgumentException( - "JDBC driver class name must be given."); - } - if (connectionUri == null) { - throw new IllegalArgumentException( - "Database connection URI must be given."); - } - if (userName == null) { - throw new IllegalArgumentException( - "Database username must be given."); - } - if (password == null) { - throw new IllegalArgumentException( - "Database password must be given."); - } - this.driverName = driverName; - this.connectionUri = connectionUri; - this.userName = userName; - this.password = password; - - /* Initialize JDBC driver */ - try { - Class.forName(driverName).newInstance(); - } catch (Exception ex) { - throw new RuntimeException("Specified JDBC Driver: " + driverName - + " - initialization failed.", ex); - } - } - - public SimpleJDBCConnectionPool(String driverName, String connectionUri, - String userName, String password, int initialConnections, - int maxConnections) throws SQLException { - this(driverName, connectionUri, userName, password); - this.initialConnections = initialConnections; - this.maxConnections = maxConnections; - } - - private void initializeConnections() throws SQLException { - availableConnections = new HashSet<Connection>(initialConnections); - reservedConnections = new HashSet<Connection>(initialConnections); - for (int i = 0; i < initialConnections; i++) { - availableConnections.add(createConnection()); - } - initialized = true; - } - - @Override - public synchronized Connection reserveConnection() throws SQLException { - if (!initialized) { - initializeConnections(); - } - if (availableConnections.isEmpty()) { - if (reservedConnections.size() < maxConnections) { - availableConnections.add(createConnection()); - } else { - throw new SQLException("Connection limit has been reached."); - } - } - - Connection c = availableConnections.iterator().next(); - availableConnections.remove(c); - reservedConnections.add(c); - - return c; - } - - @Override - public synchronized void releaseConnection(Connection conn) { - if (conn == null || !initialized) { - return; - } - /* Try to roll back if necessary */ - try { - if (!conn.getAutoCommit()) { - conn.rollback(); - } - } catch (SQLException e) { - /* Roll back failed, close and discard connection */ - try { - conn.close(); - } catch (SQLException e1) { - /* Nothing needs to be done */ - } - reservedConnections.remove(conn); - return; - } - reservedConnections.remove(conn); - availableConnections.add(conn); - } - - private Connection createConnection() throws SQLException { - Connection c = DriverManager.getConnection(connectionUri, userName, - password); - c.setAutoCommit(false); - if (driverName.toLowerCase().contains("mysql")) { - try { - Statement s = c.createStatement(); - s.execute("SET SESSION sql_mode = 'ANSI'"); - s.close(); - } catch (Exception e) { - // Failed to set ansi mode; continue - } - } - return c; - } - - @Override - public void destroy() { - for (Connection c : availableConnections) { - try { - c.close(); - } catch (SQLException e) { - // No need to do anything - } - } - for (Connection c : reservedConnections) { - try { - c.close(); - } catch (SQLException e) { - // No need to do anything - } - } - - } - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - initialized = false; - out.defaultWriteObject(); - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java b/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java deleted file mode 100644 index ec986fab95..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQuery.java +++ /dev/null @@ -1,507 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.RowItem; -import com.vaadin.data.util.sqlcontainer.SQLContainer; -import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; -import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; - -@SuppressWarnings("serial") -public class FreeformQuery implements QueryDelegate { - - FreeformQueryDelegate delegate = null; - private String queryString; - private List<String> primaryKeyColumns; - private JDBCConnectionPool connectionPool; - private transient Connection activeConnection = null; - - /** - * Prevent no-parameters instantiation of FreeformQuery - */ - @SuppressWarnings("unused") - private FreeformQuery() { - } - - /** - * Creates a new freeform query delegate to be used with the - * {@link SQLContainer}. - * - * @param queryString - * The actual query to perform. - * @param primaryKeyColumns - * The primary key columns. Read-only mode is forced if this - * parameter is null or empty. - * @param connectionPool - * the JDBCConnectionPool to use to open connections to the SQL - * database. - * @deprecated @see - * {@link FreeformQuery#FreeformQuery(String, JDBCConnectionPool, String...)} - */ - @Deprecated - public FreeformQuery(String queryString, List<String> primaryKeyColumns, - JDBCConnectionPool connectionPool) { - if (primaryKeyColumns == null) { - primaryKeyColumns = new ArrayList<String>(); - } - if (primaryKeyColumns.contains("")) { - throw new IllegalArgumentException( - "The primary key columns contain an empty string!"); - } else if (queryString == null || "".equals(queryString)) { - throw new IllegalArgumentException( - "The query string may not be empty or null!"); - } else if (connectionPool == null) { - throw new IllegalArgumentException( - "The connectionPool may not be null!"); - } - this.queryString = queryString; - this.primaryKeyColumns = Collections - .unmodifiableList(primaryKeyColumns); - this.connectionPool = connectionPool; - } - - /** - * Creates a new freeform query delegate to be used with the - * {@link SQLContainer}. - * - * @param queryString - * The actual query to perform. - * @param connectionPool - * the JDBCConnectionPool to use to open connections to the SQL - * database. - * @param primaryKeyColumns - * The primary key columns. Read-only mode is forced if none are - * provided. (optional) - */ - public FreeformQuery(String queryString, JDBCConnectionPool connectionPool, - String... primaryKeyColumns) { - this(queryString, Arrays.asList(primaryKeyColumns), connectionPool); - } - - /** - * This implementation of getCount() actually fetches all records from the - * database, which might be a performance issue. Override this method with a - * SELECT COUNT(*) ... query if this is too slow for your needs. - * - * {@inheritDoc} - */ - @Override - public int getCount() throws SQLException { - // First try the delegate - int count = countByDelegate(); - if (count < 0) { - // Couldn't use the delegate, use the bad way. - Connection conn = getConnection(); - Statement statement = conn.createStatement( - ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY); - - ResultSet rs = statement.executeQuery(queryString); - if (rs.last()) { - count = rs.getRow(); - } else { - count = 0; - } - rs.close(); - statement.close(); - releaseConnection(conn); - } - return count; - } - - @SuppressWarnings("deprecation") - private int countByDelegate() throws SQLException { - int count = -1; - if (delegate == null) { - return count; - } - /* First try using prepared statement */ - if (delegate instanceof FreeformStatementDelegate) { - try { - StatementHelper sh = ((FreeformStatementDelegate) delegate) - .getCountStatement(); - Connection c = getConnection(); - PreparedStatement pstmt = c.prepareStatement(sh - .getQueryString()); - sh.setParameterValuesToStatement(pstmt); - ResultSet rs = pstmt.executeQuery(); - rs.next(); - count = rs.getInt(1); - rs.close(); - pstmt.clearParameters(); - pstmt.close(); - releaseConnection(c); - return count; - } catch (UnsupportedOperationException e) { - // Count statement generation not supported - } - } - /* Try using regular statement */ - try { - String countQuery = delegate.getCountQuery(); - if (countQuery != null) { - Connection conn = getConnection(); - Statement statement = conn.createStatement(); - ResultSet rs = statement.executeQuery(countQuery); - rs.next(); - count = rs.getInt(1); - rs.close(); - statement.close(); - releaseConnection(conn); - return count; - } - } catch (UnsupportedOperationException e) { - // Count query generation not supported - } - return count; - } - - private Connection getConnection() throws SQLException { - if (activeConnection != null) { - return activeConnection; - } - return connectionPool.reserveConnection(); - } - - /** - * Fetches the results for the query. This implementation always fetches the - * entire record set, ignoring the offset and page length parameters. In - * order to support lazy loading of records, you must supply a - * FreeformQueryDelegate that implements the - * FreeformQueryDelegate.getQueryString(int,int) method. - * - * @throws SQLException - * - * @see FreeformQueryDelegate#getQueryString(int, int) - */ - @Override - @SuppressWarnings("deprecation") - public ResultSet getResults(int offset, int pagelength) throws SQLException { - if (activeConnection == null) { - throw new SQLException("No active transaction!"); - } - String query = queryString; - if (delegate != null) { - /* First try using prepared statement */ - if (delegate instanceof FreeformStatementDelegate) { - try { - StatementHelper sh = ((FreeformStatementDelegate) delegate) - .getQueryStatement(offset, pagelength); - PreparedStatement pstmt = activeConnection - .prepareStatement(sh.getQueryString()); - sh.setParameterValuesToStatement(pstmt); - return pstmt.executeQuery(); - } catch (UnsupportedOperationException e) { - // Statement generation not supported, continue... - } - } - try { - query = delegate.getQueryString(offset, pagelength); - } catch (UnsupportedOperationException e) { - // This is fine, we'll just use the default queryString. - } - } - Statement statement = activeConnection.createStatement(); - ResultSet rs = statement.executeQuery(query); - return rs; - } - - @Override - @SuppressWarnings("deprecation") - public boolean implementationRespectsPagingLimits() { - if (delegate == null) { - return false; - } - /* First try using prepared statement */ - if (delegate instanceof FreeformStatementDelegate) { - try { - StatementHelper sh = ((FreeformStatementDelegate) delegate) - .getCountStatement(); - if (sh != null && sh.getQueryString() != null - && sh.getQueryString().length() > 0) { - return true; - } - } catch (UnsupportedOperationException e) { - // Statement generation not supported, continue... - } - } - try { - String queryString = delegate.getQueryString(0, 50); - return queryString != null && queryString.length() > 0; - } catch (UnsupportedOperationException e) { - return false; - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#setFilters(java - * .util.List) - */ - @Override - public void setFilters(List<Filter> filters) - throws UnsupportedOperationException { - if (delegate != null) { - delegate.setFilters(filters); - } else if (filters != null) { - throw new UnsupportedOperationException( - "FreeFormQueryDelegate not set!"); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#setOrderBy(java - * .util.List) - */ - @Override - public void setOrderBy(List<OrderBy> orderBys) - throws UnsupportedOperationException { - if (delegate != null) { - delegate.setOrderBy(orderBys); - } else if (orderBys != null) { - throw new UnsupportedOperationException( - "FreeFormQueryDelegate not set!"); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#storeRow(com.vaadin - * .data.util.sqlcontainer.RowItem) - */ - @Override - public int storeRow(RowItem row) throws SQLException { - if (activeConnection == null) { - throw new IllegalStateException("No transaction is active!"); - } else if (primaryKeyColumns.isEmpty()) { - throw new UnsupportedOperationException( - "Cannot store items fetched with a read-only freeform query!"); - } - if (delegate != null) { - return delegate.storeRow(activeConnection, row); - } else { - throw new UnsupportedOperationException( - "FreeFormQueryDelegate not set!"); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#removeRow(com.vaadin - * .data.util.sqlcontainer.RowItem) - */ - @Override - public boolean removeRow(RowItem row) throws SQLException { - if (activeConnection == null) { - throw new IllegalStateException("No transaction is active!"); - } else if (primaryKeyColumns.isEmpty()) { - throw new UnsupportedOperationException( - "Cannot remove items fetched with a read-only freeform query!"); - } - if (delegate != null) { - return delegate.removeRow(activeConnection, row); - } else { - throw new UnsupportedOperationException( - "FreeFormQueryDelegate not set!"); - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#beginTransaction() - */ - @Override - public synchronized void beginTransaction() - throws UnsupportedOperationException, SQLException { - if (activeConnection != null) { - throw new IllegalStateException("A transaction is already active!"); - } - activeConnection = connectionPool.reserveConnection(); - activeConnection.setAutoCommit(false); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#commit() - */ - @Override - public synchronized void commit() throws UnsupportedOperationException, - SQLException { - if (activeConnection == null) { - throw new SQLException("No active transaction"); - } - if (!activeConnection.getAutoCommit()) { - activeConnection.commit(); - } - connectionPool.releaseConnection(activeConnection); - activeConnection = null; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.util.sqlcontainer.query.QueryDelegate#rollback() - */ - @Override - public synchronized void rollback() throws UnsupportedOperationException, - SQLException { - if (activeConnection == null) { - throw new SQLException("No active transaction"); - } - activeConnection.rollback(); - connectionPool.releaseConnection(activeConnection); - activeConnection = null; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.util.sqlcontainer.query.QueryDelegate#getPrimaryKeyColumns - * () - */ - @Override - public List<String> getPrimaryKeyColumns() { - return primaryKeyColumns; - } - - public String getQueryString() { - return queryString; - } - - public FreeformQueryDelegate getDelegate() { - return delegate; - } - - public void setDelegate(FreeformQueryDelegate delegate) { - this.delegate = delegate; - } - - /** - * This implementation of the containsRowWithKey method rewrites existing - * WHERE clauses in the query string. The logic is, however, not very - * complex and some times can do the Wrong Thing<sup>TM</sup>. For the - * situations where this logic is not enough, you can implement the - * getContainsRowQueryString method in FreeformQueryDelegate and this will - * be used instead of the logic. - * - * @see FreeformQueryDelegate#getContainsRowQueryString(Object...) - * - */ - @Override - @SuppressWarnings("deprecation") - public boolean containsRowWithKey(Object... keys) throws SQLException { - String query = null; - boolean contains = false; - if (delegate != null) { - if (delegate instanceof FreeformStatementDelegate) { - try { - StatementHelper sh = ((FreeformStatementDelegate) delegate) - .getContainsRowQueryStatement(keys); - Connection c = getConnection(); - PreparedStatement pstmt = c.prepareStatement(sh - .getQueryString()); - sh.setParameterValuesToStatement(pstmt); - ResultSet rs = pstmt.executeQuery(); - contains = rs.next(); - rs.close(); - pstmt.clearParameters(); - pstmt.close(); - releaseConnection(c); - return contains; - } catch (UnsupportedOperationException e) { - // Statement generation not supported, continue... - } - } - try { - query = delegate.getContainsRowQueryString(keys); - } catch (UnsupportedOperationException e) { - query = modifyWhereClause(keys); - } - } else { - query = modifyWhereClause(keys); - } - Connection conn = getConnection(); - try { - Statement statement = conn.createStatement(); - ResultSet rs = statement.executeQuery(query); - contains = rs.next(); - rs.close(); - statement.close(); - } finally { - releaseConnection(conn); - } - return contains; - } - - /** - * Releases the connection if it is not part of an active transaction. - * - * @param conn - * the connection to release - */ - private void releaseConnection(Connection conn) { - if (conn != activeConnection) { - connectionPool.releaseConnection(conn); - } - } - - private String modifyWhereClause(Object... keys) { - // Build the where rules for the provided keys - StringBuffer where = new StringBuffer(); - for (int ix = 0; ix < primaryKeyColumns.size(); ix++) { - where.append(QueryBuilder.quote(primaryKeyColumns.get(ix))); - if (keys[ix] == null) { - where.append(" IS NULL"); - } else { - where.append(" = '").append(keys[ix]).append("'"); - } - if (ix < primaryKeyColumns.size() - 1) { - where.append(" AND "); - } - } - // Is there already a WHERE clause in the query string? - int index = queryString.toLowerCase().indexOf("where "); - if (index > -1) { - // Rewrite the where clause - return queryString.substring(0, index) + "WHERE " + where + " AND " - + queryString.substring(index + 6); - } - // Append a where clause - return queryString + " WHERE " + where; - } - - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - try { - rollback(); - } catch (SQLException ignored) { - } - out.defaultWriteObject(); - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryDelegate.java b/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryDelegate.java deleted file mode 100644 index 433d742be8..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/FreeformQueryDelegate.java +++ /dev/null @@ -1,118 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query; - -import java.io.Serializable; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.List; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.RowItem; - -public interface FreeformQueryDelegate extends Serializable { - /** - * Should return the SQL query string to be performed. This method is - * responsible for gluing together the select query from the filters and the - * order by conditions if these are supported. - * - * @param offset - * the first record (row) to fetch. - * @param pagelength - * the number of records (rows) to fetch. 0 means all records - * starting from offset. - * @deprecated Implement {@link FreeformStatementDelegate} instead of - * {@link FreeformQueryDelegate} - */ - @Deprecated - public String getQueryString(int offset, int limit) - throws UnsupportedOperationException; - - /** - * Generates and executes a query to determine the current row count from - * the DB. Row count will be fetched using filters that are currently set to - * the QueryDelegate. - * - * @return row count - * @throws SQLException - * @deprecated Implement {@link FreeformStatementDelegate} instead of - * {@link FreeformQueryDelegate} - */ - @Deprecated - public String getCountQuery() throws UnsupportedOperationException; - - /** - * Sets the filters to apply when performing the SQL query. These are - * translated into a WHERE clause. Default filtering mode will be used. - * - * @param filters - * The filters to apply. - * @throws UnsupportedOperationException - * if the implementation doesn't support filtering. - */ - public void setFilters(List<Filter> filters) - throws UnsupportedOperationException; - - /** - * Sets the order in which to retrieve rows from the database. The result - * can be ordered by zero or more columns and each column can be in - * ascending or descending order. These are translated into an ORDER BY - * clause in the SQL query. - * - * @param orderBys - * A list of the OrderBy conditions. - * @throws UnsupportedOperationException - * if the implementation doesn't support ordering. - */ - public void setOrderBy(List<OrderBy> orderBys) - throws UnsupportedOperationException; - - /** - * Stores a row in the database. The implementation of this interface - * decides how to identify whether to store a new row or update an existing - * one. - * - * @param conn - * the JDBC connection to use - * @param row - * RowItem to be stored or updated. - * @throws UnsupportedOperationException - * if the implementation is read only. - * @throws SQLException - */ - public int storeRow(Connection conn, RowItem row) - throws UnsupportedOperationException, SQLException; - - /** - * Removes the given RowItem from the database. - * - * @param conn - * the JDBC connection to use - * @param row - * RowItem to be removed - * @return true on success - * @throws UnsupportedOperationException - * @throws SQLException - */ - public boolean removeRow(Connection conn, RowItem row) - throws UnsupportedOperationException, SQLException; - - /** - * Generates an SQL Query string that allows the user of the FreeformQuery - * class to customize the query string used by the - * FreeformQuery.containsRowWithKeys() method. This is useful for cases when - * the logic in the containsRowWithKeys method is not enough to support more - * complex free form queries. - * - * @param keys - * the values of the primary keys - * @throws UnsupportedOperationException - * to use the default logic in FreeformQuery - * @deprecated Implement {@link FreeformStatementDelegate} instead of - * {@link FreeformQueryDelegate} - */ - @Deprecated - public String getContainsRowQueryString(Object... keys) - throws UnsupportedOperationException; -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/FreeformStatementDelegate.java b/src/com/vaadin/data/util/sqlcontainer/query/FreeformStatementDelegate.java deleted file mode 100644 index 95521c5019..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/FreeformStatementDelegate.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query; - -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -/** - * FreeformStatementDelegate is an extension to FreeformQueryDelegate that - * provides definitions for methods that produce StatementHelper objects instead - * of basic query strings. This allows the FreeformQuery query delegate to use - * PreparedStatements instead of regular Statement when accessing the database. - * - * Due to the injection protection and other benefits of prepared statements, it - * is advisable to implement this interface instead of the FreeformQueryDelegate - * whenever possible. - */ -public interface FreeformStatementDelegate extends FreeformQueryDelegate { - /** - * Should return a new instance of StatementHelper that contains the query - * string and parameter values required to create a PreparedStatement. This - * method is responsible for gluing together the select query from the - * filters and the order by conditions if these are supported. - * - * @param offset - * the first record (row) to fetch. - * @param pagelength - * the number of records (rows) to fetch. 0 means all records - * starting from offset. - */ - public StatementHelper getQueryStatement(int offset, int limit) - throws UnsupportedOperationException; - - /** - * Should return a new instance of StatementHelper that contains the query - * string and parameter values required to create a PreparedStatement that - * will fetch the row count from the DB. Row count should be fetched using - * filters that are currently set to the QueryDelegate. - */ - public StatementHelper getCountStatement() - throws UnsupportedOperationException; - - /** - * Should return a new instance of StatementHelper that contains the query - * string and parameter values required to create a PreparedStatement used - * by the FreeformQuery.containsRowWithKeys() method. This is useful for - * cases when the default logic in said method is not enough to support more - * complex free form queries. - * - * @param keys - * the values of the primary keys - * @throws UnsupportedOperationException - * to use the default logic in FreeformQuery - */ - public StatementHelper getContainsRowQueryStatement(Object... keys) - throws UnsupportedOperationException; -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/OrderBy.java b/src/com/vaadin/data/util/sqlcontainer/query/OrderBy.java deleted file mode 100644 index 8ebe10067e..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/OrderBy.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query; - -import java.io.Serializable; - -/** - * OrderBy represents a sorting rule to be applied to a query made by the - * SQLContainer's QueryDelegate. - * - * The sorting rule is simple and contains only the affected column's name and - * the direction of the sort. - */ -public class OrderBy implements Serializable { - private String column; - private boolean isAscending; - - /** - * Prevent instantiation without required parameters. - */ - @SuppressWarnings("unused") - private OrderBy() { - } - - public OrderBy(String column, boolean isAscending) { - setColumn(column); - setAscending(isAscending); - } - - public void setColumn(String column) { - this.column = column; - } - - public String getColumn() { - return column; - } - - public void setAscending(boolean isAscending) { - this.isAscending = isAscending; - } - - public boolean isAscending() { - return isAscending; - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/QueryDelegate.java b/src/com/vaadin/data/util/sqlcontainer/query/QueryDelegate.java deleted file mode 100644 index 6e4396fad1..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/QueryDelegate.java +++ /dev/null @@ -1,211 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query; - -import java.io.Serializable; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.RowId; -import com.vaadin.data.util.sqlcontainer.RowItem; - -public interface QueryDelegate extends Serializable { - /** - * Generates and executes a query to determine the current row count from - * the DB. Row count will be fetched using filters that are currently set to - * the QueryDelegate. - * - * @return row count - * @throws SQLException - */ - public int getCount() throws SQLException; - - /** - * Executes a paged SQL query and returns the ResultSet. The query is - * defined through implementations of this QueryDelegate interface. - * - * @param offset - * the first item of the page to load - * @param pagelength - * the length of the page to load - * @return a ResultSet containing the rows of the page - * @throws SQLException - * if the database access fails. - */ - public ResultSet getResults(int offset, int pagelength) throws SQLException; - - /** - * Allows the SQLContainer implementation to check whether the QueryDelegate - * implementation implements paging in the getResults method. - * - * @see QueryDelegate#getResults(int, int) - * - * @return true if the delegate implements paging - */ - public boolean implementationRespectsPagingLimits(); - - /** - * Sets the filters to apply when performing the SQL query. These are - * translated into a WHERE clause. Default filtering mode will be used. - * - * @param filters - * The filters to apply. - * @throws UnsupportedOperationException - * if the implementation doesn't support filtering. - */ - public void setFilters(List<Filter> filters) - throws UnsupportedOperationException; - - /** - * Sets the order in which to retrieve rows from the database. The result - * can be ordered by zero or more columns and each column can be in - * ascending or descending order. These are translated into an ORDER BY - * clause in the SQL query. - * - * @param orderBys - * A list of the OrderBy conditions. - * @throws UnsupportedOperationException - * if the implementation doesn't support ordering. - */ - public void setOrderBy(List<OrderBy> orderBys) - throws UnsupportedOperationException; - - /** - * Stores a row in the database. The implementation of this interface - * decides how to identify whether to store a new row or update an existing - * one. - * - * @param columnToValueMap - * A map containing the values for all columns to be stored or - * updated. - * @return the number of affected rows in the database table - * @throws UnsupportedOperationException - * if the implementation is read only. - */ - public int storeRow(RowItem row) throws UnsupportedOperationException, - SQLException; - - /** - * Removes the given RowItem from the database. - * - * @param row - * RowItem to be removed - * @return true on success - * @throws UnsupportedOperationException - * @throws SQLException - */ - public boolean removeRow(RowItem row) throws UnsupportedOperationException, - SQLException; - - /** - * Starts a new database transaction. Used when storing multiple changes. - * - * Note that if a transaction is already open, it will be rolled back when a - * new transaction is started. - * - * @throws SQLException - * if the database access fails. - */ - public void beginTransaction() throws SQLException; - - /** - * Commits a transaction. If a transaction is not open nothing should - * happen. - * - * @throws SQLException - * if the database access fails. - */ - public void commit() throws SQLException; - - /** - * Rolls a transaction back. If a transaction is not open nothing should - * happen. - * - * @throws SQLException - * if the database access fails. - */ - public void rollback() throws SQLException; - - /** - * Returns a list of primary key column names. The list is either fetched - * from the database (TableQuery) or given as an argument depending on - * implementation. - * - * @return - */ - public List<String> getPrimaryKeyColumns(); - - /** - * Performs a query to find out whether the SQL table contains a row with - * the given set of primary keys. - * - * @param keys - * the primary keys - * @return true if the SQL table contains a row with the provided keys - * @throws SQLException - */ - public boolean containsRowWithKey(Object... keys) throws SQLException; - - /************************/ - /** ROWID CHANGE EVENT **/ - /************************/ - - /** - * An <code>Event</code> object specifying the old and new RowId of an added - * item after the addition has been successfully committed. - */ - public interface RowIdChangeEvent extends Serializable { - /** - * Gets the old (temporary) RowId of the added row that raised this - * event. - * - * @return old RowId - */ - public RowId getOldRowId(); - - /** - * Gets the new, possibly database assigned RowId of the added row that - * raised this event. - * - * @return new RowId - */ - public RowId getNewRowId(); - } - - /** RowId change listener interface. */ - public interface RowIdChangeListener extends Serializable { - /** - * Lets the listener know that a RowId has been changed. - * - * @param event - */ - public void rowIdChange(QueryDelegate.RowIdChangeEvent event); - } - - /** - * The interface for adding and removing <code>RowIdChangeEvent</code> - * listeners. By implementing this interface a class explicitly announces - * that it will generate a <code>RowIdChangeEvent</code> when it performs a - * database commit that may change the RowId. - */ - public interface RowIdChangeNotifier extends Serializable { - /** - * Adds a RowIdChangeListener for the object. - * - * @param listener - * listener to be added - */ - public void addListener(QueryDelegate.RowIdChangeListener listener); - - /** - * Removes the specified RowIdChangeListener from the object. - * - * @param listener - * listener to be removed - */ - public void removeListener(QueryDelegate.RowIdChangeListener listener); - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java b/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java deleted file mode 100644 index d0606704f7..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/TableQuery.java +++ /dev/null @@ -1,715 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.EventObject; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.Compare.Equal; -import com.vaadin.data.util.sqlcontainer.ColumnProperty; -import com.vaadin.data.util.sqlcontainer.OptimisticLockException; -import com.vaadin.data.util.sqlcontainer.RowId; -import com.vaadin.data.util.sqlcontainer.RowItem; -import com.vaadin.data.util.sqlcontainer.SQLUtil; -import com.vaadin.data.util.sqlcontainer.TemporaryRowId; -import com.vaadin.data.util.sqlcontainer.connection.JDBCConnectionPool; -import com.vaadin.data.util.sqlcontainer.query.generator.DefaultSQLGenerator; -import com.vaadin.data.util.sqlcontainer.query.generator.MSSQLGenerator; -import com.vaadin.data.util.sqlcontainer.query.generator.SQLGenerator; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -@SuppressWarnings("serial") -public class TableQuery implements QueryDelegate, - QueryDelegate.RowIdChangeNotifier { - - /** Table name, primary key column name(s) and version column name */ - private String tableName; - private List<String> primaryKeyColumns; - private String versionColumn; - - /** Currently set Filters and OrderBys */ - private List<Filter> filters; - private List<OrderBy> orderBys; - - /** SQLGenerator instance to use for generating queries */ - private SQLGenerator sqlGenerator; - - /** Fields related to Connection and Transaction handling */ - private JDBCConnectionPool connectionPool; - private transient Connection activeConnection; - private boolean transactionOpen; - - /** Row ID change listeners */ - private LinkedList<RowIdChangeListener> rowIdChangeListeners; - /** Row ID change events, stored until commit() is called */ - private final List<RowIdChangeEvent> bufferedEvents = new ArrayList<RowIdChangeEvent>(); - - /** Set to true to output generated SQL Queries to System.out */ - private boolean debug = false; - - /** Prevent no-parameters instantiation of TableQuery */ - @SuppressWarnings("unused") - private TableQuery() { - } - - /** - * Creates a new TableQuery using the given connection pool, SQL generator - * and table name to fetch the data from. All parameters must be non-null. - * - * @param tableName - * Name of the database table to connect to - * @param connectionPool - * Connection pool for accessing the database - * @param sqlGenerator - * SQL query generator implementation - */ - public TableQuery(String tableName, JDBCConnectionPool connectionPool, - SQLGenerator sqlGenerator) { - if (tableName == null || tableName.trim().length() < 1 - || connectionPool == null || sqlGenerator == null) { - throw new IllegalArgumentException( - "All parameters must be non-null and a table name must be given."); - } - this.tableName = tableName; - this.sqlGenerator = sqlGenerator; - this.connectionPool = connectionPool; - fetchMetaData(); - } - - /** - * Creates a new TableQuery using the given connection pool and table name - * to fetch the data from. All parameters must be non-null. The default SQL - * generator will be used for queries. - * - * @param tableName - * Name of the database table to connect to - * @param connectionPool - * Connection pool for accessing the database - */ - public TableQuery(String tableName, JDBCConnectionPool connectionPool) { - this(tableName, connectionPool, new DefaultSQLGenerator()); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#getCount() - */ - @Override - public int getCount() throws SQLException { - getLogger().log(Level.FINE, "Fetching count..."); - StatementHelper sh = sqlGenerator.generateSelectQuery(tableName, - filters, null, 0, 0, "COUNT(*)"); - boolean shouldCloseTransaction = false; - if (!transactionOpen) { - shouldCloseTransaction = true; - beginTransaction(); - } - ResultSet r = executeQuery(sh); - r.next(); - int count = r.getInt(1); - r.getStatement().close(); - r.close(); - if (shouldCloseTransaction) { - commit(); - } - return count; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#getResults(int, - * int) - */ - @Override - public ResultSet getResults(int offset, int pagelength) throws SQLException { - StatementHelper sh; - /* - * If no ordering is explicitly set, results will be ordered by the - * first primary key column. - */ - if (orderBys == null || orderBys.isEmpty()) { - List<OrderBy> ob = new ArrayList<OrderBy>(); - ob.add(new OrderBy(primaryKeyColumns.get(0), true)); - sh = sqlGenerator.generateSelectQuery(tableName, filters, ob, - offset, pagelength, null); - } else { - sh = sqlGenerator.generateSelectQuery(tableName, filters, orderBys, - offset, pagelength, null); - } - return executeQuery(sh); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate# - * implementationRespectsPagingLimits() - */ - @Override - public boolean implementationRespectsPagingLimits() { - return true; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.addon.sqlcontainer.query.QueryDelegate#storeRow(com.vaadin - * .addon.sqlcontainer.RowItem) - */ - @Override - public int storeRow(RowItem row) throws UnsupportedOperationException, - SQLException { - if (row == null) { - throw new IllegalArgumentException("Row argument must be non-null."); - } - StatementHelper sh; - int result = 0; - if (row.getId() instanceof TemporaryRowId) { - setVersionColumnFlagInProperty(row); - sh = sqlGenerator.generateInsertQuery(tableName, row); - result = executeUpdateReturnKeys(sh, row); - } else { - setVersionColumnFlagInProperty(row); - sh = sqlGenerator.generateUpdateQuery(tableName, row); - result = executeUpdate(sh); - } - if (versionColumn != null && result == 0) { - throw new OptimisticLockException( - "Someone else changed the row that was being updated.", - row.getId()); - } - return result; - } - - private void setVersionColumnFlagInProperty(RowItem row) { - ColumnProperty versionProperty = (ColumnProperty) row - .getItemProperty(versionColumn); - if (versionProperty != null) { - versionProperty.setVersionColumn(true); - } - } - - /** - * Inserts the given row in the database table immediately. Begins and - * commits the transaction needed. This method was added specifically to - * solve the problem of returning the final RowId immediately on the - * SQLContainer.addItem() call when auto commit mode is enabled in the - * SQLContainer. - * - * @param row - * RowItem to add to the database - * @return Final RowId of the added row - * @throws SQLException - */ - public RowId storeRowImmediately(RowItem row) throws SQLException { - beginTransaction(); - /* Set version column, if one is provided */ - setVersionColumnFlagInProperty(row); - /* Generate query */ - StatementHelper sh = sqlGenerator.generateInsertQuery(tableName, row); - PreparedStatement pstmt = activeConnection.prepareStatement( - sh.getQueryString(), primaryKeyColumns.toArray(new String[0])); - sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); - int result = pstmt.executeUpdate(); - if (result > 0) { - /* - * If affected rows exist, we'll get the new RowId, commit the - * transaction and return the new RowId. - */ - ResultSet generatedKeys = pstmt.getGeneratedKeys(); - RowId newId = getNewRowId(row, generatedKeys); - generatedKeys.close(); - pstmt.clearParameters(); - pstmt.close(); - commit(); - return newId; - } else { - pstmt.clearParameters(); - pstmt.close(); - /* On failure return null */ - return null; - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.addon.sqlcontainer.query.QueryDelegate#setFilters(java.util - * .List) - */ - @Override - public void setFilters(List<Filter> filters) - throws UnsupportedOperationException { - if (filters == null) { - this.filters = null; - return; - } - this.filters = Collections.unmodifiableList(filters); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.addon.sqlcontainer.query.QueryDelegate#setOrderBy(java.util - * .List) - */ - @Override - public void setOrderBy(List<OrderBy> orderBys) - throws UnsupportedOperationException { - if (orderBys == null) { - this.orderBys = null; - return; - } - this.orderBys = Collections.unmodifiableList(orderBys); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#beginTransaction() - */ - @Override - public void beginTransaction() throws UnsupportedOperationException, - SQLException { - if (transactionOpen && activeConnection != null) { - throw new IllegalStateException(); - } - - getLogger().log(Level.FINE, "DB -> begin transaction"); - activeConnection = connectionPool.reserveConnection(); - activeConnection.setAutoCommit(false); - transactionOpen = true; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#commit() - */ - @Override - public void commit() throws UnsupportedOperationException, SQLException { - if (transactionOpen && activeConnection != null) { - getLogger().log(Level.FINE, "DB -> commit"); - activeConnection.commit(); - connectionPool.releaseConnection(activeConnection); - } else { - throw new SQLException("No active transaction"); - } - transactionOpen = false; - - /* Handle firing row ID change events */ - RowIdChangeEvent[] unFiredEvents = bufferedEvents - .toArray(new RowIdChangeEvent[] {}); - bufferedEvents.clear(); - if (rowIdChangeListeners != null && !rowIdChangeListeners.isEmpty()) { - for (RowIdChangeListener r : rowIdChangeListeners) { - for (RowIdChangeEvent e : unFiredEvents) { - r.rowIdChange(e); - } - } - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.QueryDelegate#rollback() - */ - @Override - public void rollback() throws UnsupportedOperationException, SQLException { - if (transactionOpen && activeConnection != null) { - getLogger().log(Level.FINE, "DB -> rollback"); - activeConnection.rollback(); - connectionPool.releaseConnection(activeConnection); - } else { - throw new SQLException("No active transaction"); - } - transactionOpen = false; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.addon.sqlcontainer.query.QueryDelegate#getPrimaryKeyColumns() - */ - @Override - public List<String> getPrimaryKeyColumns() { - return Collections.unmodifiableList(primaryKeyColumns); - } - - public String getVersionColumn() { - return versionColumn; - } - - public void setVersionColumn(String column) { - versionColumn = column; - } - - public String getTableName() { - return tableName; - } - - public SQLGenerator getSqlGenerator() { - return sqlGenerator; - } - - /** - * Executes the given query string using either the active connection if a - * transaction is already open, or a new connection from this query's - * connection pool. - * - * @param sh - * an instance of StatementHelper, containing the query string - * and parameter values. - * @return ResultSet of the query - * @throws SQLException - */ - private ResultSet executeQuery(StatementHelper sh) throws SQLException { - Connection c = null; - if (transactionOpen && activeConnection != null) { - c = activeConnection; - } else { - throw new SQLException("No active transaction!"); - } - PreparedStatement pstmt = c.prepareStatement(sh.getQueryString()); - sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); - return pstmt.executeQuery(); - } - - /** - * Executes the given update query string using either the active connection - * if a transaction is already open, or a new connection from this query's - * connection pool. - * - * @param sh - * an instance of StatementHelper, containing the query string - * and parameter values. - * @return Number of affected rows - * @throws SQLException - */ - private int executeUpdate(StatementHelper sh) throws SQLException { - Connection c = null; - PreparedStatement pstmt = null; - try { - if (transactionOpen && activeConnection != null) { - c = activeConnection; - } else { - c = connectionPool.reserveConnection(); - } - pstmt = c.prepareStatement(sh.getQueryString()); - sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); - int retval = pstmt.executeUpdate(); - return retval; - } finally { - if (pstmt != null) { - pstmt.clearParameters(); - pstmt.close(); - } - if (!transactionOpen) { - connectionPool.releaseConnection(c); - } - } - } - - /** - * Executes the given update query string using either the active connection - * if a transaction is already open, or a new connection from this query's - * connection pool. - * - * Additionally adds a new RowIdChangeEvent to the event buffer. - * - * @param sh - * an instance of StatementHelper, containing the query string - * and parameter values. - * @param row - * the row item to update - * @return Number of affected rows - * @throws SQLException - */ - private int executeUpdateReturnKeys(StatementHelper sh, RowItem row) - throws SQLException { - Connection c = null; - PreparedStatement pstmt = null; - ResultSet genKeys = null; - try { - if (transactionOpen && activeConnection != null) { - c = activeConnection; - } else { - c = connectionPool.reserveConnection(); - } - pstmt = c.prepareStatement(sh.getQueryString(), - primaryKeyColumns.toArray(new String[0])); - sh.setParameterValuesToStatement(pstmt); - getLogger().log(Level.FINE, "DB -> " + sh.getQueryString()); - int result = pstmt.executeUpdate(); - genKeys = pstmt.getGeneratedKeys(); - RowId newId = getNewRowId(row, genKeys); - bufferedEvents.add(new RowIdChangeEvent(row.getId(), newId)); - return result; - } finally { - if (genKeys != null) { - genKeys.close(); - } - if (pstmt != null) { - pstmt.clearParameters(); - pstmt.close(); - } - if (!transactionOpen) { - connectionPool.releaseConnection(c); - } - } - } - - /** - * Fetches name(s) of primary key column(s) from DB metadata. - * - * Also tries to get the escape string to be used in search strings. - */ - private void fetchMetaData() { - Connection c = null; - try { - c = connectionPool.reserveConnection(); - DatabaseMetaData dbmd = c.getMetaData(); - if (dbmd != null) { - tableName = SQLUtil.escapeSQL(tableName); - ResultSet tables = dbmd.getTables(null, null, tableName, null); - if (!tables.next()) { - tables = dbmd.getTables(null, null, - tableName.toUpperCase(), null); - if (!tables.next()) { - throw new IllegalArgumentException( - "Table with the name \"" - + tableName - + "\" was not found. Check your database contents."); - } else { - tableName = tableName.toUpperCase(); - } - } - tables.close(); - ResultSet rs = dbmd.getPrimaryKeys(null, null, tableName); - List<String> names = new ArrayList<String>(); - while (rs.next()) { - names.add(rs.getString("COLUMN_NAME")); - } - rs.close(); - if (!names.isEmpty()) { - primaryKeyColumns = names; - } - if (primaryKeyColumns == null || primaryKeyColumns.isEmpty()) { - throw new IllegalArgumentException( - "Primary key constraints have not been defined for the table \"" - + tableName - + "\". Use FreeFormQuery to access this table."); - } - for (String colName : primaryKeyColumns) { - if (colName.equalsIgnoreCase("rownum")) { - if (getSqlGenerator() instanceof MSSQLGenerator - || getSqlGenerator() instanceof MSSQLGenerator) { - throw new IllegalArgumentException( - "When using Oracle or MSSQL, a primary key column" - + " named \'rownum\' is not allowed!"); - } - } - } - } - } catch (SQLException e) { - throw new RuntimeException(e); - } finally { - connectionPool.releaseConnection(c); - } - } - - private RowId getNewRowId(RowItem row, ResultSet genKeys) { - try { - /* Fetch primary key values and generate a map out of them. */ - Map<String, Object> values = new HashMap<String, Object>(); - ResultSetMetaData rsmd = genKeys.getMetaData(); - int colCount = rsmd.getColumnCount(); - if (genKeys.next()) { - for (int i = 1; i <= colCount; i++) { - values.put(rsmd.getColumnName(i), genKeys.getObject(i)); - } - } - /* Generate new RowId */ - List<Object> newRowId = new ArrayList<Object>(); - if (values.size() == 1) { - if (primaryKeyColumns.size() == 1) { - newRowId.add(values.get(values.keySet().iterator().next())); - } else { - for (String s : primaryKeyColumns) { - if (!((ColumnProperty) row.getItemProperty(s)) - .isReadOnlyChangeAllowed()) { - newRowId.add(values.get(values.keySet().iterator() - .next())); - } else { - newRowId.add(values.get(s)); - } - } - } - } else { - for (String s : primaryKeyColumns) { - newRowId.add(values.get(s)); - } - } - return new RowId(newRowId.toArray()); - } catch (Exception e) { - getLogger().log(Level.FINE, - "Failed to fetch key values on insert: " + e.getMessage()); - return null; - } - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.addon.sqlcontainer.query.QueryDelegate#removeRow(com.vaadin - * .addon.sqlcontainer.RowItem) - */ - @Override - public boolean removeRow(RowItem row) throws UnsupportedOperationException, - SQLException { - getLogger().log(Level.FINE, - "Removing row with id: " + row.getId().getId()[0].toString()); - if (executeUpdate(sqlGenerator.generateDeleteQuery(getTableName(), - primaryKeyColumns, versionColumn, row)) == 1) { - return true; - } - if (versionColumn != null) { - throw new OptimisticLockException( - "Someone else changed the row that was being deleted.", - row.getId()); - } - return false; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.addon.sqlcontainer.query.QueryDelegate#containsRowWithKey( - * java.lang.Object[]) - */ - @Override - public boolean containsRowWithKey(Object... keys) throws SQLException { - ArrayList<Filter> filtersAndKeys = new ArrayList<Filter>(); - if (filters != null) { - filtersAndKeys.addAll(filters); - } - int ix = 0; - for (String colName : primaryKeyColumns) { - filtersAndKeys.add(new Equal(colName, keys[ix])); - ix++; - } - StatementHelper sh = sqlGenerator.generateSelectQuery(tableName, - filtersAndKeys, orderBys, 0, 0, "*"); - - boolean shouldCloseTransaction = false; - if (!transactionOpen) { - shouldCloseTransaction = true; - beginTransaction(); - } - ResultSet rs = null; - try { - rs = executeQuery(sh); - boolean contains = rs.next(); - return contains; - } finally { - if (rs != null) { - if (rs.getStatement() != null) { - rs.getStatement().close(); - } - rs.close(); - } - if (shouldCloseTransaction) { - commit(); - } - } - } - - /** - * Custom writeObject to call rollback() if object is serialized. - */ - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - try { - rollback(); - } catch (SQLException ignored) { - } - out.defaultWriteObject(); - } - - /** - * Simple RowIdChangeEvent implementation. - */ - public class RowIdChangeEvent extends EventObject implements - QueryDelegate.RowIdChangeEvent { - private final RowId oldId; - private final RowId newId; - - private RowIdChangeEvent(RowId oldId, RowId newId) { - super(oldId); - this.oldId = oldId; - this.newId = newId; - } - - @Override - public RowId getNewRowId() { - return newId; - } - - @Override - public RowId getOldRowId() { - return oldId; - } - } - - /** - * Adds RowIdChangeListener to this query - */ - @Override - public void addListener(RowIdChangeListener listener) { - if (rowIdChangeListeners == null) { - rowIdChangeListeners = new LinkedList<QueryDelegate.RowIdChangeListener>(); - } - rowIdChangeListeners.add(listener); - } - - /** - * Removes the given RowIdChangeListener from this query - */ - @Override - public void removeListener(RowIdChangeListener listener) { - if (rowIdChangeListeners != null) { - rowIdChangeListeners.remove(listener); - } - } - - private static final Logger getLogger() { - return Logger.getLogger(TableQuery.class.getName()); - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java deleted file mode 100644 index 6485330541..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/DefaultSQLGenerator.java +++ /dev/null @@ -1,367 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.ColumnProperty; -import com.vaadin.data.util.sqlcontainer.RowItem; -import com.vaadin.data.util.sqlcontainer.SQLUtil; -import com.vaadin.data.util.sqlcontainer.TemporaryRowId; -import com.vaadin.data.util.sqlcontainer.query.OrderBy; -import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; -import com.vaadin.data.util.sqlcontainer.query.generator.filter.StringDecorator; - -/** - * Generates generic SQL that is supported by HSQLDB, MySQL and PostgreSQL. - * - * @author Jonatan Kronqvist / Vaadin Ltd - */ -@SuppressWarnings("serial") -public class DefaultSQLGenerator implements SQLGenerator { - - private Class<? extends StatementHelper> statementHelperClass = null; - - public DefaultSQLGenerator() { - - } - - /** - * Create a new DefaultSqlGenerator instance that uses the given - * implementation of {@link StatementHelper} - * - * @param statementHelper - */ - public DefaultSQLGenerator( - Class<? extends StatementHelper> statementHelperClazz) { - this(); - statementHelperClass = statementHelperClazz; - } - - /** - * Construct a DefaultSQLGenerator with the specified identifiers for start - * and end of quoted strings. The identifiers may be different depending on - * the database engine and it's settings. - * - * @param quoteStart - * the identifier (character) denoting the start of a quoted - * string - * @param quoteEnd - * the identifier (character) denoting the end of a quoted string - */ - public DefaultSQLGenerator(String quoteStart, String quoteEnd) { - QueryBuilder.setStringDecorator(new StringDecorator(quoteStart, - quoteEnd)); - } - - /** - * Same as {@link #DefaultSQLGenerator(String, String)} but with support for - * custom {@link StatementHelper} implementation. - * - * @param quoteStart - * @param quoteEnd - * @param statementHelperClazz - */ - public DefaultSQLGenerator(String quoteStart, String quoteEnd, - Class<? extends StatementHelper> statementHelperClazz) { - this(quoteStart, quoteEnd); - statementHelperClass = statementHelperClazz; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator# - * generateSelectQuery(java.lang.String, java.util.List, java.util.List, - * int, int, java.lang.String) - */ - @Override - public StatementHelper generateSelectQuery(String tableName, - List<Filter> filters, List<OrderBy> orderBys, int offset, - int pagelength, String toSelect) { - if (tableName == null || tableName.trim().equals("")) { - throw new IllegalArgumentException("Table name must be given."); - } - toSelect = toSelect == null ? "*" : toSelect; - StatementHelper sh = getStatementHelper(); - StringBuffer query = new StringBuffer(); - query.append("SELECT " + toSelect + " FROM ").append( - SQLUtil.escapeSQL(tableName)); - if (filters != null) { - query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); - } - if (orderBys != null) { - for (OrderBy o : orderBys) { - generateOrderBy(query, o, orderBys.indexOf(o) == 0); - } - } - if (pagelength != 0) { - generateLimits(query, offset, pagelength); - } - sh.setQueryString(query.toString()); - return sh; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator# - * generateUpdateQuery(java.lang.String, - * com.vaadin.addon.sqlcontainer.RowItem) - */ - @Override - public StatementHelper generateUpdateQuery(String tableName, RowItem item) { - if (tableName == null || tableName.trim().equals("")) { - throw new IllegalArgumentException("Table name must be given."); - } - if (item == null) { - throw new IllegalArgumentException("Updated item must be given."); - } - StatementHelper sh = getStatementHelper(); - StringBuffer query = new StringBuffer(); - query.append("UPDATE ").append(tableName).append(" SET"); - - /* Generate column<->value and rowidentifiers map */ - Map<String, Object> columnToValueMap = generateColumnToValueMap(item); - Map<String, Object> rowIdentifiers = generateRowIdentifiers(item); - /* Generate columns and values to update */ - boolean first = true; - for (String column : columnToValueMap.keySet()) { - if (first) { - query.append(" " + QueryBuilder.quote(column) + " = ?"); - } else { - query.append(", " + QueryBuilder.quote(column) + " = ?"); - } - sh.addParameterValue(columnToValueMap.get(column), item - .getItemProperty(column).getType()); - first = false; - } - /* Generate identifiers for the row to be updated */ - first = true; - for (String column : rowIdentifiers.keySet()) { - if (first) { - query.append(" WHERE " + QueryBuilder.quote(column) + " = ?"); - } else { - query.append(" AND " + QueryBuilder.quote(column) + " = ?"); - } - sh.addParameterValue(rowIdentifiers.get(column), item - .getItemProperty(column).getType()); - first = false; - } - sh.setQueryString(query.toString()); - return sh; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator# - * generateInsertQuery(java.lang.String, - * com.vaadin.addon.sqlcontainer.RowItem) - */ - @Override - public StatementHelper generateInsertQuery(String tableName, RowItem item) { - if (tableName == null || tableName.trim().equals("")) { - throw new IllegalArgumentException("Table name must be given."); - } - if (item == null) { - throw new IllegalArgumentException("New item must be given."); - } - if (!(item.getId() instanceof TemporaryRowId)) { - throw new IllegalArgumentException( - "Cannot generate an insert query for item already in database."); - } - StatementHelper sh = getStatementHelper(); - StringBuffer query = new StringBuffer(); - query.append("INSERT INTO ").append(tableName).append(" ("); - - /* Generate column<->value map */ - Map<String, Object> columnToValueMap = generateColumnToValueMap(item); - /* Generate column names for insert query */ - boolean first = true; - for (String column : columnToValueMap.keySet()) { - if (!first) { - query.append(", "); - } - query.append(QueryBuilder.quote(column)); - first = false; - } - - /* Generate values for insert query */ - query.append(") VALUES ("); - first = true; - for (String column : columnToValueMap.keySet()) { - if (!first) { - query.append(", "); - } - query.append("?"); - sh.addParameterValue(columnToValueMap.get(column), item - .getItemProperty(column).getType()); - first = false; - } - query.append(")"); - sh.setQueryString(query.toString()); - return sh; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.generator.SQLGenerator# - * generateDeleteQuery(java.lang.String, - * com.vaadin.addon.sqlcontainer.RowItem) - */ - @Override - public StatementHelper generateDeleteQuery(String tableName, - List<String> primaryKeyColumns, String versionColumn, RowItem item) { - if (tableName == null || tableName.trim().equals("")) { - throw new IllegalArgumentException("Table name must be given."); - } - if (item == null) { - throw new IllegalArgumentException( - "Item to be deleted must be given."); - } - if (primaryKeyColumns == null || primaryKeyColumns.isEmpty()) { - throw new IllegalArgumentException( - "Valid keyColumnNames must be provided."); - } - StatementHelper sh = getStatementHelper(); - StringBuffer query = new StringBuffer(); - query.append("DELETE FROM ").append(tableName).append(" WHERE "); - int count = 1; - for (String keyColName : primaryKeyColumns) { - if ((this instanceof MSSQLGenerator || this instanceof OracleGenerator) - && keyColName.equalsIgnoreCase("rownum")) { - count++; - continue; - } - if (count > 1) { - query.append(" AND "); - } - if (item.getItemProperty(keyColName).getValue() != null) { - query.append(QueryBuilder.quote(keyColName) + " = ?"); - sh.addParameterValue(item.getItemProperty(keyColName) - .getValue(), item.getItemProperty(keyColName).getType()); - } - count++; - } - if (versionColumn != null) { - query.append(String.format(" AND %s = ?", - QueryBuilder.quote(versionColumn))); - sh.addParameterValue( - item.getItemProperty(versionColumn).getValue(), item - .getItemProperty(versionColumn).getType()); - } - - sh.setQueryString(query.toString()); - return sh; - } - - /** - * Generates sorting rules as an ORDER BY -clause - * - * @param sb - * StringBuffer to which the clause is appended. - * @param o - * OrderBy object to be added into the sb. - * @param firstOrderBy - * If true, this is the first OrderBy. - * @return - */ - protected StringBuffer generateOrderBy(StringBuffer sb, OrderBy o, - boolean firstOrderBy) { - if (firstOrderBy) { - sb.append(" ORDER BY "); - } else { - sb.append(", "); - } - sb.append(QueryBuilder.quote(o.getColumn())); - if (o.isAscending()) { - sb.append(" ASC"); - } else { - sb.append(" DESC"); - } - return sb; - } - - /** - * Generates the LIMIT and OFFSET clause. - * - * @param sb - * StringBuffer to which the clause is appended. - * @param offset - * Value for offset. - * @param pagelength - * Value for pagelength. - * @return StringBuffer with LIMIT and OFFSET clause added. - */ - protected StringBuffer generateLimits(StringBuffer sb, int offset, - int pagelength) { - sb.append(" LIMIT ").append(pagelength).append(" OFFSET ") - .append(offset); - return sb; - } - - protected Map<String, Object> generateColumnToValueMap(RowItem item) { - Map<String, Object> columnToValueMap = new HashMap<String, Object>(); - for (Object id : item.getItemPropertyIds()) { - ColumnProperty cp = (ColumnProperty) item.getItemProperty(id); - /* Prevent "rownum" usage as a column name if MSSQL or ORACLE */ - if ((this instanceof MSSQLGenerator || this instanceof OracleGenerator) - && cp.getPropertyId().equalsIgnoreCase("rownum")) { - continue; - } - Object value = cp.getValue() == null ? null : cp.getValue(); - /* Only include properties whose read-only status can be altered */ - if (cp.isReadOnlyChangeAllowed() && !cp.isVersionColumn()) { - columnToValueMap.put(cp.getPropertyId(), value); - } - } - return columnToValueMap; - } - - protected Map<String, Object> generateRowIdentifiers(RowItem item) { - Map<String, Object> rowIdentifiers = new HashMap<String, Object>(); - for (Object id : item.getItemPropertyIds()) { - ColumnProperty cp = (ColumnProperty) item.getItemProperty(id); - /* Prevent "rownum" usage as a column name if MSSQL or ORACLE */ - if ((this instanceof MSSQLGenerator || this instanceof OracleGenerator) - && cp.getPropertyId().equalsIgnoreCase("rownum")) { - continue; - } - Object value = cp.getValue() == null ? null : cp.getValue(); - if (!cp.isReadOnlyChangeAllowed() || cp.isVersionColumn()) { - rowIdentifiers.put(cp.getPropertyId(), value); - } - } - return rowIdentifiers; - } - - /** - * Returns the statement helper for the generator. Override this to handle - * platform specific data types. - * - * @see http://dev.vaadin.com/ticket/9148 - * @return a new instance of the statement helper - */ - protected StatementHelper getStatementHelper() { - if (statementHelperClass == null) { - return new StatementHelper(); - } - - try { - return statementHelperClass.newInstance(); - } catch (InstantiationException e) { - throw new RuntimeException( - "Unable to instantiate custom StatementHelper", e); - } catch (IllegalAccessException e) { - throw new RuntimeException( - "Unable to instantiate custom StatementHelper", e); - } - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/MSSQLGenerator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/MSSQLGenerator.java deleted file mode 100644 index 13ef1d0090..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/MSSQLGenerator.java +++ /dev/null @@ -1,101 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator; - -import java.util.List; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.query.OrderBy; -import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; - -@SuppressWarnings("serial") -public class MSSQLGenerator extends DefaultSQLGenerator { - - public MSSQLGenerator() { - - } - - /** - * Construct a MSSQLGenerator with the specified identifiers for start and - * end of quoted strings. The identifiers may be different depending on the - * database engine and it's settings. - * - * @param quoteStart - * the identifier (character) denoting the start of a quoted - * string - * @param quoteEnd - * the identifier (character) denoting the end of a quoted string - */ - public MSSQLGenerator(String quoteStart, String quoteEnd) { - super(quoteStart, quoteEnd); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.generator.DefaultSQLGenerator# - * generateSelectQuery(java.lang.String, java.util.List, - * com.vaadin.addon.sqlcontainer.query.FilteringMode, java.util.List, int, - * int, java.lang.String) - */ - @Override - public StatementHelper generateSelectQuery(String tableName, - List<Filter> filters, List<OrderBy> orderBys, int offset, - int pagelength, String toSelect) { - if (tableName == null || tableName.trim().equals("")) { - throw new IllegalArgumentException("Table name must be given."); - } - /* Adjust offset and page length parameters to match "row numbers" */ - offset = pagelength > 1 ? ++offset : offset; - pagelength = pagelength > 1 ? --pagelength : pagelength; - toSelect = toSelect == null ? "*" : toSelect; - StatementHelper sh = getStatementHelper(); - StringBuffer query = new StringBuffer(); - - /* Row count request is handled here */ - if ("COUNT(*)".equalsIgnoreCase(toSelect)) { - query.append(String.format( - "SELECT COUNT(*) AS %s FROM (SELECT * FROM %s", - QueryBuilder.quote("rowcount"), tableName)); - if (filters != null && !filters.isEmpty()) { - query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); - } - query.append(") AS t"); - sh.setQueryString(query.toString()); - return sh; - } - - /* SELECT without row number constraints */ - if (offset == 0 && pagelength == 0) { - query.append("SELECT ").append(toSelect).append(" FROM ") - .append(tableName); - if (filters != null) { - query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); - } - if (orderBys != null) { - for (OrderBy o : orderBys) { - generateOrderBy(query, o, orderBys.indexOf(o) == 0); - } - } - sh.setQueryString(query.toString()); - return sh; - } - - /* Remaining SELECT cases are handled here */ - query.append("SELECT * FROM (SELECT row_number() OVER ("); - if (orderBys != null) { - for (OrderBy o : orderBys) { - generateOrderBy(query, o, orderBys.indexOf(o) == 0); - } - } - query.append(") AS rownum, " + toSelect + " FROM ").append(tableName); - if (filters != null) { - query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); - } - query.append(") AS a WHERE a.rownum BETWEEN ").append(offset) - .append(" AND ").append(Integer.toString(offset + pagelength)); - sh.setQueryString(query.toString()); - return sh; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/OracleGenerator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/OracleGenerator.java deleted file mode 100644 index 43a562d3a8..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/OracleGenerator.java +++ /dev/null @@ -1,112 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator; - -import java.util.List; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.query.OrderBy; -import com.vaadin.data.util.sqlcontainer.query.generator.filter.QueryBuilder; - -@SuppressWarnings("serial") -public class OracleGenerator extends DefaultSQLGenerator { - - public OracleGenerator() { - - } - - public OracleGenerator(Class<? extends StatementHelper> statementHelperClazz) { - super(statementHelperClazz); - } - - /** - * Construct an OracleSQLGenerator with the specified identifiers for start - * and end of quoted strings. The identifiers may be different depending on - * the database engine and it's settings. - * - * @param quoteStart - * the identifier (character) denoting the start of a quoted - * string - * @param quoteEnd - * the identifier (character) denoting the end of a quoted string - */ - public OracleGenerator(String quoteStart, String quoteEnd) { - super(quoteStart, quoteEnd); - } - - public OracleGenerator(String quoteStart, String quoteEnd, - Class<? extends StatementHelper> statementHelperClazz) { - super(quoteStart, quoteEnd, statementHelperClazz); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.addon.sqlcontainer.query.generator.DefaultSQLGenerator# - * generateSelectQuery(java.lang.String, java.util.List, - * com.vaadin.addon.sqlcontainer.query.FilteringMode, java.util.List, int, - * int, java.lang.String) - */ - @Override - public StatementHelper generateSelectQuery(String tableName, - List<Filter> filters, List<OrderBy> orderBys, int offset, - int pagelength, String toSelect) { - if (tableName == null || tableName.trim().equals("")) { - throw new IllegalArgumentException("Table name must be given."); - } - /* Adjust offset and page length parameters to match "row numbers" */ - offset = pagelength > 1 ? ++offset : offset; - pagelength = pagelength > 1 ? --pagelength : pagelength; - toSelect = toSelect == null ? "*" : toSelect; - StatementHelper sh = getStatementHelper(); - StringBuffer query = new StringBuffer(); - - /* Row count request is handled here */ - if ("COUNT(*)".equalsIgnoreCase(toSelect)) { - query.append(String.format( - "SELECT COUNT(*) AS %s FROM (SELECT * FROM %s", - QueryBuilder.quote("rowcount"), tableName)); - if (filters != null && !filters.isEmpty()) { - query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); - } - query.append(")"); - sh.setQueryString(query.toString()); - return sh; - } - - /* SELECT without row number constraints */ - if (offset == 0 && pagelength == 0) { - query.append("SELECT ").append(toSelect).append(" FROM ") - .append(tableName); - if (filters != null) { - query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); - } - if (orderBys != null) { - for (OrderBy o : orderBys) { - generateOrderBy(query, o, orderBys.indexOf(o) == 0); - } - } - sh.setQueryString(query.toString()); - return sh; - } - - /* Remaining SELECT cases are handled here */ - query.append(String - .format("SELECT * FROM (SELECT x.*, ROWNUM AS %s FROM (SELECT %s FROM %s", - QueryBuilder.quote("rownum"), toSelect, tableName)); - if (filters != null) { - query.append(QueryBuilder.getWhereStringForFilters(filters, sh)); - } - if (orderBys != null) { - for (OrderBy o : orderBys) { - generateOrderBy(query, o, orderBys.indexOf(o) == 0); - } - } - query.append(String.format(") x) WHERE %s BETWEEN %d AND %d", - QueryBuilder.quote("rownum"), offset, offset + pagelength)); - sh.setQueryString(query.toString()); - return sh; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/SQLGenerator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/SQLGenerator.java deleted file mode 100644 index dde7077eee..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/SQLGenerator.java +++ /dev/null @@ -1,88 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator; - -import java.io.Serializable; -import java.util.List; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.RowItem; -import com.vaadin.data.util.sqlcontainer.query.OrderBy; - -/** - * The SQLGenerator interface is meant to be implemented for each different SQL - * syntax that is to be supported. By default there are implementations for - * HSQLDB, MySQL, PostgreSQL, MSSQL and Oracle syntaxes. - * - * @author Jonatan Kronqvist / Vaadin Ltd - */ -public interface SQLGenerator extends Serializable { - /** - * Generates a SELECT query with the provided parameters. Uses default - * filtering mode (INCLUSIVE). - * - * @param tableName - * Name of the table queried - * @param filters - * The filters, converted into a WHERE clause - * @param orderBys - * The the ordering conditions, converted into an ORDER BY clause - * @param offset - * The offset of the first row to be included - * @param pagelength - * The number of rows to be returned when the query executes - * @param toSelect - * String containing what to select, e.g. "*", "COUNT(*)" - * @return StatementHelper instance containing the query string for a - * PreparedStatement and the values required for the parameters - */ - public StatementHelper generateSelectQuery(String tableName, - List<Filter> filters, List<OrderBy> orderBys, int offset, - int pagelength, String toSelect); - - /** - * Generates an UPDATE query with the provided parameters. - * - * @param tableName - * Name of the table queried - * @param item - * RowItem containing the updated values update. - * @return StatementHelper instance containing the query string for a - * PreparedStatement and the values required for the parameters - */ - public StatementHelper generateUpdateQuery(String tableName, RowItem item); - - /** - * Generates an INSERT query for inserting a new row with the provided - * values. - * - * @param tableName - * Name of the table queried - * @param item - * New RowItem to be inserted into the database. - * @return StatementHelper instance containing the query string for a - * PreparedStatement and the values required for the parameters - */ - public StatementHelper generateInsertQuery(String tableName, RowItem item); - - /** - * Generates a DELETE query for deleting data related to the given RowItem - * from the database. - * - * @param tableName - * Name of the table queried - * @param primaryKeyColumns - * the names of the columns holding the primary key. Usually just - * one column, but might be several. - * @param versionColumn - * the column containing the version number of the row, null if - * versioning (optimistic locking) not enabled. - * @param item - * Item to be deleted from the database - * @return StatementHelper instance containing the query string for a - * PreparedStatement and the values required for the parameters - */ - public StatementHelper generateDeleteQuery(String tableName, - List<String> primaryKeyColumns, String versionColumn, RowItem item); -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/StatementHelper.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/StatementHelper.java deleted file mode 100644 index b012ce7685..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/StatementHelper.java +++ /dev/null @@ -1,163 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; -import java.sql.Types; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * StatementHelper is a simple helper class that assists TableQuery and the - * query generators in filling a PreparedStatement. The actual statement is - * generated by the query generator methods, but the resulting statement and all - * the parameter values are stored in an instance of StatementHelper. - * - * This class will also fill the values with correct setters into the - * PreparedStatement on request. - */ -public class StatementHelper implements Serializable { - - private String queryString; - - private List<Object> parameters = new ArrayList<Object>(); - private Map<Integer, Class<?>> dataTypes = new HashMap<Integer, Class<?>>(); - - public StatementHelper() { - } - - public void setQueryString(String queryString) { - this.queryString = queryString; - } - - public String getQueryString() { - return queryString; - } - - public void addParameterValue(Object parameter) { - if (parameter != null) { - parameters.add(parameter); - dataTypes.put(parameters.size() - 1, parameter.getClass()); - } else { - throw new IllegalArgumentException( - "You cannot add null parameters using addParamaters(Object). " - + "Use addParameters(Object,Class) instead"); - } - } - - public void addParameterValue(Object parameter, Class<?> type) { - parameters.add(parameter); - dataTypes.put(parameters.size() - 1, type); - } - - public void setParameterValuesToStatement(PreparedStatement pstmt) - throws SQLException { - for (int i = 0; i < parameters.size(); i++) { - if (parameters.get(i) == null) { - handleNullValue(i, pstmt); - } else { - pstmt.setObject(i + 1, parameters.get(i)); - } - } - - /* - * The following list contains the data types supported by - * PreparedStatement but not supported by SQLContainer: - * - * [The list is provided as PreparedStatement method signatures] - * - * setNCharacterStream(int parameterIndex, Reader value) - * - * setNClob(int parameterIndex, NClob value) - * - * setNString(int parameterIndex, String value) - * - * setRef(int parameterIndex, Ref x) - * - * setRowId(int parameterIndex, RowId x) - * - * setSQLXML(int parameterIndex, SQLXML xmlObject) - * - * setBytes(int parameterIndex, byte[] x) - * - * setCharacterStream(int parameterIndex, Reader reader) - * - * setClob(int parameterIndex, Clob x) - * - * setURL(int parameterIndex, URL x) - * - * setArray(int parameterIndex, Array x) - * - * setAsciiStream(int parameterIndex, InputStream x) - * - * setBinaryStream(int parameterIndex, InputStream x) - * - * setBlob(int parameterIndex, Blob x) - */ - } - - private void handleNullValue(int i, PreparedStatement pstmt) - throws SQLException { - if (BigDecimal.class.equals(dataTypes.get(i))) { - pstmt.setBigDecimal(i + 1, null); - } else if (Boolean.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.BOOLEAN); - } else if (Byte.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.SMALLINT); - } else if (Date.class.equals(dataTypes.get(i))) { - pstmt.setDate(i + 1, null); - } else if (Double.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.DOUBLE); - } else if (Float.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.FLOAT); - } else if (Integer.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.INTEGER); - } else if (Long.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.BIGINT); - } else if (Short.class.equals(dataTypes.get(i))) { - pstmt.setNull(i + 1, Types.SMALLINT); - } else if (String.class.equals(dataTypes.get(i))) { - pstmt.setString(i + 1, null); - } else if (Time.class.equals(dataTypes.get(i))) { - pstmt.setTime(i + 1, null); - } else if (Timestamp.class.equals(dataTypes.get(i))) { - pstmt.setTimestamp(i + 1, null); - } else { - - if (handleUnrecognizedTypeNullValue(i, pstmt, dataTypes)) { - return; - } - - throw new SQLException("Data type not supported by SQLContainer: " - + parameters.get(i).getClass().toString()); - } - } - - /** - * Handle unrecognized null values. Override this to handle null values for - * platform specific data types that are not handled by the default - * implementation of the {@link StatementHelper}. - * - * @param i - * @param pstmt - * @param dataTypes2 - * - * @return true if handled, false otherwise - * - * @see {@link http://dev.vaadin.com/ticket/9148} - */ - protected boolean handleUnrecognizedTypeNullValue(int i, - PreparedStatement pstmt, Map<Integer, Class<?>> dataTypes) - throws SQLException { - return false; - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/AndTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/AndTranslator.java deleted file mode 100644 index 251a543a8a..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/AndTranslator.java +++ /dev/null @@ -1,23 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.And; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class AndTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof And; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - return QueryBuilder.group(QueryBuilder.getJoinedFilterString( - ((And) filter).getFilters(), "AND", sh)); - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/BetweenTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/BetweenTranslator.java deleted file mode 100644 index 4fcaf759ea..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/BetweenTranslator.java +++ /dev/null @@ -1,25 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.Between; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class BetweenTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof Between; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - Between between = (Between) filter; - sh.addParameterValue(between.getStartValue()); - sh.addParameterValue(between.getEndValue()); - return QueryBuilder.quote(between.getPropertyId()) + " BETWEEN ? AND ?"; - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/CompareTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/CompareTranslator.java deleted file mode 100644 index 4293e1d630..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/CompareTranslator.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.Compare; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class CompareTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof Compare; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - Compare compare = (Compare) filter; - sh.addParameterValue(compare.getValue()); - String prop = QueryBuilder.quote(compare.getPropertyId()); - switch (compare.getOperation()) { - case EQUAL: - return prop + " = ?"; - case GREATER: - return prop + " > ?"; - case GREATER_OR_EQUAL: - return prop + " >= ?"; - case LESS: - return prop + " < ?"; - case LESS_OR_EQUAL: - return prop + " <= ?"; - default: - return ""; - } - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/FilterTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/FilterTranslator.java deleted file mode 100644 index 84af9d5c97..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/FilterTranslator.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import java.io.Serializable; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public interface FilterTranslator extends Serializable { - public boolean translatesFilter(Filter filter); - - public String getWhereStringForFilter(Filter filter, StatementHelper sh); - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/IsNullTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/IsNullTranslator.java deleted file mode 100644 index a2a6cd2c09..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/IsNullTranslator.java +++ /dev/null @@ -1,22 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.IsNull; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class IsNullTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof IsNull; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - IsNull in = (IsNull) filter; - return QueryBuilder.quote(in.getPropertyId()) + " IS NULL"; - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/LikeTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/LikeTranslator.java deleted file mode 100644 index 25a85caec0..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/LikeTranslator.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.Like; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class LikeTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof Like; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - Like like = (Like) filter; - if (like.isCaseSensitive()) { - sh.addParameterValue(like.getValue()); - return QueryBuilder.quote(like.getPropertyId()) + " LIKE ?"; - } else { - sh.addParameterValue(like.getValue().toUpperCase()); - return "UPPER(" + QueryBuilder.quote(like.getPropertyId()) - + ") LIKE ?"; - } - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/NotTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/NotTranslator.java deleted file mode 100644 index 5dfbe240e7..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/NotTranslator.java +++ /dev/null @@ -1,29 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.IsNull; -import com.vaadin.data.util.filter.Not; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class NotTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof Not; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - Not not = (Not) filter; - if (not.getFilter() instanceof IsNull) { - IsNull in = (IsNull) not.getFilter(); - return QueryBuilder.quote(in.getPropertyId()) + " IS NOT NULL"; - } - return "NOT " - + QueryBuilder.getWhereStringForFilter(not.getFilter(), sh); - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/OrTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/OrTranslator.java deleted file mode 100644 index 2f0ed814e0..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/OrTranslator.java +++ /dev/null @@ -1,23 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.Or; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class OrTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof Or; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - return QueryBuilder.group(QueryBuilder.getJoinedFilterString( - ((Or) filter).getFilters(), "OR", sh)); - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/QueryBuilder.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/QueryBuilder.java deleted file mode 100644 index 24be8963e0..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/QueryBuilder.java +++ /dev/null @@ -1,98 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class QueryBuilder implements Serializable { - - private static ArrayList<FilterTranslator> filterTranslators = new ArrayList<FilterTranslator>(); - private static StringDecorator stringDecorator = new StringDecorator("\"", - "\""); - - static { - /* Register all default filter translators */ - addFilterTranslator(new AndTranslator()); - addFilterTranslator(new OrTranslator()); - addFilterTranslator(new LikeTranslator()); - addFilterTranslator(new BetweenTranslator()); - addFilterTranslator(new CompareTranslator()); - addFilterTranslator(new NotTranslator()); - addFilterTranslator(new IsNullTranslator()); - addFilterTranslator(new SimpleStringTranslator()); - } - - public synchronized static void addFilterTranslator( - FilterTranslator translator) { - filterTranslators.add(translator); - } - - /** - * Allows specification of a custom ColumnQuoter instance that handles - * quoting of column names for the current DB dialect. - * - * @param decorator - * the ColumnQuoter instance to use. - */ - public static void setStringDecorator(StringDecorator decorator) { - stringDecorator = decorator; - } - - public static String quote(Object str) { - return stringDecorator.quote(str); - } - - public static String group(String str) { - return stringDecorator.group(str); - } - - /** - * Constructs and returns a string representing the filter that can be used - * in a WHERE clause. - * - * @param filter - * the filter to translate - * @param sh - * the statement helper to update with the value(s) of the filter - * @return a string representing the filter. - */ - public synchronized static String getWhereStringForFilter(Filter filter, - StatementHelper sh) { - for (FilterTranslator ft : filterTranslators) { - if (ft.translatesFilter(filter)) { - return ft.getWhereStringForFilter(filter, sh); - } - } - return ""; - } - - public static String getJoinedFilterString(Collection<Filter> filters, - String joinString, StatementHelper sh) { - StringBuilder result = new StringBuilder(); - for (Filter f : filters) { - result.append(getWhereStringForFilter(f, sh)); - result.append(" ").append(joinString).append(" "); - } - // Remove the last instance of joinString - result.delete(result.length() - joinString.length() - 2, - result.length()); - return result.toString(); - } - - public static String getWhereStringForFilters(List<Filter> filters, - StatementHelper sh) { - if (filters == null || filters.isEmpty()) { - return ""; - } - StringBuilder where = new StringBuilder(" WHERE "); - where.append(getJoinedFilterString(filters, "AND", sh)); - return where.toString(); - } -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/SimpleStringTranslator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/SimpleStringTranslator.java deleted file mode 100644 index f108003535..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/SimpleStringTranslator.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import com.vaadin.data.Container.Filter; -import com.vaadin.data.util.filter.Like; -import com.vaadin.data.util.filter.SimpleStringFilter; -import com.vaadin.data.util.sqlcontainer.query.generator.StatementHelper; - -public class SimpleStringTranslator implements FilterTranslator { - - @Override - public boolean translatesFilter(Filter filter) { - return filter instanceof SimpleStringFilter; - } - - @Override - public String getWhereStringForFilter(Filter filter, StatementHelper sh) { - SimpleStringFilter ssf = (SimpleStringFilter) filter; - // Create a Like filter based on the SimpleStringFilter and execute the - // LikeTranslator - String likeStr = ssf.isOnlyMatchPrefix() ? ssf.getFilterString() + "%" - : "%" + ssf.getFilterString() + "%"; - Like like = new Like(ssf.getPropertyId().toString(), likeStr); - like.setCaseSensitive(!ssf.isIgnoreCase()); - return new LikeTranslator().getWhereStringForFilter(like, sh); - } - -} diff --git a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/StringDecorator.java b/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/StringDecorator.java deleted file mode 100644 index 8d2eabb5bc..0000000000 --- a/src/com/vaadin/data/util/sqlcontainer/query/generator/filter/StringDecorator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.util.sqlcontainer.query.generator.filter; - -import java.io.Serializable; - -/** - * The StringDecorator knows how to produce a quoted string using the specified - * quote start and quote end characters. It also handles grouping of a string - * (surrounding it in parenthesis). - * - * Extend this class if you need to support special characters for grouping - * (parenthesis). - * - * @author Vaadin Ltd - */ -public class StringDecorator implements Serializable { - - private final String quoteStart; - private final String quoteEnd; - - /** - * Constructs a StringDecorator that uses the quoteStart and quoteEnd - * characters to create quoted strings. - * - * @param quoteStart - * the character denoting the start of a quote. - * @param quoteEnd - * the character denoting the end of a quote. - */ - public StringDecorator(String quoteStart, String quoteEnd) { - this.quoteStart = quoteStart; - this.quoteEnd = quoteEnd; - } - - /** - * Surround a string with quote characters. - * - * @param str - * the string to quote - * @return the quoted string - */ - public String quote(Object str) { - return quoteStart + str + quoteEnd; - } - - /** - * Groups a string by surrounding it in parenthesis - * - * @param str - * the string to group - * @return the grouped string - */ - public String group(String str) { - return "(" + str + ")"; - } -} diff --git a/src/com/vaadin/data/validator/AbstractStringValidator.java b/src/com/vaadin/data/validator/AbstractStringValidator.java deleted file mode 100644 index 5267cc7b7b..0000000000 --- a/src/com/vaadin/data/validator/AbstractStringValidator.java +++ /dev/null @@ -1,42 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -/** - * Validator base class for validating strings. - * <p> - * To include the value that failed validation in the exception message you can - * use "{0}" in the error message. This will be replaced with the failed value - * (converted to string using {@link #toString()}) or "null" if the value is - * null. - * </p> - * - * @author Vaadin Ltd. - * @version @VERSION@ - * @since 5.4 - */ -@SuppressWarnings("serial") -public abstract class AbstractStringValidator extends AbstractValidator<String> { - - /** - * Constructs a validator for strings. - * - * <p> - * Null and empty string values are always accepted. To reject empty values, - * set the field being validated as required. - * </p> - * - * @param errorMessage - * the message to be included in an {@link InvalidValueException} - * (with "{0}" replaced by the value that failed validation). - * */ - public AbstractStringValidator(String errorMessage) { - super(errorMessage); - } - - @Override - public Class<String> getType() { - return String.class; - } -} diff --git a/src/com/vaadin/data/validator/AbstractValidator.java b/src/com/vaadin/data/validator/AbstractValidator.java deleted file mode 100644 index 8febe5338a..0000000000 --- a/src/com/vaadin/data/validator/AbstractValidator.java +++ /dev/null @@ -1,139 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -import com.vaadin.data.Validator; - -/** - * Abstract {@link com.vaadin.data.Validator Validator} implementation that - * provides a basic Validator implementation except the - * {@link #isValidValue(Object)} method. - * <p> - * To include the value that failed validation in the exception message you can - * use "{0}" in the error message. This will be replaced with the failed value - * (converted to string using {@link #toString()}) or "null" if the value is - * null. - * </p> - * <p> - * The default implementation of AbstractValidator does not support HTML in - * error messages. To enable HTML support, override - * {@link InvalidValueException#getHtmlMessage()} and throw such exceptions from - * {@link #validate(Object)}. - * </p> - * <p> - * Since Vaadin 7, subclasses can either implement {@link #validate(Object)} - * directly or implement {@link #isValidValue(Object)} when migrating legacy - * applications. To check validity, {@link #validate(Object)} should be used. - * </p> - * - * @param <T> - * The type - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.4 - */ -public abstract class AbstractValidator<T> implements Validator { - - /** - * Error message that is included in an {@link InvalidValueException} if - * such is thrown. - */ - private String errorMessage; - - /** - * Constructs a validator with the given error message. - * - * @param errorMessage - * the message to be included in an {@link InvalidValueException} - * (with "{0}" replaced by the value that failed validation). - */ - public AbstractValidator(String errorMessage) { - this.errorMessage = errorMessage; - } - - /** - * Since Vaadin 7, subclasses of AbstractValidator should override - * {@link #isValidValue(Object)} or {@link #validate(Object)} instead of - * {@link #isValid(Object)}. {@link #validate(Object)} should normally be - * used to check values. - * - * @param value - * @return true if the value is valid - */ - public boolean isValid(Object value) { - try { - validate(value); - return true; - } catch (InvalidValueException e) { - return false; - } - } - - /** - * Internally check the validity of a value. This method can be used to - * perform validation in subclasses if customization of the error message is - * not needed. Otherwise, subclasses should override - * {@link #validate(Object)} and the return value of this method is ignored. - * - * This method should not be called from outside the validator class itself. - * - * @param value - * @return - */ - protected abstract boolean isValidValue(T value); - - @Override - public void validate(Object value) throws InvalidValueException { - // isValidType ensures that value can safely be cast to TYPE - if (!isValidType(value) || !isValidValue((T) value)) { - String message = getErrorMessage().replace("{0}", - String.valueOf(value)); - throw new InvalidValueException(message); - } - } - - /** - * Checks the type of the value to validate to ensure it conforms with - * getType. Enables sub classes to handle the specific type instead of - * Object. - * - * @param value - * The value to check - * @return true if the value can safely be cast to the type specified by - * {@link #getType()} - */ - protected boolean isValidType(Object value) { - if (value == null) { - return true; - } - - return getType().isAssignableFrom(value.getClass()); - } - - /** - * Returns the message to be included in the exception in case the value - * does not validate. - * - * @return the error message provided in the constructor or using - * {@link #setErrorMessage(String)}. - */ - public String getErrorMessage() { - return errorMessage; - } - - /** - * Sets the message to be included in the exception in case the value does - * not validate. The exception message is typically shown to the end user. - * - * @param errorMessage - * the error message. "{0}" is automatically replaced by the - * value that did not validate. - */ - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - - public abstract Class<T> getType(); -} diff --git a/src/com/vaadin/data/validator/BeanValidator.java b/src/com/vaadin/data/validator/BeanValidator.java deleted file mode 100644 index 816ff79b83..0000000000 --- a/src/com/vaadin/data/validator/BeanValidator.java +++ /dev/null @@ -1,176 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.validator; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -import javax.validation.ConstraintViolation; -import javax.validation.MessageInterpolator.Context; -import javax.validation.Validation; -import javax.validation.ValidatorFactory; -import javax.validation.metadata.ConstraintDescriptor; - -import com.vaadin.data.Validator; - -/** - * Vaadin {@link Validator} using the JSR-303 (javax.validation) - * annotation-based bean validation. - * - * The annotations of the fields of the beans are used to determine the - * validation to perform. - * - * Note that a JSR-303 implementation (e.g. Hibernate Validator or Apache Bean - * Validation - formerly agimatec validation) must be present on the project - * classpath when using bean validation. - * - * @since 7.0 - * - * @author Petri Hakala - * @author Henri Sara - */ -public class BeanValidator implements Validator { - - private static final long serialVersionUID = 1L; - private static ValidatorFactory factory; - - private transient javax.validation.Validator javaxBeanValidator; - private String propertyName; - private Class<?> beanClass; - private Locale locale; - - /** - * Simple implementation of a message interpolator context that returns - * fixed values. - */ - protected static class SimpleContext implements Context, Serializable { - - private final Object value; - private final ConstraintDescriptor<?> descriptor; - - /** - * Create a simple immutable message interpolator context. - * - * @param value - * value being validated - * @param descriptor - * ConstraintDescriptor corresponding to the constraint being - * validated - */ - public SimpleContext(Object value, ConstraintDescriptor<?> descriptor) { - this.value = value; - this.descriptor = descriptor; - } - - @Override - public ConstraintDescriptor<?> getConstraintDescriptor() { - return descriptor; - } - - @Override - public Object getValidatedValue() { - return value; - } - - } - - /** - * Creates a Vaadin {@link Validator} utilizing JSR-303 bean validation. - * - * @param beanClass - * bean class based on which the validation should be performed - * @param propertyName - * property to validate - */ - public BeanValidator(Class<?> beanClass, String propertyName) { - this.beanClass = beanClass; - this.propertyName = propertyName; - locale = Locale.getDefault(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Validator#validate(java.lang.Object) - */ - @Override - public void validate(final Object value) throws InvalidValueException { - Set<?> violations = getJavaxBeanValidator().validateValue(beanClass, - propertyName, value); - if (violations.size() > 0) { - List<String> exceptions = new ArrayList<String>(); - for (Object v : violations) { - final ConstraintViolation<?> violation = (ConstraintViolation<?>) v; - String msg = getJavaxBeanValidatorFactory() - .getMessageInterpolator().interpolate( - violation.getMessageTemplate(), - new SimpleContext(value, violation - .getConstraintDescriptor()), locale); - exceptions.add(msg); - } - StringBuilder b = new StringBuilder(); - for (int i = 0; i < exceptions.size(); i++) { - if (i != 0) { - b.append("<br/>"); - } - b.append(exceptions.get(i)); - } - throw new InvalidValueException(b.toString()); - } - } - - /** - * Sets the locale used for validation error messages. - * - * Revalidation is not automatically triggered by setting the locale. - * - * @param locale - */ - public void setLocale(Locale locale) { - this.locale = locale; - } - - /** - * Gets the locale used for validation error messages. - * - * @return locale used for validation - */ - public Locale getLocale() { - return locale; - } - - /** - * Returns the underlying JSR-303 bean validator factory used. A factory is - * created using {@link Validation} if necessary. - * - * @return {@link ValidatorFactory} to use - */ - protected static ValidatorFactory getJavaxBeanValidatorFactory() { - if (factory == null) { - factory = Validation.buildDefaultValidatorFactory(); - } - - return factory; - } - - /** - * Returns a shared Validator instance to use. An instance is created using - * the validator factory if necessary and thereafter reused by the - * {@link BeanValidator} instance. - * - * @return the JSR-303 {@link javax.validation.Validator} to use - */ - protected javax.validation.Validator getJavaxBeanValidator() { - if (javaxBeanValidator == null) { - javaxBeanValidator = getJavaxBeanValidatorFactory().getValidator(); - } - - return javaxBeanValidator; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/data/validator/CompositeValidator.java b/src/com/vaadin/data/validator/CompositeValidator.java deleted file mode 100644 index cad31c9d4d..0000000000 --- a/src/com/vaadin/data/validator/CompositeValidator.java +++ /dev/null @@ -1,259 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.validator; - -import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; - -import com.vaadin.data.Validator; - -/** - * The <code>CompositeValidator</code> allows you to chain (compose) many - * validators to validate one field. The contained validators may be required to - * all validate the value to validate or it may be enough that one contained - * validator validates the value. This behaviour is controlled by the modes - * <code>AND</code> and <code>OR</code>. - * - * @author Vaadin Ltd. - * @version @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class CompositeValidator implements Validator { - - public enum CombinationMode { - /** - * The validators are combined with <code>AND</code> clause: validity of - * the composite implies validity of the all validators it is composed - * of must be valid. - */ - AND, - /** - * The validators are combined with <code>OR</code> clause: validity of - * the composite implies that some of validators it is composed of must - * be valid. - */ - OR; - } - - /** - * @deprecated from 7.0, use {@link CombinationMode#AND} instead   - */ - @Deprecated - public static final CombinationMode MODE_AND = CombinationMode.AND; - /** - * @deprecated from 7.0, use {@link CombinationMode#OR} instead   - */ - @Deprecated - public static final CombinationMode MODE_OR = CombinationMode.OR; - - private String errorMessage; - - /** - * Operation mode. - */ - private CombinationMode mode = CombinationMode.AND; - - /** - * List of contained validators. - */ - private final List<Validator> validators = new LinkedList<Validator>(); - - /** - * Construct a composite validator in <code>AND</code> mode without error - * message. - */ - public CompositeValidator() { - this(CombinationMode.AND, ""); - } - - /** - * Constructs a composite validator in given mode. - * - * @param mode - * @param errorMessage - */ - public CompositeValidator(CombinationMode mode, String errorMessage) { - setErrorMessage(errorMessage); - setMode(mode); - } - - /** - * Validates the given value. - * <p> - * The value is valid, if: - * <ul> - * <li><code>MODE_AND</code>: All of the sub-validators are valid - * <li><code>MODE_OR</code>: Any of the sub-validators are valid - * </ul> - * - * If the value is invalid, validation error is thrown. If the error message - * is set (non-null), it is used. If the error message has not been set, the - * first error occurred is thrown. - * </p> - * - * @param value - * the value to check. - * @throws Validator.InvalidValueException - * if the value is not valid. - */ - @Override - public void validate(Object value) throws Validator.InvalidValueException { - switch (mode) { - case AND: - for (Validator validator : validators) { - validator.validate(value); - } - return; - - case OR: - Validator.InvalidValueException first = null; - for (Validator v : validators) { - try { - v.validate(value); - return; - } catch (final Validator.InvalidValueException e) { - if (first == null) { - first = e; - } - } - } - if (first == null) { - return; - } - final String em = getErrorMessage(); - if (em != null) { - throw new Validator.InvalidValueException(em); - } else { - throw first; - } - } - } - - /** - * Gets the mode of the validator. - * - * @return Operation mode of the validator: {@link CombinationMode#AND} or - * {@link CombinationMode#OR}. - */ - public final CombinationMode getMode() { - return mode; - } - - /** - * Sets the mode of the validator. The valid modes are: - * <ul> - * <li>{@link CombinationMode#AND} (default) - * <li>{@link CombinationMode#OR} - * </ul> - * - * @param mode - * the mode to set. - */ - public void setMode(CombinationMode mode) { - if (mode == null) { - throw new IllegalArgumentException( - "The validator can't be set to null"); - } - this.mode = mode; - } - - /** - * Gets the error message for the composite validator. If the error message - * is null, original error messages of the sub-validators are used instead. - */ - public String getErrorMessage() { - if (errorMessage != null) { - return errorMessage; - } - - // TODO Return composite error message - - return null; - } - - /** - * Adds validator to the interface. - * - * @param validator - * the Validator object which performs validation checks on this - * set of data field values. - */ - public void addValidator(Validator validator) { - if (validator == null) { - return; - } - validators.add(validator); - } - - /** - * Removes a validator from the composite. - * - * @param validator - * the Validator object which performs validation checks on this - * set of data field values. - */ - public void removeValidator(Validator validator) { - validators.remove(validator); - } - - /** - * Gets sub-validators by class. - * - * <p> - * If the component contains directly or recursively (it contains another - * composite containing the validator) validators compatible with given type - * they are returned. This only applies to <code>AND</code> mode composite - * validators. - * </p> - * - * <p> - * If the validator is in <code>OR</code> mode or does not contain any - * validators of given type null is returned. - * </p> - * - * @param validatorType - * The type of validators to return - * - * @return Collection<Validator> of validators compatible with given type - * that must apply or null if none found. - */ - public Collection<Validator> getSubValidators(Class validatorType) { - if (mode != CombinationMode.AND) { - return null; - } - - final HashSet<Validator> found = new HashSet<Validator>(); - for (Validator v : validators) { - if (validatorType.isAssignableFrom(v.getClass())) { - found.add(v); - } - if (v instanceof CompositeValidator - && ((CompositeValidator) v).getMode() == MODE_AND) { - final Collection<Validator> c = ((CompositeValidator) v) - .getSubValidators(validatorType); - if (c != null) { - found.addAll(c); - } - } - } - - return found.isEmpty() ? null : found; - } - - /** - * Sets the message to be included in the exception in case the value does - * not validate. The exception message is typically shown to the end user. - * - * @param errorMessage - * the error message. - */ - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - -} diff --git a/src/com/vaadin/data/validator/DateRangeValidator.java b/src/com/vaadin/data/validator/DateRangeValidator.java deleted file mode 100644 index 24f3d3ce10..0000000000 --- a/src/com/vaadin/data/validator/DateRangeValidator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -import java.util.Date; - -import com.vaadin.ui.DateField.Resolution; - -/** - * Validator for validating that a Date is inside a given range. - * - * <p> - * Note that the comparison is done directly on the Date object so take care - * that the hours/minutes/seconds/milliseconds of the min/max values are - * properly set. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 7.0 - */ -public class DateRangeValidator extends RangeValidator<Date> { - - /** - * Creates a validator for checking that an Date is within a given range. - * <p> - * By default the range is inclusive i.e. both minValue and maxValue are - * valid values. Use {@link #setMinValueIncluded(boolean)} or - * {@link #setMaxValueIncluded(boolean)} to change it. - * </p> - * <p> - * Note that the comparison is done directly on the Date object so take care - * that the hours/minutes/seconds/milliseconds of the min/max values are - * properly set. - * </p> - * - * @param errorMessage - * the message to display in case the value does not validate. - * @param minValue - * The minimum value to accept or null for no limit - * @param maxValue - * The maximum value to accept or null for no limit - */ - public DateRangeValidator(String errorMessage, Date minValue, - Date maxValue, Resolution resolution) { - super(errorMessage, Date.class, minValue, maxValue); - } - -} diff --git a/src/com/vaadin/data/validator/DoubleRangeValidator.java b/src/com/vaadin/data/validator/DoubleRangeValidator.java deleted file mode 100644 index 05ae2f827e..0000000000 --- a/src/com/vaadin/data/validator/DoubleRangeValidator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -/** - * Validator for validating that a {@link Double} is inside a given range. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 7.0 - */ -@SuppressWarnings("serial") -public class DoubleRangeValidator extends RangeValidator<Double> { - - /** - * Creates a validator for checking that an Double is within a given range. - * - * By default the range is inclusive i.e. both minValue and maxValue are - * valid values. Use {@link #setMinValueIncluded(boolean)} or - * {@link #setMaxValueIncluded(boolean)} to change it. - * - * - * @param errorMessage - * the message to display in case the value does not validate. - * @param minValue - * The minimum value to accept or null for no limit - * @param maxValue - * The maximum value to accept or null for no limit - */ - public DoubleRangeValidator(String errorMessage, Double minValue, - Double maxValue) { - super(errorMessage, Double.class, minValue, maxValue); - } - -} diff --git a/src/com/vaadin/data/validator/DoubleValidator.java b/src/com/vaadin/data/validator/DoubleValidator.java deleted file mode 100644 index 18f1909add..0000000000 --- a/src/com/vaadin/data/validator/DoubleValidator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -/** - * String validator for a double precision floating point number. See - * {@link com.vaadin.data.validator.AbstractStringValidator} for more - * information. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.4 - * @deprecated in Vaadin 7.0. Use an Double converter on the field instead. - */ -@Deprecated -@SuppressWarnings("serial") -public class DoubleValidator extends AbstractStringValidator { - - /** - * Creates a validator for checking that a string can be parsed as an - * double. - * - * @param errorMessage - * the message to display in case the value does not validate. - * @deprecated in Vaadin 7.0. Use a Double converter on the field instead - * and/or use a {@link DoubleRangeValidator} for validating that - * the value is inside a given range. - */ - @Deprecated - public DoubleValidator(String errorMessage) { - super(errorMessage); - } - - @Override - protected boolean isValidValue(String value) { - try { - Double.parseDouble(value); - return true; - } catch (Exception e) { - return false; - } - } - - @Override - public void validate(Object value) throws InvalidValueException { - if (value != null && value instanceof Double) { - // Allow Doubles to pass through the validator for easier - // migration. Otherwise a TextField connected to an double property - // with a DoubleValidator will fail. - return; - } - - super.validate(value); - } - -} diff --git a/src/com/vaadin/data/validator/EmailValidator.java b/src/com/vaadin/data/validator/EmailValidator.java deleted file mode 100644 index c76d7e13dc..0000000000 --- a/src/com/vaadin/data/validator/EmailValidator.java +++ /dev/null @@ -1,35 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -/** - * String validator for e-mail addresses. The e-mail address syntax is not - * complete according to RFC 822 but handles the vast majority of valid e-mail - * addresses correctly. - * - * See {@link com.vaadin.data.validator.AbstractStringValidator} for more - * information. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.4 - */ -@SuppressWarnings("serial") -public class EmailValidator extends RegexpValidator { - - /** - * Creates a validator for checking that a string is a syntactically valid - * e-mail address. - * - * @param errorMessage - * the message to display in case the value does not validate. - */ - public EmailValidator(String errorMessage) { - super( - "^([a-zA-Z0-9_\\.\\-+])+@(([a-zA-Z0-9-])+\\.)+([a-zA-Z0-9]{2,4})+$", - true, errorMessage); - } - -} diff --git a/src/com/vaadin/data/validator/IntegerRangeValidator.java b/src/com/vaadin/data/validator/IntegerRangeValidator.java deleted file mode 100644 index c171dd97d8..0000000000 --- a/src/com/vaadin/data/validator/IntegerRangeValidator.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -/** - * Validator for validating that an {@link Integer} is inside a given range. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.4 - */ -@SuppressWarnings("serial") -public class IntegerRangeValidator extends RangeValidator<Integer> { - - /** - * Creates a validator for checking that an Integer is within a given range. - * - * By default the range is inclusive i.e. both minValue and maxValue are - * valid values. Use {@link #setMinValueIncluded(boolean)} or - * {@link #setMaxValueIncluded(boolean)} to change it. - * - * - * @param errorMessage - * the message to display in case the value does not validate. - * @param minValue - * The minimum value to accept or null for no limit - * @param maxValue - * The maximum value to accept or null for no limit - */ - public IntegerRangeValidator(String errorMessage, Integer minValue, - Integer maxValue) { - super(errorMessage, Integer.class, minValue, maxValue); - } - -} diff --git a/src/com/vaadin/data/validator/IntegerValidator.java b/src/com/vaadin/data/validator/IntegerValidator.java deleted file mode 100644 index 88ae9f3f0b..0000000000 --- a/src/com/vaadin/data/validator/IntegerValidator.java +++ /dev/null @@ -1,58 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -/** - * String validator for integers. See - * {@link com.vaadin.data.validator.AbstractStringValidator} for more - * information. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.4 - * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead. - */ -@SuppressWarnings("serial") -@Deprecated -public class IntegerValidator extends AbstractStringValidator { - - /** - * Creates a validator for checking that a string can be parsed as an - * integer. - * - * @param errorMessage - * the message to display in case the value does not validate. - * @deprecated in Vaadin 7.0. Use an Integer converter on the field instead - * and/or use an {@link IntegerRangeValidator} for validating - * that the value is inside a given range. - */ - @Deprecated - public IntegerValidator(String errorMessage) { - super(errorMessage); - - } - - @Override - protected boolean isValidValue(String value) { - try { - Integer.parseInt(value); - return true; - } catch (Exception e) { - return false; - } - } - - @Override - public void validate(Object value) throws InvalidValueException { - if (value != null && value instanceof Integer) { - // Allow Integers to pass through the validator for easier - // migration. Otherwise a TextField connected to an integer property - // with an IntegerValidator will fail. - return; - } - - super.validate(value); - } -} diff --git a/src/com/vaadin/data/validator/NullValidator.java b/src/com/vaadin/data/validator/NullValidator.java deleted file mode 100644 index 551d88c776..0000000000 --- a/src/com/vaadin/data/validator/NullValidator.java +++ /dev/null @@ -1,92 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.validator; - -import com.vaadin.data.Validator; - -/** - * This validator is used for validating properties that do or do not allow null - * values. By default, nulls are not allowed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class NullValidator implements Validator { - - private boolean onlyNullAllowed; - - private String errorMessage; - - /** - * Creates a new NullValidator. - * - * @param errorMessage - * the error message to display on invalidation. - * @param onlyNullAllowed - * Are only nulls allowed? - */ - public NullValidator(String errorMessage, boolean onlyNullAllowed) { - setErrorMessage(errorMessage); - setNullAllowed(onlyNullAllowed); - } - - /** - * Validates the data given in value. - * - * @param value - * the value to validate. - * @throws Validator.InvalidValueException - * if the value was invalid. - */ - @Override - public void validate(Object value) throws Validator.InvalidValueException { - if ((onlyNullAllowed && value != null) - || (!onlyNullAllowed && value == null)) { - throw new Validator.InvalidValueException(errorMessage); - } - } - - /** - * Returns <code>true</code> if nulls are allowed otherwise - * <code>false</code>. - */ - public final boolean isNullAllowed() { - return onlyNullAllowed; - } - - /** - * Sets if nulls (and only nulls) are to be allowed. - * - * @param onlyNullAllowed - * If true, only nulls are allowed. If false only non-nulls are - * allowed. Do we allow nulls? - */ - public void setNullAllowed(boolean onlyNullAllowed) { - this.onlyNullAllowed = onlyNullAllowed; - } - - /** - * Gets the error message that is displayed in case the value is invalid. - * - * @return the Error Message. - */ - public String getErrorMessage() { - return errorMessage; - } - - /** - * Sets the error message to be displayed on invalid value. - * - * @param errorMessage - * the Error Message to set. - */ - public void setErrorMessage(String errorMessage) { - this.errorMessage = errorMessage; - } - -} diff --git a/src/com/vaadin/data/validator/RangeValidator.java b/src/com/vaadin/data/validator/RangeValidator.java deleted file mode 100644 index 433271274f..0000000000 --- a/src/com/vaadin/data/validator/RangeValidator.java +++ /dev/null @@ -1,186 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -/** - * An base implementation for validating any objects that implement - * {@link Comparable}. - * - * Verifies that the value is of the given type and within the (optionally) - * given limits. Typically you want to use a sub class of this like - * {@link IntegerRangeValidator}, {@link DoubleRangeValidator} or - * {@link DateRangeValidator} in applications. - * <p> - * Note that {@link RangeValidator} always accept null values. Make a field - * required to ensure that no empty values are accepted or override - * {@link #isValidValue(Comparable)}. - * </p> - * - * @param <T> - * The type of Number to validate. Must implement Comparable so that - * minimum and maximum checks work. - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 7.0 - */ -public class RangeValidator<T extends Comparable> extends AbstractValidator<T> { - - private T minValue = null; - private boolean minValueIncluded = true; - private T maxValue = null; - private boolean maxValueIncluded = true; - private Class<T> type; - - /** - * Creates a new range validator of the given type. - * - * @param errorMessage - * The error message to use if validation fails - * @param type - * The type of object the validator can validate. - * @param minValue - * The minimum value that should be accepted or null for no limit - * @param maxValue - * The maximum value that should be accepted or null for no limit - */ - public RangeValidator(String errorMessage, Class<T> type, T minValue, - T maxValue) { - super(errorMessage); - this.type = type; - this.minValue = minValue; - this.maxValue = maxValue; - } - - /** - * Checks if the minimum value is part of the accepted range - * - * @return true if the minimum value is part of the range, false otherwise - */ - public boolean isMinValueIncluded() { - return minValueIncluded; - } - - /** - * Sets if the minimum value is part of the accepted range - * - * @param minValueIncluded - * true if the minimum value should be part of the range, false - * otherwise - */ - public void setMinValueIncluded(boolean minValueIncluded) { - this.minValueIncluded = minValueIncluded; - } - - /** - * Checks if the maximum value is part of the accepted range - * - * @return true if the maximum value is part of the range, false otherwise - */ - public boolean isMaxValueIncluded() { - return maxValueIncluded; - } - - /** - * Sets if the maximum value is part of the accepted range - * - * @param maxValueIncluded - * true if the maximum value should be part of the range, false - * otherwise - */ - public void setMaxValueIncluded(boolean maxValueIncluded) { - this.maxValueIncluded = maxValueIncluded; - } - - /** - * Gets the minimum value of the range - * - * @return the minimum value - */ - public T getMinValue() { - return minValue; - } - - /** - * Sets the minimum value of the range. Use - * {@link #setMinValueIncluded(boolean)} to control whether this value is - * part of the range or not. - * - * @param minValue - * the minimum value - */ - public void setMinValue(T minValue) { - this.minValue = minValue; - } - - /** - * Gets the maximum value of the range - * - * @return the maximum value - */ - public T getMaxValue() { - return maxValue; - } - - /** - * Sets the maximum value of the range. Use - * {@link #setMaxValueIncluded(boolean)} to control whether this value is - * part of the range or not. - * - * @param maxValue - * the maximum value - */ - public void setMaxValue(T maxValue) { - this.maxValue = maxValue; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object - * ) - */ - @Override - protected boolean isValidValue(T value) { - if (value == null) { - return true; - } - - if (getMinValue() != null) { - // Ensure that the min limit is ok - int result = value.compareTo(getMinValue()); - if (result < 0) { - // value less than min value - return false; - } else if (result == 0 && !isMinValueIncluded()) { - // values equal and min value not included - return false; - } - } - if (getMaxValue() != null) { - // Ensure that the Max limit is ok - int result = value.compareTo(getMaxValue()); - if (result > 0) { - // value greater than max value - return false; - } else if (result == 0 && !isMaxValueIncluded()) { - // values equal and max value not included - return false; - } - } - return true; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.validator.AbstractValidator#getType() - */ - @Override - public Class<T> getType() { - return type; - } - -} diff --git a/src/com/vaadin/data/validator/RegexpValidator.java b/src/com/vaadin/data/validator/RegexpValidator.java deleted file mode 100644 index 8143d54c97..0000000000 --- a/src/com/vaadin/data/validator/RegexpValidator.java +++ /dev/null @@ -1,97 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.data.validator; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * String validator comparing the string against a Java regular expression. Both - * complete matches and substring matches are supported. - * - * <p> - * For the Java regular expression syntax, see - * {@link java.util.regex.Pattern#sum} - * </p> - * <p> - * See {@link com.vaadin.data.validator.AbstractStringValidator} for more - * information. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.4 - */ -@SuppressWarnings("serial") -public class RegexpValidator extends AbstractStringValidator { - - private Pattern pattern; - private boolean complete; - private transient Matcher matcher = null; - - /** - * Creates a validator for checking that the regular expression matches the - * complete string to validate. - * - * @param regexp - * a Java regular expression - * @param errorMessage - * the message to display in case the value does not validate. - */ - public RegexpValidator(String regexp, String errorMessage) { - this(regexp, true, errorMessage); - } - - /** - * Creates a validator for checking that the regular expression matches the - * string to validate. - * - * @param regexp - * a Java regular expression - * @param complete - * true to use check for a complete match, false to look for a - * matching substring - * @param errorMessage - * the message to display in case the value does not validate. - */ - public RegexpValidator(String regexp, boolean complete, String errorMessage) { - super(errorMessage); - pattern = Pattern.compile(regexp); - this.complete = complete; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.data.validator.AbstractValidator#isValidValue(java.lang.Object - * ) - */ - @Override - protected boolean isValidValue(String value) { - if (complete) { - return getMatcher(value).matches(); - } else { - return getMatcher(value).find(); - } - } - - /** - * Get a new or reused matcher for the pattern - * - * @param value - * the string to find matches in - * @return Matcher for the string - */ - private Matcher getMatcher(String value) { - if (matcher == null) { - matcher = pattern.matcher(value); - } else { - matcher.reset(value); - } - return matcher; - } - -} diff --git a/src/com/vaadin/data/validator/StringLengthValidator.java b/src/com/vaadin/data/validator/StringLengthValidator.java deleted file mode 100644 index 54b2d28f58..0000000000 --- a/src/com/vaadin/data/validator/StringLengthValidator.java +++ /dev/null @@ -1,139 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.data.validator; - -/** - * This <code>StringLengthValidator</code> is used to validate the length of - * strings. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class StringLengthValidator extends AbstractStringValidator { - - private Integer minLength = null; - - private Integer maxLength = null; - - private boolean allowNull = true; - - /** - * Creates a new StringLengthValidator with a given error message. - * - * @param errorMessage - * the message to display in case the value does not validate. - */ - public StringLengthValidator(String errorMessage) { - super(errorMessage); - } - - /** - * Creates a new StringLengthValidator with a given error message and - * minimum and maximum length limits. - * - * @param errorMessage - * the message to display in case the value does not validate. - * @param minLength - * the minimum permissible length of the string or null for no - * limit. A negative value for no limit is also supported for - * backwards compatibility. - * @param maxLength - * the maximum permissible length of the string or null for no - * limit. A negative value for no limit is also supported for - * backwards compatibility. - * @param allowNull - * Are null strings permissible? This can be handled better by - * setting a field as required or not. - */ - public StringLengthValidator(String errorMessage, Integer minLength, - Integer maxLength, boolean allowNull) { - this(errorMessage); - setMinLength(minLength); - setMaxLength(maxLength); - setNullAllowed(allowNull); - } - - /** - * Checks if the given value is valid. - * - * @param value - * the value to validate. - * @return <code>true</code> for valid value, otherwise <code>false</code>. - */ - @Override - protected boolean isValidValue(String value) { - if (value == null) { - return allowNull; - } - final int len = value.length(); - if ((minLength != null && minLength > -1 && len < minLength) - || (maxLength != null && maxLength > -1 && len > maxLength)) { - return false; - } - return true; - } - - /** - * Returns <code>true</code> if null strings are allowed. - * - * @return <code>true</code> if allows null string, otherwise - * <code>false</code>. - */ - @Deprecated - public final boolean isNullAllowed() { - return allowNull; - } - - /** - * Gets the maximum permissible length of the string. - * - * @return the maximum length of the string or null if there is no limit - */ - public Integer getMaxLength() { - return maxLength; - } - - /** - * Gets the minimum permissible length of the string. - * - * @return the minimum length of the string or null if there is no limit - */ - public Integer getMinLength() { - return minLength; - } - - /** - * Sets whether null-strings are to be allowed. This can be better handled - * by setting a field as required or not. - */ - @Deprecated - public void setNullAllowed(boolean allowNull) { - this.allowNull = allowNull; - } - - /** - * Sets the maximum permissible length of the string. - * - * @param maxLength - * the maximum length to accept or null for no limit - */ - public void setMaxLength(Integer maxLength) { - this.maxLength = maxLength; - } - - /** - * Sets the minimum permissible length. - * - * @param minLength - * the minimum length to accept or null for no limit - */ - public void setMinLength(Integer minLength) { - this.minLength = minLength; - } - -} diff --git a/src/com/vaadin/data/validator/package.html b/src/com/vaadin/data/validator/package.html deleted file mode 100644 index c991bfc82a..0000000000 --- a/src/com/vaadin/data/validator/package.html +++ /dev/null @@ -1,23 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> - -</head> - -<body bgcolor="white"> - -<!-- Package summary here --> - -<p>Provides various {@link com.vaadin.data.Validator} -implementations.</p> - -<p>{@link com.vaadin.data.validator.AbstractValidator -AbstractValidator} provides an abstract implementation of the {@link -com.vaadin.data.Validator} interface and can be extended for custom -validation needs. {@link -com.vaadin.data.validator.AbstractStringValidator -AbstractStringValidator} can also be extended if the value is a String.</p> - - -</body> -</html> diff --git a/src/com/vaadin/event/Action.java b/src/com/vaadin/event/Action.java deleted file mode 100644 index 6c218c25dc..0000000000 --- a/src/com/vaadin/event/Action.java +++ /dev/null @@ -1,195 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.io.Serializable; - -import com.vaadin.terminal.Resource; - -/** - * Implements the action framework. This class contains subinterfaces for action - * handling and listing, and for action handler registrations and - * unregistration. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Action implements Serializable { - - /** - * Action title. - */ - private String caption; - - /** - * Action icon. - */ - private Resource icon = null; - - /** - * Constructs a new action with the given caption. - * - * @param caption - * the caption for the new action. - */ - public Action(String caption) { - this.caption = caption; - } - - /** - * Constructs a new action with the given caption string and icon. - * - * @param caption - * the caption for the new action. - * @param icon - * the icon for the new action. - */ - public Action(String caption, Resource icon) { - this.caption = caption; - this.icon = icon; - } - - /** - * Returns the action's caption. - * - * @return the action's caption as a <code>String</code>. - */ - public String getCaption() { - return caption; - } - - /** - * Returns the action's icon. - * - * @return the action's Icon. - */ - public Resource getIcon() { - return icon; - } - - /** - * An Action that implements this interface can be added to an - * Action.Notifier (or NotifierProxy) via the <code>addAction()</code> - * -method, which in many cases is easier than implementing the - * Action.Handler interface.<br/> - * - */ - public interface Listener extends Serializable { - public void handleAction(Object sender, Object target); - } - - /** - * Action.Containers implementing this support an easier way of adding - * single Actions than the more involved Action.Handler. The added actions - * must be Action.Listeners, thus handling the action themselves. - * - */ - public interface Notifier extends Container { - public <T extends Action & Action.Listener> void addAction(T action); - - public <T extends Action & Action.Listener> void removeAction(T action); - } - - public interface ShortcutNotifier extends Serializable { - public void addShortcutListener(ShortcutListener shortcut); - - public void removeShortcutListener(ShortcutListener shortcut); - } - - /** - * Interface implemented by classes who wish to handle actions. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface Handler extends Serializable { - - /** - * Gets the list of actions applicable to this handler. - * - * @param target - * the target handler to list actions for. For item - * containers this is the item id. - * @param sender - * the party that would be sending the actions. Most of this - * is the action container. - * @return the list of Action - */ - public Action[] getActions(Object target, Object sender); - - /** - * Handles an action for the given target. The handler method may just - * discard the action if it's not suitable. - * - * @param action - * the action to be handled. - * @param sender - * the sender of the action. This is most often the action - * container. - * @param target - * the target of the action. For item containers this is the - * item id. - */ - public void handleAction(Action action, Object sender, Object target); - } - - /** - * Interface implemented by all components where actions can be registered. - * This means that the components lets others to register as action handlers - * to it. When the component receives an action targeting its contents it - * should loop all action handlers registered to it and let them handle the - * action. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface Container extends Serializable { - - /** - * Registers a new action handler for this container - * - * @param actionHandler - * the new handler to be added. - */ - public void addActionHandler(Action.Handler actionHandler); - - /** - * Removes a previously registered action handler for the contents of - * this container. - * - * @param actionHandler - * the handler to be removed. - */ - public void removeActionHandler(Action.Handler actionHandler); - } - - /** - * Sets the caption. - * - * @param caption - * the caption to set. - */ - public void setCaption(String caption) { - this.caption = caption; - } - - /** - * Sets the icon. - * - * @param icon - * the icon to set. - */ - public void setIcon(Resource icon) { - this.icon = icon; - } - -} diff --git a/src/com/vaadin/event/ActionManager.java b/src/com/vaadin/event/ActionManager.java deleted file mode 100644 index 64fdeea69b..0000000000 --- a/src/com/vaadin/event/ActionManager.java +++ /dev/null @@ -1,249 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import java.util.HashSet; -import java.util.Map; - -import com.vaadin.event.Action.Container; -import com.vaadin.event.Action.Handler; -import com.vaadin.terminal.KeyMapper; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.ui.Component; - -/** - * Javadoc TODO - * - * Notes: - * <p> - * Empties the keymapper for each repaint to avoid leaks; can cause problems in - * the future if the client assumes key don't change. (if lazyloading, one must - * not cache results) - * </p> - * - * - */ -public class ActionManager implements Action.Container, Action.Handler, - Action.Notifier { - - private static final long serialVersionUID = 1641868163608066491L; - - /** List of action handlers */ - protected HashSet<Action> ownActions = null; - - /** List of action handlers */ - protected HashSet<Handler> actionHandlers = null; - - /** Action mapper */ - protected KeyMapper<Action> actionMapper = null; - - protected Component viewer; - - private boolean clientHasActions = false; - - public ActionManager() { - - } - - public <T extends Component & Container & VariableOwner> ActionManager( - T viewer) { - this.viewer = viewer; - } - - private void requestRepaint() { - if (viewer != null) { - viewer.requestRepaint(); - } - } - - public <T extends Component & Container & VariableOwner> void setViewer( - T viewer) { - if (viewer == this.viewer) { - return; - } - if (this.viewer != null) { - ((Container) this.viewer).removeActionHandler(this); - } - requestRepaint(); // this goes to the old viewer - if (viewer != null) { - viewer.addActionHandler(this); - } - this.viewer = viewer; - requestRepaint(); // this goes to the new viewer - } - - @Override - public <T extends Action & Action.Listener> void addAction(T action) { - if (ownActions == null) { - ownActions = new HashSet<Action>(); - } - if (ownActions.add(action)) { - requestRepaint(); - } - } - - @Override - public <T extends Action & Action.Listener> void removeAction(T action) { - if (ownActions != null) { - if (ownActions.remove(action)) { - requestRepaint(); - } - } - } - - @Override - public void addActionHandler(Handler actionHandler) { - if (actionHandler == this) { - // don't add the actionHandler to itself - return; - } - if (actionHandler != null) { - - if (actionHandlers == null) { - actionHandlers = new HashSet<Handler>(); - } - - if (actionHandlers.add(actionHandler)) { - requestRepaint(); - } - } - } - - @Override - public void removeActionHandler(Action.Handler actionHandler) { - if (actionHandlers != null && actionHandlers.contains(actionHandler)) { - - if (actionHandlers.remove(actionHandler)) { - requestRepaint(); - } - if (actionHandlers.isEmpty()) { - actionHandlers = null; - } - - } - } - - public void removeAllActionHandlers() { - if (actionHandlers != null) { - actionHandlers = null; - requestRepaint(); - } - } - - public void paintActions(Object actionTarget, PaintTarget paintTarget) - throws PaintException { - - actionMapper = null; - - HashSet<Action> actions = new HashSet<Action>(); - if (actionHandlers != null) { - for (Action.Handler handler : actionHandlers) { - Action[] as = handler.getActions(actionTarget, viewer); - if (as != null) { - for (Action action : as) { - actions.add(action); - } - } - } - } - if (ownActions != null) { - actions.addAll(ownActions); - } - - /* - * Must repaint whenever there are actions OR if all actions have been - * removed but still exist on client side - */ - if (!actions.isEmpty() || clientHasActions) { - actionMapper = new KeyMapper<Action>(); - - paintTarget.addVariable((VariableOwner) viewer, "action", ""); - paintTarget.startTag("actions"); - - for (final Action a : actions) { - paintTarget.startTag("action"); - final String akey = actionMapper.key(a); - paintTarget.addAttribute("key", akey); - if (a.getCaption() != null) { - paintTarget.addAttribute("caption", a.getCaption()); - } - if (a.getIcon() != null) { - paintTarget.addAttribute("icon", a.getIcon()); - } - if (a instanceof ShortcutAction) { - final ShortcutAction sa = (ShortcutAction) a; - paintTarget.addAttribute("kc", sa.getKeyCode()); - final int[] modifiers = sa.getModifiers(); - if (modifiers != null) { - final String[] smodifiers = new String[modifiers.length]; - for (int i = 0; i < modifiers.length; i++) { - smodifiers[i] = String.valueOf(modifiers[i]); - } - paintTarget.addAttribute("mk", smodifiers); - } - } - paintTarget.endTag("action"); - } - - paintTarget.endTag("actions"); - } - - /* - * Update flag for next repaint so we know if we need to paint empty - * actions or not (must send actions is client had actions before and - * all actions were removed). - */ - clientHasActions = !actions.isEmpty(); - } - - public void handleActions(Map<String, Object> variables, Container sender) { - if (variables.containsKey("action") && actionMapper != null) { - final String key = (String) variables.get("action"); - final Action action = actionMapper.get(key); - final Object target = variables.get("actiontarget"); - if (action != null) { - handleAction(action, sender, target); - } - } - } - - @Override - public Action[] getActions(Object target, Object sender) { - HashSet<Action> actions = new HashSet<Action>(); - if (ownActions != null) { - for (Action a : ownActions) { - actions.add(a); - } - } - if (actionHandlers != null) { - for (Action.Handler h : actionHandlers) { - Action[] as = h.getActions(target, sender); - if (as != null) { - for (Action a : as) { - actions.add(a); - } - } - } - } - return actions.toArray(new Action[actions.size()]); - } - - @Override - public void handleAction(Action action, Object sender, Object target) { - if (actionHandlers != null) { - Handler[] array = actionHandlers.toArray(new Handler[actionHandlers - .size()]); - for (Handler handler : array) { - handler.handleAction(action, sender, target); - } - } - if (ownActions != null && ownActions.contains(action) - && action instanceof Action.Listener) { - ((Action.Listener) action).handleAction(sender, target); - } - } - -} diff --git a/src/com/vaadin/event/ComponentEventListener.java b/src/com/vaadin/event/ComponentEventListener.java deleted file mode 100644 index 21fe8683f6..0000000000 --- a/src/com/vaadin/event/ComponentEventListener.java +++ /dev/null @@ -1,11 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import java.io.Serializable; -import java.util.EventListener; - -public interface ComponentEventListener extends EventListener, Serializable { - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/DataBoundTransferable.java b/src/com/vaadin/event/DataBoundTransferable.java deleted file mode 100644 index 6f742e68d3..0000000000 --- a/src/com/vaadin/event/DataBoundTransferable.java +++ /dev/null @@ -1,66 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import java.util.Map; - -import com.vaadin.data.Container; -import com.vaadin.ui.Component; - -/** - * Parent class for {@link Transferable} implementations that have a Vaadin - * container as a data source. The transfer is associated with an item - * (identified by its Id) and optionally also a property identifier (e.g. a - * table column identifier when transferring a single table cell). - * - * The component must implement the interface - * {@link com.vaadin.data.Container.Viewer}. - * - * In most cases, receivers of data transfers should depend on this class - * instead of its concrete subclasses. - * - * @since 6.3 - */ -public abstract class DataBoundTransferable extends TransferableImpl { - - public DataBoundTransferable(Component sourceComponent, - Map<String, Object> rawVariables) { - super(sourceComponent, rawVariables); - } - - /** - * Returns the identifier of the item being transferred. - * - * @return item identifier - */ - public abstract Object getItemId(); - - /** - * Returns the optional property identifier that the transfer concerns. - * - * This can be e.g. the table column from which a drag operation originated. - * - * @return property identifier - */ - public abstract Object getPropertyId(); - - /** - * Returns the container data source from which the transfer occurs. - * - * {@link com.vaadin.data.Container.Viewer#getContainerDataSource()} is used - * to obtain the underlying container of the source component. - * - * @return Container - */ - public Container getSourceContainer() { - Component sourceComponent = getSourceComponent(); - if (sourceComponent instanceof Container.Viewer) { - return ((Container.Viewer) sourceComponent) - .getContainerDataSource(); - } else { - // this should not happen - return null; - } - } -} diff --git a/src/com/vaadin/event/EventRouter.java b/src/com/vaadin/event/EventRouter.java deleted file mode 100644 index 90c080b860..0000000000 --- a/src/com/vaadin/event/EventRouter.java +++ /dev/null @@ -1,201 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EventObject; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; - -/** - * <code>EventRouter</code> class implementing the inheritable event listening - * model. For more information on the event model see the - * {@link com.vaadin.event package documentation}. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class EventRouter implements MethodEventSource { - - /** - * List of registered listeners. - */ - private LinkedHashSet<ListenerMethod> listenerList = null; - - /* - * Registers a new listener with the specified activation method to listen - * events generated by this component. Don't add a JavaDoc comment here, we - * use the default documentation from implemented interface. - */ - @Override - public void addListener(Class<?> eventType, Object object, Method method) { - if (listenerList == null) { - listenerList = new LinkedHashSet<ListenerMethod>(); - } - listenerList.add(new ListenerMethod(eventType, object, method)); - } - - /* - * Registers a new listener with the specified named activation method to - * listen events generated by this component. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public void addListener(Class<?> eventType, Object object, String methodName) { - if (listenerList == null) { - listenerList = new LinkedHashSet<ListenerMethod>(); - } - listenerList.add(new ListenerMethod(eventType, object, methodName)); - } - - /* - * Removes all registered listeners matching the given parameters. Don't add - * a JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void removeListener(Class<?> eventType, Object target) { - if (listenerList != null) { - final Iterator<ListenerMethod> i = listenerList.iterator(); - while (i.hasNext()) { - final ListenerMethod lm = i.next(); - if (lm.matches(eventType, target)) { - i.remove(); - return; - } - } - } - } - - /* - * Removes the event listener methods matching the given given paramaters. - * Don't add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public void removeListener(Class<?> eventType, Object target, Method method) { - if (listenerList != null) { - final Iterator<ListenerMethod> i = listenerList.iterator(); - while (i.hasNext()) { - final ListenerMethod lm = i.next(); - if (lm.matches(eventType, target, method)) { - i.remove(); - return; - } - } - } - } - - /* - * Removes the event listener method matching the given given parameters. - * Don't add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public void removeListener(Class<?> eventType, Object target, - String methodName) { - - // Find the correct method - final Method[] methods = target.getClass().getMethods(); - Method method = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals(methodName)) { - method = methods[i]; - } - } - if (method == null) { - throw new IllegalArgumentException(); - } - - // Remove the listeners - if (listenerList != null) { - final Iterator<ListenerMethod> i = listenerList.iterator(); - while (i.hasNext()) { - final ListenerMethod lm = i.next(); - if (lm.matches(eventType, target, method)) { - i.remove(); - return; - } - } - } - - } - - /** - * Removes all listeners from event router. - */ - public void removeAllListeners() { - listenerList = null; - } - - /** - * Sends an event to all registered listeners. The listeners will decide if - * the activation method should be called or not. - * - * @param event - * the Event to be sent to all listeners. - */ - public void fireEvent(EventObject event) { - // It is not necessary to send any events if there are no listeners - if (listenerList != null) { - - // Make a copy of the listener list to allow listeners to be added - // inside listener methods. Fixes #3605. - - // Send the event to all listeners. The listeners themselves - // will filter out unwanted events. - final Object[] listeners = listenerList.toArray(); - for (int i = 0; i < listeners.length; i++) { - ((ListenerMethod) listeners[i]).receiveEvent(event); - } - - } - } - - /** - * Checks if the given Event type is listened by a listener registered to - * this router. - * - * @param eventType - * the event type to be checked - * @return true if a listener is registered for the given event type - */ - public boolean hasListeners(Class<?> eventType) { - if (listenerList != null) { - for (ListenerMethod lm : listenerList) { - if (lm.isType(eventType)) { - return true; - } - } - } - return false; - } - - /** - * Returns all listeners that match or extend the given event type. - * - * @param eventType - * The type of event to return listeners for. - * @return A collection with all registered listeners. Empty if no listeners - * are found. - */ - public Collection<?> getListeners(Class<?> eventType) { - List<Object> listeners = new ArrayList<Object>(); - if (listenerList != null) { - for (ListenerMethod lm : listenerList) { - if (lm.isOrExtendsType(eventType)) { - listeners.add(lm.getTarget()); - } - } - } - return listeners; - } -} diff --git a/src/com/vaadin/event/FieldEvents.java b/src/com/vaadin/event/FieldEvents.java deleted file mode 100644 index 8f101c1913..0000000000 --- a/src/com/vaadin/event/FieldEvents.java +++ /dev/null @@ -1,275 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import com.vaadin.shared.EventId; -import com.vaadin.shared.communication.FieldRpc.FocusAndBlurServerRpc; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.Component; -import com.vaadin.ui.Component.Event; -import com.vaadin.ui.Field; -import com.vaadin.ui.Field.ValueChangeEvent; -import com.vaadin.ui.TextField; - -/** - * Interface that serves as a wrapper for {@link Field} related events. - */ -public interface FieldEvents { - - /** - * The interface for adding and removing <code>FocusEvent</code> listeners. - * By implementing this interface a class explicitly announces that it will - * generate a <code>FocusEvent</code> when it receives keyboard focus. - * <p> - * Note: The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - * - * @since 6.2 - * @see FocusListener - * @see FocusEvent - */ - public interface FocusNotifier extends Serializable { - /** - * Adds a <code>FocusListener</code> to the Component which gets fired - * when a <code>Field</code> receives keyboard focus. - * - * @param listener - * @see FocusListener - * @since 6.2 - */ - public void addListener(FocusListener listener); - - /** - * Removes a <code>FocusListener</code> from the Component. - * - * @param listener - * @see FocusListener - * @since 6.2 - */ - public void removeListener(FocusListener listener); - } - - /** - * The interface for adding and removing <code>BlurEvent</code> listeners. - * By implementing this interface a class explicitly announces that it will - * generate a <code>BlurEvent</code> when it loses keyboard focus. - * <p> - * Note: The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - * - * @since 6.2 - * @see BlurListener - * @see BlurEvent - */ - public interface BlurNotifier extends Serializable { - /** - * Adds a <code>BlurListener</code> to the Component which gets fired - * when a <code>Field</code> loses keyboard focus. - * - * @param listener - * @see BlurListener - * @since 6.2 - */ - public void addListener(BlurListener listener); - - /** - * Removes a <code>BlurListener</code> from the Component. - * - * @param listener - * @see BlurListener - * @since 6.2 - */ - public void removeListener(BlurListener listener); - } - - /** - * <code>FocusEvent</code> class for holding additional event information. - * Fired when a <code>Field</code> receives keyboard focus. - * - * @since 6.2 - */ - @SuppressWarnings("serial") - public class FocusEvent extends Component.Event { - - /** - * Identifier for event that can be used in {@link EventRouter} - */ - public static final String EVENT_ID = EventId.FOCUS; - - public FocusEvent(Component source) { - super(source); - } - } - - /** - * <code>FocusListener</code> interface for listening for - * <code>FocusEvent</code> fired by a <code>Field</code>. - * - * @see FocusEvent - * @since 6.2 - */ - public interface FocusListener extends ComponentEventListener { - - public static final Method focusMethod = ReflectTools.findMethod( - FocusListener.class, "focus", FocusEvent.class); - - /** - * Component has been focused - * - * @param event - * Component focus event. - */ - public void focus(FocusEvent event); - } - - /** - * <code>BlurEvent</code> class for holding additional event information. - * Fired when a <code>Field</code> loses keyboard focus. - * - * @since 6.2 - */ - @SuppressWarnings("serial") - public class BlurEvent extends Component.Event { - - /** - * Identifier for event that can be used in {@link EventRouter} - */ - public static final String EVENT_ID = EventId.BLUR; - - public BlurEvent(Component source) { - super(source); - } - } - - /** - * <code>BlurListener</code> interface for listening for - * <code>BlurEvent</code> fired by a <code>Field</code>. - * - * @see BlurEvent - * @since 6.2 - */ - public interface BlurListener extends ComponentEventListener { - - public static final Method blurMethod = ReflectTools.findMethod( - BlurListener.class, "blur", BlurEvent.class); - - /** - * Component has been blurred - * - * @param event - * Component blur event. - */ - public void blur(BlurEvent event); - } - - /** - * TextChangeEvents are fired when the user is editing the text content of a - * field. Most commonly text change events are triggered by typing text with - * keyboard, but e.g. pasting content from clip board to a text field also - * triggers an event. - * <p> - * TextChangeEvents differ from {@link ValueChangeEvent}s so that they are - * triggered repeatedly while the end user is filling the field. - * ValueChangeEvents are not fired until the user for example hits enter or - * focuses another field. Also note the difference that TextChangeEvents are - * only fired if the change is triggered from the user, while - * ValueChangeEvents are also fired if the field value is set by the - * application code. - * <p> - * The {@link TextChangeNotifier}s implementation may decide when exactly - * TextChangeEvents are fired. TextChangeEvents are not necessary fire for - * example on each key press, but buffered with a small delay. The - * {@link TextField} component supports different modes for triggering - * TextChangeEvents. - * - * @see TextChangeListener - * @see TextChangeNotifier - * @see TextField#setTextChangeEventMode(com.vaadin.ui.TextField.TextChangeEventMode) - * @since 6.5 - */ - public static abstract class TextChangeEvent extends Component.Event { - public TextChangeEvent(Component source) { - super(source); - } - - /** - * @return the text content of the field after the - * {@link TextChangeEvent} - */ - public abstract String getText(); - - /** - * @return the cursor position during after the {@link TextChangeEvent} - */ - public abstract int getCursorPosition(); - } - - /** - * A listener for {@link TextChangeEvent}s. - * - * @since 6.5 - */ - public interface TextChangeListener extends ComponentEventListener { - - public static String EVENT_ID = "ie"; - public static Method EVENT_METHOD = ReflectTools.findMethod( - TextChangeListener.class, "textChange", TextChangeEvent.class); - - /** - * This method is called repeatedly while the text is edited by a user. - * - * @param event - * the event providing details of the text change - */ - public void textChange(TextChangeEvent event); - } - - /** - * An interface implemented by a {@link Field} supporting - * {@link TextChangeEvent}s. An example a {@link TextField} supports - * {@link TextChangeListener}s. - */ - public interface TextChangeNotifier extends Serializable { - public void addListener(TextChangeListener listener); - - public void removeListener(TextChangeListener listener); - } - - public static abstract class FocusAndBlurServerRpcImpl implements - FocusAndBlurServerRpc { - - private Component component; - - public FocusAndBlurServerRpcImpl(Component component) { - this.component = component; - } - - protected abstract void fireEvent(Event event); - - @Override - public void blur() { - fireEvent(new BlurEvent(component)); - } - - @Override - public void focus() { - fireEvent(new FocusEvent(component)); - } - }; - -} diff --git a/src/com/vaadin/event/ItemClickEvent.java b/src/com/vaadin/event/ItemClickEvent.java deleted file mode 100644 index 0aa0e106c5..0000000000 --- a/src/com/vaadin/event/ItemClickEvent.java +++ /dev/null @@ -1,121 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.ui.Component; - -/** - * - * Click event fired by a {@link Component} implementing - * {@link com.vaadin.data.Container} interface. ItemClickEvents happens on an - * {@link Item} rendered somehow on terminal. Event may also contain a specific - * {@link Property} on which the click event happened. - * - * @since 5.3 - * - */ -@SuppressWarnings("serial") -public class ItemClickEvent extends ClickEvent implements Serializable { - private Item item; - private Object itemId; - private Object propertyId; - - public ItemClickEvent(Component source, Item item, Object itemId, - Object propertyId, MouseEventDetails details) { - super(source, details); - this.item = item; - this.itemId = itemId; - this.propertyId = propertyId; - } - - /** - * Gets the item on which the click event occurred. - * - * @return item which was clicked - */ - public Item getItem() { - return item; - } - - /** - * Gets a possible identifier in source for clicked Item - * - * @return - */ - public Object getItemId() { - return itemId; - } - - /** - * Returns property on which click event occurred. Returns null if source - * cannot be resolved at property leve. For example if clicked a cell in - * table, the "column id" is returned. - * - * @return a property id of clicked property or null if click didn't occur - * on any distinct property. - */ - public Object getPropertyId() { - return propertyId; - } - - public static final Method ITEM_CLICK_METHOD; - - static { - try { - ITEM_CLICK_METHOD = ItemClickListener.class.getDeclaredMethod( - "itemClick", new Class[] { ItemClickEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException(); - } - } - - public interface ItemClickListener extends Serializable { - public void itemClick(ItemClickEvent event); - } - - /** - * The interface for adding and removing <code>ItemClickEvent</code> - * listeners. By implementing this interface a class explicitly announces - * that it will generate an <code>ItemClickEvent</code> when one of its - * items is clicked. - * <p> - * Note: The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - * - * @since 6.5 - * @see ItemClickListener - * @see ItemClickEvent - */ - public interface ItemClickNotifier extends Serializable { - /** - * Register a listener to handle {@link ItemClickEvent}s. - * - * @param listener - * ItemClickListener to be registered - */ - public void addListener(ItemClickListener listener); - - /** - * Removes an ItemClickListener. - * - * @param listener - * ItemClickListener to be removed - */ - public void removeListener(ItemClickListener listener); - } - -} diff --git a/src/com/vaadin/event/LayoutEvents.java b/src/com/vaadin/event/LayoutEvents.java deleted file mode 100644 index 602440ea07..0000000000 --- a/src/com/vaadin/event/LayoutEvents.java +++ /dev/null @@ -1,138 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.shared.Connector; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.Component; -import com.vaadin.ui.ComponentContainer; - -public interface LayoutEvents { - - public interface LayoutClickListener extends ComponentEventListener { - - public static final Method clickMethod = ReflectTools.findMethod( - LayoutClickListener.class, "layoutClick", - LayoutClickEvent.class); - - /** - * Layout has been clicked - * - * @param event - * Component click event. - */ - public void layoutClick(LayoutClickEvent event); - } - - /** - * The interface for adding and removing <code>LayoutClickEvent</code> - * listeners. By implementing this interface a class explicitly announces - * that it will generate a <code>LayoutClickEvent</code> when a component - * inside it is clicked and a <code>LayoutClickListener</code> is - * registered. - * <p> - * Note: The general Java convention is not to explicitly declare that a - * class generates events, but to directly define the - * <code>addListener</code> and <code>removeListener</code> methods. That - * way the caller of these methods has no real way of finding out if the - * class really will send the events, or if it just defines the methods to - * be able to implement an interface. - * </p> - * - * @since 6.5.2 - * @see LayoutClickListener - * @see LayoutClickEvent - */ - public interface LayoutClickNotifier extends Serializable { - /** - * Add a click listener to the layout. The listener is called whenever - * the user clicks inside the layout. An event is also triggered when - * the click targets a component inside a nested layout or Panel, - * provided the targeted component does not prevent the click event from - * propagating. A caption is not considered part of a component. - * - * The child component that was clicked is included in the - * {@link LayoutClickEvent}. - * - * Use {@link #removeListener(LayoutClickListener)} to remove the - * listener. - * - * @param listener - * The listener to add - */ - public void addListener(LayoutClickListener listener); - - /** - * Removes an LayoutClickListener. - * - * @param listener - * LayoutClickListener to be removed - */ - public void removeListener(LayoutClickListener listener); - } - - /** - * An event fired when the layout has been clicked. The event contains - * information about the target layout (component) and the child component - * that was clicked. If no child component was found it is set to null. - */ - public static class LayoutClickEvent extends ClickEvent { - - private final Component clickedComponent; - private final Component childComponent; - - public LayoutClickEvent(Component source, - MouseEventDetails mouseEventDetails, - Component clickedComponent, Component childComponent) { - super(source, mouseEventDetails); - this.clickedComponent = clickedComponent; - this.childComponent = childComponent; - } - - /** - * Returns the component that was clicked, which is somewhere inside the - * parent layout on which the listener was registered. - * - * For the direct child component of the layout, see - * {@link #getChildComponent()}. - * - * @return clicked {@link Component}, null if none found - */ - public Component getClickedComponent() { - return clickedComponent; - } - - /** - * Returns the direct child component of the layout which contains the - * clicked component. - * - * For the clicked component inside that child component of the layout, - * see {@link #getClickedComponent()}. - * - * @return direct child {@link Component} of the layout which contains - * the clicked Component, null if none found - */ - public Component getChildComponent() { - return childComponent; - } - - public static LayoutClickEvent createEvent(ComponentContainer layout, - MouseEventDetails mouseDetails, Connector clickedConnector) { - Component clickedComponent = (Component) clickedConnector; - Component childComponent = clickedComponent; - while (childComponent != null - && childComponent.getParent() != layout) { - childComponent = childComponent.getParent(); - } - - return new LayoutClickEvent(layout, mouseDetails, clickedComponent, - childComponent); - } - } -}
\ No newline at end of file diff --git a/src/com/vaadin/event/ListenerMethod.java b/src/com/vaadin/event/ListenerMethod.java deleted file mode 100644 index f7dc8a7f13..0000000000 --- a/src/com/vaadin/event/ListenerMethod.java +++ /dev/null @@ -1,663 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.EventListener; -import java.util.EventObject; -import java.util.logging.Level; -import java.util.logging.Logger; - -/** - * <p> - * One registered event listener. This class contains the listener object - * reference, listened event type, the trigger method to call when the event - * fires, and the optional argument list to pass to the method and the index of - * the argument to replace with the event object. - * </p> - * - * <p> - * This Class provides several constructors that allow omission of the optional - * arguments, and giving the listener method directly, or having the constructor - * to reflect it using merely the name of the method. - * </p> - * - * <p> - * It should be pointed out that the method - * {@link #receiveEvent(EventObject event)} is the one that filters out the - * events that do not match with the given event type and thus do not result in - * calling of the trigger method. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ListenerMethod implements EventListener, Serializable { - - /** - * Type of the event that should trigger this listener. Also the subclasses - * of this class are accepted to trigger the listener. - */ - private final Class<?> eventType; - - /** - * The object containing the trigger method. - */ - private final Object target; - - /** - * The trigger method to call when an event passing the given criteria - * fires. - */ - private transient Method method; - - /** - * Optional argument set to pass to the trigger method. - */ - private Object[] arguments; - - /** - * Optional index to <code>arguments</code> that point out which one should - * be replaced with the triggering event object and thus be passed to the - * trigger method. - */ - private int eventArgumentIndex; - - /* Special serialization to handle method references */ - private void writeObject(java.io.ObjectOutputStream out) throws IOException { - try { - out.defaultWriteObject(); - String name = method.getName(); - Class<?>[] paramTypes = method.getParameterTypes(); - out.writeObject(name); - out.writeObject(paramTypes); - } catch (NotSerializableException e) { - getLogger().warning( - "Error in serialization of the application: Class " - + target.getClass().getName() - + " must implement serialization."); - throw e; - } - - }; - - /* Special serialization to handle method references */ - private void readObject(java.io.ObjectInputStream in) throws IOException, - ClassNotFoundException { - in.defaultReadObject(); - try { - String name = (String) in.readObject(); - Class<?>[] paramTypes = (Class<?>[]) in.readObject(); - // We can not use getMethod directly as we want to support anonymous - // inner classes - method = findHighestMethod(target.getClass(), name, paramTypes); - } catch (SecurityException e) { - getLogger().log(Level.SEVERE, "Internal deserialization error", e); - } - }; - - private static Method findHighestMethod(Class<?> cls, String method, - Class<?>[] paramTypes) { - Class<?>[] ifaces = cls.getInterfaces(); - for (int i = 0; i < ifaces.length; i++) { - Method ifaceMethod = findHighestMethod(ifaces[i], method, - paramTypes); - if (ifaceMethod != null) { - return ifaceMethod; - } - } - if (cls.getSuperclass() != null) { - Method parentMethod = findHighestMethod(cls.getSuperclass(), - method, paramTypes); - if (parentMethod != null) { - return parentMethod; - } - } - Method[] methods = cls.getMethods(); - for (int i = 0; i < methods.length; i++) { - // we ignore parameter types for now - you need to add this - if (methods[i].getName().equals(method)) { - return methods[i]; - } - } - return null; - } - - /** - * <p> - * Constructs a new event listener from a trigger method, it's arguments and - * the argument index specifying which one is replaced with the event object - * when the trigger method is called. - * </p> - * - * <p> - * This constructor gets the trigger method as a parameter so it does not - * need to reflect to find it out. - * </p> - * - * @param eventType - * the event type that is listener listens to. All events of this - * kind (or its subclasses) result in calling the trigger method. - * @param target - * the object instance that contains the trigger method - * @param method - * the trigger method - * @param arguments - * the arguments to be passed to the trigger method - * @param eventArgumentIndex - * An index to the argument list. This index points out the - * argument that is replaced with the event object before the - * argument set is passed to the trigger method. If the - * eventArgumentIndex is negative, the triggering event object - * will not be passed to the trigger method, though it is still - * called. - * @throws java.lang.IllegalArgumentException - * if <code>method</code> is not a member of <code>target</code> - * . - */ - public ListenerMethod(Class<?> eventType, Object target, Method method, - Object[] arguments, int eventArgumentIndex) - throws java.lang.IllegalArgumentException { - - // Checks that the object is of correct type - if (!method.getDeclaringClass().isAssignableFrom(target.getClass())) { - throw new java.lang.IllegalArgumentException("The method " - + method.getName() - + " cannot be used for the given target: " - + target.getClass().getName()); - } - - // Checks that the event argument is null - if (eventArgumentIndex >= 0 && arguments[eventArgumentIndex] != null) { - throw new java.lang.IllegalArgumentException("argument[" - + eventArgumentIndex + "] must be null"); - } - - // Checks the event type is supported by the method - if (eventArgumentIndex >= 0 - && !method.getParameterTypes()[eventArgumentIndex] - .isAssignableFrom(eventType)) { - throw new java.lang.IllegalArgumentException("The method " - + method.getName() - + " does not accept the given eventType: " - + eventType.getName()); - } - - this.eventType = eventType; - this.target = target; - this.method = method; - this.arguments = arguments; - this.eventArgumentIndex = eventArgumentIndex; - } - - /** - * <p> - * Constructs a new event listener from a trigger method name, it's - * arguments and the argument index specifying which one is replaced with - * the event object. The actual trigger method is reflected from - * <code>object</code>, and <code>java.lang.IllegalArgumentException</code> - * is thrown unless exactly one match is found. - * </p> - * - * @param eventType - * the event type that is listener listens to. All events of this - * kind (or its subclasses) result in calling the trigger method. - * @param target - * the object instance that contains the trigger method. - * @param methodName - * the name of the trigger method. If the object does not contain - * the method or it contains more than one matching methods - * <code>java.lang.IllegalArgumentException</code> is thrown. - * @param arguments - * the arguments to be passed to the trigger method. - * @param eventArgumentIndex - * An index to the argument list. This index points out the - * argument that is replaced with the event object before the - * argument set is passed to the trigger method. If the - * eventArgumentIndex is negative, the triggering event object - * will not be passed to the trigger method, though it is still - * called. - * @throws java.lang.IllegalArgumentException - * unless exactly one match <code>methodName</code> is found in - * <code>target</code>. - */ - public ListenerMethod(Class<?> eventType, Object target, String methodName, - Object[] arguments, int eventArgumentIndex) - throws java.lang.IllegalArgumentException { - - // Finds the correct method - final Method[] methods = target.getClass().getMethods(); - Method method = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals(methodName)) { - method = methods[i]; - } - } - if (method == null) { - throw new IllegalArgumentException("Method " + methodName - + " not found in class " + target.getClass().getName()); - } - - // Checks that the event argument is null - if (eventArgumentIndex >= 0 && arguments[eventArgumentIndex] != null) { - throw new java.lang.IllegalArgumentException("argument[" - + eventArgumentIndex + "] must be null"); - } - - // Checks the event type is supported by the method - if (eventArgumentIndex >= 0 - && !method.getParameterTypes()[eventArgumentIndex] - .isAssignableFrom(eventType)) { - throw new java.lang.IllegalArgumentException("The method " - + method.getName() - + " does not accept the given eventType: " - + eventType.getName()); - } - - this.eventType = eventType; - this.target = target; - this.method = method; - this.arguments = arguments; - this.eventArgumentIndex = eventArgumentIndex; - } - - /** - * <p> - * Constructs a new event listener from the trigger method and it's - * arguments. Since the the index to the replaced parameter is not specified - * the event triggering this listener will not be passed to the trigger - * method. - * </p> - * - * <p> - * This constructor gets the trigger method as a parameter so it does not - * need to reflect to find it out. - * </p> - * - * @param eventType - * the event type that is listener listens to. All events of this - * kind (or its subclasses) result in calling the trigger method. - * @param target - * the object instance that contains the trigger method. - * @param method - * the trigger method. - * @param arguments - * the arguments to be passed to the trigger method. - * @throws java.lang.IllegalArgumentException - * if <code>method</code> is not a member of <code>target</code> - * . - */ - public ListenerMethod(Class<?> eventType, Object target, Method method, - Object[] arguments) throws java.lang.IllegalArgumentException { - - // Check that the object is of correct type - if (!method.getDeclaringClass().isAssignableFrom(target.getClass())) { - throw new java.lang.IllegalArgumentException("The method " - + method.getName() - + " cannot be used for the given target: " - + target.getClass().getName()); - } - - this.eventType = eventType; - this.target = target; - this.method = method; - this.arguments = arguments; - eventArgumentIndex = -1; - } - - /** - * <p> - * Constructs a new event listener from a trigger method name and it's - * arguments. Since the the index to the replaced parameter is not specified - * the event triggering this listener will not be passed to the trigger - * method. - * </p> - * - * <p> - * The actual trigger method is reflected from <code>target</code>, and - * <code>java.lang.IllegalArgumentException</code> is thrown unless exactly - * one match is found. - * </p> - * - * @param eventType - * the event type that is listener listens to. All events of this - * kind (or its subclasses) result in calling the trigger method. - * @param target - * the object instance that contains the trigger method. - * @param methodName - * the name of the trigger method. If the object does not contain - * the method or it contains more than one matching methods - * <code>java.lang.IllegalArgumentException</code> is thrown. - * @param arguments - * the arguments to be passed to the trigger method. - * @throws java.lang.IllegalArgumentException - * unless exactly one match <code>methodName</code> is found in - * <code>object</code>. - */ - public ListenerMethod(Class<?> eventType, Object target, String methodName, - Object[] arguments) throws java.lang.IllegalArgumentException { - - // Find the correct method - final Method[] methods = target.getClass().getMethods(); - Method method = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals(methodName)) { - method = methods[i]; - } - } - if (method == null) { - throw new IllegalArgumentException("Method " + methodName - + " not found in class " + target.getClass().getName()); - } - - this.eventType = eventType; - this.target = target; - this.method = method; - this.arguments = arguments; - eventArgumentIndex = -1; - } - - /** - * <p> - * Constructs a new event listener from a trigger method. Since the argument - * list is unspecified no parameters are passed to the trigger method when - * the listener is triggered. - * </p> - * - * <p> - * This constructor gets the trigger method as a parameter so it does not - * need to reflect to find it out. - * </p> - * - * @param eventType - * the event type that is listener listens to. All events of this - * kind (or its subclasses) result in calling the trigger method. - * @param target - * the object instance that contains the trigger method. - * @param method - * the trigger method. - * @throws java.lang.IllegalArgumentException - * if <code>method</code> is not a member of <code>object</code> - * . - */ - public ListenerMethod(Class<?> eventType, Object target, Method method) - throws java.lang.IllegalArgumentException { - - // Checks that the object is of correct type - if (!method.getDeclaringClass().isAssignableFrom(target.getClass())) { - throw new java.lang.IllegalArgumentException("The method " - + method.getName() - + " cannot be used for the given target: " - + target.getClass().getName()); - } - - this.eventType = eventType; - this.target = target; - this.method = method; - eventArgumentIndex = -1; - - final Class<?>[] params = method.getParameterTypes(); - - if (params.length == 0) { - arguments = new Object[0]; - } else if (params.length == 1 && params[0].isAssignableFrom(eventType)) { - arguments = new Object[] { null }; - eventArgumentIndex = 0; - } else { - throw new IllegalArgumentException( - "Method requires unknown parameters"); - } - } - - /** - * <p> - * Constructs a new event listener from a trigger method name. Since the - * argument list is unspecified no parameters are passed to the trigger - * method when the listener is triggered. - * </p> - * - * <p> - * The actual trigger method is reflected from <code>object</code>, and - * <code>java.lang.IllegalArgumentException</code> is thrown unless exactly - * one match is found. - * </p> - * - * @param eventType - * the event type that is listener listens to. All events of this - * kind (or its subclasses) result in calling the trigger method. - * @param target - * the object instance that contains the trigger method. - * @param methodName - * the name of the trigger method. If the object does not contain - * the method or it contains more than one matching methods - * <code>java.lang.IllegalArgumentException</code> is thrown. - * @throws java.lang.IllegalArgumentException - * unless exactly one match <code>methodName</code> is found in - * <code>target</code>. - */ - public ListenerMethod(Class<?> eventType, Object target, String methodName) - throws java.lang.IllegalArgumentException { - - // Finds the correct method - final Method[] methods = target.getClass().getMethods(); - Method method = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals(methodName)) { - method = methods[i]; - } - } - if (method == null) { - throw new IllegalArgumentException("Method " + methodName - + " not found in class " + target.getClass().getName()); - } - - this.eventType = eventType; - this.target = target; - this.method = method; - eventArgumentIndex = -1; - - final Class<?>[] params = method.getParameterTypes(); - - if (params.length == 0) { - arguments = new Object[0]; - } else if (params.length == 1 && params[0].isAssignableFrom(eventType)) { - arguments = new Object[] { null }; - eventArgumentIndex = 0; - } else { - throw new IllegalArgumentException( - "Method requires unknown parameters"); - } - } - - /** - * Receives one event from the <code>EventRouter</code> and calls the - * trigger method if it matches with the criteria defined for the listener. - * Only the events of the same or subclass of the specified event class - * result in the trigger method to be called. - * - * @param event - * the fired event. Unless the trigger method's argument list and - * the index to the to be replaced argument is specified, this - * event will not be passed to the trigger method. - */ - public void receiveEvent(EventObject event) { - // Only send events supported by the method - if (eventType.isAssignableFrom(event.getClass())) { - try { - if (eventArgumentIndex >= 0) { - if (eventArgumentIndex == 0 && arguments.length == 1) { - method.invoke(target, new Object[] { event }); - } else { - final Object[] arg = new Object[arguments.length]; - for (int i = 0; i < arg.length; i++) { - arg[i] = arguments[i]; - } - arg[eventArgumentIndex] = event; - method.invoke(target, arg); - } - } else { - method.invoke(target, arguments); - } - - } catch (final java.lang.IllegalAccessException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error - please report", e); - } catch (final java.lang.reflect.InvocationTargetException e) { - // An exception was thrown by the invocation target. Throw it - // forwards. - throw new MethodException("Invocation of method " - + method.getName() + " in " - + target.getClass().getName() + " failed.", - e.getTargetException()); - } - } - } - - /** - * Checks if the given object and event match with the ones stored in this - * listener. - * - * @param target - * the object to be matched against the object stored by this - * listener. - * @param eventType - * the type to be tested for equality against the type stored by - * this listener. - * @return <code>true</code> if <code>target</code> is the same object as - * the one stored in this object and <code>eventType</code> equals - * the event type stored in this object. * - */ - public boolean matches(Class<?> eventType, Object target) { - return (this.target == target) && (eventType.equals(this.eventType)); - } - - /** - * Checks if the given object, event and method match with the ones stored - * in this listener. - * - * @param target - * the object to be matched against the object stored by this - * listener. - * @param eventType - * the type to be tested for equality against the type stored by - * this listener. - * @param method - * the method to be tested for equality against the method stored - * by this listener. - * @return <code>true</code> if <code>target</code> is the same object as - * the one stored in this object, <code>eventType</code> equals with - * the event type stored in this object and <code>method</code> - * equals with the method stored in this object - */ - public boolean matches(Class<?> eventType, Object target, Method method) { - return (this.target == target) - && (eventType.equals(this.eventType) && method - .equals(this.method)); - } - - @Override - public int hashCode() { - int hash = 7; - - hash = 31 * hash + eventArgumentIndex; - hash = 31 * hash + (eventType == null ? 0 : eventType.hashCode()); - hash = 31 * hash + (target == null ? 0 : target.hashCode()); - hash = 31 * hash + (method == null ? 0 : method.hashCode()); - - return hash; - } - - @Override - public boolean equals(Object obj) { - - if (this == obj) { - return true; - } - - // return false if obj is a subclass (do not use instanceof check) - if ((obj == null) || (obj.getClass() != getClass())) { - return false; - } - - // obj is of same class, test it further - ListenerMethod t = (ListenerMethod) obj; - - return eventArgumentIndex == t.eventArgumentIndex - && (eventType == t.eventType || (eventType != null && eventType - .equals(t.eventType))) - && (target == t.target || (target != null && target - .equals(t.target))) - && (method == t.method || (method != null && method - .equals(t.method))) - && (arguments == t.arguments || (Arrays.equals(arguments, - t.arguments))); - } - - /** - * Exception that wraps an exception thrown by an invoked method. When - * <code>ListenerMethod</code> invokes the target method, it may throw - * arbitrary exception. The original exception is wrapped into - * MethodException instance and rethrown by the <code>ListenerMethod</code>. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class MethodException extends RuntimeException implements - Serializable { - - private MethodException(String message, Throwable cause) { - super(message, cause); - } - - } - - /** - * Compares the type of this ListenerMethod to the given type - * - * @param eventType - * The type to compare with - * @return true if this type of this ListenerMethod matches the given type, - * false otherwise - */ - public boolean isType(Class<?> eventType) { - return this.eventType == eventType; - } - - /** - * Compares the type of this ListenerMethod to the given type - * - * @param eventType - * The type to compare with - * @return true if this event type can be assigned to the given type, false - * otherwise - */ - public boolean isOrExtendsType(Class<?> eventType) { - return eventType.isAssignableFrom(this.eventType); - } - - /** - * Returns the target object which contains the trigger method. - * - * @return The target object - */ - public Object getTarget() { - return target; - } - - private static final Logger getLogger() { - return Logger.getLogger(ListenerMethod.class.getName()); - } - -} diff --git a/src/com/vaadin/event/MethodEventSource.java b/src/com/vaadin/event/MethodEventSource.java deleted file mode 100644 index fb2e7b029b..0000000000 --- a/src/com/vaadin/event/MethodEventSource.java +++ /dev/null @@ -1,157 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.io.Serializable; -import java.lang.reflect.Method; - -/** - * <p> - * Interface for classes supporting registration of methods as event receivers. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface MethodEventSource extends Serializable { - - /** - * <p> - * Registers a new event listener with the specified activation method to - * listen events generated by this component. If the activation method does - * not have any arguments the event object will not be passed to it when - * it's called. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the type of the listened event. Events of this type or its - * subclasses activate the listener. - * @param object - * the object instance who owns the activation method. - * @param method - * the activation method. - * @throws java.lang.IllegalArgumentException - * unless <code>method</code> has exactly one match in - * <code>object</code> - */ - public void addListener(Class<?> eventType, Object object, Method method); - - /** - * <p> - * Registers a new listener with the specified activation method to listen - * events generated by this component. If the activation method does not - * have any arguments the event object will not be passed to it when it's - * called. - * </p> - * - * <p> - * This version of <code>addListener</code> gets the name of the activation - * method as a parameter. The actual method is reflected from - * <code>object</code>, and unless exactly one match is found, - * <code>java.lang.IllegalArgumentException</code> is thrown. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the type of the listened event. Events of this type or its - * subclasses activate the listener. - * @param object - * the object instance who owns the activation method. - * @param methodName - * the name of the activation method. - * @throws java.lang.IllegalArgumentException - * unless <code>method</code> has exactly one match in - * <code>object</code> - */ - public void addListener(Class<?> eventType, Object object, String methodName); - - /** - * Removes all registered listeners matching the given parameters. Since - * this method receives the event type and the listener object as - * parameters, it will unregister all <code>object</code>'s methods that are - * registered to listen to events of type <code>eventType</code> generated - * by this component. - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the exact event type the <code>object</code> listens to. - * @param target - * the target object that has registered to listen to events of - * type <code>eventType</code> with one or more methods. - */ - public void removeListener(Class<?> eventType, Object target); - - /** - * Removes one registered listener method. The given method owned by the - * given object will no longer be called when the specified events are - * generated by this component. - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the exact event type the <code>object</code> listens to. - * @param target - * the target object that has registered to listen to events of - * type eventType with one or more methods. - * @param method - * the method owned by the target that's registered to listen to - * events of type eventType. - */ - public void removeListener(Class<?> eventType, Object target, Method method); - - /** - * <p> - * Removes one registered listener method. The given method owned by the - * given object will no longer be called when the specified events are - * generated by this component. - * </p> - * - * <p> - * This version of <code>removeListener</code> gets the name of the - * activation method as a parameter. The actual method is reflected from the - * target, and unless exactly one match is found, - * <code>java.lang.IllegalArgumentException</code> is thrown. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the exact event type the <code>object</code> listens to. - * @param target - * the target object that has registered to listen to events of - * type <code>eventType</code> with one or more methods. - * @param methodName - * the name of the method owned by <code>target</code> that's - * registered to listen to events of type <code>eventType</code>. - */ - public void removeListener(Class<?> eventType, Object target, - String methodName); -} diff --git a/src/com/vaadin/event/MouseEvents.java b/src/com/vaadin/event/MouseEvents.java deleted file mode 100644 index fafd44be89..0000000000 --- a/src/com/vaadin/event/MouseEvents.java +++ /dev/null @@ -1,234 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.lang.reflect.Method; - -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.Component; - -/** - * Interface that serves as a wrapper for mouse related events. - * - * @author Vaadin Ltd. - * @see ClickListener - * @version - * @VERSION@ - * @since 6.2 - */ -public interface MouseEvents { - - /** - * Class for holding information about a mouse click event. A - * {@link ClickEvent} is fired when the user clicks on a - * <code>Component</code>. - * - * The information available for click events are terminal dependent. - * Correct values for all event details cannot be guaranteed. - * - * @author Vaadin Ltd. - * @see ClickListener - * @version - * @VERSION@ - * @since 6.2 - */ - public class ClickEvent extends Component.Event { - public static final int BUTTON_LEFT = MouseEventDetails.BUTTON_LEFT; - public static final int BUTTON_MIDDLE = MouseEventDetails.BUTTON_MIDDLE; - public static final int BUTTON_RIGHT = MouseEventDetails.BUTTON_RIGHT; - - private MouseEventDetails details; - - public ClickEvent(Component source, MouseEventDetails mouseEventDetails) { - super(source); - details = mouseEventDetails; - } - - /** - * Returns an identifier describing which mouse button the user pushed. - * Compare with {@link #BUTTON_LEFT},{@link #BUTTON_MIDDLE}, - * {@link #BUTTON_RIGHT} to find out which butten it is. - * - * @return one of {@link #BUTTON_LEFT}, {@link #BUTTON_MIDDLE}, - * {@link #BUTTON_RIGHT}. - */ - public int getButton() { - return details.getButton(); - } - - /** - * Returns the mouse position (x coordinate) when the click took place. - * The position is relative to the browser client area. - * - * @return The mouse cursor x position - */ - public int getClientX() { - return details.getClientX(); - } - - /** - * Returns the mouse position (y coordinate) when the click took place. - * The position is relative to the browser client area. - * - * @return The mouse cursor y position - */ - public int getClientY() { - return details.getClientY(); - } - - /** - * Returns the relative mouse position (x coordinate) when the click - * took place. The position is relative to the clicked component. - * - * @return The mouse cursor x position relative to the clicked layout - * component or -1 if no x coordinate available - */ - public int getRelativeX() { - return details.getRelativeX(); - } - - /** - * Returns the relative mouse position (y coordinate) when the click - * took place. The position is relative to the clicked component. - * - * @return The mouse cursor y position relative to the clicked layout - * component or -1 if no y coordinate available - */ - public int getRelativeY() { - return details.getRelativeY(); - } - - /** - * Checks if the event is a double click event. - * - * @return true if the event is a double click event, false otherwise - */ - public boolean isDoubleClick() { - return details.isDoubleClick(); - } - - /** - * Checks if the Alt key was down when the mouse event took place. - * - * @return true if Alt was down when the event occured, false otherwise - */ - public boolean isAltKey() { - return details.isAltKey(); - } - - /** - * Checks if the Ctrl key was down when the mouse event took place. - * - * @return true if Ctrl was pressed when the event occured, false - * otherwise - */ - public boolean isCtrlKey() { - return details.isCtrlKey(); - } - - /** - * Checks if the Meta key was down when the mouse event took place. - * - * @return true if Meta was pressed when the event occured, false - * otherwise - */ - public boolean isMetaKey() { - return details.isMetaKey(); - } - - /** - * Checks if the Shift key was down when the mouse event took place. - * - * @return true if Shift was pressed when the event occured, false - * otherwise - */ - public boolean isShiftKey() { - return details.isShiftKey(); - } - - /** - * Returns a human readable string representing which button has been - * pushed. This is meant for debug purposes only and the string returned - * could change. Use {@link #getButton()} to check which button was - * pressed. - * - * @since 6.3 - * @return A string representation of which button was pushed. - */ - public String getButtonName() { - return details.getButtonName(); - } - } - - /** - * Interface for listening for a {@link ClickEvent} fired by a - * {@link Component}. - * - * @see ClickEvent - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.2 - */ - public interface ClickListener extends ComponentEventListener { - - public static final Method clickMethod = ReflectTools.findMethod( - ClickListener.class, "click", ClickEvent.class); - - /** - * Called when a {@link Component} has been clicked. A reference to the - * component is given by {@link ClickEvent#getComponent()}. - * - * @param event - * An event containing information about the click. - */ - public void click(ClickEvent event); - } - - /** - * Class for holding additional event information for DoubleClick events. - * Fired when the user double-clicks on a <code>Component</code>. - * - * @see ClickEvent - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.2 - */ - public class DoubleClickEvent extends Component.Event { - - public DoubleClickEvent(Component source) { - super(source); - } - } - - /** - * Interface for listening for a {@link DoubleClickEvent} fired by a - * {@link Component}. - * - * @see DoubleClickEvent - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.2 - */ - public interface DoubleClickListener extends ComponentEventListener { - - public static final Method doubleClickMethod = ReflectTools.findMethod( - DoubleClickListener.class, "doubleClick", - DoubleClickEvent.class); - - /** - * Called when a {@link Component} has been double clicked. A reference - * to the component is given by {@link DoubleClickEvent#getComponent()}. - * - * @param event - * An event containing information about the double click. - */ - public void doubleClick(DoubleClickEvent event); - } - -} diff --git a/src/com/vaadin/event/ShortcutAction.java b/src/com/vaadin/event/ShortcutAction.java deleted file mode 100644 index c42dd731c8..0000000000 --- a/src/com/vaadin/event/ShortcutAction.java +++ /dev/null @@ -1,373 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.event; - -import java.io.Serializable; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.vaadin.terminal.Resource; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.Panel; -import com.vaadin.ui.Window; - -/** - * Shortcuts are a special type of {@link Action}s used to create keyboard - * shortcuts. - * <p> - * The ShortcutAction is triggered when the user presses a given key in - * combination with the (optional) given modifier keys. - * </p> - * <p> - * ShortcutActions can be global (by attaching to the {@link Window}), or - * attached to different parts of the UI so that a specific shortcut is only - * valid in part of the UI. For instance, one can attach shortcuts to a specific - * {@link Panel} - look for {@link ComponentContainer}s implementing - * {@link Handler Action.Handler} or {@link Notifier Action.Notifier}. - * </p> - * <p> - * ShortcutActions have a caption that may be used to display the shortcut - * visually. This allows the ShortcutAction to be used as a plain Action while - * still reacting to a keyboard shortcut. Note that this functionality is not - * very well supported yet, but it might still be a good idea to give a caption - * to the shortcut. - * </p> - * - * @author Vaadin Ltd. - * @version - * @since 4.0.1 - */ -@SuppressWarnings("serial") -public class ShortcutAction extends Action { - - private final int keyCode; - - private final int[] modifiers; - - /** - * Creates a shortcut that reacts to the given {@link KeyCode} and - * (optionally) {@link ModifierKey}s. <br/> - * The shortcut might be shown in the UI (e.g context menu), in which case - * the caption will be used. - * - * @param caption - * used when displaying the shortcut visually - * @param kc - * KeyCode that the shortcut reacts to - * @param m - * optional modifier keys - */ - public ShortcutAction(String caption, int kc, int[] m) { - super(caption); - keyCode = kc; - modifiers = m; - } - - /** - * Creates a shortcut that reacts to the given {@link KeyCode} and - * (optionally) {@link ModifierKey}s. <br/> - * The shortcut might be shown in the UI (e.g context menu), in which case - * the caption and icon will be used. - * - * @param caption - * used when displaying the shortcut visually - * @param icon - * used when displaying the shortcut visually - * @param kc - * KeyCode that the shortcut reacts to - * @param m - * optional modifier keys - */ - public ShortcutAction(String caption, Resource icon, int kc, int[] m) { - super(caption, icon); - keyCode = kc; - modifiers = m; - } - - /** - * Used in the caption shorthand notation to indicate the ALT modifier. - */ - public static final char SHORTHAND_CHAR_ALT = '&'; - /** - * Used in the caption shorthand notation to indicate the SHIFT modifier. - */ - public static final char SHORTHAND_CHAR_SHIFT = '_'; - /** - * Used in the caption shorthand notation to indicate the CTRL modifier. - */ - public static final char SHORTHAND_CHAR_CTRL = '^'; - - // regex-quote (escape) the characters - private static final String SHORTHAND_ALT = Pattern.quote(Character - .toString(SHORTHAND_CHAR_ALT)); - private static final String SHORTHAND_SHIFT = Pattern.quote(Character - .toString(SHORTHAND_CHAR_SHIFT)); - private static final String SHORTHAND_CTRL = Pattern.quote(Character - .toString(SHORTHAND_CHAR_CTRL)); - // Used for replacing escaped chars, e.g && with & - private static final Pattern SHORTHAND_ESCAPE = Pattern.compile("(" - + SHORTHAND_ALT + "?)" + SHORTHAND_ALT + "|(" + SHORTHAND_SHIFT - + "?)" + SHORTHAND_SHIFT + "|(" + SHORTHAND_CTRL + "?)" - + SHORTHAND_CTRL); - // Used for removing escaped chars, only leaving real shorthands - private static final Pattern SHORTHAND_REMOVE = Pattern.compile("([" - + SHORTHAND_ALT + "|" + SHORTHAND_SHIFT + "|" + SHORTHAND_CTRL - + "])\\1"); - // Mnemonic char, optionally followed by another, and optionally a third - private static final Pattern SHORTHANDS = Pattern.compile("(" - + SHORTHAND_ALT + "|" + SHORTHAND_SHIFT + "|" + SHORTHAND_CTRL - + ")(?!\\1)(?:(" + SHORTHAND_ALT + "|" + SHORTHAND_SHIFT + "|" - + SHORTHAND_CTRL + ")(?!\\1|\\2))?(?:(" + SHORTHAND_ALT + "|" - + SHORTHAND_SHIFT + "|" + SHORTHAND_CTRL + ")(?!\\1|\\2|\\3))?."); - - /** - * Constructs a ShortcutAction using a shorthand notation to encode the - * keycode and modifiers in the caption. - * <p> - * Insert one or more modifier characters before the character to use as - * keycode. E.g <code>"&Save"</code> will make a shortcut responding to - * ALT-S, <code>"E^xit"</code> will respond to CTRL-X.<br/> - * Multiple modifiers can be used, e.g <code>"&^Delete"</code> will respond - * to CTRL-ALT-D (the order of the modifier characters is not important). - * </p> - * <p> - * The modifier characters will be removed from the caption. The modifier - * character is be escaped by itself: two consecutive characters are turned - * into the original character w/o the special meaning. E.g - * <code>"Save&&&close"</code> will respond to ALT-C, and the caption will - * say "Save&close". - * </p> - * - * @param shorthandCaption - * the caption in modifier shorthand - */ - public ShortcutAction(String shorthandCaption) { - this(shorthandCaption, null); - } - - /** - * Constructs a ShortcutAction using a shorthand notation to encode the - * keycode a in the caption. - * <p> - * This works the same way as {@link #ShortcutAction(String)}, with the - * exception that the modifiers given override those indicated in the - * caption. I.e use any of the modifier characters in the caption to - * indicate the keycode, but the modifier will be the given set.<br/> - * E.g - * <code>new ShortcutAction("Do &stuff", new int[]{ShortcutAction.ModifierKey.CTRL}));</code> - * will respond to CTRL-S. - * </p> - * - * @param shorthandCaption - * @param modifierKeys - */ - public ShortcutAction(String shorthandCaption, int[] modifierKeys) { - // && -> & etc - super(SHORTHAND_ESCAPE.matcher(shorthandCaption).replaceAll("$1$2$3")); - // replace escaped chars with something that won't accidentally match - shorthandCaption = SHORTHAND_REMOVE.matcher(shorthandCaption) - .replaceAll("\u001A"); - Matcher matcher = SHORTHANDS.matcher(shorthandCaption); - if (matcher.find()) { - String match = matcher.group(); - - // KeyCode from last char in match, uppercase - keyCode = Character.toUpperCase(matcher.group().charAt( - match.length() - 1)); - - // Given modifiers override this indicated in the caption - if (modifierKeys != null) { - modifiers = modifierKeys; - } else { - // Read modifiers from caption - int[] mod = new int[match.length() - 1]; - for (int i = 0; i < mod.length; i++) { - int kc = match.charAt(i); - switch (kc) { - case SHORTHAND_CHAR_ALT: - mod[i] = ModifierKey.ALT; - break; - case SHORTHAND_CHAR_CTRL: - mod[i] = ModifierKey.CTRL; - break; - case SHORTHAND_CHAR_SHIFT: - mod[i] = ModifierKey.SHIFT; - break; - } - } - modifiers = mod; - } - - } else { - keyCode = -1; - modifiers = modifierKeys; - } - } - - /** - * Get the {@link KeyCode} that this shortcut reacts to (in combination with - * the {@link ModifierKey}s). - * - * @return keycode for this shortcut - */ - public int getKeyCode() { - return keyCode; - } - - /** - * Get the {@link ModifierKey}s required for the shortcut to react. - * - * @return modifier keys for this shortcut - */ - public int[] getModifiers() { - return modifiers; - } - - /** - * Key codes that can be used for shortcuts - * - */ - public interface KeyCode extends Serializable { - public static final int ENTER = 13; - - public static final int ESCAPE = 27; - - public static final int PAGE_UP = 33; - - public static final int PAGE_DOWN = 34; - - public static final int TAB = 9; - - public static final int ARROW_LEFT = 37; - - public static final int ARROW_UP = 38; - - public static final int ARROW_RIGHT = 39; - - public static final int ARROW_DOWN = 40; - - public static final int BACKSPACE = 8; - - public static final int DELETE = 46; - - public static final int INSERT = 45; - - public static final int END = 35; - - public static final int HOME = 36; - - public static final int F1 = 112; - - public static final int F2 = 113; - - public static final int F3 = 114; - - public static final int F4 = 115; - - public static final int F5 = 116; - - public static final int F6 = 117; - - public static final int F7 = 118; - - public static final int F8 = 119; - - public static final int F9 = 120; - - public static final int F10 = 121; - - public static final int F11 = 122; - - public static final int F12 = 123; - - public static final int A = 65; - - public static final int B = 66; - - public static final int C = 67; - - public static final int D = 68; - - public static final int E = 69; - - public static final int F = 70; - - public static final int G = 71; - - public static final int H = 72; - - public static final int I = 73; - - public static final int J = 74; - - public static final int K = 75; - - public static final int L = 76; - - public static final int M = 77; - - public static final int N = 78; - - public static final int O = 79; - - public static final int P = 80; - - public static final int Q = 81; - - public static final int R = 82; - - public static final int S = 83; - - public static final int T = 84; - - public static final int U = 85; - - public static final int V = 86; - - public static final int W = 87; - - public static final int X = 88; - - public static final int Y = 89; - - public static final int Z = 90; - - public static final int NUM0 = 48; - - public static final int NUM1 = 49; - - public static final int NUM2 = 50; - - public static final int NUM3 = 51; - - public static final int NUM4 = 52; - - public static final int NUM5 = 53; - - public static final int NUM6 = 54; - - public static final int NUM7 = 55; - - public static final int NUM8 = 56; - - public static final int NUM9 = 57; - - public static final int SPACEBAR = 32; - } - - /** - * Modifier key constants - * - */ - public interface ModifierKey extends Serializable { - public static final int SHIFT = 16; - - public static final int CTRL = 17; - - public static final int ALT = 18; - - public static final int META = 91; - } -} diff --git a/src/com/vaadin/event/ShortcutListener.java b/src/com/vaadin/event/ShortcutListener.java deleted file mode 100644 index b760cfabe6..0000000000 --- a/src/com/vaadin/event/ShortcutListener.java +++ /dev/null @@ -1,33 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import com.vaadin.event.Action.Listener; -import com.vaadin.terminal.Resource; - -public abstract class ShortcutListener extends ShortcutAction implements - Listener { - - private static final long serialVersionUID = 1L; - - public ShortcutListener(String caption, int keyCode, int... modifierKeys) { - super(caption, keyCode, modifierKeys); - } - - public ShortcutListener(String shorthandCaption, int... modifierKeys) { - super(shorthandCaption, modifierKeys); - } - - public ShortcutListener(String caption, Resource icon, int keyCode, - int... modifierKeys) { - super(caption, icon, keyCode, modifierKeys); - } - - public ShortcutListener(String shorthandCaption) { - super(shorthandCaption); - } - - @Override - abstract public void handleAction(Object sender, Object target); -} diff --git a/src/com/vaadin/event/Transferable.java b/src/com/vaadin/event/Transferable.java deleted file mode 100644 index 838d8ad7e2..0000000000 --- a/src/com/vaadin/event/Transferable.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import java.io.Serializable; -import java.util.Collection; - -import com.vaadin.ui.Component; - -/** - * Transferable wraps the data that is to be imported into another component. - * Currently Transferable is only used for drag and drop. - * - * @since 6.3 - */ -public interface Transferable extends Serializable { - - /** - * Returns the data from Transferable by its data flavor (aka data type). - * Data types can be any string keys, but MIME types like "text/plain" are - * commonly used. - * <p> - * Note, implementations of {@link Transferable} often provide a better - * typed API for accessing data. - * - * @param dataFlavor - * the data flavor to be returned from Transferable - * @return the data stored in the Transferable or null if Transferable - * contains no data for given data flavour - */ - public Object getData(String dataFlavor); - - /** - * Stores data of given data flavor to Transferable. Possibly existing value - * of the same data flavor will be replaced. - * - * @param dataFlavor - * the data flavor - * @param value - * the new value of the data flavor - */ - public void setData(String dataFlavor, Object value); - - /** - * @return a collection of data flavors ( data types ) available in this - * Transferable - */ - public Collection<String> getDataFlavors(); - - /** - * @return the component that created the Transferable or null if the source - * component is unknown - */ - public Component getSourceComponent(); - -} diff --git a/src/com/vaadin/event/TransferableImpl.java b/src/com/vaadin/event/TransferableImpl.java deleted file mode 100644 index 4c973571f7..0000000000 --- a/src/com/vaadin/event/TransferableImpl.java +++ /dev/null @@ -1,47 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import com.vaadin.ui.Component; - -/** - * TODO Javadoc! - * - * @since 6.3 - */ -public class TransferableImpl implements Transferable { - private Map<String, Object> rawVariables = new HashMap<String, Object>(); - private Component sourceComponent; - - public TransferableImpl(Component sourceComponent, - Map<String, Object> rawVariables) { - this.sourceComponent = sourceComponent; - this.rawVariables = rawVariables; - } - - @Override - public Component getSourceComponent() { - return sourceComponent; - } - - @Override - public Object getData(String dataFlavor) { - return rawVariables.get(dataFlavor); - } - - @Override - public void setData(String dataFlavor, Object value) { - rawVariables.put(dataFlavor, value); - } - - @Override - public Collection<String> getDataFlavors() { - return rawVariables.keySet(); - } - -} diff --git a/src/com/vaadin/event/dd/DragAndDropEvent.java b/src/com/vaadin/event/dd/DragAndDropEvent.java deleted file mode 100644 index b920d43469..0000000000 --- a/src/com/vaadin/event/dd/DragAndDropEvent.java +++ /dev/null @@ -1,50 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd; - -import java.io.Serializable; - -import com.vaadin.event.Transferable; -import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; - -/** - * DragAndDropEvent wraps information related to drag and drop operation. It is - * passed by terminal implementation for - * {@link DropHandler#drop(DragAndDropEvent)} and - * {@link AcceptCriterion#accept(DragAndDropEvent)} methods. - * <p> - * DragAndDropEvent instances contains both the dragged data in - * {@link Transferable} (generated by {@link DragSource} and details about the - * current drop event in {@link TargetDetails} (generated by {@link DropTarget}. - * - * @since 6.3 - * - */ -public class DragAndDropEvent implements Serializable { - private Transferable transferable; - private TargetDetails dropTargetDetails; - - public DragAndDropEvent(Transferable transferable, - TargetDetails dropTargetDetails) { - this.transferable = transferable; - this.dropTargetDetails = dropTargetDetails; - } - - /** - * @return the Transferable instance representing the data dragged in this - * drag and drop event - */ - public Transferable getTransferable() { - return transferable; - } - - /** - * @return the TargetDetails containing drop target related details of drag - * and drop operation - */ - public TargetDetails getTargetDetails() { - return dropTargetDetails; - } - -} diff --git a/src/com/vaadin/event/dd/DragSource.java b/src/com/vaadin/event/dd/DragSource.java deleted file mode 100644 index 4daf0dcb18..0000000000 --- a/src/com/vaadin/event/dd/DragSource.java +++ /dev/null @@ -1,52 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd; - -import java.util.Map; - -import com.vaadin.event.Transferable; -import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; -import com.vaadin.ui.Component; -import com.vaadin.ui.Tree; - -/** - * DragSource is a {@link Component} that builds a {@link Transferable} for a - * drag and drop operation. - * <p> - * In Vaadin the drag and drop operation practically starts from client side - * component. The client side component initially defines the data that will be - * present in {@link Transferable} object on server side. If the server side - * counterpart of the component implements this interface, terminal - * implementation lets it create the {@link Transferable} instance from the raw - * client side "seed data". This way server side implementation may translate or - * extend the data that will be available for {@link DropHandler}. - * - * @since 6.3 - * - */ -public interface DragSource extends Component { - - /** - * DragSource may convert data added by client side component to meaningful - * values for server side developer or add other data based on it. - * - * <p> - * For example Tree converts item identifiers to generated string keys for - * the client side. Vaadin developer don't and can't know anything about - * these generated keys, only about item identifiers. When tree node is - * dragged client puts that key to {@link Transferable}s client side - * counterpart. In {@link Tree#getTransferable(Map)} the key is converted - * back to item identifier that the server side developer can use. - * <p> - * - * @since 6.3 - * @param rawVariables - * the data that client side initially included in - * {@link Transferable}s client side counterpart. - * @return the {@link Transferable} instance that will be passed to - * {@link DropHandler} (and/or {@link AcceptCriterion}) - */ - public Transferable getTransferable(Map<String, Object> rawVariables); - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/DropHandler.java b/src/com/vaadin/event/dd/DropHandler.java deleted file mode 100644 index 7a15ea5b68..0000000000 --- a/src/com/vaadin/event/dd/DropHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd; - -import java.io.Serializable; - -import com.vaadin.event.Transferable; -import com.vaadin.event.dd.acceptcriteria.AcceptAll; -import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; -import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion; - -/** - * DropHandlers contain the actual business logic for drag and drop operations. - * <p> - * The {@link #drop(DragAndDropEvent)} method is used to receive the transferred - * data and the {@link #getAcceptCriterion()} method contains the (possibly - * client side verifiable) criterion whether the dragged data will be handled at - * all. - * - * @since 6.3 - * - */ -public interface DropHandler extends Serializable { - - /** - * Drop method is called when the end user has finished the drag operation - * on a {@link DropTarget} and {@link DragAndDropEvent} has passed - * {@link AcceptCriterion} defined by {@link #getAcceptCriterion()} method. - * The actual business logic of drag and drop operation is implemented into - * this method. - * - * @param event - * the event related to this drop - */ - public void drop(DragAndDropEvent event); - - /** - * Returns the {@link AcceptCriterion} used to evaluate whether the - * {@link Transferable} will be handed over to - * {@link DropHandler#drop(DragAndDropEvent)} method. If client side can't - * verify the {@link AcceptCriterion}, the same criteria may be tested also - * prior to actual drop - during the drag operation. - * <p> - * Based on information from {@link AcceptCriterion} components may display - * some hints for the end user whether the drop will be accepted or not. - * <p> - * Vaadin contains a variety of criteria built in that can be composed to - * more complex criterion. If the build in criteria are not enough, - * developer can use a {@link ServerSideCriterion} or build own custom - * criterion with client side counterpart. - * <p> - * If developer wants to handle everything in the - * {@link #drop(DragAndDropEvent)} method, {@link AcceptAll} instance can be - * returned. - * - * @return the {@link AcceptCriterion} - */ - public AcceptCriterion getAcceptCriterion(); - -} diff --git a/src/com/vaadin/event/dd/DropTarget.java b/src/com/vaadin/event/dd/DropTarget.java deleted file mode 100644 index c18aa60b19..0000000000 --- a/src/com/vaadin/event/dd/DropTarget.java +++ /dev/null @@ -1,42 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd; - -import java.util.Map; - -import com.vaadin.ui.Component; - -/** - * DropTarget is an interface for components supporting drop operations. A - * component that wants to receive drop events should implement this interface - * and provide a {@link DropHandler} which will handle the actual drop event. - * - * @since 6.3 - */ -public interface DropTarget extends Component { - - /** - * @return the drop hanler that will receive the dragged data or null if - * drops are not currently accepted - */ - public DropHandler getDropHandler(); - - /** - * Called before the {@link DragAndDropEvent} is passed to - * {@link DropHandler}. Implementation may for example translate the drop - * target details provided by the client side (drop target) to meaningful - * server side values. If null is returned the terminal implementation will - * automatically create a {@link TargetDetails} with raw client side data. - * - * @see DragSource#getTransferable(Map) - * - * @param clientVariables - * data passed from the DropTargets client side counterpart. - * @return A DropTargetDetails object with the translated data or null to - * use a default implementation. - */ - public TargetDetails translateDropTargetDetails( - Map<String, Object> clientVariables); - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/TargetDetails.java b/src/com/vaadin/event/dd/TargetDetails.java deleted file mode 100644 index a352fbec60..0000000000 --- a/src/com/vaadin/event/dd/TargetDetails.java +++ /dev/null @@ -1,37 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd; - -import java.io.Serializable; - -import com.vaadin.ui.Tree.TreeTargetDetails; - -/** - * TargetDetails wraps drop target related information about - * {@link DragAndDropEvent}. - * <p> - * When a TargetDetails object is used in {@link DropHandler} it is often - * preferable to cast the TargetDetails to an implementation provided by - * DropTarget like {@link TreeTargetDetails}. They often provide a better typed, - * drop target specific API. - * - * @since 6.3 - * - */ -public interface TargetDetails extends Serializable { - - /** - * Gets target data associated with the given string key - * - * @param key - * @return The data associated with the key - */ - public Object getData(String key); - - /** - * @return the drop target on which the {@link DragAndDropEvent} happened. - */ - public DropTarget getTarget(); - -} diff --git a/src/com/vaadin/event/dd/TargetDetailsImpl.java b/src/com/vaadin/event/dd/TargetDetailsImpl.java deleted file mode 100644 index 4a459777ed..0000000000 --- a/src/com/vaadin/event/dd/TargetDetailsImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd; - -import java.util.HashMap; -import java.util.Map; - -/** - * A HashMap backed implementation of {@link TargetDetails} for terminal - * implementation and for extension. - * - * @since 6.3 - * - */ -@SuppressWarnings("serial") -public class TargetDetailsImpl implements TargetDetails { - - private HashMap<String, Object> data = new HashMap<String, Object>(); - private DropTarget dropTarget; - - protected TargetDetailsImpl(Map<String, Object> rawDropData) { - data.putAll(rawDropData); - } - - public TargetDetailsImpl(Map<String, Object> rawDropData, - DropTarget dropTarget) { - this(rawDropData); - this.dropTarget = dropTarget; - } - - @Override - public Object getData(String key) { - return data.get(key); - } - - public Object setData(String key, Object value) { - return data.put(key, value); - } - - @Override - public DropTarget getTarget() { - return dropTarget; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/AcceptAll.java b/src/com/vaadin/event/dd/acceptcriteria/AcceptAll.java deleted file mode 100644 index 1457ea9df3..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/AcceptAll.java +++ /dev/null @@ -1,36 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import com.vaadin.event.dd.DragAndDropEvent; - -/** - * Criterion that accepts all drops anywhere on the component. - * <p> - * Note! Class is singleton, use {@link #get()} method to get the instance. - * - * - * @since 6.3 - * - */ -public final class AcceptAll extends ClientSideCriterion { - - private static final long serialVersionUID = 7406683402153141461L; - private static AcceptCriterion singleton = new AcceptAll(); - - private AcceptAll() { - } - - public static AcceptCriterion get() { - return singleton; - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - return true; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/AcceptCriterion.java b/src/com/vaadin/event/dd/acceptcriteria/AcceptCriterion.java deleted file mode 100644 index c0f04d362f..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/AcceptCriterion.java +++ /dev/null @@ -1,75 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import java.io.Serializable; - -import com.vaadin.event.Transferable; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.DropHandler; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * Criterion that can be used create policy to accept/discard dragged content - * (presented by {@link Transferable}). - * - * The drag and drop mechanism will verify the criteria returned by - * {@link DropHandler#getAcceptCriterion()} before calling - * {@link DropHandler#drop(DragAndDropEvent)}. - * - * The criteria can be evaluated either on the client (browser - see - * {@link ClientSideCriterion}) or on the server (see - * {@link ServerSideCriterion}). If no constraints are needed, an - * {@link AcceptAll} can be used. - * - * In addition to accepting or rejecting a possible drop, criteria can provide - * additional hints for client side painting. - * - * @see DropHandler - * @see ClientSideCriterion - * @see ServerSideCriterion - * - * @since 6.3 - */ -public interface AcceptCriterion extends Serializable { - - /** - * Returns whether the criteria can be checked on the client or whether a - * server request is needed to check the criteria. - * - * This requirement may depend on the state of the criterion (e.g. logical - * operations between criteria), so this cannot be based on a marker - * interface. - */ - public boolean isClientSideVerifiable(); - - public void paint(PaintTarget target) throws PaintException; - - /** - * This needs to be implemented iff criterion does some lazy server side - * initialization. The UIDL painted in this method will be passed to client - * side drop handler implementation. Implementation can assume that - * {@link #accept(DragAndDropEvent)} is called before this method. - * - * @param target - * @throws PaintException - */ - public void paintResponse(PaintTarget target) throws PaintException; - - /** - * Validates the data in event to be appropriate for the - * {@link DropHandler#drop(DragAndDropEvent)} method. - * <p> - * Note that even if your criterion is validated on client side, you should - * always validate the data on server side too. - * - * @param dragEvent - * @return - */ - public boolean accept(DragAndDropEvent dragEvent); -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/And.java b/src/com/vaadin/event/dd/acceptcriteria/And.java deleted file mode 100644 index 4122d67160..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/And.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * A compound criterion that accepts the drag if all of its criteria accepts the - * drag. - * - * @see Or - * - * @since 6.3 - * - */ -public class And extends ClientSideCriterion { - - private static final long serialVersionUID = -5242574480825471748L; - protected ClientSideCriterion[] criteria; - - /** - * - * @param criteria - * criteria of which the And criterion will be composed - */ - public And(ClientSideCriterion... criteria) { - this.criteria = criteria; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - for (ClientSideCriterion crit : criteria) { - crit.paint(target); - } - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - for (ClientSideCriterion crit : criteria) { - if (!crit.accept(dragEvent)) { - return false; - } - } - return true; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/ClientSideCriterion.java b/src/com/vaadin/event/dd/acceptcriteria/ClientSideCriterion.java deleted file mode 100644 index 7d2c42ecb0..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/ClientSideCriterion.java +++ /dev/null @@ -1,61 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd.acceptcriteria; - -import java.io.Serializable; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * Parent class for criteria that can be completely validated on client side. - * All classes that provide criteria that can be completely validated on client - * side should extend this class. - * - * It is recommended that subclasses of ClientSideCriterion re-validate the - * condition on the server side in - * {@link AcceptCriterion#accept(com.vaadin.event.dd.DragAndDropEvent)} after - * the client side validation has accepted a transfer. - * - * @since 6.3 - */ -public abstract class ClientSideCriterion implements Serializable, - AcceptCriterion { - - /* - * All criteria that extend this must be completely validatable on client - * side. - * - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.acceptCriteria.AcceptCriterion#isClientSideVerifiable - * () - */ - @Override - public final boolean isClientSideVerifiable() { - return true; - } - - @Override - public void paint(PaintTarget target) throws PaintException { - target.startTag("-ac"); - target.addAttribute("name", getIdentifier()); - paintContent(target); - target.endTag("-ac"); - } - - protected void paintContent(PaintTarget target) throws PaintException { - } - - protected String getIdentifier() { - return getClass().getCanonicalName(); - } - - @Override - public final void paintResponse(PaintTarget target) throws PaintException { - // NOP, nothing to do as this is client side verified criterion - } - -} diff --git a/src/com/vaadin/event/dd/acceptcriteria/ContainsDataFlavor.java b/src/com/vaadin/event/dd/acceptcriteria/ContainsDataFlavor.java deleted file mode 100644 index 4c52698a4a..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/ContainsDataFlavor.java +++ /dev/null @@ -1,53 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import com.vaadin.event.Transferable; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * A Criterion that checks whether {@link Transferable} contains given data - * flavor. The developer might for example accept the incoming data only if it - * contains "Url" or "Text". - * - * @since 6.3 - */ -public class ContainsDataFlavor extends ClientSideCriterion { - - private String dataFlavorId; - - /** - * Constructs a new instance of {@link ContainsDataFlavor}. - * - * @param dataFlawor - * the type of data that will be checked from - * {@link Transferable} - */ - public ContainsDataFlavor(String dataFlawor) { - dataFlavorId = dataFlawor; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - target.addAttribute("p", dataFlavorId); - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - return dragEvent.getTransferable().getDataFlavors() - .contains(dataFlavorId); - } - - @Override - protected String getIdentifier() { - // extending classes use client side implementation from this class - return ContainsDataFlavor.class.getCanonicalName(); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/Not.java b/src/com/vaadin/event/dd/acceptcriteria/Not.java deleted file mode 100644 index 1ed40a324d..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/Not.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * Criterion that wraps another criterion and inverts its return value. - * - * @since 6.3 - * - */ -public class Not extends ClientSideCriterion { - - private static final long serialVersionUID = 1131422338558613244L; - private AcceptCriterion acceptCriterion; - - public Not(ClientSideCriterion acceptCriterion) { - this.acceptCriterion = acceptCriterion; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - acceptCriterion.paint(target); - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - return !acceptCriterion.accept(dragEvent); - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/Or.java b/src/com/vaadin/event/dd/acceptcriteria/Or.java deleted file mode 100644 index 6ad45c54af..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/Or.java +++ /dev/null @@ -1,52 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * A compound criterion that accepts the drag if any of its criterion accepts - * it. - * - * @see And - * - * @since 6.3 - * - */ -public class Or extends ClientSideCriterion { - private static final long serialVersionUID = 1L; - private AcceptCriterion criteria[]; - - /** - * @param criteria - * the criteria of which the Or criteria will be composed - */ - public Or(ClientSideCriterion... criteria) { - this.criteria = criteria; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - for (AcceptCriterion crit : criteria) { - crit.paint(target); - } - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - for (AcceptCriterion crit : criteria) { - if (crit.accept(dragEvent)) { - return true; - } - } - return false; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/ServerSideCriterion.java b/src/com/vaadin/event/dd/acceptcriteria/ServerSideCriterion.java deleted file mode 100644 index 47f06d434c..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/ServerSideCriterion.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.event.dd.acceptcriteria; - -import java.io.Serializable; - -import com.vaadin.event.Transferable; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * Parent class for criteria which are verified on the server side during a drag - * operation to accept/discard dragged content (presented by - * {@link Transferable}). - * <p> - * Subclasses should implement the - * {@link AcceptCriterion#accept(com.vaadin.event.dd.DragAndDropEvent)} method. - * <p> - * As all server side state can be used to make a decision, this is more - * flexible than {@link ClientSideCriterion}. However, this does require - * additional requests from the browser to the server during a drag operation. - * - * @see AcceptCriterion - * @see ClientSideCriterion - * - * @since 6.3 - */ -public abstract class ServerSideCriterion implements Serializable, - AcceptCriterion { - - private static final long serialVersionUID = 2128510128911628902L; - - @Override - public final boolean isClientSideVerifiable() { - return false; - } - - @Override - public void paint(PaintTarget target) throws PaintException { - target.startTag("-ac"); - target.addAttribute("name", getIdentifier()); - paintContent(target); - target.endTag("-ac"); - } - - public void paintContent(PaintTarget target) { - } - - @Override - public void paintResponse(PaintTarget target) throws PaintException { - } - - protected String getIdentifier() { - return ServerSideCriterion.class.getCanonicalName(); - } -} diff --git a/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java b/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java deleted file mode 100644 index d4fd20c952..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/SourceIs.java +++ /dev/null @@ -1,67 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.event.TransferableImpl; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.ui.Component; - -/** - * Client side criteria that checks if the drag source is one of the given - * components. - * - * @since 6.3 - */ -@SuppressWarnings("serial") -public class SourceIs extends ClientSideCriterion { - - private Component[] components; - - public SourceIs(Component... component) { - components = component; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - int paintedComponents = 0; - for (int i = 0; i < components.length; i++) { - Component c = components[i]; - if (c.getApplication() != null) { - target.addAttribute("component" + paintedComponents++, c); - } else { - Logger.getLogger(SourceIs.class.getName()) - .log(Level.WARNING, - "SourceIs component {0} at index {1} is not attached to the component hierachy and will thus be ignored", - new Object[] { c.getClass().getName(), - Integer.valueOf(i) }); - } - } - target.addAttribute("c", paintedComponents); - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - if (dragEvent.getTransferable() instanceof TransferableImpl) { - Component sourceComponent = ((TransferableImpl) dragEvent - .getTransferable()).getSourceComponent(); - for (Component c : components) { - if (c == sourceComponent) { - return true; - } - } - } - - return false; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/SourceIsTarget.java b/src/com/vaadin/event/dd/acceptcriteria/SourceIsTarget.java deleted file mode 100644 index a644b858e2..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/SourceIsTarget.java +++ /dev/null @@ -1,51 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import com.vaadin.event.Transferable; -import com.vaadin.event.TransferableImpl; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.DropTarget; -import com.vaadin.ui.Component; -import com.vaadin.ui.Table; -import com.vaadin.ui.Tree; - -/** - * - * A criterion that ensures the drag source is the same as drop target. Eg. - * {@link Tree} or {@link Table} could support only re-ordering of items, but no - * {@link Transferable}s coming outside. - * <p> - * Note! Class is singleton, use {@link #get()} method to get the instance. - * - * @since 6.3 - * - */ -public class SourceIsTarget extends ClientSideCriterion { - - private static final long serialVersionUID = -451399314705532584L; - private static SourceIsTarget instance = new SourceIsTarget(); - - private SourceIsTarget() { - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - if (dragEvent.getTransferable() instanceof TransferableImpl) { - Component sourceComponent = ((TransferableImpl) dragEvent - .getTransferable()).getSourceComponent(); - DropTarget target = dragEvent.getTargetDetails().getTarget(); - return sourceComponent == target; - } - return false; - } - - public static synchronized SourceIsTarget get() { - return instance; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/event/dd/acceptcriteria/TargetDetailIs.java b/src/com/vaadin/event/dd/acceptcriteria/TargetDetailIs.java deleted file mode 100644 index 5df8f3f618..0000000000 --- a/src/com/vaadin/event/dd/acceptcriteria/TargetDetailIs.java +++ /dev/null @@ -1,72 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -/** - * - */ -package com.vaadin.event.dd.acceptcriteria; - -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.TargetDetails; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * Criterion for checking if drop target details contains the specific property - * with the specific value. Currently only String values are supported. - * - * @since 6.3 - * - * TODO add support for other basic data types that we support in UIDL. - * - */ -public class TargetDetailIs extends ClientSideCriterion { - - private static final long serialVersionUID = 763165450054331246L; - private String propertyName; - private Object value; - - /** - * Constructs a criterion which ensures that the value there is a value in - * {@link TargetDetails} that equals the reference value. - * - * @param dataFlavor - * the type of data to be checked - * @param value - * the reference value to which the drop target detail will be - * compared - */ - public TargetDetailIs(String dataFlavor, String value) { - propertyName = dataFlavor; - this.value = value; - } - - public TargetDetailIs(String dataFlavor, Boolean true1) { - propertyName = dataFlavor; - value = true1; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - target.addAttribute("p", propertyName); - if (value instanceof Boolean) { - target.addAttribute("v", ((Boolean) value).booleanValue()); - target.addAttribute("t", "b"); - } else if (value instanceof String) { - target.addAttribute("v", (String) value); - } - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - Object data = dragEvent.getTargetDetails().getData(propertyName); - return value.equals(data); - } - - @Override - protected String getIdentifier() { - // sub classes by default use VDropDetailEquals a client implementation - return TargetDetailIs.class.getCanonicalName(); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/event/package.html b/src/com/vaadin/event/package.html deleted file mode 100644 index 2e7e17b892..0000000000 --- a/src/com/vaadin/event/package.html +++ /dev/null @@ -1,58 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -</head> - -<body bgcolor="white"> - -<!-- Package summary here --> - -<p>Provides classes and interfaces for the inheritable event -model. The model supports inheritable events and a flexible way of -registering and unregistering event listeners. It's a fundamental building -block of Vaadin, and as it is included in -{@link com.vaadin.ui.AbstractComponent}, all UI components -automatically support it.</p> - -<h2>Package Specification</h2> - -<p>The core of the event model is the inheritable event class -hierarchy, and the {@link com.vaadin.event.EventRouter EventRouter} -which provide a simple, ubiquitous mechanism to transport events to all -interested parties.</p> - -<p>The power of the event inheritance arises from the possibility of -receiving not only the events of the registered type, <i>but also the -ones which are inherited from it</i>. For example, let's assume that there -are the events <code>GeneralEvent</code> and <code>SpecializedEvent</code> -so that the latter inherits the former. Furthermore we have an object -<code>A</code> which registers to receive <code>GeneralEvent</code> type -events from the object <code>B</code>. <code>A</code> would of course -receive all <code>GeneralEvent</code>s generated by <code>B</code>, but in -addition to this, <code>A</code> would also receive all -<code>SpecializedEvent</code>s generated by <code>B</code>. However, if -<code>B</code> generates some other events that do not have -<code>GeneralEvent</code> as an ancestor, <code>A</code> would not receive -them unless it registers to listen for them, too.</p> - -<p>The interface to attaching and detaching listeners to and from an object -works with methods. One specifies the event that should trigger the listener, -the trigger method that should be called when a suitable event occurs and the -object owning the method. From these a new listener is constructed and added -to the event router of the specified component.</p> - -<p>The interface is defined in -{@link com.vaadin.event.MethodEventSource MethodEventSource}, and a -straightforward implementation of it is defined in -{@link com.vaadin.event.EventRouter EventRouter} which also includes -a method to actually fire the events.</p> - -<p>All fired events are passed to all registered listeners, which are of -type {@link com.vaadin.event.ListenerMethod ListenerMethod}. The -listener then checks if the event type matches with the specified event -type and calls the specified trigger method if it does.</p> - -<!-- Put @see and @since tags down here. --> - -</body> -</html> diff --git a/src/com/vaadin/external/json/JSONArray.java b/src/com/vaadin/external/json/JSONArray.java deleted file mode 100644 index 2307749ffc..0000000000 --- a/src/com/vaadin/external/json/JSONArray.java +++ /dev/null @@ -1,963 +0,0 @@ -package com.vaadin.external.json; - -/* - Copyright (c) 2002 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -import java.io.IOException; -import java.io.Serializable; -import java.io.Writer; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; - -/** - * A JSONArray is an ordered sequence of values. Its external text form is a - * string wrapped in square brackets with commas separating the values. The - * internal form is an object having <code>get</code> and <code>opt</code> - * methods for accessing the values by index, and <code>put</code> methods for - * adding or replacing values. The values can be any of these types: - * <code>Boolean</code>, <code>JSONArray</code>, <code>JSONObject</code>, - * <code>Number</code>, <code>String</code>, or the - * <code>JSONObject.NULL object</code>. - * <p> - * The constructor can convert a JSON text into a Java object. The - * <code>toString</code> method converts to JSON text. - * <p> - * A <code>get</code> method returns a value if one can be found, and throws an - * exception if one cannot be found. An <code>opt</code> method returns a - * default value instead of throwing an exception, and so is useful for - * obtaining optional values. - * <p> - * The generic <code>get()</code> and <code>opt()</code> methods return an - * object which you can cast or query for type. There are also typed - * <code>get</code> and <code>opt</code> methods that do type checking and type - * coercion for you. - * <p> - * The texts produced by the <code>toString</code> methods strictly conform to - * JSON syntax rules. The constructors are more forgiving in the texts they will - * accept: - * <ul> - * <li>An extra <code>,</code> <small>(comma)</small> may appear just - * before the closing bracket.</li> - * <li>The <code>null</code> value will be inserted when there is <code>,</code> - * <small>(comma)</small> elision.</li> - * <li>Strings may be quoted with <code>'</code> <small>(single - * quote)</small>.</li> - * <li>Strings do not need to be quoted at all if they do not begin with a quote - * or single quote, and if they do not contain leading or trailing spaces, and - * if they do not contain any of these characters: - * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and - * if they are not the reserved words <code>true</code>, <code>false</code>, or - * <code>null</code>.</li> - * <li>Values can be separated by <code>;</code> <small>(semicolon)</small> as - * well as by <code>,</code> <small>(comma)</small>.</li> - * <li>Numbers may have the <code>0x-</code> <small>(hex)</small> prefix.</li> - * </ul> - * - * @author JSON.org - * @version 2011-08-25 - */ -public class JSONArray implements Serializable { - - /** - * The arrayList where the JSONArray's properties are kept. - */ - private ArrayList myArrayList; - - /** - * Construct an empty JSONArray. - */ - public JSONArray() { - myArrayList = new ArrayList(); - } - - /** - * Construct a JSONArray from a JSONTokener. - * - * @param x - * A JSONTokener - * @throws JSONException - * If there is a syntax error. - */ - public JSONArray(JSONTokener x) throws JSONException { - this(); - if (x.nextClean() != '[') { - throw x.syntaxError("A JSONArray text must start with '['"); - } - if (x.nextClean() != ']') { - x.back(); - for (;;) { - if (x.nextClean() == ',') { - x.back(); - myArrayList.add(JSONObject.NULL); - } else { - x.back(); - myArrayList.add(x.nextValue()); - } - switch (x.nextClean()) { - case ';': - case ',': - if (x.nextClean() == ']') { - return; - } - x.back(); - break; - case ']': - return; - default: - throw x.syntaxError("Expected a ',' or ']'"); - } - } - } - } - - /** - * Construct a JSONArray from a source JSON text. - * - * @param source - * A string that begins with <code>[</code> <small>(left - * bracket)</small> and ends with <code>]</code> - * <small>(right bracket)</small>. - * @throws JSONException - * If there is a syntax error. - */ - public JSONArray(String source) throws JSONException { - this(new JSONTokener(source)); - } - - /** - * Construct a JSONArray from a Collection. - * - * @param collection - * A Collection. - */ - public JSONArray(Collection collection) { - myArrayList = new ArrayList(); - if (collection != null) { - Iterator iter = collection.iterator(); - while (iter.hasNext()) { - myArrayList.add(JSONObject.wrap(iter.next())); - } - } - } - - /** - * Construct a JSONArray from an array - * - * @throws JSONException - * If not an array. - */ - public JSONArray(Object array) throws JSONException { - this(); - if (array.getClass().isArray()) { - int length = Array.getLength(array); - for (int i = 0; i < length; i += 1) { - this.put(JSONObject.wrap(Array.get(array, i))); - } - } else { - throw new JSONException( - "JSONArray initial value should be a string or collection or array."); - } - } - - /** - * Get the object value associated with an index. - * - * @param index - * The index must be between 0 and length() - 1. - * @return An object value. - * @throws JSONException - * If there is no value for the index. - */ - public Object get(int index) throws JSONException { - Object object = opt(index); - if (object == null) { - throw new JSONException("JSONArray[" + index + "] not found."); - } - return object; - } - - /** - * Get the boolean value associated with an index. The string values "true" - * and "false" are converted to boolean. - * - * @param index - * The index must be between 0 and length() - 1. - * @return The truth. - * @throws JSONException - * If there is no value for the index or if the value is not - * convertible to boolean. - */ - public boolean getBoolean(int index) throws JSONException { - Object object = get(index); - if (object.equals(Boolean.FALSE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("false"))) { - return false; - } else if (object.equals(Boolean.TRUE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("true"))) { - return true; - } - throw new JSONException("JSONArray[" + index + "] is not a boolean."); - } - - /** - * Get the double value associated with an index. - * - * @param index - * The index must be between 0 and length() - 1. - * @return The value. - * @throws JSONException - * If the key is not found or if the value cannot be converted - * to a number. - */ - public double getDouble(int index) throws JSONException { - Object object = get(index); - try { - return object instanceof Number ? ((Number) object).doubleValue() - : Double.parseDouble((String) object); - } catch (Exception e) { - throw new JSONException("JSONArray[" + index + "] is not a number."); - } - } - - /** - * Get the int value associated with an index. - * - * @param index - * The index must be between 0 and length() - 1. - * @return The value. - * @throws JSONException - * If the key is not found or if the value is not a number. - */ - public int getInt(int index) throws JSONException { - Object object = get(index); - try { - return object instanceof Number ? ((Number) object).intValue() - : Integer.parseInt((String) object); - } catch (Exception e) { - throw new JSONException("JSONArray[" + index + "] is not a number."); - } - } - - /** - * Get the JSONArray associated with an index. - * - * @param index - * The index must be between 0 and length() - 1. - * @return A JSONArray value. - * @throws JSONException - * If there is no value for the index. or if the value is not a - * JSONArray - */ - public JSONArray getJSONArray(int index) throws JSONException { - Object object = get(index); - if (object instanceof JSONArray) { - return (JSONArray) object; - } - throw new JSONException("JSONArray[" + index + "] is not a JSONArray."); - } - - /** - * Get the JSONObject associated with an index. - * - * @param index - * subscript - * @return A JSONObject value. - * @throws JSONException - * If there is no value for the index or if the value is not a - * JSONObject - */ - public JSONObject getJSONObject(int index) throws JSONException { - Object object = get(index); - if (object instanceof JSONObject) { - return (JSONObject) object; - } - throw new JSONException("JSONArray[" + index + "] is not a JSONObject."); - } - - /** - * Get the long value associated with an index. - * - * @param index - * The index must be between 0 and length() - 1. - * @return The value. - * @throws JSONException - * If the key is not found or if the value cannot be converted - * to a number. - */ - public long getLong(int index) throws JSONException { - Object object = get(index); - try { - return object instanceof Number ? ((Number) object).longValue() - : Long.parseLong((String) object); - } catch (Exception e) { - throw new JSONException("JSONArray[" + index + "] is not a number."); - } - } - - /** - * Get the string associated with an index. - * - * @param index - * The index must be between 0 and length() - 1. - * @return A string value. - * @throws JSONException - * If there is no string value for the index. - */ - public String getString(int index) throws JSONException { - Object object = get(index); - if (object instanceof String) { - return (String) object; - } - throw new JSONException("JSONArray[" + index + "] not a string."); - } - - /** - * Determine if the value is null. - * - * @param index - * The index must be between 0 and length() - 1. - * @return true if the value at the index is null, or if there is no value. - */ - public boolean isNull(int index) { - return JSONObject.NULL.equals(opt(index)); - } - - /** - * Make a string from the contents of this JSONArray. The - * <code>separator</code> string is inserted between each element. Warning: - * This method assumes that the data structure is acyclical. - * - * @param separator - * A string that will be inserted between the elements. - * @return a string. - * @throws JSONException - * If the array contains an invalid number. - */ - public String join(String separator) throws JSONException { - int len = length(); - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < len; i += 1) { - if (i > 0) { - sb.append(separator); - } - sb.append(JSONObject.valueToString(myArrayList.get(i))); - } - return sb.toString(); - } - - /** - * Get the number of elements in the JSONArray, included nulls. - * - * @return The length (or size). - */ - public int length() { - return myArrayList.size(); - } - - /** - * Get the optional object value associated with an index. - * - * @param index - * The index must be between 0 and length() - 1. - * @return An object value, or null if there is no object at that index. - */ - public Object opt(int index) { - return (index < 0 || index >= length()) ? null : myArrayList.get(index); - } - - /** - * Get the optional boolean value associated with an index. It returns false - * if there is no value at that index, or if the value is not Boolean.TRUE - * or the String "true". - * - * @param index - * The index must be between 0 and length() - 1. - * @return The truth. - */ - public boolean optBoolean(int index) { - return optBoolean(index, false); - } - - /** - * Get the optional boolean value associated with an index. It returns the - * defaultValue if there is no value at that index or if it is not a Boolean - * or the String "true" or "false" (case insensitive). - * - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * A boolean default. - * @return The truth. - */ - public boolean optBoolean(int index, boolean defaultValue) { - try { - return getBoolean(index); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get the optional double value associated with an index. NaN is returned - * if there is no value for the index, or if the value is not a number and - * cannot be converted to a number. - * - * @param index - * The index must be between 0 and length() - 1. - * @return The value. - */ - public double optDouble(int index) { - return optDouble(index, Double.NaN); - } - - /** - * Get the optional double value associated with an index. The defaultValue - * is returned if there is no value for the index, or if the value is not a - * number and cannot be converted to a number. - * - * @param index - * subscript - * @param defaultValue - * The default value. - * @return The value. - */ - public double optDouble(int index, double defaultValue) { - try { - return getDouble(index); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get the optional int value associated with an index. Zero is returned if - * there is no value for the index, or if the value is not a number and - * cannot be converted to a number. - * - * @param index - * The index must be between 0 and length() - 1. - * @return The value. - */ - public int optInt(int index) { - return optInt(index, 0); - } - - /** - * Get the optional int value associated with an index. The defaultValue is - * returned if there is no value for the index, or if the value is not a - * number and cannot be converted to a number. - * - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * The default value. - * @return The value. - */ - public int optInt(int index, int defaultValue) { - try { - return getInt(index); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get the optional JSONArray associated with an index. - * - * @param index - * subscript - * @return A JSONArray value, or null if the index has no value, or if the - * value is not a JSONArray. - */ - public JSONArray optJSONArray(int index) { - Object o = opt(index); - return o instanceof JSONArray ? (JSONArray) o : null; - } - - /** - * Get the optional JSONObject associated with an index. Null is returned if - * the key is not found, or null if the index has no value, or if the value - * is not a JSONObject. - * - * @param index - * The index must be between 0 and length() - 1. - * @return A JSONObject value. - */ - public JSONObject optJSONObject(int index) { - Object o = opt(index); - return o instanceof JSONObject ? (JSONObject) o : null; - } - - /** - * Get the optional long value associated with an index. Zero is returned if - * there is no value for the index, or if the value is not a number and - * cannot be converted to a number. - * - * @param index - * The index must be between 0 and length() - 1. - * @return The value. - */ - public long optLong(int index) { - return optLong(index, 0); - } - - /** - * Get the optional long value associated with an index. The defaultValue is - * returned if there is no value for the index, or if the value is not a - * number and cannot be converted to a number. - * - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * The default value. - * @return The value. - */ - public long optLong(int index, long defaultValue) { - try { - return getLong(index); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get the optional string value associated with an index. It returns an - * empty string if there is no value at that index. If the value is not a - * string and is not null, then it is coverted to a string. - * - * @param index - * The index must be between 0 and length() - 1. - * @return A String value. - */ - public String optString(int index) { - return optString(index, ""); - } - - /** - * Get the optional string associated with an index. The defaultValue is - * returned if the key is not found. - * - * @param index - * The index must be between 0 and length() - 1. - * @param defaultValue - * The default value. - * @return A String value. - */ - public String optString(int index, String defaultValue) { - Object object = opt(index); - return JSONObject.NULL.equals(object) ? object.toString() - : defaultValue; - } - - /** - * Append a boolean value. This increases the array's length by one. - * - * @param value - * A boolean value. - * @return this. - */ - public JSONArray put(boolean value) { - put(value ? Boolean.TRUE : Boolean.FALSE); - return this; - } - - /** - * Put a value in the JSONArray, where the value will be a JSONArray which - * is produced from a Collection. - * - * @param value - * A Collection value. - * @return this. - */ - public JSONArray put(Collection value) { - put(new JSONArray(value)); - return this; - } - - /** - * Append a double value. This increases the array's length by one. - * - * @param value - * A double value. - * @throws JSONException - * if the value is not finite. - * @return this. - */ - public JSONArray put(double value) throws JSONException { - Double d = new Double(value); - JSONObject.testValidity(d); - put(d); - return this; - } - - /** - * Append an int value. This increases the array's length by one. - * - * @param value - * An int value. - * @return this. - */ - public JSONArray put(int value) { - put(new Integer(value)); - return this; - } - - /** - * Append an long value. This increases the array's length by one. - * - * @param value - * A long value. - * @return this. - */ - public JSONArray put(long value) { - put(new Long(value)); - return this; - } - - /** - * Put a value in the JSONArray, where the value will be a JSONObject which - * is produced from a Map. - * - * @param value - * A Map value. - * @return this. - */ - public JSONArray put(Map value) { - put(new JSONObject(value)); - return this; - } - - /** - * Append an object value. This increases the array's length by one. - * - * @param value - * An object value. The value should be a Boolean, Double, - * Integer, JSONArray, JSONObject, Long, or String, or the - * JSONObject.NULL object. - * @return this. - */ - public JSONArray put(Object value) { - myArrayList.add(value); - return this; - } - - /** - * Put or replace a boolean value in the JSONArray. If the index is greater - * than the length of the JSONArray, then null elements will be added as - * necessary to pad it out. - * - * @param index - * The subscript. - * @param value - * A boolean value. - * @return this. - * @throws JSONException - * If the index is negative. - */ - public JSONArray put(int index, boolean value) throws JSONException { - put(index, value ? Boolean.TRUE : Boolean.FALSE); - return this; - } - - /** - * Put a value in the JSONArray, where the value will be a JSONArray which - * is produced from a Collection. - * - * @param index - * The subscript. - * @param value - * A Collection value. - * @return this. - * @throws JSONException - * If the index is negative or if the value is not finite. - */ - public JSONArray put(int index, Collection value) throws JSONException { - put(index, new JSONArray(value)); - return this; - } - - /** - * Put or replace a double value. If the index is greater than the length of - * the JSONArray, then null elements will be added as necessary to pad it - * out. - * - * @param index - * The subscript. - * @param value - * A double value. - * @return this. - * @throws JSONException - * If the index is negative or if the value is not finite. - */ - public JSONArray put(int index, double value) throws JSONException { - put(index, new Double(value)); - return this; - } - - /** - * Put or replace an int value. If the index is greater than the length of - * the JSONArray, then null elements will be added as necessary to pad it - * out. - * - * @param index - * The subscript. - * @param value - * An int value. - * @return this. - * @throws JSONException - * If the index is negative. - */ - public JSONArray put(int index, int value) throws JSONException { - put(index, new Integer(value)); - return this; - } - - /** - * Put or replace a long value. If the index is greater than the length of - * the JSONArray, then null elements will be added as necessary to pad it - * out. - * - * @param index - * The subscript. - * @param value - * A long value. - * @return this. - * @throws JSONException - * If the index is negative. - */ - public JSONArray put(int index, long value) throws JSONException { - put(index, new Long(value)); - return this; - } - - /** - * Put a value in the JSONArray, where the value will be a JSONObject that - * is produced from a Map. - * - * @param index - * The subscript. - * @param value - * The Map value. - * @return this. - * @throws JSONException - * If the index is negative or if the the value is an invalid - * number. - */ - public JSONArray put(int index, Map value) throws JSONException { - put(index, new JSONObject(value)); - return this; - } - - /** - * Put or replace an object value in the JSONArray. If the index is greater - * than the length of the JSONArray, then null elements will be added as - * necessary to pad it out. - * - * @param index - * The subscript. - * @param value - * The value to put into the array. The value should be a - * Boolean, Double, Integer, JSONArray, JSONObject, Long, or - * String, or the JSONObject.NULL object. - * @return this. - * @throws JSONException - * If the index is negative or if the the value is an invalid - * number. - */ - public JSONArray put(int index, Object value) throws JSONException { - JSONObject.testValidity(value); - if (index < 0) { - throw new JSONException("JSONArray[" + index + "] not found."); - } - if (index < length()) { - myArrayList.set(index, value); - } else { - while (index != length()) { - put(JSONObject.NULL); - } - put(value); - } - return this; - } - - /** - * Remove an index and close the hole. - * - * @param index - * The index of the element to be removed. - * @return The value that was associated with the index, or null if there - * was no value. - */ - public Object remove(int index) { - Object o = opt(index); - myArrayList.remove(index); - return o; - } - - /** - * Produce a JSONObject by combining a JSONArray of names with the values of - * this JSONArray. - * - * @param names - * A JSONArray containing a list of key strings. These will be - * paired with the values. - * @return A JSONObject, or null if there are no names or if this JSONArray - * has no values. - * @throws JSONException - * If any of the names are null. - */ - public JSONObject toJSONObject(JSONArray names) throws JSONException { - if (names == null || names.length() == 0 || length() == 0) { - return null; - } - JSONObject jo = new JSONObject(); - for (int i = 0; i < names.length(); i += 1) { - jo.put(names.getString(i), opt(i)); - } - return jo; - } - - /** - * Make a JSON text of this JSONArray. For compactness, no unnecessary - * whitespace is added. If it is not possible to produce a syntactically - * correct JSON text then null will be returned instead. This could occur if - * the array contains an invalid number. - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @return a printable, displayable, transmittable representation of the - * array. - */ - @Override - public String toString() { - try { - return '[' + join(",") + ']'; - } catch (Exception e) { - return null; - } - } - - /** - * Make a prettyprinted JSON text of this JSONArray. Warning: This method - * assumes that the data structure is acyclical. - * - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @return a printable, displayable, transmittable representation of the - * object, beginning with <code>[</code> <small>(left - * bracket)</small> and ending with <code>]</code> - * <small>(right bracket)</small>. - * @throws JSONException - */ - public String toString(int indentFactor) throws JSONException { - return toString(indentFactor, 0); - } - - /** - * Make a prettyprinted JSON text of this JSONArray. Warning: This method - * assumes that the data structure is acyclical. - * - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @param indent - * The indention of the top level. - * @return a printable, displayable, transmittable representation of the - * array. - * @throws JSONException - */ - String toString(int indentFactor, int indent) throws JSONException { - int len = length(); - if (len == 0) { - return "[]"; - } - int i; - StringBuffer sb = new StringBuffer("["); - if (len == 1) { - sb.append(JSONObject.valueToString(myArrayList.get(0), - indentFactor, indent)); - } else { - int newindent = indent + indentFactor; - sb.append('\n'); - for (i = 0; i < len; i += 1) { - if (i > 0) { - sb.append(",\n"); - } - for (int j = 0; j < newindent; j += 1) { - sb.append(' '); - } - sb.append(JSONObject.valueToString(myArrayList.get(i), - indentFactor, newindent)); - } - sb.append('\n'); - for (i = 0; i < indent; i += 1) { - sb.append(' '); - } - } - sb.append(']'); - return sb.toString(); - } - - /** - * Write the contents of the JSONArray as JSON text to a writer. For - * compactness, no whitespace is added. - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @return The writer. - * @throws JSONException - */ - public Writer write(Writer writer) throws JSONException { - try { - boolean b = false; - int len = length(); - - writer.write('['); - - for (int i = 0; i < len; i += 1) { - if (b) { - writer.write(','); - } - Object v = myArrayList.get(i); - if (v instanceof JSONObject) { - ((JSONObject) v).write(writer); - } else if (v instanceof JSONArray) { - ((JSONArray) v).write(writer); - } else { - writer.write(JSONObject.valueToString(v)); - } - b = true; - } - writer.write(']'); - return writer; - } catch (IOException e) { - throw new JSONException(e); - } - } -}
\ No newline at end of file diff --git a/src/com/vaadin/external/json/JSONException.java b/src/com/vaadin/external/json/JSONException.java deleted file mode 100644 index 895ffcb457..0000000000 --- a/src/com/vaadin/external/json/JSONException.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.vaadin.external.json; - -/** - * The JSONException is thrown by the JSON.org classes when things are amiss. - * - * @author JSON.org - * @version 2010-12-24 - */ -public class JSONException extends Exception { - private static final long serialVersionUID = 0; - private Throwable cause; - - /** - * Constructs a JSONException with an explanatory message. - * - * @param message - * Detail about the reason for the exception. - */ - public JSONException(String message) { - super(message); - } - - public JSONException(Throwable cause) { - super(cause.getMessage()); - this.cause = cause; - } - - @Override - public Throwable getCause() { - return this.cause; - } -} diff --git a/src/com/vaadin/external/json/JSONObject.java b/src/com/vaadin/external/json/JSONObject.java deleted file mode 100644 index ba772933be..0000000000 --- a/src/com/vaadin/external/json/JSONObject.java +++ /dev/null @@ -1,1693 +0,0 @@ -package com.vaadin.external.json; - -/* - Copyright (c) 2002 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -import java.io.IOException; -import java.io.Serializable; -import java.io.Writer; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; -import java.util.ResourceBundle; - -/** - * A JSONObject is an unordered collection of name/value pairs. Its external - * form is a string wrapped in curly braces with colons between the names and - * values, and commas between the values and names. The internal form is an - * object having <code>get</code> and <code>opt</code> methods for accessing the - * values by name, and <code>put</code> methods for adding or replacing values - * by name. The values can be any of these types: <code>Boolean</code>, - * <code>JSONArray</code>, <code>JSONObject</code>, <code>Number</code>, - * <code>String</code>, or the <code>JSONObject.NULL</code> object. A JSONObject - * constructor can be used to convert an external form JSON text into an - * internal form whose values can be retrieved with the <code>get</code> and - * <code>opt</code> methods, or to convert values into a JSON text using the - * <code>put</code> and <code>toString</code> methods. A <code>get</code> method - * returns a value if one can be found, and throws an exception if one cannot be - * found. An <code>opt</code> method returns a default value instead of throwing - * an exception, and so is useful for obtaining optional values. - * <p> - * The generic <code>get()</code> and <code>opt()</code> methods return an - * object, which you can cast or query for type. There are also typed - * <code>get</code> and <code>opt</code> methods that do type checking and type - * coercion for you. The opt methods differ from the get methods in that they do - * not throw. Instead, they return a specified value, such as null. - * <p> - * The <code>put</code> methods add or replace values in an object. For example, - * - * <pre> - * myString = new JSONObject().put("JSON", "Hello, World!").toString(); - * </pre> - * - * produces the string <code>{"JSON": "Hello, World"}</code>. - * <p> - * The texts produced by the <code>toString</code> methods strictly conform to - * the JSON syntax rules. The constructors are more forgiving in the texts they - * will accept: - * <ul> - * <li>An extra <code>,</code> <small>(comma)</small> may appear just - * before the closing brace.</li> - * <li>Strings may be quoted with <code>'</code> <small>(single - * quote)</small>.</li> - * <li>Strings do not need to be quoted at all if they do not begin with a quote - * or single quote, and if they do not contain leading or trailing spaces, and - * if they do not contain any of these characters: - * <code>{ } [ ] / \ : , = ; #</code> and if they do not look like numbers and - * if they are not the reserved words <code>true</code>, <code>false</code>, or - * <code>null</code>.</li> - * <li>Keys can be followed by <code>=</code> or <code>=></code> as well as by - * <code>:</code>.</li> - * <li>Values can be followed by <code>;</code> <small>(semicolon)</small> as - * well as by <code>,</code> <small>(comma)</small>.</li> - * <li>Numbers may have the <code>0x-</code> <small>(hex)</small> prefix.</li> - * </ul> - * - * @author JSON.org - * @version 2011-10-16 - */ -public class JSONObject implements Serializable { - - /** - * JSONObject.NULL is equivalent to the value that JavaScript calls null, - * whilst Java's null is equivalent to the value that JavaScript calls - * undefined. - */ - private static final class Null implements Serializable { - - /** - * There is only intended to be a single instance of the NULL object, so - * the clone method returns itself. - * - * @return NULL. - */ - @Override - protected final Object clone() { - return this; - } - - /** - * A Null object is equal to the null value and to itself. - * - * @param object - * An object to test for nullness. - * @return true if the object parameter is the JSONObject.NULL object or - * null. - */ - @Override - public boolean equals(Object object) { - return object == null || object == this; - } - - /** - * Get the "null" string value. - * - * @return The string "null". - */ - @Override - public String toString() { - return "null"; - } - } - - /** - * The map where the JSONObject's properties are kept. - */ - private Map map; - - /** - * It is sometimes more convenient and less ambiguous to have a - * <code>NULL</code> object than to use Java's <code>null</code> value. - * <code>JSONObject.NULL.equals(null)</code> returns <code>true</code>. - * <code>JSONObject.NULL.toString()</code> returns <code>"null"</code>. - */ - public static final Object NULL = new Null(); - - /** - * Construct an empty JSONObject. - */ - public JSONObject() { - map = new HashMap(); - } - - /** - * Construct a JSONObject from a subset of another JSONObject. An array of - * strings is used to identify the keys that should be copied. Missing keys - * are ignored. - * - * @param jo - * A JSONObject. - * @param names - * An array of strings. - * @throws JSONException - * @exception JSONException - * If a value is a non-finite number or if a name is - * duplicated. - */ - public JSONObject(JSONObject jo, String[] names) { - this(); - for (int i = 0; i < names.length; i += 1) { - try { - putOnce(names[i], jo.opt(names[i])); - } catch (Exception ignore) { - } - } - } - - /** - * Construct a JSONObject from a JSONTokener. - * - * @param x - * A JSONTokener object containing the source string. - * @throws JSONException - * If there is a syntax error in the source string or a - * duplicated key. - */ - public JSONObject(JSONTokener x) throws JSONException { - this(); - char c; - String key; - - if (x.nextClean() != '{') { - throw x.syntaxError("A JSONObject text must begin with '{'"); - } - for (;;) { - c = x.nextClean(); - switch (c) { - case 0: - throw x.syntaxError("A JSONObject text must end with '}'"); - case '}': - return; - default: - x.back(); - key = x.nextValue().toString(); - } - - // The key is followed by ':'. We will also tolerate '=' or '=>'. - - c = x.nextClean(); - if (c == '=') { - if (x.next() != '>') { - x.back(); - } - } else if (c != ':') { - throw x.syntaxError("Expected a ':' after a key"); - } - putOnce(key, x.nextValue()); - - // Pairs are separated by ','. We will also tolerate ';'. - - switch (x.nextClean()) { - case ';': - case ',': - if (x.nextClean() == '}') { - return; - } - x.back(); - break; - case '}': - return; - default: - throw x.syntaxError("Expected a ',' or '}'"); - } - } - } - - /** - * Construct a JSONObject from a Map. - * - * @param map - * A map object that can be used to initialize the contents of - * the JSONObject. - * @throws JSONException - */ - public JSONObject(Map map) { - this.map = new HashMap(); - if (map != null) { - Iterator i = map.entrySet().iterator(); - while (i.hasNext()) { - Map.Entry e = (Map.Entry) i.next(); - Object value = e.getValue(); - if (value != null) { - this.map.put(e.getKey(), wrap(value)); - } - } - } - } - - /** - * Construct a JSONObject from an Object using bean getters. It reflects on - * all of the public methods of the object. For each of the methods with no - * parameters and a name starting with <code>"get"</code> or - * <code>"is"</code> followed by an uppercase letter, the method is invoked, - * and a key and the value returned from the getter method are put into the - * new JSONObject. - * - * The key is formed by removing the <code>"get"</code> or <code>"is"</code> - * prefix. If the second remaining character is not upper case, then the - * first character is converted to lower case. - * - * For example, if an object has a method named <code>"getName"</code>, and - * if the result of calling <code>object.getName()</code> is - * <code>"Larry Fine"</code>, then the JSONObject will contain - * <code>"name": "Larry Fine"</code>. - * - * @param bean - * An object that has getter methods that should be used to make - * a JSONObject. - */ - public JSONObject(Object bean) { - this(); - populateMap(bean); - } - - /** - * Construct a JSONObject from an Object, using reflection to find the - * public members. The resulting JSONObject's keys will be the strings from - * the names array, and the values will be the field values associated with - * those keys in the object. If a key is not found or not visible, then it - * will not be copied into the new JSONObject. - * - * @param object - * An object that has fields that should be used to make a - * JSONObject. - * @param names - * An array of strings, the names of the fields to be obtained - * from the object. - */ - public JSONObject(Object object, String names[]) { - this(); - Class c = object.getClass(); - for (int i = 0; i < names.length; i += 1) { - String name = names[i]; - try { - putOpt(name, c.getField(name).get(object)); - } catch (Exception ignore) { - } - } - } - - /** - * Construct a JSONObject from a source JSON text string. This is the most - * commonly used JSONObject constructor. - * - * @param source - * A string beginning with <code>{</code> <small>(left - * brace)</small> and ending with <code>}</code> - * <small>(right brace)</small>. - * @exception JSONException - * If there is a syntax error in the source string or a - * duplicated key. - */ - public JSONObject(String source) throws JSONException { - this(new JSONTokener(source)); - } - - /** - * Construct a JSONObject from a ResourceBundle. - * - * @param baseName - * The ResourceBundle base name. - * @param locale - * The Locale to load the ResourceBundle for. - * @throws JSONException - * If any JSONExceptions are detected. - */ - public JSONObject(String baseName, Locale locale) throws JSONException { - this(); - ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, - Thread.currentThread().getContextClassLoader()); - - // Iterate through the keys in the bundle. - - Enumeration keys = bundle.getKeys(); - while (keys.hasMoreElements()) { - Object key = keys.nextElement(); - if (key instanceof String) { - - // Go through the path, ensuring that there is a nested - // JSONObject for each - // segment except the last. Add the value using the last - // segment's name into - // the deepest nested JSONObject. - - String[] path = ((String) key).split("\\."); - int last = path.length - 1; - JSONObject target = this; - for (int i = 0; i < last; i += 1) { - String segment = path[i]; - JSONObject nextTarget = target.optJSONObject(segment); - if (nextTarget == null) { - nextTarget = new JSONObject(); - target.put(segment, nextTarget); - } - target = nextTarget; - } - target.put(path[last], bundle.getString((String) key)); - } - } - } - - /** - * Accumulate values under a key. It is similar to the put method except - * that if there is already an object stored under the key then a JSONArray - * is stored under the key to hold all of the accumulated values. If there - * is already a JSONArray, then the new value is appended to it. In - * contrast, the put method replaces the previous value. - * - * If only one value is accumulated that is not a JSONArray, then the result - * will be the same as using put. But if multiple values are accumulated, - * then the result will be like append. - * - * @param key - * A key string. - * @param value - * An object to be accumulated under the key. - * @return this. - * @throws JSONException - * If the value is an invalid number or if the key is null. - */ - public JSONObject accumulate(String key, Object value) throws JSONException { - testValidity(value); - Object object = opt(key); - if (object == null) { - put(key, value instanceof JSONArray ? new JSONArray().put(value) - : value); - } else if (object instanceof JSONArray) { - ((JSONArray) object).put(value); - } else { - put(key, new JSONArray().put(object).put(value)); - } - return this; - } - - /** - * Append values to the array under a key. If the key does not exist in the - * JSONObject, then the key is put in the JSONObject with its value being a - * JSONArray containing the value parameter. If the key was already - * associated with a JSONArray, then the value parameter is appended to it. - * - * @param key - * A key string. - * @param value - * An object to be accumulated under the key. - * @return this. - * @throws JSONException - * If the key is null or if the current value associated with - * the key is not a JSONArray. - */ - public JSONObject append(String key, Object value) throws JSONException { - testValidity(value); - Object object = opt(key); - if (object == null) { - put(key, new JSONArray().put(value)); - } else if (object instanceof JSONArray) { - put(key, ((JSONArray) object).put(value)); - } else { - throw new JSONException("JSONObject[" + key - + "] is not a JSONArray."); - } - return this; - } - - /** - * Produce a string from a double. The string "null" will be returned if the - * number is not finite. - * - * @param d - * A double. - * @return A String. - */ - public static String doubleToString(double d) { - if (Double.isInfinite(d) || Double.isNaN(d)) { - return "null"; - } - - // Shave off trailing zeros and decimal point, if possible. - - String string = Double.toString(d); - if (string.indexOf('.') > 0 && string.indexOf('e') < 0 - && string.indexOf('E') < 0) { - while (string.endsWith("0")) { - string = string.substring(0, string.length() - 1); - } - if (string.endsWith(".")) { - string = string.substring(0, string.length() - 1); - } - } - return string; - } - - /** - * Get the value object associated with a key. - * - * @param key - * A key string. - * @return The object associated with the key. - * @throws JSONException - * if the key is not found. - */ - public Object get(String key) throws JSONException { - if (key == null) { - throw new JSONException("Null key."); - } - Object object = opt(key); - if (object == null) { - throw new JSONException("JSONObject[" + quote(key) + "] not found."); - } - return object; - } - - /** - * Get the boolean value associated with a key. - * - * @param key - * A key string. - * @return The truth. - * @throws JSONException - * if the value is not a Boolean or the String "true" or - * "false". - */ - public boolean getBoolean(String key) throws JSONException { - Object object = get(key); - if (object.equals(Boolean.FALSE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("false"))) { - return false; - } else if (object.equals(Boolean.TRUE) - || (object instanceof String && ((String) object) - .equalsIgnoreCase("true"))) { - return true; - } - throw new JSONException("JSONObject[" + quote(key) - + "] is not a Boolean."); - } - - /** - * Get the double value associated with a key. - * - * @param key - * A key string. - * @return The numeric value. - * @throws JSONException - * if the key is not found or if the value is not a Number - * object and cannot be converted to a number. - */ - public double getDouble(String key) throws JSONException { - Object object = get(key); - try { - return object instanceof Number ? ((Number) object).doubleValue() - : Double.parseDouble((String) object); - } catch (Exception e) { - throw new JSONException("JSONObject[" + quote(key) - + "] is not a number."); - } - } - - /** - * Get the int value associated with a key. - * - * @param key - * A key string. - * @return The integer value. - * @throws JSONException - * if the key is not found or if the value cannot be converted - * to an integer. - */ - public int getInt(String key) throws JSONException { - Object object = get(key); - try { - return object instanceof Number ? ((Number) object).intValue() - : Integer.parseInt((String) object); - } catch (Exception e) { - throw new JSONException("JSONObject[" + quote(key) - + "] is not an int."); - } - } - - /** - * Get the JSONArray value associated with a key. - * - * @param key - * A key string. - * @return A JSONArray which is the value. - * @throws JSONException - * if the key is not found or if the value is not a JSONArray. - */ - public JSONArray getJSONArray(String key) throws JSONException { - Object object = get(key); - if (object instanceof JSONArray) { - return (JSONArray) object; - } - throw new JSONException("JSONObject[" + quote(key) - + "] is not a JSONArray."); - } - - /** - * Get the JSONObject value associated with a key. - * - * @param key - * A key string. - * @return A JSONObject which is the value. - * @throws JSONException - * if the key is not found or if the value is not a JSONObject. - */ - public JSONObject getJSONObject(String key) throws JSONException { - Object object = get(key); - if (object instanceof JSONObject) { - return (JSONObject) object; - } - throw new JSONException("JSONObject[" + quote(key) - + "] is not a JSONObject."); - } - - /** - * Get the long value associated with a key. - * - * @param key - * A key string. - * @return The long value. - * @throws JSONException - * if the key is not found or if the value cannot be converted - * to a long. - */ - public long getLong(String key) throws JSONException { - Object object = get(key); - try { - return object instanceof Number ? ((Number) object).longValue() - : Long.parseLong((String) object); - } catch (Exception e) { - throw new JSONException("JSONObject[" + quote(key) - + "] is not a long."); - } - } - - /** - * Get an array of field names from a JSONObject. - * - * @return An array of field names, or null if there are no names. - */ - public static String[] getNames(JSONObject jo) { - int length = jo.length(); - if (length == 0) { - return null; - } - Iterator iterator = jo.keys(); - String[] names = new String[length]; - int i = 0; - while (iterator.hasNext()) { - names[i] = (String) iterator.next(); - i += 1; - } - return names; - } - - /** - * Get an array of field names from an Object. - * - * @return An array of field names, or null if there are no names. - */ - public static String[] getNames(Object object) { - if (object == null) { - return null; - } - Class klass = object.getClass(); - Field[] fields = klass.getFields(); - int length = fields.length; - if (length == 0) { - return null; - } - String[] names = new String[length]; - for (int i = 0; i < length; i += 1) { - names[i] = fields[i].getName(); - } - return names; - } - - /** - * Get the string associated with a key. - * - * @param key - * A key string. - * @return A string which is the value. - * @throws JSONException - * if there is no string value for the key. - */ - public String getString(String key) throws JSONException { - Object object = get(key); - if (object instanceof String) { - return (String) object; - } - throw new JSONException("JSONObject[" + quote(key) + "] not a string."); - } - - /** - * Determine if the JSONObject contains a specific key. - * - * @param key - * A key string. - * @return true if the key exists in the JSONObject. - */ - public boolean has(String key) { - return map.containsKey(key); - } - - /** - * Increment a property of a JSONObject. If there is no such property, - * create one with a value of 1. If there is such a property, and if it is - * an Integer, Long, Double, or Float, then add one to it. - * - * @param key - * A key string. - * @return this. - * @throws JSONException - * If there is already a property with this name that is not an - * Integer, Long, Double, or Float. - */ - public JSONObject increment(String key) throws JSONException { - Object value = opt(key); - if (value == null) { - put(key, 1); - } else if (value instanceof Integer) { - put(key, ((Integer) value).intValue() + 1); - } else if (value instanceof Long) { - put(key, ((Long) value).longValue() + 1); - } else if (value instanceof Double) { - put(key, ((Double) value).doubleValue() + 1); - } else if (value instanceof Float) { - put(key, ((Float) value).floatValue() + 1); - } else { - throw new JSONException("Unable to increment [" + quote(key) + "]."); - } - return this; - } - - /** - * Determine if the value associated with the key is null or if there is no - * value. - * - * @param key - * A key string. - * @return true if there is no value associated with the key or if the value - * is the JSONObject.NULL object. - */ - public boolean isNull(String key) { - return JSONObject.NULL.equals(opt(key)); - } - - /** - * Get an enumeration of the keys of the JSONObject. - * - * @return An iterator of the keys. - */ - public Iterator keys() { - return map.keySet().iterator(); - } - - /** - * Get the number of keys stored in the JSONObject. - * - * @return The number of keys in the JSONObject. - */ - public int length() { - return map.size(); - } - - /** - * Produce a JSONArray containing the names of the elements of this - * JSONObject. - * - * @return A JSONArray containing the key strings, or null if the JSONObject - * is empty. - */ - public JSONArray names() { - JSONArray ja = new JSONArray(); - Iterator keys = keys(); - while (keys.hasNext()) { - ja.put(keys.next()); - } - return ja.length() == 0 ? null : ja; - } - - /** - * Produce a string from a Number. - * - * @param number - * A Number - * @return A String. - * @throws JSONException - * If n is a non-finite number. - */ - public static String numberToString(Number number) throws JSONException { - if (number == null) { - throw new JSONException("Null pointer"); - } - testValidity(number); - - // Shave off trailing zeros and decimal point, if possible. - - String string = number.toString(); - if (string.indexOf('.') > 0 && string.indexOf('e') < 0 - && string.indexOf('E') < 0) { - while (string.endsWith("0")) { - string = string.substring(0, string.length() - 1); - } - if (string.endsWith(".")) { - string = string.substring(0, string.length() - 1); - } - } - return string; - } - - /** - * Get an optional value associated with a key. - * - * @param key - * A key string. - * @return An object which is the value, or null if there is no value. - */ - public Object opt(String key) { - return key == null ? null : map.get(key); - } - - /** - * Get an optional boolean associated with a key. It returns false if there - * is no such key, or if the value is not Boolean.TRUE or the String "true". - * - * @param key - * A key string. - * @return The truth. - */ - public boolean optBoolean(String key) { - return optBoolean(key, false); - } - - /** - * Get an optional boolean associated with a key. It returns the - * defaultValue if there is no such key, or if it is not a Boolean or the - * String "true" or "false" (case insensitive). - * - * @param key - * A key string. - * @param defaultValue - * The default. - * @return The truth. - */ - public boolean optBoolean(String key, boolean defaultValue) { - try { - return getBoolean(key); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get an optional double associated with a key, or NaN if there is no such - * key or if its value is not a number. If the value is a string, an attempt - * will be made to evaluate it as a number. - * - * @param key - * A string which is the key. - * @return An object which is the value. - */ - public double optDouble(String key) { - return optDouble(key, Double.NaN); - } - - /** - * Get an optional double associated with a key, or the defaultValue if - * there is no such key or if its value is not a number. If the value is a - * string, an attempt will be made to evaluate it as a number. - * - * @param key - * A key string. - * @param defaultValue - * The default. - * @return An object which is the value. - */ - public double optDouble(String key, double defaultValue) { - try { - return getDouble(key); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get an optional int value associated with a key, or zero if there is no - * such key or if the value is not a number. If the value is a string, an - * attempt will be made to evaluate it as a number. - * - * @param key - * A key string. - * @return An object which is the value. - */ - public int optInt(String key) { - return optInt(key, 0); - } - - /** - * Get an optional int value associated with a key, or the default if there - * is no such key or if the value is not a number. If the value is a string, - * an attempt will be made to evaluate it as a number. - * - * @param key - * A key string. - * @param defaultValue - * The default. - * @return An object which is the value. - */ - public int optInt(String key, int defaultValue) { - try { - return getInt(key); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get an optional JSONArray associated with a key. It returns null if there - * is no such key, or if its value is not a JSONArray. - * - * @param key - * A key string. - * @return A JSONArray which is the value. - */ - public JSONArray optJSONArray(String key) { - Object o = opt(key); - return o instanceof JSONArray ? (JSONArray) o : null; - } - - /** - * Get an optional JSONObject associated with a key. It returns null if - * there is no such key, or if its value is not a JSONObject. - * - * @param key - * A key string. - * @return A JSONObject which is the value. - */ - public JSONObject optJSONObject(String key) { - Object object = opt(key); - return object instanceof JSONObject ? (JSONObject) object : null; - } - - /** - * Get an optional long value associated with a key, or zero if there is no - * such key or if the value is not a number. If the value is a string, an - * attempt will be made to evaluate it as a number. - * - * @param key - * A key string. - * @return An object which is the value. - */ - public long optLong(String key) { - return optLong(key, 0); - } - - /** - * Get an optional long value associated with a key, or the default if there - * is no such key or if the value is not a number. If the value is a string, - * an attempt will be made to evaluate it as a number. - * - * @param key - * A key string. - * @param defaultValue - * The default. - * @return An object which is the value. - */ - public long optLong(String key, long defaultValue) { - try { - return getLong(key); - } catch (Exception e) { - return defaultValue; - } - } - - /** - * Get an optional string associated with a key. It returns an empty string - * if there is no such key. If the value is not a string and is not null, - * then it is converted to a string. - * - * @param key - * A key string. - * @return A string which is the value. - */ - public String optString(String key) { - return optString(key, ""); - } - - /** - * Get an optional string associated with a key. It returns the defaultValue - * if there is no such key. - * - * @param key - * A key string. - * @param defaultValue - * The default. - * @return A string which is the value. - */ - public String optString(String key, String defaultValue) { - Object object = opt(key); - return NULL.equals(object) ? defaultValue : object.toString(); - } - - private void populateMap(Object bean) { - Class klass = bean.getClass(); - - // If klass is a System class then set includeSuperClass to false. - - boolean includeSuperClass = klass.getClassLoader() != null; - - Method[] methods = (includeSuperClass) ? klass.getMethods() : klass - .getDeclaredMethods(); - for (int i = 0; i < methods.length; i += 1) { - try { - Method method = methods[i]; - if (Modifier.isPublic(method.getModifiers())) { - String name = method.getName(); - String key = ""; - if (name.startsWith("get")) { - if (name.equals("getClass") - || name.equals("getDeclaringClass")) { - key = ""; - } else { - key = name.substring(3); - } - } else if (name.startsWith("is")) { - key = name.substring(2); - } - if (key.length() > 0 - && Character.isUpperCase(key.charAt(0)) - && method.getParameterTypes().length == 0) { - if (key.length() == 1) { - key = key.toLowerCase(); - } else if (!Character.isUpperCase(key.charAt(1))) { - key = key.substring(0, 1).toLowerCase() - + key.substring(1); - } - - Object result = method.invoke(bean, (Object[]) null); - if (result != null) { - map.put(key, wrap(result)); - } - } - } - } catch (Exception ignore) { - } - } - } - - /** - * Put a key/boolean pair in the JSONObject. - * - * @param key - * A key string. - * @param value - * A boolean which is the value. - * @return this. - * @throws JSONException - * If the key is null. - */ - public JSONObject put(String key, boolean value) throws JSONException { - put(key, value ? Boolean.TRUE : Boolean.FALSE); - return this; - } - - /** - * Put a key/value pair in the JSONObject, where the value will be a - * JSONArray which is produced from a Collection. - * - * @param key - * A key string. - * @param value - * A Collection value. - * @return this. - * @throws JSONException - */ - public JSONObject put(String key, Collection value) throws JSONException { - put(key, new JSONArray(value)); - return this; - } - - /** - * Put a key/double pair in the JSONObject. - * - * @param key - * A key string. - * @param value - * A double which is the value. - * @return this. - * @throws JSONException - * If the key is null or if the number is invalid. - */ - public JSONObject put(String key, double value) throws JSONException { - put(key, new Double(value)); - return this; - } - - /** - * Put a key/int pair in the JSONObject. - * - * @param key - * A key string. - * @param value - * An int which is the value. - * @return this. - * @throws JSONException - * If the key is null. - */ - public JSONObject put(String key, int value) throws JSONException { - put(key, new Integer(value)); - return this; - } - - /** - * Put a key/long pair in the JSONObject. - * - * @param key - * A key string. - * @param value - * A long which is the value. - * @return this. - * @throws JSONException - * If the key is null. - */ - public JSONObject put(String key, long value) throws JSONException { - put(key, new Long(value)); - return this; - } - - /** - * Put a key/value pair in the JSONObject, where the value will be a - * JSONObject which is produced from a Map. - * - * @param key - * A key string. - * @param value - * A Map value. - * @return this. - * @throws JSONException - */ - public JSONObject put(String key, Map value) throws JSONException { - put(key, new JSONObject(value)); - return this; - } - - /** - * Put a key/value pair in the JSONObject. If the value is null, then the - * key will be removed from the JSONObject if it is present. - * - * @param key - * A key string. - * @param value - * An object which is the value. It should be of one of these - * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, - * String, or the JSONObject.NULL object. - * @return this. - * @throws JSONException - * If the value is non-finite number or if the key is null. - */ - public JSONObject put(String key, Object value) throws JSONException { - if (key == null) { - throw new JSONException("Null key."); - } - if (value != null) { - testValidity(value); - map.put(key, value); - } else { - remove(key); - } - return this; - } - - /** - * Put a key/value pair in the JSONObject, but only if the key and the value - * are both non-null, and only if there is not already a member with that - * name. - * - * @param key - * @param value - * @return his. - * @throws JSONException - * if the key is a duplicate - */ - public JSONObject putOnce(String key, Object value) throws JSONException { - if (key != null && value != null) { - if (opt(key) != null) { - throw new JSONException("Duplicate key \"" + key + "\""); - } - put(key, value); - } - return this; - } - - /** - * Put a key/value pair in the JSONObject, but only if the key and the value - * are both non-null. - * - * @param key - * A key string. - * @param value - * An object which is the value. It should be of one of these - * types: Boolean, Double, Integer, JSONArray, JSONObject, Long, - * String, or the JSONObject.NULL object. - * @return this. - * @throws JSONException - * If the value is a non-finite number. - */ - public JSONObject putOpt(String key, Object value) throws JSONException { - if (key != null && value != null) { - put(key, value); - } - return this; - } - - /** - * Produce a string in double quotes with backslash sequences in all the - * right places. A backslash will be inserted within </, producing <\/, - * allowing JSON text to be delivered in HTML. In JSON text, a string cannot - * contain a control character or an unescaped quote or backslash. - * - * @param string - * A String - * @return A String correctly formatted for insertion in a JSON text. - */ - public static String quote(String string) { - if (string == null || string.length() == 0) { - return "\"\""; - } - - char b; - char c = 0; - String hhhh; - int i; - int len = string.length(); - StringBuffer sb = new StringBuffer(len + 4); - - sb.append('"'); - for (i = 0; i < len; i += 1) { - b = c; - c = string.charAt(i); - switch (c) { - case '\\': - case '"': - sb.append('\\'); - sb.append(c); - break; - case '/': - if (b == '<') { - sb.append('\\'); - } - sb.append(c); - break; - case '\b': - sb.append("\\b"); - break; - case '\t': - sb.append("\\t"); - break; - case '\n': - sb.append("\\n"); - break; - case '\f': - sb.append("\\f"); - break; - case '\r': - sb.append("\\r"); - break; - default: - if (c < ' ' || (c >= '\u0080' && c < '\u00a0') - || (c >= '\u2000' && c < '\u2100')) { - hhhh = "000" + Integer.toHexString(c); - sb.append("\\u" + hhhh.substring(hhhh.length() - 4)); - } else { - sb.append(c); - } - } - } - sb.append('"'); - return sb.toString(); - } - - /** - * Remove a name and its value, if present. - * - * @param key - * The name to be removed. - * @return The value that was associated with the name, or null if there was - * no value. - */ - public Object remove(String key) { - return map.remove(key); - } - - /** - * Try to convert a string into a number, boolean, or null. If the string - * can't be converted, return the string. - * - * @param string - * A String. - * @return A simple JSON value. - */ - public static Object stringToValue(String string) { - Double d; - if (string.equals("")) { - return string; - } - if (string.equalsIgnoreCase("true")) { - return Boolean.TRUE; - } - if (string.equalsIgnoreCase("false")) { - return Boolean.FALSE; - } - if (string.equalsIgnoreCase("null")) { - return JSONObject.NULL; - } - - /* - * If it might be a number, try converting it. We support the - * non-standard 0x- convention. If a number cannot be produced, then the - * value will just be a string. Note that the 0x-, plus, and implied - * string conventions are non-standard. A JSON parser may accept - * non-JSON forms as long as it accepts all correct JSON forms. - */ - - char b = string.charAt(0); - if ((b >= '0' && b <= '9') || b == '.' || b == '-' || b == '+') { - if (b == '0' && string.length() > 2 - && (string.charAt(1) == 'x' || string.charAt(1) == 'X')) { - try { - return new Integer( - Integer.parseInt(string.substring(2), 16)); - } catch (Exception ignore) { - } - } - try { - if (string.indexOf('.') > -1 || string.indexOf('e') > -1 - || string.indexOf('E') > -1) { - d = Double.valueOf(string); - if (!d.isInfinite() && !d.isNaN()) { - return d; - } - } else { - Long myLong = new Long(string); - if (myLong.longValue() == myLong.intValue()) { - return new Integer(myLong.intValue()); - } else { - return myLong; - } - } - } catch (Exception ignore) { - } - } - return string; - } - - /** - * Throw an exception if the object is a NaN or infinite number. - * - * @param o - * The object to test. - * @throws JSONException - * If o is a non-finite number. - */ - public static void testValidity(Object o) throws JSONException { - if (o != null) { - if (o instanceof Double) { - if (((Double) o).isInfinite() || ((Double) o).isNaN()) { - throw new JSONException( - "JSON does not allow non-finite numbers."); - } - } else if (o instanceof Float) { - if (((Float) o).isInfinite() || ((Float) o).isNaN()) { - throw new JSONException( - "JSON does not allow non-finite numbers."); - } - } - } - } - - /** - * Produce a JSONArray containing the values of the members of this - * JSONObject. - * - * @param names - * A JSONArray containing a list of key strings. This determines - * the sequence of the values in the result. - * @return A JSONArray of values. - * @throws JSONException - * If any of the values are non-finite numbers. - */ - public JSONArray toJSONArray(JSONArray names) throws JSONException { - if (names == null || names.length() == 0) { - return null; - } - JSONArray ja = new JSONArray(); - for (int i = 0; i < names.length(); i += 1) { - ja.put(opt(names.getString(i))); - } - return ja; - } - - /** - * Make a JSON text of this JSONObject. For compactness, no whitespace is - * added. If this would not result in a syntactically correct JSON text, - * then null will be returned instead. - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @return a printable, displayable, portable, transmittable representation - * of the object, beginning with <code>{</code> <small>(left - * brace)</small> and ending with <code>}</code> <small>(right - * brace)</small>. - */ - @Override - public String toString() { - try { - Iterator keys = keys(); - StringBuffer sb = new StringBuffer("{"); - - while (keys.hasNext()) { - if (sb.length() > 1) { - sb.append(','); - } - Object o = keys.next(); - sb.append(quote(o.toString())); - sb.append(':'); - sb.append(valueToString(map.get(o))); - } - sb.append('}'); - return sb.toString(); - } catch (Exception e) { - return null; - } - } - - /** - * Make a prettyprinted JSON text of this JSONObject. - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @return a printable, displayable, portable, transmittable representation - * of the object, beginning with <code>{</code> <small>(left - * brace)</small> and ending with <code>}</code> <small>(right - * brace)</small>. - * @throws JSONException - * If the object contains an invalid number. - */ - public String toString(int indentFactor) throws JSONException { - return toString(indentFactor, 0); - } - - /** - * Make a prettyprinted JSON text of this JSONObject. - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @param indent - * The indentation of the top level. - * @return a printable, displayable, transmittable representation of the - * object, beginning with <code>{</code> <small>(left - * brace)</small> and ending with <code>}</code> <small>(right - * brace)</small>. - * @throws JSONException - * If the object contains an invalid number. - */ - String toString(int indentFactor, int indent) throws JSONException { - int i; - int length = length(); - if (length == 0) { - return "{}"; - } - Iterator keys = keys(); - int newindent = indent + indentFactor; - Object object; - StringBuffer sb = new StringBuffer("{"); - if (length == 1) { - object = keys.next(); - sb.append(quote(object.toString())); - sb.append(": "); - sb.append(valueToString(map.get(object), indentFactor, indent)); - } else { - while (keys.hasNext()) { - object = keys.next(); - if (sb.length() > 1) { - sb.append(",\n"); - } else { - sb.append('\n'); - } - for (i = 0; i < newindent; i += 1) { - sb.append(' '); - } - sb.append(quote(object.toString())); - sb.append(": "); - sb.append(valueToString(map.get(object), indentFactor, - newindent)); - } - if (sb.length() > 1) { - sb.append('\n'); - for (i = 0; i < indent; i += 1) { - sb.append(' '); - } - } - } - sb.append('}'); - return sb.toString(); - } - - /** - * Make a JSON text of an Object value. If the object has an - * value.toJSONString() method, then that method will be used to produce the - * JSON text. The method is required to produce a strictly conforming text. - * If the object does not contain a toJSONString method (which is the most - * common case), then a text will be produced by other means. If the value - * is an array or Collection, then a JSONArray will be made from it and its - * toJSONString method will be called. If the value is a MAP, then a - * JSONObject will be made from it and its toJSONString method will be - * called. Otherwise, the value's toString method will be called, and the - * result will be quoted. - * - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @param value - * The value to be serialized. - * @return a printable, displayable, transmittable representation of the - * object, beginning with <code>{</code> <small>(left - * brace)</small> and ending with <code>}</code> <small>(right - * brace)</small>. - * @throws JSONException - * If the value is or contains an invalid number. - */ - public static String valueToString(Object value) throws JSONException { - if (value == null || value.equals(null)) { - return "null"; - } - if (value instanceof JSONString) { - Object object; - try { - object = ((JSONString) value).toJSONString(); - } catch (Exception e) { - throw new JSONException(e); - } - if (object instanceof String) { - return (String) object; - } - throw new JSONException("Bad value from toJSONString: " + object); - } - if (value instanceof Number) { - return numberToString((Number) value); - } - if (value instanceof Boolean || value instanceof JSONObject - || value instanceof JSONArray) { - return value.toString(); - } - if (value instanceof Map) { - return new JSONObject((Map) value).toString(); - } - if (value instanceof Collection) { - return new JSONArray((Collection) value).toString(); - } - if (value.getClass().isArray()) { - return new JSONArray(value).toString(); - } - return quote(value.toString()); - } - - /** - * Make a prettyprinted JSON text of an object value. - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @param value - * The value to be serialized. - * @param indentFactor - * The number of spaces to add to each level of indentation. - * @param indent - * The indentation of the top level. - * @return a printable, displayable, transmittable representation of the - * object, beginning with <code>{</code> <small>(left - * brace)</small> and ending with <code>}</code> <small>(right - * brace)</small>. - * @throws JSONException - * If the object contains an invalid number. - */ - static String valueToString(Object value, int indentFactor, int indent) - throws JSONException { - if (value == null || value.equals(null)) { - return "null"; - } - try { - if (value instanceof JSONString) { - Object o = ((JSONString) value).toJSONString(); - if (o instanceof String) { - return (String) o; - } - } - } catch (Exception ignore) { - } - if (value instanceof Number) { - return numberToString((Number) value); - } - if (value instanceof Boolean) { - return value.toString(); - } - if (value instanceof JSONObject) { - return ((JSONObject) value).toString(indentFactor, indent); - } - if (value instanceof JSONArray) { - return ((JSONArray) value).toString(indentFactor, indent); - } - if (value instanceof Map) { - return new JSONObject((Map) value).toString(indentFactor, indent); - } - if (value instanceof Collection) { - return new JSONArray((Collection) value).toString(indentFactor, - indent); - } - if (value.getClass().isArray()) { - return new JSONArray(value).toString(indentFactor, indent); - } - return quote(value.toString()); - } - - /** - * Wrap an object, if necessary. If the object is null, return the NULL - * object. If it is an array or collection, wrap it in a JSONArray. If it is - * a map, wrap it in a JSONObject. If it is a standard property (Double, - * String, et al) then it is already wrapped. Otherwise, if it comes from - * one of the java packages, turn it into a string. And if it doesn't, try - * to wrap it in a JSONObject. If the wrapping fails, then null is returned. - * - * @param object - * The object to wrap - * @return The wrapped value - */ - public static Object wrap(Object object) { - try { - if (object == null) { - return NULL; - } - if (object instanceof JSONObject || object instanceof JSONArray - || NULL.equals(object) || object instanceof JSONString - || object instanceof Byte || object instanceof Character - || object instanceof Short || object instanceof Integer - || object instanceof Long || object instanceof Boolean - || object instanceof Float || object instanceof Double - || object instanceof String) { - return object; - } - - if (object instanceof Collection) { - return new JSONArray((Collection) object); - } - if (object.getClass().isArray()) { - return new JSONArray(object); - } - if (object instanceof Map) { - return new JSONObject((Map) object); - } - Package objectPackage = object.getClass().getPackage(); - String objectPackageName = objectPackage != null ? objectPackage - .getName() : ""; - if (objectPackageName.startsWith("java.") - || objectPackageName.startsWith("javax.") - || object.getClass().getClassLoader() == null) { - return object.toString(); - } - return new JSONObject(object); - } catch (Exception exception) { - return null; - } - } - - /** - * Write the contents of the JSONObject as JSON text to a writer. For - * compactness, no whitespace is added. - * <p> - * Warning: This method assumes that the data structure is acyclical. - * - * @return The writer. - * @throws JSONException - */ - public Writer write(Writer writer) throws JSONException { - try { - boolean commanate = false; - Iterator keys = keys(); - writer.write('{'); - - while (keys.hasNext()) { - if (commanate) { - writer.write(','); - } - Object key = keys.next(); - writer.write(quote(key.toString())); - writer.write(':'); - Object value = map.get(key); - if (value instanceof JSONObject) { - ((JSONObject) value).write(writer); - } else if (value instanceof JSONArray) { - ((JSONArray) value).write(writer); - } else { - writer.write(valueToString(value)); - } - commanate = true; - } - writer.write('}'); - return writer; - } catch (IOException exception) { - throw new JSONException(exception); - } - } -}
\ No newline at end of file diff --git a/src/com/vaadin/external/json/JSONString.java b/src/com/vaadin/external/json/JSONString.java deleted file mode 100644 index cc7e4d8c07..0000000000 --- a/src/com/vaadin/external/json/JSONString.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.vaadin.external.json; - -import java.io.Serializable; - -/** - * The <code>JSONString</code> interface allows a <code>toJSONString()</code> - * method so that a class can change the behavior of - * <code>JSONObject.toString()</code>, <code>JSONArray.toString()</code>, and - * <code>JSONWriter.value(</code>Object<code>)</code>. The - * <code>toJSONString</code> method will be used instead of the default behavior - * of using the Object's <code>toString()</code> method and quoting the result. - */ -public interface JSONString extends Serializable { - /** - * The <code>toJSONString</code> method allows a class to produce its own - * JSON serialization. - * - * @return A strictly syntactically correct JSON text. - */ - public String toJSONString(); -} diff --git a/src/com/vaadin/external/json/JSONStringer.java b/src/com/vaadin/external/json/JSONStringer.java deleted file mode 100644 index ae905cb15f..0000000000 --- a/src/com/vaadin/external/json/JSONStringer.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.vaadin.external.json; - -/* - Copyright (c) 2006 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -import java.io.StringWriter; - -/** - * JSONStringer provides a quick and convenient way of producing JSON text. The - * texts produced strictly conform to JSON syntax rules. No whitespace is added, - * so the results are ready for transmission or storage. Each instance of - * JSONStringer can produce one JSON text. - * <p> - * A JSONStringer instance provides a <code>value</code> method for appending - * values to the text, and a <code>key</code> method for adding keys before - * values in objects. There are <code>array</code> and <code>endArray</code> - * methods that make and bound array values, and <code>object</code> and - * <code>endObject</code> methods which make and bound object values. All of - * these methods return the JSONWriter instance, permitting cascade style. For - * example, - * - * <pre> - * myString = new JSONStringer().object().key("JSON").value("Hello, World!") - * .endObject().toString(); - * </pre> - * - * which produces the string - * - * <pre> - * {"JSON":"Hello, World!"} - * </pre> - * <p> - * The first method called must be <code>array</code> or <code>object</code>. - * There are no methods for adding commas or colons. JSONStringer adds them for - * you. Objects and arrays can be nested up to 20 levels deep. - * <p> - * This can sometimes be easier than using a JSONObject to build a string. - * - * @author JSON.org - * @version 2008-09-18 - */ -public class JSONStringer extends JSONWriter { - /** - * Make a fresh JSONStringer. It can be used to build one JSON text. - */ - public JSONStringer() { - super(new StringWriter()); - } - - /** - * Return the JSON text. This method is used to obtain the product of the - * JSONStringer instance. It will return <code>null</code> if there was a - * problem in the construction of the JSON text (such as the calls to - * <code>array</code> were not properly balanced with calls to - * <code>endArray</code>). - * - * @return The JSON text. - */ - @Override - public String toString() { - return this.mode == 'd' ? this.writer.toString() : null; - } -} diff --git a/src/com/vaadin/external/json/JSONTokener.java b/src/com/vaadin/external/json/JSONTokener.java deleted file mode 100644 index c3531cae1d..0000000000 --- a/src/com/vaadin/external/json/JSONTokener.java +++ /dev/null @@ -1,451 +0,0 @@ -package com.vaadin.external.json; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.Serializable; -import java.io.StringReader; - -/* - Copyright (c) 2002 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * A JSONTokener takes a source string and extracts characters and tokens from - * it. It is used by the JSONObject and JSONArray constructors to parse JSON - * source strings. - * - * @author JSON.org - * @version 2010-12-24 - */ -public class JSONTokener implements Serializable { - - private int character; - private boolean eof; - private int index; - private int line; - private char previous; - private Reader reader; - private boolean usePrevious; - - /** - * Construct a JSONTokener from a Reader. - * - * @param reader - * A reader. - */ - public JSONTokener(Reader reader) { - this.reader = reader.markSupported() ? reader : new BufferedReader( - reader); - eof = false; - usePrevious = false; - previous = 0; - index = 0; - character = 1; - line = 1; - } - - /** - * Construct a JSONTokener from an InputStream. - */ - public JSONTokener(InputStream inputStream) throws JSONException { - this(new InputStreamReader(inputStream)); - } - - /** - * Construct a JSONTokener from a string. - * - * @param s - * A source string. - */ - public JSONTokener(String s) { - this(new StringReader(s)); - } - - /** - * Back up one character. This provides a sort of lookahead capability, so - * that you can test for a digit or letter before attempting to parse the - * next number or identifier. - */ - public void back() throws JSONException { - if (usePrevious || index <= 0) { - throw new JSONException("Stepping back two steps is not supported"); - } - index -= 1; - character -= 1; - usePrevious = true; - eof = false; - } - - /** - * Get the hex value of a character (base16). - * - * @param c - * A character between '0' and '9' or between 'A' and 'F' or - * between 'a' and 'f'. - * @return An int between 0 and 15, or -1 if c was not a hex digit. - */ - public static int dehexchar(char c) { - if (c >= '0' && c <= '9') { - return c - '0'; - } - if (c >= 'A' && c <= 'F') { - return c - ('A' - 10); - } - if (c >= 'a' && c <= 'f') { - return c - ('a' - 10); - } - return -1; - } - - public boolean end() { - return eof && !usePrevious; - } - - /** - * Determine if the source string still contains characters that next() can - * consume. - * - * @return true if not yet at the end of the source. - */ - public boolean more() throws JSONException { - next(); - if (end()) { - return false; - } - back(); - return true; - } - - /** - * Get the next character in the source string. - * - * @return The next character, or 0 if past the end of the source string. - */ - public char next() throws JSONException { - int c; - if (usePrevious) { - usePrevious = false; - c = previous; - } else { - try { - c = reader.read(); - } catch (IOException exception) { - throw new JSONException(exception); - } - - if (c <= 0) { // End of stream - eof = true; - c = 0; - } - } - index += 1; - if (previous == '\r') { - line += 1; - character = c == '\n' ? 0 : 1; - } else if (c == '\n') { - line += 1; - character = 0; - } else { - character += 1; - } - previous = (char) c; - return previous; - } - - /** - * Consume the next character, and check that it matches a specified - * character. - * - * @param c - * The character to match. - * @return The character. - * @throws JSONException - * if the character does not match. - */ - public char next(char c) throws JSONException { - char n = next(); - if (n != c) { - throw syntaxError("Expected '" + c + "' and instead saw '" + n - + "'"); - } - return n; - } - - /** - * Get the next n characters. - * - * @param n - * The number of characters to take. - * @return A string of n characters. - * @throws JSONException - * Substring bounds error if there are not n characters - * remaining in the source string. - */ - public String next(int n) throws JSONException { - if (n == 0) { - return ""; - } - - char[] chars = new char[n]; - int pos = 0; - - while (pos < n) { - chars[pos] = next(); - if (end()) { - throw syntaxError("Substring bounds error"); - } - pos += 1; - } - return new String(chars); - } - - /** - * Get the next char in the string, skipping whitespace. - * - * @throws JSONException - * @return A character, or 0 if there are no more characters. - */ - public char nextClean() throws JSONException { - for (;;) { - char c = next(); - if (c == 0 || c > ' ') { - return c; - } - } - } - - /** - * Return the characters up to the next close quote character. Backslash - * processing is done. The formal JSON format does not allow strings in - * single quotes, but an implementation is allowed to accept them. - * - * @param quote - * The quoting character, either <code>"</code> - * <small>(double quote)</small> or <code>'</code> - * <small>(single quote)</small>. - * @return A String. - * @throws JSONException - * Unterminated string. - */ - public String nextString(char quote) throws JSONException { - char c; - StringBuffer sb = new StringBuffer(); - for (;;) { - c = next(); - switch (c) { - case 0: - case '\n': - case '\r': - throw syntaxError("Unterminated string"); - case '\\': - c = next(); - switch (c) { - case 'b': - sb.append('\b'); - break; - case 't': - sb.append('\t'); - break; - case 'n': - sb.append('\n'); - break; - case 'f': - sb.append('\f'); - break; - case 'r': - sb.append('\r'); - break; - case 'u': - sb.append((char) Integer.parseInt(next(4), 16)); - break; - case '"': - case '\'': - case '\\': - case '/': - sb.append(c); - break; - default: - throw syntaxError("Illegal escape."); - } - break; - default: - if (c == quote) { - return sb.toString(); - } - sb.append(c); - } - } - } - - /** - * Get the text up but not including the specified character or the end of - * line, whichever comes first. - * - * @param delimiter - * A delimiter character. - * @return A string. - */ - public String nextTo(char delimiter) throws JSONException { - StringBuffer sb = new StringBuffer(); - for (;;) { - char c = next(); - if (c == delimiter || c == 0 || c == '\n' || c == '\r') { - if (c != 0) { - back(); - } - return sb.toString().trim(); - } - sb.append(c); - } - } - - /** - * Get the text up but not including one of the specified delimiter - * characters or the end of line, whichever comes first. - * - * @param delimiters - * A set of delimiter characters. - * @return A string, trimmed. - */ - public String nextTo(String delimiters) throws JSONException { - char c; - StringBuffer sb = new StringBuffer(); - for (;;) { - c = next(); - if (delimiters.indexOf(c) >= 0 || c == 0 || c == '\n' || c == '\r') { - if (c != 0) { - back(); - } - return sb.toString().trim(); - } - sb.append(c); - } - } - - /** - * Get the next value. The value can be a Boolean, Double, Integer, - * JSONArray, JSONObject, Long, or String, or the JSONObject.NULL object. - * - * @throws JSONException - * If syntax error. - * - * @return An object. - */ - public Object nextValue() throws JSONException { - char c = nextClean(); - String string; - - switch (c) { - case '"': - case '\'': - return nextString(c); - case '{': - back(); - return new JSONObject(this); - case '[': - back(); - return new JSONArray(this); - } - - /* - * Handle unquoted text. This could be the values true, false, or null, - * or it can be a number. An implementation (such as this one) is - * allowed to also accept non-standard forms. - * - * Accumulate characters until we reach the end of the text or a - * formatting character. - */ - - StringBuffer sb = new StringBuffer(); - while (c >= ' ' && ",:]}/\\\"[{;=#".indexOf(c) < 0) { - sb.append(c); - c = next(); - } - back(); - - string = sb.toString().trim(); - if (string.equals("")) { - throw syntaxError("Missing value"); - } - return JSONObject.stringToValue(string); - } - - /** - * Skip characters until the next character is the requested character. If - * the requested character is not found, no characters are skipped. - * - * @param to - * A character to skip to. - * @return The requested character, or zero if the requested character is - * not found. - */ - public char skipTo(char to) throws JSONException { - char c; - try { - int startIndex = index; - int startCharacter = character; - int startLine = line; - reader.mark(Integer.MAX_VALUE); - do { - c = next(); - if (c == 0) { - reader.reset(); - index = startIndex; - character = startCharacter; - line = startLine; - return c; - } - } while (c != to); - } catch (IOException exc) { - throw new JSONException(exc); - } - - back(); - return c; - } - - /** - * Make a JSONException to signal a syntax error. - * - * @param message - * The error message. - * @return A JSONException object, suitable for throwing - */ - public JSONException syntaxError(String message) { - return new JSONException(message + toString()); - } - - /** - * Make a printable string of this JSONTokener. - * - * @return " at {index} [character {character} line {line}]" - */ - @Override - public String toString() { - return " at " + index + " [character " + character + " line " + line - + "]"; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/external/json/JSONWriter.java b/src/com/vaadin/external/json/JSONWriter.java deleted file mode 100644 index 5f9ddeeae2..0000000000 --- a/src/com/vaadin/external/json/JSONWriter.java +++ /dev/null @@ -1,355 +0,0 @@ -package com.vaadin.external.json; - -import java.io.IOException; -import java.io.Serializable; -import java.io.Writer; - -/* - Copyright (c) 2006 JSON.org - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in all - copies or substantial portions of the Software. - - The Software shall be used for Good, not Evil. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - SOFTWARE. - */ - -/** - * JSONWriter provides a quick and convenient way of producing JSON text. The - * texts produced strictly conform to JSON syntax rules. No whitespace is added, - * so the results are ready for transmission or storage. Each instance of - * JSONWriter can produce one JSON text. - * <p> - * A JSONWriter instance provides a <code>value</code> method for appending - * values to the text, and a <code>key</code> method for adding keys before - * values in objects. There are <code>array</code> and <code>endArray</code> - * methods that make and bound array values, and <code>object</code> and - * <code>endObject</code> methods which make and bound object values. All of - * these methods return the JSONWriter instance, permitting a cascade style. For - * example, - * - * <pre> - * new JSONWriter(myWriter).object().key("JSON").value("Hello, World!") - * .endObject(); - * </pre> - * - * which writes - * - * <pre> - * {"JSON":"Hello, World!"} - * </pre> - * <p> - * The first method called must be <code>array</code> or <code>object</code>. - * There are no methods for adding commas or colons. JSONWriter adds them for - * you. Objects and arrays can be nested up to 20 levels deep. - * <p> - * This can sometimes be easier than using a JSONObject to build a string. - * - * @author JSON.org - * @version 2011-11-14 - */ -public class JSONWriter implements Serializable { - private static final int maxdepth = 200; - - /** - * The comma flag determines if a comma should be output before the next - * value. - */ - private boolean comma; - - /** - * The current mode. Values: 'a' (array), 'd' (done), 'i' (initial), 'k' - * (key), 'o' (object). - */ - protected char mode; - - /** - * The object/array stack. - */ - private final JSONObject stack[]; - - /** - * The stack top index. A value of 0 indicates that the stack is empty. - */ - private int top; - - /** - * The writer that will receive the output. - */ - protected Writer writer; - - /** - * Make a fresh JSONWriter. It can be used to build one JSON text. - */ - public JSONWriter(Writer w) { - comma = false; - mode = 'i'; - stack = new JSONObject[maxdepth]; - top = 0; - writer = w; - } - - /** - * Append a value. - * - * @param string - * A string value. - * @return this - * @throws JSONException - * If the value is out of sequence. - */ - private JSONWriter append(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null pointer"); - } - if (mode == 'o' || mode == 'a') { - try { - if (comma && mode == 'a') { - writer.write(','); - } - writer.write(string); - } catch (IOException e) { - throw new JSONException(e); - } - if (mode == 'o') { - mode = 'k'; - } - comma = true; - return this; - } - throw new JSONException("Value out of sequence."); - } - - /** - * Begin appending a new array. All values until the balancing - * <code>endArray</code> will be appended to this array. The - * <code>endArray</code> method must be called to mark the array's end. - * - * @return this - * @throws JSONException - * If the nesting is too deep, or if the object is started in - * the wrong place (for example as a key or after the end of the - * outermost array or object). - */ - public JSONWriter array() throws JSONException { - if (mode == 'i' || mode == 'o' || mode == 'a') { - push(null); - append("["); - comma = false; - return this; - } - throw new JSONException("Misplaced array."); - } - - /** - * End something. - * - * @param mode - * Mode - * @param c - * Closing character - * @return this - * @throws JSONException - * If unbalanced. - */ - private JSONWriter end(char mode, char c) throws JSONException { - if (this.mode != mode) { - throw new JSONException(mode == 'a' ? "Misplaced endArray." - : "Misplaced endObject."); - } - pop(mode); - try { - writer.write(c); - } catch (IOException e) { - throw new JSONException(e); - } - comma = true; - return this; - } - - /** - * End an array. This method most be called to balance calls to - * <code>array</code>. - * - * @return this - * @throws JSONException - * If incorrectly nested. - */ - public JSONWriter endArray() throws JSONException { - return end('a', ']'); - } - - /** - * End an object. This method most be called to balance calls to - * <code>object</code>. - * - * @return this - * @throws JSONException - * If incorrectly nested. - */ - public JSONWriter endObject() throws JSONException { - return end('k', '}'); - } - - /** - * Append a key. The key will be associated with the next value. In an - * object, every value must be preceded by a key. - * - * @param string - * A key string. - * @return this - * @throws JSONException - * If the key is out of place. For example, keys do not belong - * in arrays or if the key is null. - */ - public JSONWriter key(String string) throws JSONException { - if (string == null) { - throw new JSONException("Null key."); - } - if (mode == 'k') { - try { - stack[top - 1].putOnce(string, Boolean.TRUE); - if (comma) { - writer.write(','); - } - writer.write(JSONObject.quote(string)); - writer.write(':'); - comma = false; - mode = 'o'; - return this; - } catch (IOException e) { - throw new JSONException(e); - } - } - throw new JSONException("Misplaced key."); - } - - /** - * Begin appending a new object. All keys and values until the balancing - * <code>endObject</code> will be appended to this object. The - * <code>endObject</code> method must be called to mark the object's end. - * - * @return this - * @throws JSONException - * If the nesting is too deep, or if the object is started in - * the wrong place (for example as a key or after the end of the - * outermost array or object). - */ - public JSONWriter object() throws JSONException { - if (mode == 'i') { - mode = 'o'; - } - if (mode == 'o' || mode == 'a') { - append("{"); - push(new JSONObject()); - comma = false; - return this; - } - throw new JSONException("Misplaced object."); - - } - - /** - * Pop an array or object scope. - * - * @param c - * The scope to close. - * @throws JSONException - * If nesting is wrong. - */ - private void pop(char c) throws JSONException { - if (top <= 0) { - throw new JSONException("Nesting error."); - } - char m = stack[top - 1] == null ? 'a' : 'k'; - if (m != c) { - throw new JSONException("Nesting error."); - } - top -= 1; - mode = top == 0 ? 'd' : stack[top - 1] == null ? 'a' : 'k'; - } - - /** - * Push an array or object scope. - * - * @param c - * The scope to open. - * @throws JSONException - * If nesting is too deep. - */ - private void push(JSONObject jo) throws JSONException { - if (top >= maxdepth) { - throw new JSONException("Nesting too deep."); - } - stack[top] = jo; - mode = jo == null ? 'a' : 'k'; - top += 1; - } - - /** - * Append either the value <code>true</code> or the value <code>false</code> - * . - * - * @param b - * A boolean. - * @return this - * @throws JSONException - */ - public JSONWriter value(boolean b) throws JSONException { - return append(b ? "true" : "false"); - } - - /** - * Append a double value. - * - * @param d - * A double. - * @return this - * @throws JSONException - * If the number is not finite. - */ - public JSONWriter value(double d) throws JSONException { - return this.value(new Double(d)); - } - - /** - * Append a long value. - * - * @param l - * A long. - * @return this - * @throws JSONException - */ - public JSONWriter value(long l) throws JSONException { - return append(Long.toString(l)); - } - - /** - * Append an object value. - * - * @param object - * The object to append. It can be null, or a Boolean, Number, - * String, JSONObject, or JSONArray, or an object that implements - * JSONString. - * @return this - * @throws JSONException - * If the value is out of sequence. - */ - public JSONWriter value(Object object) throws JSONException { - return append(JSONObject.valueToString(object)); - } -} diff --git a/src/com/vaadin/external/json/README b/src/com/vaadin/external/json/README deleted file mode 100644 index ca6dc11764..0000000000 --- a/src/com/vaadin/external/json/README +++ /dev/null @@ -1,68 +0,0 @@ -JSON in Java [package org.json] - -Douglas Crockford -douglas@crockford.com - -2011-02-02 - - -JSON is a light-weight, language independent, data interchange format. -See http://www.JSON.org/ - -The files in this package implement JSON encoders/decoders in Java. -It also includes the capability to convert between JSON and XML, HTTP -headers, Cookies, and CDL. - -This is a reference implementation. There is a large number of JSON packages -in Java. Perhaps someday the Java community will standardize on one. Until -then, choose carefully. - -The license includes this restriction: "The software shall be used for good, -not evil." If your conscience cannot live with that, then choose a different -package. - -The package compiles on Java 1.2 thru Java 1.4. - - -JSONObject.java: The JSONObject can parse text from a String or a JSONTokener -to produce a map-like object. The object provides methods for manipulating its -contents, and for producing a JSON compliant object serialization. - -JSONArray.java: The JSONObject can parse text from a String or a JSONTokener -to produce a vector-like object. The object provides methods for manipulating -its contents, and for producing a JSON compliant array serialization. - -JSONTokener.java: The JSONTokener breaks a text into a sequence of individual -tokens. It can be constructed from a String, Reader, or InputStream. - -JSONException.java: The JSONException is the standard exception type thrown -by this package. - - -JSONString.java: The JSONString interface requires a toJSONString method, -allowing an object to provide its own serialization. - -JSONStringer.java: The JSONStringer provides a convenient facility for -building JSON strings. - -JSONWriter.java: The JSONWriter provides a convenient facility for building -JSON text through a writer. - - -CDL.java: CDL provides support for converting between JSON and comma -delimited lists. - -Cookie.java: Cookie provides support for converting between JSON and cookies. - -CookieList.java: CookieList provides support for converting between JSON and -cookie lists. - -HTTP.java: HTTP provides support for converting between JSON and HTTP headers. - -HTTPTokener.java: HTTPTokener extends JSONTokener for parsing HTTP headers. - -XML.java: XML provides support for converting between JSON and XML. - -JSONML.java: JSONML provides support for converting between JSONML and XML. - -XMLTokener.java: XMLTokener extends JSONTokener for parsing XML text.
\ No newline at end of file diff --git a/src/com/vaadin/navigator/FragmentManager.java b/src/com/vaadin/navigator/FragmentManager.java deleted file mode 100644 index f1fd90e569..0000000000 --- a/src/com/vaadin/navigator/FragmentManager.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.navigator; - -import java.io.Serializable; - -/** - * Fragment manager that handles interaction between Navigator and URI fragments - * or other similar view identification and bookmarking system. - * - * Alternative implementations can be created for HTML5 pushState, for portlet - * URL navigation and other similar systems. - * - * This interface is mostly for internal use by {@link Navigator}. - * - * @author Vaadin Ltd - * @since 7.0 - */ -public interface FragmentManager extends Serializable { - /** - * Return the current fragment (location string) including view name and any - * optional parameters. - * - * @return current view and parameter string, not null - */ - public String getFragment(); - - /** - * Set the current fragment (location string) in the application URL or - * similar location, including view name and any optional parameters. - * - * @param fragment - * new view and parameter string, not null - */ - public void setFragment(String fragment); -}
\ No newline at end of file diff --git a/src/com/vaadin/navigator/Navigator.java b/src/com/vaadin/navigator/Navigator.java deleted file mode 100644 index 1813301fe6..0000000000 --- a/src/com/vaadin/navigator/Navigator.java +++ /dev/null @@ -1,656 +0,0 @@ -package com.vaadin.navigator; - -/* - @VaadinApache2LicenseForJavaFiles@ - */ - -import java.io.Serializable; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import com.vaadin.navigator.ViewChangeListener.ViewChangeEvent; -import com.vaadin.terminal.Page; -import com.vaadin.terminal.Page.FragmentChangedEvent; -import com.vaadin.terminal.Page.FragmentChangedListener; -import com.vaadin.ui.Component; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.CssLayout; -import com.vaadin.ui.CustomComponent; - -/** - * Navigator utility that allows switching of views in a part of an application. - * - * The view switching can be based e.g. on URI fragments containing the view - * name and parameters to the view. There are two types of parameters for views: - * an optional parameter string that is included in the fragment (may be - * bookmarkable). - * - * Views can be explicitly registered or dynamically generated and listening to - * view changes is possible. - * - * Note that {@link Navigator} is not a component itself but comes with - * {@link SimpleViewDisplay} which is a component that displays the selected - * view as its contents. - * - * @author Vaadin Ltd - * @since 7.0 - */ -public class Navigator implements Serializable { - - // TODO divert navigation e.g. if no permissions? Or just show another view - // but keep URL? how best to intercept - // TODO investigate relationship with TouchKit navigation support - - /** - * Empty view component. - */ - public static class EmptyView extends CssLayout implements View { - /** - * Create minimally sized empty view. - */ - public EmptyView() { - setWidth("0px"); - setHeight("0px"); - } - - @Override - public void navigateTo(String fragmentParameters) { - // nothing to do - } - } - - /** - * Fragment manager using URI fragments of a Page to track views and enable - * listening to view changes. - * - * This class is mostly for internal use by Navigator, and is only public - * and static to enable testing. - */ - public static class UriFragmentManager implements FragmentManager, - FragmentChangedListener { - private final Page page; - private final Navigator navigator; - - /** - * Create a new URIFragmentManager and attach it to listen to URI - * fragment changes of a {@link Page}. - * - * @param page - * page whose URI fragment to get and modify - * @param navigator - * {@link Navigator} to notify of fragment changes (using - * {@link Navigator#navigateTo(String)} - */ - public UriFragmentManager(Page page, Navigator navigator) { - this.page = page; - this.navigator = navigator; - - page.addListener(this); - } - - @Override - public String getFragment() { - return page.getFragment(); - } - - @Override - public void setFragment(String fragment) { - page.setFragment(fragment, false); - } - - @Override - public void fragmentChanged(FragmentChangedEvent event) { - UriFragmentManager.this.navigator.navigateTo(getFragment()); - } - } - - /** - * View display that is a component itself and replaces its contents with - * the view. - * - * This display only supports views that are {@link Component}s themselves. - * Attempting to display a view that is not a component causes an exception - * to be thrown. - * - * By default, the view display has full size. - */ - public static class SimpleViewDisplay extends CustomComponent implements - ViewDisplay { - - /** - * Create new {@link ViewDisplay} that is itself a component displaying - * the view. - */ - public SimpleViewDisplay() { - setSizeFull(); - } - - @Override - public void showView(View view) { - if (view instanceof Component) { - setCompositionRoot((Component) view); - } else { - throw new IllegalArgumentException("View is not a component: " - + view); - } - } - } - - /** - * View display that replaces the contents of a {@link ComponentContainer} - * with the active {@link View}. - * - * All components of the container are removed before adding the new view to - * it. - * - * This display only supports views that are {@link Component}s themselves. - * Attempting to display a view that is not a component causes an exception - * to be thrown. - */ - public static class ComponentContainerViewDisplay implements ViewDisplay { - - private final ComponentContainer container; - - /** - * Create new {@link ViewDisplay} that updates a - * {@link ComponentContainer} to show the view. - */ - public ComponentContainerViewDisplay(ComponentContainer container) { - this.container = container; - } - - @Override - public void showView(View view) { - if (view instanceof Component) { - container.removeAllComponents(); - container.addComponent((Component) view); - } else { - throw new IllegalArgumentException("View is not a component: " - + view); - } - } - } - - /** - * View provider which supports mapping a single view name to a single - * pre-initialized view instance. - * - * For most cases, ClassBasedViewProvider should be used instead of this. - */ - public static class StaticViewProvider implements ViewProvider { - private final String viewName; - private final View view; - - /** - * Create a new view provider which returns a pre-created view instance. - * - * @param viewName - * name of the view (not null) - * @param view - * view instance to return (not null), reused on every - * request - */ - public StaticViewProvider(String viewName, View view) { - this.viewName = viewName; - this.view = view; - } - - @Override - public String getViewName(String viewAndParameters) { - if (null == viewAndParameters) { - return null; - } - if (viewAndParameters.startsWith(viewName)) { - return viewName; - } - return null; - } - - @Override - public View getView(String viewName) { - if (this.viewName.equals(viewName)) { - return view; - } - return null; - } - - /** - * Get the view name for this provider. - * - * @return view name for this provider - */ - public String getViewName() { - return viewName; - } - } - - /** - * View provider which maps a single view name to a class to instantiate for - * the view. - * - * Note that the view class must be accessible by the class loader used by - * the provider. This may require its visibility to be public. - * - * This class is primarily for internal use by {@link Navigator}. - */ - public static class ClassBasedViewProvider implements ViewProvider { - - private final String viewName; - private final Class<? extends View> viewClass; - - /** - * Create a new view provider which creates new view instances based on - * a view class. - * - * @param viewName - * name of the views to create (not null) - * @param viewClass - * class to instantiate when a view is requested (not null) - */ - public ClassBasedViewProvider(String viewName, - Class<? extends View> viewClass) { - if (null == viewName || null == viewClass) { - throw new IllegalArgumentException( - "View name and class should not be null"); - } - this.viewName = viewName; - this.viewClass = viewClass; - } - - @Override - public String getViewName(String viewAndParameters) { - if (null == viewAndParameters) { - return null; - } - if (viewAndParameters.equals(viewName) - || viewAndParameters.startsWith(viewName + "/")) { - return viewName; - } - return null; - } - - @Override - public View getView(String viewName) { - if (this.viewName.equals(viewName)) { - try { - View view = viewClass.newInstance(); - return view; - } catch (InstantiationException e) { - // TODO error handling - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - // TODO error handling - throw new RuntimeException(e); - } - } - return null; - } - - /** - * Get the view name for this provider. - * - * @return view name for this provider - */ - public String getViewName() { - return viewName; - } - - /** - * Get the view class for this provider. - * - * @return {@link View} class - */ - public Class<? extends View> getViewClass() { - return viewClass; - } - } - - private final FragmentManager fragmentManager; - private final ViewDisplay display; - private View currentView = null; - private List<ViewChangeListener> listeners = new LinkedList<ViewChangeListener>(); - private List<ViewProvider> providers = new LinkedList<ViewProvider>(); - - /** - * Create a navigator that is tracking the active view using URI fragments - * of the current {@link Page} and replacing the contents of a - * {@link ComponentContainer} with the active view. - * - * In case the container is not on the current page, use another - * {@link Navigator#Navigator(Page, ViewDisplay)} with an explicitly created - * {@link ComponentContainerViewDisplay}. - * - * All components of the container are removed each time before adding the - * active {@link View}. Views must implement {@link Component} when using - * this constructor. - * - * <p> - * After all {@link View}s and {@link ViewProvider}s have been registered, - * the application should trigger navigation to the current fragment using - * e.g. - * - * <pre> - * navigator.navigateTo(Page.getCurrent().getFragment()); - * </pre> - * - * @param container - * ComponentContainer whose contents should be replaced with the - * active view on view change - */ - public Navigator(ComponentContainer container) { - display = new ComponentContainerViewDisplay(container); - fragmentManager = new UriFragmentManager(Page.getCurrent(), this); - } - - /** - * Create a navigator that is tracking the active view using URI fragments. - * - * <p> - * After all {@link View}s and {@link ViewProvider}s have been registered, - * the application should trigger navigation to the current fragment using - * e.g. - * - * <pre> - * navigator.navigateTo(Page.getCurrent().getFragment()); - * </pre> - * - * @param page - * whose URI fragments are used - * @param display - * where to display the views - */ - public Navigator(Page page, ViewDisplay display) { - this.display = display; - fragmentManager = new UriFragmentManager(page, this); - } - - /** - * Create a navigator. - * - * When a custom fragment manager is not needed, use the constructor - * {@link #Navigator(Page, ViewDisplay)} which uses a URI fragment based - * fragment manager. - * - * Note that navigation to the initial view must be performed explicitly by - * the application after creating a Navigator using this constructor. - * - * @param fragmentManager - * fragment manager keeping track of the active view and enabling - * bookmarking and direct navigation - * @param display - * where to display the views - */ - public Navigator(FragmentManager fragmentManager, ViewDisplay display) { - this.display = display; - this.fragmentManager = fragmentManager; - } - - /** - * Navigate to a view and initialize the view with given parameters. - * - * The view string consists of a view name optionally followed by a slash - * and (fragment) parameters. ViewProviders are used to find and create the - * correct type of view. - * - * If multiple providers return a matching view, the view with the longest - * name is selected. This way, e.g. hierarchies of subviews can be - * registered like "admin/", "admin/users", "admin/settings" and the longest - * match is used. - * - * If the view being deactivated indicates it wants a confirmation for the - * navigation operation, the user is asked for the confirmation. - * - * Registered {@link ViewChangeListener}s are called upon successful view - * change. - * - * @param viewAndParameters - * view name and parameters - */ - public void navigateTo(String viewAndParameters) { - String longestViewName = null; - View viewWithLongestName = null; - for (ViewProvider provider : providers) { - String viewName = provider.getViewName(viewAndParameters); - if (null != viewName - && (longestViewName == null || viewName.length() > longestViewName - .length())) { - View view = provider.getView(viewName); - if (null != view) { - longestViewName = viewName; - viewWithLongestName = view; - } - } - } - if (viewWithLongestName != null) { - String parameters = null; - if (viewAndParameters.length() > longestViewName.length() + 1) { - parameters = viewAndParameters.substring(longestViewName - .length() + 1); - } - navigateTo(viewWithLongestName, longestViewName, parameters); - } - // TODO if no view is found, what to do? - } - - /** - * Internal method activating a view, setting its parameters and calling - * listeners. - * - * This method also verifies that the user is allowed to perform the - * navigation operation. - * - * @param view - * view to activate - * @param viewName - * (optional) name of the view or null not to set the fragment - * @param fragmentParameters - * parameters passed in the fragment for the view - */ - protected void navigateTo(View view, String viewName, - String fragmentParameters) { - ViewChangeEvent event = new ViewChangeEvent(this, currentView, view, - viewName, fragmentParameters); - if (!isViewChangeAllowed(event)) { - return; - } - - if (null != viewName && getFragmentManager() != null) { - String currentFragment = viewName; - if (fragmentParameters != null) { - currentFragment += "/" + fragmentParameters; - } - if (!currentFragment.equals(getFragmentManager().getFragment())) { - getFragmentManager().setFragment(currentFragment); - } - } - - view.navigateTo(fragmentParameters); - currentView = view; - - if (display != null) { - display.showView(view); - } - - fireViewChange(event); - } - - /** - * Check whether view change is allowed. - * - * All related listeners are called. The view change is blocked if any of - * them wants to block the navigation operation. - * - * The view change listeners may also e.g. open a warning or question dialog - * and save the parameters to re-initiate the navigation operation upon user - * action. - * - * @param event - * view change event (not null, view change not yet performed) - * @return true if the view change should be allowed, false to silently - * block the navigation operation - */ - protected boolean isViewChangeAllowed(ViewChangeEvent event) { - for (ViewChangeListener l : listeners) { - if (!l.isViewChangeAllowed(event)) { - return false; - } - } - return true; - } - - /** - * Return the fragment manager that is used to get, listen to and manipulate - * the URI fragment or other source of navigation information. - * - * @return fragment manager in use - */ - protected FragmentManager getFragmentManager() { - return fragmentManager; - } - - /** - * Returns the ViewDisplay used by the navigator. Unless another display is - * specified, a {@link SimpleViewDisplay} (which is a {@link Component}) is - * used by default. - * - * @return current ViewDisplay - */ - public ViewDisplay getDisplay() { - return display; - } - - /** - * Fire an event when the current view has changed. - * - * @param event - * view change event (not null) - */ - protected void fireViewChange(ViewChangeEvent event) { - for (ViewChangeListener l : listeners) { - l.navigatorViewChanged(event); - } - } - - /** - * Register a static, pre-initialized view instance for a view name. - * - * Registering another view with a name that is already registered - * overwrites the old registration of the same type. - * - * @param viewName - * String that identifies a view (not null nor empty string) - * @param view - * {@link View} instance (not null) - */ - public void addView(String viewName, View view) { - - // Check parameters - if (viewName == null || view == null) { - throw new IllegalArgumentException( - "view and viewName must be non-null"); - } - - removeView(viewName); - registerProvider(new StaticViewProvider(viewName, view)); - } - - /** - * Register for a view name a view class. - * - * Registering another view with a name that is already registered - * overwrites the old registration of the same type. - * - * A new view instance is created every time a view is requested. - * - * @param viewName - * String that identifies a view (not null nor empty string) - * @param viewClass - * {@link View} class to instantiate when a view is requested - * (not null) - */ - public void addView(String viewName, Class<? extends View> viewClass) { - - // Check parameters - if (viewName == null || viewClass == null) { - throw new IllegalArgumentException( - "view and viewClass must be non-null"); - } - - removeView(viewName); - registerProvider(new ClassBasedViewProvider(viewName, viewClass)); - } - - /** - * Remove view from navigator. - * - * This method only applies to views registered using - * {@link #addView(String, View)} or {@link #addView(String, Class)}. - * - * @param viewName - * name of the view to remove - */ - public void removeView(String viewName) { - Iterator<ViewProvider> it = providers.iterator(); - while (it.hasNext()) { - ViewProvider provider = it.next(); - if (provider instanceof StaticViewProvider) { - StaticViewProvider staticProvider = (StaticViewProvider) provider; - if (staticProvider.getViewName().equals(viewName)) { - it.remove(); - } - } else if (provider instanceof ClassBasedViewProvider) { - ClassBasedViewProvider classBasedProvider = (ClassBasedViewProvider) provider; - if (classBasedProvider.getViewName().equals(viewName)) { - it.remove(); - } - } - } - } - - /** - * Register a view provider (factory). - * - * Providers are called in order of registration until one that can handle - * the requested view name is found. - * - * @param provider - * provider to register - */ - public void registerProvider(ViewProvider provider) { - providers.add(provider); - } - - /** - * Unregister a view provider (factory). - * - * @param provider - * provider to unregister - */ - public void unregisterProvider(ViewProvider provider) { - providers.remove(provider); - } - - /** - * Listen to changes of the active view. - * - * The listener will get notified after the view has changed. - * - * @param listener - * Listener to invoke after view changes. - */ - public void addListener(ViewChangeListener listener) { - listeners.add(listener); - } - - /** - * Remove a view change listener. - * - * @param listener - * Listener to remove. - */ - public void removeListener(ViewChangeListener listener) { - listeners.remove(listener); - } - -} diff --git a/src/com/vaadin/navigator/View.java b/src/com/vaadin/navigator/View.java deleted file mode 100644 index 4d135b4c0b..0000000000 --- a/src/com/vaadin/navigator/View.java +++ /dev/null @@ -1,36 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.navigator; - -import java.io.Serializable; - -import com.vaadin.ui.Component; - -/** - * Interface for all views controlled by the navigator. - * - * Each view added to the navigator must implement this interface. Typically, a - * view is a {@link Component}. - * - * @author Vaadin Ltd - * @since 7.0 - */ -public interface View extends Serializable { - - /** - * This view is navigated to. - * - * This method is always called before the view is shown on screen. If there - * is any additional id to data what should be shown in the view, it is also - * optionally passed as parameter. - * - * TODO fragmentParameters null if no parameters or empty string? - * - * @param fragmentParameters - * parameters to the view or null if none given. This is the - * string that appears e.g. in URI after "viewname/" - */ - public void navigateTo(String fragmentParameters); -}
\ No newline at end of file diff --git a/src/com/vaadin/navigator/ViewChangeListener.java b/src/com/vaadin/navigator/ViewChangeListener.java deleted file mode 100644 index 2eb34e6fcf..0000000000 --- a/src/com/vaadin/navigator/ViewChangeListener.java +++ /dev/null @@ -1,118 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.navigator; - -import java.io.Serializable; -import java.util.EventObject; - -/** - * Interface for listening to View changes before and after they occur. - * - * Implementations of this interface can also block navigation between views - * before it is performed. - * - * @author Vaadin Ltd - * @since 7.0 - */ -public interface ViewChangeListener extends Serializable { - - /** - * Event received by the listener for attempted and executed view changes. - */ - public static class ViewChangeEvent extends EventObject { - private final View oldView; - private final View newView; - private final String viewName; - private final String fragmentParameters; - - /** - * Create a new view change event. - * - * @param navigator - * Navigator that triggered the event, not null - */ - public ViewChangeEvent(Navigator navigator, View oldView, View newView, - String viewName, String fragmentParameters) { - super(navigator); - this.oldView = oldView; - this.newView = newView; - this.viewName = viewName; - this.fragmentParameters = fragmentParameters; - } - - /** - * Returns the navigator that triggered this event. - * - * @return Navigator (not null) - */ - public Navigator getNavigator() { - return (Navigator) getSource(); - } - - /** - * Returns the view being deactivated. - * - * @return old View - */ - public View getOldView() { - return oldView; - } - - /** - * Returns the view being activated. - * - * @return new View - */ - public View getNewView() { - return newView; - } - - /** - * Returns the view name of the view being activated. - * - * @return view name of the new View - */ - public String getViewName() { - return viewName; - } - - /** - * Returns the parameters for the view being activated. - * - * @return fragment parameters (potentially bookmarkable) for the new - * view - */ - public String getFragmentParameters() { - return fragmentParameters; - } - } - - /** - * Check whether changing the view is permissible. - * - * This method may also e.g. open a "save" dialog or question about the - * change, which may re-initiate the navigation operation after user action. - * - * If this listener does not want to block the view change (e.g. does not - * know the view in question), it should return true. If any listener - * returns false, the view change is not allowed. - * - * @param event - * view change event - * @return true if the view change should be allowed or this listener does - * not care about the view change, false to block the change - */ - public boolean isViewChangeAllowed(ViewChangeEvent event); - - /** - * Invoked after the view has changed. Be careful for deadlocks if you - * decide to change the view again in the listener. - * - * @param event - * view change event - */ - public void navigatorViewChanged(ViewChangeEvent event); - -}
\ No newline at end of file diff --git a/src/com/vaadin/navigator/ViewDisplay.java b/src/com/vaadin/navigator/ViewDisplay.java deleted file mode 100644 index 6016951394..0000000000 --- a/src/com/vaadin/navigator/ViewDisplay.java +++ /dev/null @@ -1,29 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.navigator; - -import java.io.Serializable; - -/** - * Interface for displaying a view in an appropriate location. - * - * The view display can be a component/layout itself or can modify a separate - * layout. - * - * @author Vaadin Ltd - * @since 7.0 - */ -public interface ViewDisplay extends Serializable { - /** - * Remove previously shown view and show the newly selected view in its - * place. - * - * The parameters for the view have been set before this method is called. - * - * @param view - * new view to show - */ - public void showView(View view); -}
\ No newline at end of file diff --git a/src/com/vaadin/navigator/ViewProvider.java b/src/com/vaadin/navigator/ViewProvider.java deleted file mode 100644 index 4d9d22acab..0000000000 --- a/src/com/vaadin/navigator/ViewProvider.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.navigator; - -import java.io.Serializable; - -/** - * A provider for view instances that can return pre-registered views or - * dynamically create new views. - * - * If multiple providers are used, {@link #getViewName(String)} of each is - * called (in registration order) until one of them returns a non-null value. - * The {@link #getView(String)} method of that provider is then used. - * - * @author Vaadin Ltd - * @since 7.0 - */ -public interface ViewProvider extends Serializable { - /** - * Extract the view name from a combined view name and parameter string. - * This method should return a view name if and only if this provider - * handles creation of such views. - * - * @param viewAndParameters - * string with view name and its fragment parameters (if given), - * not null - * @return view name if the view is handled by this provider, null otherwise - */ - public String getViewName(String viewAndParameters); - - /** - * Create or return a pre-created instance of a view. - * - * The parameters for the view are set separately by the navigator when the - * view is activated. - * - * @param viewName - * name of the view, not null - * @return newly created view (null if none available for the view name) - */ - public View getView(String viewName); -}
\ No newline at end of file diff --git a/src/com/vaadin/package.html b/src/com/vaadin/package.html deleted file mode 100644 index f771019709..0000000000 --- a/src/com/vaadin/package.html +++ /dev/null @@ -1,27 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -</head> - -<body bgcolor="white"> - -<p>The Vaadin base package. Contains the Application class, the -starting point of any application that uses Vaadin.</p> - -<p>Contains all Vaadin core classes. A Vaadin application is based -on the {@link com.vaadin.Application} class and deployed as a servlet -using {@link com.vaadin.terminal.gwt.server.ApplicationServlet} or -{@link com.vaadin.terminal.gwt.server.GAEApplicationServlet} (for Google -App Engine).</p> - -<p>Vaadin applications can also be deployed as portlets using {@link -com.vaadin.terminal.gwt.server.ApplicationPortlet} (JSR-168) or {@link -com.vaadin.terminal.gwt.server.ApplicationPortlet2} (JSR-286).</p> - -<p>All classes in Vaadin are serializable unless otherwise noted. -This allows Vaadin applications to run in cluster and cloud -environments.</p> - - -</body> -</html> diff --git a/src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml b/src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml deleted file mode 100644 index bd91d05b02..0000000000 --- a/src/com/vaadin/portal/gwt/PortalDefaultWidgetSet.gwt.xml +++ /dev/null @@ -1,6 +0,0 @@ -<module> - <!-- WS Compiler: manually edited --> - - <!-- Inherit the DefaultWidgetSet --> - <inherits name="com.vaadin.terminal.gwt.DefaultWidgetSet" /> -</module> diff --git a/src/com/vaadin/service/ApplicationContext.java b/src/com/vaadin/service/ApplicationContext.java deleted file mode 100644 index 71bff7b865..0000000000 --- a/src/com/vaadin/service/ApplicationContext.java +++ /dev/null @@ -1,165 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.service; - -import java.io.File; -import java.io.Serializable; -import java.net.URL; -import java.util.Collection; - -import com.vaadin.Application; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.gwt.server.AbstractCommunicationManager; - -/** - * <code>ApplicationContext</code> provides information about the running - * context of the application. Each context is shared by all applications that - * are open for one user. In a web-environment this corresponds to a - * HttpSession. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.1 - */ -public interface ApplicationContext extends Serializable { - - /** - * Returns application context base directory. - * - * Typically an application is deployed in a such way that is has an - * application directory. For web applications this directory is the root - * directory of the web applications. In some cases applications might not - * have an application directory (for example web applications running - * inside a war). - * - * @return The application base directory or null if the application has no - * base directory. - */ - public File getBaseDirectory(); - - /** - * Returns a collection of all the applications in this context. - * - * Each application context contains all active applications for one user. - * - * @return A collection containing all the applications in this context. - */ - public Collection<Application> getApplications(); - - /** - * Adds a transaction listener to this context. The transaction listener is - * called before and after each each request related to this session except - * when serving static resources. - * - * The transaction listener must not be null. - * - * @see com.vaadin.service.ApplicationContext#addTransactionListener(com.vaadin.service.ApplicationContext.TransactionListener) - */ - public void addTransactionListener(TransactionListener listener); - - /** - * Removes a transaction listener from this context. - * - * @param listener - * the listener to be removed. - * @see TransactionListener - */ - public void removeTransactionListener(TransactionListener listener); - - /** - * Generate a URL that can be used as the relative location of e.g. an - * {@link ApplicationResource}. - * - * This method should only be called from the processing of a UIDL request, - * not from a background thread. The return value is null if used outside a - * suitable request. - * - * @deprecated this method is intended for terminal implementation only and - * is subject to change/removal from the interface (to - * {@link AbstractCommunicationManager}) - * - * @param resource - * @param urlKey - * a key for the resource that can later be extracted from a URL - * with {@link #getURLKey(URL, String)} - */ - @Deprecated - public String generateApplicationResourceURL(ApplicationResource resource, - String urlKey); - - /** - * Tests if a URL is for an application resource (APP/...). - * - * @deprecated this method is intended for terminal implementation only and - * is subject to change/removal from the interface (to - * {@link AbstractCommunicationManager}) - * - * @param context - * @param relativeUri - * @return - */ - @Deprecated - public boolean isApplicationResourceURL(URL context, String relativeUri); - - /** - * Gets the identifier (key) from an application resource URL. This key is - * the one that was given to - * {@link #generateApplicationResourceURL(ApplicationResource, String)} when - * creating the URL. - * - * @deprecated this method is intended for terminal implementation only and - * is subject to change/removal from the interface (to - * {@link AbstractCommunicationManager}) - * - * - * @param context - * @param relativeUri - * @return - */ - @Deprecated - public String getURLKey(URL context, String relativeUri); - - /** - * Interface for listening to transaction events. Implement this interface - * to listen to all transactions between the client and the application. - * - */ - public interface TransactionListener extends Serializable { - - /** - * Invoked at the beginning of every transaction. - * - * The transaction is linked to the context, not the application so if - * you have multiple applications running in the same context you need - * to check that the request is associated with the application you are - * interested in. This can be done looking at the application parameter. - * - * @param application - * the Application object. - * @param transactionData - * the Data identifying the transaction. - */ - public void transactionStart(Application application, - Object transactionData); - - /** - * Invoked at the end of every transaction. - * - * The transaction is linked to the context, not the application so if - * you have multiple applications running in the same context you need - * to check that the request is associated with the application you are - * interested in. This can be done looking at the application parameter. - * - * @param applcation - * the Application object. - * @param transactionData - * the Data identifying the transaction. - */ - public void transactionEnd(Application application, - Object transactionData); - - } -} diff --git a/src/com/vaadin/service/FileTypeResolver.java b/src/com/vaadin/service/FileTypeResolver.java deleted file mode 100644 index c457c16eb4..0000000000 --- a/src/com/vaadin/service/FileTypeResolver.java +++ /dev/null @@ -1,385 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.service; - -import java.io.File; -import java.io.Serializable; -import java.util.Collections; -import java.util.Hashtable; -import java.util.Map; -import java.util.StringTokenizer; - -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.ThemeResource; - -/** - * Utility class that can figure out mime-types and icons related to files. - * <p> - * Note : The icons are associated purely to mime-types, so a file may not have - * a custom icon accessible with this class. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class FileTypeResolver implements Serializable { - - /** - * Default icon given if no icon is specified for a mime-type. - */ - static public Resource DEFAULT_ICON = new ThemeResource( - "../runo/icons/16/document.png"); - - /** - * Default mime-type. - */ - static public String DEFAULT_MIME_TYPE = "application/octet-stream"; - - /** - * Initial file extension to mime-type mapping. - */ - static private String initialExtToMIMEMap = "application/cu-seeme csm cu," - + "application/dsptype tsp," - + "application/futuresplash spl," - + "application/mac-binhex40 hqx," - + "application/msaccess mdb," - + "application/msword doc dot," - + "application/octet-stream bin," - + "application/oda oda," - + "application/pdf pdf," - + "application/pgp-signature pgp," - + "application/postscript ps ai eps," - + "application/rtf rtf," - + "application/vnd.ms-excel xls xlb," - + "application/vnd.ms-powerpoint ppt pps pot," - + "application/vnd.wap.wmlc wmlc," - + "application/vnd.wap.wmlscriptc wmlsc," - + "application/wordperfect5.1 wp5," - + "application/zip zip," - + "application/x-123 wk," - + "application/x-bcpio bcpio," - + "application/x-chess-pgn pgn," - + "application/x-cpio cpio," - + "application/x-debian-package deb," - + "application/x-director dcr dir dxr," - + "application/x-dms dms," - + "application/x-dvi dvi," - + "application/x-xfig fig," - + "application/x-font pfa pfb gsf pcf pcf.Z," - + "application/x-gnumeric gnumeric," - + "application/x-gtar gtar tgz taz," - + "application/x-hdf hdf," - + "application/x-httpd-php phtml pht php," - + "application/x-httpd-php3 php3," - + "application/x-httpd-php3-source phps," - + "application/x-httpd-php3-preprocessed php3p," - + "application/x-httpd-php4 php4," - + "application/x-ica ica," - + "application/x-java-archive jar," - + "application/x-java-serialized-object ser," - + "application/x-java-vm class," - + "application/x-javascript js," - + "application/x-kchart chrt," - + "application/x-killustrator kil," - + "application/x-kpresenter kpr kpt," - + "application/x-kspread ksp," - + "application/x-kword kwd kwt," - + "application/x-latex latex," - + "application/x-lha lha," - + "application/x-lzh lzh," - + "application/x-lzx lzx," - + "application/x-maker frm maker frame fm fb book fbdoc," - + "application/x-mif mif," - + "application/x-msdos-program com exe bat dll," - + "application/x-msi msi," - + "application/x-netcdf nc cdf," - + "application/x-ns-proxy-autoconfig pac," - + "application/x-object o," - + "application/x-ogg ogg," - + "application/x-oz-application oza," - + "application/x-perl pl pm," - + "application/x-pkcs7-crl crl," - + "application/x-redhat-package-manager rpm," - + "application/x-shar shar," - + "application/x-shockwave-flash swf swfl," - + "application/x-star-office sdd sda," - + "application/x-stuffit sit," - + "application/x-sv4cpio sv4cpio," - + "application/x-sv4crc sv4crc," - + "application/x-tar tar," - + "application/x-tex-gf gf," - + "application/x-tex-pk pk PK," - + "application/x-texinfo texinfo texi," - + "application/x-trash ~ % bak old sik," - + "application/x-troff t tr roff," - + "application/x-troff-man man," - + "application/x-troff-me me," - + "application/x-troff-ms ms," - + "application/x-ustar ustar," - + "application/x-wais-source src," - + "application/x-wingz wz," - + "application/x-x509-ca-cert crt," - + "audio/basic au snd," - + "audio/midi mid midi," - + "audio/mpeg mpga mpega mp2 mp3," - + "audio/mpegurl m3u," - + "audio/prs.sid sid," - + "audio/x-aiff aif aiff aifc," - + "audio/x-gsm gsm," - + "audio/x-pn-realaudio ra rm ram," - + "audio/x-scpls pls," - + "audio/x-wav wav," - + "audio/ogg ogg," - + "audio/mp4 m4a," - + "audio/x-aac aac," - + "image/bitmap bmp," - + "image/gif gif," - + "image/ief ief," - + "image/jpeg jpeg jpg jpe," - + "image/pcx pcx," - + "image/png png," - + "image/svg+xml svg svgz," - + "image/tiff tiff tif," - + "image/vnd.wap.wbmp wbmp," - + "image/x-cmu-raster ras," - + "image/x-coreldraw cdr," - + "image/x-coreldrawpattern pat," - + "image/x-coreldrawtemplate cdt," - + "image/x-corelphotopaint cpt," - + "image/x-jng jng," - + "image/x-portable-anymap pnm," - + "image/x-portable-bitmap pbm," - + "image/x-portable-graymap pgm," - + "image/x-portable-pixmap ppm," - + "image/x-rgb rgb," - + "image/x-xbitmap xbm," - + "image/x-xpixmap xpm," - + "image/x-xwindowdump xwd," - + "text/comma-separated-values csv," - + "text/css css," - + "text/html htm html xhtml," - + "text/mathml mml," - + "text/plain txt text diff," - + "text/richtext rtx," - + "text/tab-separated-values tsv," - + "text/vnd.wap.wml wml," - + "text/vnd.wap.wmlscript wmls," - + "text/xml xml," - + "text/x-c++hdr h++ hpp hxx hh," - + "text/x-c++src c++ cpp cxx cc," - + "text/x-chdr h," - + "text/x-csh csh," - + "text/x-csrc c," - + "text/x-java java," - + "text/x-moc moc," - + "text/x-pascal p pas," - + "text/x-setext etx," - + "text/x-sh sh," - + "text/x-tcl tcl tk," - + "text/x-tex tex ltx sty cls," - + "text/x-vcalendar vcs," - + "text/x-vcard vcf," - + "video/dl dl," - + "video/fli fli," - + "video/gl gl," - + "video/mpeg mpeg mpg mpe," - + "video/quicktime qt mov," - + "video/x-mng mng," - + "video/x-ms-asf asf asx," - + "video/x-msvideo avi," - + "video/x-sgi-movie movie," - + "video/ogg ogv," - + "video/mp4 mp4," - + "x-world/x-vrml vrm vrml wrl"; - - /** - * File extension to MIME type mapping. All extensions are in lower case. - */ - static private Hashtable<String, String> extToMIMEMap = new Hashtable<String, String>(); - - /** - * MIME type to Icon mapping. - */ - static private Hashtable<String, Resource> MIMEToIconMap = new Hashtable<String, Resource>(); - - static { - - // Initialize extension to MIME map - final StringTokenizer lines = new StringTokenizer(initialExtToMIMEMap, - ","); - while (lines.hasMoreTokens()) { - final String line = lines.nextToken(); - final StringTokenizer exts = new StringTokenizer(line); - final String type = exts.nextToken(); - while (exts.hasMoreTokens()) { - final String ext = exts.nextToken(); - addExtension(ext, type); - } - } - - // Initialize Icons - ThemeResource folder = new ThemeResource("../runo/icons/16/folder.png"); - addIcon("inode/drive", folder); - addIcon("inode/directory", folder); - } - - /** - * Gets the mime-type of a file. Currently the mime-type is resolved based - * only on the file name extension. - * - * @param fileName - * the name of the file whose mime-type is requested. - * @return mime-type <code>String</code> for the given filename - */ - public static String getMIMEType(String fileName) { - - // Checks for nulls - if (fileName == null) { - throw new NullPointerException("Filename can not be null"); - } - - // Calculates the extension of the file - int dotIndex = fileName.indexOf("."); - while (dotIndex >= 0 && fileName.indexOf(".", dotIndex + 1) >= 0) { - dotIndex = fileName.indexOf(".", dotIndex + 1); - } - dotIndex++; - - if (fileName.length() > dotIndex) { - String ext = fileName.substring(dotIndex); - - // Ignore any query parameters - int queryStringStart = ext.indexOf('?'); - if (queryStringStart > 0) { - ext = ext.substring(0, queryStringStart); - } - - // Return type from extension map, if found - final String type = extToMIMEMap.get(ext.toLowerCase()); - if (type != null) { - return type; - } - } - - return DEFAULT_MIME_TYPE; - } - - /** - * Gets the descriptive icon representing file, based on the filename. First - * the mime-type for the given filename is resolved, and then the - * corresponding icon is fetched from the internal icon storage. If it is - * not found the default icon is returned. - * - * @param fileName - * the name of the file whose icon is requested. - * @return the icon corresponding to the given file - */ - public static Resource getIcon(String fileName) { - return getIconByMimeType(getMIMEType(fileName)); - } - - private static Resource getIconByMimeType(String mimeType) { - final Resource icon = MIMEToIconMap.get(mimeType); - if (icon != null) { - return icon; - } - - // If nothing is known about the file-type, general file - // icon is used - return DEFAULT_ICON; - } - - /** - * Gets the descriptive icon representing a file. First the mime-type for - * the given file name is resolved, and then the corresponding icon is - * fetched from the internal icon storage. If it is not found the default - * icon is returned. - * - * @param file - * the file whose icon is requested. - * @return the icon corresponding to the given file - */ - public static Resource getIcon(File file) { - return getIconByMimeType(getMIMEType(file)); - } - - /** - * Gets the mime-type for a file. Currently the returned file type is - * resolved by the filename extension only. - * - * @param file - * the file whose mime-type is requested. - * @return the files mime-type <code>String</code> - */ - public static String getMIMEType(File file) { - - // Checks for nulls - if (file == null) { - throw new NullPointerException("File can not be null"); - } - - // Directories - if (file.isDirectory()) { - // Drives - if (file.getParentFile() == null) { - return "inode/drive"; - } else { - return "inode/directory"; - } - } - - // Return type from extension - return getMIMEType(file.getName()); - } - - /** - * Adds a mime-type mapping for the given filename extension. If the - * extension is already in the internal mapping it is overwritten. - * - * @param extension - * the filename extension to be associated with - * <code>MIMEType</code>. - * @param MIMEType - * the new mime-type for <code>extension</code>. - */ - public static void addExtension(String extension, String MIMEType) { - extToMIMEMap.put(extension.toLowerCase(), MIMEType); - } - - /** - * Adds a icon for the given mime-type. If the mime-type also has a - * corresponding icon, it is replaced with the new icon. - * - * @param MIMEType - * the mime-type whose icon is to be changed. - * @param icon - * the new icon to be associated with <code>MIMEType</code>. - */ - public static void addIcon(String MIMEType, Resource icon) { - MIMEToIconMap.put(MIMEType, icon); - } - - /** - * Gets the internal file extension to mime-type mapping. - * - * @return unmodifiable map containing the current file extension to - * mime-type mapping - */ - public static Map<String, String> getExtensionToMIMETypeMapping() { - return Collections.unmodifiableMap(extToMIMEMap); - } - - /** - * Gets the internal mime-type to icon mapping. - * - * @return unmodifiable map containing the current mime-type to icon mapping - */ - public static Map<String, Resource> getMIMETypeToIconMapping() { - return Collections.unmodifiableMap(MIMEToIconMap); - } -} diff --git a/src/com/vaadin/service/package.html b/src/com/vaadin/service/package.html deleted file mode 100644 index ea21139b91..0000000000 --- a/src/com/vaadin/service/package.html +++ /dev/null @@ -1,20 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> -</head> - -<body bgcolor="white"> - -<!-- Package summary here --> - -<p>Provides some general service classes used throughout Vaadin -based applications.</p> - -<!-- <h2>Package Specification</h2> --> - -<!-- Package spec here --> - -<!-- Put @see and @since tags down here. --> - -</body> -</html> diff --git a/src/com/vaadin/terminal/AbstractClientConnector.java b/src/com/vaadin/terminal/AbstractClientConnector.java deleted file mode 100644 index 9c68361382..0000000000 --- a/src/com/vaadin/terminal/AbstractClientConnector.java +++ /dev/null @@ -1,510 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal; - -import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.logging.Logger; - -import com.vaadin.Application; -import com.vaadin.shared.communication.ClientRpc; -import com.vaadin.shared.communication.ServerRpc; -import com.vaadin.shared.communication.SharedState; -import com.vaadin.terminal.gwt.server.ClientConnector; -import com.vaadin.terminal.gwt.server.ClientMethodInvocation; -import com.vaadin.terminal.gwt.server.RpcManager; -import com.vaadin.terminal.gwt.server.RpcTarget; -import com.vaadin.terminal.gwt.server.ServerRpcManager; -import com.vaadin.ui.HasComponents; -import com.vaadin.ui.Root; - -/** - * An abstract base class for ClientConnector implementations. This class - * provides all the basic functionality required for connectors. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public abstract class AbstractClientConnector implements ClientConnector { - /** - * A map from client to server RPC interface class to the RPC call manager - * that handles incoming RPC calls for that interface. - */ - private Map<Class<?>, RpcManager> rpcManagerMap = new HashMap<Class<?>, RpcManager>(); - - /** - * A map from server to client RPC interface class to the RPC proxy that - * sends ourgoing RPC calls for that interface. - */ - private Map<Class<?>, ClientRpc> rpcProxyMap = new HashMap<Class<?>, ClientRpc>(); - - /** - * Shared state object to be communicated from the server to the client when - * modified. - */ - private SharedState sharedState; - - /** - * Pending RPC method invocations to be sent. - */ - private ArrayList<ClientMethodInvocation> pendingInvocations = new ArrayList<ClientMethodInvocation>(); - - private String connectorId; - - private ArrayList<Extension> extensions = new ArrayList<Extension>(); - - private ClientConnector parent; - - /* Documentation copied from interface */ - @Override - public void requestRepaint() { - Root root = getRoot(); - if (root != null) { - root.getConnectorTracker().markDirty(this); - } - } - - /** - * Registers an RPC interface implementation for this component. - * - * A component can listen to multiple RPC interfaces, and subclasses can - * register additional implementations. - * - * @since 7.0 - * - * @param implementation - * RPC interface implementation - * @param rpcInterfaceType - * RPC interface class for which the implementation should be - * registered - */ - protected <T> void registerRpc(T implementation, Class<T> rpcInterfaceType) { - rpcManagerMap.put(rpcInterfaceType, new ServerRpcManager<T>( - implementation, rpcInterfaceType)); - } - - /** - * Registers an RPC interface implementation for this component. - * - * A component can listen to multiple RPC interfaces, and subclasses can - * register additional implementations. - * - * @since 7.0 - * - * @param implementation - * RPC interface implementation. Also used to deduce the type. - */ - protected <T extends ServerRpc> void registerRpc(T implementation) { - Class<?> cls = implementation.getClass(); - Class<?>[] interfaces = cls.getInterfaces(); - while (interfaces.length == 0) { - // Search upwards until an interface is found. It must be found as T - // extends ServerRpc - cls = cls.getSuperclass(); - interfaces = cls.getInterfaces(); - } - if (interfaces.length != 1 - || !(ServerRpc.class.isAssignableFrom(interfaces[0]))) { - throw new RuntimeException( - "Use registerRpc(T implementation, Class<T> rpcInterfaceType) if the Rpc implementation implements more than one interface"); - } - @SuppressWarnings("unchecked") - Class<T> type = (Class<T>) interfaces[0]; - registerRpc(implementation, type); - } - - @Override - public SharedState getState() { - if (null == sharedState) { - sharedState = createState(); - } - return sharedState; - } - - /** - * Creates the shared state bean to be used in server to client - * communication. - * <p> - * By default a state object of the defined return type of - * {@link #getState()} is created. Subclasses can override this method and - * return a new instance of the correct state class but this should rarely - * be necessary. - * </p> - * <p> - * No configuration of the values of the state should be performed in - * {@link #createState()}. - * - * @since 7.0 - * - * @return new shared state object - */ - protected SharedState createState() { - try { - return getStateType().newInstance(); - } catch (Exception e) { - throw new RuntimeException( - "Error creating state of type " + getStateType().getName() - + " for " + getClass().getName(), e); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.server.ClientConnector#getStateType() - */ - @Override - public Class<? extends SharedState> getStateType() { - try { - Method m = getClass().getMethod("getState", (Class[]) null); - Class<?> type = m.getReturnType(); - return type.asSubclass(SharedState.class); - } catch (Exception e) { - throw new RuntimeException("Error finding state type for " - + getClass().getName(), e); - } - } - - /** - * Returns an RPC proxy for a given server to client RPC interface for this - * component. - * - * TODO more javadoc, subclasses, ... - * - * @param rpcInterface - * RPC interface type - * - * @since 7.0 - */ - public <T extends ClientRpc> T getRpcProxy(final Class<T> rpcInterface) { - // create, initialize and return a dynamic proxy for RPC - try { - if (!rpcProxyMap.containsKey(rpcInterface)) { - Class<?> proxyClass = Proxy.getProxyClass( - rpcInterface.getClassLoader(), rpcInterface); - Constructor<?> constructor = proxyClass - .getConstructor(InvocationHandler.class); - T rpcProxy = rpcInterface.cast(constructor - .newInstance(new RpcInvoicationHandler(rpcInterface))); - // cache the proxy - rpcProxyMap.put(rpcInterface, rpcProxy); - } - return (T) rpcProxyMap.get(rpcInterface); - } catch (Exception e) { - // TODO exception handling? - throw new RuntimeException(e); - } - } - - private static final class AllChildrenIterable implements - Iterable<ClientConnector>, Serializable { - private final ClientConnector connector; - - private AllChildrenIterable(ClientConnector connector) { - this.connector = connector; - } - - @Override - public Iterator<ClientConnector> iterator() { - CombinedIterator<ClientConnector> iterator = new CombinedIterator<ClientConnector>(); - iterator.addIterator(connector.getExtensions().iterator()); - - if (connector instanceof HasComponents) { - HasComponents hasComponents = (HasComponents) connector; - iterator.addIterator(hasComponents.iterator()); - } - - return iterator; - } - } - - private class RpcInvoicationHandler implements InvocationHandler, - Serializable { - - private String rpcInterfaceName; - - public RpcInvoicationHandler(Class<?> rpcInterface) { - rpcInterfaceName = rpcInterface.getName().replaceAll("\\$", "."); - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { - addMethodInvocationToQueue(rpcInterfaceName, method, args); - // TODO no need to do full repaint if only RPC calls - requestRepaint(); - return null; - } - - } - - /** - * For internal use: adds a method invocation to the pending RPC call queue. - * - * @param interfaceName - * RPC interface name - * @param method - * RPC method - * @param parameters - * RPC all parameters - * - * @since 7.0 - */ - protected void addMethodInvocationToQueue(String interfaceName, - Method method, Object[] parameters) { - // add to queue - pendingInvocations.add(new ClientMethodInvocation(this, interfaceName, - method, parameters)); - } - - /** - * @see RpcTarget#getRpcManager(Class) - * - * @param rpcInterface - * RPC interface for which a call was made - * @return RPC Manager handling calls for the interface - * - * @since 7.0 - */ - @Override - public RpcManager getRpcManager(Class<?> rpcInterface) { - return rpcManagerMap.get(rpcInterface); - } - - @Override - public List<ClientMethodInvocation> retrievePendingRpcCalls() { - if (pendingInvocations.isEmpty()) { - return Collections.emptyList(); - } else { - List<ClientMethodInvocation> result = pendingInvocations; - pendingInvocations = new ArrayList<ClientMethodInvocation>(); - return Collections.unmodifiableList(result); - } - } - - @Override - public String getConnectorId() { - if (connectorId == null) { - if (getApplication() == null) { - throw new RuntimeException( - "Component must be attached to an application when getConnectorId() is called for the first time"); - } - connectorId = getApplication().createConnectorId(this); - } - return connectorId; - } - - /** - * Finds the Application to which this connector belongs. If the connector - * has not been attached, <code>null</code> is returned. - * - * @return The connector's application, or <code>null</code> if not attached - */ - protected Application getApplication() { - Root root = getRoot(); - if (root == null) { - return null; - } else { - return root.getApplication(); - } - } - - /** - * Finds a Root ancestor of this connector. <code>null</code> is returned if - * no Root ancestor is found (typically because the connector is not - * attached to a proper hierarchy). - * - * @return the Root ancestor of this connector, or <code>null</code> if none - * is found. - */ - @Override - public Root getRoot() { - ClientConnector connector = this; - while (connector != null) { - if (connector instanceof Root) { - return (Root) connector; - } - connector = connector.getParent(); - } - return null; - } - - private static Logger getLogger() { - return Logger.getLogger(AbstractClientConnector.class.getName()); - } - - @Override - public void requestRepaintAll() { - requestRepaint(); - - for (ClientConnector connector : getAllChildrenIterable(this)) { - connector.requestRepaintAll(); - } - } - - private static final class CombinedIterator<T> implements Iterator<T>, - Serializable { - - private final Collection<Iterator<? extends T>> iterators = new ArrayList<Iterator<? extends T>>(); - - public void addIterator(Iterator<? extends T> iterator) { - iterators.add(iterator); - } - - @Override - public boolean hasNext() { - for (Iterator<? extends T> i : iterators) { - if (i.hasNext()) { - return true; - } - } - return false; - } - - @Override - public T next() { - for (Iterator<? extends T> i : iterators) { - if (i.hasNext()) { - return i.next(); - } - } - throw new NoSuchElementException(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - /** - * Get an Iterable for iterating over all child connectors, including both - * extensions and child components. - * - * @param connector - * the connector to get children for - * @return an Iterable giving all child connectors. - */ - public static Iterable<ClientConnector> getAllChildrenIterable( - final ClientConnector connector) { - return new AllChildrenIterable(connector); - } - - @Override - public Collection<Extension> getExtensions() { - return Collections.unmodifiableCollection(extensions); - } - - /** - * Add an extension to this connector. This method is protected to allow - * extensions to select which targets they can extend. - * - * @param extension - * the extension to add - */ - protected void addExtension(Extension extension) { - ClientConnector previousParent = extension.getParent(); - if (previousParent == this) { - // Nothing to do, already attached - return; - } else if (previousParent != null) { - throw new IllegalStateException( - "Moving an extension from one parent to another is not supported"); - } - - extensions.add(extension); - extension.setParent(this); - requestRepaint(); - } - - @Override - public void removeExtension(Extension extension) { - extension.setParent(null); - extensions.remove(extension); - requestRepaint(); - } - - @Override - public void setParent(ClientConnector parent) { - - // If the parent is not changed, don't do anything - if (parent == this.parent) { - return; - } - - if (parent != null && this.parent != null) { - throw new IllegalStateException(getClass().getName() - + " already has a parent."); - } - - // Send detach event if the component have been connected to a window - if (getApplication() != null) { - detach(); - } - - // Connect to new parent - this.parent = parent; - - // Send attach event if connected to an application - if (getApplication() != null) { - attach(); - } - } - - @Override - public ClientConnector getParent() { - return parent; - } - - @Override - public void attach() { - requestRepaint(); - - getRoot().getConnectorTracker().registerConnector(this); - - for (ClientConnector connector : getAllChildrenIterable(this)) { - connector.attach(); - } - - } - - /** - * {@inheritDoc} - * - * <p> - * The {@link #getApplication()} and {@link #getRoot()} methods might return - * <code>null</code> after this method is called. - * </p> - */ - @Override - public void detach() { - for (ClientConnector connector : getAllChildrenIterable(this)) { - connector.detach(); - } - - getRoot().getConnectorTracker().unregisterConnector(this); - } - - @Override - public boolean isConnectorEnabled() { - if (getParent() == null) { - // No parent -> the component cannot receive updates from the client - return false; - } else { - return getParent().isConnectorEnabled(); - } - } -} diff --git a/src/com/vaadin/terminal/AbstractErrorMessage.java b/src/com/vaadin/terminal/AbstractErrorMessage.java deleted file mode 100644 index f7cd0e6aad..0000000000 --- a/src/com/vaadin/terminal/AbstractErrorMessage.java +++ /dev/null @@ -1,176 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - -import com.vaadin.data.Buffered; -import com.vaadin.data.Validator; -import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; - -/** - * Base class for component error messages. - * - * This class is used on the server side to construct the error messages to send - * to the client. - * - * @since 7.0 - */ -public abstract class AbstractErrorMessage implements ErrorMessage { - - public enum ContentMode { - /** - * Content mode, where the error contains only plain text. - */ - TEXT, - /** - * Content mode, where the error contains preformatted text. - */ - PREFORMATTED, - /** - * Content mode, where the error contains XHTML. - */ - XHTML; - } - - /** - * Content mode. - */ - private ContentMode mode = ContentMode.TEXT; - - /** - * Message in content mode. - */ - private String message; - - /** - * Error level. - */ - private ErrorLevel level = ErrorLevel.ERROR; - - private List<ErrorMessage> causes = new ArrayList<ErrorMessage>(); - - protected AbstractErrorMessage(String message) { - this.message = message; - } - - public String getMessage() { - return message; - } - - protected void setMessage(String message) { - this.message = message; - } - - /* Documented in interface */ - @Override - public ErrorLevel getErrorLevel() { - return level; - } - - protected void setErrorLevel(ErrorLevel level) { - this.level = level; - } - - protected ContentMode getMode() { - return mode; - } - - protected void setMode(ContentMode mode) { - this.mode = mode; - } - - protected List<ErrorMessage> getCauses() { - return causes; - } - - protected void addCause(ErrorMessage cause) { - causes.add(cause); - } - - @Override - public String getFormattedHtmlMessage() { - String result = null; - switch (getMode()) { - case TEXT: - result = AbstractApplicationServlet.safeEscapeForHtml(getMessage()); - break; - case PREFORMATTED: - result = "<pre>" - + AbstractApplicationServlet - .safeEscapeForHtml(getMessage()) + "</pre>"; - break; - case XHTML: - result = getMessage(); - break; - } - // if no message, combine the messages of all children - if (null == result && null != getCauses() && getCauses().size() > 0) { - StringBuilder sb = new StringBuilder(); - for (ErrorMessage cause : getCauses()) { - String childMessage = cause.getFormattedHtmlMessage(); - if (null != childMessage) { - sb.append("<div>"); - sb.append(childMessage); - sb.append("</div>\n"); - } - } - if (sb.length() > 0) { - result = sb.toString(); - } - } - // still no message? use an empty string for backwards compatibility - if (null == result) { - result = ""; - } - return result; - } - - // TODO replace this with a helper method elsewhere? - public static ErrorMessage getErrorMessageForException(Throwable t) { - if (null == t) { - return null; - } else if (t instanceof ErrorMessage) { - // legacy case for custom error messages - return (ErrorMessage) t; - } else if (t instanceof Validator.InvalidValueException) { - UserError error = new UserError( - ((Validator.InvalidValueException) t).getHtmlMessage(), - ContentMode.XHTML, ErrorLevel.ERROR); - for (Validator.InvalidValueException nestedException : ((Validator.InvalidValueException) t) - .getCauses()) { - error.addCause(getErrorMessageForException(nestedException)); - } - return error; - } else if (t instanceof Buffered.SourceException) { - // no message, only the causes to be painted - UserError error = new UserError(null); - // in practice, this was always ERROR in Vaadin 6 unless tweaked in - // custom exceptions implementing ErrorMessage - error.setErrorLevel(ErrorLevel.ERROR); - // causes - for (Throwable nestedException : ((Buffered.SourceException) t) - .getCauses()) { - error.addCause(getErrorMessageForException(nestedException)); - } - return error; - } else { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - t.printStackTrace(pw); - return new SystemError(sw.toString()); - } - } - - /* Documented in superclass */ - @Override - public String toString() { - return getMessage(); - } - -} diff --git a/src/com/vaadin/terminal/AbstractExtension.java b/src/com/vaadin/terminal/AbstractExtension.java deleted file mode 100644 index 33a60e39ef..0000000000 --- a/src/com/vaadin/terminal/AbstractExtension.java +++ /dev/null @@ -1,76 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import com.vaadin.terminal.gwt.server.ClientConnector; - -/** - * An extension is an entity that is attached to a Component or another - * Extension and independently communicates between client and server. - * <p> - * Extensions can use shared state and RPC in the same way as components. - * <p> - * AbstractExtension adds a mechanism for adding the extension to any Connector - * (extend). To let the Extension determine what kind target it can be added to, - * the extend method is declared as protected. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public abstract class AbstractExtension extends AbstractClientConnector - implements Extension { - private boolean previouslyAttached = false; - - /** - * Gets a type that the parent must be an instance of. Override this if the - * extension only support certain targets, e.g. if only TextFields can be - * extended. - * - * @return a type that the parent must be an instance of - */ - protected Class<? extends ClientConnector> getSupportedParentType() { - return ClientConnector.class; - } - - /** - * Add this extension to the target connector. This method is protected to - * allow subclasses to require a more specific type of target. - * - * @param target - * the connector to attach this extension to - */ - protected void extend(AbstractClientConnector target) { - target.addExtension(this); - } - - /** - * Remove this extension from its target. After an extension has been - * removed, it can not be attached again. - */ - public void removeFromTarget() { - getParent().removeExtension(this); - } - - @Override - public void setParent(ClientConnector parent) { - if (previouslyAttached && parent != null) { - throw new IllegalStateException( - "An extension can not be set to extend a new target after getting detached from the previous."); - } - - Class<? extends ClientConnector> supportedParentType = getSupportedParentType(); - if (parent == null || supportedParentType.isInstance(parent)) { - super.setParent(parent); - previouslyAttached = true; - } else { - throw new IllegalArgumentException(getClass().getName() - + " can only be attached to targets of type " - + supportedParentType.getName() + " but attach to " - + parent.getClass().getName() + " was attempted."); - } - } - -} diff --git a/src/com/vaadin/terminal/AbstractJavaScriptExtension.java b/src/com/vaadin/terminal/AbstractJavaScriptExtension.java deleted file mode 100644 index 7bafb6d2b3..0000000000 --- a/src/com/vaadin/terminal/AbstractJavaScriptExtension.java +++ /dev/null @@ -1,162 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import com.vaadin.shared.JavaScriptExtensionState; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.ui.JavaScriptFunction; - -/** - * Base class for Extensions with all client-side logic implemented using - * JavaScript. - * <p> - * When a new JavaScript extension is initialized in the browser, the framework - * will look for a globally defined JavaScript function that will initialize the - * extension. The name of the initialization function is formed by replacing . - * with _ in the name of the server-side class. If no such function is defined, - * each super class is used in turn until a match is found. The framework will - * thus first attempt with <code>com_example_MyExtension</code> for the - * server-side - * <code>com.example.MyExtension extends AbstractJavaScriptExtension</code> - * class. If MyExtension instead extends <code>com.example.SuperExtension</code> - * , then <code>com_example_SuperExtension</code> will also be attempted if - * <code>com_example_MyExtension</code> has not been defined. - * <p> - * - * The initialization function will be called with <code>this</code> pointing to - * a connector wrapper object providing integration to Vaadin with the following - * functions: - * <ul> - * <li><code>getConnectorId()</code> - returns a string with the id of the - * connector.</li> - * <li><code>getParentId([connectorId])</code> - returns a string with the id of - * the connector's parent. If <code>connectorId</code> is provided, the id of - * the parent of the corresponding connector with the passed id is returned - * instead.</li> - * <li><code>getElement([connectorId])</code> - returns the DOM Element that is - * the root of a connector's widget. <code>null</code> is returned if the - * connector can not be found or if the connector doesn't have a widget. If - * <code>connectorId</code> is not provided, the connector id of the current - * connector will be used.</li> - * <li><code>getState()</code> - returns an object corresponding to the shared - * state defined on the server. The scheme for conversion between Java and - * JavaScript types is described bellow.</li> - * <li><code>registerRpc([name, ] rpcObject)</code> - registers the - * <code>rpcObject</code> as a RPC handler. <code>rpcObject</code> should be an - * object with field containing functions for all eligible RPC functions. If - * <code>name</code> is provided, the RPC handler will only used for RPC calls - * for the RPC interface with the same fully qualified Java name. If no - * <code>name</code> is provided, the RPC handler will be used for all incoming - * RPC invocations where the RPC method name is defined as a function field in - * the handler. The scheme for conversion between Java types in the RPC - * interface definition and the JavaScript values passed as arguments to the - * handler functions is described bellow.</li> - * <li><code>getRpcProxy([name])</code> - returns an RPC proxy object. If - * <code>name</code> is provided, the proxy object will contain functions for - * all methods in the RPC interface with the same fully qualified name, provided - * a RPC handler has been registered by the server-side code. If no - * <code>name</code> is provided, the returned RPC proxy object will contain - * functions for all methods in all RPC interfaces registered for the connector - * on the server. If the same method name is present in multiple registered RPC - * interfaces, the corresponding function in the RPC proxy object will throw an - * exception when called. The scheme for conversion between Java types in the - * RPC interface and the JavaScript values that should be passed to the - * functions is described bellow.</li> - * <li><code>translateVaadinUri(uri)</code> - Translates a Vaadin URI to a URL - * that can be used in the browser. This is just way of accessing - * {@link ApplicationConnection#translateVaadinUri(String)}</li> - * </ul> - * The connector wrapper also supports these special functions: - * <ul> - * <li><code>onStateChange</code> - If the JavaScript code assigns a function to - * the field, that function is called whenever the contents of the shared state - * is changed.</li> - * <li>Any field name corresponding to a call to - * {@link #addFunction(String, JavaScriptFunction)} on the server will - * automatically be present as a function that triggers the registered function - * on the server.</li> - * <li>Any field name referred to using - * {@link #callFunction(String, Object...)} on the server will be called if a - * function has been assigned to the field.</li> - * </ul> - * <p> - * - * Values in the Shared State and in RPC calls are converted between Java and - * JavaScript using the following conventions: - * <ul> - * <li>Primitive Java numbers (byte, char, int, long, float, double) and their - * boxed types (Byte, Character, Integer, Long, Float, Double) are represented - * by JavaScript numbers.</li> - * <li>The primitive Java boolean and the boxed Boolean are represented by - * JavaScript booleans.</li> - * <li>Java Strings are represented by JavaScript strings.</li> - * <li>List, Set and all arrays in Java are represented by JavaScript arrays.</li> - * <li>Map<String, ?> in Java is represented by JavaScript object with fields - * corresponding to the map keys.</li> - * <li>Any other Java Map is represented by a JavaScript array containing two - * arrays, the first contains the keys and the second contains the values in the - * same order.</li> - * <li>A Java Bean is represented by a JavaScript object with fields - * corresponding to the bean's properties.</li> - * <li>A Java Connector is represented by a JavaScript string containing the - * connector's id.</li> - * <li>A pluggable serialization mechanism is provided for types not described - * here. Please refer to the documentation for specific types for serialization - * information.</li> - * </ul> - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public abstract class AbstractJavaScriptExtension extends AbstractExtension { - private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper( - this); - - @Override - protected <T> void registerRpc(T implementation, Class<T> rpcInterfaceType) { - super.registerRpc(implementation, rpcInterfaceType); - callbackHelper.registerRpc(rpcInterfaceType); - } - - /** - * Register a {@link JavaScriptFunction} that can be called from the - * JavaScript using the provided name. A JavaScript function with the - * provided name will be added to the connector wrapper object (initially - * available as <code>this</code>). Calling that JavaScript function will - * cause the call method in the registered {@link JavaScriptFunction} to be - * invoked with the same arguments. - * - * @param functionName - * the name that should be used for client-side callback - * @param function - * the {@link JavaScriptFunction} object that will be invoked - * when the JavaScript function is called - */ - protected void addFunction(String functionName, JavaScriptFunction function) { - callbackHelper.registerCallback(functionName, function); - } - - /** - * Invoke a named function that the connector JavaScript has added to the - * JavaScript connector wrapper object. The arguments should only contain - * data types that can be represented in JavaScript including primitives, - * their boxed types, arrays, String, List, Set, Map, Connector and - * JavaBeans. - * - * @param name - * the name of the function - * @param arguments - * function arguments - */ - protected void callFunction(String name, Object... arguments) { - callbackHelper.invokeCallback(name, arguments); - } - - @Override - public JavaScriptExtensionState getState() { - return (JavaScriptExtensionState) super.getState(); - } -} diff --git a/src/com/vaadin/terminal/ApplicationResource.java b/src/com/vaadin/terminal/ApplicationResource.java deleted file mode 100644 index da92642d02..0000000000 --- a/src/com/vaadin/terminal/ApplicationResource.java +++ /dev/null @@ -1,75 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; - -import com.vaadin.Application; - -/** - * This interface must be implemented by classes wishing to provide Application - * resources. - * <p> - * <code>ApplicationResource</code> are a set of named resources (pictures, - * sounds, etc) associated with some specific application. Having named - * application resources provides a convenient method for having inter-theme - * common resources for an application. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface ApplicationResource extends Resource, Serializable { - - /** - * Default cache time. - */ - public static final long DEFAULT_CACHETIME = 1000 * 60 * 60 * 24; - - /** - * Gets resource as stream. - */ - public DownloadStream getStream(); - - /** - * Gets the application of the resource. - */ - public Application getApplication(); - - /** - * Gets the virtual filename for this resource. - * - * @return the file name associated to this resource. - */ - public String getFilename(); - - /** - * Gets the length of cache expiration time. - * - * <p> - * This gives the adapter the possibility cache streams sent to the client. - * The caching may be made in adapter or at the client if the client - * supports caching. Default is <code>DEFAULT_CACHETIME</code>. - * </p> - * - * @return Cache time in milliseconds - */ - public long getCacheTime(); - - /** - * Gets the size of the download buffer used for this resource. - * - * <p> - * If the buffer size is 0, the buffer size is decided by the terminal - * adapter. The default value is 0. - * </p> - * - * @return int the size of the buffer in bytes. - */ - public int getBufferSize(); - -} diff --git a/src/com/vaadin/terminal/ClassResource.java b/src/com/vaadin/terminal/ClassResource.java deleted file mode 100644 index b74c8e7bb7..0000000000 --- a/src/com/vaadin/terminal/ClassResource.java +++ /dev/null @@ -1,178 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; - -import com.vaadin.Application; -import com.vaadin.service.FileTypeResolver; - -/** - * <code>ClassResource</code> is a named resource accessed with the class - * loader. - * - * This can be used to access resources such as icons, files, etc. - * - * @see java.lang.Class#getResource(java.lang.String) - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ClassResource implements ApplicationResource, Serializable { - - /** - * Default buffer size for this stream resource. - */ - private int bufferSize = 0; - - /** - * Default cache time for this stream resource. - */ - private long cacheTime = DEFAULT_CACHETIME; - - /** - * Associated class used for indetifying the source of the resource. - */ - private final Class<?> associatedClass; - - /** - * Name of the resource is relative to the associated class. - */ - private final String resourceName; - - /** - * Application used for serving the class. - */ - private final Application application; - - /** - * Creates a new application resource instance. The resource id is relative - * to the location of the application class. - * - * @param resourceName - * the Unique identifier of the resource within the application. - * @param application - * the application this resource will be added to. - */ - public ClassResource(String resourceName, Application application) { - this(application.getClass(), resourceName, application); - } - - /** - * Creates a new application resource instance. - * - * @param associatedClass - * the class of the which the resource is associated. - * @param resourceName - * the Unique identifier of the resource within the application. - * @param application - * the application this resource will be added to. - */ - public ClassResource(Class<?> associatedClass, String resourceName, - Application application) { - this.associatedClass = associatedClass; - this.resourceName = resourceName; - this.application = application; - if (resourceName == null || associatedClass == null) { - throw new NullPointerException(); - } - application.addResource(this); - } - - /** - * Gets the MIME type of this resource. - * - * @see com.vaadin.terminal.Resource#getMIMEType() - */ - @Override - public String getMIMEType() { - return FileTypeResolver.getMIMEType(resourceName); - } - - /** - * Gets the application of this resource. - * - * @see com.vaadin.terminal.ApplicationResource#getApplication() - */ - @Override - public Application getApplication() { - return application; - } - - /** - * Gets the virtual filename for this resource. - * - * @return the file name associated to this resource. - * @see com.vaadin.terminal.ApplicationResource#getFilename() - */ - @Override - public String getFilename() { - int index = 0; - int next = 0; - while ((next = resourceName.indexOf('/', index)) > 0 - && next + 1 < resourceName.length()) { - index = next + 1; - } - return resourceName.substring(index); - } - - /** - * Gets resource as stream. - * - * @see com.vaadin.terminal.ApplicationResource#getStream() - */ - @Override - public DownloadStream getStream() { - final DownloadStream ds = new DownloadStream( - associatedClass.getResourceAsStream(resourceName), - getMIMEType(), getFilename()); - ds.setBufferSize(getBufferSize()); - ds.setCacheTime(cacheTime); - return ds; - } - - /* documented in superclass */ - @Override - public int getBufferSize() { - return bufferSize; - } - - /** - * Sets the size of the download buffer used for this resource. - * - * @param bufferSize - * the size of the buffer in bytes. - */ - public void setBufferSize(int bufferSize) { - this.bufferSize = bufferSize; - } - - /* documented in superclass */ - @Override - public long getCacheTime() { - return cacheTime; - } - - /** - * Sets the length of cache expiration time. - * - * <p> - * This gives the adapter the possibility cache streams sent to the client. - * The caching may be made in adapter or at the client if the client - * supports caching. Zero or negavive value disbales the caching of this - * stream. - * </p> - * - * @param cacheTime - * the cache time in milliseconds. - * - */ - public void setCacheTime(long cacheTime) { - this.cacheTime = cacheTime; - } -} diff --git a/src/com/vaadin/terminal/CombinedRequest.java b/src/com/vaadin/terminal/CombinedRequest.java deleted file mode 100644 index 5b92feb39a..0000000000 --- a/src/com/vaadin/terminal/CombinedRequest.java +++ /dev/null @@ -1,187 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; - -import com.vaadin.Application; -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.terminal.gwt.server.WebApplicationContext; -import com.vaadin.terminal.gwt.server.WebBrowser; - -/** - * A {@link WrappedRequest} with path and parameters from one request and - * {@link WrappedRequest.BrowserDetails} extracted from another request. - * - * This class is intended to be used for a two request initialization where the - * first request fetches the actual application page and the second request - * contains information extracted from the browser using javascript. - * - */ -public class CombinedRequest implements WrappedRequest { - - private final WrappedRequest secondRequest; - private Map<String, String[]> parameterMap; - - /** - * Creates a new combined request based on the second request and some - * details from the first request. - * - * @param secondRequest - * the second request which will be used as the foundation of the - * combined request - * @throws JSONException - * if the initialParams parameter can not be decoded - */ - public CombinedRequest(WrappedRequest secondRequest) throws JSONException { - this.secondRequest = secondRequest; - - HashMap<String, String[]> map = new HashMap<String, String[]>(); - JSONObject initialParams = new JSONObject( - secondRequest.getParameter("initialParams")); - for (Iterator<?> keys = initialParams.keys(); keys.hasNext();) { - String name = (String) keys.next(); - JSONArray jsonValues = initialParams.getJSONArray(name); - String[] values = new String[jsonValues.length()]; - for (int i = 0; i < values.length; i++) { - values[i] = jsonValues.getString(i); - } - map.put(name, values); - } - - parameterMap = Collections.unmodifiableMap(map); - - } - - @Override - public String getParameter(String parameter) { - String[] strings = getParameterMap().get(parameter); - if (strings == null || strings.length == 0) { - return null; - } else { - return strings[0]; - } - } - - @Override - public Map<String, String[]> getParameterMap() { - return parameterMap; - } - - @Override - public int getContentLength() { - return secondRequest.getContentLength(); - } - - @Override - public InputStream getInputStream() throws IOException { - return secondRequest.getInputStream(); - } - - @Override - public Object getAttribute(String name) { - return secondRequest.getAttribute(name); - } - - @Override - public void setAttribute(String name, Object value) { - secondRequest.setAttribute(name, value); - } - - @Override - public String getRequestPathInfo() { - return secondRequest.getParameter("initialPath"); - } - - @Override - public int getSessionMaxInactiveInterval() { - return secondRequest.getSessionMaxInactiveInterval(); - } - - @Override - public Object getSessionAttribute(String name) { - return secondRequest.getSessionAttribute(name); - } - - @Override - public void setSessionAttribute(String name, Object attribute) { - secondRequest.setSessionAttribute(name, attribute); - } - - @Override - public String getContentType() { - return secondRequest.getContentType(); - } - - @Override - public BrowserDetails getBrowserDetails() { - return new BrowserDetails() { - @Override - public String getUriFragment() { - String fragment = secondRequest.getParameter("fr"); - if (fragment == null) { - return ""; - } else { - return fragment; - } - } - - @Override - public String getWindowName() { - return secondRequest.getParameter("wn"); - } - - @Override - public WebBrowser getWebBrowser() { - WebApplicationContext context = (WebApplicationContext) Application - .getCurrent().getContext(); - return context.getBrowser(); - } - }; - } - - /** - * Gets the original second request. This can be used e.g. if a request - * parameter from the second request is required. - * - * @return the original second wrapped request - */ - public WrappedRequest getSecondRequest() { - return secondRequest; - } - - @Override - public Locale getLocale() { - return secondRequest.getLocale(); - } - - @Override - public String getRemoteAddr() { - return secondRequest.getRemoteAddr(); - } - - @Override - public boolean isSecure() { - return secondRequest.isSecure(); - } - - @Override - public String getHeader(String name) { - return secondRequest.getHeader(name); - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return secondRequest.getDeploymentConfiguration(); - } -} diff --git a/src/com/vaadin/terminal/CompositeErrorMessage.java b/src/com/vaadin/terminal/CompositeErrorMessage.java deleted file mode 100644 index b82b622f54..0000000000 --- a/src/com/vaadin/terminal/CompositeErrorMessage.java +++ /dev/null @@ -1,112 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.util.Collection; -import java.util.Iterator; - -/** - * Class for combining multiple error messages together. - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class CompositeErrorMessage extends AbstractErrorMessage { - - /** - * Constructor for CompositeErrorMessage. - * - * @param errorMessages - * the Array of error messages that are listed togeter. Nulls are - * ignored, but at least one message is required. - */ - public CompositeErrorMessage(ErrorMessage[] errorMessages) { - super(null); - setErrorLevel(ErrorLevel.INFORMATION); - - for (int i = 0; i < errorMessages.length; i++) { - addErrorMessage(errorMessages[i]); - } - - if (getCauses().size() == 0) { - throw new IllegalArgumentException( - "Composite error message must have at least one error"); - } - - } - - /** - * Constructor for CompositeErrorMessage. - * - * @param errorMessages - * the Collection of error messages that are listed together. At - * least one message is required. - */ - public CompositeErrorMessage( - Collection<? extends ErrorMessage> errorMessages) { - super(null); - setErrorLevel(ErrorLevel.INFORMATION); - - for (final Iterator<? extends ErrorMessage> i = errorMessages - .iterator(); i.hasNext();) { - addErrorMessage(i.next()); - } - - if (getCauses().size() == 0) { - throw new IllegalArgumentException( - "Composite error message must have at least one error"); - } - } - - /** - * Adds a error message into this composite message. Updates the level - * field. - * - * @param error - * the error message to be added. Duplicate errors are ignored. - */ - private void addErrorMessage(ErrorMessage error) { - if (error != null && !getCauses().contains(error)) { - addCause(error); - if (error.getErrorLevel().intValue() > getErrorLevel().intValue()) { - setErrorLevel(error.getErrorLevel()); - } - } - } - - /** - * Gets Error Iterator. - * - * @return the error iterator. - */ - public Iterator<ErrorMessage> iterator() { - return getCauses().iterator(); - } - - /** - * Returns a comma separated list of the error messages. - * - * @return String, comma separated list of error messages. - */ - @Override - public String toString() { - String retval = "["; - int pos = 0; - for (final Iterator<ErrorMessage> i = getCauses().iterator(); i - .hasNext();) { - if (pos > 0) { - retval += ","; - } - pos++; - retval += i.next().toString(); - } - retval += "]"; - - return retval; - } -} diff --git a/src/com/vaadin/terminal/DeploymentConfiguration.java b/src/com/vaadin/terminal/DeploymentConfiguration.java deleted file mode 100644 index ae96dcaec5..0000000000 --- a/src/com/vaadin/terminal/DeploymentConfiguration.java +++ /dev/null @@ -1,123 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.util.Iterator; -import java.util.Properties; - -import javax.portlet.PortletContext; -import javax.servlet.ServletContext; - -import com.vaadin.terminal.gwt.server.AddonContext; -import com.vaadin.terminal.gwt.server.AddonContextListener; - -/** - * Provide deployment specific settings that are required outside terminal - * specific code. - * - * @author Vaadin Ltd. - * - * @since 7.0 - */ -public interface DeploymentConfiguration extends Serializable { - - /** - * Gets the base URL of the location of Vaadin's static files. - * - * @param request - * the request for which the location should be determined - * - * @return a string with the base URL for static files - */ - public String getStaticFileLocation(WrappedRequest request); - - /** - * Gets the widgetset that is configured for this deployment, e.g. from a - * parameter in web.xml. - * - * @param request - * the request for which a widgetset is required - * @return the name of the widgetset - */ - public String getConfiguredWidgetset(WrappedRequest request); - - /** - * Gets the theme that is configured for this deployment, e.g. from a portal - * parameter or just some sensible default value. - * - * @param request - * the request for which a theme is required - * @return the name of the theme - */ - public String getConfiguredTheme(WrappedRequest request); - - /** - * Checks whether the Vaadin application will be rendered on its own in the - * browser or whether it will be included into some other context. A - * standalone application may do things that might interfere with other - * parts of a page, e.g. changing the page title and requesting focus upon - * loading. - * - * @param request - * the request for which the application is loaded - * @return a boolean indicating whether the application should be standalone - */ - public boolean isStandalone(WrappedRequest request); - - /** - * Gets a configured property. The properties are typically read from e.g. - * web.xml or from system properties of the JVM. - * - * @param propertyName - * The simple of the property, in some contexts, lookup might be - * performed using variations of the provided name. - * @param defaultValue - * the default value that should be used if no value has been - * defined - * @return the property value, or the passed default value if no property - * value is found - */ - public String getApplicationOrSystemProperty(String propertyName, - String defaultValue); - - /** - * Get the class loader to use for loading classes loaded by name, e.g. - * custom Root classes. <code>null</code> indicates that the default class - * loader should be used. - * - * @return the class loader to use, or <code>null</code> - */ - public ClassLoader getClassLoader(); - - /** - * Returns the MIME type of the specified file, or null if the MIME type is - * not known. The MIME type is determined by the configuration of the - * container, and may be specified in a deployment descriptor. Common MIME - * types are "text/html" and "image/gif". - * - * @param resourceName - * a String specifying the name of a file - * @return a String specifying the file's MIME type - * - * @see ServletContext#getMimeType(String) - * @see PortletContext#getMimeType(String) - */ - public String getMimeType(String resourceName); - - /** - * Gets the properties configured for the deployment, e.g. as init - * parameters to the servlet or portlet. - * - * @return properties for the application. - */ - public Properties getInitParameters(); - - public Iterator<AddonContextListener> getAddonContextListeners(); - - public AddonContext getAddonContext(); - - public void setAddonContext(AddonContext vaadinContext); -} diff --git a/src/com/vaadin/terminal/DownloadStream.java b/src/com/vaadin/terminal/DownloadStream.java deleted file mode 100644 index 9853b0eee2..0000000000 --- a/src/com/vaadin/terminal/DownloadStream.java +++ /dev/null @@ -1,335 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.servlet.http.HttpServletResponse; - -import com.vaadin.terminal.gwt.server.Constants; - -/** - * Downloadable stream. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class DownloadStream implements Serializable { - - /** - * Maximum cache time. - */ - public static final long MAX_CACHETIME = Long.MAX_VALUE; - - /** - * Default cache time. - */ - public static final long DEFAULT_CACHETIME = 1000 * 60 * 60 * 24; - - private InputStream stream; - - private String contentType; - - private String fileName; - - private Map<String, String> params; - - private long cacheTime = DEFAULT_CACHETIME; - - private int bufferSize = 0; - - /** - * Creates a new instance of DownloadStream. - */ - public DownloadStream(InputStream stream, String contentType, - String fileName) { - setStream(stream); - setContentType(contentType); - setFileName(fileName); - } - - /** - * Gets downloadable stream. - * - * @return output stream. - */ - public InputStream getStream() { - return stream; - } - - /** - * Sets the stream. - * - * @param stream - * The stream to set - */ - public void setStream(InputStream stream) { - this.stream = stream; - } - - /** - * Gets stream content type. - * - * @return type of the stream content. - */ - public String getContentType() { - return contentType; - } - - /** - * Sets stream content type. - * - * @param contentType - * the contentType to set - */ - public void setContentType(String contentType) { - this.contentType = contentType; - } - - /** - * Returns the file name. - * - * @return the name of the file. - */ - public String getFileName() { - return fileName; - } - - /** - * Sets the file name. - * - * @param fileName - * the file name to set. - */ - public void setFileName(String fileName) { - this.fileName = fileName; - } - - /** - * Sets a paramater for download stream. Parameters are optional information - * about the downloadable stream and their meaning depends on the used - * adapter. For example in WebAdapter they are interpreted as HTTP response - * headers. - * - * If the parameters by this name exists, the old value is replaced. - * - * @param name - * the Name of the parameter to set. - * @param value - * the Value of the parameter to set. - */ - public void setParameter(String name, String value) { - if (params == null) { - params = new HashMap<String, String>(); - } - params.put(name, value); - } - - /** - * Gets a paramater for download stream. Parameters are optional information - * about the downloadable stream and their meaning depends on the used - * adapter. For example in WebAdapter they are interpreted as HTTP response - * headers. - * - * @param name - * the Name of the parameter to set. - * @return Value of the parameter or null if the parameter does not exist. - */ - public String getParameter(String name) { - if (params != null) { - return params.get(name); - } - return null; - } - - /** - * Gets the names of the parameters. - * - * @return Iterator of names or null if no parameters are set. - */ - public Iterator<String> getParameterNames() { - if (params != null) { - return params.keySet().iterator(); - } - return null; - } - - /** - * Gets length of cache expiration time. This gives the adapter the - * possibility cache streams sent to the client. The caching may be made in - * adapter or at the client if the client supports caching. Default is - * <code>DEFAULT_CACHETIME</code>. - * - * @return Cache time in milliseconds - */ - public long getCacheTime() { - return cacheTime; - } - - /** - * Sets length of cache expiration time. This gives the adapter the - * possibility cache streams sent to the client. The caching may be made in - * adapter or at the client if the client supports caching. Zero or negavive - * value disbales the caching of this stream. - * - * @param cacheTime - * the cache time in milliseconds. - */ - public void setCacheTime(long cacheTime) { - this.cacheTime = cacheTime; - } - - /** - * Gets the size of the download buffer. - * - * @return int The size of the buffer in bytes. - */ - public int getBufferSize() { - return bufferSize; - } - - /** - * Sets the size of the download buffer. - * - * @param bufferSize - * the size of the buffer in bytes. - * - * @since 7.0 - */ - public void setBufferSize(int bufferSize) { - this.bufferSize = bufferSize; - } - - /** - * Writes this download stream to a wrapped response. This takes care of - * setting response headers according to what is defined in this download - * stream ({@link #getContentType()}, {@link #getCacheTime()}, - * {@link #getFileName()}) and transferring the data from the stream ( - * {@link #getStream()}) to the response. Defined parameters ( - * {@link #getParameterNames()}) are also included as headers in the - * response. If there's is a parameter named <code>Location</code>, a - * redirect (302 Moved temporarily) is sent instead of the contents of this - * stream. - * - * @param response - * the wrapped response to write this download stream to - * @throws IOException - * passed through from the wrapped response - * - * @since 7.0 - */ - public void writeTo(WrappedResponse response) throws IOException { - if (getParameter("Location") != null) { - response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); - response.setHeader("Location", getParameter("Location")); - return; - } - - // Download from given stream - final InputStream data = getStream(); - if (data != null) { - - OutputStream out = null; - try { - // Sets content type - response.setContentType(getContentType()); - - // Sets cache headers - response.setCacheTime(getCacheTime()); - - // Copy download stream parameters directly - // to HTTP headers. - final Iterator<String> i = getParameterNames(); - if (i != null) { - while (i.hasNext()) { - final String param = i.next(); - response.setHeader(param, getParameter(param)); - } - } - - // suggest local filename from DownloadStream if - // Content-Disposition - // not explicitly set - String contentDispositionValue = getParameter("Content-Disposition"); - if (contentDispositionValue == null) { - contentDispositionValue = "filename=\"" + getFileName() - + "\""; - response.setHeader("Content-Disposition", - contentDispositionValue); - } - - int bufferSize = getBufferSize(); - if (bufferSize <= 0 || bufferSize > Constants.MAX_BUFFER_SIZE) { - bufferSize = Constants.DEFAULT_BUFFER_SIZE; - } - final byte[] buffer = new byte[bufferSize]; - int bytesRead = 0; - - out = response.getOutputStream(); - - long totalWritten = 0; - while ((bytesRead = data.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - - totalWritten += bytesRead; - if (totalWritten >= buffer.length) { - // Avoid chunked encoding for small resources - out.flush(); - } - } - } finally { - tryToCloseStream(out); - tryToCloseStream(data); - } - } - } - - /** - * Helper method that tries to close an output stream and ignores any - * exceptions. - * - * @param out - * the output stream to close, <code>null</code> is also - * supported - */ - static void tryToCloseStream(OutputStream out) { - try { - // try to close output stream (e.g. file handle) - if (out != null) { - out.close(); - } - } catch (IOException e1) { - // NOP - } - } - - /** - * Helper method that tries to close an input stream and ignores any - * exceptions. - * - * @param in - * the input stream to close, <code>null</code> is also supported - */ - static void tryToCloseStream(InputStream in) { - try { - // try to close output stream (e.g. file handle) - if (in != null) { - in.close(); - } - } catch (IOException e1) { - // NOP - } - } - -} diff --git a/src/com/vaadin/terminal/ErrorMessage.java b/src/com/vaadin/terminal/ErrorMessage.java deleted file mode 100644 index 60a0780a72..0000000000 --- a/src/com/vaadin/terminal/ErrorMessage.java +++ /dev/null @@ -1,126 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; - -/** - * Interface for rendering error messages to terminal. All the visible errors - * shown to user must implement this interface. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface ErrorMessage extends Serializable { - - public enum ErrorLevel { - /** - * Error code for informational messages. - */ - INFORMATION("info", 0), - /** - * Error code for warning messages. - */ - WARNING("warning", 1), - /** - * Error code for regular error messages. - */ - ERROR("error", 2), - /** - * Error code for critical error messages. - */ - CRITICAL("critical", 3), - /** - * Error code for system errors and bugs. - */ - SYSTEMERROR("system", 4); - - String text; - int errorLevel; - - private ErrorLevel(String text, int errorLevel) { - this.text = text; - this.errorLevel = errorLevel; - } - - /** - * Textual representation for server-client communication of level - * - * @return String for error severity - */ - public String getText() { - return text; - } - - /** - * Integer representation of error severity for comparison - * - * @return integer for error severity - */ - public int intValue() { - return errorLevel; - } - - @Override - public String toString() { - return text; - } - - } - - /** - * @deprecated from 7.0, use {@link ErrorLevel#SYSTEMERROR} instead   - */ - @Deprecated - public static final ErrorLevel SYSTEMERROR = ErrorLevel.SYSTEMERROR; - - /** - * @deprecated from 7.0, use {@link ErrorLevel#CRITICAL} instead   - */ - @Deprecated - public static final ErrorLevel CRITICAL = ErrorLevel.CRITICAL; - - /** - * @deprecated from 7.0, use {@link ErrorLevel#ERROR} instead   - */ - - @Deprecated - public static final ErrorLevel ERROR = ErrorLevel.ERROR; - - /** - * @deprecated from 7.0, use {@link ErrorLevel#WARNING} instead   - */ - @Deprecated - public static final ErrorLevel WARNING = ErrorLevel.WARNING; - - /** - * @deprecated from 7.0, use {@link ErrorLevel#INFORMATION} instead   - */ - @Deprecated - public static final ErrorLevel INFORMATION = ErrorLevel.INFORMATION; - - /** - * Gets the errors level. - * - * @return the level of error as an integer. - */ - public ErrorLevel getErrorLevel(); - - /** - * Returns the HTML formatted message to show in as the error message on the - * client. - * - * This method should perform any necessary escaping to avoid XSS attacks. - * - * TODO this API may still change to use a separate data transfer object - * - * @return HTML formatted string for the error message - * @since 7.0 - */ - public String getFormattedHtmlMessage(); - -} diff --git a/src/com/vaadin/terminal/Extension.java b/src/com/vaadin/terminal/Extension.java deleted file mode 100644 index ef5bb4cf8d..0000000000 --- a/src/com/vaadin/terminal/Extension.java +++ /dev/null @@ -1,27 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import com.vaadin.terminal.gwt.server.ClientConnector; - -/** - * An extension is an entity that is attached to a Component or another - * Extension and independently communicates between client and server. - * <p> - * An extension can only be attached once. It is not supported to move an - * extension from one target to another. - * <p> - * Extensions can use shared state and RPC in the same way as components. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public interface Extension extends ClientConnector { - /* - * Currently just an empty marker interface to distinguish between - * extensions and other connectors, e.g. components - */ -} diff --git a/src/com/vaadin/terminal/ExternalResource.java b/src/com/vaadin/terminal/ExternalResource.java deleted file mode 100644 index 84fcc65a44..0000000000 --- a/src/com/vaadin/terminal/ExternalResource.java +++ /dev/null @@ -1,118 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.net.URL; - -import com.vaadin.service.FileTypeResolver; - -/** - * <code>ExternalResource</code> implements source for resources fetched from - * location specified by URL:s. The resources are fetched directly by the client - * terminal and are not fetched trough the terminal adapter. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ExternalResource implements Resource, Serializable { - - /** - * Url of the download. - */ - private String sourceURL = null; - - /** - * MIME Type for the resource - */ - private String mimeType = null; - - /** - * Creates a new download component for downloading directly from given URL. - * - * @param sourceURL - * the source URL. - */ - public ExternalResource(URL sourceURL) { - if (sourceURL == null) { - throw new RuntimeException("Source must be non-null"); - } - - this.sourceURL = sourceURL.toString(); - } - - /** - * Creates a new download component for downloading directly from given URL. - * - * @param sourceURL - * the source URL. - * @param mimeType - * the MIME Type - */ - public ExternalResource(URL sourceURL, String mimeType) { - this(sourceURL); - this.mimeType = mimeType; - } - - /** - * Creates a new download component for downloading directly from given URL. - * - * @param sourceURL - * the source URL. - */ - public ExternalResource(String sourceURL) { - if (sourceURL == null) { - throw new RuntimeException("Source must be non-null"); - } - - this.sourceURL = sourceURL.toString(); - } - - /** - * Creates a new download component for downloading directly from given URL. - * - * @param sourceURL - * the source URL. - * @param mimeType - * the MIME Type - */ - public ExternalResource(String sourceURL, String mimeType) { - this(sourceURL); - this.mimeType = mimeType; - } - - /** - * Gets the URL of the external resource. - * - * @return the URL of the external resource. - */ - public String getURL() { - return sourceURL; - } - - /** - * Gets the MIME type of the resource. - * - * @see com.vaadin.terminal.Resource#getMIMEType() - */ - @Override - public String getMIMEType() { - if (mimeType == null) { - mimeType = FileTypeResolver.getMIMEType(getURL().toString()); - } - return mimeType; - } - - /** - * Sets the MIME type of the resource. - */ - public void setMIMEType(String mimeType) { - this.mimeType = mimeType; - } - -} diff --git a/src/com/vaadin/terminal/FileResource.java b/src/com/vaadin/terminal/FileResource.java deleted file mode 100644 index e3c9f0172a..0000000000 --- a/src/com/vaadin/terminal/FileResource.java +++ /dev/null @@ -1,174 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; - -import com.vaadin.Application; -import com.vaadin.service.FileTypeResolver; -import com.vaadin.terminal.Terminal.ErrorEvent; - -/** - * <code>FileResources</code> are files or directories on local filesystem. The - * files and directories are served through URI:s to the client terminal and - * thus must be registered to an URI context before they can be used. The - * resource is automatically registered to the application when it is created. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class FileResource implements ApplicationResource { - - /** - * Default buffer size for this stream resource. - */ - private int bufferSize = 0; - - /** - * File where the downloaded content is fetched from. - */ - private File sourceFile; - - /** - * Application. - */ - private final Application application; - - /** - * Default cache time for this stream resource. - */ - private long cacheTime = DownloadStream.DEFAULT_CACHETIME; - - /** - * Creates a new file resource for providing given file for client - * terminals. - */ - public FileResource(File sourceFile, Application application) { - this.application = application; - setSourceFile(sourceFile); - application.addResource(this); - } - - /** - * Gets the resource as stream. - * - * @see com.vaadin.terminal.ApplicationResource#getStream() - */ - @Override - public DownloadStream getStream() { - try { - final DownloadStream ds = new DownloadStream(new FileInputStream( - sourceFile), getMIMEType(), getFilename()); - ds.setParameter("Content-Length", - String.valueOf(sourceFile.length())); - - ds.setCacheTime(cacheTime); - return ds; - } catch (final FileNotFoundException e) { - // Log the exception using the application error handler - getApplication().getErrorHandler().terminalError(new ErrorEvent() { - - @Override - public Throwable getThrowable() { - return e; - } - - }); - - return null; - } - } - - /** - * Gets the source file. - * - * @return the source File. - */ - public File getSourceFile() { - return sourceFile; - } - - /** - * Sets the source file. - * - * @param sourceFile - * the source file to set. - */ - public void setSourceFile(File sourceFile) { - this.sourceFile = sourceFile; - } - - /** - * @see com.vaadin.terminal.ApplicationResource#getApplication() - */ - @Override - public Application getApplication() { - return application; - } - - /** - * @see com.vaadin.terminal.ApplicationResource#getFilename() - */ - @Override - public String getFilename() { - return sourceFile.getName(); - } - - /** - * @see com.vaadin.terminal.Resource#getMIMEType() - */ - @Override - public String getMIMEType() { - return FileTypeResolver.getMIMEType(sourceFile); - } - - /** - * Gets the length of cache expiration time. This gives the adapter the - * possibility cache streams sent to the client. The caching may be made in - * adapter or at the client if the client supports caching. Default is - * <code>DownloadStream.DEFAULT_CACHETIME</code>. - * - * @return Cache time in milliseconds. - */ - @Override - public long getCacheTime() { - return cacheTime; - } - - /** - * Sets the length of cache expiration time. This gives the adapter the - * possibility cache streams sent to the client. The caching may be made in - * adapter or at the client if the client supports caching. Zero or negavive - * value disbales the caching of this stream. - * - * @param cacheTime - * the cache time in milliseconds. - */ - public void setCacheTime(long cacheTime) { - this.cacheTime = cacheTime; - } - - /* documented in superclass */ - @Override - public int getBufferSize() { - return bufferSize; - } - - /** - * Sets the size of the download buffer used for this resource. - * - * @param bufferSize - * the size of the buffer in bytes. - */ - public void setBufferSize(int bufferSize) { - this.bufferSize = bufferSize; - } - -} diff --git a/src/com/vaadin/terminal/JavaScriptCallbackHelper.java b/src/com/vaadin/terminal/JavaScriptCallbackHelper.java deleted file mode 100644 index 265e578c6d..0000000000 --- a/src/com/vaadin/terminal/JavaScriptCallbackHelper.java +++ /dev/null @@ -1,116 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.shared.JavaScriptConnectorState; -import com.vaadin.terminal.gwt.client.JavaScriptConnectorHelper; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.AbstractJavaScriptComponent; -import com.vaadin.ui.JavaScript.JavaScriptCallbackRpc; -import com.vaadin.ui.JavaScriptFunction; - -/** - * Internal helper class used to implement functionality common to - * {@link AbstractJavaScriptComponent} and {@link AbstractJavaScriptExtension}. - * Corresponding support in client-side code is in - * {@link JavaScriptConnectorHelper}. - * <p> - * You should most likely no use this class directly. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public class JavaScriptCallbackHelper implements Serializable { - - private static final Method CALL_METHOD = ReflectTools.findMethod( - JavaScriptCallbackRpc.class, "call", String.class, JSONArray.class); - private AbstractClientConnector connector; - - private Map<String, JavaScriptFunction> callbacks = new HashMap<String, JavaScriptFunction>(); - private JavaScriptCallbackRpc javascriptCallbackRpc; - - public JavaScriptCallbackHelper(AbstractClientConnector connector) { - this.connector = connector; - } - - public void registerCallback(String functionName, - JavaScriptFunction javaScriptCallback) { - callbacks.put(functionName, javaScriptCallback); - JavaScriptConnectorState state = getConnectorState(); - if (state.getCallbackNames().add(functionName)) { - connector.requestRepaint(); - } - ensureRpc(); - } - - private JavaScriptConnectorState getConnectorState() { - JavaScriptConnectorState state = (JavaScriptConnectorState) connector - .getState(); - return state; - } - - private void ensureRpc() { - if (javascriptCallbackRpc == null) { - javascriptCallbackRpc = new JavaScriptCallbackRpc() { - @Override - public void call(String name, JSONArray arguments) { - JavaScriptFunction callback = callbacks.get(name); - try { - callback.call(arguments); - } catch (JSONException e) { - throw new IllegalArgumentException(e); - } - } - }; - connector.registerRpc(javascriptCallbackRpc); - } - } - - public void invokeCallback(String name, Object... arguments) { - if (callbacks.containsKey(name)) { - throw new IllegalStateException( - "Can't call callback " - + name - + " on the client because a callback with the same name is registered on the server."); - } - JSONArray args = new JSONArray(Arrays.asList(arguments)); - connector.addMethodInvocationToQueue( - JavaScriptCallbackRpc.class.getName(), CALL_METHOD, - new Object[] { name, args }); - connector.requestRepaint(); - } - - public void registerRpc(Class<?> rpcInterfaceType) { - if (rpcInterfaceType == JavaScriptCallbackRpc.class) { - // Ignore - return; - } - Map<String, Set<String>> rpcInterfaces = getConnectorState() - .getRpcInterfaces(); - String interfaceName = rpcInterfaceType.getName(); - if (!rpcInterfaces.containsKey(interfaceName)) { - Set<String> methodNames = new HashSet<String>(); - - for (Method method : rpcInterfaceType.getMethods()) { - methodNames.add(method.getName()); - } - - rpcInterfaces.put(interfaceName, methodNames); - connector.requestRepaint(); - } - } - -} diff --git a/src/com/vaadin/terminal/KeyMapper.java b/src/com/vaadin/terminal/KeyMapper.java deleted file mode 100644 index 3f19692ef1..0000000000 --- a/src/com/vaadin/terminal/KeyMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.util.HashMap; - -/** - * <code>KeyMapper</code> is the simple two-way map for generating textual keys - * for objects and retrieving the objects later with the key. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public class KeyMapper<V> implements Serializable { - - private int lastKey = 0; - - private final HashMap<V, String> objectKeyMap = new HashMap<V, String>(); - - private final HashMap<String, V> keyObjectMap = new HashMap<String, V>(); - - /** - * Gets key for an object. - * - * @param o - * the object. - */ - public String key(V o) { - - if (o == null) { - return "null"; - } - - // If the object is already mapped, use existing key - String key = objectKeyMap.get(o); - if (key != null) { - return key; - } - - // If the object is not yet mapped, map it - key = String.valueOf(++lastKey); - objectKeyMap.put(o, key); - keyObjectMap.put(key, o); - - return key; - } - - /** - * Retrieves object with the key. - * - * @param key - * the name with the desired value. - * @return the object with the key. - */ - public V get(String key) { - return keyObjectMap.get(key); - } - - /** - * Removes object from the mapper. - * - * @param removeobj - * the object to be removed. - */ - public void remove(V removeobj) { - final String key = objectKeyMap.get(removeobj); - - if (key != null) { - objectKeyMap.remove(removeobj); - keyObjectMap.remove(key); - } - } - - /** - * Removes all objects from the mapper. - */ - public void removeAll() { - objectKeyMap.clear(); - keyObjectMap.clear(); - } -} diff --git a/src/com/vaadin/terminal/LegacyPaint.java b/src/com/vaadin/terminal/LegacyPaint.java deleted file mode 100644 index ea93e3db7f..0000000000 --- a/src/com/vaadin/terminal/LegacyPaint.java +++ /dev/null @@ -1,85 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal; - -import java.io.Serializable; - -import com.vaadin.terminal.PaintTarget.PaintStatus; -import com.vaadin.ui.Component; -import com.vaadin.ui.HasComponents; - -public class LegacyPaint implements Serializable { - /** - * - * <p> - * Paints the Paintable into a UIDL stream. This method creates the UIDL - * sequence describing it and outputs it to the given UIDL stream. - * </p> - * - * <p> - * It is called when the contents of the component should be painted in - * response to the component first being shown or having been altered so - * that its visual representation is changed. - * </p> - * - * <p> - * <b>Do not override this to paint your component.</b> Override - * {@link #paintContent(PaintTarget)} instead. - * </p> - * - * - * @param target - * the target UIDL stream where the component should paint itself - * to. - * @throws PaintException - * if the paint operation failed. - */ - public static void paint(Component component, PaintTarget target) - throws PaintException { - // Only paint content of visible components. - if (!isVisibleInContext(component)) { - return; - } - - final String tag = target.getTag(component); - final PaintStatus status = target.startPaintable(component, tag); - if (PaintStatus.CACHED == status) { - // nothing to do but flag as cached and close the paintable tag - target.addAttribute("cached", true); - } else { - // Paint the contents of the component - if (component instanceof Vaadin6Component) { - ((Vaadin6Component) component).paintContent(target); - } - - } - target.endPaintable(component); - - } - - /** - * Checks if the component is visible and its parent is visible, - * recursively. - * <p> - * This is only a helper until paint is moved away from this class. - * - * @return - */ - protected static boolean isVisibleInContext(Component c) { - HasComponents p = c.getParent(); - while (p != null) { - if (!p.isVisible()) { - return false; - } - p = p.getParent(); - } - if (c.getParent() != null && !c.getParent().isComponentVisible(c)) { - return false; - } - - // All parents visible, return this state - return c.isVisible(); - } - -} diff --git a/src/com/vaadin/terminal/Page.java b/src/com/vaadin/terminal/Page.java deleted file mode 100644 index a068e7573e..0000000000 --- a/src/com/vaadin/terminal/Page.java +++ /dev/null @@ -1,646 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.EventObject; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -import com.vaadin.event.EventRouter; -import com.vaadin.shared.ui.root.PageClientRpc; -import com.vaadin.terminal.WrappedRequest.BrowserDetails; -import com.vaadin.terminal.gwt.client.ui.notification.VNotification; -import com.vaadin.terminal.gwt.client.ui.root.VRoot; -import com.vaadin.terminal.gwt.server.WebApplicationContext; -import com.vaadin.terminal.gwt.server.WebBrowser; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.JavaScript; -import com.vaadin.ui.Notification; -import com.vaadin.ui.Root; - -public class Page implements Serializable { - - /** - * Listener that gets notified when the size of the browser window - * containing the root has changed. - * - * @see Root#addListener(BrowserWindowResizeListener) - */ - public interface BrowserWindowResizeListener extends Serializable { - /** - * Invoked when the browser window containing a Root has been resized. - * - * @param event - * a browser window resize event - */ - public void browserWindowResized(BrowserWindowResizeEvent event); - } - - /** - * Event that is fired when a browser window containing a root is resized. - */ - public class BrowserWindowResizeEvent extends EventObject { - - private final int width; - private final int height; - - /** - * Creates a new event - * - * @param source - * the root for which the browser window has been resized - * @param width - * the new width of the browser window - * @param height - * the new height of the browser window - */ - public BrowserWindowResizeEvent(Page source, int width, int height) { - super(source); - this.width = width; - this.height = height; - } - - @Override - public Page getSource() { - return (Page) super.getSource(); - } - - /** - * Gets the new browser window height - * - * @return an integer with the new pixel height of the browser window - */ - public int getHeight() { - return height; - } - - /** - * Gets the new browser window width - * - * @return an integer with the new pixel width of the browser window - */ - public int getWidth() { - return width; - } - } - - /** - * Private class for storing properties related to opening resources. - */ - private class OpenResource implements Serializable { - - /** - * The resource to open - */ - private final Resource resource; - - /** - * The name of the target window - */ - private final String name; - - /** - * The width of the target window - */ - private final int width; - - /** - * The height of the target window - */ - private final int height; - - /** - * The border style of the target window - */ - private final int border; - - /** - * Creates a new open resource. - * - * @param resource - * The resource to open - * @param name - * The name of the target window - * @param width - * The width of the target window - * @param height - * The height of the target window - * @param border - * The border style of the target window - */ - private OpenResource(Resource resource, String name, int width, - int height, int border) { - this.resource = resource; - this.name = name; - this.width = width; - this.height = height; - this.border = border; - } - - /** - * Paints the open request. Should be painted inside the window. - * - * @param target - * the paint target - * @throws PaintException - * if the paint operation fails - */ - private void paintContent(PaintTarget target) throws PaintException { - target.startTag("open"); - target.addAttribute("src", resource); - if (name != null && name.length() > 0) { - target.addAttribute("name", name); - } - if (width >= 0) { - target.addAttribute("width", width); - } - if (height >= 0) { - target.addAttribute("height", height); - } - switch (border) { - case BORDER_MINIMAL: - target.addAttribute("border", "minimal"); - break; - case BORDER_NONE: - target.addAttribute("border", "none"); - break; - } - - target.endTag("open"); - } - } - - private static final Method BROWSWER_RESIZE_METHOD = ReflectTools - .findMethod(BrowserWindowResizeListener.class, - "browserWindowResized", BrowserWindowResizeEvent.class); - - /** - * A border style used for opening resources in a window without a border. - */ - public static final int BORDER_NONE = 0; - - /** - * A border style used for opening resources in a window with a minimal - * border. - */ - public static final int BORDER_MINIMAL = 1; - - /** - * A border style that indicates that the default border style should be - * used when opening resources. - */ - public static final int BORDER_DEFAULT = 2; - - /** - * Listener that listens changes in URI fragment. - */ - public interface FragmentChangedListener extends Serializable { - public void fragmentChanged(FragmentChangedEvent event); - } - - private static final Method FRAGMENT_CHANGED_METHOD = ReflectTools - .findMethod(Page.FragmentChangedListener.class, "fragmentChanged", - FragmentChangedEvent.class); - - /** - * Resources to be opened automatically on next repaint. The list is - * automatically cleared when it has been sent to the client. - */ - private final LinkedList<OpenResource> openList = new LinkedList<OpenResource>(); - - /** - * A list of notifications that are waiting to be sent to the client. - * Cleared (set to null) when the notifications have been sent. - */ - private List<Notification> notifications; - - /** - * Event fired when uri fragment changes. - */ - public class FragmentChangedEvent extends EventObject { - - /** - * The new uri fragment - */ - private final String fragment; - - /** - * Creates a new instance of UriFragmentReader change event. - * - * @param source - * the Source of the event. - */ - public FragmentChangedEvent(Page source, String fragment) { - super(source); - this.fragment = fragment; - } - - /** - * Gets the root in which the fragment has changed. - * - * @return the root in which the fragment has changed - */ - public Page getPage() { - return (Page) getSource(); - } - - /** - * Get the new fragment - * - * @return the new fragment - */ - public String getFragment() { - return fragment; - } - } - - private EventRouter eventRouter; - - /** - * The current URI fragment. - */ - private String fragment; - - private final Root root; - - private int browserWindowWidth = -1; - private int browserWindowHeight = -1; - - private JavaScript javaScript; - - public Page(Root root) { - this.root = root; - } - - private void addListener(Class<?> eventType, Object target, Method method) { - if (eventRouter == null) { - eventRouter = new EventRouter(); - } - eventRouter.addListener(eventType, target, method); - } - - private void removeListener(Class<?> eventType, Object target, Method method) { - if (eventRouter != null) { - eventRouter.removeListener(eventType, target, method); - } - } - - public void addListener(Page.FragmentChangedListener listener) { - addListener(FragmentChangedEvent.class, listener, - FRAGMENT_CHANGED_METHOD); - } - - public void removeListener(Page.FragmentChangedListener listener) { - removeListener(FragmentChangedEvent.class, listener, - FRAGMENT_CHANGED_METHOD); - } - - /** - * Sets URI fragment. Optionally fires a {@link FragmentChangedEvent} - * - * @param newFragment - * id of the new fragment - * @param fireEvent - * true to fire event - * @see FragmentChangedEvent - * @see Page.FragmentChangedListener - */ - public void setFragment(String newFragment, boolean fireEvents) { - if (newFragment == null) { - throw new NullPointerException("The fragment may not be null"); - } - if (!newFragment.equals(fragment)) { - fragment = newFragment; - if (fireEvents) { - fireEvent(new FragmentChangedEvent(this, newFragment)); - } - root.requestRepaint(); - } - } - - private void fireEvent(EventObject event) { - if (eventRouter != null) { - eventRouter.fireEvent(event); - } - } - - /** - * Sets URI fragment. This method fires a {@link FragmentChangedEvent} - * - * @param newFragment - * id of the new fragment - * @see FragmentChangedEvent - * @see Page.FragmentChangedListener - */ - public void setFragment(String newFragment) { - setFragment(newFragment, true); - } - - /** - * Gets currently set URI fragment. - * <p> - * To listen changes in fragment, hook a - * {@link Page.FragmentChangedListener}. - * - * @return the current fragment in browser uri or null if not known - */ - public String getFragment() { - return fragment; - } - - public void init(WrappedRequest request) { - BrowserDetails browserDetails = request.getBrowserDetails(); - if (browserDetails != null) { - fragment = browserDetails.getUriFragment(); - } - } - - public WebBrowser getWebBrowser() { - return ((WebApplicationContext) root.getApplication().getContext()) - .getBrowser(); - } - - public void setBrowserWindowSize(Integer width, Integer height) { - boolean fireEvent = false; - - if (width != null) { - int newWidth = width.intValue(); - if (newWidth != browserWindowWidth) { - browserWindowWidth = newWidth; - fireEvent = true; - } - } - - if (height != null) { - int newHeight = height.intValue(); - if (newHeight != browserWindowHeight) { - browserWindowHeight = newHeight; - fireEvent = true; - } - } - - if (fireEvent) { - fireEvent(new BrowserWindowResizeEvent(this, browserWindowWidth, - browserWindowHeight)); - } - - } - - /** - * Adds a new {@link BrowserWindowResizeListener} to this root. The listener - * will be notified whenever the browser window within which this root - * resides is resized. - * - * @param resizeListener - * the listener to add - * - * @see BrowserWindowResizeListener#browserWindowResized(BrowserWindowResizeEvent) - * @see #setResizeLazy(boolean) - */ - public void addListener(BrowserWindowResizeListener resizeListener) { - addListener(BrowserWindowResizeEvent.class, resizeListener, - BROWSWER_RESIZE_METHOD); - } - - /** - * Removes a {@link BrowserWindowResizeListener} from this root. The - * listener will no longer be notified when the browser window is resized. - * - * @param resizeListener - * the listener to remove - */ - public void removeListener(BrowserWindowResizeListener resizeListener) { - removeListener(BrowserWindowResizeEvent.class, resizeListener, - BROWSWER_RESIZE_METHOD); - } - - /** - * Gets the last known height of the browser window in which this root - * resides. - * - * @return the browser window height in pixels - */ - public int getBrowserWindowHeight() { - return browserWindowHeight; - } - - /** - * Gets the last known width of the browser window in which this root - * resides. - * - * @return the browser window width in pixels - */ - public int getBrowserWindowWidth() { - return browserWindowWidth; - } - - public JavaScript getJavaScript() { - if (javaScript == null) { - // Create and attach on first use - javaScript = new JavaScript(); - javaScript.extend(root); - } - - return javaScript; - } - - public void paintContent(PaintTarget target) throws PaintException { - if (!openList.isEmpty()) { - for (final Iterator<OpenResource> i = openList.iterator(); i - .hasNext();) { - (i.next()).paintContent(target); - } - openList.clear(); - } - - // Paint notifications - if (notifications != null) { - target.startTag("notifications"); - for (final Iterator<Notification> it = notifications.iterator(); it - .hasNext();) { - final Notification n = it.next(); - target.startTag("notification"); - if (n.getCaption() != null) { - target.addAttribute( - VNotification.ATTRIBUTE_NOTIFICATION_CAPTION, - n.getCaption()); - } - if (n.getDescription() != null) { - target.addAttribute( - VNotification.ATTRIBUTE_NOTIFICATION_MESSAGE, - n.getDescription()); - } - if (n.getIcon() != null) { - target.addAttribute( - VNotification.ATTRIBUTE_NOTIFICATION_ICON, - n.getIcon()); - } - if (!n.isHtmlContentAllowed()) { - target.addAttribute( - VRoot.NOTIFICATION_HTML_CONTENT_NOT_ALLOWED, true); - } - target.addAttribute( - VNotification.ATTRIBUTE_NOTIFICATION_POSITION, - n.getPosition()); - target.addAttribute(VNotification.ATTRIBUTE_NOTIFICATION_DELAY, - n.getDelayMsec()); - if (n.getStyleName() != null) { - target.addAttribute( - VNotification.ATTRIBUTE_NOTIFICATION_STYLE, - n.getStyleName()); - } - target.endTag("notification"); - } - target.endTag("notifications"); - notifications = null; - } - - if (fragment != null) { - target.addAttribute(VRoot.FRAGMENT_VARIABLE, fragment); - } - - } - - /** - * Opens the given resource in this root. The contents of this Root is - * replaced by the {@code Resource}. - * - * @param resource - * the resource to show in this root - */ - public void open(Resource resource) { - openList.add(new OpenResource(resource, null, -1, -1, BORDER_DEFAULT)); - root.requestRepaint(); - } - - /** - * Opens the given resource in a window with the given name. - * <p> - * The supplied {@code windowName} is used as the target name in a - * window.open call in the client. This means that special values such as - * "_blank", "_self", "_top", "_parent" have special meaning. An empty or - * <code>null</code> window name is also a special case. - * </p> - * <p> - * "", null and "_self" as {@code windowName} all causes the resource to be - * opened in the current window, replacing any old contents. For - * downloadable content you should avoid "_self" as "_self" causes the - * client to skip rendering of any other changes as it considers them - * irrelevant (the page will be replaced by the resource). This can speed up - * the opening of a resource, but it might also put the client side into an - * inconsistent state if the window content is not completely replaced e.g., - * if the resource is downloaded instead of displayed in the browser. - * </p> - * <p> - * "_blank" as {@code windowName} causes the resource to always be opened in - * a new window or tab (depends on the browser and browser settings). - * </p> - * <p> - * "_top" and "_parent" as {@code windowName} works as specified by the HTML - * standard. - * </p> - * <p> - * Any other {@code windowName} will open the resource in a window with that - * name, either by opening a new window/tab in the browser or by replacing - * the contents of an existing window with that name. - * </p> - * - * @param resource - * the resource. - * @param windowName - * the name of the window. - */ - public void open(Resource resource, String windowName) { - openList.add(new OpenResource(resource, windowName, -1, -1, - BORDER_DEFAULT)); - root.requestRepaint(); - } - - /** - * Opens the given resource in a window with the given size, border and - * name. For more information on the meaning of {@code windowName}, see - * {@link #open(Resource, String)}. - * - * @param resource - * the resource. - * @param windowName - * the name of the window. - * @param width - * the width of the window in pixels - * @param height - * the height of the window in pixels - * @param border - * the border style of the window. See {@link #BORDER_NONE - * Window.BORDER_* constants} - */ - public void open(Resource resource, String windowName, int width, - int height, int border) { - openList.add(new OpenResource(resource, windowName, width, height, - border)); - root.requestRepaint(); - } - - /** - * Internal helper method to actually add a notification. - * - * @param notification - * the notification to add - */ - private void addNotification(Notification notification) { - if (notifications == null) { - notifications = new LinkedList<Notification>(); - } - notifications.add(notification); - root.requestRepaint(); - } - - /** - * Shows a notification message. - * - * @see Notification - * - * @param notification - * The notification message to show - * - * @deprecated Use Notification.show(Page) instead. - */ - @Deprecated - public void showNotification(Notification notification) { - addNotification(notification); - } - - /** - * Gets the Page to which the current root belongs. This is automatically - * defined when processing requests to the server. In other cases, (e.g. - * from background threads), the current root is not automatically defined. - * - * @see Root#getCurrent() - * - * @return the current page instance if available, otherwise - * <code>null</code> - */ - public static Page getCurrent() { - Root currentRoot = Root.getCurrent(); - if (currentRoot == null) { - return null; - } - return currentRoot.getPage(); - } - - /** - * Sets the page title. The page title is displayed by the browser e.g. as - * the title of the browser window or as the title of the tab. - * - * @param title - * the new page title to set - */ - public void setTitle(String title) { - root.getRpcProxy(PageClientRpc.class).setTitle(title); - } - -} diff --git a/src/com/vaadin/terminal/PaintException.java b/src/com/vaadin/terminal/PaintException.java deleted file mode 100644 index 68f689b7f1..0000000000 --- a/src/com/vaadin/terminal/PaintException.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.IOException; -import java.io.Serializable; - -/** - * <code>PaintExcepection</code> is thrown if painting of a component fails. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class PaintException extends IOException implements Serializable { - - /** - * Constructs an instance of <code>PaintExeception</code> with the specified - * detail message. - * - * @param msg - * the detail message. - */ - public PaintException(String msg) { - super(msg); - } - - /** - * Constructs an instance of <code>PaintExeception</code> with the specified - * detail message and cause. - * - * @param msg - * the detail message. - * @param cause - * the cause - */ - public PaintException(String msg, Throwable cause) { - super(msg, cause); - } - - /** - * Constructs an instance of <code>PaintExeception</code> from IOException. - * - * @param exception - * the original exception. - */ - public PaintException(IOException exception) { - super(exception.getMessage()); - } -} diff --git a/src/com/vaadin/terminal/PaintTarget.java b/src/com/vaadin/terminal/PaintTarget.java deleted file mode 100644 index b658c9f4a3..0000000000 --- a/src/com/vaadin/terminal/PaintTarget.java +++ /dev/null @@ -1,509 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.util.Map; - -import com.vaadin.terminal.StreamVariable.StreamingStartEvent; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.Paintable; -import com.vaadin.terminal.gwt.server.ClientConnector; -import com.vaadin.ui.Component; - -/** - * This interface defines the methods for painting XML to the UIDL stream. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface PaintTarget extends Serializable { - - /** - * Prints single XMLsection. - * - * Prints full XML section. The section data is escaped from XML tags and - * surrounded by XML start and end-tags. - * - * @param sectionTagName - * the name of the tag. - * @param sectionData - * the scetion data. - * @throws PaintException - * if the paint operation failed. - */ - public void addSection(String sectionTagName, String sectionData) - throws PaintException; - - /** - * Result of starting to paint a Paintable ( - * {@link PaintTarget#startPaintable(Component, String)}). - * - * @since 7.0 - */ - public enum PaintStatus { - /** - * Painting started, addVariable() and addAttribute() etc. methods may - * be called. - */ - PAINTING, - /** - * A previously unpainted or painted {@link Paintable} has been queued - * be created/update later in a separate change in the same set of - * changes. - */ - CACHED - } - - /** - * Prints element start tag of a paintable section. Starts a paintable - * section using the given tag. The PaintTarget may implement a caching - * scheme, that checks the paintable has actually changed or can a cached - * version be used instead. This method should call the startTag method. - * <p> - * If the Paintable is found in cache and this function returns true it may - * omit the content and close the tag, in which case cached content should - * be used. - * </p> - * <p> - * This method may also add only a reference to the paintable and queue the - * paintable to be painted separately. - * </p> - * <p> - * Each paintable being painted should be closed by a matching - * {@link #endPaintable(Component)} regardless of the {@link PaintStatus} - * returned. - * </p> - * - * @param paintable - * the paintable to start. - * @param tag - * the name of the start tag. - * @return {@link PaintStatus} - ready to paint or already cached on the - * client (also used for sub paintables that are painted later - * separately) - * @throws PaintException - * if the paint operation failed. - * @see #startTag(String) - * @since 7.0 (previously using startTag(Paintable, String)) - */ - public PaintStatus startPaintable(Component paintable, String tag) - throws PaintException; - - /** - * Prints paintable element end tag. - * - * Calls to {@link #startPaintable(Component, String)}should be matched by - * {@link #endPaintable(Component)}. If the parent tag is closed before - * every child tag is closed a PaintException is raised. - * - * @param paintable - * the paintable to close. - * @throws PaintException - * if the paint operation failed. - * @since 7.0 (previously using engTag(String)) - */ - public void endPaintable(Component paintable) throws PaintException; - - /** - * Prints element start tag. - * - * <pre> - * Todo: - * Checking of input values - * </pre> - * - * @param tagName - * the name of the start tag. - * @throws PaintException - * if the paint operation failed. - */ - public void startTag(String tagName) throws PaintException; - - /** - * Prints element end tag. - * - * If the parent tag is closed before every child tag is closed an - * PaintException is raised. - * - * @param tagName - * the name of the end tag. - * @throws PaintException - * if the paint operation failed. - */ - public void endTag(String tagName) throws PaintException; - - /** - * Adds a boolean attribute to component. Atributes must be added before any - * content is written. - * - * @param name - * the Attribute name. - * @param value - * the Attribute value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addAttribute(String name, boolean value) throws PaintException; - - /** - * Adds a integer attribute to component. Atributes must be added before any - * content is written. - * - * @param name - * the Attribute name. - * @param value - * the Attribute value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addAttribute(String name, int value) throws PaintException; - - /** - * Adds a resource attribute to component. Atributes must be added before - * any content is written. - * - * @param name - * the Attribute name - * @param value - * the Attribute value - * - * @throws PaintException - * if the paint operation failed. - */ - public void addAttribute(String name, Resource value) throws PaintException; - - /** - * Adds details about {@link StreamVariable} to the UIDL stream. Eg. in web - * terminals Receivers are typically rendered for the client side as URLs, - * where the client side implementation can do an http post request. - * <p> - * The urls in UIDL message may use Vaadin specific protocol. Before - * actually using the urls on the client side, they should be passed via - * {@link ApplicationConnection#translateVaadinUri(String)}. - * <p> - * Note that in current terminal implementation StreamVariables are cleaned - * from the terminal only when: - * <ul> - * <li>a StreamVariable with same name replaces an old one - * <li>the variable owner is no more attached - * <li>the developer signals this by calling - * {@link StreamingStartEvent#disposeStreamVariable()} - * </ul> - * Most commonly a component developer can just ignore this issue, but with - * strict memory requirements and lots of StreamVariables implementations - * that reserve a lot of memory this may be a critical issue. - * - * @param owner - * the ReceiverOwner that can track the progress of streaming to - * the given StreamVariable - * @param name - * an identifying name for the StreamVariable - * @param value - * the StreamVariable to paint - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, - StreamVariable value) throws PaintException; - - /** - * Adds a long attribute to component. Atributes must be added before any - * content is written. - * - * @param name - * the Attribute name. - * @param value - * the Attribute value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addAttribute(String name, long value) throws PaintException; - - /** - * Adds a float attribute to component. Atributes must be added before any - * content is written. - * - * @param name - * the Attribute name. - * @param value - * the Attribute value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addAttribute(String name, float value) throws PaintException; - - /** - * Adds a double attribute to component. Atributes must be added before any - * content is written. - * - * @param name - * the Attribute name. - * @param value - * the Attribute value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addAttribute(String name, double value) throws PaintException; - - /** - * Adds a string attribute to component. Atributes must be added before any - * content is written. - * - * @param name - * the Boolean attribute name. - * @param value - * the Boolean attribute value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addAttribute(String name, String value) throws PaintException; - - /** - * TODO - * - * @param name - * @param value - * @throws PaintException - */ - public void addAttribute(String name, Map<?, ?> value) - throws PaintException; - - /** - * Adds a Paintable type attribute. On client side the value will be a - * terminal specific reference to corresponding component on client side - * implementation. - * - * @param name - * the name of the attribute - * @param value - * the Paintable to be referenced on client side - * @throws PaintException - */ - public void addAttribute(String name, Component value) - throws PaintException; - - /** - * Adds a string type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * @param value - * the Variable initial value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, String value) - throws PaintException; - - /** - * Adds a int type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * @param value - * the Variable initial value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, int value) - throws PaintException; - - /** - * Adds a long type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * @param value - * the Variable initial value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, long value) - throws PaintException; - - /** - * Adds a float type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * @param value - * the Variable initial value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, float value) - throws PaintException; - - /** - * Adds a double type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * @param value - * the Variable initial value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, double value) - throws PaintException; - - /** - * Adds a boolean type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * @param value - * the Variable initial value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, boolean value) - throws PaintException; - - /** - * Adds a string array type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * @param value - * the Variable initial value. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addVariable(VariableOwner owner, String name, String[] value) - throws PaintException; - - /** - * Adds a Paintable type variable. On client side the variable value will be - * a terminal specific reference to corresponding component on client side - * implementation. When updated from client side, terminal will map the - * client side component reference back to a corresponding server side - * reference. - * - * @param owner - * the Listener for variable changes - * @param name - * the name of the variable - * @param value - * the initial value of the variable - * - * @throws PaintException - * if the paint oparation fails - */ - public void addVariable(VariableOwner owner, String name, Component value) - throws PaintException; - - /** - * Adds a upload stream type variable. - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * - * @throws PaintException - * if the paint operation failed. - */ - public void addUploadStreamVariable(VariableOwner owner, String name) - throws PaintException; - - /** - * Prints single XML section. - * <p> - * Prints full XML section. The section data must be XML and it is - * surrounded by XML start and end-tags. - * </p> - * - * @param sectionTagName - * the tag name. - * @param sectionData - * the section data to be printed. - * @param namespace - * the namespace. - * @throws PaintException - * if the paint operation failed. - */ - public void addXMLSection(String sectionTagName, String sectionData, - String namespace) throws PaintException; - - /** - * Adds UIDL directly. The UIDL must be valid in accordance with the - * UIDL.dtd - * - * @param uidl - * the UIDL to be added. - * @throws PaintException - * if the paint operation failed. - */ - public void addUIDL(java.lang.String uidl) throws PaintException; - - /** - * Adds text node. All the contents of the text are XML-escaped. - * - * @param text - * the Text to add - * @throws PaintException - * if the paint operation failed. - */ - void addText(String text) throws PaintException; - - /** - * Adds CDATA node to target UIDL-tree. - * - * @param text - * the Character data to add - * @throws PaintException - * if the paint operation failed. - * @since 3.1 - */ - void addCharacterData(String text) throws PaintException; - - public void addAttribute(String string, Object[] keys); - - /** - * @return the "tag" string used in communication to present given - * {@link ClientConnector} type. Terminal may define how to present - * the connector. - */ - public String getTag(ClientConnector paintable); - - /** - * @return true if a full repaint has been requested. E.g. refresh in a - * browser window or such. - */ - public boolean isFullRepaint(); - -} diff --git a/src/com/vaadin/terminal/RequestHandler.java b/src/com/vaadin/terminal/RequestHandler.java deleted file mode 100644 index f37201715d..0000000000 --- a/src/com/vaadin/terminal/RequestHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.IOException; -import java.io.Serializable; - -import com.vaadin.Application; - -/** - * Handler for producing a response to non-UIDL requests. Handlers can be added - * to applications using {@link Application#addRequestHandler(RequestHandler)} - */ -public interface RequestHandler extends Serializable { - - /** - * Handles a non-UIDL request. If a response is written, this method should - * return <code>false</code> to indicate that no more request handlers - * should be invoked for the request. - * - * @param application - * The application to which the request belongs - * @param request - * The request to handle - * @param response - * The response object to which a response can be written. - * @return true if a response has been written and no further request - * handlers should be called, otherwise false - * @throws IOException - */ - boolean handleRequest(Application application, WrappedRequest request, - WrappedResponse response) throws IOException; - -} diff --git a/src/com/vaadin/terminal/Resource.java b/src/com/vaadin/terminal/Resource.java deleted file mode 100644 index 58dc4fea9d..0000000000 --- a/src/com/vaadin/terminal/Resource.java +++ /dev/null @@ -1,26 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; - -/** - * <code>Resource</code> provided to the client terminal. Support for actually - * displaying the resource type is left to the terminal. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Resource extends Serializable { - - /** - * Gets the MIME type of the resource. - * - * @return the MIME type of the resource. - */ - public String getMIMEType(); -} diff --git a/src/com/vaadin/terminal/Scrollable.java b/src/com/vaadin/terminal/Scrollable.java deleted file mode 100644 index 472954c556..0000000000 --- a/src/com/vaadin/terminal/Scrollable.java +++ /dev/null @@ -1,80 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; - -/** - * <p> - * This interface is implemented by all visual objects that can be scrolled - * programmatically from the server-side. The unit of scrolling is pixel. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Scrollable extends Serializable { - - /** - * Gets scroll left offset. - * - * <p> - * Scrolling offset is the number of pixels this scrollable has been - * scrolled right. - * </p> - * - * @return Horizontal scrolling position in pixels. - */ - public int getScrollLeft(); - - /** - * Sets scroll left offset. - * - * <p> - * Scrolling offset is the number of pixels this scrollable has been - * scrolled right. - * </p> - * - * @param scrollLeft - * the xOffset. - */ - public void setScrollLeft(int scrollLeft); - - /** - * Gets scroll top offset. - * - * <p> - * Scrolling offset is the number of pixels this scrollable has been - * scrolled down. - * </p> - * - * @return Vertical scrolling position in pixels. - */ - public int getScrollTop(); - - /** - * Sets scroll top offset. - * - * <p> - * Scrolling offset is the number of pixels this scrollable has been - * scrolled down. - * </p> - * - * <p> - * The scrolling position is limited by the current height of the content - * area. If the position is below the height, it is scrolled to the bottom. - * However, if the same response also adds height to the content area, - * scrolling to bottom only scrolls to the bottom of the previous content - * area. - * </p> - * - * @param scrollTop - * the yOffset. - */ - public void setScrollTop(int scrollTop); - -} diff --git a/src/com/vaadin/terminal/Sizeable.java b/src/com/vaadin/terminal/Sizeable.java deleted file mode 100644 index e3c98e0fa9..0000000000 --- a/src/com/vaadin/terminal/Sizeable.java +++ /dev/null @@ -1,242 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; - -/** - * Interface to be implemented by components wishing to display some object that - * may be dynamically resized during runtime. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Sizeable extends Serializable { - - /** - * @deprecated from 7.0, use {@link Unit#PIXELS} instead   - */ - @Deprecated - public static final Unit UNITS_PIXELS = Unit.PIXELS; - - /** - * @deprecated from 7.0, use {@link Unit#POINTS} instead   - */ - @Deprecated - public static final Unit UNITS_POINTS = Unit.POINTS; - - /** - * @deprecated from 7.0, use {@link Unit#PICAS} instead   - */ - @Deprecated - public static final Unit UNITS_PICAS = Unit.PICAS; - - /** - * @deprecated from 7.0, use {@link Unit#EM} instead   - */ - @Deprecated - public static final Unit UNITS_EM = Unit.EM; - - /** - * @deprecated from 7.0, use {@link Unit#EX} instead   - */ - @Deprecated - public static final Unit UNITS_EX = Unit.EX; - - /** - * @deprecated from 7.0, use {@link Unit#MM} instead   - */ - @Deprecated - public static final Unit UNITS_MM = Unit.MM; - - /** - * @deprecated from 7.0, use {@link Unit#CM} instead   - */ - @Deprecated - public static final Unit UNITS_CM = Unit.CM; - - /** - * @deprecated from 7.0, use {@link Unit#INCH} instead   - */ - @Deprecated - public static final Unit UNITS_INCH = Unit.INCH; - - /** - * @deprecated from 7.0, use {@link Unit#PERCENTAGE} instead   - */ - @Deprecated - public static final Unit UNITS_PERCENTAGE = Unit.PERCENTAGE; - - public static final float SIZE_UNDEFINED = -1; - - public enum Unit { - /** - * Unit code representing pixels. - */ - PIXELS("px"), - /** - * Unit code representing points (1/72nd of an inch). - */ - POINTS("pt"), - /** - * Unit code representing picas (12 points). - */ - PICAS("pc"), - /** - * Unit code representing the font-size of the relevant font. - */ - EM("em"), - /** - * Unit code representing the x-height of the relevant font. - */ - EX("ex"), - /** - * Unit code representing millimeters. - */ - MM("mm"), - /** - * Unit code representing centimeters. - */ - CM("cm"), - /** - * Unit code representing inches. - */ - INCH("in"), - /** - * Unit code representing in percentage of the containing element - * defined by terminal. - */ - PERCENTAGE("%"); - - private String symbol; - - private Unit(String symbol) { - this.symbol = symbol; - } - - public String getSymbol() { - return symbol; - } - - @Override - public String toString() { - return symbol; - } - - public static Unit getUnitFromSymbol(String symbol) { - if (symbol == null) { - return Unit.PIXELS; // Defaults to pixels - } - for (Unit unit : Unit.values()) { - if (symbol.equals(unit.getSymbol())) { - return unit; - } - } - return Unit.PIXELS; // Defaults to pixels - } - } - - /** - * Gets the width of the object. Negative number implies unspecified size - * (terminal is free to set the size). - * - * @return width of the object in units specified by widthUnits property. - */ - public float getWidth(); - - /** - * Gets the height of the object. Negative number implies unspecified size - * (terminal is free to set the size). - * - * @return height of the object in units specified by heightUnits property. - */ - public float getHeight(); - - /** - * Gets the width property units. - * - * @return units used in width property. - */ - public Unit getWidthUnits(); - - /** - * Gets the height property units. - * - * @return units used in height property. - */ - public Unit getHeightUnits(); - - /** - * Sets the height of the component using String presentation. - * - * String presentation is similar to what is used in Cascading Style Sheets. - * Size can be length or percentage of available size. - * - * The empty string ("") or null will unset the height and set the units to - * pixels. - * - * See <a - * href="http://www.w3.org/TR/REC-CSS2/syndata.html#value-def-length">CSS - * specification</a> for more details. - * - * @param height - * in CSS style string representation - */ - public void setHeight(String height); - - /** - * Sets the width of the object. Negative number implies unspecified size - * (terminal is free to set the size). - * - * @param width - * the width of the object. - * @param unit - * the unit used for the width. - */ - public void setWidth(float width, Unit unit); - - /** - * Sets the height of the object. Negative number implies unspecified size - * (terminal is free to set the size). - * - * @param height - * the height of the object. - * @param unit - * the unit used for the width. - */ - public void setHeight(float height, Unit unit); - - /** - * Sets the width of the component using String presentation. - * - * String presentation is similar to what is used in Cascading Style Sheets. - * Size can be length or percentage of available size. - * - * The empty string ("") or null will unset the width and set the units to - * pixels. - * - * See <a - * href="http://www.w3.org/TR/REC-CSS2/syndata.html#value-def-length">CSS - * specification</a> for more details. - * - * @param width - * in CSS style string representation, null or empty string to - * reset - */ - public void setWidth(String width); - - /** - * Sets the size to 100% x 100%. - */ - public void setSizeFull(); - - /** - * Clears any size settings. - */ - public void setSizeUndefined(); - -} diff --git a/src/com/vaadin/terminal/StreamResource.java b/src/com/vaadin/terminal/StreamResource.java deleted file mode 100644 index 1afd91dc08..0000000000 --- a/src/com/vaadin/terminal/StreamResource.java +++ /dev/null @@ -1,222 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.InputStream; -import java.io.Serializable; - -import com.vaadin.Application; -import com.vaadin.service.FileTypeResolver; - -/** - * <code>StreamResource</code> is a resource provided to the client directly by - * the application. The strean resource is fetched from URI that is most often - * in the context of the application or window. The resource is automatically - * registered to window in creation. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class StreamResource implements ApplicationResource { - - /** - * Source stream the downloaded content is fetched from. - */ - private StreamSource streamSource = null; - - /** - * Explicit mime-type. - */ - private String MIMEType = null; - - /** - * Filename. - */ - private String filename; - - /** - * Application. - */ - private final Application application; - - /** - * Default buffer size for this stream resource. - */ - private int bufferSize = 0; - - /** - * Default cache time for this stream resource. - */ - private long cacheTime = DEFAULT_CACHETIME; - - /** - * Creates a new stream resource for downloading from stream. - * - * @param streamSource - * the source Stream. - * @param filename - * the name of the file. - * @param application - * the Application object. - */ - public StreamResource(StreamSource streamSource, String filename, - Application application) { - - this.application = application; - setFilename(filename); - setStreamSource(streamSource); - - // Register to application - application.addResource(this); - - } - - /** - * @see com.vaadin.terminal.Resource#getMIMEType() - */ - @Override - public String getMIMEType() { - if (MIMEType != null) { - return MIMEType; - } - return FileTypeResolver.getMIMEType(filename); - } - - /** - * Sets the mime type of the resource. - * - * @param MIMEType - * the MIME type to be set. - */ - public void setMIMEType(String MIMEType) { - this.MIMEType = MIMEType; - } - - /** - * Returns the source for this <code>StreamResource</code>. StreamSource is - * queried when the resource is about to be streamed to the client. - * - * @return Source of the StreamResource. - */ - public StreamSource getStreamSource() { - return streamSource; - } - - /** - * Sets the source for this <code>StreamResource</code>. - * <code>StreamSource</code> is queried when the resource is about to be - * streamed to the client. - * - * @param streamSource - * the source to set. - */ - public void setStreamSource(StreamSource streamSource) { - this.streamSource = streamSource; - } - - /** - * Gets the filename. - * - * @return the filename. - */ - @Override - public String getFilename() { - return filename; - } - - /** - * Sets the filename. - * - * @param filename - * the filename to set. - */ - public void setFilename(String filename) { - this.filename = filename; - } - - /** - * @see com.vaadin.terminal.ApplicationResource#getApplication() - */ - @Override - public Application getApplication() { - return application; - } - - /** - * @see com.vaadin.terminal.ApplicationResource#getStream() - */ - @Override - public DownloadStream getStream() { - final StreamSource ss = getStreamSource(); - if (ss == null) { - return null; - } - final DownloadStream ds = new DownloadStream(ss.getStream(), - getMIMEType(), getFilename()); - ds.setBufferSize(getBufferSize()); - ds.setCacheTime(cacheTime); - return ds; - } - - /** - * Interface implemented by the source of a StreamResource. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface StreamSource extends Serializable { - - /** - * Returns new input stream that is used for reading the resource. - */ - public InputStream getStream(); - } - - /* documented in superclass */ - @Override - public int getBufferSize() { - return bufferSize; - } - - /** - * Sets the size of the download buffer used for this resource. - * - * @param bufferSize - * the size of the buffer in bytes. - */ - public void setBufferSize(int bufferSize) { - this.bufferSize = bufferSize; - } - - /* documented in superclass */ - @Override - public long getCacheTime() { - return cacheTime; - } - - /** - * Sets the length of cache expiration time. - * - * <p> - * This gives the adapter the possibility cache streams sent to the client. - * The caching may be made in adapter or at the client if the client - * supports caching. Zero or negavive value disbales the caching of this - * stream. - * </p> - * - * @param cacheTime - * the cache time in milliseconds. - * - */ - public void setCacheTime(long cacheTime) { - this.cacheTime = cacheTime; - } - -} diff --git a/src/com/vaadin/terminal/StreamVariable.java b/src/com/vaadin/terminal/StreamVariable.java deleted file mode 100644 index 63763a5751..0000000000 --- a/src/com/vaadin/terminal/StreamVariable.java +++ /dev/null @@ -1,157 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal; - -import java.io.OutputStream; -import java.io.Serializable; - -import com.vaadin.Application; -import com.vaadin.terminal.StreamVariable.StreamingEndEvent; -import com.vaadin.terminal.StreamVariable.StreamingErrorEvent; -import com.vaadin.terminal.StreamVariable.StreamingStartEvent; - -/** - * StreamVariable is a special kind of variable whose value is streamed to an - * {@link OutputStream} provided by the {@link #getOutputStream()} method. E.g. - * in web terminals {@link StreamVariable} can be used to send large files from - * browsers to the server without consuming large amounts of memory. - * <p> - * Note, writing to the {@link OutputStream} is not synchronized by the terminal - * (to avoid stalls in other operations when eg. streaming to a slow network - * service or file system). If UI is changed as a side effect of writing to the - * output stream, developer must handle synchronization manually. - * <p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.5 - * @see PaintTarget#addVariable(VariableOwner, String, StreamVariable) - */ -public interface StreamVariable extends Serializable { - - /** - * Invoked by the terminal when a new upload arrives, after - * {@link #streamingStarted(StreamingStartEvent)} method has been called. - * The terminal implementation will write the streamed variable to the - * returned output stream. - * - * @return Stream to which the uploaded file should be written. - */ - public OutputStream getOutputStream(); - - /** - * Whether the {@link #onProgress(long, long)} method should be called - * during the upload. - * <p> - * {@link #onProgress(long, long)} is called in a synchronized block when - * the content is being received. This is potentially bit slow, so we are - * calling that method only if requested. The value is requested after the - * {@link #uploadStarted(StreamingStartEvent)} event, but not after reading - * each buffer. - * - * @return true if this {@link StreamVariable} wants to by notified during - * the upload of the progress of streaming. - * @see #onProgress(StreamingProgressEvent) - */ - public boolean listenProgress(); - - /** - * This method is called by the terminal if {@link #listenProgress()} - * returns true when the streaming starts. - */ - public void onProgress(StreamingProgressEvent event); - - public void streamingStarted(StreamingStartEvent event); - - public void streamingFinished(StreamingEndEvent event); - - public void streamingFailed(StreamingErrorEvent event); - - /* - * Not synchronized to avoid stalls (caused by UIDL requests) while - * streaming the content. Implementations also most commonly atomic even - * without the restriction. - */ - /** - * If this method returns true while the content is being streamed the - * Terminal to stop receiving current upload. - * <p> - * Note, the usage of this method is not synchronized over the Application - * instance by the terminal like other methods. The implementation should - * only return a boolean field and especially not modify UI or implement a - * synchronization by itself. - * - * @return true if the streaming should be interrupted as soon as possible. - */ - public boolean isInterrupted(); - - public interface StreamingEvent extends Serializable { - - /** - * @return the file name of the streamed file if known - */ - public String getFileName(); - - /** - * @return the mime type of the streamed file if known - */ - public String getMimeType(); - - /** - * @return the length of the stream (in bytes) if known, else -1 - */ - public long getContentLength(); - - /** - * @return then number of bytes streamed to StreamVariable - */ - public long getBytesReceived(); - } - - /** - * Event passed to {@link #uploadStarted(StreamingStartEvent)} method before - * the streaming of the content to {@link StreamVariable} starts. - */ - public interface StreamingStartEvent extends StreamingEvent { - /** - * The owner of the StreamVariable can call this method to inform the - * terminal implementation that this StreamVariable will not be used to - * accept more post. - */ - public void disposeStreamVariable(); - } - - /** - * Event passed to {@link #onProgress(StreamingProgressEvent)} method during - * the streaming progresses. - */ - public interface StreamingProgressEvent extends StreamingEvent { - } - - /** - * Event passed to {@link #uploadFinished(StreamingEndEvent)} method the - * contents have been streamed to StreamVariable successfully. - */ - public interface StreamingEndEvent extends StreamingEvent { - } - - /** - * Event passed to {@link #uploadFailed(StreamingErrorEvent)} method when - * the streaming ended before the end of the input. The streaming may fail - * due an interruption by {@link } or due an other unknown exception in - * communication. In the latter case the exception is also passed to - * {@link Application#terminalError(com.vaadin.terminal.Terminal.ErrorEvent)} - * . - */ - public interface StreamingErrorEvent extends StreamingEvent { - - /** - * @return the exception that caused the receiving not to finish cleanly - */ - public Exception getException(); - - } - -} diff --git a/src/com/vaadin/terminal/SystemError.java b/src/com/vaadin/terminal/SystemError.java deleted file mode 100644 index bae135ee6b..0000000000 --- a/src/com/vaadin/terminal/SystemError.java +++ /dev/null @@ -1,82 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import com.vaadin.terminal.gwt.server.AbstractApplicationServlet; - -/** - * <code>SystemError</code> is an error message for a problem caused by error in - * system, not the user application code. The system error can contain technical - * information such as stack trace and exception. - * - * SystemError does not support HTML in error messages or stack traces. If HTML - * messages are required, use {@link UserError} or a custom implementation of - * {@link ErrorMessage}. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class SystemError extends AbstractErrorMessage { - - /** - * Constructor for SystemError with error message specified. - * - * @param message - * the Textual error description. - */ - public SystemError(String message) { - super(message); - setErrorLevel(ErrorLevel.SYSTEMERROR); - setMode(ContentMode.XHTML); - setMessage(getHtmlMessage()); - } - - /** - * Constructor for SystemError with causing exception and error message. - * - * @param message - * the Textual error description. - * @param cause - * the throwable causing the system error. - */ - public SystemError(String message, Throwable cause) { - this(message); - addCause(AbstractErrorMessage.getErrorMessageForException(cause)); - } - - /** - * Constructor for SystemError with cause. - * - * @param cause - * the throwable causing the system error. - */ - public SystemError(Throwable cause) { - this(null, cause); - } - - /** - * Returns the message of the error in HTML. - * - * Note that this API may change in future versions. - */ - protected String getHtmlMessage() { - // TODO wrapping div with namespace? See the old code: - // target.addXMLSection("div", message, - // "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"); - - StringBuilder sb = new StringBuilder(); - if (getMessage() != null) { - sb.append("<h2>"); - sb.append(AbstractApplicationServlet - .safeEscapeForHtml(getMessage())); - sb.append("</h2>"); - } - return sb.toString(); - } - -} diff --git a/src/com/vaadin/terminal/Terminal.java b/src/com/vaadin/terminal/Terminal.java deleted file mode 100644 index 9dc6ced6a7..0000000000 --- a/src/com/vaadin/terminal/Terminal.java +++ /dev/null @@ -1,80 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; - -/** - * An interface that provides information about the user's terminal. - * Implementors typically provide additional information using methods not in - * this interface. </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Terminal extends Serializable { - - /** - * Gets the name of the default theme for this terminal. - * - * @return the name of the theme that is used by default by this terminal. - */ - public String getDefaultTheme(); - - /** - * Gets the width of the terminal screen in pixels. This is the width of the - * screen and not the width available for the application. - * <p> - * Note that the screen width is typically not available in the - * {@link com.vaadin.Application#init()} method as this is called before the - * browser has a chance to report the screen size to the server. - * </p> - * - * @return the width of the terminal screen. - */ - public int getScreenWidth(); - - /** - * Gets the height of the terminal screen in pixels. This is the height of - * the screen and not the height available for the application. - * - * <p> - * Note that the screen height is typically not available in the - * {@link com.vaadin.Application#init()} method as this is called before the - * browser has a chance to report the screen size to the server. - * </p> - * - * @return the height of the terminal screen. - */ - public int getScreenHeight(); - - /** - * An error event implementation for Terminal. - */ - public interface ErrorEvent extends Serializable { - - /** - * Gets the contained throwable, the cause of the error. - */ - public Throwable getThrowable(); - - } - - /** - * Interface for listening to Terminal errors. - */ - public interface ErrorListener extends Serializable { - - /** - * Invoked when a terminal error occurs. - * - * @param event - * the fired event. - */ - public void terminalError(Terminal.ErrorEvent event); - } -} diff --git a/src/com/vaadin/terminal/ThemeResource.java b/src/com/vaadin/terminal/ThemeResource.java deleted file mode 100644 index 41674b2373..0000000000 --- a/src/com/vaadin/terminal/ThemeResource.java +++ /dev/null @@ -1,96 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import com.vaadin.service.FileTypeResolver; - -/** - * <code>ThemeResource</code> is a named theme dependant resource provided and - * managed by a theme. The actual resource contents are dynamically resolved to - * comply with the used theme by the terminal adapter. This is commonly used to - * provide static images, flash, java-applets, etc for the terminals. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class ThemeResource implements Resource { - - /** - * Id of the terminal managed resource. - */ - private String resourceID = null; - - /** - * Creates a resource. - * - * @param resourceId - * the Id of the resource. - */ - public ThemeResource(String resourceId) { - if (resourceId == null) { - throw new NullPointerException("Resource ID must not be null"); - } - if (resourceId.length() == 0) { - throw new IllegalArgumentException("Resource ID can not be empty"); - } - if (resourceId.charAt(0) == '/') { - throw new IllegalArgumentException( - "Resource ID must be relative (can not begin with /)"); - } - - resourceID = resourceId; - } - - /** - * Tests if the given object equals this Resource. - * - * @param obj - * the object to be tested for equality. - * @return <code>true</code> if the given object equals this Icon, - * <code>false</code> if not. - * @see java.lang.Object#equals(Object) - */ - @Override - public boolean equals(Object obj) { - return obj instanceof ThemeResource - && resourceID.equals(((ThemeResource) obj).resourceID); - } - - /** - * @see java.lang.Object#hashCode() - */ - @Override - public int hashCode() { - return resourceID.hashCode(); - } - - /** - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return resourceID.toString(); - } - - /** - * Gets the resource id. - * - * @return the resource id. - */ - public String getResourceId() { - return resourceID; - } - - /** - * @see com.vaadin.terminal.Resource#getMIMEType() - */ - @Override - public String getMIMEType() { - return FileTypeResolver.getMIMEType(getResourceId()); - } -} diff --git a/src/com/vaadin/terminal/UserError.java b/src/com/vaadin/terminal/UserError.java deleted file mode 100644 index a7a4fd89e2..0000000000 --- a/src/com/vaadin/terminal/UserError.java +++ /dev/null @@ -1,70 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -/** - * <code>UserError</code> is a controlled error occurred in application. User - * errors are occur in normal usage of the application and guide the user. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class UserError extends AbstractErrorMessage { - - /** - * @deprecated from 7.0, use {@link ContentMode#TEXT} instead   - */ - @Deprecated - public static final ContentMode CONTENT_TEXT = ContentMode.TEXT; - - /** - * @deprecated from 7.0, use {@link ContentMode#PREFORMATTED} instead   - */ - @Deprecated - public static final ContentMode CONTENT_PREFORMATTED = ContentMode.PREFORMATTED; - - /** - * @deprecated from 7.0, use {@link ContentMode#XHTML} instead   - */ - @Deprecated - public static final ContentMode CONTENT_XHTML = ContentMode.XHTML; - - /** - * Creates a textual error message of level ERROR. - * - * @param textErrorMessage - * the text of the error message. - */ - public UserError(String textErrorMessage) { - super(textErrorMessage); - } - - /** - * Creates an error message with level and content mode. - * - * @param message - * the error message. - * @param contentMode - * the content Mode. - * @param errorLevel - * the level of error. - */ - public UserError(String message, ContentMode contentMode, - ErrorLevel errorLevel) { - super(message); - if (contentMode == null) { - contentMode = ContentMode.TEXT; - } - if (errorLevel == null) { - errorLevel = ErrorLevel.ERROR; - } - setMode(contentMode); - setErrorLevel(errorLevel); - } - -} diff --git a/src/com/vaadin/terminal/Vaadin6Component.java b/src/com/vaadin/terminal/Vaadin6Component.java deleted file mode 100644 index 59cbf956ca..0000000000 --- a/src/com/vaadin/terminal/Vaadin6Component.java +++ /dev/null @@ -1,44 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal; - -import java.util.EventListener; - -import com.vaadin.ui.Component; - -/** - * Interface provided to ease porting of Vaadin 6 components to Vaadin 7. By - * implementing this interface your Component will be able to use - * {@link #paintContent(PaintTarget)} and - * {@link #changeVariables(Object, java.util.Map)} just like in Vaadin 6. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - * - */ -public interface Vaadin6Component extends VariableOwner, Component, - EventListener { - - /** - * <p> - * Paints the Paintable into a UIDL stream. This method creates the UIDL - * sequence describing it and outputs it to the given UIDL stream. - * </p> - * - * <p> - * It is called when the contents of the component should be painted in - * response to the component first being shown or having been altered so - * that its visual representation is changed. - * </p> - * - * @param target - * the target UIDL stream where the component should paint itself - * to. - * @throws PaintException - * if the paint operation failed. - */ - public void paintContent(PaintTarget target) throws PaintException; - -} diff --git a/src/com/vaadin/terminal/VariableOwner.java b/src/com/vaadin/terminal/VariableOwner.java deleted file mode 100644 index c52e04c008..0000000000 --- a/src/com/vaadin/terminal/VariableOwner.java +++ /dev/null @@ -1,85 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.Serializable; -import java.util.Map; - -/** - * <p> - * Listener interface for UI variable changes. The user communicates with the - * application using the so-called <i>variables</i>. When the user makes a - * change using the UI the terminal trasmits the changed variables to the - * application, and the components owning those variables may then process those - * changes. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - * @deprecated in 7.0. Only provided to ease porting of Vaadin 6 components. Do - * not implement this directly, implement {@link Vaadin6Component}. - */ -@Deprecated -public interface VariableOwner extends Serializable { - - /** - * Called when one or more variables handled by the implementing class are - * changed. - * - * @param source - * the Source of the variable change. This is the origin of the - * event. For example in Web Adapter this is the request. - * @param variables - * the Mapping from variable names to new variable values. - */ - public void changeVariables(Object source, Map<String, Object> variables); - - /** - * <p> - * Tests if the variable owner is enabled or not. The terminal should not - * send any variable changes to disabled variable owners. - * </p> - * - * @return <code>true</code> if the variable owner is enabled, - * <code>false</code> if not - */ - public boolean isEnabled(); - - /** - * <p> - * Tests if the variable owner is in immediate mode or not. Being in - * immediate mode means that all variable changes are required to be sent - * back from the terminal immediately when they occur. - * </p> - * - * <p> - * <strong>Note:</strong> <code>VariableOwner</code> does not include a set- - * method for the immediateness property. This is because not all - * VariableOwners wish to offer the functionality. Such VariableOwners are - * never in the immediate mode, thus they always return <code>false</code> - * in {@link #isImmediate()}. - * </p> - * - * @return <code>true</code> if the component is in immediate mode, - * <code>false</code> if not. - */ - public boolean isImmediate(); - - /** - * VariableOwner error event. - */ - public interface ErrorEvent extends Terminal.ErrorEvent { - - /** - * Gets the source VariableOwner. - * - * @return the variable owner. - */ - public VariableOwner getVariableOwner(); - - } -} diff --git a/src/com/vaadin/terminal/WrappedRequest.java b/src/com/vaadin/terminal/WrappedRequest.java deleted file mode 100644 index a27213d921..0000000000 --- a/src/com/vaadin/terminal/WrappedRequest.java +++ /dev/null @@ -1,277 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Serializable; -import java.util.Locale; -import java.util.Map; - -import javax.portlet.PortletRequest; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; - -import com.vaadin.Application; -import com.vaadin.RootRequiresMoreInformationException; -import com.vaadin.annotations.EagerInit; -import com.vaadin.terminal.gwt.server.WebBrowser; -import com.vaadin.ui.Root; - -/** - * A generic request to the server, wrapping a more specific request type, e.g. - * HttpServletReqest or PortletRequest. - * - * @since 7.0 - */ -public interface WrappedRequest extends Serializable { - - /** - * Detailed information extracted from the browser. - * - * @see WrappedRequest#getBrowserDetails() - */ - public interface BrowserDetails extends Serializable { - /** - * Gets the URI hash fragment for the request. This is typically used to - * encode navigation within an application. - * - * @return the URI hash fragment - */ - public String getUriFragment(); - - /** - * Gets the value of window.name from the browser. This can be used to - * keep track of the specific window between browser reloads. - * - * @return the string value of window.name in the browser - */ - public String getWindowName(); - - /** - * Gets a reference to the {@link WebBrowser} object containing - * additional information, e.g. screen size and the time zone offset. - * - * @return the web browser object - */ - public WebBrowser getWebBrowser(); - } - - /** - * Gets the named request parameter This is typically a HTTP GET or POST - * parameter, though other request types might have other ways of - * representing parameters. - * - * @see javax.servlet.ServletRequest#getParameter(String) - * @see javax.portlet.PortletRequest#getParameter(String) - * - * @param parameter - * the name of the parameter - * @return The paramter value, or <code>null</code> if no parameter with the - * given name is present - */ - public String getParameter(String parameter); - - /** - * Gets all the parameters of the request. - * - * @see #getParameter(String) - * - * @see javax.servlet.ServletRequest#getParameterMap() - * @see javax.portlet.PortletRequest#getParameter(String) - * - * @return A mapping of parameter names to arrays of parameter values - */ - public Map<String, String[]> getParameterMap(); - - /** - * Returns the length of the request content that can be read from the input - * stream returned by {@link #getInputStream()}. - * - * @see javax.servlet.ServletRequest#getContentLength() - * @see javax.portlet.ClientDataRequest#getContentLength() - * - * @return content length in bytes - */ - public int getContentLength(); - - /** - * Returns an input stream from which the request content can be read. The - * request content length can be obtained with {@link #getContentLength()} - * without reading the full stream contents. - * - * @see javax.servlet.ServletRequest#getInputStream() - * @see javax.portlet.ClientDataRequest#getPortletInputStream() - * - * @return the input stream from which the contents of the request can be - * read - * @throws IOException - * if the input stream can not be opened - */ - public InputStream getInputStream() throws IOException; - - /** - * Gets a request attribute. - * - * @param name - * the name of the attribute - * @return the value of the attribute, or <code>null</code> if there is no - * attribute with the given name - * - * @see javax.servlet.ServletRequest#getAttribute(String) - * @see javax.portlet.PortletRequest#getAttribute(String) - */ - public Object getAttribute(String name); - - /** - * Defines a request attribute. - * - * @param name - * the name of the attribute - * @param value - * the attribute value - * - * @see javax.servlet.ServletRequest#setAttribute(String, Object) - * @see javax.portlet.PortletRequest#setAttribute(String, Object) - */ - public void setAttribute(String name, Object value); - - /** - * Gets the path of the requested resource relative to the application. The - * path be <code>null</code> if no path information is available. Does - * always start with / if the path isn't <code>null</code>. - * - * @return a string with the path relative to the application. - * - * @see javax.servlet.http.HttpServletRequest#getPathInfo() - */ - public String getRequestPathInfo(); - - /** - * Returns the maximum time interval, in seconds, that the session - * associated with this request will be kept open between client accesses. - * - * @return an integer specifying the number of seconds the session - * associated with this request remains open between client requests - * - * @see javax.servlet.http.HttpSession#getMaxInactiveInterval() - * @see javax.portlet.PortletSession#getMaxInactiveInterval() - */ - public int getSessionMaxInactiveInterval(); - - /** - * Gets an attribute from the session associated with this request. - * - * @param name - * the name of the attribute - * @return the attribute value, or <code>null</code> if the attribute is not - * defined in the session - * - * @see javax.servlet.http.HttpSession#getAttribute(String) - * @see javax.portlet.PortletSession#getAttribute(String) - */ - public Object getSessionAttribute(String name); - - /** - * Saves an attribute value in the session associated with this request. - * - * @param name - * the name of the attribute - * @param attribute - * the attribute value - * - * @see javax.servlet.http.HttpSession#setAttribute(String, Object) - * @see javax.portlet.PortletSession#setAttribute(String, Object) - */ - public void setSessionAttribute(String name, Object attribute); - - /** - * Returns the MIME type of the body of the request, or null if the type is - * not known. - * - * @return a string containing the name of the MIME type of the request, or - * null if the type is not known - * - * @see javax.servlet.ServletRequest#getContentType() - * @see javax.portlet.ResourceRequest#getContentType() - * - */ - public String getContentType(); - - /** - * Gets detailed information about the browser from which the request - * originated. This consists of information that is not available from - * normal HTTP requests, but requires additional information to be extracted - * for instance using javascript in the browser. - * - * This information is only guaranteed to be available in some special - * cases, for instance when {@link Application#getRoot} is called again - * after throwing {@link RootRequiresMoreInformationException} or in - * {@link Root#init(WrappedRequest)} for a Root class not annotated with - * {@link EagerInit} - * - * @return the browser details, or <code>null</code> if details are not - * available - * - * @see BrowserDetails - */ - public BrowserDetails getBrowserDetails(); - - /** - * Gets locale information from the query, e.g. using the Accept-Language - * header. - * - * @return the preferred Locale - * - * @see ServletRequest#getLocale() - * @see PortletRequest#getLocale() - */ - public Locale getLocale(); - - /** - * Returns the IP address from which the request came. This might also be - * the address of a proxy between the server and the original requester. - * - * @return a string containing the IP address, or <code>null</code> if the - * address is not available - * - * @see ServletRequest#getRemoteAddr() - */ - public String getRemoteAddr(); - - /** - * Checks whether the request was made using a secure channel, e.g. using - * https. - * - * @return a boolean indicating if the request is secure - * - * @see ServletRequest#isSecure() - * @see PortletRequest#isSecure() - */ - public boolean isSecure(); - - /** - * Gets the value of a request header, e.g. a http header for a - * {@link HttpServletRequest}. - * - * @param headerName - * the name of the header - * @return the header value, or <code>null</code> if the header is not - * present in the request - * - * @see HttpServletRequest#getHeader(String) - */ - public String getHeader(String headerName); - - /** - * Gets the deployment configuration for the context of this request. - * - * @return the deployment configuration - * - * @see DeploymentConfiguration - */ - public DeploymentConfiguration getDeploymentConfiguration(); - -} diff --git a/src/com/vaadin/terminal/WrappedResponse.java b/src/com/vaadin/terminal/WrappedResponse.java deleted file mode 100644 index 995133a269..0000000000 --- a/src/com/vaadin/terminal/WrappedResponse.java +++ /dev/null @@ -1,147 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Serializable; - -import javax.portlet.MimeResponse; -import javax.portlet.PortletResponse; -import javax.portlet.ResourceResponse; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; - -/** - * A generic response from the server, wrapping a more specific response type, - * e.g. HttpServletResponse or PortletResponse. - * - * @since 7.0 - */ -public interface WrappedResponse extends Serializable { - - /** - * Sets the (http) status code for the response. If you want to include an - * error message along the status code, use {@link #sendError(int, String)} - * instead. - * - * @param statusCode - * the status code to set - * @see HttpServletResponse#setStatus(int) - * - * @see ResourceResponse#HTTP_STATUS_CODE - */ - public void setStatus(int statusCode); - - /** - * Sets the content type of this response. If the content type including a - * charset is set before {@link #getWriter()} is invoked, the returned - * PrintWriter will automatically use the defined charset. - * - * @param contentType - * a string specifying the MIME type of the content - * - * @see ServletResponse#setContentType(String) - * @see MimeResponse#setContentType(String) - */ - public void setContentType(String contentType); - - /** - * Sets the value of a generic response header. If the header had already - * been set, the new value overwrites the previous one. - * - * @param name - * the name of the header - * @param value - * the header value. - * - * @see HttpServletResponse#setHeader(String, String) - * @see PortletResponse#setProperty(String, String) - */ - public void setHeader(String name, String value); - - /** - * Properly formats a timestamp as a date header. If the header had already - * been set, the new value overwrites the previous one. - * - * @param name - * the name of the header - * @param timestamp - * the number of milliseconds since epoch - * - * @see HttpServletResponse#setDateHeader(String, long) - */ - public void setDateHeader(String name, long timestamp); - - /** - * Returns a <code>OutputStream</code> for writing binary data in the - * response. - * <p> - * Either this method or getWriter() may be called to write the response, - * not both. - * - * @return a <code>OutputStream</code> for writing binary data - * @throws IOException - * if an input or output exception occurred - * - * @see #getWriter() - * @see ServletResponse#getOutputStream() - * @see MimeResponse#getPortletOutputStream() - */ - public OutputStream getOutputStream() throws IOException; - - /** - * Returns a <code>PrintWriter</code> object that can send character text to - * the client. The PrintWriter uses the character encoding defined using - * setContentType. - * <p> - * Either this method or getOutputStream() may be called to write the - * response, not both. - * - * @return a <code>PrintWriter</code> for writing character text - * @throws IOException - * if an input or output exception occurred - * - * @see #getOutputStream() - * @see ServletResponse#getWriter() - * @see MimeResponse#getWriter() - */ - public PrintWriter getWriter() throws IOException; - - /** - * Sets cache time in milliseconds, -1 means no cache at all. All required - * headers related to caching in the response are set based on the time. - * - * @param milliseconds - * Cache time in milliseconds - */ - public void setCacheTime(long milliseconds); - - /** - * Sends an error response to the client using the specified status code and - * clears the buffer. In some configurations, this can cause a predefined - * error page to be displayed. - * - * @param errorCode - * the HTTP status code - * @param message - * a message to accompany the error - * @throws IOException - * if an input or output exception occurs - * - * @see HttpServletResponse#sendError(int, String) - */ - public void sendError(int errorCode, String message) throws IOException; - - /** - * Gets the deployment configuration for the context of this response. - * - * @return the deployment configuration - * - * @see DeploymentConfiguration - */ - public DeploymentConfiguration getDeploymentConfiguration(); -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java deleted file mode 100644 index 40958e2868..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java +++ /dev/null @@ -1,1079 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.security.GeneralSecurityException; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.logging.Logger; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.EventRequest; -import javax.portlet.EventResponse; -import javax.portlet.GenericPortlet; -import javax.portlet.PortletConfig; -import javax.portlet.PortletContext; -import javax.portlet.PortletException; -import javax.portlet.PortletRequest; -import javax.portlet.PortletResponse; -import javax.portlet.PortletSession; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceRequest; -import javax.portlet.ResourceResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; - -import com.liferay.portal.kernel.util.PortalClassInvoker; -import com.liferay.portal.kernel.util.PropsUtil; -import com.vaadin.Application; -import com.vaadin.Application.ApplicationStartEvent; -import com.vaadin.Application.SystemMessages; -import com.vaadin.RootRequiresMoreInformationException; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback; -import com.vaadin.ui.Root; - -/** - * Portlet 2.0 base class. This replaces the servlet in servlet/portlet 1.0 - * deployments and handles various portlet requests from the browser. - * - * TODO Document me! - * - * @author peholmst - */ -public abstract class AbstractApplicationPortlet extends GenericPortlet - implements Constants { - - public static final String RESOURCE_URL_ID = "APP"; - - public static class WrappedHttpAndPortletRequest extends - WrappedPortletRequest { - - public WrappedHttpAndPortletRequest(PortletRequest request, - HttpServletRequest originalRequest, - DeploymentConfiguration deploymentConfiguration) { - super(request, deploymentConfiguration); - this.originalRequest = originalRequest; - } - - private final HttpServletRequest originalRequest; - - @Override - public String getParameter(String name) { - String parameter = super.getParameter(name); - if (parameter == null) { - parameter = originalRequest.getParameter(name); - } - return parameter; - } - - @Override - public String getRemoteAddr() { - return originalRequest.getRemoteAddr(); - } - - @Override - public String getHeader(String name) { - String header = super.getHeader(name); - if (header == null) { - header = originalRequest.getHeader(name); - } - return header; - } - - @Override - public Map<String, String[]> getParameterMap() { - Map<String, String[]> parameterMap = super.getParameterMap(); - if (parameterMap == null) { - parameterMap = originalRequest.getParameterMap(); - } - return parameterMap; - } - } - - public static class WrappedGateinRequest extends - WrappedHttpAndPortletRequest { - public WrappedGateinRequest(PortletRequest request, - DeploymentConfiguration deploymentConfiguration) { - super(request, getOriginalRequest(request), deploymentConfiguration); - } - - private static final HttpServletRequest getOriginalRequest( - PortletRequest request) { - try { - Method getRealReq = request.getClass().getMethod( - "getRealRequest"); - HttpServletRequestWrapper origRequest = (HttpServletRequestWrapper) getRealReq - .invoke(request); - return origRequest; - } catch (Exception e) { - throw new IllegalStateException("GateIn request not detected", - e); - } - } - } - - public static class WrappedLiferayRequest extends - WrappedHttpAndPortletRequest { - - public WrappedLiferayRequest(PortletRequest request, - DeploymentConfiguration deploymentConfiguration) { - super(request, getOriginalRequest(request), deploymentConfiguration); - } - - @Override - public String getPortalProperty(String name) { - return PropsUtil.get(name); - } - - private static HttpServletRequest getOriginalRequest( - PortletRequest request) { - try { - // httpRequest = PortalUtil.getHttpServletRequest(request); - HttpServletRequest httpRequest = (HttpServletRequest) PortalClassInvoker - .invoke("com.liferay.portal.util.PortalUtil", - "getHttpServletRequest", request); - - // httpRequest = - // PortalUtil.getOriginalServletRequest(httpRequest); - httpRequest = (HttpServletRequest) PortalClassInvoker.invoke( - "com.liferay.portal.util.PortalUtil", - "getOriginalServletRequest", httpRequest); - return httpRequest; - } catch (Exception e) { - throw new IllegalStateException("Liferay request not detected", - e); - } - } - - } - - public static class AbstractApplicationPortletWrapper implements Callback { - - private final AbstractApplicationPortlet portlet; - - public AbstractApplicationPortletWrapper( - AbstractApplicationPortlet portlet) { - this.portlet = portlet; - } - - @Override - public void criticalNotification(WrappedRequest request, - WrappedResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException { - portlet.criticalNotification(WrappedPortletRequest.cast(request), - (WrappedPortletResponse) response, cap, msg, details, - outOfSyncURL); - } - } - - /** - * This portlet parameter is used to add styles to the main element. E.g - * "height:500px" generates a style="height:500px" to the main element. - */ - public static final String PORTLET_PARAMETER_STYLE = "style"; - - /** - * This portal parameter is used to define the name of the Vaadin theme that - * is used for all Vaadin applications in the portal. - */ - public static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; - - public static final String WRITE_AJAX_PAGE_SCRIPT_WIDGETSET_SHOULD_WRITE = "writeAjaxPageScriptWidgetsetShouldWrite"; - - // TODO some parts could be shared with AbstractApplicationServlet - - // TODO Can we close the application when the portlet is removed? Do we know - // when the portlet is removed? - - private boolean productionMode = false; - - private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration( - getClass()) { - @Override - public String getConfiguredWidgetset(WrappedRequest request) { - - String widgetset = getApplicationOrSystemProperty( - PARAMETER_WIDGETSET, null); - - if (widgetset == null) { - // If no widgetset defined for the application, check the - // portal - // property - widgetset = WrappedPortletRequest.cast(request) - .getPortalProperty(PORTAL_PARAMETER_VAADIN_WIDGETSET); - } - - if (widgetset == null) { - // If no widgetset defined for the portal, use the default - widgetset = DEFAULT_WIDGETSET; - } - - return widgetset; - } - - @Override - public String getConfiguredTheme(WrappedRequest request) { - - // is the default theme defined by the portal? - String themeName = WrappedPortletRequest.cast(request) - .getPortalProperty(Constants.PORTAL_PARAMETER_VAADIN_THEME); - - if (themeName == null) { - // no, using the default theme defined by Vaadin - themeName = DEFAULT_THEME_NAME; - } - - return themeName; - } - - @Override - public boolean isStandalone(WrappedRequest request) { - return false; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.DeploymentConfiguration#getStaticFileLocation - * (com.vaadin.terminal.WrappedRequest) - * - * Return the URL from where static files, e.g. the widgetset and the - * theme, are served. In a standard configuration the VAADIN folder - * inside the returned folder is what is used for widgetsets and themes. - * - * @return The location of static resources (inside which there should - * be a VAADIN directory). Does not end with a slash (/). - */ - - @Override - public String getStaticFileLocation(WrappedRequest request) { - String staticFileLocation = WrappedPortletRequest.cast(request) - .getPortalProperty( - Constants.PORTAL_PARAMETER_VAADIN_RESOURCE_PATH); - if (staticFileLocation != null) { - // remove trailing slash if any - while (staticFileLocation.endsWith(".")) { - staticFileLocation = staticFileLocation.substring(0, - staticFileLocation.length() - 1); - } - return staticFileLocation; - } else { - // default for Liferay - return "/html"; - } - } - - @Override - public String getMimeType(String resourceName) { - return getPortletContext().getMimeType(resourceName); - } - }; - - private final AddonContext addonContext = new AddonContext( - getDeploymentConfiguration()); - - @Override - public void init(PortletConfig config) throws PortletException { - super.init(config); - Properties applicationProperties = getDeploymentConfiguration() - .getInitParameters(); - - // Read default parameters from the context - final PortletContext context = config.getPortletContext(); - for (final Enumeration<String> e = context.getInitParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - context.getInitParameter(name)); - } - - // Override with application settings from portlet.xml - for (final Enumeration<String> e = config.getInitParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - config.getInitParameter(name)); - } - - checkProductionMode(); - checkCrossSiteProtection(); - - addonContext.init(); - } - - @Override - public void destroy() { - super.destroy(); - - addonContext.destroy(); - } - - private void checkCrossSiteProtection() { - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false").equals( - "true")) { - /* - * Print an information/warning message about running with xsrf - * protection disabled - */ - getLogger().warning(WARNING_XSRF_PROTECTION_DISABLED); - } - } - - private void checkProductionMode() { - // TODO Identical code in AbstractApplicationServlet -> refactor - // Check if the application is in production mode. - // We are in production mode if productionMode=true - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) { - productionMode = true; - } - - if (!productionMode) { - /* Print an information/warning message about running in debug mode */ - // TODO Maybe we need a different message for portlets? - getLogger().warning(NOT_PRODUCTION_MODE_INFO); - } - } - - protected enum RequestType { - FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS, CONNECTOR_RESOURCE; - } - - protected RequestType getRequestType(WrappedPortletRequest wrappedRequest) { - PortletRequest request = wrappedRequest.getPortletRequest(); - if (request instanceof RenderRequest) { - return RequestType.RENDER; - } else if (request instanceof ResourceRequest) { - ResourceRequest resourceRequest = (ResourceRequest) request; - if (ServletPortletHelper.isUIDLRequest(wrappedRequest)) { - return RequestType.UIDL; - } else if (isBrowserDetailsRequest(resourceRequest)) { - return RequestType.BROWSER_DETAILS; - } else if (ServletPortletHelper.isFileUploadRequest(wrappedRequest)) { - return RequestType.FILE_UPLOAD; - } else if (ServletPortletHelper - .isConnectorResourceRequest(wrappedRequest)) { - return RequestType.CONNECTOR_RESOURCE; - } else if (ServletPortletHelper - .isApplicationResourceRequest(wrappedRequest)) { - return RequestType.APPLICATION_RESOURCE; - } else if (isDummyRequest(resourceRequest)) { - return RequestType.DUMMY; - } else { - return RequestType.STATIC_FILE; - } - } else if (request instanceof ActionRequest) { - return RequestType.ACTION; - } else if (request instanceof EventRequest) { - return RequestType.EVENT; - } - return RequestType.UNKNOWN; - } - - private boolean isBrowserDetailsRequest(ResourceRequest request) { - return request.getResourceID() != null - && request.getResourceID().equals("browserDetails"); - } - - private boolean isDummyRequest(ResourceRequest request) { - return request.getResourceID() != null - && request.getResourceID().equals("DUMMY"); - } - - /** - * Returns true if the servlet is running in production mode. Production - * mode disables all debug facilities. - * - * @return true if in production mode, false if in debug mode - */ - public boolean isProductionMode() { - return productionMode; - } - - protected void handleRequest(PortletRequest request, - PortletResponse response) throws PortletException, IOException { - RequestTimer requestTimer = new RequestTimer(); - requestTimer.start(); - - AbstractApplicationPortletWrapper portletWrapper = new AbstractApplicationPortletWrapper( - this); - - WrappedPortletRequest wrappedRequest = createWrappedRequest(request); - - WrappedPortletResponse wrappedResponse = new WrappedPortletResponse( - response, getDeploymentConfiguration()); - - RequestType requestType = getRequestType(wrappedRequest); - - if (requestType == RequestType.UNKNOWN) { - handleUnknownRequest(request, response); - } else if (requestType == RequestType.DUMMY) { - /* - * This dummy page is used by action responses to redirect to, in - * order to prevent the boot strap code from being rendered into - * strange places such as iframes. - */ - ((ResourceResponse) response).setContentType("text/html"); - final OutputStream out = ((ResourceResponse) response) - .getPortletOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print("<html><body>dummy page</body></html>"); - outWriter.close(); - } else if (requestType == RequestType.STATIC_FILE) { - serveStaticResources((ResourceRequest) request, - (ResourceResponse) response); - } else { - Application application = null; - boolean transactionStarted = false; - boolean requestStarted = false; - - try { - // TODO What about PARAM_UNLOADBURST & redirectToApplication?? - - /* Find out which application this request is related to */ - application = findApplicationInstance(wrappedRequest, - requestType); - if (application == null) { - return; - } - Application.setCurrent(application); - - /* - * Get or create an application context and an application - * manager for the session - */ - PortletApplicationContext2 applicationContext = getApplicationContext(request - .getPortletSession()); - applicationContext.setResponse(response); - applicationContext.setPortletConfig(getPortletConfig()); - - PortletCommunicationManager applicationManager = applicationContext - .getApplicationManager(application); - - if (requestType == RequestType.CONNECTOR_RESOURCE) { - applicationManager.serveConnectorResource(wrappedRequest, - wrappedResponse); - return; - } - - /* Update browser information from request */ - applicationContext.getBrowser().updateRequestDetails( - wrappedRequest); - - /* - * Call application requestStart before Application.init() is - * called (bypasses the limitation in TransactionListener) - */ - if (application instanceof PortletRequestListener) { - ((PortletRequestListener) application).onRequestStart( - request, response); - requestStarted = true; - } - - /* Start the newly created application */ - startApplication(request, application, applicationContext); - - /* - * Transaction starts. Call transaction listeners. Transaction - * end is called in the finally block below. - */ - applicationContext.startTransaction(application, request); - transactionStarted = true; - - /* Notify listeners */ - - // Finds the window within the application - Root root = null; - synchronized (application) { - if (application.isRunning()) { - switch (requestType) { - case RENDER: - case ACTION: - // Both action requests and render requests are ok - // without a Root as they render the initial HTML - // and then do a second request - try { - root = application - .getRootForRequest(wrappedRequest); - } catch (RootRequiresMoreInformationException e) { - // Ignore problem and continue without root - } - break; - case BROWSER_DETAILS: - // Should not try to find a root here as the - // combined request details might change the root - break; - case FILE_UPLOAD: - // no window - break; - case APPLICATION_RESOURCE: - // use main window - should not need any window - // root = application.getRoot(); - break; - default: - root = application - .getRootForRequest(wrappedRequest); - } - // if window not found, not a problem - use null - } - } - - // TODO Should this happen before or after the transaction - // starts? - if (request instanceof RenderRequest) { - applicationContext.firePortletRenderRequest(application, - root, (RenderRequest) request, - (RenderResponse) response); - } else if (request instanceof ActionRequest) { - applicationContext.firePortletActionRequest(application, - root, (ActionRequest) request, - (ActionResponse) response); - } else if (request instanceof EventRequest) { - applicationContext.firePortletEventRequest(application, - root, (EventRequest) request, - (EventResponse) response); - } else if (request instanceof ResourceRequest) { - applicationContext.firePortletResourceRequest(application, - root, (ResourceRequest) request, - (ResourceResponse) response); - } - - /* Handle the request */ - if (requestType == RequestType.FILE_UPLOAD) { - // Root is resolved in handleFileUpload by - // PortletCommunicationManager - applicationManager.handleFileUpload(application, - wrappedRequest, wrappedResponse); - return; - } else if (requestType == RequestType.BROWSER_DETAILS) { - applicationManager.handleBrowserDetailsRequest( - wrappedRequest, wrappedResponse, application); - return; - } else if (requestType == RequestType.UIDL) { - // Handles AJAX UIDL requests - applicationManager.handleUidlRequest(wrappedRequest, - wrappedResponse, portletWrapper, root); - return; - } else { - /* - * Removes the application if it has stopped - */ - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - - handleOtherRequest(wrappedRequest, wrappedResponse, - requestType, application, applicationContext, - applicationManager); - } - } catch (final SessionExpiredException e) { - // TODO Figure out a better way to deal with - // SessionExpiredExceptions - getLogger().finest("A user session has expired"); - } catch (final GeneralSecurityException e) { - // TODO Figure out a better way to deal with - // GeneralSecurityExceptions - getLogger() - .fine("General security exception, the security key was probably incorrect."); - } catch (final Throwable e) { - handleServiceException(wrappedRequest, wrappedResponse, - application, e); - } finally { - // Notifies transaction end - try { - if (transactionStarted) { - ((PortletApplicationContext2) application.getContext()) - .endTransaction(application, request); - } - } finally { - try { - if (requestStarted) { - ((PortletRequestListener) application) - .onRequestEnd(request, response); - - } - } finally { - Root.setCurrent(null); - Application.setCurrent(null); - - PortletSession session = request - .getPortletSession(false); - if (session != null) { - requestTimer.stop(getApplicationContext(session)); - } - } - } - } - } - } - - /** - * Wraps the request in a (possibly portal specific) wrapped portlet - * request. - * - * @param request - * The original PortletRequest - * @return A wrapped version of the PorletRequest - */ - protected WrappedPortletRequest createWrappedRequest(PortletRequest request) { - String portalInfo = request.getPortalContext().getPortalInfo() - .toLowerCase(); - if (portalInfo.contains("liferay")) { - return new WrappedLiferayRequest(request, - getDeploymentConfiguration()); - } else if (portalInfo.contains("gatein")) { - return new WrappedGateinRequest(request, - getDeploymentConfiguration()); - } else { - return new WrappedPortletRequest(request, - getDeploymentConfiguration()); - } - - } - - protected DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - private void handleUnknownRequest(PortletRequest request, - PortletResponse response) { - getLogger().warning("Unknown request type"); - } - - /** - * Handle a portlet request that is not for static files, UIDL or upload. - * Also render requests are handled here. - * - * This method is called after starting the application and calling portlet - * and transaction listeners. - * - * @param request - * @param response - * @param requestType - * @param application - * @param applicationContext - * @param applicationManager - * @throws PortletException - * @throws IOException - * @throws MalformedURLException - */ - private void handleOtherRequest(WrappedPortletRequest request, - WrappedResponse response, RequestType requestType, - Application application, - PortletApplicationContext2 applicationContext, - PortletCommunicationManager applicationManager) - throws PortletException, IOException, MalformedURLException { - if (requestType == RequestType.APPLICATION_RESOURCE - || requestType == RequestType.RENDER) { - if (!applicationManager.handleApplicationRequest(request, response)) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - "Not found"); - } - } else if (requestType == RequestType.EVENT) { - // nothing to do, listeners do all the work - } else if (requestType == RequestType.ACTION) { - // nothing to do, listeners do all the work - } else { - throw new IllegalStateException( - "handleRequest() without anything to do - should never happen!"); - } - } - - @Override - public void processEvent(EventRequest request, EventResponse response) - throws PortletException, IOException { - handleRequest(request, response); - } - - private void serveStaticResources(ResourceRequest request, - ResourceResponse response) throws IOException, PortletException { - final String resourceID = request.getResourceID(); - final PortletContext pc = getPortletContext(); - - InputStream is = pc.getResourceAsStream(resourceID); - if (is != null) { - final String mimetype = pc.getMimeType(resourceID); - if (mimetype != null) { - response.setContentType(mimetype); - } - final OutputStream os = response.getPortletOutputStream(); - final byte buffer[] = new byte[DEFAULT_BUFFER_SIZE]; - int bytes; - while ((bytes = is.read(buffer)) >= 0) { - os.write(buffer, 0, bytes); - } - } else { - getLogger().info( - "Requested resource [" + resourceID - + "] could not be found"); - response.setProperty(ResourceResponse.HTTP_STATUS_CODE, - Integer.toString(HttpServletResponse.SC_NOT_FOUND)); - } - } - - @Override - public void processAction(ActionRequest request, ActionResponse response) - throws PortletException, IOException { - handleRequest(request, response); - } - - @Override - protected void doDispatch(RenderRequest request, RenderResponse response) - throws PortletException, IOException { - try { - // try to let super handle - it'll call methods annotated for - // handling, the default doXYZ(), or throw if a handler for the mode - // is not found - super.doDispatch(request, response); - - } catch (PortletException e) { - if (e.getCause() == null) { - // No cause interpreted as 'unknown mode' - pass that trough - // so that the application can handle - handleRequest(request, response); - - } else { - // Something else failed, pass on - throw e; - } - } - } - - @Override - public void serveResource(ResourceRequest request, ResourceResponse response) - throws PortletException, IOException { - handleRequest(request, response); - } - - boolean requestCanCreateApplication(PortletRequest request, - RequestType requestType) { - if (requestType == RequestType.UIDL && isRepaintAll(request)) { - return true; - } else if (requestType == RequestType.RENDER) { - // In most cases the first request is a render request that renders - // the HTML fragment. This should create an application instance. - return true; - } else if (requestType == RequestType.EVENT) { - // A portlet can also be sent an event even though it has not been - // rendered, e.g. portlet on one page sends an event to a portlet on - // another page and then moves the user to that page. - return true; - } - return false; - } - - private boolean isRepaintAll(PortletRequest request) { - return (request.getParameter(URL_PARAMETER_REPAINT_ALL) != null) - && (request.getParameter(URL_PARAMETER_REPAINT_ALL).equals("1")); - } - - private void startApplication(PortletRequest request, - Application application, PortletApplicationContext2 context) - throws PortletException, MalformedURLException { - if (!application.isRunning()) { - Locale locale = request.getLocale(); - application.setLocale(locale); - // No application URL when running inside a portlet - application.start(new ApplicationStartEvent(null, - getDeploymentConfiguration().getInitParameters(), context, - isProductionMode())); - addonContext.applicationStarted(application); - } - } - - private void endApplication(PortletRequest request, - PortletResponse response, Application application) - throws IOException { - final PortletSession session = request.getPortletSession(); - if (session != null) { - getApplicationContext(session).removeApplication(application); - } - // Do not send any redirects when running inside a portlet. - } - - private Application findApplicationInstance( - WrappedPortletRequest wrappedRequest, RequestType requestType) - throws PortletException, SessionExpiredException, - MalformedURLException { - PortletRequest request = wrappedRequest.getPortletRequest(); - - boolean requestCanCreateApplication = requestCanCreateApplication( - request, requestType); - - /* Find an existing application for this request. */ - Application application = getExistingApplication(request, - requestCanCreateApplication); - - if (application != null) { - /* - * There is an existing application. We can use this as long as the - * user not specifically requested to close or restart it. - */ - - final boolean restartApplication = (wrappedRequest - .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); - final boolean closeApplication = (wrappedRequest - .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); - - if (restartApplication) { - closeApplication(application, request.getPortletSession(false)); - return createApplication(request); - } else if (closeApplication) { - closeApplication(application, request.getPortletSession(false)); - return null; - } else { - return application; - } - } - - // No existing application was found - - if (requestCanCreateApplication) { - return createApplication(request); - } else { - throw new SessionExpiredException(); - } - } - - private void closeApplication(Application application, - PortletSession session) { - if (application == null) { - return; - } - - application.close(); - if (session != null) { - PortletApplicationContext2 context = getApplicationContext(session); - context.removeApplication(application); - } - } - - private Application createApplication(PortletRequest request) - throws PortletException, MalformedURLException { - Application newApplication = getNewApplication(request); - final PortletApplicationContext2 context = getApplicationContext(request - .getPortletSession()); - context.addApplication(newApplication, request.getWindowID()); - return newApplication; - } - - private Application getExistingApplication(PortletRequest request, - boolean allowSessionCreation) throws MalformedURLException, - SessionExpiredException { - - final PortletSession session = request - .getPortletSession(allowSessionCreation); - - if (session == null) { - throw new SessionExpiredException(); - } - - PortletApplicationContext2 context = getApplicationContext(session); - Application application = context.getApplicationForWindowId(request - .getWindowID()); - if (application == null) { - return null; - } - if (application.isRunning()) { - return application; - } - // application found but not running - context.removeApplication(application); - - return null; - } - - protected abstract Class<? extends Application> getApplicationClass() - throws ClassNotFoundException; - - protected Application getNewApplication(PortletRequest request) - throws PortletException { - try { - final Application application = getApplicationClass().newInstance(); - application.setRootPreserved(true); - return application; - } catch (final IllegalAccessException e) { - throw new PortletException("getNewApplication failed", e); - } catch (final InstantiationException e) { - throw new PortletException("getNewApplication failed", e); - } catch (final ClassNotFoundException e) { - throw new PortletException("getNewApplication failed", e); - } - } - - /** - * Get system messages from the current application class - * - * @return - */ - protected SystemMessages getSystemMessages() { - try { - Class<? extends Application> appCls = getApplicationClass(); - Method m = appCls.getMethod("getSystemMessages", (Class[]) null); - return (Application.SystemMessages) m.invoke(null, (Object[]) null); - } catch (ClassNotFoundException e) { - // This should never happen - throw new SystemMessageException(e); - } catch (SecurityException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (NoSuchMethodException e) { - // This is completely ok and should be silently ignored - } catch (IllegalArgumentException e) { - // This should never happen - throw new SystemMessageException(e); - } catch (IllegalAccessException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (InvocationTargetException e) { - // This should never happen - throw new SystemMessageException(e); - } - return Application.getSystemMessages(); - } - - private void handleServiceException(WrappedPortletRequest request, - WrappedPortletResponse response, Application application, - Throwable e) throws IOException, PortletException { - // TODO Check that this error handler is working when running inside a - // portlet - - // if this was an UIDL request, response UIDL back to client - if (getRequestType(request) == RequestType.UIDL) { - Application.SystemMessages ci = getSystemMessages(); - criticalNotification(request, response, - ci.getInternalErrorCaption(), ci.getInternalErrorMessage(), - null, ci.getInternalErrorURL()); - if (application != null) { - application.getErrorHandler() - .terminalError(new RequestError(e)); - } else { - throw new PortletException(e); - } - } else { - // Re-throw other exceptions - throw new PortletException(e); - } - - } - - @SuppressWarnings("serial") - public class RequestError implements Terminal.ErrorEvent, Serializable { - - private final Throwable throwable; - - public RequestError(Throwable throwable) { - this.throwable = throwable; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - } - - /** - * Send notification to client's application. Used to notify client of - * critical errors and session expiration due to long inactivity. Server has - * no knowledge of what application client refers to. - * - * @param request - * the Portlet request instance. - * @param response - * the Portlet response to write to. - * @param caption - * for the notification - * @param message - * for the notification - * @param details - * a detail message to show in addition to the passed message. - * Currently shown directly but could be hidden behind a details - * drop down. - * @param url - * url to load after message, null for current page - * @throws IOException - * if the writing failed due to input/output error. - */ - void criticalNotification(WrappedPortletRequest request, - WrappedPortletResponse response, String caption, String message, - String details, String url) throws IOException { - - // clients JS app is still running, but server application either - // no longer exists or it might fail to perform reasonably. - // send a notification to client's application and link how - // to "restart" application. - - if (caption != null) { - caption = "\"" + caption + "\""; - } - if (details != null) { - if (message == null) { - message = details; - } else { - message += "<br/><br/>" + details; - } - } - if (message != null) { - message = "\"" + message + "\""; - } - if (url != null) { - url = "\"" + url + "\""; - } - - // Set the response type - response.setContentType("application/json; charset=UTF-8"); - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print("for(;;);[{\"changes\":[], \"meta\" : {" - + "\"appError\": {" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}}, \"resources\": {}, \"locales\":[]}]"); - outWriter.close(); - } - - /** - * - * Gets the application context for a PortletSession. If no context is - * currently stored in a session a new context is created and stored in the - * session. - * - * @param portletSession - * the portlet session. - * @return the application context for the session. - */ - protected PortletApplicationContext2 getApplicationContext( - PortletSession portletSession) { - return PortletApplicationContext2.getApplicationContext(portletSession); - } - - private static final Logger getLogger() { - return Logger.getLogger(AbstractApplicationPortlet.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java deleted file mode 100644 index 603bc74a21..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java +++ /dev/null @@ -1,1623 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.security.GeneralSecurityException; -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Locale; -import java.util.Properties; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import com.vaadin.Application; -import com.vaadin.Application.ApplicationStartEvent; -import com.vaadin.Application.SystemMessages; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.ThemeResource; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.server.AbstractCommunicationManager.Callback; -import com.vaadin.ui.Root; - -/** - * Abstract implementation of the ApplicationServlet which handles all - * communication between the client and the server. - * - * It is possible to extend this class to provide own functionality but in most - * cases this is unnecessary. - * - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.0 - */ - -@SuppressWarnings("serial") -public abstract class AbstractApplicationServlet extends HttpServlet implements - Constants { - - private static class AbstractApplicationServletWrapper implements Callback { - - private final AbstractApplicationServlet servlet; - - public AbstractApplicationServletWrapper( - AbstractApplicationServlet servlet) { - this.servlet = servlet; - } - - @Override - public void criticalNotification(WrappedRequest request, - WrappedResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException { - servlet.criticalNotification( - WrappedHttpServletRequest.cast(request), - ((WrappedHttpServletResponse) response), cap, msg, details, - outOfSyncURL); - } - } - - // TODO Move some (all?) of the constants to a separate interface (shared - // with portlet) - - private boolean productionMode = false; - - private final String resourcePath = null; - - private int resourceCacheTime = 3600; - - private DeploymentConfiguration deploymentConfiguration = new AbstractDeploymentConfiguration( - getClass()) { - - @Override - public String getStaticFileLocation(WrappedRequest request) { - HttpServletRequest servletRequest = WrappedHttpServletRequest - .cast(request); - return AbstractApplicationServlet.this - .getStaticFilesLocation(servletRequest); - } - - @Override - public String getConfiguredWidgetset(WrappedRequest request) { - return getApplicationOrSystemProperty( - AbstractApplicationServlet.PARAMETER_WIDGETSET, - AbstractApplicationServlet.DEFAULT_WIDGETSET); - } - - @Override - public String getConfiguredTheme(WrappedRequest request) { - // Use the default - return AbstractApplicationServlet.getDefaultTheme(); - } - - @Override - public boolean isStandalone(WrappedRequest request) { - return true; - } - - @Override - public String getMimeType(String resourceName) { - return getServletContext().getMimeType(resourceName); - } - }; - - private final AddonContext addonContext = new AddonContext( - getDeploymentConfiguration()); - - /** - * Called by the servlet container to indicate to a servlet that the servlet - * is being placed into service. - * - * @param servletConfig - * the object containing the servlet's configuration and - * initialization parameters - * @throws javax.servlet.ServletException - * if an exception has occurred that interferes with the - * servlet's normal operation. - */ - @Override - public void init(javax.servlet.ServletConfig servletConfig) - throws javax.servlet.ServletException { - super.init(servletConfig); - Properties applicationProperties = getDeploymentConfiguration() - .getInitParameters(); - - // Read default parameters from server.xml - final ServletContext context = servletConfig.getServletContext(); - for (final Enumeration<String> e = context.getInitParameterNames(); e - .hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - context.getInitParameter(name)); - } - - // Override with application config from web.xml - for (final Enumeration<String> e = servletConfig - .getInitParameterNames(); e.hasMoreElements();) { - final String name = e.nextElement(); - applicationProperties.setProperty(name, - servletConfig.getInitParameter(name)); - } - - checkProductionMode(); - checkCrossSiteProtection(); - checkResourceCacheTime(); - - addonContext.init(); - } - - @Override - public void destroy() { - super.destroy(); - - addonContext.destroy(); - } - - private void checkCrossSiteProtection() { - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION, "false").equals( - "true")) { - /* - * Print an information/warning message about running with xsrf - * protection disabled - */ - getLogger().warning(WARNING_XSRF_PROTECTION_DISABLED); - } - } - - private void checkProductionMode() { - // Check if the application is in production mode. - // We are in production mode if productionMode=true - if (getDeploymentConfiguration().getApplicationOrSystemProperty( - SERVLET_PARAMETER_PRODUCTION_MODE, "false").equals("true")) { - productionMode = true; - } - - if (!productionMode) { - /* Print an information/warning message about running in debug mode */ - getLogger().warning(NOT_PRODUCTION_MODE_INFO); - } - - } - - private void checkResourceCacheTime() { - // Check if the browser caching time has been set in web.xml - try { - String rct = getDeploymentConfiguration() - .getApplicationOrSystemProperty( - SERVLET_PARAMETER_RESOURCE_CACHE_TIME, "3600"); - resourceCacheTime = Integer.parseInt(rct); - } catch (NumberFormatException nfe) { - // Default is 1h - resourceCacheTime = 3600; - getLogger().warning(WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC); - } - } - - /** - * Returns true if the servlet is running in production mode. Production - * mode disables all debug facilities. - * - * @return true if in production mode, false if in debug mode - */ - public boolean isProductionMode() { - return productionMode; - } - - /** - * Returns the amount of milliseconds the browser should cache a file. - * Default is 1 hour (3600 ms). - * - * @return The amount of milliseconds files are cached in the browser - */ - public int getResourceCacheTime() { - return resourceCacheTime; - } - - /** - * Receives standard HTTP requests from the public service method and - * dispatches them. - * - * @param request - * the object that contains the request the client made of the - * servlet. - * @param response - * the object that contains the response the servlet returns to - * the client. - * @throws ServletException - * if an input or output error occurs while the servlet is - * handling the TRACE request. - * @throws IOException - * if the request for the TRACE cannot be handled. - */ - - @Override - protected void service(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - service(createWrappedRequest(request), createWrappedResponse(response)); - } - - private void service(WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws ServletException, - IOException { - RequestTimer requestTimer = new RequestTimer(); - requestTimer.start(); - - AbstractApplicationServletWrapper servletWrapper = new AbstractApplicationServletWrapper( - this); - - RequestType requestType = getRequestType(request); - if (!ensureCookiesEnabled(requestType, request, response)) { - return; - } - - if (requestType == RequestType.STATIC_FILE) { - serveStaticResources(request, response); - return; - } - - Application application = null; - boolean transactionStarted = false; - boolean requestStarted = false; - - try { - // If a duplicate "close application" URL is received for an - // application that is not open, redirect to the application's main - // page. - // This is needed as e.g. Spring Security remembers the last - // URL from the application, which is the logout URL, and repeats - // it. - // We can tell apart a real onunload request from a repeated one - // based on the real one having content (at least the UIDL security - // key). - if (requestType == RequestType.UIDL - && request.getParameterMap().containsKey( - ApplicationConnection.PARAM_UNLOADBURST) - && request.getContentLength() < 1 - && getExistingApplication(request, false) == null) { - redirectToApplication(request, response); - return; - } - - // Find out which application this request is related to - application = findApplicationInstance(request, requestType); - if (application == null) { - return; - } - Application.setCurrent(application); - - /* - * Get or create a WebApplicationContext and an ApplicationManager - * for the session - */ - WebApplicationContext webApplicationContext = getApplicationContext(request - .getSession()); - CommunicationManager applicationManager = webApplicationContext - .getApplicationManager(application, this); - - if (requestType == RequestType.CONNECTOR_RESOURCE) { - applicationManager.serveConnectorResource(request, response); - return; - } - - /* Update browser information from the request */ - webApplicationContext.getBrowser().updateRequestDetails(request); - - /* - * Call application requestStart before Application.init() is called - * (bypasses the limitation in TransactionListener) - */ - if (application instanceof HttpServletRequestListener) { - ((HttpServletRequestListener) application).onRequestStart( - request, response); - requestStarted = true; - } - - // Start the application if it's newly created - startApplication(request, application, webApplicationContext); - - /* - * Transaction starts. Call transaction listeners. Transaction end - * is called in the finally block below. - */ - webApplicationContext.startTransaction(application, request); - transactionStarted = true; - - /* Handle the request */ - if (requestType == RequestType.FILE_UPLOAD) { - // Root is resolved in communication manager - applicationManager.handleFileUpload(application, request, - response); - return; - } else if (requestType == RequestType.UIDL) { - Root root = application.getRootForRequest(request); - if (root == null) { - throw new ServletException(ERROR_NO_ROOT_FOUND); - } - // Handles AJAX UIDL requests - applicationManager.handleUidlRequest(request, response, - servletWrapper, root); - return; - } else if (requestType == RequestType.BROWSER_DETAILS) { - // Browser details - not related to a specific root - applicationManager.handleBrowserDetailsRequest(request, - response, application); - return; - } - - // Removes application if it has stopped (maybe by thread or - // transactionlistener) - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - - if (applicationManager.handleApplicationRequest(request, response)) { - return; - } - // TODO Should return 404 error here and not do anything more - - } catch (final SessionExpiredException e) { - // Session has expired, notify user - handleServiceSessionExpired(request, response); - } catch (final GeneralSecurityException e) { - handleServiceSecurityException(request, response); - } catch (final Throwable e) { - handleServiceException(request, response, application, e); - } finally { - // Notifies transaction end - try { - if (transactionStarted) { - ((WebApplicationContext) application.getContext()) - .endTransaction(application, request); - - } - - } finally { - try { - if (requestStarted) { - ((HttpServletRequestListener) application) - .onRequestEnd(request, response); - } - } finally { - Root.setCurrent(null); - Application.setCurrent(null); - - HttpSession session = request.getSession(false); - if (session != null) { - requestTimer.stop(getApplicationContext(session)); - } - } - } - - } - } - - private WrappedHttpServletResponse createWrappedResponse( - HttpServletResponse response) { - WrappedHttpServletResponse wrappedResponse = new WrappedHttpServletResponse( - response, getDeploymentConfiguration()); - return wrappedResponse; - } - - /** - * Create a wrapped request for a http servlet request. This method can be - * overridden if the wrapped request should have special properties. - * - * @param request - * the original http servlet request - * @return a wrapped request for the original request - */ - protected WrappedHttpServletRequest createWrappedRequest( - HttpServletRequest request) { - return new WrappedHttpServletRequest(request, - getDeploymentConfiguration()); - } - - /** - * Gets a the deployment configuration for this servlet. - * - * @return the deployment configuration - */ - protected DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - /** - * Check that cookie support is enabled in the browser. Only checks UIDL - * requests. - * - * @param requestType - * Type of the request as returned by - * {@link #getRequestType(HttpServletRequest)} - * @param request - * The request from the browser - * @param response - * The response to which an error can be written - * @return false if cookies are disabled, true otherwise - * @throws IOException - */ - private boolean ensureCookiesEnabled(RequestType requestType, - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - if (requestType == RequestType.UIDL && !isRepaintAll(request)) { - // In all other but the first UIDL request a cookie should be - // returned by the browser. - // This can be removed if cookieless mode (#3228) is supported - if (request.getRequestedSessionId() == null) { - // User has cookies disabled - criticalNotification(request, response, getSystemMessages() - .getCookiesDisabledCaption(), getSystemMessages() - .getCookiesDisabledMessage(), null, getSystemMessages() - .getCookiesDisabledURL()); - return false; - } - } - return true; - } - - /** - * Send a notification to client's application. Used to notify client of - * critical errors, session expiration and more. Server has no knowledge of - * what application client refers to. - * - * @param request - * the HTTP request instance. - * @param response - * the HTTP response to write to. - * @param caption - * the notification caption - * @param message - * to notification body - * @param details - * a detail message to show in addition to the message. Currently - * shown directly below the message but could be hidden behind a - * details drop down in the future. Mainly used to give - * additional information not necessarily useful to the end user. - * @param url - * url to load when the message is dismissed. Null will reload - * the current page. - * @throws IOException - * if the writing failed due to input/output error. - */ - protected void criticalNotification(WrappedHttpServletRequest request, - HttpServletResponse response, String caption, String message, - String details, String url) throws IOException { - - if (ServletPortletHelper.isUIDLRequest(request)) { - - if (caption != null) { - caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\""; - } - if (details != null) { - if (message == null) { - message = details; - } else { - message += "<br/><br/>" + details; - } - } - - if (message != null) { - message = "\"" + JsonPaintTarget.escapeJSON(message) + "\""; - } - if (url != null) { - url = "\"" + JsonPaintTarget.escapeJSON(url) + "\""; - } - - String output = "for(;;);[{\"changes\":[], \"meta\" : {" - + "\"appError\": {" + "\"caption\":" + caption + "," - + "\"message\" : " + message + "," + "\"url\" : " + url - + "}}, \"resources\": {}, \"locales\":[]}]"; - writeResponse(response, "application/json; charset=UTF-8", output); - } else { - // Create an HTML reponse with the error - String output = ""; - - if (url != null) { - output += "<a href=\"" + url + "\">"; - } - if (caption != null) { - output += "<b>" + caption + "</b><br/>"; - } - if (message != null) { - output += message; - output += "<br/><br/>"; - } - - if (details != null) { - output += details; - output += "<br/><br/>"; - } - if (url != null) { - output += "</a>"; - } - writeResponse(response, "text/html; charset=UTF-8", output); - - } - - } - - /** - * Writes the response in {@code output} using the contentType given in - * {@code contentType} to the provided {@link HttpServletResponse} - * - * @param response - * @param contentType - * @param output - * Output to write (UTF-8 encoded) - * @throws IOException - */ - private void writeResponse(HttpServletResponse response, - String contentType, String output) throws IOException { - response.setContentType(contentType); - final ServletOutputStream out = response.getOutputStream(); - // Set the response type - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print(output); - outWriter.flush(); - outWriter.close(); - out.flush(); - - } - - /** - * Returns the application instance to be used for the request. If an - * existing instance is not found a new one is created or null is returned - * to indicate that the application is not available. - * - * @param request - * @param requestType - * @return - * @throws MalformedURLException - * @throws IllegalAccessException - * @throws InstantiationException - * @throws ServletException - * @throws SessionExpiredException - */ - private Application findApplicationInstance(HttpServletRequest request, - RequestType requestType) throws MalformedURLException, - ServletException, SessionExpiredException { - - boolean requestCanCreateApplication = requestCanCreateApplication( - request, requestType); - - /* Find an existing application for this request. */ - Application application = getExistingApplication(request, - requestCanCreateApplication); - - if (application != null) { - /* - * There is an existing application. We can use this as long as the - * user not specifically requested to close or restart it. - */ - - final boolean restartApplication = (request - .getParameter(URL_PARAMETER_RESTART_APPLICATION) != null); - final boolean closeApplication = (request - .getParameter(URL_PARAMETER_CLOSE_APPLICATION) != null); - - if (restartApplication) { - closeApplication(application, request.getSession(false)); - return createApplication(request); - } else if (closeApplication) { - closeApplication(application, request.getSession(false)); - return null; - } else { - return application; - } - } - - // No existing application was found - - if (requestCanCreateApplication) { - /* - * If the request is such that it should create a new application if - * one as not found, we do that. - */ - return createApplication(request); - } else { - /* - * The application was not found and a new one should not be - * created. Assume the session has expired. - */ - throw new SessionExpiredException(); - } - - } - - /** - * Check if the request should create an application if an existing - * application is not found. - * - * @param request - * @param requestType - * @return true if an application should be created, false otherwise - */ - boolean requestCanCreateApplication(HttpServletRequest request, - RequestType requestType) { - if (requestType == RequestType.UIDL && isRepaintAll(request)) { - /* - * UIDL request contains valid repaintAll=1 event, the user probably - * wants to initiate a new application through a custom index.html - * without using the bootstrap page. - */ - return true; - - } else if (requestType == RequestType.OTHER) { - /* - * I.e URIs that are not application resources or static (theme) - * files. - */ - return true; - - } - - return false; - } - - /** - * Gets resource path using different implementations. Required to - * supporting different servlet container implementations (application - * servers). - * - * @param servletContext - * @param path - * the resource path. - * @return the resource path. - */ - protected static String getResourcePath(ServletContext servletContext, - String path) { - String resultPath = null; - resultPath = servletContext.getRealPath(path); - if (resultPath != null) { - return resultPath; - } else { - try { - final URL url = servletContext.getResource(path); - resultPath = url.getFile(); - } catch (final Exception e) { - // FIXME: Handle exception - getLogger().log(Level.INFO, - "Could not find resource path " + path, e); - } - } - return resultPath; - } - - /** - * Creates a new application and registers it into WebApplicationContext - * (aka session). This is not meant to be overridden. Override - * getNewApplication to create the application instance in a custom way. - * - * @param request - * @return - * @throws ServletException - * @throws MalformedURLException - */ - private Application createApplication(HttpServletRequest request) - throws ServletException, MalformedURLException { - Application newApplication = getNewApplication(request); - - final WebApplicationContext context = getApplicationContext(request - .getSession()); - context.addApplication(newApplication); - - return newApplication; - } - - private void handleServiceException(WrappedHttpServletRequest request, - WrappedHttpServletResponse response, Application application, - Throwable e) throws IOException, ServletException { - // if this was an UIDL request, response UIDL back to client - if (getRequestType(request) == RequestType.UIDL) { - Application.SystemMessages ci = getSystemMessages(); - criticalNotification(request, response, - ci.getInternalErrorCaption(), ci.getInternalErrorMessage(), - null, ci.getInternalErrorURL()); - if (application != null) { - application.getErrorHandler() - .terminalError(new RequestError(e)); - } else { - throw new ServletException(e); - } - } else { - // Re-throw other exceptions - throw new ServletException(e); - } - - } - - /** - * A helper method to strip away characters that might somehow be used for - * XSS attacs. Leaves at least alphanumeric characters intact. Also removes - * eg. ( and ), so values should be safe in javascript too. - * - * @param themeName - * @return - */ - protected static String stripSpecialChars(String themeName) { - StringBuilder sb = new StringBuilder(); - char[] charArray = themeName.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - char c = charArray[i]; - if (!CHAR_BLACKLIST.contains(c)) { - sb.append(c); - } - } - return sb.toString(); - } - - private static final Collection<Character> CHAR_BLACKLIST = new HashSet<Character>( - Arrays.asList(new Character[] { '&', '"', '\'', '<', '>', '(', ')', - ';' })); - - /** - * Returns the default theme. Must never return null. - * - * @return - */ - public static String getDefaultTheme() { - return DEFAULT_THEME_NAME; - } - - void handleServiceSessionExpired(WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException, - ServletException { - - if (isOnUnloadRequest(request)) { - /* - * Request was an unload request (e.g. window close event) and the - * client expects no response if it fails. - */ - return; - } - - try { - Application.SystemMessages ci = getSystemMessages(); - if (getRequestType(request) != RequestType.UIDL) { - // 'plain' http req - e.g. browser reload; - // just go ahead redirect the browser - response.sendRedirect(ci.getSessionExpiredURL()); - } else { - /* - * Invalidate session (weird to have session if we're saying - * that it's expired, and worse: portal integration will fail - * since the session is not created by the portal. - * - * Session must be invalidated before criticalNotification as it - * commits the response. - */ - request.getSession().invalidate(); - - // send uidl redirect - criticalNotification(request, response, - ci.getSessionExpiredCaption(), - ci.getSessionExpiredMessage(), null, - ci.getSessionExpiredURL()); - - } - } catch (SystemMessageException ee) { - throw new ServletException(ee); - } - - } - - private void handleServiceSecurityException( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException, - ServletException { - if (isOnUnloadRequest(request)) { - /* - * Request was an unload request (e.g. window close event) and the - * client expects no response if it fails. - */ - return; - } - - try { - Application.SystemMessages ci = getSystemMessages(); - if (getRequestType(request) != RequestType.UIDL) { - // 'plain' http req - e.g. browser reload; - // just go ahead redirect the browser - response.sendRedirect(ci.getCommunicationErrorURL()); - } else { - // send uidl redirect - criticalNotification(request, response, - ci.getCommunicationErrorCaption(), - ci.getCommunicationErrorMessage(), - INVALID_SECURITY_KEY_MSG, ci.getCommunicationErrorURL()); - /* - * Invalidate session. Portal integration will fail otherwise - * since the session is not created by the portal. - */ - request.getSession().invalidate(); - } - } catch (SystemMessageException ee) { - throw new ServletException(ee); - } - - log("Invalid security key received from " + request.getRemoteHost()); - } - - /** - * Creates a new application for the given request. - * - * @param request - * the HTTP request. - * @return A new Application instance. - * @throws ServletException - */ - protected abstract Application getNewApplication(HttpServletRequest request) - throws ServletException; - - /** - * Starts the application if it is not already running. - * - * @param request - * @param application - * @param webApplicationContext - * @throws ServletException - * @throws MalformedURLException - */ - private void startApplication(HttpServletRequest request, - Application application, WebApplicationContext webApplicationContext) - throws ServletException, MalformedURLException { - - if (!application.isRunning()) { - // Create application - final URL applicationUrl = getApplicationUrl(request); - - // Initial locale comes from the request - Locale locale = request.getLocale(); - application.setLocale(locale); - application.start(new ApplicationStartEvent(applicationUrl, - getDeploymentConfiguration().getInitParameters(), - webApplicationContext, isProductionMode())); - addonContext.applicationStarted(application); - } - } - - /** - * Check if this is a request for a static resource and, if it is, serve the - * resource to the client. - * - * @param request - * @param response - * @return true if a file was served and the request has been handled, false - * otherwise. - * @throws IOException - * @throws ServletException - */ - private boolean serveStaticResources(HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { - - // FIXME What does 10 refer to? - String pathInfo = request.getPathInfo(); - if (pathInfo == null || pathInfo.length() <= 10) { - return false; - } - - if ((request.getContextPath() != null) - && (request.getRequestURI().startsWith("/VAADIN/"))) { - serveStaticResourcesInVAADIN(request.getRequestURI(), request, - response); - return true; - } else if (request.getRequestURI().startsWith( - request.getContextPath() + "/VAADIN/")) { - serveStaticResourcesInVAADIN( - request.getRequestURI().substring( - request.getContextPath().length()), request, - response); - return true; - } - - return false; - } - - /** - * Serve resources from VAADIN directory. - * - * @param filename - * The filename to serve. Should always start with /VAADIN/. - * @param request - * @param response - * @throws IOException - * @throws ServletException - */ - private void serveStaticResourcesInVAADIN(String filename, - HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - - final ServletContext sc = getServletContext(); - URL resourceUrl = sc.getResource(filename); - if (resourceUrl == null) { - // try if requested file is found from classloader - - // strip leading "/" otherwise stream from JAR wont work - filename = filename.substring(1); - resourceUrl = getDeploymentConfiguration().getClassLoader() - .getResource(filename); - - if (resourceUrl == null) { - // cannot serve requested file - getLogger() - .info("Requested resource [" - + filename - + "] not found from filesystem or through class loader." - + " Add widgetset and/or theme JAR to your classpath or add files to WebContent/VAADIN folder."); - response.setStatus(HttpServletResponse.SC_NOT_FOUND); - return; - } - - // security check: do not permit navigation out of the VAADIN - // directory - if (!isAllowedVAADINResourceUrl(request, resourceUrl)) { - getLogger() - .info("Requested resource [" - + filename - + "] not accessible in the VAADIN directory or access to it is forbidden."); - response.setStatus(HttpServletResponse.SC_FORBIDDEN); - return; - } - } - - // Find the modification timestamp - long lastModifiedTime = 0; - URLConnection connection = null; - try { - connection = resourceUrl.openConnection(); - lastModifiedTime = connection.getLastModified(); - // Remove milliseconds to avoid comparison problems (milliseconds - // are not returned by the browser in the "If-Modified-Since" - // header). - lastModifiedTime = lastModifiedTime - lastModifiedTime % 1000; - - if (browserHasNewestVersion(request, lastModifiedTime)) { - response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - return; - } - } catch (Exception e) { - // Failed to find out last modified timestamp. Continue without it. - getLogger() - .log(Level.FINEST, - "Failed to find out last modified timestamp. Continuing without it.", - e); - } finally { - if (connection instanceof URLConnection) { - try { - // Explicitly close the input stream to prevent it - // from remaining hanging - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4257700 - InputStream is = connection.getInputStream(); - if (is != null) { - is.close(); - } - } catch (IOException e) { - getLogger().log(Level.INFO, - "Error closing URLConnection input stream", e); - } - } - } - - // Set type mime type if we can determine it based on the filename - final String mimetype = sc.getMimeType(filename); - if (mimetype != null) { - response.setContentType(mimetype); - } - - // Provide modification timestamp to the browser if it is known. - if (lastModifiedTime > 0) { - response.setDateHeader("Last-Modified", lastModifiedTime); - /* - * The browser is allowed to cache for 1 hour without checking if - * the file has changed. This forces browsers to fetch a new version - * when the Vaadin version is updated. This will cause more requests - * to the servlet than without this but for high volume sites the - * static files should never be served through the servlet. The - * cache timeout can be configured by setting the resourceCacheTime - * parameter in web.xml - */ - response.setHeader("Cache-Control", - "max-age= " + String.valueOf(resourceCacheTime)); - } - - // Write the resource to the client. - final OutputStream os = response.getOutputStream(); - final byte buffer[] = new byte[DEFAULT_BUFFER_SIZE]; - int bytes; - InputStream is = resourceUrl.openStream(); - while ((bytes = is.read(buffer)) >= 0) { - os.write(buffer, 0, bytes); - } - is.close(); - } - - /** - * Check whether a URL obtained from a classloader refers to a valid static - * resource in the directory VAADIN. - * - * Warning: Overriding of this method is not recommended, but is possible to - * support non-default classloaders or servers that may produce URLs - * different from the normal ones. The method prototype may change in the - * future. Care should be taken not to expose class files or other resources - * outside the VAADIN directory if the method is overridden. - * - * @param request - * @param resourceUrl - * @return - * - * @since 6.6.7 - */ - protected boolean isAllowedVAADINResourceUrl(HttpServletRequest request, - URL resourceUrl) { - if ("jar".equals(resourceUrl.getProtocol())) { - // This branch is used for accessing resources directly from the - // Vaadin JAR in development environments and in similar cases. - - // Inside a JAR, a ".." would mean a real directory named ".." so - // using it in paths should just result in the file not being found. - // However, performing a check in case some servers or class loaders - // try to normalize the path by collapsing ".." before the class - // loader sees it. - - if (!resourceUrl.getPath().contains("!/VAADIN/")) { - getLogger().info( - "Blocked attempt to access a JAR entry not starting with /VAADIN/: " - + resourceUrl); - return false; - } - getLogger().fine( - "Accepted access to a JAR entry using a class loader: " - + resourceUrl); - return true; - } else { - // Some servers such as GlassFish extract files from JARs (file:) - // and e.g. JBoss 5+ use protocols vsf: and vfsfile: . - - // Check that the URL is in a VAADIN directory and does not contain - // "/../" - if (!resourceUrl.getPath().contains("/VAADIN/") - || resourceUrl.getPath().contains("/../")) { - getLogger().info( - "Blocked attempt to access file: " + resourceUrl); - return false; - } - getLogger().fine( - "Accepted access to a file using a class loader: " - + resourceUrl); - return true; - } - } - - /** - * Checks if the browser has an up to date cached version of requested - * resource. Currently the check is performed using the "If-Modified-Since" - * header. Could be expanded if needed. - * - * @param request - * The HttpServletRequest from the browser. - * @param resourceLastModifiedTimestamp - * The timestamp when the resource was last modified. 0 if the - * last modification time is unknown. - * @return true if the If-Modified-Since header tells the cached version in - * the browser is up to date, false otherwise - */ - private boolean browserHasNewestVersion(HttpServletRequest request, - long resourceLastModifiedTimestamp) { - if (resourceLastModifiedTimestamp < 1) { - // We do not know when it was modified so the browser cannot have an - // up-to-date version - return false; - } - /* - * The browser can request the resource conditionally using an - * If-Modified-Since header. Check this against the last modification - * time. - */ - try { - // If-Modified-Since represents the timestamp of the version cached - // in the browser - long headerIfModifiedSince = request - .getDateHeader("If-Modified-Since"); - - if (headerIfModifiedSince >= resourceLastModifiedTimestamp) { - // Browser has this an up-to-date version of the resource - return true; - } - } catch (Exception e) { - // Failed to parse header. Fail silently - the browser does not have - // an up-to-date version in its cache. - } - return false; - } - - protected enum RequestType { - FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE, CONNECTOR_RESOURCE; - } - - protected RequestType getRequestType(WrappedHttpServletRequest request) { - if (ServletPortletHelper.isFileUploadRequest(request)) { - return RequestType.FILE_UPLOAD; - } else if (ServletPortletHelper.isConnectorResourceRequest(request)) { - return RequestType.CONNECTOR_RESOURCE; - } else if (isBrowserDetailsRequest(request)) { - return RequestType.BROWSER_DETAILS; - } else if (ServletPortletHelper.isUIDLRequest(request)) { - return RequestType.UIDL; - } else if (isStaticResourceRequest(request)) { - return RequestType.STATIC_FILE; - } else if (ServletPortletHelper.isApplicationResourceRequest(request)) { - return RequestType.APPLICATION_RESOURCE; - } - return RequestType.OTHER; - - } - - private static boolean isBrowserDetailsRequest(HttpServletRequest request) { - return "POST".equals(request.getMethod()) - && request.getParameter("browserDetails") != null; - } - - private boolean isStaticResourceRequest(HttpServletRequest request) { - String pathInfo = request.getPathInfo(); - if (pathInfo == null || pathInfo.length() <= 10) { - return false; - } - - if ((request.getContextPath() != null) - && (request.getRequestURI().startsWith("/VAADIN/"))) { - return true; - } else if (request.getRequestURI().startsWith( - request.getContextPath() + "/VAADIN/")) { - return true; - } - - return false; - } - - private boolean isOnUnloadRequest(HttpServletRequest request) { - return request.getParameter(ApplicationConnection.PARAM_UNLOADBURST) != null; - } - - /** - * Get system messages from the current application class - * - * @return - */ - protected SystemMessages getSystemMessages() { - Class<? extends Application> appCls = null; - try { - appCls = getApplicationClass(); - } catch (ClassNotFoundException e) { - // Previous comment claimed that this should never happen - throw new SystemMessageException(e); - } - return getSystemMessages(appCls); - } - - public static SystemMessages getSystemMessages( - Class<? extends Application> appCls) { - try { - if (appCls != null) { - Method m = appCls - .getMethod("getSystemMessages", (Class[]) null); - return (Application.SystemMessages) m.invoke(null, - (Object[]) null); - } - } catch (SecurityException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (NoSuchMethodException e) { - // This is completely ok and should be silently ignored - } catch (IllegalArgumentException e) { - // This should never happen - throw new SystemMessageException(e); - } catch (IllegalAccessException e) { - throw new SystemMessageException( - "Application.getSystemMessage() should be static public", e); - } catch (InvocationTargetException e) { - // This should never happen - throw new SystemMessageException(e); - } - return Application.getSystemMessages(); - } - - protected abstract Class<? extends Application> getApplicationClass() - throws ClassNotFoundException; - - /** - * Return the URL from where static files, e.g. the widgetset and the theme, - * are served. In a standard configuration the VAADIN folder inside the - * returned folder is what is used for widgetsets and themes. - * - * The returned folder is usually the same as the context path and - * independent of the application. - * - * @param request - * @return The location of static resources (should contain the VAADIN - * directory). Never ends with a slash (/). - */ - protected String getStaticFilesLocation(HttpServletRequest request) { - - return getWebApplicationsStaticFileLocation(request); - } - - /** - * The default method to fetch static files location (URL). This method does - * not check for request attribute {@value #REQUEST_VAADIN_STATIC_FILE_PATH} - * - * @param request - * @return - */ - private String getWebApplicationsStaticFileLocation( - HttpServletRequest request) { - String staticFileLocation; - // if property is defined in configurations, use that - staticFileLocation = getDeploymentConfiguration() - .getApplicationOrSystemProperty(PARAMETER_VAADIN_RESOURCES, - null); - if (staticFileLocation != null) { - return staticFileLocation; - } - - // the last (but most common) option is to generate default location - // from request - - // if context is specified add it to widgetsetUrl - String ctxPath = request.getContextPath(); - - // FIXME: ctxPath.length() == 0 condition is probably unnecessary and - // might even be wrong. - - if (ctxPath.length() == 0 - && request.getAttribute("javax.servlet.include.context_path") != null) { - // include request (e.g portlet), get context path from - // attribute - ctxPath = (String) request - .getAttribute("javax.servlet.include.context_path"); - } - - // Remove heading and trailing slashes from the context path - ctxPath = removeHeadingOrTrailing(ctxPath, "/"); - - if (ctxPath.equals("")) { - return ""; - } else { - return "/" + ctxPath; - } - } - - /** - * Remove any heading or trailing "what" from the "string". - * - * @param string - * @param what - * @return - */ - private static String removeHeadingOrTrailing(String string, String what) { - while (string.startsWith(what)) { - string = string.substring(1); - } - - while (string.endsWith(what)) { - string = string.substring(0, string.length() - 1); - } - - return string; - } - - /** - * Write a redirect response to the main page of the application. - * - * @param request - * @param response - * @throws IOException - * if sending the redirect fails due to an input/output error or - * a bad application URL - */ - private void redirectToApplication(HttpServletRequest request, - HttpServletResponse response) throws IOException { - String applicationUrl = getApplicationUrl(request).toExternalForm(); - response.sendRedirect(response.encodeRedirectURL(applicationUrl)); - } - - /** - * Gets the current application URL from request. - * - * @param request - * the HTTP request. - * @throws MalformedURLException - * if the application is denied access to the persistent data - * store represented by the given URL. - */ - protected URL getApplicationUrl(HttpServletRequest request) - throws MalformedURLException { - final URL reqURL = new URL( - (request.isSecure() ? "https://" : "http://") - + request.getServerName() - + ((request.isSecure() && request.getServerPort() == 443) - || (!request.isSecure() && request - .getServerPort() == 80) ? "" : ":" - + request.getServerPort()) - + request.getRequestURI()); - String servletPath = ""; - if (request.getAttribute("javax.servlet.include.servlet_path") != null) { - // this is an include request - servletPath = request.getAttribute( - "javax.servlet.include.context_path").toString() - + request - .getAttribute("javax.servlet.include.servlet_path"); - - } else { - servletPath = request.getContextPath() + request.getServletPath(); - } - - if (servletPath.length() == 0 - || servletPath.charAt(servletPath.length() - 1) != '/') { - servletPath = servletPath + "/"; - } - URL u = new URL(reqURL, servletPath); - return u; - } - - /** - * Gets the existing application for given request. Looks for application - * instance for given request based on the requested URL. - * - * @param request - * the HTTP request. - * @param allowSessionCreation - * true if a session should be created if no session exists, - * false if no session should be created - * @return Application instance, or null if the URL does not map to valid - * application. - * @throws MalformedURLException - * if the application is denied access to the persistent data - * store represented by the given URL. - * @throws IllegalAccessException - * @throws InstantiationException - * @throws SessionExpiredException - */ - protected Application getExistingApplication(HttpServletRequest request, - boolean allowSessionCreation) throws MalformedURLException, - SessionExpiredException { - - // Ensures that the session is still valid - final HttpSession session = request.getSession(allowSessionCreation); - if (session == null) { - throw new SessionExpiredException(); - } - - WebApplicationContext context = getApplicationContext(session); - - // Gets application list for the session. - final Collection<Application> applications = context.getApplications(); - - // Search for the application (using the application URI) from the list - for (final Iterator<Application> i = applications.iterator(); i - .hasNext();) { - final Application sessionApplication = i.next(); - final String sessionApplicationPath = sessionApplication.getURL() - .getPath(); - String requestApplicationPath = getApplicationUrl(request) - .getPath(); - - if (requestApplicationPath.equals(sessionApplicationPath)) { - // Found a running application - if (sessionApplication.isRunning()) { - return sessionApplication; - } - // Application has stopped, so remove it before creating a new - // application - getApplicationContext(session).removeApplication( - sessionApplication); - break; - } - } - - // Existing application not found - return null; - } - - /** - * Ends the application. - * - * @param request - * the HTTP request. - * @param response - * the HTTP response to write to. - * @param application - * the application to end. - * @throws IOException - * if the writing failed due to input/output error. - */ - private void endApplication(HttpServletRequest request, - HttpServletResponse response, Application application) - throws IOException { - - String logoutUrl = application.getLogoutURL(); - if (logoutUrl == null) { - logoutUrl = application.getURL().toString(); - } - - final HttpSession session = request.getSession(); - if (session != null) { - getApplicationContext(session).removeApplication(application); - } - - response.sendRedirect(response.encodeRedirectURL(logoutUrl)); - } - - /** - * Returns the path info; note that this _can_ be different than - * request.getPathInfo(). Examples where this might be useful: - * <ul> - * <li>An application runner servlet that runs different Vaadin applications - * based on an identifier.</li> - * <li>Providing a REST interface in the context root, while serving a - * Vaadin UI on a sub-URI using only one servlet (e.g. REST on - * http://example.com/foo, UI on http://example.com/foo/vaadin)</li> - * - * @param request - * @return - */ - protected String getRequestPathInfo(HttpServletRequest request) { - return request.getPathInfo(); - } - - /** - * Gets relative location of a theme resource. - * - * @param theme - * the Theme name. - * @param resource - * the Theme resource. - * @return External URI specifying the resource - */ - public String getResourceLocation(String theme, ThemeResource resource) { - - if (resourcePath == null) { - return resource.getResourceId(); - } - return resourcePath + theme + "/" + resource.getResourceId(); - } - - private boolean isRepaintAll(HttpServletRequest request) { - return (request.getParameter(URL_PARAMETER_REPAINT_ALL) != null) - && (request.getParameter(URL_PARAMETER_REPAINT_ALL).equals("1")); - } - - private void closeApplication(Application application, HttpSession session) { - if (application == null) { - return; - } - - application.close(); - if (session != null) { - WebApplicationContext context = getApplicationContext(session); - context.removeApplication(application); - } - } - - /** - * - * Gets the application context from an HttpSession. If no context is - * currently stored in a session a new context is created and stored in the - * session. - * - * @param session - * the HTTP session. - * @return the application context for HttpSession. - */ - protected WebApplicationContext getApplicationContext(HttpSession session) { - /* - * TODO the ApplicationContext.getApplicationContext() should be removed - * and logic moved here. Now overriding context type is possible, but - * the whole creation logic should be here. MT 1101 - */ - return WebApplicationContext.getApplicationContext(session); - } - - public class RequestError implements Terminal.ErrorEvent, Serializable { - - private final Throwable throwable; - - public RequestError(Throwable throwable) { - this.throwable = throwable; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - } - - /** - * Override this method if you need to use a specialized communicaiton - * mananger implementation. - * - * @deprecated Instead of overriding this method, override - * {@link WebApplicationContext} implementation via - * {@link AbstractApplicationServlet#getApplicationContext(HttpSession)} - * method and in that customized implementation return your - * CommunicationManager in - * {@link WebApplicationContext#getApplicationManager(Application, AbstractApplicationServlet)} - * method. - * - * @param application - * @return - */ - @Deprecated - public CommunicationManager createCommunicationManager( - Application application) { - return new CommunicationManager(application); - } - - /** - * Escapes characters to html entities. An exception is made for some - * "safe characters" to keep the text somewhat readable. - * - * @param unsafe - * @return a safe string to be added inside an html tag - */ - public static final String safeEscapeForHtml(String unsafe) { - if (null == unsafe) { - return null; - } - StringBuilder safe = new StringBuilder(); - char[] charArray = unsafe.toCharArray(); - for (int i = 0; i < charArray.length; i++) { - char c = charArray[i]; - if (isSafe(c)) { - safe.append(c); - } else { - safe.append("&#"); - safe.append((int) c); - safe.append(";"); - } - } - - return safe.toString(); - } - - private static boolean isSafe(char c) { - return // - c > 47 && c < 58 || // alphanum - c > 64 && c < 91 || // A-Z - c > 96 && c < 123 // a-z - ; - } - - private static final Logger getLogger() { - return Logger.getLogger(AbstractApplicationServlet.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java deleted file mode 100644 index ba1b3cadb6..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java +++ /dev/null @@ -1,2790 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.CharArrayWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Serializable; -import java.io.StringWriter; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Type; -import java.net.URI; -import java.net.URISyntaxException; -import java.security.GeneralSecurityException; -import java.text.CharacterIterator; -import java.text.DateFormat; -import java.text.DateFormatSymbols; -import java.text.SimpleDateFormat; -import java.text.StringCharacterIterator; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.http.HttpServletResponse; - -import com.vaadin.Application; -import com.vaadin.Application.SystemMessages; -import com.vaadin.RootRequiresMoreInformationException; -import com.vaadin.Version; -import com.vaadin.annotations.JavaScript; -import com.vaadin.annotations.StyleSheet; -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.shared.Connector; -import com.vaadin.shared.communication.MethodInvocation; -import com.vaadin.shared.communication.SharedState; -import com.vaadin.shared.communication.UidlValue; -import com.vaadin.terminal.AbstractClientConnector; -import com.vaadin.terminal.CombinedRequest; -import com.vaadin.terminal.LegacyPaint; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.StreamVariable; -import com.vaadin.terminal.StreamVariable.StreamingEndEvent; -import com.vaadin.terminal.StreamVariable.StreamingErrorEvent; -import com.vaadin.terminal.Terminal.ErrorEvent; -import com.vaadin.terminal.Terminal.ErrorListener; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.server.BootstrapHandler.BootstrapContext; -import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout; -import com.vaadin.terminal.gwt.server.RpcManager.RpcInvocationException; -import com.vaadin.ui.AbstractComponent; -import com.vaadin.ui.AbstractField; -import com.vaadin.ui.Component; -import com.vaadin.ui.ConnectorTracker; -import com.vaadin.ui.HasComponents; -import com.vaadin.ui.Root; -import com.vaadin.ui.Window; - -/** - * This is a common base class for the server-side implementations of the - * communication system between the client code (compiled with GWT into - * JavaScript) and the server side components. Its client side counterpart is - * {@link ApplicationConnection}. - * - * TODO Document better! - */ -@SuppressWarnings("serial") -public abstract class AbstractCommunicationManager implements Serializable { - - private static final String DASHDASH = "--"; - - private static final RequestHandler APP_RESOURCE_HANDLER = new ApplicationResourceHandler(); - - private static final RequestHandler UNSUPPORTED_BROWSER_HANDLER = new UnsupportedBrowserHandler(); - - /** - * TODO Document me! - * - * @author peholmst - */ - public interface Callback extends Serializable { - - public void criticalNotification(WrappedRequest request, - WrappedResponse response, String cap, String msg, - String details, String outOfSyncURL) throws IOException; - } - - static class UploadInterruptedException extends Exception { - public UploadInterruptedException() { - super("Upload interrupted by other thread"); - } - } - - private static String GET_PARAM_REPAINT_ALL = "repaintAll"; - - // flag used in the request to indicate that the security token should be - // written to the response - private static final String WRITE_SECURITY_TOKEN_FLAG = "writeSecurityToken"; - - /* Variable records indexes */ - public static final char VAR_BURST_SEPARATOR = '\u001d'; - - public static final char VAR_ESCAPE_CHARACTER = '\u001b'; - - private final HashMap<Integer, ClientCache> rootToClientCache = new HashMap<Integer, ClientCache>(); - - private static final int MAX_BUFFER_SIZE = 64 * 1024; - - /* Same as in apache commons file upload library that was previously used. */ - private static final int MAX_UPLOAD_BUFFER_SIZE = 4 * 1024; - - private static final String GET_PARAM_ANALYZE_LAYOUTS = "analyzeLayouts"; - - /** - * The application this communication manager is used for - */ - private final Application application; - - private List<String> locales; - - private int pendingLocalesIndex; - - private int timeoutInterval = -1; - - private DragAndDropService dragAndDropService; - - private String requestThemeName; - - private int maxInactiveInterval; - - private Connector highlightedConnector; - - private Map<String, Class<?>> connectorResourceContexts = new HashMap<String, Class<?>>(); - - private Map<String, Map<String, StreamVariable>> pidToNameToStreamVariable; - - private Map<StreamVariable, String> streamVariableToSeckey; - - /** - * TODO New constructor - document me! - * - * @param application - */ - public AbstractCommunicationManager(Application application) { - this.application = application; - application.addRequestHandler(getBootstrapHandler()); - application.addRequestHandler(APP_RESOURCE_HANDLER); - application.addRequestHandler(UNSUPPORTED_BROWSER_HANDLER); - requireLocale(application.getLocale().toString()); - } - - protected Application getApplication() { - return application; - } - - private static final int LF = "\n".getBytes()[0]; - - private static final String CRLF = "\r\n"; - - private static final String UTF8 = "UTF8"; - - private static final String GET_PARAM_HIGHLIGHT_COMPONENT = "highlightComponent"; - - private static String readLine(InputStream stream) throws IOException { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - int readByte = stream.read(); - while (readByte != LF) { - bout.write(readByte); - readByte = stream.read(); - } - byte[] bytes = bout.toByteArray(); - return new String(bytes, 0, bytes.length - 1, UTF8); - } - - /** - * Method used to stream content from a multipart request (either from - * servlet or portlet request) to given StreamVariable - * - * - * @param request - * @param response - * @param streamVariable - * @param owner - * @param boundary - * @throws IOException - */ - protected void doHandleSimpleMultipartFileUpload(WrappedRequest request, - WrappedResponse response, StreamVariable streamVariable, - String variableName, ClientConnector owner, String boundary) - throws IOException { - // multipart parsing, supports only one file for request, but that is - // fine for our current terminal - - final InputStream inputStream = request.getInputStream(); - - int contentLength = request.getContentLength(); - - boolean atStart = false; - boolean firstFileFieldFound = false; - - String rawfilename = "unknown"; - String rawMimeType = "application/octet-stream"; - - /* - * Read the stream until the actual file starts (empty line). Read - * filename and content type from multipart headers. - */ - while (!atStart) { - String readLine = readLine(inputStream); - contentLength -= (readLine.length() + 2); - if (readLine.startsWith("Content-Disposition:") - && readLine.indexOf("filename=") > 0) { - rawfilename = readLine.replaceAll(".*filename=", ""); - String parenthesis = rawfilename.substring(0, 1); - rawfilename = rawfilename.substring(1); - rawfilename = rawfilename.substring(0, - rawfilename.indexOf(parenthesis)); - firstFileFieldFound = true; - } else if (firstFileFieldFound && readLine.equals("")) { - atStart = true; - } else if (readLine.startsWith("Content-Type")) { - rawMimeType = readLine.split(": ")[1]; - } - } - - contentLength -= (boundary.length() + CRLF.length() + 2 - * DASHDASH.length() + 2); // 2 == CRLF - - /* - * Reads bytes from the underlying stream. Compares the read bytes to - * the boundary string and returns -1 if met. - * - * The matching happens so that if the read byte equals to the first - * char of boundary string, the stream goes to "buffering mode". In - * buffering mode bytes are read until the character does not match the - * corresponding from boundary string or the full boundary string is - * found. - * - * Note, if this is someday needed elsewhere, don't shoot yourself to - * foot and split to a top level helper class. - */ - InputStream simpleMultiPartReader = new SimpleMultiPartInputStream( - inputStream, boundary); - - /* - * Should report only the filename even if the browser sends the path - */ - final String filename = removePath(rawfilename); - final String mimeType = rawMimeType; - - try { - // TODO Shouldn't this check connectorEnabled? - if (owner == null) { - throw new UploadException( - "File upload ignored because the connector for the stream variable was not found"); - } - if (owner instanceof Component) { - if (((Component) owner).isReadOnly()) { - throw new UploadException( - "Warning: file upload ignored because the componente was read-only"); - } - } - boolean forgetVariable = streamToReceiver(simpleMultiPartReader, - streamVariable, filename, mimeType, contentLength); - if (forgetVariable) { - cleanStreamVariable(owner, variableName); - } - } catch (Exception e) { - synchronized (application) { - handleChangeVariablesError(application, (Component) owner, e, - new HashMap<String, Object>()); - } - } - sendUploadResponse(request, response); - - } - - /** - * Used to stream plain file post (aka XHR2.post(File)) - * - * @param request - * @param response - * @param streamVariable - * @param owner - * @param contentLength - * @throws IOException - */ - protected void doHandleXhrFilePost(WrappedRequest request, - WrappedResponse response, StreamVariable streamVariable, - String variableName, ClientConnector owner, int contentLength) - throws IOException { - - // These are unknown in filexhr ATM, maybe add to Accept header that - // is accessible in portlets - final String filename = "unknown"; - final String mimeType = filename; - final InputStream stream = request.getInputStream(); - try { - /* - * safe cast as in GWT terminal all variable owners are expected to - * be components. - */ - Component component = (Component) owner; - if (component.isReadOnly()) { - throw new UploadException( - "Warning: file upload ignored because the component was read-only"); - } - boolean forgetVariable = streamToReceiver(stream, streamVariable, - filename, mimeType, contentLength); - if (forgetVariable) { - cleanStreamVariable(owner, variableName); - } - } catch (Exception e) { - synchronized (application) { - handleChangeVariablesError(application, (Component) owner, e, - new HashMap<String, Object>()); - } - } - sendUploadResponse(request, response); - } - - /** - * @param in - * @param streamVariable - * @param filename - * @param type - * @param contentLength - * @return true if the streamvariable has informed that the terminal can - * forget this variable - * @throws UploadException - */ - protected final boolean streamToReceiver(final InputStream in, - StreamVariable streamVariable, String filename, String type, - int contentLength) throws UploadException { - if (streamVariable == null) { - throw new IllegalStateException( - "StreamVariable for the post not found"); - } - - final Application application = getApplication(); - - OutputStream out = null; - int totalBytes = 0; - StreamingStartEventImpl startedEvent = new StreamingStartEventImpl( - filename, type, contentLength); - try { - boolean listenProgress; - synchronized (application) { - streamVariable.streamingStarted(startedEvent); - out = streamVariable.getOutputStream(); - listenProgress = streamVariable.listenProgress(); - } - - // Gets the output target stream - if (out == null) { - throw new NoOutputStreamException(); - } - - if (null == in) { - // No file, for instance non-existent filename in html upload - throw new NoInputStreamException(); - } - - final byte buffer[] = new byte[MAX_UPLOAD_BUFFER_SIZE]; - int bytesReadToBuffer = 0; - while ((bytesReadToBuffer = in.read(buffer)) > 0) { - out.write(buffer, 0, bytesReadToBuffer); - totalBytes += bytesReadToBuffer; - if (listenProgress) { - // update progress if listener set and contentLength - // received - synchronized (application) { - StreamingProgressEventImpl progressEvent = new StreamingProgressEventImpl( - filename, type, contentLength, totalBytes); - streamVariable.onProgress(progressEvent); - } - } - if (streamVariable.isInterrupted()) { - throw new UploadInterruptedException(); - } - } - - // upload successful - out.close(); - StreamingEndEvent event = new StreamingEndEventImpl(filename, type, - totalBytes); - synchronized (application) { - streamVariable.streamingFinished(event); - } - - } catch (UploadInterruptedException e) { - // Download interrupted by application code - tryToCloseStream(out); - StreamingErrorEvent event = new StreamingErrorEventImpl(filename, - type, contentLength, totalBytes, e); - synchronized (application) { - streamVariable.streamingFailed(event); - } - // Note, we are not throwing interrupted exception forward as it is - // not a terminal level error like all other exception. - } catch (final Exception e) { - tryToCloseStream(out); - synchronized (application) { - StreamingErrorEvent event = new StreamingErrorEventImpl( - filename, type, contentLength, totalBytes, e); - synchronized (application) { - streamVariable.streamingFailed(event); - } - // throw exception for terminal to be handled (to be passed to - // terminalErrorHandler) - throw new UploadException(e); - } - } - return startedEvent.isDisposed(); - } - - static void tryToCloseStream(OutputStream out) { - try { - // try to close output stream (e.g. file handle) - if (out != null) { - out.close(); - } - } catch (IOException e1) { - // NOP - } - } - - /** - * Removes any possible path information from the filename and returns the - * filename. Separators / and \\ are used. - * - * @param name - * @return - */ - private static String removePath(String filename) { - if (filename != null) { - filename = filename.replaceAll("^.*[/\\\\]", ""); - } - - return filename; - } - - /** - * TODO document - * - * @param request - * @param response - * @throws IOException - */ - protected void sendUploadResponse(WrappedRequest request, - WrappedResponse response) throws IOException { - response.setContentType("text/html"); - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - outWriter.print("<html><body>download handled</body></html>"); - outWriter.flush(); - out.close(); - } - - /** - * Internally process a UIDL request from the client. - * - * This method calls - * {@link #handleVariables(WrappedRequest, WrappedResponse, Callback, Application, Root)} - * to process any changes to variables by the client and then repaints - * affected components using {@link #paintAfterVariableChanges()}. - * - * Also, some cleanup is done when a request arrives for an application that - * has already been closed. - * - * The method handleUidlRequest(...) in subclasses should call this method. - * - * TODO better documentation - * - * @param request - * @param response - * @param callback - * @param root - * target window for the UIDL request, can be null if target not - * found - * @throws IOException - * @throws InvalidUIDLSecurityKeyException - * @throws JSONException - */ - public void handleUidlRequest(WrappedRequest request, - WrappedResponse response, Callback callback, Root root) - throws IOException, InvalidUIDLSecurityKeyException, JSONException { - - checkWidgetsetVersion(request); - requestThemeName = request.getParameter("theme"); - maxInactiveInterval = request.getSessionMaxInactiveInterval(); - // repaint requested or session has timed out and new one is created - boolean repaintAll; - final OutputStream out; - - repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null); - // || (request.getSession().isNew()); FIXME What the h*ll is this?? - out = response.getOutputStream(); - - boolean analyzeLayouts = false; - if (repaintAll) { - // analyzing can be done only with repaintAll - analyzeLayouts = (request.getParameter(GET_PARAM_ANALYZE_LAYOUTS) != null); - - if (request.getParameter(GET_PARAM_HIGHLIGHT_COMPONENT) != null) { - String pid = request - .getParameter(GET_PARAM_HIGHLIGHT_COMPONENT); - highlightedConnector = root.getConnectorTracker().getConnector( - pid); - highlightConnector(highlightedConnector); - } - } - - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - - // The rest of the process is synchronized with the application - // in order to guarantee that no parallel variable handling is - // made - synchronized (application) { - - // Finds the window within the application - if (application.isRunning()) { - // Returns if no window found - if (root == null) { - // This should not happen, no windows exists but - // application is still open. - getLogger().warning("Could not get root for application"); - return; - } - } else { - // application has been closed - endApplication(request, response, application); - return; - } - - // Change all variables based on request parameters - if (!handleVariables(request, response, callback, application, root)) { - - // var inconsistency; the client is probably out-of-sync - SystemMessages ci = null; - try { - Method m = application.getClass().getMethod( - "getSystemMessages", (Class[]) null); - ci = (Application.SystemMessages) m.invoke(null, - (Object[]) null); - } catch (Exception e2) { - // FIXME: Handle exception - // Not critical, but something is still wrong; print - // stacktrace - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e2); - } - if (ci != null) { - String msg = ci.getOutOfSyncMessage(); - String cap = ci.getOutOfSyncCaption(); - if (msg != null || cap != null) { - callback.criticalNotification(request, response, cap, - msg, null, ci.getOutOfSyncURL()); - // will reload page after this - return; - } - } - // No message to show, let's just repaint all. - repaintAll = true; - } - - paintAfterVariableChanges(request, response, callback, repaintAll, - outWriter, root, analyzeLayouts); - postPaint(root); - } - - outWriter.close(); - requestThemeName = null; - } - - /** - * Checks that the version reported by the client (widgetset) matches that - * of the server. - * - * @param request - */ - private void checkWidgetsetVersion(WrappedRequest request) { - String widgetsetVersion = request.getParameter("wsver"); - if (widgetsetVersion == null) { - // Only check when the widgetset version is reported. It is reported - // in the first UIDL request (not the initial request as it is a - // plain GET /) - return; - } - - if (!Version.getFullVersion().equals(widgetsetVersion)) { - getLogger().warning( - String.format(Constants.WIDGETSET_MISMATCH_INFO, - Version.getFullVersion(), widgetsetVersion)); - } - } - - /** - * Method called after the paint phase while still being synchronized on the - * application - * - * @param root - * - */ - protected void postPaint(Root root) { - // Remove connectors that have been detached from the application during - // handling of the request - root.getConnectorTracker().cleanConnectorMap(); - - if (pidToNameToStreamVariable != null) { - Iterator<String> iterator = pidToNameToStreamVariable.keySet() - .iterator(); - while (iterator.hasNext()) { - String connectorId = iterator.next(); - if (root.getConnectorTracker().getConnector(connectorId) == null) { - // Owner is no longer attached to the application - Map<String, StreamVariable> removed = pidToNameToStreamVariable - .get(connectorId); - for (String key : removed.keySet()) { - streamVariableToSeckey.remove(removed.get(key)); - } - iterator.remove(); - } - } - } - } - - protected void highlightConnector(Connector highlightedConnector) { - StringBuilder sb = new StringBuilder(); - sb.append("*** Debug details of a component: *** \n"); - sb.append("Type: "); - sb.append(highlightedConnector.getClass().getName()); - if (highlightedConnector instanceof AbstractComponent) { - AbstractComponent component = (AbstractComponent) highlightedConnector; - sb.append("\nId:"); - sb.append(highlightedConnector.getConnectorId()); - if (component.getCaption() != null) { - sb.append("\nCaption:"); - sb.append(component.getCaption()); - } - - printHighlightedComponentHierarchy(sb, component); - } - getLogger().info(sb.toString()); - } - - protected void printHighlightedComponentHierarchy(StringBuilder sb, - AbstractComponent component) { - LinkedList<Component> h = new LinkedList<Component>(); - h.add(component); - Component parent = component.getParent(); - while (parent != null) { - h.addFirst(parent); - parent = parent.getParent(); - } - - sb.append("\nComponent hierarchy:\n"); - Application application2 = component.getApplication(); - sb.append(application2.getClass().getName()); - sb.append("."); - sb.append(application2.getClass().getSimpleName()); - sb.append("("); - sb.append(application2.getClass().getSimpleName()); - sb.append(".java"); - sb.append(":1)"); - int l = 1; - for (Component component2 : h) { - sb.append("\n"); - for (int i = 0; i < l; i++) { - sb.append(" "); - } - l++; - Class<? extends Component> componentClass = component2.getClass(); - Class<?> topClass = componentClass; - while (topClass.getEnclosingClass() != null) { - topClass = topClass.getEnclosingClass(); - } - sb.append(componentClass.getName()); - sb.append("."); - sb.append(componentClass.getSimpleName()); - sb.append("("); - sb.append(topClass.getSimpleName()); - sb.append(".java:1)"); - } - } - - /** - * TODO document - * - * @param request - * @param response - * @param callback - * @param repaintAll - * @param outWriter - * @param window - * @param analyzeLayouts - * @throws PaintException - * @throws IOException - * @throws JSONException - */ - private void paintAfterVariableChanges(WrappedRequest request, - WrappedResponse response, Callback callback, boolean repaintAll, - final PrintWriter outWriter, Root root, boolean analyzeLayouts) - throws PaintException, IOException, JSONException { - - // Removes application if it has stopped during variable changes - if (!application.isRunning()) { - endApplication(request, response, application); - return; - } - - openJsonMessage(outWriter, response); - - // security key - Object writeSecurityTokenFlag = request - .getAttribute(WRITE_SECURITY_TOKEN_FLAG); - - if (writeSecurityTokenFlag != null) { - outWriter.print(getSecurityKeyUIDL(request)); - } - - writeUidlResponse(request, repaintAll, outWriter, root, analyzeLayouts); - - closeJsonMessage(outWriter); - - outWriter.close(); - - } - - /** - * Gets the security key (and generates one if needed) as UIDL. - * - * @param request - * @return the security key UIDL or "" if the feature is turned off - */ - public String getSecurityKeyUIDL(WrappedRequest request) { - final String seckey = getSecurityKey(request); - if (seckey != null) { - return "\"" + ApplicationConnection.UIDL_SECURITY_TOKEN_ID - + "\":\"" + seckey + "\","; - } else { - return ""; - } - } - - /** - * Gets the security key (and generates one if needed). - * - * @param request - * @return the security key - */ - protected String getSecurityKey(WrappedRequest request) { - String seckey = null; - seckey = (String) request - .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID); - if (seckey == null) { - seckey = UUID.randomUUID().toString(); - request.setSessionAttribute( - ApplicationConnection.UIDL_SECURITY_TOKEN_ID, seckey); - } - - return seckey; - } - - @SuppressWarnings("unchecked") - public void writeUidlResponse(WrappedRequest request, boolean repaintAll, - final PrintWriter outWriter, Root root, boolean analyzeLayouts) - throws PaintException, JSONException { - ArrayList<ClientConnector> dirtyVisibleConnectors = new ArrayList<ClientConnector>(); - Application application = root.getApplication(); - // Paints components - ConnectorTracker rootConnectorTracker = root.getConnectorTracker(); - getLogger().log(Level.FINE, "* Creating response to client"); - if (repaintAll) { - getClientCache(root).clear(); - rootConnectorTracker.markAllConnectorsDirty(); - - // Reset sent locales - locales = null; - requireLocale(application.getLocale().toString()); - } - - dirtyVisibleConnectors - .addAll(getDirtyVisibleConnectors(rootConnectorTracker)); - - getLogger().log( - Level.FINE, - "Found " + dirtyVisibleConnectors.size() - + " dirty connectors to paint"); - for (ClientConnector connector : dirtyVisibleConnectors) { - if (connector instanceof Component) { - ((Component) connector).updateState(); - } - } - rootConnectorTracker.markAllConnectorsClean(); - - outWriter.print("\"changes\":["); - - List<InvalidLayout> invalidComponentRelativeSizes = null; - - JsonPaintTarget paintTarget = new JsonPaintTarget(this, outWriter, - !repaintAll); - legacyPaint(paintTarget, dirtyVisibleConnectors); - - if (analyzeLayouts) { - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes(root.getContent(), null, - null); - - // Also check any existing subwindows - if (root.getWindows() != null) { - for (Window subWindow : root.getWindows()) { - invalidComponentRelativeSizes = ComponentSizeValidator - .validateComponentRelativeSizes( - subWindow.getContent(), - invalidComponentRelativeSizes, null); - } - } - } - - paintTarget.close(); - outWriter.print("], "); // close changes - - // send shared state to client - - // for now, send the complete state of all modified and new - // components - - // Ideally, all this would be sent before "changes", but that causes - // complications with legacy components that create sub-components - // in their paint phase. Nevertheless, this will be processed on the - // client after component creation but before legacy UIDL - // processing. - JSONObject sharedStates = new JSONObject(); - for (ClientConnector connector : dirtyVisibleConnectors) { - SharedState state = connector.getState(); - if (null != state) { - // encode and send shared state - try { - Class<? extends SharedState> stateType = connector - .getStateType(); - SharedState referenceState = null; - if (repaintAll) { - // Use an empty state object as reference for full - // repaints - try { - referenceState = stateType.newInstance(); - } catch (Exception e) { - getLogger().log( - Level.WARNING, - "Error creating reference object for state of type " - + stateType.getName()); - } - } - Object stateJson = JsonCodec.encode(state, referenceState, - stateType, root.getConnectorTracker()); - - sharedStates.put(connector.getConnectorId(), stateJson); - } catch (JSONException e) { - throw new PaintException( - "Failed to serialize shared state for connector " - + connector.getClass().getName() + " (" - + connector.getConnectorId() + "): " - + e.getMessage(), e); - } - } - } - outWriter.print("\"state\":"); - outWriter.append(sharedStates.toString()); - outWriter.print(", "); // close states - - // TODO This should be optimized. The type only needs to be - // sent once for each connector id + on refresh. Use the same cache as - // widget mapping - - JSONObject connectorTypes = new JSONObject(); - for (ClientConnector connector : dirtyVisibleConnectors) { - String connectorType = paintTarget.getTag(connector); - try { - connectorTypes.put(connector.getConnectorId(), connectorType); - } catch (JSONException e) { - throw new PaintException( - "Failed to send connector type for connector " - + connector.getConnectorId() + ": " - + e.getMessage(), e); - } - } - outWriter.print("\"types\":"); - outWriter.append(connectorTypes.toString()); - outWriter.print(", "); // close states - - // Send update hierarchy information to the client. - - // This could be optimized aswell to send only info if hierarchy has - // actually changed. Much like with the shared state. Note though - // that an empty hierarchy is information aswell (e.g. change from 1 - // child to 0 children) - - outWriter.print("\"hierarchy\":"); - - JSONObject hierarchyInfo = new JSONObject(); - for (ClientConnector connector : dirtyVisibleConnectors) { - String connectorId = connector.getConnectorId(); - JSONArray children = new JSONArray(); - - for (ClientConnector child : AbstractClientConnector - .getAllChildrenIterable(connector)) { - if (isVisible(child)) { - children.put(child.getConnectorId()); - } - } - try { - hierarchyInfo.put(connectorId, children); - } catch (JSONException e) { - throw new PaintException( - "Failed to send hierarchy information about " - + connectorId + " to the client: " - + e.getMessage(), e); - } - } - outWriter.append(hierarchyInfo.toString()); - outWriter.print(", "); // close hierarchy - - // send server to client RPC calls for components in the root, in call - // order - - // collect RPC calls from components in the root in the order in - // which they were performed, remove the calls from components - - LinkedList<ClientConnector> rpcPendingQueue = new LinkedList<ClientConnector>( - dirtyVisibleConnectors); - List<ClientMethodInvocation> pendingInvocations = collectPendingRpcCalls(dirtyVisibleConnectors); - - JSONArray rpcCalls = new JSONArray(); - for (ClientMethodInvocation invocation : pendingInvocations) { - // add invocation to rpcCalls - try { - JSONArray invocationJson = new JSONArray(); - invocationJson.put(invocation.getConnector().getConnectorId()); - invocationJson.put(invocation.getInterfaceName()); - invocationJson.put(invocation.getMethodName()); - JSONArray paramJson = new JSONArray(); - for (int i = 0; i < invocation.getParameterTypes().length; ++i) { - Type parameterType = invocation.getParameterTypes()[i]; - Object referenceParameter = null; - // TODO Use default values for RPC parameter types - // if (!JsonCodec.isInternalType(parameterType)) { - // try { - // referenceParameter = parameterType.newInstance(); - // } catch (Exception e) { - // logger.log(Level.WARNING, - // "Error creating reference object for parameter of type " - // + parameterType.getName()); - // } - // } - paramJson.put(JsonCodec.encode( - invocation.getParameters()[i], referenceParameter, - parameterType, root.getConnectorTracker())); - } - invocationJson.put(paramJson); - rpcCalls.put(invocationJson); - } catch (JSONException e) { - throw new PaintException( - "Failed to serialize RPC method call parameters for connector " - + invocation.getConnector().getConnectorId() - + " method " + invocation.getInterfaceName() - + "." + invocation.getMethodName() + ": " - + e.getMessage(), e); - } - - } - - if (rpcCalls.length() > 0) { - outWriter.print("\"rpc\" : "); - outWriter.append(rpcCalls.toString()); - outWriter.print(", "); // close rpc - } - - outWriter.print("\"meta\" : {"); - boolean metaOpen = false; - - if (repaintAll) { - metaOpen = true; - outWriter.write("\"repaintAll\":true"); - if (analyzeLayouts) { - outWriter.write(", \"invalidLayouts\":"); - outWriter.write("["); - if (invalidComponentRelativeSizes != null) { - boolean first = true; - for (InvalidLayout invalidLayout : invalidComponentRelativeSizes) { - if (!first) { - outWriter.write(","); - } else { - first = false; - } - invalidLayout.reportErrors(outWriter, this, System.err); - } - } - outWriter.write("]"); - } - if (highlightedConnector != null) { - outWriter.write(", \"hl\":\""); - outWriter.write(highlightedConnector.getConnectorId()); - outWriter.write("\""); - highlightedConnector = null; - } - } - - SystemMessages ci = null; - try { - Method m = application.getClass().getMethod("getSystemMessages", - (Class[]) null); - ci = (Application.SystemMessages) m.invoke(null, (Object[]) null); - } catch (NoSuchMethodException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } catch (IllegalArgumentException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } catch (IllegalAccessException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } catch (InvocationTargetException e) { - getLogger().log(Level.WARNING, - "getSystemMessages() failed - continuing", e); - } - - // meta instruction for client to enable auto-forward to - // sessionExpiredURL after timer expires. - if (ci != null && ci.getSessionExpiredMessage() == null - && ci.getSessionExpiredCaption() == null - && ci.isSessionExpiredNotificationEnabled()) { - int newTimeoutInterval = getTimeoutInterval(); - if (repaintAll || (timeoutInterval != newTimeoutInterval)) { - String escapedURL = ci.getSessionExpiredURL() == null ? "" : ci - .getSessionExpiredURL().replace("/", "\\/"); - if (metaOpen) { - outWriter.write(","); - } - outWriter.write("\"timedRedirect\":{\"interval\":" - + (newTimeoutInterval + 15) + ",\"url\":\"" - + escapedURL + "\"}"); - metaOpen = true; - } - timeoutInterval = newTimeoutInterval; - } - - outWriter.print("}, \"resources\" : {"); - - // Precache custom layouts - - // TODO We should only precache the layouts that are not - // cached already (plagiate from usedPaintableTypes) - int resourceIndex = 0; - for (final Iterator<Object> i = paintTarget.getUsedResources() - .iterator(); i.hasNext();) { - final String resource = (String) i.next(); - InputStream is = null; - try { - is = getThemeResourceAsStream(root, getTheme(root), resource); - } catch (final Exception e) { - // FIXME: Handle exception - getLogger().log(Level.FINER, - "Failed to get theme resource stream.", e); - } - if (is != null) { - - outWriter.print((resourceIndex++ > 0 ? ", " : "") + "\"" - + resource + "\" : "); - final StringBuffer layout = new StringBuffer(); - - try { - final InputStreamReader r = new InputStreamReader(is, - "UTF-8"); - final char[] buffer = new char[20000]; - int charsRead = 0; - while ((charsRead = r.read(buffer)) > 0) { - layout.append(buffer, 0, charsRead); - } - r.close(); - } catch (final java.io.IOException e) { - // FIXME: Handle exception - getLogger().log(Level.INFO, "Resource transfer failed", e); - } - outWriter.print("\"" - + JsonPaintTarget.escapeJSON(layout.toString()) + "\""); - } else { - // FIXME: Handle exception - getLogger().severe("CustomLayout not found: " + resource); - } - } - outWriter.print("}"); - - Collection<Class<? extends ClientConnector>> usedClientConnectors = paintTarget - .getUsedClientConnectors(); - boolean typeMappingsOpen = false; - ClientCache clientCache = getClientCache(root); - - List<Class<? extends ClientConnector>> newConnectorTypes = new ArrayList<Class<? extends ClientConnector>>(); - - for (Class<? extends ClientConnector> class1 : usedClientConnectors) { - if (clientCache.cache(class1)) { - // client does not know the mapping key for this type, send - // mapping to client - newConnectorTypes.add(class1); - - if (!typeMappingsOpen) { - typeMappingsOpen = true; - outWriter.print(", \"typeMappings\" : { "); - } else { - outWriter.print(" , "); - } - String canonicalName = class1.getCanonicalName(); - outWriter.print("\""); - outWriter.print(canonicalName); - outWriter.print("\" : "); - outWriter.print(getTagForType(class1)); - } - } - if (typeMappingsOpen) { - outWriter.print(" }"); - } - - boolean typeInheritanceMapOpen = false; - if (typeMappingsOpen) { - // send the whole type inheritance map if any new mappings - for (Class<? extends ClientConnector> class1 : usedClientConnectors) { - if (!ClientConnector.class.isAssignableFrom(class1 - .getSuperclass())) { - continue; - } - if (!typeInheritanceMapOpen) { - typeInheritanceMapOpen = true; - outWriter.print(", \"typeInheritanceMap\" : { "); - } else { - outWriter.print(" , "); - } - outWriter.print("\""); - outWriter.print(getTagForType(class1)); - outWriter.print("\" : "); - outWriter - .print(getTagForType((Class<? extends ClientConnector>) class1 - .getSuperclass())); - } - if (typeInheritanceMapOpen) { - outWriter.print(" }"); - } - } - - /* - * Ensure super classes come before sub classes to get script dependency - * order right. Sub class @JavaScript might assume that @JavaScript - * defined by super class is already loaded. - */ - Collections.sort(newConnectorTypes, new Comparator<Class<?>>() { - @Override - public int compare(Class<?> o1, Class<?> o2) { - // TODO optimize using Class.isAssignableFrom? - return hierarchyDepth(o1) - hierarchyDepth(o2); - } - - private int hierarchyDepth(Class<?> type) { - if (type == Object.class) { - return 0; - } else { - return hierarchyDepth(type.getSuperclass()) + 1; - } - } - }); - - List<String> scriptDependencies = new ArrayList<String>(); - List<String> styleDependencies = new ArrayList<String>(); - - for (Class<? extends ClientConnector> class1 : newConnectorTypes) { - JavaScript jsAnnotation = class1.getAnnotation(JavaScript.class); - if (jsAnnotation != null) { - for (String resource : jsAnnotation.value()) { - scriptDependencies.add(registerResource(resource, class1)); - } - } - - StyleSheet styleAnnotation = class1.getAnnotation(StyleSheet.class); - if (styleAnnotation != null) { - for (String resource : styleAnnotation.value()) { - styleDependencies.add(registerResource(resource, class1)); - } - } - } - - // Include script dependencies in output if there are any - if (!scriptDependencies.isEmpty()) { - outWriter.print(", \"scriptDependencies\": " - + new JSONArray(scriptDependencies).toString()); - } - - // Include style dependencies in output if there are any - if (!styleDependencies.isEmpty()) { - outWriter.print(", \"styleDependencies\": " - + new JSONArray(styleDependencies).toString()); - } - - // add any pending locale definitions requested by the client - printLocaleDeclarations(outWriter); - - if (dragAndDropService != null) { - dragAndDropService.printJSONResponse(outWriter); - } - - writePerformanceData(outWriter); - } - - /** - * Resolves a resource URI, registering the URI with this - * {@code AbstractCommunicationManager} if needed and returns a fully - * qualified URI. - */ - private String registerResource(String resourceUri, Class<?> context) { - try { - URI uri = new URI(resourceUri); - String protocol = uri.getScheme(); - - if ("connector".equals(protocol)) { - // Strip initial slash - String resourceName = uri.getPath().substring(1); - return registerConnectorResource(resourceName, context); - } - - if (protocol != null || uri.getHost() != null) { - return resourceUri; - } - - // Bare path interpreted as connector resource - return registerConnectorResource(resourceUri, context); - } catch (URISyntaxException e) { - getLogger().log(Level.WARNING, - "Could not parse resource url " + resourceUri, e); - return resourceUri; - } - } - - private String registerConnectorResource(String name, Class<?> context) { - synchronized (connectorResourceContexts) { - // Add to map of names accepted by serveConnectorResource - if (connectorResourceContexts.containsKey(name)) { - Class<?> oldContext = connectorResourceContexts.get(name); - if (oldContext != context) { - getLogger().warning( - "Resource " + name + " defined by both " + context - + " and " + oldContext + ". Resource from " - + oldContext + " will be used."); - } - } else { - connectorResourceContexts.put(name, context); - } - } - - return ApplicationConnection.CONNECTOR_PROTOCOL_PREFIX + "/" + name; - } - - /** - * Adds the performance timing data (used by TestBench 3) to the UIDL - * response. - */ - private void writePerformanceData(final PrintWriter outWriter) { - AbstractWebApplicationContext ctx = (AbstractWebApplicationContext) application - .getContext(); - outWriter.write(String.format(", \"timings\":[%d, %d]", - ctx.getTotalSessionTime(), ctx.getLastRequestTime())); - } - - private void legacyPaint(PaintTarget paintTarget, - ArrayList<ClientConnector> dirtyVisibleConnectors) - throws PaintException { - List<Vaadin6Component> legacyComponents = new ArrayList<Vaadin6Component>(); - for (Connector connector : dirtyVisibleConnectors) { - // All Components that want to use paintContent must implement - // Vaadin6Component - if (connector instanceof Vaadin6Component) { - legacyComponents.add((Vaadin6Component) connector); - } - } - sortByHierarchy((List) legacyComponents); - for (Vaadin6Component c : legacyComponents) { - getLogger().fine( - "Painting Vaadin6Component " + c.getClass().getName() + "@" - + Integer.toHexString(c.hashCode())); - paintTarget.startTag("change"); - final String pid = c.getConnectorId(); - paintTarget.addAttribute("pid", pid); - LegacyPaint.paint(c, paintTarget); - paintTarget.endTag("change"); - } - - } - - private void sortByHierarchy(List<Component> paintables) { - // Vaadin 6 requires parents to be painted before children as component - // containers rely on that their updateFromUIDL method has been called - // before children start calling e.g. updateCaption - Collections.sort(paintables, new Comparator<Component>() { - - @Override - public int compare(Component c1, Component c2) { - int depth1 = 0; - while (c1.getParent() != null) { - depth1++; - c1 = c1.getParent(); - } - int depth2 = 0; - while (c2.getParent() != null) { - depth2++; - c2 = c2.getParent(); - } - if (depth1 < depth2) { - return -1; - } - if (depth1 > depth2) { - return 1; - } - return 0; - } - }); - - } - - private ClientCache getClientCache(Root root) { - Integer rootId = Integer.valueOf(root.getRootId()); - ClientCache cache = rootToClientCache.get(rootId); - if (cache == null) { - cache = new ClientCache(); - rootToClientCache.put(rootId, cache); - } - return cache; - } - - /** - * Checks if the connector is visible in context. For Components, - * {@link #isVisible(Component)} is used. For other types of connectors, the - * contextual visibility of its first Component ancestor is used. If no - * Component ancestor is found, the connector is not visible. - * - * @param connector - * The connector to check - * @return <code>true</code> if the connector is visible to the client, - * <code>false</code> otherwise - */ - static boolean isVisible(ClientConnector connector) { - if (connector instanceof Component) { - return isVisible((Component) connector); - } else { - ClientConnector parent = connector.getParent(); - if (parent == null) { - return false; - } else { - return isVisible(parent); - } - } - } - - /** - * Checks if the component is visible in context, i.e. returns false if the - * child is hidden, the parent is hidden or the parent says the child should - * not be rendered (using - * {@link HasComponents#isComponentVisible(Component)} - * - * @param child - * The child to check - * @return true if the child is visible to the client, false otherwise - */ - static boolean isVisible(Component child) { - if (!child.isVisible()) { - return false; - } - - HasComponents parent = child.getParent(); - if (parent == null) { - if (child instanceof Root) { - return child.isVisible(); - } else { - return false; - } - } - - return parent.isComponentVisible(child) && isVisible(parent); - } - - private static class NullIterator<E> implements Iterator<E> { - - @Override - public boolean hasNext() { - return false; - } - - @Override - public E next() { - return null; - } - - @Override - public void remove() { - } - - } - - /** - * Collects all pending RPC calls from listed {@link ClientConnector}s and - * clears their RPC queues. - * - * @param rpcPendingQueue - * list of {@link ClientConnector} of interest - * @return ordered list of pending RPC calls - */ - private List<ClientMethodInvocation> collectPendingRpcCalls( - List<ClientConnector> rpcPendingQueue) { - List<ClientMethodInvocation> pendingInvocations = new ArrayList<ClientMethodInvocation>(); - for (ClientConnector connector : rpcPendingQueue) { - List<ClientMethodInvocation> paintablePendingRpc = connector - .retrievePendingRpcCalls(); - if (null != paintablePendingRpc && !paintablePendingRpc.isEmpty()) { - List<ClientMethodInvocation> oldPendingRpc = pendingInvocations; - int totalCalls = pendingInvocations.size() - + paintablePendingRpc.size(); - pendingInvocations = new ArrayList<ClientMethodInvocation>( - totalCalls); - - // merge two ordered comparable lists - for (int destIndex = 0, oldIndex = 0, paintableIndex = 0; destIndex < totalCalls; destIndex++) { - if (paintableIndex >= paintablePendingRpc.size() - || (oldIndex < oldPendingRpc.size() && ((Comparable<ClientMethodInvocation>) oldPendingRpc - .get(oldIndex)) - .compareTo(paintablePendingRpc - .get(paintableIndex)) <= 0)) { - pendingInvocations.add(oldPendingRpc.get(oldIndex++)); - } else { - pendingInvocations.add(paintablePendingRpc - .get(paintableIndex++)); - } - } - } - } - return pendingInvocations; - } - - protected abstract InputStream getThemeResourceAsStream(Root root, - String themeName, String resource); - - private int getTimeoutInterval() { - return maxInactiveInterval; - } - - private String getTheme(Root root) { - String themeName = root.getApplication().getThemeForRoot(root); - String requestThemeName = getRequestTheme(); - - if (requestThemeName != null) { - themeName = requestThemeName; - } - if (themeName == null) { - themeName = AbstractApplicationServlet.getDefaultTheme(); - } - return themeName; - } - - private String getRequestTheme() { - return requestThemeName; - } - - /** - * Returns false if the cross site request forgery protection is turned off. - * - * @param application - * @return false if the XSRF is turned off, true otherwise - */ - public boolean isXSRFEnabled(Application application) { - return !"true" - .equals(application - .getProperty(AbstractApplicationServlet.SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION)); - } - - /** - * TODO document - * - * If this method returns false, something was submitted that we did not - * expect; this is probably due to the client being out-of-sync and sending - * variable changes for non-existing pids - * - * @return true if successful, false if there was an inconsistency - */ - private boolean handleVariables(WrappedRequest request, - WrappedResponse response, Callback callback, - Application application2, Root root) throws IOException, - InvalidUIDLSecurityKeyException, JSONException { - boolean success = true; - - String changes = getRequestPayload(request); - if (changes != null) { - - // Manage bursts one by one - final String[] bursts = changes.split(String - .valueOf(VAR_BURST_SEPARATOR)); - - // Security: double cookie submission pattern unless disabled by - // property - if (isXSRFEnabled(application2)) { - if (bursts.length == 1 && "init".equals(bursts[0])) { - // init request; don't handle any variables, key sent in - // response. - request.setAttribute(WRITE_SECURITY_TOKEN_FLAG, true); - return true; - } else { - // ApplicationServlet has stored the security token in the - // session; check that it matched the one sent in the UIDL - String sessId = (String) request - .getSessionAttribute(ApplicationConnection.UIDL_SECURITY_TOKEN_ID); - - if (sessId == null || !sessId.equals(bursts[0])) { - throw new InvalidUIDLSecurityKeyException( - "Security key mismatch"); - } - } - - } - - for (int bi = 1; bi < bursts.length; bi++) { - // unescape any encoded separator characters in the burst - final String burst = unescapeBurst(bursts[bi]); - success &= handleBurst(request, root, burst); - - // In case that there were multiple bursts, we know that this is - // a special synchronous case for closing window. Thus we are - // not interested in sending any UIDL changes back to client. - // Still we must clear component tree between bursts to ensure - // that no removed components are updated. The painting after - // the last burst is handled normally by the calling method. - if (bi < bursts.length - 1) { - - // We will be discarding all changes - final PrintWriter outWriter = new PrintWriter( - new CharArrayWriter()); - - paintAfterVariableChanges(request, response, callback, - true, outWriter, root, false); - - } - - } - } - /* - * Note that we ignore inconsistencies while handling unload request. - * The client can't remove invalid variable changes from the burst, and - * we don't have the required logic implemented on the server side. E.g. - * a component is removed in a previous burst. - */ - return success; - } - - /** - * Processes a message burst received from the client. - * - * A burst can contain any number of RPC calls, including legacy variable - * change calls that are processed separately. - * - * Consecutive changes to the value of the same variable are combined and - * changeVariables() is only called once for them. This preserves the Vaadin - * 6 semantics for components and add-ons that do not use Vaadin 7 RPC - * directly. - * - * @param source - * @param root - * the root receiving the burst - * @param burst - * the content of the burst as a String to be parsed - * @return true if the processing of the burst was successful and there were - * no messages to non-existent components - */ - public boolean handleBurst(WrappedRequest source, Root root, - final String burst) { - boolean success = true; - try { - Set<Connector> enabledConnectors = new HashSet<Connector>(); - - List<MethodInvocation> invocations = parseInvocations( - root.getConnectorTracker(), burst); - for (MethodInvocation invocation : invocations) { - final ClientConnector connector = getConnector(root, - invocation.getConnectorId()); - - if (connector != null && connector.isConnectorEnabled()) { - enabledConnectors.add(connector); - } - } - - for (int i = 0; i < invocations.size(); i++) { - MethodInvocation invocation = invocations.get(i); - - final ClientConnector connector = getConnector(root, - invocation.getConnectorId()); - - if (connector == null) { - getLogger().log( - Level.WARNING, - "RPC call to " + invocation.getInterfaceName() - + "." + invocation.getMethodName() - + " received for connector " - + invocation.getConnectorId() - + " but no such connector could be found"); - continue; - } - - if (!enabledConnectors.contains(connector)) { - - if (invocation instanceof LegacyChangeVariablesInvocation) { - LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation; - // TODO convert window close to a separate RPC call and - // handle above - not a variable change - - // Handle special case where window-close is called - // after the window has been removed from the - // application or the application has closed - Map<String, Object> changes = legacyInvocation - .getVariableChanges(); - if (changes.size() == 1 && changes.containsKey("close") - && Boolean.TRUE.equals(changes.get("close"))) { - // Silently ignore this - continue; - } - } - - // Connector is disabled, log a warning and move to the next - String msg = "Ignoring RPC call for disabled connector " - + connector.getClass().getName(); - if (connector instanceof Component) { - String caption = ((Component) connector).getCaption(); - if (caption != null) { - msg += ", caption=" + caption; - } - } - getLogger().warning(msg); - continue; - } - - if (invocation instanceof ServerRpcMethodInvocation) { - try { - ServerRpcManager.applyInvocation(connector, - (ServerRpcMethodInvocation) invocation); - } catch (RpcInvocationException e) { - Throwable realException = e.getCause(); - Component errorComponent = null; - if (connector instanceof Component) { - errorComponent = (Component) connector; - } - handleChangeVariablesError(root.getApplication(), - errorComponent, realException, null); - } - } else { - - // All code below is for legacy variable changes - LegacyChangeVariablesInvocation legacyInvocation = (LegacyChangeVariablesInvocation) invocation; - Map<String, Object> changes = legacyInvocation - .getVariableChanges(); - try { - if (connector instanceof VariableOwner) { - changeVariables(source, (VariableOwner) connector, - changes); - } else { - throw new IllegalStateException( - "Received legacy variable change for " - + connector.getClass().getName() - + " (" - + connector.getConnectorId() - + ") which is not a VariableOwner. The client-side connector sent these legacy varaibles: " - + changes.keySet()); - } - } catch (Exception e) { - Component errorComponent = null; - if (connector instanceof Component) { - errorComponent = (Component) connector; - } else if (connector instanceof DragAndDropService) { - Object dropHandlerOwner = changes.get("dhowner"); - if (dropHandlerOwner instanceof Component) { - errorComponent = (Component) dropHandlerOwner; - } - } - handleChangeVariablesError(root.getApplication(), - errorComponent, e, changes); - } - } - } - } catch (JSONException e) { - getLogger().warning( - "Unable to parse RPC call from the client: " - + e.getMessage()); - // TODO or return success = false? - throw new RuntimeException(e); - } - - return success; - } - - /** - * Parse a message burst from the client into a list of MethodInvocation - * instances. - * - * @param connectorTracker - * The ConnectorTracker used to lookup connectors - * @param burst - * message string (JSON) - * @return list of MethodInvocation to perform - * @throws JSONException - */ - private List<MethodInvocation> parseInvocations( - ConnectorTracker connectorTracker, final String burst) - throws JSONException { - JSONArray invocationsJson = new JSONArray(burst); - - ArrayList<MethodInvocation> invocations = new ArrayList<MethodInvocation>(); - - MethodInvocation previousInvocation = null; - // parse JSON to MethodInvocations - for (int i = 0; i < invocationsJson.length(); ++i) { - - JSONArray invocationJson = invocationsJson.getJSONArray(i); - - MethodInvocation invocation = parseInvocation(invocationJson, - previousInvocation, connectorTracker); - if (invocation != null) { - // Can be null iff the invocation was a legacy invocation and it - // was merged with the previous one - invocations.add(invocation); - previousInvocation = invocation; - } - } - return invocations; - } - - private MethodInvocation parseInvocation(JSONArray invocationJson, - MethodInvocation previousInvocation, - ConnectorTracker connectorTracker) throws JSONException { - String connectorId = invocationJson.getString(0); - String interfaceName = invocationJson.getString(1); - String methodName = invocationJson.getString(2); - - JSONArray parametersJson = invocationJson.getJSONArray(3); - - if (LegacyChangeVariablesInvocation.isLegacyVariableChange( - interfaceName, methodName)) { - if (!(previousInvocation instanceof LegacyChangeVariablesInvocation)) { - previousInvocation = null; - } - - return parseLegacyChangeVariablesInvocation(connectorId, - interfaceName, methodName, - (LegacyChangeVariablesInvocation) previousInvocation, - parametersJson, connectorTracker); - } else { - return parseServerRpcInvocation(connectorId, interfaceName, - methodName, parametersJson, connectorTracker); - } - - } - - private LegacyChangeVariablesInvocation parseLegacyChangeVariablesInvocation( - String connectorId, String interfaceName, String methodName, - LegacyChangeVariablesInvocation previousInvocation, - JSONArray parametersJson, ConnectorTracker connectorTracker) - throws JSONException { - if (parametersJson.length() != 2) { - throw new JSONException( - "Invalid parameters in legacy change variables call. Expected 2, was " - + parametersJson.length()); - } - String variableName = parametersJson.getString(0); - UidlValue uidlValue = (UidlValue) JsonCodec.decodeInternalType( - UidlValue.class, true, parametersJson.get(1), connectorTracker); - - Object value = uidlValue.getValue(); - - if (previousInvocation != null - && previousInvocation.getConnectorId().equals(connectorId)) { - previousInvocation.setVariableChange(variableName, value); - return null; - } else { - return new LegacyChangeVariablesInvocation(connectorId, - variableName, value); - } - } - - private ServerRpcMethodInvocation parseServerRpcInvocation( - String connectorId, String interfaceName, String methodName, - JSONArray parametersJson, ConnectorTracker connectorTracker) - throws JSONException { - ServerRpcMethodInvocation invocation = new ServerRpcMethodInvocation( - connectorId, interfaceName, methodName, parametersJson.length()); - - Object[] parameters = new Object[parametersJson.length()]; - Type[] declaredRpcMethodParameterTypes = invocation.getMethod() - .getGenericParameterTypes(); - - for (int j = 0; j < parametersJson.length(); ++j) { - Object parameterValue = parametersJson.get(j); - Type parameterType = declaredRpcMethodParameterTypes[j]; - parameters[j] = JsonCodec.decodeInternalOrCustomType(parameterType, - parameterValue, connectorTracker); - } - invocation.setParameters(parameters); - return invocation; - } - - protected void changeVariables(Object source, final VariableOwner owner, - Map<String, Object> m) { - owner.changeVariables(source, m); - } - - protected ClientConnector getConnector(Root root, String connectorId) { - ClientConnector c = root.getConnectorTracker() - .getConnector(connectorId); - if (c == null - && connectorId.equals(getDragAndDropService().getConnectorId())) { - return getDragAndDropService(); - } - - return c; - } - - private DragAndDropService getDragAndDropService() { - if (dragAndDropService == null) { - dragAndDropService = new DragAndDropService(this); - } - return dragAndDropService; - } - - /** - * Reads the request data from the Request and returns it converted to an - * UTF-8 string. - * - * @param request - * @return - * @throws IOException - */ - protected String getRequestPayload(WrappedRequest request) - throws IOException { - - int requestLength = request.getContentLength(); - if (requestLength == 0) { - return null; - } - - ByteArrayOutputStream bout = requestLength <= 0 ? new ByteArrayOutputStream() - : new ByteArrayOutputStream(requestLength); - - InputStream inputStream = request.getInputStream(); - byte[] buffer = new byte[MAX_BUFFER_SIZE]; - - while (true) { - int read = inputStream.read(buffer); - if (read == -1) { - break; - } - bout.write(buffer, 0, read); - } - String result = new String(bout.toByteArray(), "utf-8"); - - return result; - } - - public class ErrorHandlerErrorEvent implements ErrorEvent, Serializable { - private final Throwable throwable; - - public ErrorHandlerErrorEvent(Throwable throwable) { - this.throwable = throwable; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - } - - /** - * Handles an error (exception) that occurred when processing variable - * changes from the client or a failure of a file upload. - * - * For {@link AbstractField} components, - * {@link AbstractField#handleError(com.vaadin.ui.AbstractComponent.ComponentErrorEvent)} - * is called. In all other cases (or if the field does not handle the - * error), {@link ErrorListener#terminalError(ErrorEvent)} for the - * application error handler is called. - * - * @param application - * @param owner - * component that the error concerns - * @param e - * exception that occurred - * @param m - * map from variable names to values - */ - private void handleChangeVariablesError(Application application, - Component owner, Throwable t, Map<String, Object> m) { - boolean handled = false; - ChangeVariablesErrorEvent errorEvent = new ChangeVariablesErrorEvent( - owner, t, m); - - if (owner instanceof AbstractField) { - try { - handled = ((AbstractField<?>) owner).handleError(errorEvent); - } catch (Exception handlerException) { - /* - * If there is an error in the component error handler we pass - * the that error to the application error handler and continue - * processing the actual error - */ - application.getErrorHandler().terminalError( - new ErrorHandlerErrorEvent(handlerException)); - handled = false; - } - } - - if (!handled) { - application.getErrorHandler().terminalError(errorEvent); - } - - } - - /** - * Unescape encoded burst separator characters in a burst received from the - * client. This protects from separator injection attacks. - * - * @param encodedValue - * to decode - * @return decoded value - */ - protected String unescapeBurst(String encodedValue) { - final StringBuilder result = new StringBuilder(); - final StringCharacterIterator iterator = new StringCharacterIterator( - encodedValue); - char character = iterator.current(); - while (character != CharacterIterator.DONE) { - if (VAR_ESCAPE_CHARACTER == character) { - character = iterator.next(); - switch (character) { - case VAR_ESCAPE_CHARACTER + 0x30: - // escaped escape character - result.append(VAR_ESCAPE_CHARACTER); - break; - case VAR_BURST_SEPARATOR + 0x30: - // +0x30 makes these letters for easier reading - result.append((char) (character - 0x30)); - break; - case CharacterIterator.DONE: - // error - throw new RuntimeException( - "Communication error: Unexpected end of message"); - default: - // other escaped character - probably a client-server - // version mismatch - throw new RuntimeException( - "Invalid escaped character from the client - check that the widgetset and server versions match"); - } - } else { - // not a special character - add it to the result as is - result.append(character); - } - character = iterator.next(); - } - return result.toString(); - } - - /** - * Prints the queued (pending) locale definitions to a {@link PrintWriter} - * in a (UIDL) format that can be sent to the client and used there in - * formatting dates, times etc. - * - * @param outWriter - */ - private void printLocaleDeclarations(PrintWriter outWriter) { - /* - * ----------------------------- Sending Locale sensitive date - * ----------------------------- - */ - - // Send locale informations to client - outWriter.print(", \"locales\":["); - for (; pendingLocalesIndex < locales.size(); pendingLocalesIndex++) { - - final Locale l = generateLocale(locales.get(pendingLocalesIndex)); - // Locale name - outWriter.print("{\"name\":\"" + l.toString() + "\","); - - /* - * Month names (both short and full) - */ - final DateFormatSymbols dfs = new DateFormatSymbols(l); - final String[] short_months = dfs.getShortMonths(); - final String[] months = dfs.getMonths(); - outWriter.print("\"smn\":[\"" - + // ShortMonthNames - short_months[0] + "\",\"" + short_months[1] + "\",\"" - + short_months[2] + "\",\"" + short_months[3] + "\",\"" - + short_months[4] + "\",\"" + short_months[5] + "\",\"" - + short_months[6] + "\",\"" + short_months[7] + "\",\"" - + short_months[8] + "\",\"" + short_months[9] + "\",\"" - + short_months[10] + "\",\"" + short_months[11] + "\"" - + "],"); - outWriter.print("\"mn\":[\"" - + // MonthNames - months[0] + "\",\"" + months[1] + "\",\"" + months[2] - + "\",\"" + months[3] + "\",\"" + months[4] + "\",\"" - + months[5] + "\",\"" + months[6] + "\",\"" + months[7] - + "\",\"" + months[8] + "\",\"" + months[9] + "\",\"" - + months[10] + "\",\"" + months[11] + "\"" + "],"); - - /* - * Weekday names (both short and full) - */ - final String[] short_days = dfs.getShortWeekdays(); - final String[] days = dfs.getWeekdays(); - outWriter.print("\"sdn\":[\"" - + // ShortDayNames - short_days[1] + "\",\"" + short_days[2] + "\",\"" - + short_days[3] + "\",\"" + short_days[4] + "\",\"" - + short_days[5] + "\",\"" + short_days[6] + "\",\"" - + short_days[7] + "\"" + "],"); - outWriter.print("\"dn\":[\"" - + // DayNames - days[1] + "\",\"" + days[2] + "\",\"" + days[3] + "\",\"" - + days[4] + "\",\"" + days[5] + "\",\"" + days[6] + "\",\"" - + days[7] + "\"" + "],"); - - /* - * First day of week (0 = sunday, 1 = monday) - */ - final Calendar cal = new GregorianCalendar(l); - outWriter.print("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ","); - - /* - * Date formatting (MM/DD/YYYY etc.) - */ - - DateFormat dateFormat = DateFormat.getDateTimeInstance( - DateFormat.SHORT, DateFormat.SHORT, l); - if (!(dateFormat instanceof SimpleDateFormat)) { - getLogger().warning( - "Unable to get default date pattern for locale " - + l.toString()); - dateFormat = new SimpleDateFormat(); - } - final String df = ((SimpleDateFormat) dateFormat).toPattern(); - - int timeStart = df.indexOf("H"); - if (timeStart < 0) { - timeStart = df.indexOf("h"); - } - final int ampm_first = df.indexOf("a"); - // E.g. in Korean locale AM/PM is before h:mm - // TODO should take that into consideration on client-side as well, - // now always h:mm a - if (ampm_first > 0 && ampm_first < timeStart) { - timeStart = ampm_first; - } - // Hebrew locale has time before the date - final boolean timeFirst = timeStart == 0; - String dateformat; - if (timeFirst) { - int dateStart = df.indexOf(' '); - if (ampm_first > dateStart) { - dateStart = df.indexOf(' ', ampm_first); - } - dateformat = df.substring(dateStart + 1); - } else { - dateformat = df.substring(0, timeStart - 1); - } - - outWriter.print("\"df\":\"" + dateformat.trim() + "\","); - - /* - * Time formatting (24 or 12 hour clock and AM/PM suffixes) - */ - final String timeformat = df.substring(timeStart, df.length()); - /* - * Doesn't return second or milliseconds. - * - * We use timeformat to determine 12/24-hour clock - */ - final boolean twelve_hour_clock = timeformat.indexOf("a") > -1; - // TODO there are other possibilities as well, like 'h' in french - // (ignore them, too complicated) - final String hour_min_delimiter = timeformat.indexOf(".") > -1 ? "." - : ":"; - // outWriter.print("\"tf\":\"" + timeformat + "\","); - outWriter.print("\"thc\":" + twelve_hour_clock + ","); - outWriter.print("\"hmd\":\"" + hour_min_delimiter + "\""); - if (twelve_hour_clock) { - final String[] ampm = dfs.getAmPmStrings(); - outWriter.print(",\"ampm\":[\"" + ampm[0] + "\",\"" + ampm[1] - + "\"]"); - } - outWriter.print("}"); - if (pendingLocalesIndex < locales.size() - 1) { - outWriter.print(","); - } - } - outWriter.print("]"); // Close locales - } - - /** - * Ends the Application. - * - * The browser is redirected to the Application logout URL set with - * {@link Application#setLogoutURL(String)}, or to the application URL if no - * logout URL is given. - * - * @param request - * the request instance. - * @param response - * the response to write to. - * @param application - * the Application to end. - * @throws IOException - * if the writing failed due to input/output error. - */ - private void endApplication(WrappedRequest request, - WrappedResponse response, Application application) - throws IOException { - - String logoutUrl = application.getLogoutURL(); - if (logoutUrl == null) { - logoutUrl = application.getURL().toString(); - } - // clients JS app is still running, send a special json file to tell - // client that application has quit and where to point browser now - // Set the response type - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - openJsonMessage(outWriter, response); - outWriter.print("\"redirect\":{"); - outWriter.write("\"url\":\"" + logoutUrl + "\"}"); - closeJsonMessage(outWriter); - outWriter.flush(); - outWriter.close(); - out.flush(); - } - - protected void closeJsonMessage(PrintWriter outWriter) { - outWriter.print("}]"); - } - - /** - * Writes the opening of JSON message to be sent to client. - * - * @param outWriter - * @param response - */ - protected void openJsonMessage(PrintWriter outWriter, - WrappedResponse response) { - // Sets the response type - response.setContentType("application/json; charset=UTF-8"); - // some dirt to prevent cross site scripting - outWriter.print("for(;;);[{"); - } - - /** - * Returns dirty components which are in given window. Components in an - * invisible subtrees are omitted. - * - * @param w - * root window for which dirty components is to be fetched - * @return - */ - private ArrayList<ClientConnector> getDirtyVisibleConnectors( - ConnectorTracker connectorTracker) { - ArrayList<ClientConnector> dirtyConnectors = new ArrayList<ClientConnector>(); - for (ClientConnector c : connectorTracker.getDirtyConnectors()) { - if (isVisible(c)) { - dirtyConnectors.add(c); - } - } - - return dirtyConnectors; - } - - /** - * Queues a locale to be sent to the client (browser) for date and time - * entry etc. All locale specific information is derived from server-side - * {@link Locale} instances and sent to the client when needed, eliminating - * the need to use the {@link Locale} class and all the framework behind it - * on the client. - * - * @see Locale#toString() - * - * @param value - */ - public void requireLocale(String value) { - if (locales == null) { - locales = new ArrayList<String>(); - locales.add(application.getLocale().toString()); - pendingLocalesIndex = 0; - } - if (!locales.contains(value)) { - locales.add(value); - } - } - - /** - * Constructs a {@link Locale} instance to be sent to the client based on a - * short locale description string. - * - * @see #requireLocale(String) - * - * @param value - * @return - */ - private Locale generateLocale(String value) { - final String[] temp = value.split("_"); - if (temp.length == 1) { - return new Locale(temp[0]); - } else if (temp.length == 2) { - return new Locale(temp[0], temp[1]); - } else { - return new Locale(temp[0], temp[1], temp[2]); - } - } - - protected class InvalidUIDLSecurityKeyException extends - GeneralSecurityException { - - InvalidUIDLSecurityKeyException(String message) { - super(message); - } - - } - - private final HashMap<Class<? extends ClientConnector>, Integer> typeToKey = new HashMap<Class<? extends ClientConnector>, Integer>(); - private int nextTypeKey = 0; - - private BootstrapHandler bootstrapHandler; - - String getTagForType(Class<? extends ClientConnector> class1) { - Integer id = typeToKey.get(class1); - if (id == null) { - id = nextTypeKey++; - typeToKey.put(class1, id); - getLogger().log(Level.FINE, - "Mapping " + class1.getName() + " to " + id); - } - return id.toString(); - } - - /** - * Helper class for terminal to keep track of data that client is expected - * to know. - * - * TODO make customlayout templates (from theme) to be cached here. - */ - class ClientCache implements Serializable { - - private final Set<Object> res = new HashSet<Object>(); - - /** - * - * @param paintable - * @return true if the given class was added to cache - */ - boolean cache(Object object) { - return res.add(object); - } - - public void clear() { - res.clear(); - } - - } - - public String getStreamVariableTargetUrl(ClientConnector owner, - String name, StreamVariable value) { - /* - * We will use the same APP/* URI space as ApplicationResources but - * prefix url with UPLOAD - * - * eg. APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY] - * - * SECKEY is created on each paint to make URL's unpredictable (to - * prevent CSRF attacks). - * - * NAME and PID from URI forms a key to fetch StreamVariable when - * handling post - */ - String paintableId = owner.getConnectorId(); - int rootId = owner.getRoot().getRootId(); - String key = rootId + "/" + paintableId + "/" + name; - - if (pidToNameToStreamVariable == null) { - pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>(); - } - Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable - .get(paintableId); - if (nameToStreamVariable == null) { - nameToStreamVariable = new HashMap<String, StreamVariable>(); - pidToNameToStreamVariable.put(paintableId, nameToStreamVariable); - } - nameToStreamVariable.put(name, value); - - if (streamVariableToSeckey == null) { - streamVariableToSeckey = new HashMap<StreamVariable, String>(); - } - String seckey = streamVariableToSeckey.get(value); - if (seckey == null) { - seckey = UUID.randomUUID().toString(); - streamVariableToSeckey.put(value, seckey); - } - - return ApplicationConnection.APP_PROTOCOL_PREFIX - + ServletPortletHelper.UPLOAD_URL_PREFIX + key + "/" + seckey; - - } - - public void cleanStreamVariable(ClientConnector owner, String name) { - Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable - .get(owner.getConnectorId()); - nameToStreamVar.remove(name); - if (nameToStreamVar.isEmpty()) { - pidToNameToStreamVariable.remove(owner.getConnectorId()); - } - } - - /** - * Gets the bootstrap handler that should be used for generating the pages - * bootstrapping applications for this communication manager. - * - * @return the bootstrap handler to use - */ - private BootstrapHandler getBootstrapHandler() { - if (bootstrapHandler == null) { - bootstrapHandler = createBootstrapHandler(); - } - - return bootstrapHandler; - } - - protected abstract BootstrapHandler createBootstrapHandler(); - - protected boolean handleApplicationRequest(WrappedRequest request, - WrappedResponse response) throws IOException { - return application.handleRequest(request, response); - } - - public void handleBrowserDetailsRequest(WrappedRequest request, - WrappedResponse response, Application application) - throws IOException { - - // if we do not yet have a currentRoot, it should be initialized - // shortly, and we should send the initial UIDL - boolean sendUIDL = Root.getCurrent() == null; - - try { - CombinedRequest combinedRequest = new CombinedRequest(request); - - Root root = application.getRootForRequest(combinedRequest); - response.setContentType("application/json; charset=UTF-8"); - - // Use the same logic as for determined roots - BootstrapHandler bootstrapHandler = getBootstrapHandler(); - BootstrapContext context = bootstrapHandler.createContext( - combinedRequest, response, application, root.getRootId()); - - String widgetset = context.getWidgetsetName(); - String theme = context.getThemeName(); - String themeUri = bootstrapHandler.getThemeUri(context, theme); - - // TODO These are not required if it was only the init of the root - // that was delayed - JSONObject params = new JSONObject(); - params.put("widgetset", widgetset); - params.put("themeUri", themeUri); - // Root id might have changed based on e.g. window.name - params.put(ApplicationConnection.ROOT_ID_PARAMETER, - root.getRootId()); - if (sendUIDL) { - String initialUIDL = getInitialUIDL(combinedRequest, root); - params.put("uidl", initialUIDL); - } - - // NOTE! GateIn requires, for some weird reason, getOutputStream - // to be used instead of getWriter() (it seems to interpret - // application/json as a binary content type) - final OutputStream out = response.getOutputStream(); - final PrintWriter outWriter = new PrintWriter(new BufferedWriter( - new OutputStreamWriter(out, "UTF-8"))); - - outWriter.write(params.toString()); - // NOTE GateIn requires the buffers to be flushed to work - outWriter.flush(); - out.flush(); - } catch (RootRequiresMoreInformationException e) { - // Requiring more information at this point is not allowed - // TODO handle in a better way - throw new RuntimeException(e); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Generates the initial UIDL message that can e.g. be included in a html - * page to avoid a separate round trip just for getting the UIDL. - * - * @param request - * the request that caused the initialization - * @param root - * the root for which the UIDL should be generated - * @return a string with the initial UIDL message - * @throws PaintException - * if an exception occurs while painting - * @throws JSONException - * if an exception occurs while encoding output - */ - protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException { - // TODO maybe unify writeUidlResponse()? - StringWriter sWriter = new StringWriter(); - PrintWriter pWriter = new PrintWriter(sWriter); - pWriter.print("{"); - if (isXSRFEnabled(root.getApplication())) { - pWriter.print(getSecurityKeyUIDL(request)); - } - writeUidlResponse(request, true, pWriter, root, false); - pWriter.print("}"); - String initialUIDL = sWriter.toString(); - getLogger().log(Level.FINE, "Initial UIDL:" + initialUIDL); - return initialUIDL; - } - - /** - * Serve a connector resource from the classpath if the resource has - * previously been registered by calling - * {@link #registerResource(String, Class)}. Sending arbitrary files from - * the classpath is prevented by only accepting resource names that have - * explicitly been registered. Resources can currently only be registered by - * including a {@link JavaScript} or {@link StyleSheet} annotation on a - * Connector class. - * - * @param request - * @param response - * - * @throws IOException - */ - public void serveConnectorResource(WrappedRequest request, - WrappedResponse response) throws IOException { - - String pathInfo = request.getRequestPathInfo(); - // + 2 to also remove beginning and ending slashes - String resourceName = pathInfo - .substring(ApplicationConnection.CONNECTOR_RESOURCE_PREFIX - .length() + 2); - - final String mimetype = response.getDeploymentConfiguration() - .getMimeType(resourceName); - - // Security check: avoid accidentally serving from the root of the - // classpath instead of relative to the context class - if (resourceName.startsWith("/")) { - getLogger().warning( - "Connector resource request starting with / rejected: " - + resourceName); - response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); - return; - } - - // Check that the resource name has been registered - Class<?> context; - synchronized (connectorResourceContexts) { - context = connectorResourceContexts.get(resourceName); - } - - // Security check: don't serve resource if the name hasn't been - // registered in the map - if (context == null) { - getLogger().warning( - "Connector resource request for unknown resource rejected: " - + resourceName); - response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); - return; - } - - // Resolve file relative to the location of the context class - InputStream in = context.getResourceAsStream(resourceName); - if (in == null) { - getLogger().warning( - resourceName + " defined by " + context.getName() - + " not found. Verify that the file " - + context.getPackage().getName().replace('.', '/') - + '/' + resourceName - + " is available on the classpath."); - response.sendError(HttpServletResponse.SC_NOT_FOUND, resourceName); - return; - } - - // TODO Check and set cache headers - - OutputStream out = null; - try { - if (mimetype != null) { - response.setContentType(mimetype); - } - - out = response.getOutputStream(); - - final byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE]; - - int bytesRead = 0; - while ((bytesRead = in.read(buffer)) > 0) { - out.write(buffer, 0, bytesRead); - } - out.flush(); - } finally { - try { - in.close(); - } catch (Exception e) { - // Do nothing - } - if (out != null) { - try { - out.close(); - } catch (Exception e) { - // Do nothing - } - } - } - } - - /** - * Handles file upload request submitted via Upload component. - * - * @param root - * The root for this request - * - * @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable) - * - * @param request - * @param response - * @throws IOException - * @throws InvalidUIDLSecurityKeyException - */ - public void handleFileUpload(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException, InvalidUIDLSecurityKeyException { - - /* - * URI pattern: APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY] See - * #createReceiverUrl - */ - - String pathInfo = request.getRequestPathInfo(); - // strip away part until the data we are interested starts - int startOfData = pathInfo - .indexOf(ServletPortletHelper.UPLOAD_URL_PREFIX) - + ServletPortletHelper.UPLOAD_URL_PREFIX.length(); - String uppUri = pathInfo.substring(startOfData); - String[] parts = uppUri.split("/", 4); // 0= rootid, 1 = cid, 2= name, 3 - // = sec key - String rootId = parts[0]; - String connectorId = parts[1]; - String variableName = parts[2]; - Root root = application.getRootById(Integer.parseInt(rootId)); - Root.setCurrent(root); - - StreamVariable streamVariable = getStreamVariable(connectorId, - variableName); - String secKey = streamVariableToSeckey.get(streamVariable); - if (secKey.equals(parts[3])) { - - ClientConnector source = getConnector(root, connectorId); - String contentType = request.getContentType(); - if (contentType.contains("boundary")) { - // Multipart requests contain boundary string - doHandleSimpleMultipartFileUpload(request, response, - streamVariable, variableName, source, - contentType.split("boundary=")[1]); - } else { - // if boundary string does not exist, the posted file is from - // XHR2.post(File) - doHandleXhrFilePost(request, response, streamVariable, - variableName, source, request.getContentLength()); - } - } else { - throw new InvalidUIDLSecurityKeyException( - "Security key in upload post did not match!"); - } - - } - - public StreamVariable getStreamVariable(String connectorId, - String variableName) { - Map<String, StreamVariable> map = pidToNameToStreamVariable - .get(connectorId); - if (map == null) { - return null; - } - StreamVariable streamVariable = map.get(variableName); - return streamVariable; - } - - /** - * Stream that extracts content from another stream until the boundary - * string is encountered. - * - * Public only for unit tests, should be considered private for all other - * purposes. - */ - public static class SimpleMultiPartInputStream extends InputStream { - - /** - * Counter of how many characters have been matched to boundary string - * from the stream - */ - int matchedCount = -1; - - /** - * Used as pointer when returning bytes after partly matched boundary - * string. - */ - int curBoundaryIndex = 0; - /** - * The byte found after a "promising start for boundary" - */ - private int bufferedByte = -1; - private boolean atTheEnd = false; - - private final char[] boundary; - - private final InputStream realInputStream; - - public SimpleMultiPartInputStream(InputStream realInputStream, - String boundaryString) { - boundary = (CRLF + DASHDASH + boundaryString).toCharArray(); - this.realInputStream = realInputStream; - } - - @Override - public int read() throws IOException { - if (atTheEnd) { - // End boundary reached, nothing more to read - return -1; - } else if (bufferedByte >= 0) { - /* Purge partially matched boundary if there was such */ - return getBuffered(); - } else if (matchedCount != -1) { - /* - * Special case where last "failed" matching ended with first - * character from boundary string - */ - return matchForBoundary(); - } else { - int fromActualStream = realInputStream.read(); - if (fromActualStream == -1) { - // unexpected end of stream - throw new IOException( - "The multipart stream ended unexpectedly"); - } - if (boundary[0] == fromActualStream) { - /* - * If matches the first character in boundary string, start - * checking if the boundary is fetched. - */ - return matchForBoundary(); - } - return fromActualStream; - } - } - - /** - * Reads the input to expect a boundary string. Expects that the first - * character has already been matched. - * - * @return -1 if the boundary was matched, else returns the first byte - * from boundary - * @throws IOException - */ - private int matchForBoundary() throws IOException { - matchedCount = 0; - /* - * Going to "buffered mode". Read until full boundary match or a - * different character. - */ - while (true) { - matchedCount++; - if (matchedCount == boundary.length) { - /* - * The whole boundary matched so we have reached the end of - * file - */ - atTheEnd = true; - return -1; - } - int fromActualStream = realInputStream.read(); - if (fromActualStream != boundary[matchedCount]) { - /* - * Did not find full boundary, cache the mismatching byte - * and start returning the partially matched boundary. - */ - bufferedByte = fromActualStream; - return getBuffered(); - } - } - } - - /** - * Returns the partly matched boundary string and the byte following - * that. - * - * @return - * @throws IOException - */ - private int getBuffered() throws IOException { - int b; - if (matchedCount == 0) { - // The boundary has been returned, return the buffered byte. - b = bufferedByte; - bufferedByte = -1; - matchedCount = -1; - } else { - b = boundary[curBoundaryIndex++]; - if (curBoundaryIndex == matchedCount) { - // The full boundary has been returned, remaining is the - // char that did not match the boundary. - - curBoundaryIndex = 0; - if (bufferedByte != boundary[0]) { - /* - * next call for getBuffered will return the - * bufferedByte that came after the partial boundary - * match - */ - matchedCount = 0; - } else { - /* - * Special case where buffered byte again matches the - * boundaryString. This could be the start of the real - * end boundary. - */ - matchedCount = 0; - bufferedByte = -1; - } - } - } - if (b == -1) { - throw new IOException("The multipart stream ended unexpectedly"); - } - return b; - } - } - - private static final Logger getLogger() { - return Logger.getLogger(AbstractCommunicationManager.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java b/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java deleted file mode 100644 index 7b51712904..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractDeploymentConfiguration.java +++ /dev/null @@ -1,143 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Constructor; -import java.util.Iterator; -import java.util.Properties; -import java.util.ServiceLoader; - -import com.vaadin.terminal.DeploymentConfiguration; - -public abstract class AbstractDeploymentConfiguration implements - DeploymentConfiguration { - - private final Class<?> systemPropertyBaseClass; - private final Properties applicationProperties = new Properties(); - private AddonContext addonContext; - - public AbstractDeploymentConfiguration(Class<?> systemPropertyBaseClass) { - this.systemPropertyBaseClass = systemPropertyBaseClass; - } - - @Override - public String getApplicationOrSystemProperty(String propertyName, - String defaultValue) { - - String val = null; - - // Try application properties - val = getApplicationProperty(propertyName); - if (val != null) { - return val; - } - - // Try system properties - val = getSystemProperty(propertyName); - if (val != null) { - return val; - } - - return defaultValue; - } - - /** - * Gets an system property value. - * - * @param parameterName - * the Name or the parameter. - * @return String value or null if not found - */ - protected String getSystemProperty(String parameterName) { - String val = null; - - String pkgName; - final Package pkg = systemPropertyBaseClass.getPackage(); - if (pkg != null) { - pkgName = pkg.getName(); - } else { - final String className = systemPropertyBaseClass.getName(); - pkgName = new String(className.toCharArray(), 0, - className.lastIndexOf('.')); - } - val = System.getProperty(pkgName + "." + parameterName); - if (val != null) { - return val; - } - - // Try lowercased system properties - val = System.getProperty(pkgName + "." + parameterName.toLowerCase()); - return val; - } - - @Override - public ClassLoader getClassLoader() { - final String classLoaderName = getApplicationOrSystemProperty( - "ClassLoader", null); - ClassLoader classLoader; - if (classLoaderName == null) { - classLoader = getClass().getClassLoader(); - } else { - try { - final Class<?> classLoaderClass = getClass().getClassLoader() - .loadClass(classLoaderName); - final Constructor<?> c = classLoaderClass - .getConstructor(new Class[] { ClassLoader.class }); - classLoader = (ClassLoader) c - .newInstance(new Object[] { getClass().getClassLoader() }); - } catch (final Exception e) { - throw new RuntimeException( - "Could not find specified class loader: " - + classLoaderName, e); - } - } - return classLoader; - } - - /** - * Gets an application property value. - * - * @param parameterName - * the Name or the parameter. - * @return String value or null if not found - */ - protected String getApplicationProperty(String parameterName) { - - String val = applicationProperties.getProperty(parameterName); - if (val != null) { - return val; - } - - // Try lower case application properties for backward compatibility with - // 3.0.2 and earlier - val = applicationProperties.getProperty(parameterName.toLowerCase()); - - return val; - } - - @Override - public Properties getInitParameters() { - return applicationProperties; - } - - @Override - public Iterator<AddonContextListener> getAddonContextListeners() { - // Called once for init and then no more, so there's no point in caching - // the instance - ServiceLoader<AddonContextListener> contextListenerLoader = ServiceLoader - .load(AddonContextListener.class, getClassLoader()); - return contextListenerLoader.iterator(); - } - - @Override - public void setAddonContext(AddonContext addonContext) { - this.addonContext = addonContext; - } - - @Override - public AddonContext getAddonContext() { - return addonContext; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractStreamingEvent.java b/src/com/vaadin/terminal/gwt/server/AbstractStreamingEvent.java deleted file mode 100644 index d3474e736e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractStreamingEvent.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingEvent; - -/** - * Abstract base class for StreamingEvent implementations. - */ -@SuppressWarnings("serial") -abstract class AbstractStreamingEvent implements StreamingEvent { - private final String type; - private final String filename; - private final long contentLength; - private final long bytesReceived; - - @Override - public final String getFileName() { - return filename; - } - - @Override - public final String getMimeType() { - return type; - } - - protected AbstractStreamingEvent(String filename, String type, long length, - long bytesReceived) { - this.filename = filename; - this.type = type; - contentLength = length; - this.bytesReceived = bytesReceived; - } - - @Override - public final long getContentLength() { - return contentLength; - } - - @Override - public final long getBytesReceived() { - return bytesReceived; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java deleted file mode 100644 index 3a33621d10..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AbstractWebApplicationContext.java +++ /dev/null @@ -1,268 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.PrintWriter; -import java.io.Serializable; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; - -import com.vaadin.Application; -import com.vaadin.service.ApplicationContext; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.gwt.client.ApplicationConnection; - -/** - * Base class for web application contexts (including portlet contexts) that - * handles the common tasks. - */ -public abstract class AbstractWebApplicationContext implements - ApplicationContext, HttpSessionBindingListener, Serializable { - - protected Collection<TransactionListener> listeners = Collections - .synchronizedList(new LinkedList<TransactionListener>()); - - protected final HashSet<Application> applications = new HashSet<Application>(); - - protected WebBrowser browser = new WebBrowser(); - - protected HashMap<Application, AbstractCommunicationManager> applicationToAjaxAppMgrMap = new HashMap<Application, AbstractCommunicationManager>(); - - private long totalSessionTime = 0; - - private long lastRequestTime = -1; - - @Override - public void addTransactionListener(TransactionListener listener) { - if (listener != null) { - listeners.add(listener); - } - } - - @Override - public void removeTransactionListener(TransactionListener listener) { - listeners.remove(listener); - } - - /** - * Sends a notification that a transaction is starting. - * - * @param application - * The application associated with the transaction. - * @param request - * the HTTP or portlet request that triggered the transaction. - */ - protected void startTransaction(Application application, Object request) { - ArrayList<TransactionListener> currentListeners; - synchronized (listeners) { - currentListeners = new ArrayList<TransactionListener>(listeners); - } - for (TransactionListener listener : currentListeners) { - listener.transactionStart(application, request); - } - } - - /** - * Sends a notification that a transaction has ended. - * - * @param application - * The application associated with the transaction. - * @param request - * the HTTP or portlet request that triggered the transaction. - */ - protected void endTransaction(Application application, Object request) { - LinkedList<Exception> exceptions = null; - - ArrayList<TransactionListener> currentListeners; - synchronized (listeners) { - currentListeners = new ArrayList<TransactionListener>(listeners); - } - - for (TransactionListener listener : currentListeners) { - try { - listener.transactionEnd(application, request); - } catch (final RuntimeException t) { - if (exceptions == null) { - exceptions = new LinkedList<Exception>(); - } - exceptions.add(t); - } - } - - // If any runtime exceptions occurred, throw a combined exception - if (exceptions != null) { - final StringBuffer msg = new StringBuffer(); - for (Exception e : exceptions) { - if (msg.length() == 0) { - msg.append("\n\n--------------------------\n\n"); - } - msg.append(e.getMessage() + "\n"); - final StringWriter trace = new StringWriter(); - e.printStackTrace(new PrintWriter(trace, true)); - msg.append(trace.toString()); - } - throw new RuntimeException(msg.toString()); - } - } - - /** - * @see javax.servlet.http.HttpSessionBindingListener#valueBound(HttpSessionBindingEvent) - */ - @Override - public void valueBound(HttpSessionBindingEvent arg0) { - // We are not interested in bindings - } - - /** - * @see javax.servlet.http.HttpSessionBindingListener#valueUnbound(HttpSessionBindingEvent) - */ - @Override - public void valueUnbound(HttpSessionBindingEvent event) { - // If we are going to be unbound from the session, the session must be - // closing - try { - while (!applications.isEmpty()) { - final Application app = applications.iterator().next(); - app.close(); - removeApplication(app); - } - } catch (Exception e) { - // This should never happen but is possible with rare - // configurations (e.g. robustness tests). If you have one - // thread doing HTTP socket write and another thread trying to - // remove same application here. Possible if you got e.g. session - // lifetime 1 min but socket write may take longer than 1 min. - // FIXME: Handle exception - getLogger().log(Level.SEVERE, - "Could not remove application, leaking memory.", e); - } - } - - /** - * Get the web browser associated with this application context. - * - * Because application context is related to the http session and server - * maintains one session per browser-instance, each context has exactly one - * web browser associated with it. - * - * @return - */ - public WebBrowser getBrowser() { - return browser; - } - - @Override - public Collection<Application> getApplications() { - return Collections.unmodifiableCollection(applications); - } - - protected void removeApplication(Application application) { - applications.remove(application); - applicationToAjaxAppMgrMap.remove(application); - } - - @Override - public String generateApplicationResourceURL(ApplicationResource resource, - String mapKey) { - - final String filename = resource.getFilename(); - if (filename == null) { - return ApplicationConnection.APP_PROTOCOL_PREFIX - + ApplicationConnection.APP_REQUEST_PATH + mapKey + "/"; - } else { - // #7738 At least Tomcat and JBoss refuses requests containing - // encoded slashes or backslashes in URLs. Application resource URLs - // should really be passed in another way than as part of the path - // in the future. - String encodedFileName = urlEncode(filename).replace("%2F", "/") - .replace("%5C", "\\"); - return ApplicationConnection.APP_PROTOCOL_PREFIX - + ApplicationConnection.APP_REQUEST_PATH + mapKey + "/" - + encodedFileName; - } - - } - - static String urlEncode(String filename) { - try { - return URLEncoder.encode(filename, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException( - "UTF-8 charset not available (\"this should never happen\")", - e); - } - } - - @Override - public boolean isApplicationResourceURL(URL context, String relativeUri) { - // If the relative uri is null, we are ready - if (relativeUri == null) { - return false; - } - - // Resolves the prefix - String prefix = relativeUri; - final int index = relativeUri.indexOf('/'); - if (index >= 0) { - prefix = relativeUri.substring(0, index); - } - - // Handles the resource requests - return (prefix.equals("APP")); - } - - @Override - public String getURLKey(URL context, String relativeUri) { - final int index = relativeUri.indexOf('/'); - final int next = relativeUri.indexOf('/', index + 1); - if (next < 0) { - return null; - } - return relativeUri.substring(index + 1, next); - } - - /** - * @return The total time spent servicing requests in this session. - */ - public long getTotalSessionTime() { - return totalSessionTime; - } - - /** - * Sets the time spent servicing the last request in the session and updates - * the total time spent servicing requests in this session. - * - * @param time - * the time spent in the last request. - */ - public void setLastRequestTime(long time) { - lastRequestTime = time; - totalSessionTime += time; - } - - /** - * @return the time spent servicing the last request in this session. - */ - public long getLastRequestTime() { - return lastRequestTime; - } - - private Logger getLogger() { - return Logger.getLogger(AbstractWebApplicationContext.class.getName()); - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/AddonContext.java b/src/com/vaadin/terminal/gwt/server/AddonContext.java deleted file mode 100644 index 41e9046e22..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AddonContext.java +++ /dev/null @@ -1,80 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import com.vaadin.Application; -import com.vaadin.event.EventRouter; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.tools.ReflectTools; - -public class AddonContext { - private static final Method APPLICATION_STARTED_METHOD = ReflectTools - .findMethod(ApplicationStartedListener.class, "applicationStarted", - ApplicationStartedEvent.class); - - private final DeploymentConfiguration deploymentConfiguration; - - private final EventRouter eventRouter = new EventRouter(); - - private List<BootstrapListener> bootstrapListeners = new ArrayList<BootstrapListener>(); - - private List<AddonContextListener> initedListeners = new ArrayList<AddonContextListener>(); - - public AddonContext(DeploymentConfiguration deploymentConfiguration) { - this.deploymentConfiguration = deploymentConfiguration; - deploymentConfiguration.setAddonContext(this); - } - - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - public void init() { - AddonContextEvent event = new AddonContextEvent(this); - Iterator<AddonContextListener> listeners = deploymentConfiguration - .getAddonContextListeners(); - while (listeners.hasNext()) { - AddonContextListener listener = listeners.next(); - listener.contextCreated(event); - initedListeners.add(listener); - } - } - - public void destroy() { - AddonContextEvent event = new AddonContextEvent(this); - for (AddonContextListener listener : initedListeners) { - listener.contextDestoryed(event); - } - } - - public void addBootstrapListener(BootstrapListener listener) { - bootstrapListeners.add(listener); - } - - public void applicationStarted(Application application) { - eventRouter.fireEvent(new ApplicationStartedEvent(this, application)); - for (BootstrapListener l : bootstrapListeners) { - application.addBootstrapListener(l); - } - } - - public void addApplicationStartedListener( - ApplicationStartedListener applicationStartListener) { - eventRouter.addListener(ApplicationStartedEvent.class, - applicationStartListener, APPLICATION_STARTED_METHOD); - } - - public void removeApplicationStartedListener( - ApplicationStartedListener applicationStartListener) { - eventRouter.removeListener(ApplicationStartedEvent.class, - applicationStartListener, APPLICATION_STARTED_METHOD); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/AddonContextEvent.java b/src/com/vaadin/terminal/gwt/server/AddonContextEvent.java deleted file mode 100644 index 33f681499f..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AddonContextEvent.java +++ /dev/null @@ -1,19 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventObject; - -public class AddonContextEvent extends EventObject { - - public AddonContextEvent(AddonContext source) { - super(source); - } - - public AddonContext getAddonContext() { - return (AddonContext) getSource(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/AddonContextListener.java b/src/com/vaadin/terminal/gwt/server/AddonContextListener.java deleted file mode 100644 index 93e7df4ede..0000000000 --- a/src/com/vaadin/terminal/gwt/server/AddonContextListener.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventListener; - -public interface AddonContextListener extends EventListener { - public void contextCreated(AddonContextEvent event); - - public void contextDestoryed(AddonContextEvent event); -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java b/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java deleted file mode 100644 index 788c48267e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationPortlet2.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.portlet.PortletConfig; -import javax.portlet.PortletException; - -import com.vaadin.Application; -import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException; - -/** - * TODO Write documentation, fix JavaDoc tags. - * - * @author peholmst - */ -public class ApplicationPortlet2 extends AbstractApplicationPortlet { - - private Class<? extends Application> applicationClass; - - @Override - public void init(PortletConfig config) throws PortletException { - super.init(config); - try { - applicationClass = ServletPortletHelper - .getApplicationClass(getDeploymentConfiguration()); - } catch (ApplicationClassException e) { - throw new PortletException(e); - } - } - - @Override - protected Class<? extends Application> getApplicationClass() { - return applicationClass; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java b/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java deleted file mode 100644 index 42726c933e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationResourceHandler.java +++ /dev/null @@ -1,55 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.http.HttpServletResponse; - -import com.vaadin.Application; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; - -public class ApplicationResourceHandler implements RequestHandler { - private static final Pattern APP_RESOURCE_PATTERN = Pattern - .compile("^/?APP/(\\d+)/.*"); - - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - // Check for application resources - String requestPath = request.getRequestPathInfo(); - if (requestPath == null) { - return false; - } - Matcher resourceMatcher = APP_RESOURCE_PATTERN.matcher(requestPath); - - if (resourceMatcher.matches()) { - ApplicationResource resource = application - .getResource(resourceMatcher.group(1)); - if (resource != null) { - DownloadStream stream = resource.getStream(); - if (stream != null) { - stream.setCacheTime(resource.getCacheTime()); - stream.writeTo(response); - return true; - } - } - // We get here if the url looks like an application resource but no - // resource can be served - response.sendError(HttpServletResponse.SC_NOT_FOUND, - request.getRequestPathInfo() + " can not be found"); - return true; - } - - return false; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java deleted file mode 100644 index 1af49e0da0..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationServlet.java +++ /dev/null @@ -1,78 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; - -import com.vaadin.Application; -import com.vaadin.terminal.gwt.server.ServletPortletHelper.ApplicationClassException; - -/** - * This servlet connects a Vaadin Application to Web. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ - -@SuppressWarnings("serial") -public class ApplicationServlet extends AbstractApplicationServlet { - - // Private fields - private Class<? extends Application> applicationClass; - - /** - * Called by the servlet container to indicate to a servlet that the servlet - * is being placed into service. - * - * @param servletConfig - * the object containing the servlet's configuration and - * initialization parameters - * @throws javax.servlet.ServletException - * if an exception has occurred that interferes with the - * servlet's normal operation. - */ - @Override - public void init(javax.servlet.ServletConfig servletConfig) - throws javax.servlet.ServletException { - super.init(servletConfig); - - // Loads the application class using the classloader defined in the - // deployment configuration - - try { - applicationClass = ServletPortletHelper - .getApplicationClass(getDeploymentConfiguration()); - } catch (ApplicationClassException e) { - throw new ServletException(e); - } - } - - @Override - protected Application getNewApplication(HttpServletRequest request) - throws ServletException { - - // Creates a new application instance - try { - final Application application = getApplicationClass().newInstance(); - - return application; - } catch (final IllegalAccessException e) { - throw new ServletException("getNewApplication failed", e); - } catch (final InstantiationException e) { - throw new ServletException("getNewApplication failed", e); - } catch (ClassNotFoundException e) { - throw new ServletException("getNewApplication failed", e); - } - } - - @Override - protected Class<? extends Application> getApplicationClass() - throws ClassNotFoundException { - return applicationClass; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationStartedEvent.java b/src/com/vaadin/terminal/gwt/server/ApplicationStartedEvent.java deleted file mode 100644 index 339b88222e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationStartedEvent.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventObject; - -import com.vaadin.Application; - -public class ApplicationStartedEvent extends EventObject { - private final Application application; - - public ApplicationStartedEvent(AddonContext context, - Application application) { - super(context); - this.application = application; - } - - public AddonContext getContext() { - return (AddonContext) getSource(); - } - - public Application getApplication() { - return application; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/ApplicationStartedListener.java b/src/com/vaadin/terminal/gwt/server/ApplicationStartedListener.java deleted file mode 100644 index 87884a0fda..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ApplicationStartedListener.java +++ /dev/null @@ -1,11 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventListener; - -public interface ApplicationStartedListener extends EventListener { - public void applicationStarted(ApplicationStartedEvent event); -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapDom.java b/src/com/vaadin/terminal/gwt/server/BootstrapDom.java deleted file mode 100644 index 4731a5b79f..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapDom.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -public class BootstrapDom { - -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java b/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java deleted file mode 100644 index bcf098b5aa..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapFragmentResponse.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.List; - -import org.jsoup.nodes.Node; - -import com.vaadin.Application; -import com.vaadin.terminal.WrappedRequest; - -public class BootstrapFragmentResponse extends BootstrapResponse { - private final List<Node> fragmentNodes; - - public BootstrapFragmentResponse(BootstrapHandler handler, - WrappedRequest request, List<Node> fragmentNodes, - Application application, Integer rootId) { - super(handler, request, application, rootId); - this.fragmentNodes = fragmentNodes; - } - - public List<Node> getFragmentNodes() { - return fragmentNodes; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java b/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java deleted file mode 100644 index e89737337b..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapHandler.java +++ /dev/null @@ -1,570 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import javax.servlet.http.HttpServletResponse; - -import org.jsoup.nodes.DataNode; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.DocumentType; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; -import org.jsoup.parser.Tag; - -import com.vaadin.Application; -import com.vaadin.RootRequiresMoreInformationException; -import com.vaadin.Version; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.ui.Root; - -public abstract class BootstrapHandler implements RequestHandler { - - protected class BootstrapContext implements Serializable { - - private final WrappedResponse response; - private final BootstrapFragmentResponse bootstrapResponse; - - private String widgetsetName; - private String themeName; - private String appId; - - public BootstrapContext(WrappedResponse response, - BootstrapFragmentResponse bootstrapResponse) { - this.response = response; - this.bootstrapResponse = bootstrapResponse; - } - - public WrappedResponse getResponse() { - return response; - } - - public WrappedRequest getRequest() { - return bootstrapResponse.getRequest(); - } - - public Application getApplication() { - return bootstrapResponse.getApplication(); - } - - public Integer getRootId() { - return bootstrapResponse.getRootId(); - } - - public Root getRoot() { - return bootstrapResponse.getRoot(); - } - - public String getWidgetsetName() { - if (widgetsetName == null) { - Root root = getRoot(); - if (root != null) { - widgetsetName = getWidgetsetForRoot(this); - } - } - return widgetsetName; - } - - public String getThemeName() { - if (themeName == null) { - Root root = getRoot(); - if (root != null) { - themeName = findAndEscapeThemeName(this); - } - } - return themeName; - } - - public String getAppId() { - if (appId == null) { - appId = getApplicationId(this); - } - return appId; - } - - public BootstrapFragmentResponse getBootstrapResponse() { - return bootstrapResponse; - } - - } - - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - - // TODO Should all urls be handled here? - Integer rootId = null; - try { - Root root = application.getRootForRequest(request); - if (root == null) { - writeError(response, new Throwable("No Root found")); - return true; - } - - rootId = Integer.valueOf(root.getRootId()); - } catch (RootRequiresMoreInformationException e) { - // Just keep going without rootId - } - - try { - BootstrapContext context = createContext(request, response, - application, rootId); - setupMainDiv(context); - - BootstrapFragmentResponse fragmentResponse = context - .getBootstrapResponse(); - application.modifyBootstrapResponse(fragmentResponse); - - String html = getBootstrapHtml(context); - - writeBootstrapPage(response, html); - } catch (JSONException e) { - writeError(response, e); - } - - return true; - } - - private String getBootstrapHtml(BootstrapContext context) { - WrappedRequest request = context.getRequest(); - WrappedResponse response = context.getResponse(); - DeploymentConfiguration deploymentConfiguration = request - .getDeploymentConfiguration(); - - BootstrapFragmentResponse fragmentResponse = context - .getBootstrapResponse(); - - if (deploymentConfiguration.isStandalone(request)) { - Map<String, Object> headers = new LinkedHashMap<String, Object>(); - Document document = Document.createShell(""); - BootstrapPageResponse pageResponse = new BootstrapPageResponse( - this, request, document, headers, context.getApplication(), - context.getRootId()); - List<Node> fragmentNodes = fragmentResponse.getFragmentNodes(); - Element body = document.body(); - for (Node node : fragmentNodes) { - body.appendChild(node); - } - - setupStandaloneDocument(context, pageResponse); - context.getApplication().modifyBootstrapResponse(pageResponse); - - sendBootstrapHeaders(response, headers); - - return document.outerHtml(); - } else { - StringBuilder sb = new StringBuilder(); - for (Node node : fragmentResponse.getFragmentNodes()) { - if (sb.length() != 0) { - sb.append('\n'); - } - sb.append(node.outerHtml()); - } - - return sb.toString(); - } - } - - private void sendBootstrapHeaders(WrappedResponse response, - Map<String, Object> headers) { - Set<Entry<String, Object>> entrySet = headers.entrySet(); - for (Entry<String, Object> header : entrySet) { - Object value = header.getValue(); - if (value instanceof String) { - response.setHeader(header.getKey(), (String) value); - } else if (value instanceof Long) { - response.setDateHeader(header.getKey(), - ((Long) value).longValue()); - } else { - throw new RuntimeException("Unsupported header value: " + value); - } - } - } - - private void writeBootstrapPage(WrappedResponse response, String html) - throws IOException { - response.setContentType("text/html"); - BufferedWriter writer = new BufferedWriter(new OutputStreamWriter( - response.getOutputStream(), "UTF-8")); - writer.append(html); - writer.close(); - } - - private void setupStandaloneDocument(BootstrapContext context, - BootstrapPageResponse response) { - response.setHeader("Cache-Control", "no-cache"); - response.setHeader("Pragma", "no-cache"); - response.setDateHeader("Expires", 0); - - Document document = response.getDocument(); - - DocumentType doctype = new DocumentType("html", - "-//W3C//DTD XHTML 1.0 Transitional//EN", - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", - document.baseUri()); - document.child(0).before(doctype); - document.body().parent().attr("xmlns", "http://www.w3.org/1999/xhtml"); - - Element head = document.head(); - head.appendElement("meta").attr("http-equiv", "Content-Type") - .attr("content", "text/html; charset=utf-8"); - - // Chrome frame in all versions of IE (only if Chrome frame is - // installed) - head.appendElement("meta").attr("http-equiv", "X-UA-Compatible") - .attr("content", "chrome=1"); - - Root root = context.getRoot(); - String title = ((root == null || root.getCaption() == null) ? "" : root - .getCaption()); - head.appendElement("title").appendText(title); - - head.appendElement("style").attr("type", "text/css") - .appendText("html, body {height:100%;margin:0;}"); - - // Add favicon links - String themeName = context.getThemeName(); - if (themeName != null) { - String themeUri = getThemeUri(context, themeName); - head.appendElement("link").attr("rel", "shortcut icon") - .attr("type", "image/vnd.microsoft.icon") - .attr("href", themeUri + "/favicon.ico"); - head.appendElement("link").attr("rel", "icon") - .attr("type", "image/vnd.microsoft.icon") - .attr("href", themeUri + "/favicon.ico"); - } - - Element body = document.body(); - body.attr("scroll", "auto"); - body.addClass(ApplicationConnection.GENERATED_BODY_CLASSNAME); - } - - public BootstrapContext createContext(WrappedRequest request, - WrappedResponse response, Application application, Integer rootId) { - BootstrapContext context = new BootstrapContext(response, - new BootstrapFragmentResponse(this, request, - new ArrayList<Node>(), application, rootId)); - return context; - } - - protected String getMainDivStyle(BootstrapContext context) { - return null; - } - - /** - * Creates and returns a unique ID for the DIV where the application is to - * be rendered. - * - * @param context - * - * @return the id to use in the DOM - */ - protected abstract String getApplicationId(BootstrapContext context); - - public String getWidgetsetForRoot(BootstrapContext context) { - Root root = context.getRoot(); - WrappedRequest request = context.getRequest(); - - String widgetset = root.getApplication().getWidgetsetForRoot(root); - if (widgetset == null) { - widgetset = request.getDeploymentConfiguration() - .getConfiguredWidgetset(request); - } - - widgetset = AbstractApplicationServlet.stripSpecialChars(widgetset); - return widgetset; - } - - /** - * Method to write the div element into which that actual Vaadin application - * is rendered. - * <p> - * Override this method if you want to add some custom html around around - * the div element into which the actual Vaadin application will be - * rendered. - * - * @param context - * - * @throws IOException - * @throws JSONException - */ - private void setupMainDiv(BootstrapContext context) throws IOException, - JSONException { - String style = getMainDivStyle(context); - - /*- Add classnames; - * .v-app - * .v-app-loading - * .v-app-<simpleName for app class> - *- Additionally added from javascript: - * .v-theme-<themeName, remove non-alphanum> - */ - - String appClass = "v-app-" - + context.getApplication().getClass().getSimpleName(); - - String classNames = "v-app " + appClass; - List<Node> fragmentNodes = context.getBootstrapResponse() - .getFragmentNodes(); - - Element mainDiv = new Element(Tag.valueOf("div"), ""); - mainDiv.attr("id", context.getAppId()); - mainDiv.addClass(classNames); - if (style != null && style.length() != 0) { - mainDiv.attr("style", style); - } - mainDiv.appendElement("div").addClass("v-app-loading"); - mainDiv.appendElement("noscript") - .append("You have to enable javascript in your browser to use an application built with Vaadin."); - fragmentNodes.add(mainDiv); - - WrappedRequest request = context.getRequest(); - - DeploymentConfiguration deploymentConfiguration = request - .getDeploymentConfiguration(); - String staticFileLocation = deploymentConfiguration - .getStaticFileLocation(request); - - fragmentNodes - .add(new Element(Tag.valueOf("iframe"), "") - .attr("tabIndex", "-1") - .attr("id", "__gwt_historyFrame") - .attr("style", - "position:absolute;width:0;height:0;border:0;overflow:hidden") - .attr("src", "javascript:false")); - - String bootstrapLocation = staticFileLocation - + "/VAADIN/vaadinBootstrap.js"; - fragmentNodes.add(new Element(Tag.valueOf("script"), "").attr("type", - "text/javascript").attr("src", bootstrapLocation)); - Element mainScriptTag = new Element(Tag.valueOf("script"), "").attr( - "type", "text/javascript"); - - StringBuilder builder = new StringBuilder(); - builder.append("//<![CDATA[\n"); - builder.append("if (!window.vaadin) alert(" - + JSONObject.quote("Failed to load the bootstrap javascript: " - + bootstrapLocation) + ");\n"); - - appendMainScriptTagContents(context, builder); - - builder.append("//]]>"); - mainScriptTag.appendChild(new DataNode(builder.toString(), - mainScriptTag.baseUri())); - fragmentNodes.add(mainScriptTag); - - } - - protected void appendMainScriptTagContents(BootstrapContext context, - StringBuilder builder) throws JSONException, IOException { - JSONObject defaults = getDefaultParameters(context); - JSONObject appConfig = getApplicationParameters(context); - - boolean isDebug = !context.getApplication().isProductionMode(); - - builder.append("vaadin.setDefaults("); - appendJsonObject(builder, defaults, isDebug); - builder.append(");\n"); - - builder.append("vaadin.initApplication(\""); - builder.append(context.getAppId()); - builder.append("\","); - appendJsonObject(builder, appConfig, isDebug); - builder.append(");\n"); - } - - private static void appendJsonObject(StringBuilder builder, - JSONObject jsonObject, boolean isDebug) throws JSONException { - if (isDebug) { - builder.append(jsonObject.toString(4)); - } else { - builder.append(jsonObject.toString()); - } - } - - protected JSONObject getApplicationParameters(BootstrapContext context) - throws JSONException, PaintException { - Application application = context.getApplication(); - Integer rootId = context.getRootId(); - - JSONObject appConfig = new JSONObject(); - - if (rootId != null) { - appConfig.put(ApplicationConnection.ROOT_ID_PARAMETER, rootId); - } - - if (context.getThemeName() != null) { - appConfig.put("themeUri", - getThemeUri(context, context.getThemeName())); - } - - JSONObject versionInfo = new JSONObject(); - versionInfo.put("vaadinVersion", Version.getFullVersion()); - versionInfo.put("applicationVersion", application.getVersion()); - appConfig.put("versionInfo", versionInfo); - - appConfig.put("widgetset", context.getWidgetsetName()); - - if (rootId == null || application.isRootInitPending(rootId.intValue())) { - appConfig.put("initialPath", context.getRequest() - .getRequestPathInfo()); - - Map<String, String[]> parameterMap = context.getRequest() - .getParameterMap(); - appConfig.put("initialParams", parameterMap); - } else { - // write the initial UIDL into the config - appConfig.put("uidl", - getInitialUIDL(context.getRequest(), context.getRoot())); - } - - return appConfig; - } - - protected JSONObject getDefaultParameters(BootstrapContext context) - throws JSONException { - JSONObject defaults = new JSONObject(); - - WrappedRequest request = context.getRequest(); - Application application = context.getApplication(); - - // Get system messages - Application.SystemMessages systemMessages = AbstractApplicationServlet - .getSystemMessages(application.getClass()); - if (systemMessages != null) { - // Write the CommunicationError -message to client - JSONObject comErrMsg = new JSONObject(); - comErrMsg.put("caption", - systemMessages.getCommunicationErrorCaption()); - comErrMsg.put("message", - systemMessages.getCommunicationErrorMessage()); - comErrMsg.put("url", systemMessages.getCommunicationErrorURL()); - - defaults.put("comErrMsg", comErrMsg); - - JSONObject authErrMsg = new JSONObject(); - authErrMsg.put("caption", - systemMessages.getAuthenticationErrorCaption()); - authErrMsg.put("message", - systemMessages.getAuthenticationErrorMessage()); - authErrMsg.put("url", systemMessages.getAuthenticationErrorURL()); - - defaults.put("authErrMsg", authErrMsg); - } - - DeploymentConfiguration deploymentConfiguration = request - .getDeploymentConfiguration(); - String staticFileLocation = deploymentConfiguration - .getStaticFileLocation(request); - String widgetsetBase = staticFileLocation + "/" - + AbstractApplicationServlet.WIDGETSET_DIRECTORY_PATH; - defaults.put("widgetsetBase", widgetsetBase); - - if (!application.isProductionMode()) { - defaults.put("debug", true); - } - - if (deploymentConfiguration.isStandalone(request)) { - defaults.put("standalone", true); - } - - defaults.put("appUri", getAppUri(context)); - - return defaults; - } - - protected abstract String getAppUri(BootstrapContext context); - - /** - * Get the URI for the application theme. - * - * A portal-wide default theme is fetched from the portal shared resource - * directory (if any), other themes from the portlet. - * - * @param context - * @param themeName - * - * @return - */ - public String getThemeUri(BootstrapContext context, String themeName) { - WrappedRequest request = context.getRequest(); - final String staticFilePath = request.getDeploymentConfiguration() - .getStaticFileLocation(request); - return staticFilePath + "/" - + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName; - } - - /** - * Override if required - * - * @param context - * @return - */ - public String getThemeName(BootstrapContext context) { - return context.getApplication().getThemeForRoot(context.getRoot()); - } - - /** - * Don not override. - * - * @param context - * @return - */ - public String findAndEscapeThemeName(BootstrapContext context) { - String themeName = getThemeName(context); - if (themeName == null) { - WrappedRequest request = context.getRequest(); - themeName = request.getDeploymentConfiguration() - .getConfiguredTheme(request); - } - - // XSS preventation, theme names shouldn't contain special chars anyway. - // The servlet denies them via url parameter. - themeName = AbstractApplicationServlet.stripSpecialChars(themeName); - - return themeName; - } - - protected void writeError(WrappedResponse response, Throwable e) - throws IOException { - response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - e.getLocalizedMessage()); - } - - /** - * Gets the initial UIDL message to send to the client. - * - * @param request - * the originating request - * @param root - * the root for which the UIDL should be generated - * @return a string with the initial UIDL message - * @throws PaintException - * if an exception occurs while painting the components - * @throws JSONException - * if an exception occurs while formatting the output - */ - protected abstract String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException; - -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapListener.java b/src/com/vaadin/terminal/gwt/server/BootstrapListener.java deleted file mode 100644 index d80e626cc1..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapListener.java +++ /dev/null @@ -1,13 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventListener; - -public interface BootstrapListener extends EventListener { - public void modifyBootstrapFragment(BootstrapFragmentResponse response); - - public void modifyBootstrapPage(BootstrapPageResponse response); -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java b/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java deleted file mode 100644 index 802238ac62..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapPageResponse.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.Map; - -import org.jsoup.nodes.Document; - -import com.vaadin.Application; -import com.vaadin.terminal.WrappedRequest; - -public class BootstrapPageResponse extends BootstrapResponse { - - private final Map<String, Object> headers; - private final Document document; - - public BootstrapPageResponse(BootstrapHandler handler, - WrappedRequest request, Document document, - Map<String, Object> headers, Application application, Integer rootId) { - super(handler, request, application, rootId); - this.headers = headers; - this.document = document; - } - - public void setHeader(String name, String value) { - headers.put(name, value); - } - - public void setDateHeader(String name, long timestamp) { - headers.put(name, Long.valueOf(timestamp)); - } - - public Document getDocument() { - return document; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java b/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java deleted file mode 100644 index 88bd58593d..0000000000 --- a/src/com/vaadin/terminal/gwt/server/BootstrapResponse.java +++ /dev/null @@ -1,45 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.EventObject; - -import com.vaadin.Application; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.ui.Root; - -public abstract class BootstrapResponse extends EventObject { - private final WrappedRequest request; - private final Application application; - private final Integer rootId; - - public BootstrapResponse(BootstrapHandler handler, WrappedRequest request, - Application application, Integer rootId) { - super(handler); - this.request = request; - this.application = application; - this.rootId = rootId; - } - - public BootstrapHandler getBootstrapHandler() { - return (BootstrapHandler) getSource(); - } - - public WrappedRequest getRequest() { - return request; - } - - public Application getApplication() { - return application; - } - - public Integer getRootId() { - return rootId; - } - - public Root getRoot() { - return Root.getCurrent(); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ChangeVariablesErrorEvent.java b/src/com/vaadin/terminal/gwt/server/ChangeVariablesErrorEvent.java deleted file mode 100644 index 8f0c80332f..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ChangeVariablesErrorEvent.java +++ /dev/null @@ -1,39 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.util.Map; - -import com.vaadin.ui.AbstractComponent.ComponentErrorEvent; -import com.vaadin.ui.Component; - -@SuppressWarnings("serial") -public class ChangeVariablesErrorEvent implements ComponentErrorEvent { - - private Throwable throwable; - private Component component; - - private Map<String, Object> variableChanges; - - public ChangeVariablesErrorEvent(Component component, Throwable throwable, - Map<String, Object> variableChanges) { - this.component = component; - this.throwable = throwable; - this.variableChanges = variableChanges; - } - - @Override - public Throwable getThrowable() { - return throwable; - } - - public Component getComponent() { - return component; - } - - public Map<String, Object> getVariableChanges() { - return variableChanges; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/ClientConnector.java b/src/com/vaadin/terminal/gwt/server/ClientConnector.java deleted file mode 100644 index 4f74cfe4bb..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ClientConnector.java +++ /dev/null @@ -1,149 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.util.Collection; -import java.util.List; - -import com.vaadin.shared.Connector; -import com.vaadin.shared.communication.SharedState; -import com.vaadin.terminal.AbstractClientConnector; -import com.vaadin.terminal.Extension; -import com.vaadin.ui.Component; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.Root; - -/** - * Interface implemented by all connectors that are capable of communicating - * with the client side - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - * - */ -public interface ClientConnector extends Connector, RpcTarget { - /** - * Returns the list of pending server to client RPC calls and clears the - * list. - * - * @return an unmodifiable ordered list of pending server to client method - * calls (not null) - */ - public List<ClientMethodInvocation> retrievePendingRpcCalls(); - - /** - * Checks if the communicator is enabled. An enabled communicator is allowed - * to receive messages from its counter-part. - * - * @return true if the connector can receive messages, false otherwise - */ - public boolean isConnectorEnabled(); - - /** - * Returns the type of the shared state for this connector - * - * @return The type of the state. Must never return null. - */ - public Class<? extends SharedState> getStateType(); - - @Override - public ClientConnector getParent(); - - /** - * Requests that the connector should be repainted as soon as possible. - */ - public void requestRepaint(); - - /** - * Causes a repaint of this connector, and all connectors below it. - * - * This should only be used in special cases, e.g when the state of a - * descendant depends on the state of an ancestor. - */ - public void requestRepaintAll(); - - /** - * Sets the parent connector of the connector. - * - * <p> - * This method automatically calls {@link #attach()} if the connector - * becomes attached to the application, regardless of whether it was - * attached previously. Conversely, if the parent is {@code null} and the - * connector is attached to the application, {@link #detach()} is called for - * the connector. - * </p> - * <p> - * This method is rarely called directly. One of the - * {@link ComponentContainer#addComponent(Component)} or - * {@link AbstractClientConnector#addExtension(Extension)} methods are - * normally used for adding connectors to a parent and they will call this - * method implicitly. - * </p> - * - * <p> - * It is not possible to change the parent without first setting the parent - * to {@code null}. - * </p> - * - * @param parent - * the parent connector - * @throws IllegalStateException - * if a parent is given even though the connector already has a - * parent - */ - public void setParent(ClientConnector parent); - - /** - * Notifies the connector that it is connected to an application. - * - * <p> - * The caller of this method is {@link #setParent(ClientConnector)} if the - * parent is itself already attached to the application. If not, the parent - * will call the {@link #attach()} for all its children when it is attached - * to the application. This method is always called before the connector's - * data is sent to the client-side for the first time. - * </p> - * - * <p> - * The attachment logic is implemented in {@link AbstractClientConnector}. - * </p> - */ - public void attach(); - - /** - * Notifies the component that it is detached from the application. - * - * <p> - * The caller of this method is {@link #setParent(ClientConnector)} if the - * parent is in the application. When the parent is detached from the - * application it is its response to call {@link #detach()} for all the - * children and to detach itself from the terminal. - * </p> - */ - public void detach(); - - /** - * Get a read-only collection of all extensions attached to this connector. - * - * @return a collection of extensions - */ - public Collection<Extension> getExtensions(); - - /** - * Remove an extension from this connector. - * - * @param extension - * the extension to remove. - */ - public void removeExtension(Extension extension); - - /** - * Returns the root this connector is attached to - * - * @return The Root this connector is attached to or null if it is not - * attached to any Root - */ - public Root getRoot(); -} diff --git a/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java deleted file mode 100644 index 64ea288665..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ClientMethodInvocation.java +++ /dev/null @@ -1,71 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.lang.reflect.Type; - -/** - * Internal class for keeping track of pending server to client method - * invocations for a Connector. - * - * @since 7.0 - */ -public class ClientMethodInvocation implements Serializable, - Comparable<ClientMethodInvocation> { - private final ClientConnector connector; - private final String interfaceName; - private final String methodName; - private final Object[] parameters; - private Type[] parameterTypes; - - // used for sorting calls between different connectors in the same Root - private final long sequenceNumber; - // TODO may cause problems when clustering etc. - private static long counter = 0; - - public ClientMethodInvocation(ClientConnector connector, - String interfaceName, Method method, Object[] parameters) { - this.connector = connector; - this.interfaceName = interfaceName; - methodName = method.getName(); - parameterTypes = method.getGenericParameterTypes(); - this.parameters = (null != parameters) ? parameters : new Object[0]; - sequenceNumber = ++counter; - } - - public Type[] getParameterTypes() { - return parameterTypes; - } - - public ClientConnector getConnector() { - return connector; - } - - public String getInterfaceName() { - return interfaceName; - } - - public String getMethodName() { - return methodName; - } - - public Object[] getParameters() { - return parameters; - } - - protected long getSequenceNumber() { - return sequenceNumber; - } - - @Override - public int compareTo(ClientMethodInvocation o) { - if (null == o) { - return 0; - } - return Long.signum(getSequenceNumber() - o.getSequenceNumber()); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java deleted file mode 100644 index 3cc3a8cb64..0000000000 --- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java +++ /dev/null @@ -1,122 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.InputStream; -import java.net.URL; - -import javax.servlet.ServletContext; - -import com.vaadin.Application; -import com.vaadin.external.json.JSONException; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.ui.Root; - -/** - * Application manager processes changes and paints for single application - * instance. - * - * This class handles applications running as servlets. - * - * @see AbstractCommunicationManager - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -@SuppressWarnings("serial") -public class CommunicationManager extends AbstractCommunicationManager { - - /** - * @deprecated use {@link #CommunicationManager(Application)} instead - * @param application - * @param applicationServlet - */ - @Deprecated - public CommunicationManager(Application application, - AbstractApplicationServlet applicationServlet) { - super(application); - } - - /** - * TODO New constructor - document me! - * - * @param application - */ - public CommunicationManager(Application application) { - super(application); - } - - @Override - protected BootstrapHandler createBootstrapHandler() { - return new BootstrapHandler() { - @Override - protected String getApplicationId(BootstrapContext context) { - String appUrl = getAppUri(context); - - String appId = appUrl; - if ("".equals(appUrl)) { - appId = "ROOT"; - } - appId = appId.replaceAll("[^a-zA-Z0-9]", ""); - // Add hashCode to the end, so that it is still (sort of) - // predictable, but indicates that it should not be used in CSS - // and - // such: - int hashCode = appId.hashCode(); - if (hashCode < 0) { - hashCode = -hashCode; - } - appId = appId + "-" + hashCode; - return appId; - } - - @Override - protected String getAppUri(BootstrapContext context) { - /* Fetch relative url to application */ - // don't use server and port in uri. It may cause problems with - // some - // virtual server configurations which lose the server name - Application application = context.getApplication(); - URL url = application.getURL(); - String appUrl = url.getPath(); - if (appUrl.endsWith("/")) { - appUrl = appUrl.substring(0, appUrl.length() - 1); - } - return appUrl; - } - - @Override - public String getThemeName(BootstrapContext context) { - String themeName = context.getRequest().getParameter( - AbstractApplicationServlet.URL_PARAMETER_THEME); - if (themeName == null) { - themeName = super.getThemeName(context); - } - return themeName; - } - - @Override - protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException { - return CommunicationManager.this.getInitialUIDL(request, root); - } - }; - } - - @Override - protected InputStream getThemeResourceAsStream(Root root, String themeName, - String resource) { - WebApplicationContext context = (WebApplicationContext) root - .getApplication().getContext(); - ServletContext servletContext = context.getHttpSession() - .getServletContext(); - return servletContext.getResourceAsStream("/" - + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName - + "/" + resource); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java b/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java deleted file mode 100644 index 171d440796..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ComponentSizeValidator.java +++ /dev/null @@ -1,664 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.PrintStream; -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Stack; -import java.util.Vector; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.terminal.Sizeable.Unit; -import com.vaadin.ui.AbstractOrderedLayout; -import com.vaadin.ui.AbstractSplitPanel; -import com.vaadin.ui.Component; -import com.vaadin.ui.ComponentContainer; -import com.vaadin.ui.CustomComponent; -import com.vaadin.ui.Form; -import com.vaadin.ui.GridLayout; -import com.vaadin.ui.GridLayout.Area; -import com.vaadin.ui.Layout; -import com.vaadin.ui.Panel; -import com.vaadin.ui.TabSheet; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.Window; - -@SuppressWarnings({ "serial", "deprecation" }) -public class ComponentSizeValidator implements Serializable { - - private final static int LAYERS_SHOWN = 4; - - /** - * Recursively checks given component and its subtree for invalid layout - * setups. Prints errors to std err stream. - * - * @param component - * component to check - * @return set of first level errors found - */ - public static List<InvalidLayout> validateComponentRelativeSizes( - Component component, List<InvalidLayout> errors, - InvalidLayout parent) { - - boolean invalidHeight = !checkHeights(component); - boolean invalidWidth = !checkWidths(component); - - if (invalidHeight || invalidWidth) { - InvalidLayout error = new InvalidLayout(component, invalidHeight, - invalidWidth); - if (parent != null) { - parent.addError(error); - } else { - if (errors == null) { - errors = new LinkedList<InvalidLayout>(); - } - errors.add(error); - } - parent = error; - } - - if (component instanceof Panel) { - Panel panel = (Panel) component; - errors = validateComponentRelativeSizes(panel.getContent(), errors, - parent); - } else if (component instanceof ComponentContainer) { - ComponentContainer lo = (ComponentContainer) component; - Iterator<Component> it = lo.getComponentIterator(); - while (it.hasNext()) { - errors = validateComponentRelativeSizes(it.next(), errors, - parent); - } - } else if (component instanceof Form) { - Form form = (Form) component; - if (form.getLayout() != null) { - errors = validateComponentRelativeSizes(form.getLayout(), - errors, parent); - } - if (form.getFooter() != null) { - errors = validateComponentRelativeSizes(form.getFooter(), - errors, parent); - } - } - - return errors; - } - - private static void printServerError(String msg, - Stack<ComponentInfo> attributes, boolean widthError, - PrintStream errorStream) { - StringBuffer err = new StringBuffer(); - err.append("Vaadin DEBUG\n"); - - StringBuilder indent = new StringBuilder(""); - ComponentInfo ci; - if (attributes != null) { - while (attributes.size() > LAYERS_SHOWN) { - attributes.pop(); - } - while (!attributes.empty()) { - ci = attributes.pop(); - showComponent(ci.component, ci.info, err, indent, widthError); - } - } - - err.append("Layout problem detected: "); - err.append(msg); - err.append("\n"); - err.append("Relative sizes were replaced by undefined sizes, components may not render as expected.\n"); - errorStream.println(err); - - } - - public static boolean checkHeights(Component component) { - try { - if (!hasRelativeHeight(component)) { - return true; - } - if (component instanceof Window) { - return true; - } - if (component.getParent() == null) { - return true; - } - - return parentCanDefineHeight(component); - } catch (Exception e) { - getLogger().log(Level.FINER, - "An exception occurred while validating sizes.", e); - return true; - } - } - - public static boolean checkWidths(Component component) { - try { - if (!hasRelativeWidth(component)) { - return true; - } - if (component instanceof Window) { - return true; - } - if (component.getParent() == null) { - return true; - } - - return parentCanDefineWidth(component); - } catch (Exception e) { - getLogger().log(Level.FINER, - "An exception occurred while validating sizes.", e); - return true; - } - } - - public static class InvalidLayout implements Serializable { - - private final Component component; - - private final boolean invalidHeight; - private final boolean invalidWidth; - - private final Vector<InvalidLayout> subErrors = new Vector<InvalidLayout>(); - - public InvalidLayout(Component component, boolean height, boolean width) { - this.component = component; - invalidHeight = height; - invalidWidth = width; - } - - public void addError(InvalidLayout error) { - subErrors.add(error); - } - - public void reportErrors(PrintWriter clientJSON, - AbstractCommunicationManager communicationManager, - PrintStream serverErrorStream) { - clientJSON.write("{"); - - Component parent = component.getParent(); - String paintableId = component.getConnectorId(); - - clientJSON.print("id:\"" + paintableId + "\""); - - if (invalidHeight) { - Stack<ComponentInfo> attributes = null; - String msg = ""; - // set proper error messages - if (parent instanceof AbstractOrderedLayout) { - AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; - boolean vertical = false; - - if (ol instanceof VerticalLayout) { - vertical = true; - } - - if (vertical) { - msg = "Component with relative height inside a VerticalLayout with no height defined."; - attributes = getHeightAttributes(component); - } else { - msg = "At least one of a HorizontalLayout's components must have non relative height if the height of the layout is not defined"; - attributes = getHeightAttributes(component); - } - } else if (parent instanceof GridLayout) { - msg = "At least one of the GridLayout's components in each row should have non relative height if the height of the layout is not defined."; - attributes = getHeightAttributes(component); - } else { - // default error for non sized parent issue - msg = "A component with relative height needs a parent with defined height."; - attributes = getHeightAttributes(component); - } - printServerError(msg, attributes, false, serverErrorStream); - clientJSON.print(",\"heightMsg\":\"" + msg + "\""); - } - if (invalidWidth) { - Stack<ComponentInfo> attributes = null; - String msg = ""; - if (parent instanceof AbstractOrderedLayout) { - AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; - boolean horizontal = true; - - if (ol instanceof VerticalLayout) { - horizontal = false; - } - - if (horizontal) { - msg = "Component with relative width inside a HorizontalLayout with no width defined"; - attributes = getWidthAttributes(component); - } else { - msg = "At least one of a VerticalLayout's components must have non relative width if the width of the layout is not defined"; - attributes = getWidthAttributes(component); - } - } else if (parent instanceof GridLayout) { - msg = "At least one of the GridLayout's components in each column should have non relative width if the width of the layout is not defined."; - attributes = getWidthAttributes(component); - } else { - // default error for non sized parent issue - msg = "A component with relative width needs a parent with defined width."; - attributes = getWidthAttributes(component); - } - clientJSON.print(",\"widthMsg\":\"" + msg + "\""); - printServerError(msg, attributes, true, serverErrorStream); - } - if (subErrors.size() > 0) { - serverErrorStream.println("Sub errors >>"); - clientJSON.write(", \"subErrors\" : ["); - boolean first = true; - for (InvalidLayout subError : subErrors) { - if (!first) { - clientJSON.print(","); - } else { - first = false; - } - subError.reportErrors(clientJSON, communicationManager, - serverErrorStream); - } - clientJSON.write("]"); - serverErrorStream.println("<< Sub erros"); - } - clientJSON.write("}"); - } - } - - private static class ComponentInfo implements Serializable { - Component component; - String info; - - public ComponentInfo(Component component, String info) { - this.component = component; - this.info = info; - } - - } - - private static Stack<ComponentInfo> getHeightAttributes(Component component) { - Stack<ComponentInfo> attributes = new Stack<ComponentInfo>(); - attributes - .add(new ComponentInfo(component, getHeightString(component))); - Component parent = component.getParent(); - attributes.add(new ComponentInfo(parent, getHeightString(parent))); - - while ((parent = parent.getParent()) != null) { - attributes.add(new ComponentInfo(parent, getHeightString(parent))); - } - - return attributes; - } - - private static Stack<ComponentInfo> getWidthAttributes(Component component) { - Stack<ComponentInfo> attributes = new Stack<ComponentInfo>(); - attributes.add(new ComponentInfo(component, getWidthString(component))); - Component parent = component.getParent(); - attributes.add(new ComponentInfo(parent, getWidthString(parent))); - - while ((parent = parent.getParent()) != null) { - attributes.add(new ComponentInfo(parent, getWidthString(parent))); - } - - return attributes; - } - - private static String getWidthString(Component component) { - String width = "width: "; - if (hasRelativeWidth(component)) { - width += "RELATIVE, " + component.getWidth() + " %"; - } else if (component instanceof Window && component.getParent() == null) { - width += "MAIN WINDOW"; - } else if (component.getWidth() >= 0) { - width += "ABSOLUTE, " + component.getWidth() + " " - + component.getWidthUnits().getSymbol(); - } else { - width += "UNDEFINED"; - } - - return width; - } - - private static String getHeightString(Component component) { - String height = "height: "; - if (hasRelativeHeight(component)) { - height += "RELATIVE, " + component.getHeight() + " %"; - } else if (component instanceof Window && component.getParent() == null) { - height += "MAIN WINDOW"; - } else if (component.getHeight() > 0) { - height += "ABSOLUTE, " + component.getHeight() + " " - + component.getHeightUnits().getSymbol(); - } else { - height += "UNDEFINED"; - } - - return height; - } - - private static void showComponent(Component component, String attribute, - StringBuffer err, StringBuilder indent, boolean widthError) { - - FileLocation createLoc = creationLocations.get(component); - - FileLocation sizeLoc; - if (widthError) { - sizeLoc = widthLocations.get(component); - } else { - sizeLoc = heightLocations.get(component); - } - - err.append(indent); - indent.append(" "); - err.append("- "); - - err.append(component.getClass().getSimpleName()); - err.append("/").append(Integer.toHexString(component.hashCode())); - - if (component.getCaption() != null) { - err.append(" \""); - err.append(component.getCaption()); - err.append("\""); - } - - if (component.getDebugId() != null) { - err.append(" debugId: "); - err.append(component.getDebugId()); - } - - if (createLoc != null) { - err.append(", created at (" + createLoc.file + ":" - + createLoc.lineNumber + ")"); - - } - - if (attribute != null) { - err.append(" ("); - err.append(attribute); - if (sizeLoc != null) { - err.append(", set at (" + sizeLoc.file + ":" - + sizeLoc.lineNumber + ")"); - } - - err.append(")"); - } - err.append("\n"); - - } - - private static boolean hasNonRelativeHeightComponent( - AbstractOrderedLayout ol) { - Iterator<Component> it = ol.getComponentIterator(); - while (it.hasNext()) { - if (!hasRelativeHeight(it.next())) { - return true; - } - } - return false; - } - - public static boolean parentCanDefineHeight(Component component) { - Component parent = component.getParent(); - if (parent == null) { - // main window, valid situation - return true; - } - if (parent.getHeight() < 0) { - // Undefined height - if (parent instanceof Window) { - // Sub window with undefined size has a min-height - return true; - } - - if (parent instanceof AbstractOrderedLayout) { - boolean horizontal = true; - if (parent instanceof VerticalLayout) { - horizontal = false; - } - if (horizontal - && hasNonRelativeHeightComponent((AbstractOrderedLayout) parent)) { - return true; - } else { - return false; - } - - } else if (parent instanceof GridLayout) { - GridLayout gl = (GridLayout) parent; - Area componentArea = gl.getComponentArea(component); - boolean rowHasHeight = false; - for (int row = componentArea.getRow1(); !rowHasHeight - && row <= componentArea.getRow2(); row++) { - for (int column = 0; !rowHasHeight - && column < gl.getColumns(); column++) { - Component c = gl.getComponent(column, row); - if (c != null) { - rowHasHeight = !hasRelativeHeight(c); - } - } - } - if (!rowHasHeight) { - return false; - } else { - // Other components define row height - return true; - } - } - - if (parent instanceof Panel || parent instanceof AbstractSplitPanel - || parent instanceof TabSheet - || parent instanceof CustomComponent) { - // height undefined, we know how how component works and no - // exceptions - // TODO horiz SplitPanel ?? - return false; - } else { - // We cannot generally know if undefined component can serve - // space for children (like CustomLayout or component built by - // third party) so we assume they can - return true; - } - - } else if (hasRelativeHeight(parent)) { - // Relative height - if (parent.getParent() != null) { - return parentCanDefineHeight(parent); - } else { - return true; - } - } else { - // Absolute height - return true; - } - } - - private static boolean hasRelativeHeight(Component component) { - return (component.getHeightUnits() == Unit.PERCENTAGE && component - .getHeight() > 0); - } - - private static boolean hasNonRelativeWidthComponent(AbstractOrderedLayout ol) { - Iterator<Component> it = ol.getComponentIterator(); - while (it.hasNext()) { - if (!hasRelativeWidth(it.next())) { - return true; - } - } - return false; - } - - private static boolean hasRelativeWidth(Component paintable) { - return paintable.getWidth() > 0 - && paintable.getWidthUnits() == Unit.PERCENTAGE; - } - - public static boolean parentCanDefineWidth(Component component) { - Component parent = component.getParent(); - if (parent == null) { - // main window, valid situation - return true; - } - if (parent instanceof Window) { - // Sub window with undefined size has a min-width - return true; - } - - if (parent.getWidth() < 0) { - // Undefined width - - if (parent instanceof AbstractOrderedLayout) { - AbstractOrderedLayout ol = (AbstractOrderedLayout) parent; - boolean horizontal = true; - if (ol instanceof VerticalLayout) { - horizontal = false; - } - - if (!horizontal && hasNonRelativeWidthComponent(ol)) { - // valid situation, other components defined width - return true; - } else { - return false; - } - } else if (parent instanceof GridLayout) { - GridLayout gl = (GridLayout) parent; - Area componentArea = gl.getComponentArea(component); - boolean columnHasWidth = false; - for (int col = componentArea.getColumn1(); !columnHasWidth - && col <= componentArea.getColumn2(); col++) { - for (int row = 0; !columnHasWidth && row < gl.getRows(); row++) { - Component c = gl.getComponent(col, row); - if (c != null) { - columnHasWidth = !hasRelativeWidth(c); - } - } - } - if (!columnHasWidth) { - return false; - } else { - // Other components define column width - return true; - } - } else if (parent instanceof Form) { - /* - * If some other part of the form is not relative it determines - * the component width - */ - return hasNonRelativeWidthComponent((Form) parent); - } else if (parent instanceof AbstractSplitPanel - || parent instanceof TabSheet - || parent instanceof CustomComponent) { - // FIXME Could we use com.vaadin package name here and - // fail for all component containers? - // FIXME Actually this should be moved to containers so it can - // be implemented for custom containers - // TODO vertical splitpanel with another non relative component? - return false; - } else if (parent instanceof Window) { - // Sub window can define width based on caption - if (parent.getCaption() != null - && !parent.getCaption().equals("")) { - return true; - } else { - return false; - } - } else if (parent instanceof Panel) { - // TODO Panel should be able to define width based on caption - return false; - } else { - return true; - } - } else if (hasRelativeWidth(parent)) { - // Relative width - if (parent.getParent() == null) { - return true; - } - - return parentCanDefineWidth(parent); - } else { - return true; - } - - } - - private static boolean hasNonRelativeWidthComponent(Form form) { - Layout layout = form.getLayout(); - Layout footer = form.getFooter(); - - if (layout != null && !hasRelativeWidth(layout)) { - return true; - } - if (footer != null && !hasRelativeWidth(footer)) { - return true; - } - - return false; - } - - private static Map<Object, FileLocation> creationLocations = new HashMap<Object, FileLocation>(); - private static Map<Object, FileLocation> widthLocations = new HashMap<Object, FileLocation>(); - private static Map<Object, FileLocation> heightLocations = new HashMap<Object, FileLocation>(); - - public static class FileLocation implements Serializable { - public String method; - public String file; - public String className; - public String classNameSimple; - public int lineNumber; - - public FileLocation(StackTraceElement traceElement) { - file = traceElement.getFileName(); - className = traceElement.getClassName(); - classNameSimple = className - .substring(className.lastIndexOf('.') + 1); - lineNumber = traceElement.getLineNumber(); - method = traceElement.getMethodName(); - } - } - - public static void setCreationLocation(Object object) { - setLocation(creationLocations, object); - } - - public static void setWidthLocation(Object object) { - setLocation(widthLocations, object); - } - - public static void setHeightLocation(Object object) { - setLocation(heightLocations, object); - } - - private static void setLocation(Map<Object, FileLocation> map, Object object) { - StackTraceElement[] traceLines = Thread.currentThread().getStackTrace(); - for (StackTraceElement traceElement : traceLines) { - Class<?> cls; - try { - String className = traceElement.getClassName(); - if (className.startsWith("java.") - || className.startsWith("sun.")) { - continue; - } - - cls = Class.forName(className); - if (cls == ComponentSizeValidator.class || cls == Thread.class) { - continue; - } - - if (Component.class.isAssignableFrom(cls) - && !CustomComponent.class.isAssignableFrom(cls)) { - continue; - } - FileLocation cl = new FileLocation(traceElement); - map.put(object, cl); - return; - } catch (Exception e) { - // TODO Auto-generated catch block - getLogger().log(Level.FINER, - "An exception occurred while validating sizes.", e); - } - - } - } - - private static Logger getLogger() { - return Logger.getLogger(ComponentSizeValidator.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/Constants.java b/src/com/vaadin/terminal/gwt/server/Constants.java deleted file mode 100644 index 7efb0205ac..0000000000 --- a/src/com/vaadin/terminal/gwt/server/Constants.java +++ /dev/null @@ -1,80 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -/** - * TODO Document me! - * - * @author peholmst - * - */ -public interface Constants { - - static final String NOT_PRODUCTION_MODE_INFO = "\n" - + "=================================================================\n" - + "Vaadin is running in DEBUG MODE.\nAdd productionMode=true to web.xml " - + "to disable debug features.\nTo show debug window, add ?debug to " - + "your application URL.\n" - + "================================================================="; - - static final String WARNING_XSRF_PROTECTION_DISABLED = "\n" - + "===========================================================\n" - + "WARNING: Cross-site request forgery protection is disabled!\n" - + "==========================================================="; - - static final String WARNING_RESOURCE_CACHING_TIME_NOT_NUMERIC = "\n" - + "===========================================================\n" - + "WARNING: resourceCacheTime has been set to a non integer value " - + "in web.xml. The default of 1h will be used.\n" - + "==========================================================="; - - static final String WIDGETSET_MISMATCH_INFO = "\n" - + "=================================================================\n" - + "The widgetset in use does not seem to be built for the Vaadin\n" - + "version in use. This might cause strange problems - a\n" - + "recompile/deploy is strongly recommended.\n" - + " Vaadin version: %s\n" - + " Widgetset version: %s\n" - + "================================================================="; - - static final String URL_PARAMETER_RESTART_APPLICATION = "restartApplication"; - static final String URL_PARAMETER_CLOSE_APPLICATION = "closeApplication"; - static final String URL_PARAMETER_REPAINT_ALL = "repaintAll"; - static final String URL_PARAMETER_THEME = "theme"; - - static final String SERVLET_PARAMETER_PRODUCTION_MODE = "productionMode"; - static final String SERVLET_PARAMETER_DISABLE_XSRF_PROTECTION = "disable-xsrf-protection"; - static final String SERVLET_PARAMETER_RESOURCE_CACHE_TIME = "resourceCacheTime"; - - // Configurable parameter names - static final String PARAMETER_VAADIN_RESOURCES = "Resources"; - - static final int DEFAULT_BUFFER_SIZE = 32 * 1024; - - static final int MAX_BUFFER_SIZE = 64 * 1024; - - final String THEME_DIRECTORY_PATH = "VAADIN/themes/"; - - static final int DEFAULT_THEME_CACHETIME = 1000 * 60 * 60 * 24; - - static final String WIDGETSET_DIRECTORY_PATH = "VAADIN/widgetsets/"; - - // Name of the default widget set, used if not specified in web.xml - static final String DEFAULT_WIDGETSET = "com.vaadin.terminal.gwt.DefaultWidgetSet"; - - // Widget set parameter name - static final String PARAMETER_WIDGETSET = "widgetset"; - - static final String ERROR_NO_ROOT_FOUND = "Application did not return a root for the request and did not request extra information either. Something is wrong."; - - static final String DEFAULT_THEME_NAME = "reindeer"; - - static final String INVALID_SECURITY_KEY_MSG = "Invalid security key."; - - // portal configuration parameters - static final String PORTAL_PARAMETER_VAADIN_WIDGETSET = "vaadin.widgetset"; - static final String PORTAL_PARAMETER_VAADIN_RESOURCE_PATH = "vaadin.resources.path"; - static final String PORTAL_PARAMETER_VAADIN_THEME = "vaadin.theme"; - -} diff --git a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java b/src/com/vaadin/terminal/gwt/server/DragAndDropService.java deleted file mode 100644 index efb5666efa..0000000000 --- a/src/com/vaadin/terminal/gwt/server/DragAndDropService.java +++ /dev/null @@ -1,313 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.PrintWriter; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -import com.vaadin.event.Transferable; -import com.vaadin.event.TransferableImpl; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.DragSource; -import com.vaadin.event.dd.DropHandler; -import com.vaadin.event.dd.DropTarget; -import com.vaadin.event.dd.TargetDetails; -import com.vaadin.event.dd.TargetDetailsImpl; -import com.vaadin.event.dd.acceptcriteria.AcceptCriterion; -import com.vaadin.shared.communication.SharedState; -import com.vaadin.shared.ui.dd.DragEventType; -import com.vaadin.terminal.Extension; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.terminal.gwt.client.ui.dd.VDragAndDropManager; -import com.vaadin.ui.Component; -import com.vaadin.ui.Root; - -public class DragAndDropService implements VariableOwner, ClientConnector { - - private int lastVisitId; - - private boolean lastVisitAccepted = false; - - private DragAndDropEvent dragEvent; - - private final AbstractCommunicationManager manager; - - private AcceptCriterion acceptCriterion; - - public DragAndDropService(AbstractCommunicationManager manager) { - this.manager = manager; - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - Object owner = variables.get("dhowner"); - - // Validate drop handler owner - if (!(owner instanceof DropTarget)) { - getLogger() - .severe("DropHandler owner " + owner - + " must implement DropTarget"); - return; - } - // owner cannot be null here - - DropTarget dropTarget = (DropTarget) owner; - lastVisitId = (Integer) variables.get("visitId"); - - // request may be dropRequest or request during drag operation (commonly - // dragover or dragenter) - boolean dropRequest = isDropRequest(variables); - if (dropRequest) { - handleDropRequest(dropTarget, variables); - } else { - handleDragRequest(dropTarget, variables); - } - - } - - /** - * Handles a drop request from the VDragAndDropManager. - * - * @param dropTarget - * @param variables - */ - private void handleDropRequest(DropTarget dropTarget, - Map<String, Object> variables) { - DropHandler dropHandler = (dropTarget).getDropHandler(); - if (dropHandler == null) { - // No dropHandler returned so no drop can be performed. - getLogger().fine( - "DropTarget.getDropHandler() returned null for owner: " - + dropTarget); - return; - } - - /* - * Construct the Transferable and the DragDropDetails for the drop - * operation based on the info passed from the client widgets (drag - * source for Transferable, drop target for DragDropDetails). - */ - Transferable transferable = constructTransferable(dropTarget, variables); - TargetDetails dropData = constructDragDropDetails(dropTarget, variables); - DragAndDropEvent dropEvent = new DragAndDropEvent(transferable, - dropData); - if (dropHandler.getAcceptCriterion().accept(dropEvent)) { - dropHandler.drop(dropEvent); - } - } - - /** - * Handles a drag/move request from the VDragAndDropManager. - * - * @param dropTarget - * @param variables - */ - private void handleDragRequest(DropTarget dropTarget, - Map<String, Object> variables) { - lastVisitId = (Integer) variables.get("visitId"); - - acceptCriterion = dropTarget.getDropHandler().getAcceptCriterion(); - - /* - * Construct the Transferable and the DragDropDetails for the drag - * operation based on the info passed from the client widgets (drag - * source for Transferable, current target for DragDropDetails). - */ - Transferable transferable = constructTransferable(dropTarget, variables); - TargetDetails dragDropDetails = constructDragDropDetails(dropTarget, - variables); - - dragEvent = new DragAndDropEvent(transferable, dragDropDetails); - - lastVisitAccepted = acceptCriterion.accept(dragEvent); - } - - /** - * Construct DragDropDetails based on variables from client drop target. - * Uses DragDropDetailsTranslator if available, otherwise a default - * DragDropDetails implementation is used. - * - * @param dropTarget - * @param variables - * @return - */ - @SuppressWarnings("unchecked") - private TargetDetails constructDragDropDetails(DropTarget dropTarget, - Map<String, Object> variables) { - Map<String, Object> rawDragDropDetails = (Map<String, Object>) variables - .get("evt"); - - TargetDetails dropData = dropTarget - .translateDropTargetDetails(rawDragDropDetails); - - if (dropData == null) { - // Create a default DragDropDetails with all the raw variables - dropData = new TargetDetailsImpl(rawDragDropDetails, dropTarget); - } - - return dropData; - } - - private boolean isDropRequest(Map<String, Object> variables) { - return getRequestType(variables) == DragEventType.DROP; - } - - private DragEventType getRequestType(Map<String, Object> variables) { - int type = (Integer) variables.get("type"); - return DragEventType.values()[type]; - } - - @SuppressWarnings("unchecked") - private Transferable constructTransferable(DropTarget dropHandlerOwner, - Map<String, Object> variables) { - final Component sourceComponent = (Component) variables - .get("component"); - - variables = (Map<String, Object>) variables.get("tra"); - - Transferable transferable = null; - if (sourceComponent != null && sourceComponent instanceof DragSource) { - transferable = ((DragSource) sourceComponent) - .getTransferable(variables); - } - if (transferable == null) { - transferable = new TransferableImpl(sourceComponent, variables); - } - - return transferable; - } - - @Override - public boolean isEnabled() { - return isConnectorEnabled(); - } - - @Override - public boolean isImmediate() { - return true; - } - - void printJSONResponse(PrintWriter outWriter) throws PaintException { - if (isDirty()) { - - outWriter.print(", \"dd\":"); - - JsonPaintTarget jsonPaintTarget = new JsonPaintTarget(manager, - outWriter, false); - jsonPaintTarget.startTag("dd"); - jsonPaintTarget.addAttribute("visitId", lastVisitId); - if (acceptCriterion != null) { - jsonPaintTarget.addAttribute("accepted", lastVisitAccepted); - acceptCriterion.paintResponse(jsonPaintTarget); - } - jsonPaintTarget.endTag("dd"); - jsonPaintTarget.close(); - lastVisitId = -1; - lastVisitAccepted = false; - acceptCriterion = null; - dragEvent = null; - } - } - - private boolean isDirty() { - if (lastVisitId > 0) { - return true; - } - return false; - } - - @Override - public SharedState getState() { - // TODO Auto-generated method stub - return null; - } - - @Override - public String getConnectorId() { - return VDragAndDropManager.DD_SERVICE; - } - - @Override - public boolean isConnectorEnabled() { - // Drag'n'drop can't be disabled - return true; - } - - @Override - public List<ClientMethodInvocation> retrievePendingRpcCalls() { - return null; - } - - @Override - public RpcManager getRpcManager(Class<?> rpcInterface) { - // TODO Use rpc for drag'n'drop - return null; - } - - @Override - public Class<? extends SharedState> getStateType() { - return SharedState.class; - } - - @Override - public void requestRepaint() { - // TODO Auto-generated method stub - - } - - @Override - public ClientConnector getParent() { - // TODO Auto-generated method stub - return null; - } - - @Override - public void requestRepaintAll() { - // TODO Auto-generated method stub - - } - - @Override - public void setParent(ClientConnector parent) { - // TODO Auto-generated method stub - - } - - @Override - public void attach() { - // TODO Auto-generated method stub - - } - - @Override - public void detach() { - // TODO Auto-generated method stub - - } - - @Override - public Collection<Extension> getExtensions() { - // TODO Auto-generated method stub - return Collections.emptySet(); - } - - @Override - public void removeExtension(Extension extension) { - // TODO Auto-generated method stub - } - - private Logger getLogger() { - return Logger.getLogger(DragAndDropService.class.getName()); - } - - @Override - public Root getRoot() { - return null; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java deleted file mode 100644 index cc12c9cc43..0000000000 --- a/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java +++ /dev/null @@ -1,417 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import com.google.appengine.api.datastore.Blob; -import com.google.appengine.api.datastore.DatastoreService; -import com.google.appengine.api.datastore.DatastoreServiceFactory; -import com.google.appengine.api.datastore.Entity; -import com.google.appengine.api.datastore.EntityNotFoundException; -import com.google.appengine.api.datastore.FetchOptions.Builder; -import com.google.appengine.api.datastore.Key; -import com.google.appengine.api.datastore.KeyFactory; -import com.google.appengine.api.datastore.PreparedQuery; -import com.google.appengine.api.datastore.Query; -import com.google.appengine.api.datastore.Query.FilterOperator; -import com.google.appengine.api.memcache.Expiration; -import com.google.appengine.api.memcache.MemcacheService; -import com.google.appengine.api.memcache.MemcacheServiceFactory; -import com.google.apphosting.api.DeadlineExceededException; -import com.vaadin.service.ApplicationContext; - -/** - * ApplicationServlet to be used when deploying to Google App Engine, in - * web.xml: - * - * <pre> - * <servlet> - * <servlet-name>HelloWorld</servlet-name> - * <servlet-class>com.vaadin.terminal.gwt.server.GAEApplicationServlet</servlet-class> - * <init-param> - * <param-name>application</param-name> - * <param-value>com.vaadin.demo.HelloWorld</param-value> - * </init-param> - * </servlet> - * </pre> - * - * Session support must be enabled in appengine-web.xml: - * - * <pre> - * <sessions-enabled>true</sessions-enabled> - * </pre> - * - * Appengine datastore cleanup can be invoked by calling one of the applications - * with an additional path "/CLEAN". This can be set up as a cron-job in - * cron.xml (see appengine documentation for more information): - * - * <pre> - * <cronentries> - * <cron> - * <url>/HelloWorld/CLEAN</url> - * <description>Clean up sessions</description> - * <schedule>every 2 hours</schedule> - * </cron> - * </cronentries> - * </pre> - * - * It is recommended (but not mandatory) to extract themes and widgetsets and - * have App Engine server these statically. Extract VAADIN folder (and it's - * contents) 'next to' the WEB-INF folder, and add the following to - * appengine-web.xml: - * - * <pre> - * <static-files> - * <include path="/VAADIN/**" /> - * </static-files> - * </pre> - * - * Additional limitations: - * <ul> - * <li/>Do not change application state when serving an ApplicationResource. - * <li/>Avoid changing application state in transaction handlers, unless you're - * confident you fully understand the synchronization issues in App Engine. - * <li/>The application remains locked while uploading - no progressbar is - * possible. - * </ul> - */ -public class GAEApplicationServlet extends ApplicationServlet { - - // memcache mutex is MUTEX_BASE + sessio id - private static final String MUTEX_BASE = "_vmutex"; - - // used identify ApplicationContext in memcache and datastore - private static final String AC_BASE = "_vac"; - - // UIDL requests will attempt to gain access for this long before telling - // the client to retry - private static final int MAX_UIDL_WAIT_MILLISECONDS = 5000; - - // Tell client to retry after this delay. - // Note: currently interpreting Retry-After as ms, not sec - private static final int RETRY_AFTER_MILLISECONDS = 100; - - // Properties used in the datastore - private static final String PROPERTY_EXPIRES = "expires"; - private static final String PROPERTY_DATA = "data"; - - // path used for cleanup - private static final String CLEANUP_PATH = "/CLEAN"; - // max entities to clean at once - private static final int CLEANUP_LIMIT = 200; - // appengine session kind - private static final String APPENGINE_SESSION_KIND = "_ah_SESSION"; - // appengine session expires-parameter - private static final String PROPERTY_APPENGINE_EXPIRES = "_expires"; - - protected void sendDeadlineExceededNotification( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - criticalNotification( - request, - response, - "Deadline Exceeded", - "I'm sorry, but the operation took too long to complete. We'll try reloading to see where we're at, please take note of any unsaved data...", - "", null); - } - - protected void sendNotSerializableNotification( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - criticalNotification( - request, - response, - "NotSerializableException", - "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...", - "", getApplicationUrl(request).toString() - + "?restartApplication"); - } - - protected void sendCriticalErrorNotification( - WrappedHttpServletRequest request, - WrappedHttpServletResponse response) throws IOException { - criticalNotification( - request, - response, - "Critical error", - "I'm sorry, but there seems to be a serious problem, please contact the administrator. And please take note of any unsaved data...", - "", getApplicationUrl(request).toString() - + "?restartApplication"); - } - - @Override - protected void service(HttpServletRequest unwrappedRequest, - HttpServletResponse unwrappedResponse) throws ServletException, - IOException { - WrappedHttpServletRequest request = new WrappedHttpServletRequest( - unwrappedRequest, getDeploymentConfiguration()); - WrappedHttpServletResponse response = new WrappedHttpServletResponse( - unwrappedResponse, getDeploymentConfiguration()); - - if (isCleanupRequest(request)) { - cleanDatastore(); - return; - } - - RequestType requestType = getRequestType(request); - - if (requestType == RequestType.STATIC_FILE) { - // no locking needed, let superclass handle - super.service(request, response); - cleanSession(request); - return; - } - - if (requestType == RequestType.APPLICATION_RESOURCE) { - // no locking needed, let superclass handle - getApplicationContext(request, - MemcacheServiceFactory.getMemcacheService()); - super.service(request, response); - cleanSession(request); - return; - } - - final HttpSession session = request - .getSession(requestCanCreateApplication(request, requestType)); - if (session == null) { - handleServiceSessionExpired(request, response); - cleanSession(request); - return; - } - - boolean locked = false; - MemcacheService memcache = null; - String mutex = MUTEX_BASE + session.getId(); - memcache = MemcacheServiceFactory.getMemcacheService(); - try { - // try to get lock - long started = new Date().getTime(); - // non-UIDL requests will try indefinitely - while (requestType != RequestType.UIDL - || new Date().getTime() - started < MAX_UIDL_WAIT_MILLISECONDS) { - locked = memcache.put(mutex, 1, Expiration.byDeltaSeconds(40), - MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT); - if (locked) { - break; - } - try { - Thread.sleep(RETRY_AFTER_MILLISECONDS); - } catch (InterruptedException e) { - getLogger().finer( - "Thread.sleep() interrupted while waiting for lock. Trying again. " - + e); - } - } - - if (!locked) { - // Not locked; only UIDL can get trough here unlocked: tell - // client to retry - response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); - // Note: currently interpreting Retry-After as ms, not sec - response.setHeader("Retry-After", "" + RETRY_AFTER_MILLISECONDS); - return; - } - - // de-serialize or create application context, store in session - ApplicationContext ctx = getApplicationContext(request, memcache); - - super.service(request, response); - - // serialize - started = new Date().getTime(); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - ObjectOutputStream oos = new ObjectOutputStream(baos); - oos.writeObject(ctx); - oos.flush(); - byte[] bytes = baos.toByteArray(); - - started = new Date().getTime(); - - String id = AC_BASE + session.getId(); - Date expire = new Date(started - + (session.getMaxInactiveInterval() * 1000)); - Expiration expires = Expiration.onDate(expire); - - memcache.put(id, bytes, expires); - - DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); - Entity entity = new Entity(AC_BASE, id); - entity.setProperty(PROPERTY_EXPIRES, expire.getTime()); - entity.setProperty(PROPERTY_DATA, new Blob(bytes)); - ds.put(entity); - - } catch (DeadlineExceededException e) { - getLogger().warning("DeadlineExceeded for " + session.getId()); - sendDeadlineExceededNotification(request, response); - } catch (NotSerializableException e) { - getLogger().log(Level.SEVERE, "Not serializable!", e); - - // TODO this notification is usually not shown - should we redirect - // in some other way - can we? - sendNotSerializableNotification(request, response); - } catch (Exception e) { - getLogger().log(Level.WARNING, - "An exception occurred while servicing request.", e); - - sendCriticalErrorNotification(request, response); - } finally { - // "Next, please!" - if (locked) { - memcache.delete(mutex); - } - cleanSession(request); - } - } - - protected ApplicationContext getApplicationContext( - HttpServletRequest request, MemcacheService memcache) { - HttpSession session = request.getSession(); - String id = AC_BASE + session.getId(); - byte[] serializedAC = (byte[]) memcache.get(id); - if (serializedAC == null) { - DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); - Key key = KeyFactory.createKey(AC_BASE, id); - Entity entity = null; - try { - entity = ds.get(key); - } catch (EntityNotFoundException e) { - // Ok, we were a bit optimistic; we'll create a new one later - } - if (entity != null) { - Blob blob = (Blob) entity.getProperty(PROPERTY_DATA); - serializedAC = blob.getBytes(); - // bring it to memcache - memcache.put(AC_BASE + session.getId(), serializedAC, - Expiration.byDeltaSeconds(session - .getMaxInactiveInterval()), - MemcacheService.SetPolicy.ADD_ONLY_IF_NOT_PRESENT); - } - } - if (serializedAC != null) { - ByteArrayInputStream bais = new ByteArrayInputStream(serializedAC); - ObjectInputStream ois; - try { - ois = new ObjectInputStream(bais); - ApplicationContext applicationContext = (ApplicationContext) ois - .readObject(); - session.setAttribute(WebApplicationContext.class.getName(), - applicationContext); - } catch (IOException e) { - getLogger().log( - Level.WARNING, - "Could not de-serialize ApplicationContext for " - + session.getId() - + " A new one will be created. ", e); - } catch (ClassNotFoundException e) { - getLogger().log( - Level.WARNING, - "Could not de-serialize ApplicationContext for " - + session.getId() - + " A new one will be created. ", e); - } - } - // will create new context if the above did not - return getApplicationContext(session); - - } - - private boolean isCleanupRequest(HttpServletRequest request) { - String path = getRequestPathInfo(request); - if (path != null && path.equals(CLEANUP_PATH)) { - return true; - } - return false; - } - - /** - * Removes the ApplicationContext from the session in order to minimize the - * data serialized to datastore and memcache. - * - * @param request - */ - private void cleanSession(HttpServletRequest request) { - HttpSession session = request.getSession(false); - if (session != null) { - session.removeAttribute(WebApplicationContext.class.getName()); - } - } - - /** - * This will look at the timestamp and delete expired persisted Vaadin and - * appengine sessions from the datastore. - * - * TODO Possible improvements include: 1. Use transactions (requires entity - * groups - overkill?) 2. Delete one-at-a-time, catch possible exception, - * continue w/ next. - */ - private void cleanDatastore() { - long expire = new Date().getTime(); - try { - DatastoreService ds = DatastoreServiceFactory.getDatastoreService(); - // Vaadin stuff first - { - Query q = new Query(AC_BASE); - q.setKeysOnly(); - - q.addFilter(PROPERTY_EXPIRES, - FilterOperator.LESS_THAN_OR_EQUAL, expire); - PreparedQuery pq = ds.prepare(q); - List<Entity> entities = pq.asList(Builder - .withLimit(CLEANUP_LIMIT)); - if (entities != null) { - getLogger().info( - "Vaadin cleanup deleting " + entities.size() - + " expired Vaadin sessions."); - List<Key> keys = new ArrayList<Key>(); - for (Entity e : entities) { - keys.add(e.getKey()); - } - ds.delete(keys); - } - } - // Also cleanup GAE sessions - { - Query q = new Query(APPENGINE_SESSION_KIND); - q.setKeysOnly(); - q.addFilter(PROPERTY_APPENGINE_EXPIRES, - FilterOperator.LESS_THAN_OR_EQUAL, expire); - PreparedQuery pq = ds.prepare(q); - List<Entity> entities = pq.asList(Builder - .withLimit(CLEANUP_LIMIT)); - if (entities != null) { - getLogger().info( - "Vaadin cleanup deleting " + entities.size() - + " expired appengine sessions."); - List<Key> keys = new ArrayList<Key>(); - for (Entity e : entities) { - keys.add(e.getKey()); - } - ds.delete(keys); - } - } - } catch (Exception e) { - getLogger().log(Level.WARNING, "Exception while cleaning.", e); - } - } - - private static final Logger getLogger() { - return Logger.getLogger(GAEApplicationServlet.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/HttpServletRequestListener.java b/src/com/vaadin/terminal/gwt/server/HttpServletRequestListener.java deleted file mode 100644 index d811cadf86..0000000000 --- a/src/com/vaadin/terminal/gwt/server/HttpServletRequestListener.java +++ /dev/null @@ -1,54 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import javax.servlet.Filter; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import com.vaadin.Application; -import com.vaadin.service.ApplicationContext.TransactionListener; -import com.vaadin.terminal.Terminal; - -/** - * {@link Application} that implements this interface gets notified of request - * start and end by terminal. - * <p> - * Interface can be used for several helper tasks including: - * <ul> - * <li>Opening and closing database connections - * <li>Implementing {@link ThreadLocal} - * <li>Setting/Getting {@link Cookie} - * </ul> - * <p> - * Alternatives for implementing similar features are are Servlet {@link Filter} - * s and {@link TransactionListener}s in Vaadin. - * - * @since 6.2 - * @see PortletRequestListener - */ -public interface HttpServletRequestListener extends Serializable { - - /** - * This method is called before {@link Terminal} applies the request to - * Application. - * - * @param request - * @param response - */ - public void onRequestStart(HttpServletRequest request, - HttpServletResponse response); - - /** - * This method is called at the end of each request. - * - * @param request - * @param response - */ - public void onRequestEnd(HttpServletRequest request, - HttpServletResponse response); -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/JsonCodec.java b/src/com/vaadin/terminal/gwt/server/JsonCodec.java deleted file mode 100644 index 8199bc6ada..0000000000 --- a/src/com/vaadin/terminal/gwt/server/JsonCodec.java +++ /dev/null @@ -1,792 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.io.Serializable; -import java.lang.reflect.Array; -import java.lang.reflect.GenericArrayType; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.lang.reflect.WildcardType; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.shared.Connector; -import com.vaadin.shared.communication.UidlValue; -import com.vaadin.terminal.gwt.client.communication.JsonEncoder; -import com.vaadin.ui.Component; -import com.vaadin.ui.ConnectorTracker; - -/** - * Decoder for converting RPC parameters and other values from JSON in transfer - * between the client and the server and vice versa. - * - * @since 7.0 - */ -public class JsonCodec implements Serializable { - - private static Map<Class<?>, String> typeToTransportType = new HashMap<Class<?>, String>(); - - /** - * Note! This does not contain primitives. - * <p> - */ - private static Map<String, Class<?>> transportTypeToType = new HashMap<String, Class<?>>(); - - static { - registerType(String.class, JsonEncoder.VTYPE_STRING); - registerType(Connector.class, JsonEncoder.VTYPE_CONNECTOR); - registerType(Boolean.class, JsonEncoder.VTYPE_BOOLEAN); - registerType(boolean.class, JsonEncoder.VTYPE_BOOLEAN); - registerType(Integer.class, JsonEncoder.VTYPE_INTEGER); - registerType(int.class, JsonEncoder.VTYPE_INTEGER); - registerType(Float.class, JsonEncoder.VTYPE_FLOAT); - registerType(float.class, JsonEncoder.VTYPE_FLOAT); - registerType(Double.class, JsonEncoder.VTYPE_DOUBLE); - registerType(double.class, JsonEncoder.VTYPE_DOUBLE); - registerType(Long.class, JsonEncoder.VTYPE_LONG); - registerType(long.class, JsonEncoder.VTYPE_LONG); - registerType(String[].class, JsonEncoder.VTYPE_STRINGARRAY); - registerType(Object[].class, JsonEncoder.VTYPE_ARRAY); - registerType(Map.class, JsonEncoder.VTYPE_MAP); - registerType(HashMap.class, JsonEncoder.VTYPE_MAP); - registerType(List.class, JsonEncoder.VTYPE_LIST); - registerType(Set.class, JsonEncoder.VTYPE_SET); - } - - private static void registerType(Class<?> type, String transportType) { - typeToTransportType.put(type, transportType); - if (!type.isPrimitive()) { - transportTypeToType.put(transportType, type); - } - } - - public static boolean isInternalTransportType(String transportType) { - return transportTypeToType.containsKey(transportType); - } - - public static boolean isInternalType(Type type) { - if (type instanceof Class && ((Class<?>) type).isPrimitive()) { - if (type == byte.class || type == char.class) { - // Almost all primitive types are handled internally - return false; - } - // All primitive types are handled internally - return true; - } else if (type == UidlValue.class) { - // UidlValue is a special internal type wrapping type info and a - // value - return true; - } - return typeToTransportType.containsKey(getClassForType(type)); - } - - private static Class<?> getClassForType(Type type) { - if (type instanceof ParameterizedType) { - return (Class<?>) (((ParameterizedType) type).getRawType()); - } else if (type instanceof Class<?>) { - return (Class<?>) type; - } else { - return null; - } - } - - private static Class<?> getType(String transportType) { - return transportTypeToType.get(transportType); - } - - public static Object decodeInternalOrCustomType(Type targetType, - Object value, ConnectorTracker connectorTracker) - throws JSONException { - if (isInternalType(targetType)) { - return decodeInternalType(targetType, false, value, - connectorTracker); - } else { - return decodeCustomType(targetType, value, connectorTracker); - } - } - - public static Object decodeCustomType(Type targetType, Object value, - ConnectorTracker connectorTracker) throws JSONException { - if (isInternalType(targetType)) { - throw new JSONException("decodeCustomType cannot be used for " - + targetType + ", which is an internal type"); - } - - // Try to decode object using fields - if (value == JSONObject.NULL) { - return null; - } else if (targetType == byte.class || targetType == Byte.class) { - return Byte.valueOf(String.valueOf(value)); - } else if (targetType == char.class || targetType == Character.class) { - return Character.valueOf(String.valueOf(value).charAt(0)); - } else if (targetType instanceof Class<?> - && ((Class<?>) targetType).isArray()) { - // Legacy Object[] and String[] handled elsewhere, this takes care - // of generic arrays - Class<?> componentType = ((Class<?>) targetType).getComponentType(); - return decodeArray(componentType, (JSONArray) value, - connectorTracker); - } else if (targetType instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) targetType) - .getGenericComponentType(); - return decodeArray(componentType, (JSONArray) value, - connectorTracker); - } else if (targetType == JSONObject.class - || targetType == JSONArray.class) { - return value; - } else { - return decodeObject(targetType, (JSONObject) value, - connectorTracker); - } - } - - private static Object decodeArray(Type componentType, JSONArray value, - ConnectorTracker connectorTracker) throws JSONException { - Class<?> componentClass = getClassForType(componentType); - Object array = Array.newInstance(componentClass, value.length()); - for (int i = 0; i < value.length(); i++) { - Object decodedValue = decodeInternalOrCustomType(componentType, - value.get(i), connectorTracker); - Array.set(array, i, decodedValue); - } - return array; - } - - /** - * Decodes a value that is of an internal type. - * <p> - * Ensures the encoded value is of the same type as target type. - * </p> - * <p> - * Allows restricting collections so that they must be declared using - * generics. If this is used then all objects in the collection are encoded - * using the declared type. Otherwise only internal types are allowed in - * collections. - * </p> - * - * @param targetType - * The type that should be returned by this method - * @param valueAndType - * The encoded value and type array - * @param application - * A reference to the application - * @param enforceGenericsInCollections - * true if generics should be enforce, false to only allow - * internal types in collections - * @return - * @throws JSONException - */ - public static Object decodeInternalType(Type targetType, - boolean restrictToInternalTypes, Object encodedJsonValue, - ConnectorTracker connectorTracker) throws JSONException { - if (!isInternalType(targetType)) { - throw new JSONException("Type " + targetType - + " is not a supported internal type."); - } - String transportType = getInternalTransportType(targetType); - - if (encodedJsonValue == JSONObject.NULL) { - return null; - } - - // UidlValue - if (targetType == UidlValue.class) { - return decodeUidlValue((JSONArray) encodedJsonValue, - connectorTracker); - } - - // Collections - if (JsonEncoder.VTYPE_LIST.equals(transportType)) { - return decodeList(targetType, restrictToInternalTypes, - (JSONArray) encodedJsonValue, connectorTracker); - } else if (JsonEncoder.VTYPE_SET.equals(transportType)) { - return decodeSet(targetType, restrictToInternalTypes, - (JSONArray) encodedJsonValue, connectorTracker); - } else if (JsonEncoder.VTYPE_MAP.equals(transportType)) { - return decodeMap(targetType, restrictToInternalTypes, - encodedJsonValue, connectorTracker); - } - - // Arrays - if (JsonEncoder.VTYPE_ARRAY.equals(transportType)) { - - return decodeObjectArray(targetType, (JSONArray) encodedJsonValue, - connectorTracker); - - } else if (JsonEncoder.VTYPE_STRINGARRAY.equals(transportType)) { - return decodeStringArray((JSONArray) encodedJsonValue); - } - - // Special Vaadin types - - String stringValue = String.valueOf(encodedJsonValue); - - if (JsonEncoder.VTYPE_CONNECTOR.equals(transportType)) { - return connectorTracker.getConnector(stringValue); - } - - // Legacy types - - if (JsonEncoder.VTYPE_STRING.equals(transportType)) { - return stringValue; - } else if (JsonEncoder.VTYPE_INTEGER.equals(transportType)) { - return Integer.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_LONG.equals(transportType)) { - return Long.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_FLOAT.equals(transportType)) { - return Float.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_DOUBLE.equals(transportType)) { - return Double.valueOf(stringValue); - } else if (JsonEncoder.VTYPE_BOOLEAN.equals(transportType)) { - return Boolean.valueOf(stringValue); - } - - throw new JSONException("Unknown type " + transportType); - } - - private static UidlValue decodeUidlValue(JSONArray encodedJsonValue, - ConnectorTracker connectorTracker) throws JSONException { - String type = encodedJsonValue.getString(0); - - Object decodedValue = decodeInternalType(getType(type), true, - encodedJsonValue.get(1), connectorTracker); - return new UidlValue(decodedValue); - } - - private static boolean transportTypesCompatible( - String encodedTransportType, String transportType) { - if (encodedTransportType == null) { - return false; - } - if (encodedTransportType.equals(transportType)) { - return true; - } - if (encodedTransportType.equals(JsonEncoder.VTYPE_NULL)) { - return true; - } - - return false; - } - - private static Map<Object, Object> decodeMap(Type targetType, - boolean restrictToInternalTypes, Object jsonMap, - ConnectorTracker connectorTracker) throws JSONException { - if (jsonMap instanceof JSONArray) { - // Client-side has no declared type information to determine - // encoding method for empty maps, so these are handled separately. - // See #8906. - JSONArray jsonArray = (JSONArray) jsonMap; - if (jsonArray.length() == 0) { - return new HashMap<Object, Object>(); - } - } - - if (!restrictToInternalTypes && targetType instanceof ParameterizedType) { - Type keyType = ((ParameterizedType) targetType) - .getActualTypeArguments()[0]; - Type valueType = ((ParameterizedType) targetType) - .getActualTypeArguments()[1]; - if (keyType == String.class) { - return decodeStringMap(valueType, (JSONObject) jsonMap, - connectorTracker); - } else if (keyType == Connector.class) { - return decodeConnectorMap(valueType, (JSONObject) jsonMap, - connectorTracker); - } else { - return decodeObjectMap(keyType, valueType, (JSONArray) jsonMap, - connectorTracker); - } - } else { - return decodeStringMap(UidlValue.class, (JSONObject) jsonMap, - connectorTracker); - } - } - - private static Map<Object, Object> decodeObjectMap(Type keyType, - Type valueType, JSONArray jsonMap, ConnectorTracker connectorTracker) - throws JSONException { - Map<Object, Object> map = new HashMap<Object, Object>(); - - JSONArray keys = jsonMap.getJSONArray(0); - JSONArray values = jsonMap.getJSONArray(1); - - assert (keys.length() == values.length()); - - for (int i = 0; i < keys.length(); i++) { - Object key = decodeInternalOrCustomType(keyType, keys.get(i), - connectorTracker); - Object value = decodeInternalOrCustomType(valueType, values.get(i), - connectorTracker); - - map.put(key, value); - } - - return map; - } - - private static Map<Object, Object> decodeConnectorMap(Type valueType, - JSONObject jsonMap, ConnectorTracker connectorTracker) - throws JSONException { - Map<Object, Object> map = new HashMap<Object, Object>(); - - for (Iterator<?> iter = jsonMap.keys(); iter.hasNext();) { - String key = (String) iter.next(); - Object value = decodeInternalOrCustomType(valueType, - jsonMap.get(key), connectorTracker); - if (valueType == UidlValue.class) { - value = ((UidlValue) value).getValue(); - } - map.put(connectorTracker.getConnector(key), value); - } - - return map; - } - - private static Map<Object, Object> decodeStringMap(Type valueType, - JSONObject jsonMap, ConnectorTracker connectorTracker) - throws JSONException { - Map<Object, Object> map = new HashMap<Object, Object>(); - - for (Iterator<?> iter = jsonMap.keys(); iter.hasNext();) { - String key = (String) iter.next(); - Object value = decodeInternalOrCustomType(valueType, - jsonMap.get(key), connectorTracker); - if (valueType == UidlValue.class) { - value = ((UidlValue) value).getValue(); - } - map.put(key, value); - } - - return map; - } - - /** - * @param targetType - * @param restrictToInternalTypes - * @param typeIndex - * The index of a generic type to use to define the child type - * that should be decoded - * @param encodedValueAndType - * @param application - * @return - * @throws JSONException - */ - private static Object decodeParametrizedType(Type targetType, - boolean restrictToInternalTypes, int typeIndex, Object value, - ConnectorTracker connectorTracker) throws JSONException { - if (!restrictToInternalTypes && targetType instanceof ParameterizedType) { - Type childType = ((ParameterizedType) targetType) - .getActualTypeArguments()[typeIndex]; - // Only decode the given type - return decodeInternalOrCustomType(childType, value, - connectorTracker); - } else { - // Only UidlValue when not enforcing a given type to avoid security - // issues - UidlValue decodeInternalType = (UidlValue) decodeInternalType( - UidlValue.class, true, value, connectorTracker); - return decodeInternalType.getValue(); - } - } - - private static Object decodeEnum(Class<? extends Enum> cls, JSONObject value) { - String enumIdentifier = String.valueOf(value); - return Enum.valueOf(cls, enumIdentifier); - } - - private static String[] decodeStringArray(JSONArray jsonArray) - throws JSONException { - int length = jsonArray.length(); - List<String> tokens = new ArrayList<String>(length); - for (int i = 0; i < length; ++i) { - tokens.add(jsonArray.getString(i)); - } - return tokens.toArray(new String[tokens.size()]); - } - - private static Object[] decodeObjectArray(Type targetType, - JSONArray jsonArray, ConnectorTracker connectorTracker) - throws JSONException { - List list = decodeList(List.class, true, jsonArray, connectorTracker); - return list.toArray(new Object[list.size()]); - } - - private static List<Object> decodeList(Type targetType, - boolean restrictToInternalTypes, JSONArray jsonArray, - ConnectorTracker connectorTracker) throws JSONException { - List<Object> list = new ArrayList<Object>(); - for (int i = 0; i < jsonArray.length(); ++i) { - // each entry always has two elements: type and value - Object encodedValue = jsonArray.get(i); - Object decodedChild = decodeParametrizedType(targetType, - restrictToInternalTypes, 0, encodedValue, connectorTracker); - list.add(decodedChild); - } - return list; - } - - private static Set<Object> decodeSet(Type targetType, - boolean restrictToInternalTypes, JSONArray jsonArray, - ConnectorTracker connectorTracker) throws JSONException { - HashSet<Object> set = new HashSet<Object>(); - set.addAll(decodeList(targetType, restrictToInternalTypes, jsonArray, - connectorTracker)); - return set; - } - - /** - * Returns the name that should be used as field name in the JSON. We strip - * "set" from the setter, keeping the result - this is easy to do on both - * server and client, avoiding some issues with cASE. E.g setZIndex() - * becomes "zIndex". Also ensures that both getter and setter are present, - * returning null otherwise. - * - * @param pd - * @return the name to be used or null if both getter and setter are not - * found. - */ - static String getTransportFieldName(PropertyDescriptor pd) { - if (pd.getReadMethod() == null || pd.getWriteMethod() == null) { - return null; - } - String fieldName = pd.getWriteMethod().getName().substring(3); - fieldName = Character.toLowerCase(fieldName.charAt(0)) - + fieldName.substring(1); - return fieldName; - } - - private static Object decodeObject(Type targetType, - JSONObject serializedObject, ConnectorTracker connectorTracker) - throws JSONException { - - Class<?> targetClass = getClassForType(targetType); - if (Enum.class.isAssignableFrom(targetClass)) { - return decodeEnum(targetClass.asSubclass(Enum.class), - serializedObject); - } - - try { - Object decodedObject = targetClass.newInstance(); - for (PropertyDescriptor pd : Introspector.getBeanInfo(targetClass) - .getPropertyDescriptors()) { - - String fieldName = getTransportFieldName(pd); - if (fieldName == null) { - continue; - } - Object encodedFieldValue = serializedObject.get(fieldName); - Type fieldType = pd.getReadMethod().getGenericReturnType(); - Object decodedFieldValue = decodeInternalOrCustomType( - fieldType, encodedFieldValue, connectorTracker); - - pd.getWriteMethod().invoke(decodedObject, decodedFieldValue); - } - - return decodedObject; - } catch (IllegalArgumentException e) { - throw new JSONException(e); - } catch (IllegalAccessException e) { - throw new JSONException(e); - } catch (InvocationTargetException e) { - throw new JSONException(e); - } catch (InstantiationException e) { - throw new JSONException(e); - } catch (IntrospectionException e) { - throw new JSONException(e); - } - } - - public static Object encode(Object value, Object referenceValue, - Type valueType, ConnectorTracker connectorTracker) - throws JSONException { - - if (valueType == null) { - throw new IllegalArgumentException("type must be defined"); - } - - if (valueType instanceof WildcardType) { - throw new IllegalStateException( - "Can not serialize type with wildcard: " + valueType); - } - - if (null == value) { - return encodeNull(); - } - - if (value instanceof String[]) { - String[] array = (String[]) value; - JSONArray jsonArray = new JSONArray(); - for (int i = 0; i < array.length; ++i) { - jsonArray.put(array[i]); - } - return jsonArray; - } else if (value instanceof String) { - return value; - } else if (value instanceof Boolean) { - return value; - } else if (value instanceof Number) { - return value; - } else if (value instanceof Character) { - // Character is not a Number - return value; - } else if (value instanceof Collection) { - Collection<?> collection = (Collection<?>) value; - JSONArray jsonArray = encodeCollection(valueType, collection, - connectorTracker); - return jsonArray; - } else if (valueType instanceof Class<?> - && ((Class<?>) valueType).isArray()) { - JSONArray jsonArray = encodeArrayContents( - ((Class<?>) valueType).getComponentType(), value, - connectorTracker); - return jsonArray; - } else if (valueType instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) valueType) - .getGenericComponentType(); - JSONArray jsonArray = encodeArrayContents(componentType, value, - connectorTracker); - return jsonArray; - } else if (value instanceof Map) { - Object jsonMap = encodeMap(valueType, (Map<?, ?>) value, - connectorTracker); - return jsonMap; - } else if (value instanceof Connector) { - Connector connector = (Connector) value; - if (value instanceof Component - && !(AbstractCommunicationManager - .isVisible((Component) value))) { - return encodeNull(); - } - return connector.getConnectorId(); - } else if (value instanceof Enum) { - return encodeEnum((Enum<?>) value, connectorTracker); - } else if (value instanceof JSONArray || value instanceof JSONObject) { - return value; - } else { - // Any object that we do not know how to encode we encode by looping - // through fields - return encodeObject(value, referenceValue, connectorTracker); - } - } - - private static Object encodeNull() { - return JSONObject.NULL; - } - - private static Object encodeObject(Object value, Object referenceValue, - ConnectorTracker connectorTracker) throws JSONException { - JSONObject jsonMap = new JSONObject(); - - try { - for (PropertyDescriptor pd : Introspector.getBeanInfo( - value.getClass()).getPropertyDescriptors()) { - String fieldName = getTransportFieldName(pd); - if (fieldName == null) { - continue; - } - Method getterMethod = pd.getReadMethod(); - // We can't use PropertyDescriptor.getPropertyType() as it does - // not support generics - Type fieldType = getterMethod.getGenericReturnType(); - Object fieldValue = getterMethod.invoke(value, (Object[]) null); - boolean equals = false; - Object referenceFieldValue = null; - if (referenceValue != null) { - referenceFieldValue = getterMethod.invoke(referenceValue, - (Object[]) null); - equals = equals(fieldValue, referenceFieldValue); - } - if (!equals) { - if (jsonMap.has(fieldName)) { - throw new RuntimeException( - "Can't encode " - + value.getClass().getName() - + " as it has multiple fields with the name " - + fieldName.toLowerCase() - + ". This can happen if only casing distinguishes one property name from another."); - } - jsonMap.put( - fieldName, - encode(fieldValue, referenceFieldValue, fieldType, - connectorTracker)); - // } else { - // System.out.println("Skipping field " + fieldName - // + " of type " + fieldType.getName() - // + " for object " + value.getClass().getName() - // + " as " + fieldValue + "==" + referenceFieldValue); - } - } - } catch (Exception e) { - // TODO: Should exceptions be handled in a different way? - throw new JSONException(e); - } - return jsonMap; - } - - /** - * Compares the value with the reference. If they match, returns true. - * - * @param fieldValue - * @param referenceValue - * @return - */ - private static boolean equals(Object fieldValue, Object referenceValue) { - if (fieldValue == null) { - return referenceValue == null; - } - - if (fieldValue.equals(referenceValue)) { - return true; - } - - return false; - } - - private static String encodeEnum(Enum<?> e, - ConnectorTracker connectorTracker) throws JSONException { - return e.name(); - } - - private static JSONArray encodeArrayContents(Type componentType, - Object array, ConnectorTracker connectorTracker) - throws JSONException { - JSONArray jsonArray = new JSONArray(); - for (int i = 0; i < Array.getLength(array); i++) { - jsonArray.put(encode(Array.get(array, i), null, componentType, - connectorTracker)); - } - return jsonArray; - } - - private static JSONArray encodeCollection(Type targetType, - Collection collection, ConnectorTracker connectorTracker) - throws JSONException { - JSONArray jsonArray = new JSONArray(); - for (Object o : collection) { - jsonArray.put(encodeChild(targetType, 0, o, connectorTracker)); - } - return jsonArray; - } - - private static Object encodeChild(Type targetType, int typeIndex, Object o, - ConnectorTracker connectorTracker) throws JSONException { - if (targetType instanceof ParameterizedType) { - Type childType = ((ParameterizedType) targetType) - .getActualTypeArguments()[typeIndex]; - // Encode using the given type - return encode(o, null, childType, connectorTracker); - } else { - throw new JSONException("Collection is missing generics"); - } - } - - private static Object encodeMap(Type mapType, Map<?, ?> map, - ConnectorTracker connectorTracker) throws JSONException { - Type keyType, valueType; - - if (mapType instanceof ParameterizedType) { - keyType = ((ParameterizedType) mapType).getActualTypeArguments()[0]; - valueType = ((ParameterizedType) mapType).getActualTypeArguments()[1]; - } else { - throw new JSONException("Map is missing generics"); - } - - if (map.isEmpty()) { - // Client -> server encodes empty map as an empty array because of - // #8906. Do the same for server -> client to maintain symmetry. - return new JSONArray(); - } - - if (keyType == String.class) { - return encodeStringMap(valueType, map, connectorTracker); - } else if (keyType == Connector.class) { - return encodeConnectorMap(valueType, map, connectorTracker); - } else { - return encodeObjectMap(keyType, valueType, map, connectorTracker); - } - } - - private static JSONArray encodeObjectMap(Type keyType, Type valueType, - Map<?, ?> map, ConnectorTracker connectorTracker) - throws JSONException { - JSONArray keys = new JSONArray(); - JSONArray values = new JSONArray(); - - for (Entry<?, ?> entry : map.entrySet()) { - Object encodedKey = encode(entry.getKey(), null, keyType, - connectorTracker); - Object encodedValue = encode(entry.getValue(), null, valueType, - connectorTracker); - - keys.put(encodedKey); - values.put(encodedValue); - } - - return new JSONArray(Arrays.asList(keys, values)); - } - - private static JSONObject encodeConnectorMap(Type valueType, Map<?, ?> map, - ConnectorTracker connectorTracker) throws JSONException { - JSONObject jsonMap = new JSONObject(); - - for (Entry<?, ?> entry : map.entrySet()) { - Connector key = (Connector) entry.getKey(); - Object encodedValue = encode(entry.getValue(), null, valueType, - connectorTracker); - jsonMap.put(key.getConnectorId(), encodedValue); - } - - return jsonMap; - } - - private static JSONObject encodeStringMap(Type valueType, Map<?, ?> map, - ConnectorTracker connectorTracker) throws JSONException { - JSONObject jsonMap = new JSONObject(); - - for (Entry<?, ?> entry : map.entrySet()) { - String key = (String) entry.getKey(); - Object encodedValue = encode(entry.getValue(), null, valueType, - connectorTracker); - jsonMap.put(key, encodedValue); - } - - return jsonMap; - } - - /** - * Gets the transport type for the given class. Returns null if no transport - * type can be found. - * - * @param valueType - * The type that should be transported - * @return - * @throws JSONException - */ - private static String getInternalTransportType(Type valueType) { - return typeToTransportType.get(getClassForType(valueType)); - } - - private static String getCustomTransportType(Class<?> targetType) { - return targetType.getName(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java b/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java deleted file mode 100644 index 5a830ddb63..0000000000 --- a/src/com/vaadin/terminal/gwt/server/JsonPaintTarget.java +++ /dev/null @@ -1,1022 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.Vector; -import java.util.logging.Logger; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.StreamVariable; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.ui.Alignment; -import com.vaadin.ui.Component; -import com.vaadin.ui.CustomLayout; - -/** - * User Interface Description Language Target. - * - * TODO document better: role of this class, UIDL format, attributes, variables, - * etc. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -@SuppressWarnings("serial") -public class JsonPaintTarget implements PaintTarget { - - /* Document type declarations */ - - private final static String UIDL_ARG_NAME = "name"; - - private final Stack<String> mOpenTags; - - private final Stack<JsonTag> openJsonTags; - - // these match each other element-wise - private final Stack<ClientConnector> openPaintables; - private final Stack<String> openPaintableTags; - - private final PrintWriter uidlBuffer; - - private boolean closed = false; - - private final AbstractCommunicationManager manager; - - private int changes = 0; - - private final Set<Object> usedResources = new HashSet<Object>(); - - private boolean customLayoutArgumentsOpen = false; - - private JsonTag tag; - - private boolean cacheEnabled = false; - - private final Set<Class<? extends ClientConnector>> usedClientConnectors = new HashSet<Class<? extends ClientConnector>>(); - - /** - * Creates a new JsonPaintTarget. - * - * @param manager - * @param outWriter - * A character-output stream. - * @param cachingRequired - * true if this is not a full repaint, i.e. caches are to be - * used. - * @throws PaintException - * if the paint operation failed. - */ - public JsonPaintTarget(AbstractCommunicationManager manager, - PrintWriter outWriter, boolean cachingRequired) - throws PaintException { - - this.manager = manager; - - // Sets the target for UIDL writing - uidlBuffer = outWriter; - - // Initialize tag-writing - mOpenTags = new Stack<String>(); - openJsonTags = new Stack<JsonTag>(); - - openPaintables = new Stack<ClientConnector>(); - openPaintableTags = new Stack<String>(); - - cacheEnabled = cachingRequired; - } - - @Override - public void startTag(String tagName) throws PaintException { - startTag(tagName, false); - } - - /** - * Prints the element start tag. - * - * <pre> - * Todo: - * Checking of input values - * - * </pre> - * - * @param tagName - * the name of the start tag. - * @throws PaintException - * if the paint operation failed. - * - */ - public void startTag(String tagName, boolean isChildNode) - throws PaintException { - // In case of null data output nothing: - if (tagName == null) { - throw new NullPointerException(); - } - - // Ensures that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - if (tag != null) { - openJsonTags.push(tag); - } - // Checks tagName and attributes here - mOpenTags.push(tagName); - - tag = new JsonTag(tagName); - - customLayoutArgumentsOpen = false; - - } - - /** - * Prints the element end tag. - * - * If the parent tag is closed before every child tag is closed an - * PaintException is raised. - * - * @param tag - * the name of the end tag. - * @throws Paintexception - * if the paint operation failed. - */ - - @Override - public void endTag(String tagName) throws PaintException { - // In case of null data output nothing: - if (tagName == null) { - throw new NullPointerException(); - } - - // Ensure that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - if (openJsonTags.size() > 0) { - final JsonTag parent = openJsonTags.pop(); - - String lastTag = ""; - - lastTag = mOpenTags.pop(); - if (!tagName.equalsIgnoreCase(lastTag)) { - throw new PaintException("Invalid UIDL: wrong ending tag: '" - + tagName + "' expected: '" + lastTag + "'."); - } - - parent.addData(tag.getJSON()); - - tag = parent; - } else { - changes++; - uidlBuffer.print(((changes > 1) ? "," : "") + tag.getJSON()); - tag = null; - } - } - - /** - * Substitutes the XML sensitive characters with predefined XML entities. - * - * @param xml - * the String to be substituted. - * @return A new string instance where all occurrences of XML sensitive - * characters are substituted with entities. - */ - static public String escapeXML(String xml) { - if (xml == null || xml.length() <= 0) { - return ""; - } - return escapeXML(new StringBuilder(xml)).toString(); - } - - /** - * Substitutes the XML sensitive characters with predefined XML entities. - * - * @param xml - * the String to be substituted. - * @return A new StringBuilder instance where all occurrences of XML - * sensitive characters are substituted with entities. - * - */ - static StringBuilder escapeXML(StringBuilder xml) { - if (xml == null || xml.length() <= 0) { - return new StringBuilder(""); - } - - final StringBuilder result = new StringBuilder(xml.length() * 2); - - for (int i = 0; i < xml.length(); i++) { - final char c = xml.charAt(i); - final String s = toXmlChar(c); - if (s != null) { - result.append(s); - } else { - result.append(c); - } - } - return result; - } - - /** - * Escapes the given string so it can safely be used as a JSON string. - * - * @param s - * The string to escape - * @return Escaped version of the string - */ - static public String escapeJSON(String s) { - // FIXME: Move this method to another class as other classes use it - // also. - if (s == null) { - return ""; - } - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < s.length(); i++) { - final char ch = s.charAt(i); - switch (ch) { - case '"': - sb.append("\\\""); - break; - case '\\': - sb.append("\\\\"); - break; - case '\b': - sb.append("\\b"); - break; - case '\f': - sb.append("\\f"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\t': - sb.append("\\t"); - break; - case '/': - sb.append("\\/"); - break; - default: - if (ch >= '\u0000' && ch <= '\u001F') { - final String ss = Integer.toHexString(ch); - sb.append("\\u"); - for (int k = 0; k < 4 - ss.length(); k++) { - sb.append('0'); - } - sb.append(ss.toUpperCase()); - } else { - sb.append(ch); - } - } - } - return sb.toString(); - } - - /** - * Substitutes a XML sensitive character with predefined XML entity. - * - * @param c - * the Character to be replaced with an entity. - * @return String of the entity or null if character is not to be replaced - * with an entity. - */ - private static String toXmlChar(char c) { - switch (c) { - case '&': - return "&"; // & => & - case '>': - return ">"; // > => > - case '<': - return "<"; // < => < - case '"': - return """; // " => " - case '\'': - return "'"; // ' => ' - default: - return null; - } - } - - /** - * Prints XML-escaped text. - * - * @param str - * @throws PaintException - * if the paint operation failed. - * - */ - - @Override - public void addText(String str) throws PaintException { - tag.addData("\"" + escapeJSON(str) + "\""); - } - - @Override - public void addAttribute(String name, boolean value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + (value ? "true" : "false")); - } - - @Override - public void addAttribute(String name, Resource value) throws PaintException { - if (value == null) { - throw new NullPointerException(); - } - ResourceReference reference = ResourceReference.create(value); - addAttribute(name, reference.getURL()); - } - - @Override - public void addAttribute(String name, int value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, long value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, float value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, double value) throws PaintException { - tag.addAttribute("\"" + name + "\":" + String.valueOf(value)); - } - - @Override - public void addAttribute(String name, String value) throws PaintException { - // In case of null data output nothing: - if ((value == null) || (name == null)) { - throw new NullPointerException( - "Parameters must be non-null strings"); - } - - tag.addAttribute("\"" + name + "\":\"" + escapeJSON(value) + "\""); - - if (customLayoutArgumentsOpen && "template".equals(name)) { - getUsedResources().add("layouts/" + value + ".html"); - } - - if (name.equals("locale")) { - manager.requireLocale(value); - } - - } - - @Override - public void addAttribute(String name, Component value) - throws PaintException { - final String id = value.getConnectorId(); - addAttribute(name, id); - } - - @Override - public void addAttribute(String name, Map<?, ?> value) - throws PaintException { - - StringBuilder sb = new StringBuilder(); - sb.append("\""); - sb.append(name); - sb.append("\":"); - sb.append("{"); - for (Iterator<?> it = value.keySet().iterator(); it.hasNext();) { - Object key = it.next(); - Object mapValue = value.get(key); - sb.append("\""); - if (key instanceof ClientConnector) { - sb.append(((ClientConnector) key).getConnectorId()); - } else { - sb.append(escapeJSON(key.toString())); - } - sb.append("\":"); - if (mapValue instanceof Float || mapValue instanceof Integer - || mapValue instanceof Double - || mapValue instanceof Boolean - || mapValue instanceof Alignment) { - sb.append(mapValue); - } else { - sb.append("\""); - sb.append(escapeJSON(mapValue.toString())); - sb.append("\""); - } - if (it.hasNext()) { - sb.append(","); - } - } - sb.append("}"); - - tag.addAttribute(sb.toString()); - } - - @Override - public void addAttribute(String name, Object[] values) { - // In case of null data output nothing: - if ((values == null) || (name == null)) { - throw new NullPointerException( - "Parameters must be non-null strings"); - } - final StringBuilder buf = new StringBuilder(); - buf.append("\"" + name + "\":["); - for (int i = 0; i < values.length; i++) { - if (i > 0) { - buf.append(","); - } - buf.append("\""); - buf.append(escapeJSON(values[i].toString())); - buf.append("\""); - } - buf.append("]"); - tag.addAttribute(buf.toString()); - } - - @Override - public void addVariable(VariableOwner owner, String name, String value) - throws PaintException { - tag.addVariable(new StringVariable(owner, name, escapeJSON(value))); - } - - @Override - public void addVariable(VariableOwner owner, String name, Component value) - throws PaintException { - tag.addVariable(new StringVariable(owner, name, value.getConnectorId())); - } - - @Override - public void addVariable(VariableOwner owner, String name, int value) - throws PaintException { - tag.addVariable(new IntVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, long value) - throws PaintException { - tag.addVariable(new LongVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, float value) - throws PaintException { - tag.addVariable(new FloatVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, double value) - throws PaintException { - tag.addVariable(new DoubleVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, boolean value) - throws PaintException { - tag.addVariable(new BooleanVariable(owner, name, value)); - } - - @Override - public void addVariable(VariableOwner owner, String name, String[] value) - throws PaintException { - tag.addVariable(new ArrayVariable(owner, name, value)); - } - - /** - * Adds a upload stream type variable. - * - * TODO not converted for JSON - * - * @param owner - * the Listener for variable changes. - * @param name - * the Variable name. - * - * @throws PaintException - * if the paint operation failed. - */ - - @Override - public void addUploadStreamVariable(VariableOwner owner, String name) - throws PaintException { - startTag("uploadstream"); - addAttribute(UIDL_ARG_NAME, name); - endTag("uploadstream"); - } - - /** - * Prints the single text section. - * - * Prints full text section. The section data is escaped - * - * @param sectionTagName - * the name of the tag. - * @param sectionData - * the section data to be printed. - * @throws PaintException - * if the paint operation failed. - */ - - @Override - public void addSection(String sectionTagName, String sectionData) - throws PaintException { - tag.addData("{\"" + sectionTagName + "\":\"" + escapeJSON(sectionData) - + "\"}"); - } - - /** - * Adds XML directly to UIDL. - * - * @param xml - * the Xml to be added. - * @throws PaintException - * if the paint operation failed. - */ - - @Override - public void addUIDL(String xml) throws PaintException { - - // Ensure that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - // Make sure that the open start tag is closed before - // anything is written. - - // Escape and write what was given - if (xml != null) { - tag.addData("\"" + escapeJSON(xml) + "\""); - } - - } - - /** - * Adds XML section with namespace. - * - * @param sectionTagName - * the name of the tag. - * @param sectionData - * the section data. - * @param namespace - * the namespace to be added. - * @throws PaintException - * if the paint operation failed. - * - * @see com.vaadin.terminal.PaintTarget#addXMLSection(String, String, - * String) - */ - - @Override - public void addXMLSection(String sectionTagName, String sectionData, - String namespace) throws PaintException { - - // Ensure that the target is open - if (closed) { - throw new PaintException( - "Attempted to write to a closed PaintTarget."); - } - - startTag(sectionTagName); - if (namespace != null) { - addAttribute("xmlns", namespace); - } - - if (sectionData != null) { - tag.addData("\"" + escapeJSON(sectionData) + "\""); - } - endTag(sectionTagName); - } - - /** - * Gets the UIDL already printed to stream. Paint target must be closed - * before the <code>getUIDL</code> can be called. - * - * @return the UIDL. - */ - public String getUIDL() { - if (closed) { - return uidlBuffer.toString(); - } - throw new IllegalStateException( - "Tried to read UIDL from open PaintTarget"); - } - - /** - * Closes the paint target. Paint target must be closed before the - * <code>getUIDL</code> can be called. Subsequent attempts to write to paint - * target. If the target was already closed, call to this function is - * ignored. will generate an exception. - * - * @throws PaintException - * if the paint operation failed. - */ - public void close() throws PaintException { - if (tag != null) { - uidlBuffer.write(tag.getJSON()); - } - flush(); - closed = true; - } - - /** - * Method flush. - */ - private void flush() { - uidlBuffer.flush(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.PaintTarget#startPaintable(com.vaadin.terminal - * .Paintable, java.lang.String) - */ - - @Override - public PaintStatus startPaintable(Component connector, String tagName) - throws PaintException { - boolean topLevelPaintable = openPaintables.isEmpty(); - - getLogger().fine( - "startPaintable for " + connector.getClass().getName() + "@" - + Integer.toHexString(connector.hashCode())); - startTag(tagName, true); - - openPaintables.push(connector); - openPaintableTags.push(tagName); - - addAttribute("id", connector.getConnectorId()); - - // Only paint top level paintables. All sub paintables are marked as - // queued and painted separately later. - if (!topLevelPaintable) { - return PaintStatus.CACHED; - } - - if (connector instanceof CustomLayout) { - customLayoutArgumentsOpen = true; - } - return PaintStatus.PAINTING; - } - - @Override - public void endPaintable(Component paintable) throws PaintException { - getLogger().fine( - "endPaintable for " + paintable.getClass().getName() + "@" - + Integer.toHexString(paintable.hashCode())); - - ClientConnector openPaintable = openPaintables.peek(); - if (paintable != openPaintable) { - throw new PaintException("Invalid UIDL: closing wrong paintable: '" - + paintable.getConnectorId() + "' expected: '" - + openPaintable.getConnectorId() + "'."); - } - // remove paintable from the stack - openPaintables.pop(); - String openTag = openPaintableTags.pop(); - endTag(openTag); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.PaintTarget#addCharacterData(java.lang.String ) - */ - - @Override - public void addCharacterData(String text) throws PaintException { - if (text != null) { - tag.addData(text); - } - } - - /** - * This is basically a container for UI components variables, that will be - * added at the end of JSON object. - * - * @author mattitahvonen - * - */ - class JsonTag implements Serializable { - boolean firstField = false; - - Vector<Object> variables = new Vector<Object>(); - - Vector<Object> children = new Vector<Object>(); - - Vector<Object> attr = new Vector<Object>(); - - StringBuilder data = new StringBuilder(); - - public boolean childrenArrayOpen = false; - - private boolean childNode = false; - - private boolean tagClosed = false; - - public JsonTag(String tagName) { - data.append("[\"" + tagName + "\""); - } - - private void closeTag() { - if (!tagClosed) { - data.append(attributesAsJsonObject()); - data.append(getData()); - // Writes the end (closing) tag - data.append("]"); - tagClosed = true; - } - } - - public String getJSON() { - if (!tagClosed) { - closeTag(); - } - return data.toString(); - } - - public void openChildrenArray() { - if (!childrenArrayOpen) { - // append("c : ["); - childrenArrayOpen = true; - // firstField = true; - } - } - - public void closeChildrenArray() { - // append("]"); - // firstField = false; - } - - public void setChildNode(boolean b) { - childNode = b; - } - - public boolean isChildNode() { - return childNode; - } - - public String startField() { - if (firstField) { - firstField = false; - return ""; - } else { - return ","; - } - } - - /** - * - * @param s - * json string, object or array - */ - public void addData(String s) { - children.add(s); - } - - public String getData() { - final StringBuilder buf = new StringBuilder(); - final Iterator<Object> it = children.iterator(); - while (it.hasNext()) { - buf.append(startField()); - buf.append(it.next()); - } - return buf.toString(); - } - - public void addAttribute(String jsonNode) { - attr.add(jsonNode); - } - - private String attributesAsJsonObject() { - final StringBuilder buf = new StringBuilder(); - buf.append(startField()); - buf.append("{"); - for (final Iterator<Object> iter = attr.iterator(); iter.hasNext();) { - final String element = (String) iter.next(); - buf.append(element); - if (iter.hasNext()) { - buf.append(","); - } - } - buf.append(tag.variablesAsJsonObject()); - buf.append("}"); - return buf.toString(); - } - - public void addVariable(Variable v) { - variables.add(v); - } - - private String variablesAsJsonObject() { - if (variables.size() == 0) { - return ""; - } - final StringBuilder buf = new StringBuilder(); - buf.append(startField()); - buf.append("\"v\":{"); - final Iterator<Object> iter = variables.iterator(); - while (iter.hasNext()) { - final Variable element = (Variable) iter.next(); - buf.append(element.getJsonPresentation()); - if (iter.hasNext()) { - buf.append(","); - } - } - buf.append("}"); - return buf.toString(); - } - } - - abstract class Variable implements Serializable { - - String name; - - public abstract String getJsonPresentation(); - } - - class BooleanVariable extends Variable implements Serializable { - boolean value; - - public BooleanVariable(VariableOwner owner, String name, boolean v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + (value == true ? "true" : "false"); - } - - } - - class StringVariable extends Variable implements Serializable { - String value; - - public StringVariable(VariableOwner owner, String name, String v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":\"" + value + "\""; - } - - } - - class IntVariable extends Variable implements Serializable { - int value; - - public IntVariable(VariableOwner owner, String name, int v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class LongVariable extends Variable implements Serializable { - long value; - - public LongVariable(VariableOwner owner, String name, long v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class FloatVariable extends Variable implements Serializable { - float value; - - public FloatVariable(VariableOwner owner, String name, float v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class DoubleVariable extends Variable implements Serializable { - double value; - - public DoubleVariable(VariableOwner owner, String name, double v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - return "\"" + name + "\":" + value; - } - } - - class ArrayVariable extends Variable implements Serializable { - String[] value; - - public ArrayVariable(VariableOwner owner, String name, String[] v) { - value = v; - this.name = name; - } - - @Override - public String getJsonPresentation() { - StringBuilder sb = new StringBuilder(); - sb.append("\""); - sb.append(name); - sb.append("\":["); - for (int i = 0; i < value.length;) { - sb.append("\""); - sb.append(escapeJSON(value[i])); - sb.append("\""); - i++; - if (i < value.length) { - sb.append(","); - } - } - sb.append("]"); - return sb.toString(); - } - } - - public Set<Object> getUsedResources() { - return usedResources; - } - - @Override - @SuppressWarnings("unchecked") - public String getTag(ClientConnector clientConnector) { - Class<? extends ClientConnector> clientConnectorClass = clientConnector - .getClass(); - while (clientConnectorClass.isAnonymousClass()) { - clientConnectorClass = (Class<? extends ClientConnector>) clientConnectorClass - .getSuperclass(); - } - Class<?> clazz = clientConnectorClass; - while (!usedClientConnectors.contains(clazz) - && clazz.getSuperclass() != null - && ClientConnector.class.isAssignableFrom(clazz)) { - usedClientConnectors.add((Class<? extends ClientConnector>) clazz); - clazz = clazz.getSuperclass(); - } - return manager.getTagForType(clientConnectorClass); - } - - Collection<Class<? extends ClientConnector>> getUsedClientConnectors() { - return usedClientConnectors; - } - - @Override - public void addVariable(VariableOwner owner, String name, - StreamVariable value) throws PaintException { - String url = manager.getStreamVariableTargetUrl( - (ClientConnector) owner, name, value); - if (url != null) { - addVariable(owner, name, url); - } // else { //NOP this was just a cleanup by component } - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.PaintTarget#isFullRepaint() - */ - - @Override - public boolean isFullRepaint() { - return !cacheEnabled; - } - - private static final Logger getLogger() { - return Logger.getLogger(JsonPaintTarget.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java b/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java deleted file mode 100644 index 9dba05d2c1..0000000000 --- a/src/com/vaadin/terminal/gwt/server/LegacyChangeVariablesInvocation.java +++ /dev/null @@ -1,38 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.util.HashMap; -import java.util.Map; - -import com.vaadin.shared.communication.MethodInvocation; -import com.vaadin.terminal.gwt.client.ApplicationConnection; - -public class LegacyChangeVariablesInvocation extends MethodInvocation { - private Map<String, Object> variableChanges = new HashMap<String, Object>(); - - public LegacyChangeVariablesInvocation(String connectorId, - String variableName, Object value) { - super(connectorId, ApplicationConnection.UPDATE_VARIABLE_INTERFACE, - ApplicationConnection.UPDATE_VARIABLE_METHOD); - setVariableChange(variableName, value); - } - - public static boolean isLegacyVariableChange(String interfaceName, - String methodName) { - return ApplicationConnection.UPDATE_VARIABLE_METHOD - .equals(interfaceName) - && ApplicationConnection.UPDATE_VARIABLE_METHOD - .equals(methodName); - } - - public void setVariableChange(String name, Object value) { - variableChanges.put(name, value); - } - - public Map<String, Object> getVariableChanges() { - return variableChanges; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/NoInputStreamException.java b/src/com/vaadin/terminal/gwt/server/NoInputStreamException.java deleted file mode 100644 index 70c3add858..0000000000 --- a/src/com/vaadin/terminal/gwt/server/NoInputStreamException.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class NoInputStreamException extends Exception { - -} diff --git a/src/com/vaadin/terminal/gwt/server/NoOutputStreamException.java b/src/com/vaadin/terminal/gwt/server/NoOutputStreamException.java deleted file mode 100644 index e4db8453b0..0000000000 --- a/src/com/vaadin/terminal/gwt/server/NoOutputStreamException.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class NoOutputStreamException extends Exception { - -} diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java deleted file mode 100644 index 70505ab5f9..0000000000 --- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java +++ /dev/null @@ -1,398 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.File; -import java.io.Serializable; -import java.net.URL; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.portlet.ActionRequest; -import javax.portlet.ActionResponse; -import javax.portlet.EventRequest; -import javax.portlet.EventResponse; -import javax.portlet.MimeResponse; -import javax.portlet.PortletConfig; -import javax.portlet.PortletMode; -import javax.portlet.PortletModeException; -import javax.portlet.PortletResponse; -import javax.portlet.PortletSession; -import javax.portlet.PortletURL; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceRequest; -import javax.portlet.ResourceResponse; -import javax.portlet.StateAwareResponse; -import javax.servlet.http.HttpSessionBindingListener; -import javax.xml.namespace.QName; - -import com.vaadin.Application; -import com.vaadin.terminal.ExternalResource; -import com.vaadin.ui.Root; - -/** - * TODO Write documentation, fix JavaDoc tags. - * - * This is automatically registered as a {@link HttpSessionBindingListener} when - * {@link PortletSession#setAttribute()} is called with the context as value. - * - * @author peholmst - */ -@SuppressWarnings("serial") -public class PortletApplicationContext2 extends AbstractWebApplicationContext { - - protected Map<Application, Set<PortletListener>> portletListeners = new HashMap<Application, Set<PortletListener>>(); - - protected transient PortletSession session; - protected transient PortletConfig portletConfig; - - protected HashMap<String, Application> portletWindowIdToApplicationMap = new HashMap<String, Application>(); - - private transient PortletResponse response; - - private final Map<String, QName> eventActionDestinationMap = new HashMap<String, QName>(); - private final Map<String, Serializable> eventActionValueMap = new HashMap<String, Serializable>(); - - private final Map<String, String> sharedParameterActionNameMap = new HashMap<String, String>(); - private final Map<String, String> sharedParameterActionValueMap = new HashMap<String, String>(); - - @Override - public File getBaseDirectory() { - String resultPath = session.getPortletContext().getRealPath("/"); - if (resultPath != null) { - return new File(resultPath); - } else { - try { - final URL url = session.getPortletContext().getResource("/"); - return new File(url.getFile()); - } catch (final Exception e) { - // FIXME: Handle exception - getLogger() - .log(Level.INFO, - "Cannot access base directory, possible security issue " - + "with Application Server or Servlet Container", - e); - } - } - return null; - } - - protected PortletCommunicationManager getApplicationManager( - Application application) { - PortletCommunicationManager mgr = (PortletCommunicationManager) applicationToAjaxAppMgrMap - .get(application); - - if (mgr == null) { - // Creates a new manager - mgr = createPortletCommunicationManager(application); - applicationToAjaxAppMgrMap.put(application, mgr); - } - return mgr; - } - - protected PortletCommunicationManager createPortletCommunicationManager( - Application application) { - return new PortletCommunicationManager(application); - } - - public static PortletApplicationContext2 getApplicationContext( - PortletSession session) { - Object cxattr = session.getAttribute(PortletApplicationContext2.class - .getName()); - PortletApplicationContext2 cx = null; - // can be false also e.g. if old context comes from another - // classloader when using - // <private-session-attributes>false</private-session-attributes> - // and redeploying the portlet - see #7461 - if (cxattr instanceof PortletApplicationContext2) { - cx = (PortletApplicationContext2) cxattr; - } - if (cx == null) { - cx = new PortletApplicationContext2(); - session.setAttribute(PortletApplicationContext2.class.getName(), cx); - } - if (cx.session == null) { - cx.session = session; - } - return cx; - } - - @Override - protected void removeApplication(Application application) { - super.removeApplication(application); - // values() is backed by map, removes the key-value pair from the map - portletWindowIdToApplicationMap.values().remove(application); - } - - protected void addApplication(Application application, - String portletWindowId) { - applications.add(application); - portletWindowIdToApplicationMap.put(portletWindowId, application); - } - - public Application getApplicationForWindowId(String portletWindowId) { - return portletWindowIdToApplicationMap.get(portletWindowId); - } - - public PortletSession getPortletSession() { - return session; - } - - public PortletConfig getPortletConfig() { - return portletConfig; - } - - public void setPortletConfig(PortletConfig config) { - portletConfig = config; - } - - public void addPortletListener(Application app, PortletListener listener) { - Set<PortletListener> l = portletListeners.get(app); - if (l == null) { - l = new LinkedHashSet<PortletListener>(); - portletListeners.put(app, l); - } - l.add(listener); - } - - public void removePortletListener(Application app, PortletListener listener) { - Set<PortletListener> l = portletListeners.get(app); - if (l != null) { - l.remove(listener); - } - } - - public void firePortletRenderRequest(Application app, Root root, - RenderRequest request, RenderResponse response) { - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleRenderRequest(request, new RestrictedRenderResponse( - response), root); - } - } - } - - public void firePortletActionRequest(Application app, Root root, - ActionRequest request, ActionResponse response) { - String key = request.getParameter(ActionRequest.ACTION_NAME); - if (eventActionDestinationMap.containsKey(key)) { - // this action request is only to send queued portlet events - response.setEvent(eventActionDestinationMap.get(key), - eventActionValueMap.get(key)); - // cleanup - eventActionDestinationMap.remove(key); - eventActionValueMap.remove(key); - } else if (sharedParameterActionNameMap.containsKey(key)) { - // this action request is only to set shared render parameters - response.setRenderParameter(sharedParameterActionNameMap.get(key), - sharedParameterActionValueMap.get(key)); - // cleanup - sharedParameterActionNameMap.remove(key); - sharedParameterActionValueMap.remove(key); - } else { - // normal action request, notify listeners - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleActionRequest(request, response, root); - } - } - } - } - - public void firePortletEventRequest(Application app, Root root, - EventRequest request, EventResponse response) { - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleEventRequest(request, response, root); - } - } - } - - public void firePortletResourceRequest(Application app, Root root, - ResourceRequest request, ResourceResponse response) { - Set<PortletListener> listeners = portletListeners.get(app); - if (listeners != null) { - for (PortletListener l : listeners) { - l.handleResourceRequest(request, response, root); - } - } - } - - public interface PortletListener extends Serializable { - - public void handleRenderRequest(RenderRequest request, - RenderResponse response, Root root); - - public void handleActionRequest(ActionRequest request, - ActionResponse response, Root root); - - public void handleEventRequest(EventRequest request, - EventResponse response, Root root); - - public void handleResourceRequest(ResourceRequest request, - ResourceResponse response, Root root); - } - - /** - * This is for use by {@link AbstractApplicationPortlet} only. - * - * TODO cleaner implementation, now "semi-static"! - * - * @param mimeResponse - */ - void setResponse(PortletResponse response) { - this.response = response; - } - - /** - * Creates a new action URL. - * - * @param action - * @return action URL or null if called outside a MimeRequest (outside a - * UIDL request or similar) - */ - public PortletURL generateActionURL(String action) { - PortletURL url = null; - if (response instanceof MimeResponse) { - url = ((MimeResponse) response).createActionURL(); - url.setParameter("javax.portlet.action", action); - } else { - return null; - } - return url; - } - - /** - * Sends a portlet event to the indicated destination. - * - * Internally, an action may be created and opened, as an event cannot be - * sent directly from all types of requests. - * - * The event destinations and values need to be kept in the context until - * sent. Any memory leaks if the action fails are limited to the session. - * - * Event names for events sent and received by a portlet need to be declared - * in portlet.xml . - * - * @param root - * a window in which a temporary action URL can be opened if - * necessary - * @param name - * event name - * @param value - * event value object that is Serializable and, if appropriate, - * has a valid JAXB annotation - */ - public void sendPortletEvent(Root root, QName name, Serializable value) - throws IllegalStateException { - if (response instanceof MimeResponse) { - String actionKey = "" + System.currentTimeMillis(); - while (eventActionDestinationMap.containsKey(actionKey)) { - actionKey = actionKey + "."; - } - PortletURL actionUrl = generateActionURL(actionKey); - if (actionUrl != null) { - eventActionDestinationMap.put(actionKey, name); - eventActionValueMap.put(actionKey, value); - root.getPage().open(new ExternalResource(actionUrl.toString())); - } else { - // this should never happen as we already know the response is a - // MimeResponse - throw new IllegalStateException( - "Portlet events can only be sent from a portlet request"); - } - } else if (response instanceof StateAwareResponse) { - ((StateAwareResponse) response).setEvent(name, value); - } else { - throw new IllegalStateException( - "Portlet events can only be sent from a portlet request"); - } - } - - /** - * Sets a shared portlet parameter. - * - * Internally, an action may be created and opened, as shared parameters - * cannot be set directly from all types of requests. - * - * The parameters and values need to be kept in the context until sent. Any - * memory leaks if the action fails are limited to the session. - * - * Shared parameters set or read by a portlet need to be declared in - * portlet.xml . - * - * @param root - * a window in which a temporary action URL can be opened if - * necessary - * @param name - * parameter identifier - * @param value - * parameter value - */ - public void setSharedRenderParameter(Root root, String name, String value) - throws IllegalStateException { - if (response instanceof MimeResponse) { - String actionKey = "" + System.currentTimeMillis(); - while (sharedParameterActionNameMap.containsKey(actionKey)) { - actionKey = actionKey + "."; - } - PortletURL actionUrl = generateActionURL(actionKey); - if (actionUrl != null) { - sharedParameterActionNameMap.put(actionKey, name); - sharedParameterActionValueMap.put(actionKey, value); - root.getPage().open(new ExternalResource(actionUrl.toString())); - } else { - // this should never happen as we already know the response is a - // MimeResponse - throw new IllegalStateException( - "Shared parameters can only be set from a portlet request"); - } - } else if (response instanceof StateAwareResponse) { - ((StateAwareResponse) response).setRenderParameter(name, value); - } else { - throw new IllegalStateException( - "Shared parameters can only be set from a portlet request"); - } - } - - /** - * Sets the portlet mode. This may trigger a new render request. - * - * Portlet modes used by a portlet need to be declared in portlet.xml . - * - * @param root - * a window in which the render URL can be opened if necessary - * @param portletMode - * the portlet mode to switch to - * @throws PortletModeException - * if the portlet mode is not allowed for some reason - * (configuration, permissions etc.) - */ - public void setPortletMode(Root root, PortletMode portletMode) - throws IllegalStateException, PortletModeException { - if (response instanceof MimeResponse) { - PortletURL url = ((MimeResponse) response).createRenderURL(); - url.setPortletMode(portletMode); - throw new RuntimeException("Root.open has not yet been implemented"); - // root.open(new ExternalResource(url.toString())); - } else if (response instanceof StateAwareResponse) { - ((StateAwareResponse) response).setPortletMode(portletMode); - } else { - throw new IllegalStateException( - "Portlet mode can only be changed from a portlet request"); - } - } - - private Logger getLogger() { - return Logger.getLogger(PortletApplicationContext2.class.getName()); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java deleted file mode 100644 index 39c27d05fe..0000000000 --- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java +++ /dev/null @@ -1,170 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.InputStream; - -import javax.portlet.MimeResponse; -import javax.portlet.PortletContext; -import javax.portlet.PortletRequest; -import javax.portlet.PortletResponse; -import javax.portlet.RenderRequest; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceURL; - -import com.vaadin.Application; -import com.vaadin.external.json.JSONException; -import com.vaadin.external.json.JSONObject; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConfiguration; -import com.vaadin.ui.Root; - -/** - * TODO document me! - * - * @author peholmst - * - */ -@SuppressWarnings("serial") -public class PortletCommunicationManager extends AbstractCommunicationManager { - - public PortletCommunicationManager(Application application) { - super(application); - } - - @Override - protected BootstrapHandler createBootstrapHandler() { - return new BootstrapHandler() { - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - PortletRequest portletRequest = WrappedPortletRequest.cast( - request).getPortletRequest(); - if (portletRequest instanceof RenderRequest) { - return super.handleRequest(application, request, response); - } else { - return false; - } - } - - @Override - protected String getApplicationId(BootstrapContext context) { - PortletRequest portletRequest = WrappedPortletRequest.cast( - context.getRequest()).getPortletRequest(); - /* - * We need to generate a unique ID because some portals already - * create a DIV with the portlet's Window ID as the DOM ID. - */ - return "v-" + portletRequest.getWindowID(); - } - - @Override - protected String getAppUri(BootstrapContext context) { - return getRenderResponse(context).createActionURL().toString(); - } - - private RenderResponse getRenderResponse(BootstrapContext context) { - PortletResponse response = ((WrappedPortletResponse) context - .getResponse()).getPortletResponse(); - - RenderResponse renderResponse = (RenderResponse) response; - return renderResponse; - } - - @Override - protected JSONObject getDefaultParameters(BootstrapContext context) - throws JSONException { - /* - * We need this in order to get uploads to work. TODO this is - * not needed for uploads anymore, check if this is needed for - * some other things - */ - JSONObject defaults = super.getDefaultParameters(context); - - ResourceURL portletResourceUrl = getRenderResponse(context) - .createResourceURL(); - portletResourceUrl - .setResourceID(AbstractApplicationPortlet.RESOURCE_URL_ID); - defaults.put(ApplicationConfiguration.PORTLET_RESOUCE_URL_BASE, - portletResourceUrl.toString()); - - defaults.put("pathInfo", ""); - - return defaults; - } - - @Override - protected void appendMainScriptTagContents( - BootstrapContext context, StringBuilder builder) - throws JSONException, IOException { - // fixed base theme to use - all portal pages with Vaadin - // applications will load this exactly once - String portalTheme = WrappedPortletRequest - .cast(context.getRequest()) - .getPortalProperty( - AbstractApplicationPortlet.PORTAL_PARAMETER_VAADIN_THEME); - if (portalTheme != null - && !portalTheme.equals(context.getThemeName())) { - String portalThemeUri = getThemeUri(context, portalTheme); - // XSS safe - originates from portal properties - builder.append("vaadin.loadTheme('" + portalThemeUri - + "');"); - } - - super.appendMainScriptTagContents(context, builder); - } - - @Override - protected String getMainDivStyle(BootstrapContext context) { - DeploymentConfiguration deploymentConfiguration = context - .getRequest().getDeploymentConfiguration(); - return deploymentConfiguration.getApplicationOrSystemProperty( - AbstractApplicationPortlet.PORTLET_PARAMETER_STYLE, - null); - } - - @Override - protected String getInitialUIDL(WrappedRequest request, Root root) - throws PaintException, JSONException { - return PortletCommunicationManager.this.getInitialUIDL(request, - root); - } - - @Override - protected JSONObject getApplicationParameters( - BootstrapContext context) throws JSONException, - PaintException { - JSONObject parameters = super.getApplicationParameters(context); - WrappedPortletResponse wrappedPortletResponse = (WrappedPortletResponse) context - .getResponse(); - MimeResponse portletResponse = (MimeResponse) wrappedPortletResponse - .getPortletResponse(); - ResourceURL resourceURL = portletResponse.createResourceURL(); - resourceURL.setResourceID("browserDetails"); - parameters.put("browserDetailsUrl", resourceURL.toString()); - return parameters; - } - - }; - - } - - @Override - protected InputStream getThemeResourceAsStream(Root root, String themeName, - String resource) { - PortletApplicationContext2 context = (PortletApplicationContext2) root - .getApplication().getContext(); - PortletContext portletContext = context.getPortletSession() - .getPortletContext(); - return portletContext.getResourceAsStream("/" - + AbstractApplicationPortlet.THEME_DIRECTORY_PATH + themeName - + "/" + resource); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/PortletRequestListener.java b/src/com/vaadin/terminal/gwt/server/PortletRequestListener.java deleted file mode 100644 index 8a30f5c1d4..0000000000 --- a/src/com/vaadin/terminal/gwt/server/PortletRequestListener.java +++ /dev/null @@ -1,56 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import javax.portlet.PortletRequest; -import javax.portlet.PortletResponse; -import javax.servlet.Filter; - -import com.vaadin.Application; -import com.vaadin.service.ApplicationContext.TransactionListener; -import com.vaadin.terminal.Terminal; - -/** - * An {@link Application} that implements this interface gets notified of - * request start and end by the terminal. It is quite similar to the - * {@link HttpServletRequestListener}, but the parameters are Portlet specific. - * If an Application is deployed as both a Servlet and a Portlet, one most - * likely needs to implement both. - * <p> - * Only JSR 286 style Portlets are supported. - * <p> - * The interface can be used for several helper tasks including: - * <ul> - * <li>Opening and closing database connections - * <li>Implementing {@link ThreadLocal} - * <li>Inter-portlet communication - * </ul> - * <p> - * Alternatives for implementing similar features are are Servlet {@link Filter} - * s and {@link TransactionListener}s in Vaadin. - * - * @since 6.2 - * @see HttpServletRequestListener - */ -public interface PortletRequestListener extends Serializable { - - /** - * This method is called before {@link Terminal} applies the request to - * Application. - * - * @param requestData - * the {@link PortletRequest} about to change Application state - */ - public void onRequestStart(PortletRequest request, PortletResponse response); - - /** - * This method is called at the end of each request. - * - * @param requestData - * the {@link PortletRequest} - */ - public void onRequestEnd(PortletRequest request, PortletResponse response); -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/RequestTimer.java b/src/com/vaadin/terminal/gwt/server/RequestTimer.java deleted file mode 100644 index 6c0edec466..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RequestTimer.java +++ /dev/null @@ -1,43 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -/** - * Times the handling of requests and stores the information as an attribute in - * the request. The timing info is later passed on to the client in the UIDL and - * the client provides JavaScript API for accessing this data from e.g. - * TestBench. - * - * @author Jonatan Kronqvist / Vaadin Ltd - */ -public class RequestTimer implements Serializable { - private long requestStartTime = 0; - - /** - * Starts the timing of a request. This should be called before any - * processing of the request. - */ - public void start() { - requestStartTime = System.nanoTime(); - } - - /** - * Stops the timing of a request. This should be called when all processing - * of a request has finished. - * - * @param context - */ - public void stop(AbstractWebApplicationContext context) { - // Measure and store the total handling time. This data can be - // used in TestBench 3 tests. - long time = (System.nanoTime() - requestStartTime) / 1000000; - - // The timings must be stored in the context, since a new - // RequestTimer is created for every request. - context.setLastRequestTime(time); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/ResourceReference.java b/src/com/vaadin/terminal/gwt/server/ResourceReference.java deleted file mode 100644 index 2104ad4b87..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ResourceReference.java +++ /dev/null @@ -1,67 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.Application; -import com.vaadin.shared.communication.URLReference; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.ExternalResource; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.ThemeResource; - -public class ResourceReference extends URLReference { - - private Resource resource; - - public ResourceReference(Resource resource) { - this.resource = resource; - } - - public Resource getResource() { - return resource; - } - - @Override - public String getURL() { - if (resource instanceof ExternalResource) { - return ((ExternalResource) resource).getURL(); - } else if (resource instanceof ApplicationResource) { - final ApplicationResource r = (ApplicationResource) resource; - final Application a = r.getApplication(); - if (a == null) { - throw new RuntimeException( - "An ApplicationResource (" - + r.getClass().getName() - + " must be attached to an application when it is sent to the client."); - } - final String uri = a.getRelativeLocation(r); - return uri; - } else if (resource instanceof ThemeResource) { - final String uri = "theme://" - + ((ThemeResource) resource).getResourceId(); - return uri; - } else { - throw new RuntimeException(getClass().getSimpleName() - + " does not support resources of type: " - + resource.getClass().getName()); - } - - } - - public static ResourceReference create(Resource resource) { - if (resource == null) { - return null; - } else { - return new ResourceReference(resource); - } - } - - public static Resource getResource(URLReference reference) { - if (reference == null) { - return null; - } - assert reference instanceof ResourceReference; - return ((ResourceReference) reference).getResource(); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/RestrictedRenderResponse.java b/src/com/vaadin/terminal/gwt/server/RestrictedRenderResponse.java deleted file mode 100644 index 9fdffbf9a5..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RestrictedRenderResponse.java +++ /dev/null @@ -1,172 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Serializable; -import java.util.Collection; -import java.util.Locale; - -import javax.portlet.CacheControl; -import javax.portlet.PortletMode; -import javax.portlet.PortletURL; -import javax.portlet.RenderResponse; -import javax.portlet.ResourceURL; -import javax.servlet.http.Cookie; - -import org.w3c.dom.DOMException; -import org.w3c.dom.Element; - -/** - * Read-only wrapper for a {@link RenderResponse}. - * - * Only for use by {@link PortletApplicationContext} and - * {@link PortletApplicationContext2}. - */ -class RestrictedRenderResponse implements RenderResponse, Serializable { - - private RenderResponse response; - - RestrictedRenderResponse(RenderResponse response) { - this.response = response; - } - - @Override - public void addProperty(String key, String value) { - response.addProperty(key, value); - } - - @Override - public PortletURL createActionURL() { - return response.createActionURL(); - } - - @Override - public PortletURL createRenderURL() { - return response.createRenderURL(); - } - - @Override - public String encodeURL(String path) { - return response.encodeURL(path); - } - - @Override - public void flushBuffer() throws IOException { - // NOP - // TODO throw? - } - - @Override - public int getBufferSize() { - return response.getBufferSize(); - } - - @Override - public String getCharacterEncoding() { - return response.getCharacterEncoding(); - } - - @Override - public String getContentType() { - return response.getContentType(); - } - - @Override - public Locale getLocale() { - return response.getLocale(); - } - - @Override - public String getNamespace() { - return response.getNamespace(); - } - - @Override - public OutputStream getPortletOutputStream() throws IOException { - // write forbidden - return null; - } - - @Override - public PrintWriter getWriter() throws IOException { - // write forbidden - return null; - } - - @Override - public boolean isCommitted() { - return response.isCommitted(); - } - - @Override - public void reset() { - // NOP - // TODO throw? - } - - @Override - public void resetBuffer() { - // NOP - // TODO throw? - } - - @Override - public void setBufferSize(int size) { - // NOP - // TODO throw? - } - - @Override - public void setContentType(String type) { - // NOP - // TODO throw? - } - - @Override - public void setProperty(String key, String value) { - response.setProperty(key, value); - } - - @Override - public void setTitle(String title) { - response.setTitle(title); - } - - @Override - public void setNextPossiblePortletModes(Collection<PortletMode> portletModes) { - // NOP - // TODO throw? - } - - @Override - public ResourceURL createResourceURL() { - return response.createResourceURL(); - } - - @Override - public CacheControl getCacheControl() { - return response.getCacheControl(); - } - - @Override - public void addProperty(Cookie cookie) { - // NOP - // TODO throw? - } - - @Override - public void addProperty(String key, Element element) { - // NOP - // TODO throw? - } - - @Override - public Element createElement(String tagName) throws DOMException { - // NOP - return null; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/RpcManager.java b/src/com/vaadin/terminal/gwt/server/RpcManager.java deleted file mode 100644 index 026c847e2b..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RpcManager.java +++ /dev/null @@ -1,48 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -/** - * Server side RPC manager that can invoke methods based on RPC calls received - * from the client. - * - * @since 7.0 - */ -public interface RpcManager extends Serializable { - public void applyInvocation(ServerRpcMethodInvocation invocation) - throws RpcInvocationException; - - /** - * Wrapper exception for exceptions which occur during invocation of an RPC - * call - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0 - * - */ - public static class RpcInvocationException extends Exception { - - public RpcInvocationException() { - super(); - } - - public RpcInvocationException(String message, Throwable cause) { - super(message, cause); - } - - public RpcInvocationException(String message) { - super(message); - } - - public RpcInvocationException(Throwable cause) { - super(cause); - } - - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/RpcTarget.java b/src/com/vaadin/terminal/gwt/server/RpcTarget.java deleted file mode 100644 index b280f5c6b5..0000000000 --- a/src/com/vaadin/terminal/gwt/server/RpcTarget.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import com.vaadin.terminal.VariableOwner; - -/** - * Marker interface for server side classes that can receive RPC calls. - * - * This plays a role similar to that of {@link VariableOwner}. - * - * @since 7.0 - */ -public interface RpcTarget extends Serializable { - /** - * Returns the RPC manager instance to use when receiving calls for an RPC - * interface. - * - * @param rpcInterface - * interface for which the call was made - * @return RpcManager or null if none found for the interface - */ - public RpcManager getRpcManager(Class<?> rpcInterface); -} diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java b/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java deleted file mode 100644 index 1c7af82a36..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ServerRpcManager.java +++ /dev/null @@ -1,142 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.shared.Connector; - -/** - * Server side RPC manager that handles RPC calls coming from the client. - * - * Each {@link RpcTarget} (typically a {@link ClientConnector}) should have its - * own instance of {@link ServerRpcManager} if it wants to receive RPC calls - * from the client. - * - * @since 7.0 - */ -public class ServerRpcManager<T> implements RpcManager { - - private final T implementation; - private final Class<T> rpcInterface; - - private static final Map<Class<?>, Class<?>> boxedTypes = new HashMap<Class<?>, Class<?>>(); - static { - try { - Class<?>[] boxClasses = new Class<?>[] { Boolean.class, Byte.class, - Short.class, Character.class, Integer.class, Long.class, - Float.class, Double.class }; - for (Class<?> boxClass : boxClasses) { - Field typeField = boxClass.getField("TYPE"); - Class<?> primitiveType = (Class<?>) typeField.get(boxClass); - boxedTypes.put(primitiveType, boxClass); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Create a RPC manager for an RPC target. - * - * @param target - * RPC call target (normally a {@link Connector}) - * @param implementation - * RPC interface implementation for the target - * @param rpcInterface - * RPC interface type - */ - public ServerRpcManager(T implementation, Class<T> rpcInterface) { - this.implementation = implementation; - this.rpcInterface = rpcInterface; - } - - /** - * Invoke a method in a server side RPC target class. This method is to be - * used by the RPC framework and unit testing tools only. - * - * @param target - * non-null target of the RPC call - * @param invocation - * method invocation to perform - * @throws RpcInvocationException - */ - public static void applyInvocation(RpcTarget target, - ServerRpcMethodInvocation invocation) throws RpcInvocationException { - RpcManager manager = target.getRpcManager(invocation - .getInterfaceClass()); - if (manager != null) { - manager.applyInvocation(invocation); - } else { - getLogger() - .log(Level.WARNING, - "RPC call received for RpcTarget " - + target.getClass().getName() - + " (" - + invocation.getConnectorId() - + ") but the target has not registered any RPC interfaces"); - } - } - - /** - * Returns the RPC interface implementation for the RPC target. - * - * @return RPC interface implementation - */ - protected T getImplementation() { - return implementation; - } - - /** - * Returns the RPC interface type managed by this RPC manager instance. - * - * @return RPC interface type - */ - protected Class<T> getRpcInterface() { - return rpcInterface; - } - - /** - * Invoke a method in a server side RPC target class. This method is to be - * used by the RPC framework and unit testing tools only. - * - * @param invocation - * method invocation to perform - */ - @Override - public void applyInvocation(ServerRpcMethodInvocation invocation) - throws RpcInvocationException { - Method method = invocation.getMethod(); - Class<?>[] parameterTypes = method.getParameterTypes(); - Object[] args = new Object[parameterTypes.length]; - Object[] arguments = invocation.getParameters(); - for (int i = 0; i < args.length; i++) { - // no conversion needed for basic cases - // Class<?> type = parameterTypes[i]; - // if (type.isPrimitive()) { - // type = boxedTypes.get(type); - // } - args[i] = arguments[i]; - } - try { - method.invoke(implementation, args); - } catch (Exception e) { - throw new RpcInvocationException("Unable to invoke method " - + invocation.getMethodName() + " in " - + invocation.getInterfaceName(), e); - } - } - - private static Logger getLogger() { - return Logger.getLogger(ServerRpcManager.class.getName()); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java b/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java deleted file mode 100644 index ff81a27596..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ServerRpcMethodInvocation.java +++ /dev/null @@ -1,113 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.lang.reflect.Method; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import com.vaadin.shared.communication.MethodInvocation; -import com.vaadin.shared.communication.ServerRpc; - -public class ServerRpcMethodInvocation extends MethodInvocation { - - private static final Map<String, Method> invocationMethodCache = new ConcurrentHashMap<String, Method>( - 128, 0.75f, 1); - - private final Method method; - - private Class<? extends ServerRpc> interfaceClass; - - public ServerRpcMethodInvocation(String connectorId, String interfaceName, - String methodName, int parameterCount) { - super(connectorId, interfaceName, methodName); - - interfaceClass = findClass(); - method = findInvocationMethod(interfaceClass, methodName, - parameterCount); - } - - private Class<? extends ServerRpc> findClass() { - try { - Class<?> rpcInterface = Class.forName(getInterfaceName()); - if (!ServerRpc.class.isAssignableFrom(rpcInterface)) { - throw new IllegalArgumentException("The interface " - + getInterfaceName() + "is not a server RPC interface."); - } - return (Class<? extends ServerRpc>) rpcInterface; - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException("The server RPC interface " - + getInterfaceName() + " could not be found", e); - } finally { - - } - } - - public Class<? extends ServerRpc> getInterfaceClass() { - return interfaceClass; - } - - public Method getMethod() { - return method; - } - - /** - * Tries to find the method from the cache or alternatively by invoking - * {@link #doFindInvocationMethod(Class, String, int)} and updating the - * cache. - * - * @param targetType - * @param methodName - * @param parameterCount - * @return - */ - private Method findInvocationMethod(Class<?> targetType, String methodName, - int parameterCount) { - // TODO currently only using method name and number of parameters as the - // signature - String signature = targetType.getName() + "." + methodName + "(" - + parameterCount; - Method invocationMethod = invocationMethodCache.get(signature); - - if (invocationMethod == null) { - invocationMethod = doFindInvocationMethod(targetType, methodName, - parameterCount); - - if (invocationMethod != null) { - invocationMethodCache.put(signature, invocationMethod); - } - } - - if (invocationMethod == null) { - throw new IllegalStateException("Can't find method " + methodName - + " with " + parameterCount + " parameters in " - + targetType.getName()); - } - - return invocationMethod; - } - - /** - * Tries to find the method from the class by looping through available - * methods. - * - * @param targetType - * @param methodName - * @param parameterCount - * @return - */ - private Method doFindInvocationMethod(Class<?> targetType, - String methodName, int parameterCount) { - Method[] methods = targetType.getMethods(); - for (Method method : methods) { - Class<?>[] parameterTypes = method.getParameterTypes(); - if (method.getName().equals(methodName) - && parameterTypes.length == parameterCount) { - return method; - } - } - return null; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java deleted file mode 100644 index 2a1dc31897..0000000000 --- a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.vaadin.terminal.gwt.server; - -import java.io.Serializable; - -import com.vaadin.Application; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.ui.Root; - -/* - @VaadinApache2LicenseForJavaFiles@ - */ - -class ServletPortletHelper implements Serializable { - public static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/"; - - public static class ApplicationClassException extends Exception { - - public ApplicationClassException(String message, Throwable cause) { - super(message, cause); - } - - public ApplicationClassException(String message) { - super(message); - } - } - - static Class<? extends Application> getApplicationClass( - DeploymentConfiguration deploymentConfiguration) - throws ApplicationClassException { - String applicationParameter = deploymentConfiguration - .getInitParameters().getProperty("application"); - String rootParameter = deploymentConfiguration.getInitParameters() - .getProperty(Application.ROOT_PARAMETER); - ClassLoader classLoader = deploymentConfiguration.getClassLoader(); - - if (applicationParameter == null) { - - // Validate the parameter value - verifyRootClass(rootParameter, classLoader); - - // Application can be used if a valid rootLayout is defined - return Application.class; - } - - try { - return (Class<? extends Application>) classLoader - .loadClass(applicationParameter); - } catch (final ClassNotFoundException e) { - throw new ApplicationClassException( - "Failed to load application class: " + applicationParameter, - e); - } - } - - private static void verifyRootClass(String className, - ClassLoader classLoader) throws ApplicationClassException { - if (className == null) { - throw new ApplicationClassException(Application.ROOT_PARAMETER - + " init parameter not defined"); - } - - // Check that the root layout class can be found - try { - Class<?> rootClass = classLoader.loadClass(className); - if (!Root.class.isAssignableFrom(rootClass)) { - throw new ApplicationClassException(className - + " does not implement Root"); - } - // Try finding a default constructor, else throw exception - rootClass.getConstructor(); - } catch (ClassNotFoundException e) { - throw new ApplicationClassException(className - + " could not be loaded", e); - } catch (SecurityException e) { - throw new ApplicationClassException("Could not access " + className - + " class", e); - } catch (NoSuchMethodException e) { - throw new ApplicationClassException(className - + " doesn't have a public no-args constructor"); - } - } - - private static boolean hasPathPrefix(WrappedRequest request, String prefix) { - String pathInfo = request.getRequestPathInfo(); - - if (pathInfo == null) { - return false; - } - - if (!prefix.startsWith("/")) { - prefix = '/' + prefix; - } - - if (pathInfo.startsWith(prefix)) { - return true; - } - - return false; - } - - public static boolean isFileUploadRequest(WrappedRequest request) { - return hasPathPrefix(request, UPLOAD_URL_PREFIX); - } - - public static boolean isConnectorResourceRequest(WrappedRequest request) { - return hasPathPrefix(request, - ApplicationConnection.CONNECTOR_RESOURCE_PREFIX + "/"); - } - - public static boolean isUIDLRequest(WrappedRequest request) { - return hasPathPrefix(request, ApplicationConnection.UIDL_REQUEST_PATH); - } - - public static boolean isApplicationResourceRequest(WrappedRequest request) { - return hasPathPrefix(request, ApplicationConnection.APP_REQUEST_PATH); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/SessionExpiredException.java b/src/com/vaadin/terminal/gwt/server/SessionExpiredException.java deleted file mode 100644 index 37b76de443..0000000000 --- a/src/com/vaadin/terminal/gwt/server/SessionExpiredException.java +++ /dev/null @@ -1,9 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class SessionExpiredException extends Exception { - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingEndEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingEndEventImpl.java deleted file mode 100644 index 0d4963bd7d..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingEndEventImpl.java +++ /dev/null @@ -1,16 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingEndEvent; - -@SuppressWarnings("serial") -final class StreamingEndEventImpl extends AbstractStreamingEvent implements - StreamingEndEvent { - - public StreamingEndEventImpl(String filename, String type, long totalBytes) { - super(filename, type, totalBytes, totalBytes); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingErrorEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingErrorEventImpl.java deleted file mode 100644 index 6ab3df2789..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingErrorEventImpl.java +++ /dev/null @@ -1,25 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingErrorEvent; - -@SuppressWarnings("serial") -final class StreamingErrorEventImpl extends AbstractStreamingEvent implements - StreamingErrorEvent { - - private final Exception exception; - - public StreamingErrorEventImpl(final String filename, final String type, - long contentLength, long bytesReceived, final Exception exception) { - super(filename, type, contentLength, bytesReceived); - this.exception = exception; - } - - @Override - public final Exception getException() { - return exception; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingProgressEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingProgressEventImpl.java deleted file mode 100644 index cfa7a1b98d..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingProgressEventImpl.java +++ /dev/null @@ -1,17 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingProgressEvent; - -@SuppressWarnings("serial") -final class StreamingProgressEventImpl extends AbstractStreamingEvent implements - StreamingProgressEvent { - - public StreamingProgressEventImpl(final String filename, final String type, - long contentLength, long bytesReceived) { - super(filename, type, contentLength, bytesReceived); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/StreamingStartEventImpl.java b/src/com/vaadin/terminal/gwt/server/StreamingStartEventImpl.java deleted file mode 100644 index 274d05e111..0000000000 --- a/src/com/vaadin/terminal/gwt/server/StreamingStartEventImpl.java +++ /dev/null @@ -1,28 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import com.vaadin.terminal.StreamVariable.StreamingStartEvent; - -@SuppressWarnings("serial") -final class StreamingStartEventImpl extends AbstractStreamingEvent implements - StreamingStartEvent { - - private boolean disposed; - - public StreamingStartEventImpl(final String filename, final String type, - long contentLength) { - super(filename, type, contentLength, 0); - } - - @Override - public void disposeStreamVariable() { - disposed = true; - } - - boolean isDisposed() { - return disposed; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/SystemMessageException.java b/src/com/vaadin/terminal/gwt/server/SystemMessageException.java deleted file mode 100644 index d15ff8a7ef..0000000000 --- a/src/com/vaadin/terminal/gwt/server/SystemMessageException.java +++ /dev/null @@ -1,57 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class SystemMessageException extends RuntimeException { - - /** - * Cause of the method exception - */ - private Throwable cause; - - /** - * Constructs a new <code>SystemMessageException</code> with the specified - * detail message. - * - * @param msg - * the detail message. - */ - public SystemMessageException(String msg) { - super(msg); - } - - /** - * Constructs a new <code>SystemMessageException</code> with the specified - * detail message and cause. - * - * @param msg - * the detail message. - * @param cause - * the cause of the exception. - */ - public SystemMessageException(String msg, Throwable cause) { - super(msg, cause); - } - - /** - * Constructs a new <code>SystemMessageException</code> from another - * exception. - * - * @param cause - * the cause of the exception. - */ - public SystemMessageException(Throwable cause) { - this.cause = cause; - } - - /** - * @see java.lang.Throwable#getCause() - */ - @Override - public Throwable getCause() { - return cause; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java b/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java deleted file mode 100644 index 5248af595e..0000000000 --- a/src/com/vaadin/terminal/gwt/server/UnsupportedBrowserHandler.java +++ /dev/null @@ -1,89 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.Writer; - -import com.vaadin.Application; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; - -/** - * A {@link RequestHandler} that presents an informative page if the browser in - * use is unsupported. Recognizes Chrome Frame and allow it to be used. - * - * <p> - * This handler is usually added to the application by - * {@link AbstractCommunicationManager}. - * </p> - */ -@SuppressWarnings("serial") -public class UnsupportedBrowserHandler implements RequestHandler { - - /** Cookie used to ignore browser checks */ - public static final String FORCE_LOAD_COOKIE = "vaadinforceload=1"; - - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - - if (request.getBrowserDetails() != null) { - // Check if the browser is supported - // If Chrome Frame is available we'll assume it's ok - WebBrowser b = request.getBrowserDetails().getWebBrowser(); - if (b.isTooOldToFunctionProperly() && !b.isChromeFrameCapable()) { - // bypass if cookie set - String c = request.getHeader("Cookie"); - if (c == null || !c.contains(FORCE_LOAD_COOKIE)) { - writeBrowserTooOldPage(request, response); - return true; // request handled - } - } - } - - return false; // pass to next handler - } - - /** - * Writes a page encouraging the user to upgrade to a more current browser. - * - * @param request - * @param response - * @throws IOException - */ - protected void writeBrowserTooOldPage(WrappedRequest request, - WrappedResponse response) throws IOException { - Writer page = response.getWriter(); - WebBrowser b = request.getBrowserDetails().getWebBrowser(); - - page.write("<html><body><h1>I'm sorry, but your browser is not supported</h1>" - + "<p>The version (" - + b.getBrowserMajorVersion() - + "." - + b.getBrowserMinorVersion() - + ") of the browser you are using " - + " is outdated and not supported.</p>" - + "<p>You should <b>consider upgrading</b> to a more up-to-date browser.</p> " - + "<p>The most popular browsers are <b>" - + " <a href=\"https://www.google.com/chrome\">Chrome</a>," - + " <a href=\"http://www.mozilla.com/firefox\">Firefox</a>," - + (b.isWindows() ? " <a href=\"http://windows.microsoft.com/en-US/internet-explorer/downloads/ie\">Internet Explorer</a>," - : "") - + " <a href=\"http://www.opera.com/browser\">Opera</a>" - + " and <a href=\"http://www.apple.com/safari\">Safari</a>.</b><br/>" - + "Upgrading to the latest version of one of these <b>will make the web safer, faster and better looking.</b></p>" - + (b.isIE() ? "<script type=\"text/javascript\" src=\"http://ajax.googleapis.com/ajax/libs/chrome-frame/1/CFInstall.min.js\"></script>" - + "<p>If you can not upgrade your browser, please consider trying <a onclick=\"CFInstall.check({mode:'overlay'});return false;\" href=\"http://www.google.com/chromeframe\">Chrome Frame</a>.</p>" - : "") // - + "<p><sub><a onclick=\"document.cookie='" - + FORCE_LOAD_COOKIE - + "';window.location.reload();return false;\" href=\"#\">Continue without updating</a> (not recommended)</sub></p>" - + "</body>\n" + "</html>"); - - page.close(); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/UploadException.java b/src/com/vaadin/terminal/gwt/server/UploadException.java deleted file mode 100644 index 58253da0fb..0000000000 --- a/src/com/vaadin/terminal/gwt/server/UploadException.java +++ /dev/null @@ -1,15 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.terminal.gwt.server; - -@SuppressWarnings("serial") -public class UploadException extends Exception { - public UploadException(Exception e) { - super("Upload failed", e); - } - - public UploadException(String msg) { - super(msg); - } -} diff --git a/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java b/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java deleted file mode 100644 index 36c08b2ed9..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WebApplicationContext.java +++ /dev/null @@ -1,180 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.File; -import java.util.Enumeration; -import java.util.HashMap; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; - -import com.vaadin.Application; - -/** - * Web application context for Vaadin applications. - * - * This is automatically added as a {@link HttpSessionBindingListener} when - * added to a {@link HttpSession}. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.1 - */ -@SuppressWarnings("serial") -public class WebApplicationContext extends AbstractWebApplicationContext { - - protected transient HttpSession session; - private transient boolean reinitializingSession = false; - - /** - * Stores a reference to the currentRequest. Null it not inside a request. - */ - private transient Object currentRequest = null; - - /** - * Creates a new Web Application Context. - * - */ - protected WebApplicationContext() { - - } - - @Override - protected void startTransaction(Application application, Object request) { - currentRequest = request; - super.startTransaction(application, request); - } - - @Override - protected void endTransaction(Application application, Object request) { - super.endTransaction(application, request); - currentRequest = null; - } - - @Override - public void valueUnbound(HttpSessionBindingEvent event) { - if (!reinitializingSession) { - // Avoid closing the application if we are only reinitializing the - // session. Closing the application would cause the state to be lost - // and a new application to be created, which is not what we want. - super.valueUnbound(event); - } - } - - /** - * Discards the current session and creates a new session with the same - * contents. The purpose of this is to introduce a new session key in order - * to avoid session fixation attacks. - */ - @SuppressWarnings("unchecked") - public void reinitializeSession() { - - HttpSession oldSession = getHttpSession(); - - // Stores all attributes (security key, reference to this context - // instance) so they can be added to the new session - HashMap<String, Object> attrs = new HashMap<String, Object>(); - for (Enumeration<String> e = oldSession.getAttributeNames(); e - .hasMoreElements();) { - String name = e.nextElement(); - attrs.put(name, oldSession.getAttribute(name)); - } - - // Invalidate the current session, set flag to avoid call to - // valueUnbound - reinitializingSession = true; - oldSession.invalidate(); - reinitializingSession = false; - - // Create a new session - HttpSession newSession = ((HttpServletRequest) currentRequest) - .getSession(); - - // Restores all attributes (security key, reference to this context - // instance) - for (String name : attrs.keySet()) { - newSession.setAttribute(name, attrs.get(name)); - } - - // Update the "current session" variable - session = newSession; - } - - /** - * Gets the application context base directory. - * - * @see com.vaadin.service.ApplicationContext#getBaseDirectory() - */ - @Override - public File getBaseDirectory() { - final String realPath = ApplicationServlet.getResourcePath( - session.getServletContext(), "/"); - if (realPath == null) { - return null; - } - return new File(realPath); - } - - /** - * Gets the http-session application is running in. - * - * @return HttpSession this application context resides in. - */ - public HttpSession getHttpSession() { - return session; - } - - /** - * Gets the application context for an HttpSession. - * - * @param session - * the HTTP session. - * @return the application context for HttpSession. - */ - static public WebApplicationContext getApplicationContext( - HttpSession session) { - WebApplicationContext cx = (WebApplicationContext) session - .getAttribute(WebApplicationContext.class.getName()); - if (cx == null) { - cx = new WebApplicationContext(); - session.setAttribute(WebApplicationContext.class.getName(), cx); - } - if (cx.session == null) { - cx.session = session; - } - return cx; - } - - protected void addApplication(Application application) { - applications.add(application); - } - - /** - * Gets communication manager for an application. - * - * If this application has not been running before, a new manager is - * created. - * - * @param application - * @return CommunicationManager - */ - public CommunicationManager getApplicationManager(Application application, - AbstractApplicationServlet servlet) { - CommunicationManager mgr = (CommunicationManager) applicationToAjaxAppMgrMap - .get(application); - - if (mgr == null) { - // Creates new manager - mgr = servlet.createCommunicationManager(application); - applicationToAjaxAppMgrMap.put(application, mgr); - } - return mgr; - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/WebBrowser.java b/src/com/vaadin/terminal/gwt/server/WebBrowser.java deleted file mode 100644 index 4b92b12b66..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WebBrowser.java +++ /dev/null @@ -1,462 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.util.Date; -import java.util.Locale; - -import com.vaadin.shared.VBrowserDetails; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.WrappedRequest; - -/** - * Class that provides information about the web browser the user is using. - * Provides information such as browser name and version, screen resolution and - * IP address. - * - * @author Vaadin Ltd. - * @version @VERSION@ - */ -public class WebBrowser implements Terminal { - - private int screenHeight = 0; - private int screenWidth = 0; - private String browserApplication = null; - private Locale locale; - private String address; - private boolean secureConnection; - private int timezoneOffset = 0; - private int rawTimezoneOffset = 0; - private int dstSavings; - private boolean dstInEffect; - private boolean touchDevice; - - private VBrowserDetails browserDetails; - private long clientServerTimeDelta; - - /** - * There is no default-theme for this terminal type. - * - * @return Always returns null. - */ - - @Override - public String getDefaultTheme() { - return null; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Terminal#getScreenHeight() - */ - - @Override - public int getScreenHeight() { - return screenHeight; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Terminal#getScreenWidth() - */ - - @Override - public int getScreenWidth() { - return screenWidth; - } - - /** - * Get the browser user-agent string. - * - * @return The raw browser userAgent string - */ - public String getBrowserApplication() { - return browserApplication; - } - - /** - * Gets the IP-address of the web browser. If the application is running - * inside a portlet, this method will return null. - * - * @return IP-address in 1.12.123.123 -format - */ - public String getAddress() { - return address; - } - - /** Get the default locate of the browser. */ - public Locale getLocale() { - return locale; - } - - /** Is the connection made using HTTPS? */ - public boolean isSecureConnection() { - return secureConnection; - } - - /** - * Tests whether the user is using Firefox. - * - * @return true if the user is using Firefox, false if the user is not using - * Firefox or if no information on the browser is present - */ - public boolean isFirefox() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isFirefox(); - } - - /** - * Tests whether the user is using Internet Explorer. - * - * @return true if the user is using Internet Explorer, false if the user is - * not using Internet Explorer or if no information on the browser - * is present - */ - public boolean isIE() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isIE(); - } - - /** - * Tests whether the user is using Safari. - * - * @return true if the user is using Safari, false if the user is not using - * Safari or if no information on the browser is present - */ - public boolean isSafari() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isSafari(); - } - - /** - * Tests whether the user is using Opera. - * - * @return true if the user is using Opera, false if the user is not using - * Opera or if no information on the browser is present - */ - public boolean isOpera() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isOpera(); - } - - /** - * Tests whether the user is using Chrome. - * - * @return true if the user is using Chrome, false if the user is not using - * Chrome or if no information on the browser is present - */ - public boolean isChrome() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isChrome(); - } - - /** - * Tests whether the user is using Chrome Frame. - * - * @return true if the user is using Chrome Frame, false if the user is not - * using Chrome or if no information on the browser is present - */ - public boolean isChromeFrame() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isChromeFrame(); - } - - /** - * Tests whether the user's browser is Chrome Frame capable. - * - * @return true if the user can use Chrome Frame, false if the user can not - * or if no information on the browser is present - */ - public boolean isChromeFrameCapable() { - if (browserDetails == null) { - return false; - } - - return browserDetails.isChromeFrameCapable(); - } - - /** - * Gets the major version of the browser the user is using. - * - * <p> - * Note that Internet Explorer in IE7 compatibility mode might return 8 in - * some cases even though it should return 7. - * </p> - * - * @return The major version of the browser or -1 if not known. - */ - public int getBrowserMajorVersion() { - if (browserDetails == null) { - return -1; - } - - return browserDetails.getBrowserMajorVersion(); - } - - /** - * Gets the minor version of the browser the user is using. - * - * @see #getBrowserMajorVersion() - * - * @return The minor version of the browser or -1 if not known. - */ - public int getBrowserMinorVersion() { - if (browserDetails == null) { - return -1; - } - - return browserDetails.getBrowserMinorVersion(); - } - - /** - * Tests whether the user is using Linux. - * - * @return true if the user is using Linux, false if the user is not using - * Linux or if no information on the browser is present - */ - public boolean isLinux() { - return browserDetails.isLinux(); - } - - /** - * Tests whether the user is using Mac OS X. - * - * @return true if the user is using Mac OS X, false if the user is not - * using Mac OS X or if no information on the browser is present - */ - public boolean isMacOSX() { - return browserDetails.isMacOSX(); - } - - /** - * Tests whether the user is using Windows. - * - * @return true if the user is using Windows, false if the user is not using - * Windows or if no information on the browser is present - */ - public boolean isWindows() { - return browserDetails.isWindows(); - } - - /** - * Returns the browser-reported TimeZone offset in milliseconds from GMT. - * This includes possible daylight saving adjustments, to figure out which - * TimeZone the user actually might be in, see - * {@link #getRawTimezoneOffset()}. - * - * @see WebBrowser#getRawTimezoneOffset() - * @return timezone offset in milliseconds, 0 if not available - */ - public Integer getTimezoneOffset() { - return timezoneOffset; - } - - /** - * Returns the browser-reported TimeZone offset in milliseconds from GMT - * ignoring possible daylight saving adjustments that may be in effect in - * the browser. - * <p> - * You can use this to figure out which TimeZones the user could actually be - * in by calling {@link TimeZone#getAvailableIDs(int)}. - * </p> - * <p> - * If {@link #getRawTimezoneOffset()} and {@link #getTimezoneOffset()} - * returns the same value, the browser is either in a zone that does not - * currently have daylight saving time, or in a zone that never has daylight - * saving time. - * </p> - * - * @return timezone offset in milliseconds excluding DST, 0 if not available - */ - public Integer getRawTimezoneOffset() { - return rawTimezoneOffset; - } - - /** - * Gets the difference in minutes between the browser's GMT TimeZone and - * DST. - * - * @return the amount of minutes that the TimeZone shifts when DST is in - * effect - */ - public int getDSTSavings() { - return dstSavings; - } - - /** - * Determines whether daylight savings time (DST) is currently in effect in - * the region of the browser or not. - * - * @return true if the browser resides at a location that currently is in - * DST - */ - public boolean isDSTInEffect() { - return dstInEffect; - } - - /** - * Returns the current date and time of the browser. This will not be - * entirely accurate due to varying network latencies, but should provide a - * close-enough value for most cases. Also note that the returned Date - * object uses servers default time zone, not the clients. - * - * @return the current date and time of the browser. - * @see #isDSTInEffect() - * @see #getDSTSavings() - * @see #getTimezoneOffset() - */ - public Date getCurrentDate() { - return new Date(new Date().getTime() + clientServerTimeDelta); - } - - /** - * @return true if the browser is detected to support touch events - */ - public boolean isTouchDevice() { - return touchDevice; - } - - /** - * For internal use by AbstractApplicationServlet/AbstractApplicationPortlet - * only. Updates all properties in the class according to the given - * information. - * - * @param sw - * Screen width - * @param sh - * Screen height - * @param tzo - * TimeZone offset in minutes from GMT - * @param rtzo - * raw TimeZone offset in minutes from GMT (w/o DST adjustment) - * @param dstSavings - * the difference between the raw TimeZone and DST in minutes - * @param dstInEffect - * is DST currently active in the region or not? - * @param curDate - * the current date in milliseconds since the epoch - * @param touchDevice - */ - void updateClientSideDetails(String sw, String sh, String tzo, String rtzo, - String dstSavings, String dstInEffect, String curDate, - boolean touchDevice) { - if (sw != null) { - try { - screenHeight = Integer.parseInt(sh); - screenWidth = Integer.parseInt(sw); - } catch (final NumberFormatException e) { - screenHeight = screenWidth = 0; - } - } - if (tzo != null) { - try { - // browser->java conversion: min->ms, reverse sign - timezoneOffset = -Integer.parseInt(tzo) * 60 * 1000; - } catch (final NumberFormatException e) { - timezoneOffset = 0; // default gmt+0 - } - } - if (rtzo != null) { - try { - // browser->java conversion: min->ms, reverse sign - rawTimezoneOffset = -Integer.parseInt(rtzo) * 60 * 1000; - } catch (final NumberFormatException e) { - rawTimezoneOffset = 0; // default gmt+0 - } - } - if (dstSavings != null) { - try { - // browser->java conversion: min->ms - this.dstSavings = Integer.parseInt(dstSavings) * 60 * 1000; - } catch (final NumberFormatException e) { - this.dstSavings = 0; // default no savings - } - } - if (dstInEffect != null) { - this.dstInEffect = Boolean.parseBoolean(dstInEffect); - } - if (curDate != null) { - try { - long curTime = Long.parseLong(curDate); - clientServerTimeDelta = curTime - new Date().getTime(); - } catch (final NumberFormatException e) { - clientServerTimeDelta = 0; - } - } - this.touchDevice = touchDevice; - - } - - /** - * For internal use by AbstractApplicationServlet/AbstractApplicationPortlet - * only. Updates all properties in the class according to the given - * information. - * - * @param request - * the wrapped request to read the information from - */ - void updateRequestDetails(WrappedRequest request) { - locale = request.getLocale(); - address = request.getRemoteAddr(); - secureConnection = request.isSecure(); - String agent = request.getHeader("user-agent"); - - if (agent != null) { - browserApplication = agent; - browserDetails = new VBrowserDetails(agent); - } - - if (request.getParameter("sw") != null) { - updateClientSideDetails(request.getParameter("sw"), - request.getParameter("sh"), request.getParameter("tzo"), - request.getParameter("rtzo"), request.getParameter("dstd"), - request.getParameter("dston"), - request.getParameter("curdate"), - request.getParameter("td") != null); - } - } - - /** - * Checks if the browser is so old that it simply won't work with a Vaadin - * application. Can be used to redirect to an alternative page, show - * alternative content or similar. - * - * When this method returns true chances are very high that the browser - * won't work and it does not make sense to direct the user to the Vaadin - * application. - * - * @return true if the browser won't work, false if not the browser is - * supported or might work - */ - public boolean isTooOldToFunctionProperly() { - if (browserDetails == null) { - // Don't know, so assume it will work - return false; - } - - return browserDetails.isTooOldToFunctionProperly(); - } - -} diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java deleted file mode 100644 index cf58f398af..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletRequest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - -import com.vaadin.Application; -import com.vaadin.terminal.CombinedRequest; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedRequest; - -/** - * Wrapper for {@link HttpServletRequest}. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedRequest - * @see WrappedHttpServletResponse - */ -public class WrappedHttpServletRequest extends HttpServletRequestWrapper - implements WrappedRequest { - - private final DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a http servlet request and associates with a deployment - * configuration - * - * @param request - * the http servlet request to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedHttpServletRequest(HttpServletRequest request, - DeploymentConfiguration deploymentConfiguration) { - super(request); - this.deploymentConfiguration = deploymentConfiguration; - } - - @Override - public String getRequestPathInfo() { - return getPathInfo(); - } - - @Override - public int getSessionMaxInactiveInterval() { - return getSession().getMaxInactiveInterval(); - } - - @Override - public Object getSessionAttribute(String name) { - return getSession().getAttribute(name); - } - - @Override - public void setSessionAttribute(String name, Object attribute) { - getSession().setAttribute(name, attribute); - } - - /** - * Gets the original, unwrapped HTTP servlet request. - * - * @return the servlet request - */ - public HttpServletRequest getHttpServletRequest() { - return this; - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - @Override - public BrowserDetails getBrowserDetails() { - return new BrowserDetails() { - @Override - public String getUriFragment() { - return null; - } - - @Override - public String getWindowName() { - return null; - } - - @Override - public WebBrowser getWebBrowser() { - WebApplicationContext context = (WebApplicationContext) Application - .getCurrent().getContext(); - return context.getBrowser(); - } - }; - } - - /** - * Helper method to get a <code>WrappedHttpServletRequest</code> from a - * <code>WrappedRequest</code>. Aside from casting, this method also takes - * care of situations where there's another level of wrapping. - * - * @param request - * a wrapped request - * @return a wrapped http servlet request - * @throws ClassCastException - * if the wrapped request doesn't wrap a http servlet request - */ - public static WrappedHttpServletRequest cast(WrappedRequest request) { - if (request instanceof CombinedRequest) { - CombinedRequest combinedRequest = (CombinedRequest) request; - request = combinedRequest.getSecondRequest(); - } - return (WrappedHttpServletRequest) request; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java deleted file mode 100644 index 32b2f352a8..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedHttpServletResponse.java +++ /dev/null @@ -1,75 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedResponse; - -/** - * Wrapper for {@link HttpServletResponse}. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedResponse - * @see WrappedHttpServletRequest - */ -public class WrappedHttpServletResponse extends HttpServletResponseWrapper - implements WrappedResponse { - - private DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a http servlet response and an associated deployment configuration - * - * @param response - * the http servlet response to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedHttpServletResponse(HttpServletResponse response, - DeploymentConfiguration deploymentConfiguration) { - super(response); - this.deploymentConfiguration = deploymentConfiguration; - } - - /** - * Gets the original unwrapped <code>HttpServletResponse</code> - * - * @return the unwrapped response - */ - public HttpServletResponse getHttpServletResponse() { - return this; - } - - @Override - public void setCacheTime(long milliseconds) { - doSetCacheTime(this, milliseconds); - } - - // Implementation shared with WrappedPortletResponse - static void doSetCacheTime(WrappedResponse response, long milliseconds) { - if (milliseconds <= 0) { - response.setHeader("Cache-Control", "no-cache"); - response.setHeader("Pragma", "no-cache"); - response.setDateHeader("Expires", 0); - } else { - response.setHeader("Cache-Control", "max-age=" + milliseconds - / 1000); - response.setDateHeader("Expires", System.currentTimeMillis() - + milliseconds); - // Required to apply caching in some Tomcats - response.setHeader("Pragma", "cache"); - } - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java deleted file mode 100644 index a3fa172034..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java +++ /dev/null @@ -1,217 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Locale; -import java.util.Map; - -import javax.portlet.ClientDataRequest; -import javax.portlet.PortletRequest; -import javax.portlet.ResourceRequest; - -import com.vaadin.Application; -import com.vaadin.terminal.CombinedRequest; -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.gwt.client.ApplicationConnection; - -/** - * Wrapper for {@link PortletRequest} and its subclasses. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedRequest - * @see WrappedPortletResponse - */ -public class WrappedPortletRequest implements WrappedRequest { - - private final PortletRequest request; - private final DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a portlet request and an associated deployment configuration - * - * @param request - * the portlet request to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedPortletRequest(PortletRequest request, - DeploymentConfiguration deploymentConfiguration) { - this.request = request; - this.deploymentConfiguration = deploymentConfiguration; - } - - @Override - public Object getAttribute(String name) { - return request.getAttribute(name); - } - - @Override - public int getContentLength() { - try { - return ((ClientDataRequest) request).getContentLength(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Content lenght only available for ClientDataRequests"); - } - } - - @Override - public InputStream getInputStream() throws IOException { - try { - return ((ClientDataRequest) request).getPortletInputStream(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Input data only available for ClientDataRequests"); - } - } - - @Override - public String getParameter(String name) { - return request.getParameter(name); - } - - @Override - public Map<String, String[]> getParameterMap() { - return request.getParameterMap(); - } - - @Override - public void setAttribute(String name, Object o) { - request.setAttribute(name, o); - } - - @Override - public String getRequestPathInfo() { - if (request instanceof ResourceRequest) { - ResourceRequest resourceRequest = (ResourceRequest) request; - String resourceID = resourceRequest.getResourceID(); - if (AbstractApplicationPortlet.RESOURCE_URL_ID.equals(resourceID)) { - String resourcePath = resourceRequest - .getParameter(ApplicationConnection.V_RESOURCE_PATH); - return resourcePath; - } - return resourceID; - } else { - return null; - } - } - - @Override - public int getSessionMaxInactiveInterval() { - return request.getPortletSession().getMaxInactiveInterval(); - } - - @Override - public Object getSessionAttribute(String name) { - return request.getPortletSession().getAttribute(name); - } - - @Override - public void setSessionAttribute(String name, Object attribute) { - request.getPortletSession().setAttribute(name, attribute); - } - - /** - * Gets the original, unwrapped portlet request. - * - * @return the unwrapped portlet request - */ - public PortletRequest getPortletRequest() { - return request; - } - - @Override - public String getContentType() { - try { - return ((ResourceRequest) request).getContentType(); - } catch (ClassCastException e) { - throw new IllegalStateException( - "Content type only available for ResourceRequests"); - } - } - - @Override - public BrowserDetails getBrowserDetails() { - return new BrowserDetails() { - @Override - public String getUriFragment() { - return null; - } - - @Override - public String getWindowName() { - return null; - } - - @Override - public WebBrowser getWebBrowser() { - PortletApplicationContext2 context = (PortletApplicationContext2) Application - .getCurrent().getContext(); - return context.getBrowser(); - } - }; - } - - @Override - public Locale getLocale() { - return request.getLocale(); - } - - @Override - public String getRemoteAddr() { - return null; - } - - @Override - public boolean isSecure() { - return request.isSecure(); - } - - @Override - public String getHeader(String string) { - return null; - } - - /** - * Reads a portal property from the portal context of the wrapped request. - * - * @param name - * a string with the name of the portal property to get - * @return a string with the value of the property, or <code>null</code> if - * the property is not defined - */ - public String getPortalProperty(String name) { - return request.getPortalContext().getProperty(name); - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } - - /** - * Helper method to get a <code>WrappedPortlettRequest</code> from a - * <code>WrappedRequest</code>. Aside from casting, this method also takes - * care of situations where there's another level of wrapping. - * - * @param request - * a wrapped request - * @return a wrapped portlet request - * @throws ClassCastException - * if the wrapped request doesn't wrap a portlet request - */ - public static WrappedPortletRequest cast(WrappedRequest request) { - if (request instanceof CombinedRequest) { - CombinedRequest combinedRequest = (CombinedRequest) request; - request = combinedRequest.getSecondRequest(); - } - return (WrappedPortletRequest) request; - } -} diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java deleted file mode 100644 index f7ecf26f3c..0000000000 --- a/src/com/vaadin/terminal/gwt/server/WrappedPortletResponse.java +++ /dev/null @@ -1,111 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.terminal.gwt.server; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -import javax.portlet.MimeResponse; -import javax.portlet.PortletResponse; -import javax.portlet.ResourceResponse; - -import com.vaadin.terminal.DeploymentConfiguration; -import com.vaadin.terminal.WrappedResponse; - -/** - * Wrapper for {@link PortletResponse} and its subclasses. - * - * @author Vaadin Ltd. - * @since 7.0 - * - * @see WrappedResponse - * @see WrappedPortletRequest - */ -public class WrappedPortletResponse implements WrappedResponse { - private static final DateFormat HTTP_DATE_FORMAT = new SimpleDateFormat( - "EEE, dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH); - static { - HTTP_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - private final PortletResponse response; - private DeploymentConfiguration deploymentConfiguration; - - /** - * Wraps a portlet response and an associated deployment configuration - * - * @param response - * the portlet response to wrap - * @param deploymentConfiguration - * the associated deployment configuration - */ - public WrappedPortletResponse(PortletResponse response, - DeploymentConfiguration deploymentConfiguration) { - this.response = response; - this.deploymentConfiguration = deploymentConfiguration; - } - - @Override - public OutputStream getOutputStream() throws IOException { - return ((MimeResponse) response).getPortletOutputStream(); - } - - /** - * Gets the original, unwrapped portlet response. - * - * @return the unwrapped portlet response - */ - public PortletResponse getPortletResponse() { - return response; - } - - @Override - public void setContentType(String type) { - ((MimeResponse) response).setContentType(type); - } - - @Override - public PrintWriter getWriter() throws IOException { - return ((MimeResponse) response).getWriter(); - } - - @Override - public void setStatus(int responseStatus) { - response.setProperty(ResourceResponse.HTTP_STATUS_CODE, - Integer.toString(responseStatus)); - } - - @Override - public void setHeader(String name, String value) { - response.setProperty(name, value); - } - - @Override - public void setDateHeader(String name, long timestamp) { - response.setProperty(name, HTTP_DATE_FORMAT.format(new Date(timestamp))); - } - - @Override - public void setCacheTime(long milliseconds) { - WrappedHttpServletResponse.doSetCacheTime(this, milliseconds); - } - - @Override - public void sendError(int errorCode, String message) throws IOException { - setStatus(errorCode); - getWriter().write(message); - } - - @Override - public DeploymentConfiguration getDeploymentConfiguration() { - return deploymentConfiguration; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/terminal/package.html b/src/com/vaadin/terminal/package.html deleted file mode 100644 index 83514a0de5..0000000000 --- a/src/com/vaadin/terminal/package.html +++ /dev/null @@ -1,21 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> - -</head> - -<body bgcolor="white"> - -<!-- Package summary here --> - -<p>Provides classes and interfaces that wrap the terminal-side functionalities -for the server-side application. (FIXME: This could be a little more descriptive and wordy.)</p> - -<h2>Package Specification</h2> - -<!-- Package spec here --> - -<!-- Put @see and @since tags down here. --> - -</body> -</html> diff --git a/src/com/vaadin/tools/ReflectTools.java b/src/com/vaadin/tools/ReflectTools.java deleted file mode 100644 index ea2afae301..0000000000 --- a/src/com/vaadin/tools/ReflectTools.java +++ /dev/null @@ -1,126 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.tools; - -import java.beans.IntrospectionException; -import java.beans.PropertyDescriptor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -/** - * An util class with helpers for reflection operations. Used internally by - * Vaadin and should not be used by application developers. Subject to change at - * any time. - * - * @since 6.2 - */ -public class ReflectTools { - /** - * Locates the method in the given class. Returns null if the method is not - * found. Throws an ExceptionInInitializerError if there is a problem - * locating the method as this is mainly called from static blocks. - * - * @param cls - * Class that contains the method - * @param methodName - * The name of the method - * @param parameterTypes - * The parameter types for the method. - * @return A reference to the method - * @throws ExceptionInInitializerError - * Wraps any exception in an {@link ExceptionInInitializerError} - * so this method can be called from a static initializer. - */ - public static Method findMethod(Class<?> cls, String methodName, - Class<?>... parameterTypes) throws ExceptionInInitializerError { - try { - return cls.getDeclaredMethod(methodName, parameterTypes); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } - - /** - * Returns the value of the java field. - * <p> - * Uses getter if present, otherwise tries to access even private fields - * directly. - * - * @param object - * The object containing the field - * @param field - * The field we want to get the value for - * @return The value of the field in the object - * @throws InvocationTargetException - * If the value could not be retrieved - * @throws IllegalAccessException - * If the value could not be retrieved - * @throws IllegalArgumentException - * If the value could not be retrieved - */ - public static Object getJavaFieldValue(Object object, - java.lang.reflect.Field field) throws IllegalArgumentException, - IllegalAccessException, InvocationTargetException { - PropertyDescriptor pd; - try { - pd = new PropertyDescriptor(field.getName(), object.getClass()); - Method getter = pd.getReadMethod(); - if (getter != null) { - return getter.invoke(object, (Object[]) null); - } - } catch (IntrospectionException e1) { - // Ignore this and try to get directly using the field - } - - // Try to get the value or throw an exception - if (!field.isAccessible()) { - // Try to gain access even if field is private - field.setAccessible(true); - } - return field.get(object); - } - - /** - * Sets the value of a java field. - * <p> - * Uses setter if present, otherwise tries to access even private fields - * directly. - * - * @param object - * The object containing the field - * @param field - * The field we want to set the value for - * @param value - * The value to set - * @throws IllegalAccessException - * If the value could not be assigned to the field - * @throws IllegalArgumentException - * If the value could not be assigned to the field - * @throws InvocationTargetException - * If the value could not be assigned to the field - */ - public static void setJavaFieldValue(Object object, - java.lang.reflect.Field field, Object value) - throws IllegalAccessException, IllegalArgumentException, - InvocationTargetException { - PropertyDescriptor pd; - try { - pd = new PropertyDescriptor(field.getName(), object.getClass()); - Method setter = pd.getWriteMethod(); - if (setter != null) { - // Exceptions are thrown forward if this fails - setter.invoke(object, value); - } - } catch (IntrospectionException e1) { - // Ignore this and try to set directly using the field - } - - // Try to set the value directly to the field or throw an exception - if (!field.isAccessible()) { - // Try to gain access even if field is private - field.setAccessible(true); - } - field.set(object, value); - } -} diff --git a/src/com/vaadin/tools/WidgetsetCompiler.java b/src/com/vaadin/tools/WidgetsetCompiler.java deleted file mode 100644 index ecc1946e60..0000000000 --- a/src/com/vaadin/tools/WidgetsetCompiler.java +++ /dev/null @@ -1,94 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.tools; - -import java.lang.reflect.Method; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.terminal.gwt.widgetsetutils.WidgetSetBuilder; - -/** - * A wrapper for the GWT 1.6 compiler that runs the compiler in a new thread. - * - * This allows circumventing a J2SE 5.0 bug (6316197) that prevents setting the - * stack size for the main thread. Thus, larger widgetsets can be compiled. - * - * This class takes the same command line arguments as the - * com.google.gwt.dev.GWTCompiler class. The old and deprecated compiler is used - * for compatibility with GWT 1.5. - * - * A typical invocation would use e.g. the following arguments - * - * "-out WebContent/VAADIN/widgetsets com.vaadin.terminal.gwt.DefaultWidgetSet" - * - * In addition, larger memory usage settings for the VM should be used, e.g. - * - * "-Xms256M -Xmx512M -Xss8M" - * - * The source directory containing widgetset and related classes must be - * included in the classpath, as well as the gwt-dev-[platform].jar and other - * relevant JARs. - * - * @deprecated with Java 6, can use com.google.gwt.dev.Compiler directly (also - * in Eclipse plug-in etc.) - */ -@Deprecated -public class WidgetsetCompiler { - - /** - * @param args - * same arguments as for com.google.gwt.dev.Compiler - */ - public static void main(final String[] args) { - try { - // run the compiler in a different thread to enable using the - // user-set stack size - - // on Windows, the default stack size is too small for the main - // thread and cannot be changed in JRE 1.5 (see - // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6316197) - - Runnable runCompiler = new Runnable() { - @Override - public void run() { - try { - // GWTCompiler.main(args); - // avoid warnings - - String wsname = args[args.length - 1]; - - // TODO expecting this is launched via eclipse WTP - // project - System.out - .println("Updating GWT module description file..."); - WidgetSetBuilder.updateWidgetSet(wsname); - System.out.println("Done."); - - System.out.println("Starting GWT compiler"); - System.setProperty("gwt.nowarn.legacy.tools", "true"); - Class<?> compilerClass = Class - .forName("com.google.gwt.dev.GWTCompiler"); - Method method = compilerClass.getDeclaredMethod("main", - String[].class); - method.invoke(null, new Object[] { args }); - } catch (Throwable thr) { - getLogger().log(Level.SEVERE, - "Widgetset compilation failed", thr); - } - } - }; - Thread runThread = new Thread(runCompiler); - runThread.start(); - runThread.join(); - System.out.println("Widgetset compilation finished"); - } catch (Throwable thr) { - getLogger().log(Level.SEVERE, "Widgetset compilation failed", thr); - } - } - - private static final Logger getLogger() { - return Logger.getLogger(WidgetsetCompiler.class.getName()); - } -} diff --git a/src/com/vaadin/ui/AbsoluteLayout.java b/src/com/vaadin/ui/AbsoluteLayout.java deleted file mode 100644 index 1c84ca2865..0000000000 --- a/src/com/vaadin/ui/AbsoluteLayout.java +++ /dev/null @@ -1,632 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; - -import com.vaadin.event.LayoutEvents.LayoutClickEvent; -import com.vaadin.event.LayoutEvents.LayoutClickListener; -import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.shared.Connector; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.absolutelayout.AbsoluteLayoutServerRpc; -import com.vaadin.shared.ui.absolutelayout.AbsoluteLayoutState; -import com.vaadin.terminal.Sizeable; -import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; - -/** - * AbsoluteLayout is a layout implementation that mimics html absolute - * positioning. - * - */ -@SuppressWarnings("serial") -public class AbsoluteLayout extends AbstractLayout implements - LayoutClickNotifier { - - private AbsoluteLayoutServerRpc rpc = new AbsoluteLayoutServerRpc() { - - @Override - public void layoutClick(MouseEventDetails mouseDetails, - Connector clickedConnector) { - fireEvent(LayoutClickEvent.createEvent(AbsoluteLayout.this, - mouseDetails, clickedConnector)); - } - }; - // Maps each component to a position - private LinkedHashMap<Component, ComponentPosition> componentToCoordinates = new LinkedHashMap<Component, ComponentPosition>(); - - /** - * Creates an AbsoluteLayout with full size. - */ - public AbsoluteLayout() { - registerRpc(rpc); - setSizeFull(); - } - - @Override - public AbsoluteLayoutState getState() { - return (AbsoluteLayoutState) super.getState(); - } - - /** - * Gets an iterator for going through all components enclosed in the - * absolute layout. - */ - @Override - public Iterator<Component> getComponentIterator() { - return componentToCoordinates.keySet().iterator(); - } - - /** - * Gets the number of contained components. Consistent with the iterator - * returned by {@link #getComponentIterator()}. - * - * @return the number of contained components - */ - @Override - public int getComponentCount() { - return componentToCoordinates.size(); - } - - /** - * Replaces one component with another one. The new component inherits the - * old components position. - */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - ComponentPosition position = getPosition(oldComponent); - removeComponent(oldComponent); - addComponent(newComponent, position); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.ui.AbstractComponentContainer#addComponent(com.vaadin.ui.Component - * ) - */ - @Override - public void addComponent(Component c) { - addComponent(c, new ComponentPosition()); - } - - /** - * Adds a component to the layout. The component can be positioned by - * providing a string formatted in CSS-format. - * <p> - * For example the string "top:10px;left:10px" will position the component - * 10 pixels from the left and 10 pixels from the top. The identifiers: - * "top","left","right" and "bottom" can be used to specify the position. - * </p> - * - * @param c - * The component to add to the layout - * @param cssPosition - * The css position string - */ - public void addComponent(Component c, String cssPosition) { - ComponentPosition position = new ComponentPosition(); - position.setCSSString(cssPosition); - addComponent(c, position); - } - - /** - * Adds the component using the given position. Ensures the position is only - * set if the component is added correctly. - * - * @param c - * The component to add - * @param position - * The position info for the component. Must not be null. - * @throws IllegalArgumentException - * If adding the component failed - */ - private void addComponent(Component c, ComponentPosition position) - throws IllegalArgumentException { - /* - * Create position instance and add it to componentToCoordinates map. We - * need to do this before we call addComponent so the attachListeners - * can access this position. #6368 - */ - internalSetPosition(c, position); - try { - super.addComponent(c); - } catch (IllegalArgumentException e) { - internalRemoveComponent(c); - throw e; - } - requestRepaint(); - } - - /** - * Removes the component from all internal data structures. Does not - * actually remove the component from the layout (this is assumed to have - * been done by the caller). - * - * @param c - * The component to remove - */ - private void internalRemoveComponent(Component c) { - componentToCoordinates.remove(c); - } - - @Override - public void updateState() { - super.updateState(); - - // This could be in internalRemoveComponent and internalSetComponent if - // Map<Connector,String> was supported. We cannot get the child - // connectorId unless the component is attached to the application so - // the String->String map cannot be populated in internal* either. - Map<String, String> connectorToPosition = new HashMap<String, String>(); - for (Iterator<Component> ci = getComponentIterator(); ci.hasNext();) { - Component c = ci.next(); - connectorToPosition.put(c.getConnectorId(), getPosition(c) - .getCSSString()); - } - getState().setConnectorToCssPosition(connectorToPosition); - - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui - * .Component) - */ - @Override - public void removeComponent(Component c) { - internalRemoveComponent(c); - super.removeComponent(c); - requestRepaint(); - } - - /** - * Gets the position of a component in the layout. Returns null if component - * is not attached to the layout. - * <p> - * Note that you cannot update the position by updating this object. Call - * {@link #setPosition(Component, ComponentPosition)} with the updated - * {@link ComponentPosition} object. - * </p> - * - * @param component - * The component which position is needed - * @return An instance of ComponentPosition containing the position of the - * component, or null if the component is not enclosed in the - * layout. - */ - public ComponentPosition getPosition(Component component) { - return componentToCoordinates.get(component); - } - - /** - * Sets the position of a component in the layout. - * - * @param component - * @param position - */ - public void setPosition(Component component, ComponentPosition position) { - if (!componentToCoordinates.containsKey(component)) { - throw new IllegalArgumentException( - "Component must be a child of this layout"); - } - internalSetPosition(component, position); - } - - /** - * Updates the position for a component. Caller must ensure component is a - * child of this layout. - * - * @param component - * The component. Must be a child for this layout. Not enforced. - * @param position - * New position. Must not be null. - */ - private void internalSetPosition(Component component, - ComponentPosition position) { - componentToCoordinates.put(component, position); - requestRepaint(); - } - - /** - * The CompontPosition class represents a components position within the - * absolute layout. It contains the attributes for left, right, top and - * bottom and the units used to specify them. - */ - public class ComponentPosition implements Serializable { - - private int zIndex = -1; - private Float topValue = null; - private Float rightValue = null; - private Float bottomValue = null; - private Float leftValue = null; - - private Unit topUnits = Unit.PIXELS; - private Unit rightUnits = Unit.PIXELS; - private Unit bottomUnits = Unit.PIXELS; - private Unit leftUnits = Unit.PIXELS; - - /** - * Sets the position attributes using CSS syntax. Attributes not - * included in the string are reset to their unset states. - * - * <code><pre> - * setCSSString("top:10px;left:20%;z-index:16;"); - * </pre></code> - * - * @param css - */ - public void setCSSString(String css) { - topValue = rightValue = bottomValue = leftValue = null; - topUnits = rightUnits = bottomUnits = leftUnits = Unit.PIXELS; - zIndex = -1; - if (css == null) { - return; - } - - String[] cssProperties = css.split(";"); - for (int i = 0; i < cssProperties.length; i++) { - String[] keyValuePair = cssProperties[i].split(":"); - String key = keyValuePair[0].trim(); - if (key.equals("")) { - continue; - } - if (key.equals("z-index")) { - zIndex = Integer.parseInt(keyValuePair[1].trim()); - } else { - String value; - if (keyValuePair.length > 1) { - value = keyValuePair[1].trim(); - } else { - value = ""; - } - String symbol = value.replaceAll("[0-9\\.\\-]+", ""); - if (!symbol.equals("")) { - value = value.substring(0, value.indexOf(symbol)) - .trim(); - } - float v = Float.parseFloat(value); - Unit unit = Unit.getUnitFromSymbol(symbol); - if (key.equals("top")) { - topValue = v; - topUnits = unit; - } else if (key.equals("right")) { - rightValue = v; - rightUnits = unit; - } else if (key.equals("bottom")) { - bottomValue = v; - bottomUnits = unit; - } else if (key.equals("left")) { - leftValue = v; - leftUnits = unit; - } - } - } - requestRepaint(); - } - - /** - * Converts the internal values into a valid CSS string. - * - * @return A valid CSS string - */ - public String getCSSString() { - String s = ""; - if (topValue != null) { - s += "top:" + topValue + topUnits.getSymbol() + ";"; - } - if (rightValue != null) { - s += "right:" + rightValue + rightUnits.getSymbol() + ";"; - } - if (bottomValue != null) { - s += "bottom:" + bottomValue + bottomUnits.getSymbol() + ";"; - } - if (leftValue != null) { - s += "left:" + leftValue + leftUnits.getSymbol() + ";"; - } - if (zIndex >= 0) { - s += "z-index:" + zIndex + ";"; - } - return s; - } - - /** - * Sets the 'top' attribute; distance from the top of the component to - * the top edge of the layout. - * - * @param topValue - * The value of the 'top' attribute - * @param topUnits - * The unit of the 'top' attribute. See UNIT_SYMBOLS for a - * description of the available units. - */ - public void setTop(Float topValue, Unit topUnits) { - this.topValue = topValue; - this.topUnits = topUnits; - requestRepaint(); - } - - /** - * Sets the 'right' attribute; distance from the right of the component - * to the right edge of the layout. - * - * @param rightValue - * The value of the 'right' attribute - * @param rightUnits - * The unit of the 'right' attribute. See UNIT_SYMBOLS for a - * description of the available units. - */ - public void setRight(Float rightValue, Unit rightUnits) { - this.rightValue = rightValue; - this.rightUnits = rightUnits; - requestRepaint(); - } - - /** - * Sets the 'bottom' attribute; distance from the bottom of the - * component to the bottom edge of the layout. - * - * @param bottomValue - * The value of the 'bottom' attribute - * @param units - * The unit of the 'bottom' attribute. See UNIT_SYMBOLS for a - * description of the available units. - */ - public void setBottom(Float bottomValue, Unit bottomUnits) { - this.bottomValue = bottomValue; - this.bottomUnits = bottomUnits; - requestRepaint(); - } - - /** - * Sets the 'left' attribute; distance from the left of the component to - * the left edge of the layout. - * - * @param leftValue - * The value of the 'left' attribute - * @param units - * The unit of the 'left' attribute. See UNIT_SYMBOLS for a - * description of the available units. - */ - public void setLeft(Float leftValue, Unit leftUnits) { - this.leftValue = leftValue; - this.leftUnits = leftUnits; - requestRepaint(); - } - - /** - * Sets the 'z-index' attribute; the visual stacking order - * - * @param zIndex - * The z-index for the component. - */ - public void setZIndex(int zIndex) { - this.zIndex = zIndex; - requestRepaint(); - } - - /** - * Sets the value of the 'top' attribute; distance from the top of the - * component to the top edge of the layout. - * - * @param topValue - * The value of the 'left' attribute - */ - public void setTopValue(Float topValue) { - this.topValue = topValue; - requestRepaint(); - } - - /** - * Gets the 'top' attributes value in current units. - * - * @see #getTopUnits() - * @return The value of the 'top' attribute, null if not set - */ - public Float getTopValue() { - return topValue; - } - - /** - * Gets the 'right' attributes value in current units. - * - * @return The value of the 'right' attribute, null if not set - * @see #getRightUnits() - */ - public Float getRightValue() { - return rightValue; - } - - /** - * Sets the 'right' attribute value (distance from the right of the - * component to the right edge of the layout). Currently active units - * are maintained. - * - * @param rightValue - * The value of the 'right' attribute - * @see #setRightUnits(int) - */ - public void setRightValue(Float rightValue) { - this.rightValue = rightValue; - requestRepaint(); - } - - /** - * Gets the 'bottom' attributes value using current units. - * - * @return The value of the 'bottom' attribute, null if not set - * @see #getBottomUnits() - */ - public Float getBottomValue() { - return bottomValue; - } - - /** - * Sets the 'bottom' attribute value (distance from the bottom of the - * component to the bottom edge of the layout). Currently active units - * are maintained. - * - * @param bottomValue - * The value of the 'bottom' attribute - * @see #setBottomUnits(int) - */ - public void setBottomValue(Float bottomValue) { - this.bottomValue = bottomValue; - requestRepaint(); - } - - /** - * Gets the 'left' attributes value using current units. - * - * @return The value of the 'left' attribute, null if not set - * @see #getLeftUnits() - */ - public Float getLeftValue() { - return leftValue; - } - - /** - * Sets the 'left' attribute value (distance from the left of the - * component to the left edge of the layout). Currently active units are - * maintained. - * - * @param leftValue - * The value of the 'left' CSS-attribute - * @see #setLeftUnits(int) - */ - public void setLeftValue(Float leftValue) { - this.leftValue = leftValue; - requestRepaint(); - } - - /** - * Gets the unit for the 'top' attribute - * - * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public Unit getTopUnits() { - return topUnits; - } - - /** - * Sets the unit for the 'top' attribute - * - * @param topUnits - * See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public void setTopUnits(Unit topUnits) { - this.topUnits = topUnits; - requestRepaint(); - } - - /** - * Gets the unit for the 'right' attribute - * - * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public Unit getRightUnits() { - return rightUnits; - } - - /** - * Sets the unit for the 'right' attribute - * - * @param rightUnits - * See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public void setRightUnits(Unit rightUnits) { - this.rightUnits = rightUnits; - requestRepaint(); - } - - /** - * Gets the unit for the 'bottom' attribute - * - * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public Unit getBottomUnits() { - return bottomUnits; - } - - /** - * Sets the unit for the 'bottom' attribute - * - * @param bottomUnits - * See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public void setBottomUnits(Unit bottomUnits) { - this.bottomUnits = bottomUnits; - requestRepaint(); - } - - /** - * Gets the unit for the 'left' attribute - * - * @return See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public Unit getLeftUnits() { - return leftUnits; - } - - /** - * Sets the unit for the 'left' attribute - * - * @param leftUnits - * See {@link Sizeable} UNIT_SYMBOLS for a description of the - * available units. - */ - public void setLeftUnits(Unit leftUnits) { - this.leftUnits = leftUnits; - requestRepaint(); - } - - /** - * Gets the 'z-index' attribute. - * - * @return the zIndex The z-index attribute - */ - public int getZIndex() { - return zIndex; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#toString() - */ - @Override - public String toString() { - return getCSSString(); - } - - } - - @Override - public void addListener(LayoutClickListener listener) { - addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener, - LayoutClickListener.clickMethod); - } - - @Override - public void removeListener(LayoutClickListener listener) { - removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener); - } - -} diff --git a/src/com/vaadin/ui/AbstractComponent.java b/src/com/vaadin/ui/AbstractComponent.java deleted file mode 100644 index e7cb38256c..0000000000 --- a/src/com/vaadin/ui/AbstractComponent.java +++ /dev/null @@ -1,1382 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.vaadin.Application; -import com.vaadin.event.ActionManager; -import com.vaadin.event.EventRouter; -import com.vaadin.event.MethodEventSource; -import com.vaadin.event.ShortcutListener; -import com.vaadin.shared.ComponentState; -import com.vaadin.terminal.AbstractClientConnector; -import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Terminal; -import com.vaadin.terminal.gwt.server.ClientConnector; -import com.vaadin.terminal.gwt.server.ComponentSizeValidator; -import com.vaadin.terminal.gwt.server.ResourceReference; -import com.vaadin.tools.ReflectTools; - -/** - * An abstract class that defines default implementation for the - * {@link Component} interface. Basic UI components that are not derived from an - * external component can inherit this class to easily qualify as Vaadin - * components. Most components in Vaadin do just that. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public abstract class AbstractComponent extends AbstractClientConnector - implements Component, MethodEventSource { - - /* Private members */ - - /** - * Application specific data object. The component does not use or modify - * this. - */ - private Object applicationData; - - /** - * The EventRouter used for the event model. - */ - private EventRouter eventRouter = null; - - /** - * The internal error message of the component. - */ - private ErrorMessage componentError = null; - - /** - * Locale of this component. - */ - private Locale locale; - - /** - * The component should receive focus (if {@link Focusable}) when attached. - */ - private boolean delayedFocus; - - /* Sizeable fields */ - - private float width = SIZE_UNDEFINED; - private float height = SIZE_UNDEFINED; - private Unit widthUnit = Unit.PIXELS; - private Unit heightUnit = Unit.PIXELS; - private static final Pattern sizePattern = Pattern - .compile("^(-?\\d+(\\.\\d+)?)(%|px|em|ex|in|cm|mm|pt|pc)?$"); - - private ComponentErrorHandler errorHandler = null; - - /** - * Keeps track of the Actions added to this component; the actual - * handling/notifying is delegated, usually to the containing window. - */ - private ActionManager actionManager; - - /* Constructor */ - - /** - * Constructs a new Component. - */ - public AbstractComponent() { - // ComponentSizeValidator.setCreationLocation(this); - } - - /* Get/Set component properties */ - - @Override - public void setDebugId(String id) { - getState().setDebugId(id); - } - - @Override - public String getDebugId() { - return getState().getDebugId(); - } - - /** - * Gets style for component. Multiple styles are joined with spaces. - * - * @return the component's styleValue of property style. - * @deprecated Use getStyleName() instead; renamed for consistency and to - * indicate that "style" should not be used to switch client - * side implementation, only to style the component. - */ - @Deprecated - public String getStyle() { - return getStyleName(); - } - - /** - * Sets and replaces all previous style names of the component. This method - * will trigger a {@link RepaintRequestEvent}. - * - * @param style - * the new style of the component. - * @deprecated Use setStyleName() instead; renamed for consistency and to - * indicate that "style" should not be used to switch client - * side implementation, only to style the component. - */ - @Deprecated - public void setStyle(String style) { - setStyleName(style); - } - - /* - * Gets the component's style. Don't add a JavaDoc comment here, we use the - * default documentation from implemented interface. - */ - @Override - public String getStyleName() { - String s = ""; - if (getState().getStyles() != null) { - for (final Iterator<String> it = getState().getStyles().iterator(); it - .hasNext();) { - s += it.next(); - if (it.hasNext()) { - s += " "; - } - } - } - return s; - } - - /* - * Sets the component's style. Don't add a JavaDoc comment here, we use the - * default documentation from implemented interface. - */ - @Override - public void setStyleName(String style) { - if (style == null || "".equals(style)) { - getState().setStyles(null); - requestRepaint(); - return; - } - if (getState().getStyles() == null) { - getState().setStyles(new ArrayList<String>()); - } - List<String> styles = getState().getStyles(); - styles.clear(); - String[] styleParts = style.split(" +"); - for (String part : styleParts) { - if (part.length() > 0) { - styles.add(part); - } - } - requestRepaint(); - } - - @Override - public void addStyleName(String style) { - if (style == null || "".equals(style)) { - return; - } - if (style.contains(" ")) { - // Split space separated style names and add them one by one. - for (String realStyle : style.split(" ")) { - addStyleName(realStyle); - } - return; - } - - if (getState().getStyles() == null) { - getState().setStyles(new ArrayList<String>()); - } - List<String> styles = getState().getStyles(); - if (!styles.contains(style)) { - styles.add(style); - requestRepaint(); - } - } - - @Override - public void removeStyleName(String style) { - if (getState().getStyles() != null) { - String[] styleParts = style.split(" +"); - for (String part : styleParts) { - if (part.length() > 0) { - getState().getStyles().remove(part); - } - } - requestRepaint(); - } - } - - /* - * Get's the component's caption. Don't add a JavaDoc comment here, we use - * the default documentation from implemented interface. - */ - @Override - public String getCaption() { - return getState().getCaption(); - } - - /** - * Sets the component's caption <code>String</code>. Caption is the visible - * name of the component. This method will trigger a - * {@link RepaintRequestEvent}. - * - * @param caption - * the new caption <code>String</code> for the component. - */ - @Override - public void setCaption(String caption) { - getState().setCaption(caption); - requestRepaint(); - } - - /* - * Don't add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public Locale getLocale() { - if (locale != null) { - return locale; - } - HasComponents parent = getParent(); - if (parent != null) { - return parent.getLocale(); - } - final Application app = getApplication(); - if (app != null) { - return app.getLocale(); - } - return null; - } - - /** - * Sets the locale of this component. - * - * <pre> - * // Component for which the locale is meaningful - * InlineDateField date = new InlineDateField("Datum"); - * - * // German language specified with ISO 639-1 language - * // code and ISO 3166-1 alpha-2 country code. - * date.setLocale(new Locale("de", "DE")); - * - * date.setResolution(DateField.RESOLUTION_DAY); - * layout.addComponent(date); - * </pre> - * - * - * @param locale - * the locale to become this component's locale. - */ - public void setLocale(Locale locale) { - this.locale = locale; - - // FIXME: Reload value if there is a converter - requestRepaint(); - } - - /* - * Gets the component's icon resource. Don't add a JavaDoc comment here, we - * use the default documentation from implemented interface. - */ - @Override - public Resource getIcon() { - return ResourceReference.getResource(getState().getIcon()); - } - - /** - * Sets the component's icon. This method will trigger a - * {@link RepaintRequestEvent}. - * - * @param icon - * the icon to be shown with the component's caption. - */ - @Override - public void setIcon(Resource icon) { - getState().setIcon(ResourceReference.create(icon)); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component#isEnabled() - */ - @Override - public boolean isEnabled() { - return getState().isEnabled(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component#setEnabled(boolean) - */ - @Override - public void setEnabled(boolean enabled) { - if (getState().isEnabled() != enabled) { - getState().setEnabled(enabled); - requestRepaint(); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.gwt.client.Connector#isConnectorEnabled() - */ - @Override - public boolean isConnectorEnabled() { - if (!isVisible()) { - return false; - } else if (!isEnabled()) { - return false; - } else if (!super.isConnectorEnabled()) { - return false; - } else if (!getParent().isComponentVisible(this)) { - return false; - } else { - return true; - } - } - - /* - * Tests if the component is in the immediate mode. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - public boolean isImmediate() { - return getState().isImmediate(); - } - - /** - * Sets the component's immediate mode to the specified status. This method - * will trigger a {@link RepaintRequestEvent}. - * - * @param immediate - * the boolean value specifying if the component should be in the - * immediate mode after the call. - * @see Component#isImmediate() - */ - public void setImmediate(boolean immediate) { - getState().setImmediate(immediate); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component#isVisible() - */ - @Override - public boolean isVisible() { - return getState().isVisible(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component#setVisible(boolean) - */ - @Override - public void setVisible(boolean visible) { - if (getState().isVisible() == visible) { - return; - } - - getState().setVisible(visible); - requestRepaint(); - if (getParent() != null) { - // Must always repaint the parent (at least the hierarchy) when - // visibility of a child component changes. - getParent().requestRepaint(); - } - } - - /** - * <p> - * Gets the component's description, used in tooltips and can be displayed - * directly in certain other components such as forms. The description can - * be used to briefly describe the state of the component to the user. The - * description string may contain certain XML tags: - * </p> - * - * <p> - * <table border=1> - * <tr> - * <td width=120><b>Tag</b></td> - * <td width=120><b>Description</b></td> - * <td width=120><b>Example</b></td> - * </tr> - * <tr> - * <td><b></td> - * <td>bold</td> - * <td><b>bold text</b></td> - * </tr> - * <tr> - * <td><i></td> - * <td>italic</td> - * <td><i>italic text</i></td> - * </tr> - * <tr> - * <td><u></td> - * <td>underlined</td> - * <td><u>underlined text</u></td> - * </tr> - * <tr> - * <td><br></td> - * <td>linebreak</td> - * <td>N/A</td> - * </tr> - * <tr> - * <td><ul><br> - * <li>item1<br> - * <li>item1<br> - * </ul></td> - * <td>item list</td> - * <td> - * <ul> - * <li>item1 - * <li>item2 - * </ul> - * </td> - * </tr> - * </table> - * </p> - * - * <p> - * These tags may be nested. - * </p> - * - * @return component's description <code>String</code> - */ - public String getDescription() { - return getState().getDescription(); - } - - /** - * Sets the component's description. See {@link #getDescription()} for more - * information on what the description is. This method will trigger a - * {@link RepaintRequestEvent}. - * - * The description is displayed as HTML/XHTML in tooltips or directly in - * certain components so care should be taken to avoid creating the - * possibility for HTML injection and possibly XSS vulnerabilities. - * - * @param description - * the new description string for the component. - */ - public void setDescription(String description) { - getState().setDescription(description); - requestRepaint(); - } - - /* - * Gets the component's parent component. Don't add a JavaDoc comment here, - * we use the default documentation from implemented interface. - */ - @Override - public HasComponents getParent() { - return (HasComponents) super.getParent(); - } - - @Override - public void setParent(ClientConnector parent) { - if (parent == null || parent instanceof HasComponents) { - super.setParent(parent); - } else { - throw new IllegalArgumentException( - "The parent of a Component must implement HasComponents, which " - + parent.getClass() + " doesn't do."); - } - } - - /** - * Returns the closest ancestor with the given type. - * <p> - * To find the Window that contains the component, use {@code Window w = - * getParent(Window.class);} - * </p> - * - * @param <T> - * The type of the ancestor - * @param parentType - * The ancestor class we are looking for - * @return The first ancestor that can be assigned to the given class. Null - * if no ancestor with the correct type could be found. - */ - public <T extends HasComponents> T findAncestor(Class<T> parentType) { - HasComponents p = getParent(); - while (p != null) { - if (parentType.isAssignableFrom(p.getClass())) { - return parentType.cast(p); - } - p = p.getParent(); - } - return null; - } - - /** - * Gets the error message for this component. - * - * @return ErrorMessage containing the description of the error state of the - * component or null, if the component contains no errors. Extending - * classes should override this method if they support other error - * message types such as validation errors or buffering errors. The - * returned error message contains information about all the errors. - */ - public ErrorMessage getErrorMessage() { - return componentError; - } - - /** - * Gets the component's error message. - * - * @link Terminal.ErrorMessage#ErrorMessage(String, int) - * - * @return the component's error message. - */ - public ErrorMessage getComponentError() { - return componentError; - } - - /** - * Sets the component's error message. The message may contain certain XML - * tags, for more information see - * - * @link Component.ErrorMessage#ErrorMessage(String, int) - * - * @param componentError - * the new <code>ErrorMessage</code> of the component. - */ - public void setComponentError(ErrorMessage componentError) { - this.componentError = componentError; - fireComponentErrorEvent(); - requestRepaint(); - } - - /* - * Tests if the component is in read-only mode. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public boolean isReadOnly() { - return getState().isReadOnly(); - } - - /* - * Sets the component's read-only mode. Don't add a JavaDoc comment here, we - * use the default documentation from implemented interface. - */ - @Override - public void setReadOnly(boolean readOnly) { - getState().setReadOnly(readOnly); - requestRepaint(); - } - - /* - * Gets the parent window of the component. Don't add a JavaDoc comment - * here, we use the default documentation from implemented interface. - */ - @Override - public Root getRoot() { - // Just make method from implemented Component interface public - return super.getRoot(); - } - - /* - * Notify the component that it's attached to a window. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void attach() { - super.attach(); - if (delayedFocus) { - focus(); - } - setActionManagerViewer(); - } - - /* - * Detach the component from application. Don't add a JavaDoc comment here, - * we use the default documentation from implemented interface. - */ - @Override - public void detach() { - super.detach(); - if (actionManager != null) { - // Remove any existing viewer. Root cast is just to make the - // compiler happy - actionManager.setViewer((Root) null); - } - } - - /** - * Sets the focus for this component if the component is {@link Focusable}. - */ - protected void focus() { - if (this instanceof Focusable) { - final Application app = getApplication(); - if (app != null) { - getRoot().setFocusedComponent((Focusable) this); - delayedFocus = false; - } else { - delayedFocus = true; - } - } - } - - /** - * Gets the application object to which the component is attached. - * - * <p> - * The method will return {@code null} if the component is not currently - * attached to an application. This is often a problem in constructors of - * regular components and in the initializers of custom composite - * components. A standard workaround is to move the problematic - * initialization to {@link #attach()}, as described in the documentation of - * the method. - * </p> - * <p> - * <b>This method is not meant to be overridden. Due to CDI requirements we - * cannot declare it as final even though it should be final.</b> - * </p> - * - * @return the parent application of the component or <code>null</code>. - * @see #attach() - */ - @Override - public Application getApplication() { - // Just make method inherited from Component interface public - return super.getApplication(); - } - - /** - * Build CSS compatible string representation of height. - * - * @return CSS height - */ - private String getCSSHeight() { - if (getHeightUnits() == Unit.PIXELS) { - return ((int) getHeight()) + getHeightUnits().getSymbol(); - } else { - return getHeight() + getHeightUnits().getSymbol(); - } - } - - /** - * Build CSS compatible string representation of width. - * - * @return CSS width - */ - private String getCSSWidth() { - if (getWidthUnits() == Unit.PIXELS) { - return ((int) getWidth()) + getWidthUnits().getSymbol(); - } else { - return getWidth() + getWidthUnits().getSymbol(); - } - } - - /** - * Returns the shared state bean with information to be sent from the server - * to the client. - * - * Subclasses should override this method and set any relevant fields of the - * state returned by super.getState(). - * - * @since 7.0 - * - * @return updated component shared state - */ - @Override - public ComponentState getState() { - return (ComponentState) super.getState(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component#updateState() - */ - @Override - public void updateState() { - // TODO This logic should be on the client side and the state should - // simply be a data object with "width" and "height". - if (getHeight() >= 0 - && (getHeightUnits() != Unit.PERCENTAGE || ComponentSizeValidator - .parentCanDefineHeight(this))) { - getState().setHeight("" + getCSSHeight()); - } else { - getState().setHeight(""); - } - - if (getWidth() >= 0 - && (getWidthUnits() != Unit.PERCENTAGE || ComponentSizeValidator - .parentCanDefineWidth(this))) { - getState().setWidth("" + getCSSWidth()); - } else { - getState().setWidth(""); - } - - ErrorMessage error = getErrorMessage(); - if (null != error) { - getState().setErrorMessage(error.getFormattedHtmlMessage()); - } else { - getState().setErrorMessage(null); - } - } - - /* Documentation copied from interface */ - @Override - public void requestRepaint() { - // Invisible components (by flag in this particular component) do not - // need repaints - if (!getState().isVisible()) { - return; - } - super.requestRepaint(); - } - - /* General event framework */ - - private static final Method COMPONENT_EVENT_METHOD = ReflectTools - .findMethod(Component.Listener.class, "componentEvent", - Component.Event.class); - - /** - * <p> - * Registers a new listener with the specified activation method to listen - * events generated by this component. If the activation method does not - * have any arguments the event object will not be passed to it when it's - * called. - * </p> - * - * <p> - * This method additionally informs the event-api to route events with the - * given eventIdentifier to the components handleEvent function call. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventIdentifier - * the identifier of the event to listen for - * @param eventType - * the type of the listened event. Events of this type or its - * subclasses activate the listener. - * @param target - * the object instance who owns the activation method. - * @param method - * the activation method. - * - * @since 6.2 - */ - protected void addListener(String eventIdentifier, Class<?> eventType, - Object target, Method method) { - if (eventRouter == null) { - eventRouter = new EventRouter(); - } - boolean needRepaint = !eventRouter.hasListeners(eventType); - eventRouter.addListener(eventType, target, method); - - if (needRepaint) { - getState().addRegisteredEventListener(eventIdentifier); - requestRepaint(); - } - } - - /** - * Checks if the given {@link Event} type is listened for this component. - * - * @param eventType - * the event type to be checked - * @return true if a listener is registered for the given event type - */ - protected boolean hasListeners(Class<?> eventType) { - return eventRouter != null && eventRouter.hasListeners(eventType); - } - - /** - * Removes all registered listeners matching the given parameters. Since - * this method receives the event type and the listener object as - * parameters, it will unregister all <code>object</code>'s methods that are - * registered to listen to events of type <code>eventType</code> generated - * by this component. - * - * <p> - * This method additionally informs the event-api to stop routing events - * with the given eventIdentifier to the components handleEvent function - * call. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventIdentifier - * the identifier of the event to stop listening for - * @param eventType - * the exact event type the <code>object</code> listens to. - * @param target - * the target object that has registered to listen to events of - * type <code>eventType</code> with one or more methods. - * - * @since 6.2 - */ - protected void removeListener(String eventIdentifier, Class<?> eventType, - Object target) { - if (eventRouter != null) { - eventRouter.removeListener(eventType, target); - if (!eventRouter.hasListeners(eventType)) { - getState().removeRegisteredEventListener(eventIdentifier); - requestRepaint(); - } - } - } - - /** - * <p> - * Registers a new listener with the specified activation method to listen - * events generated by this component. If the activation method does not - * have any arguments the event object will not be passed to it when it's - * called. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the type of the listened event. Events of this type or its - * subclasses activate the listener. - * @param target - * the object instance who owns the activation method. - * @param method - * the activation method. - */ - @Override - public void addListener(Class<?> eventType, Object target, Method method) { - if (eventRouter == null) { - eventRouter = new EventRouter(); - } - eventRouter.addListener(eventType, target, method); - } - - /** - * <p> - * Convenience method for registering a new listener with the specified - * activation method to listen events generated by this component. If the - * activation method does not have any arguments the event object will not - * be passed to it when it's called. - * </p> - * - * <p> - * This version of <code>addListener</code> gets the name of the activation - * method as a parameter. The actual method is reflected from - * <code>object</code>, and unless exactly one match is found, - * <code>java.lang.IllegalArgumentException</code> is thrown. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * <p> - * Note: Using this method is discouraged because it cannot be checked - * during compilation. Use {@link #addListener(Class, Object, Method)} or - * {@link #addListener(com.vaadin.ui.Component.Listener)} instead. - * </p> - * - * @param eventType - * the type of the listened event. Events of this type or its - * subclasses activate the listener. - * @param target - * the object instance who owns the activation method. - * @param methodName - * the name of the activation method. - */ - @Override - public void addListener(Class<?> eventType, Object target, String methodName) { - if (eventRouter == null) { - eventRouter = new EventRouter(); - } - eventRouter.addListener(eventType, target, methodName); - } - - /** - * Removes all registered listeners matching the given parameters. Since - * this method receives the event type and the listener object as - * parameters, it will unregister all <code>object</code>'s methods that are - * registered to listen to events of type <code>eventType</code> generated - * by this component. - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the exact event type the <code>object</code> listens to. - * @param target - * the target object that has registered to listen to events of - * type <code>eventType</code> with one or more methods. - */ - @Override - public void removeListener(Class<?> eventType, Object target) { - if (eventRouter != null) { - eventRouter.removeListener(eventType, target); - } - } - - /** - * Removes one registered listener method. The given method owned by the - * given object will no longer be called when the specified events are - * generated by this component. - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the exact event type the <code>object</code> listens to. - * @param target - * target object that has registered to listen to events of type - * <code>eventType</code> with one or more methods. - * @param method - * the method owned by <code>target</code> that's registered to - * listen to events of type <code>eventType</code>. - */ - @Override - public void removeListener(Class<?> eventType, Object target, Method method) { - if (eventRouter != null) { - eventRouter.removeListener(eventType, target, method); - } - } - - /** - * <p> - * Removes one registered listener method. The given method owned by the - * given object will no longer be called when the specified events are - * generated by this component. - * </p> - * - * <p> - * This version of <code>removeListener</code> gets the name of the - * activation method as a parameter. The actual method is reflected from - * <code>target</code>, and unless exactly one match is found, - * <code>java.lang.IllegalArgumentException</code> is thrown. - * </p> - * - * <p> - * For more information on the inheritable event mechanism see the - * {@link com.vaadin.event com.vaadin.event package documentation}. - * </p> - * - * @param eventType - * the exact event type the <code>object</code> listens to. - * @param target - * the target object that has registered to listen to events of - * type <code>eventType</code> with one or more methods. - * @param methodName - * the name of the method owned by <code>target</code> that's - * registered to listen to events of type <code>eventType</code>. - */ - @Override - public void removeListener(Class<?> eventType, Object target, - String methodName) { - if (eventRouter != null) { - eventRouter.removeListener(eventType, target, methodName); - } - } - - /** - * Returns all listeners that are registered for the given event type or one - * of its subclasses. - * - * @param eventType - * The type of event to return listeners for. - * @return A collection with all registered listeners. Empty if no listeners - * are found. - */ - public Collection<?> getListeners(Class<?> eventType) { - if (eventRouter == null) { - return Collections.EMPTY_LIST; - } - - return eventRouter.getListeners(eventType); - } - - /** - * Sends the event to all listeners. - * - * @param event - * the Event to be sent to all listeners. - */ - protected void fireEvent(Component.Event event) { - if (eventRouter != null) { - eventRouter.fireEvent(event); - } - - } - - /* Component event framework */ - - /* - * Registers a new listener to listen events generated by this component. - * Don't add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public void addListener(Component.Listener listener) { - addListener(Component.Event.class, listener, COMPONENT_EVENT_METHOD); - } - - /* - * Removes a previously registered listener from this component. Don't add a - * JavaDoc comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void removeListener(Component.Listener listener) { - removeListener(Component.Event.class, listener, COMPONENT_EVENT_METHOD); - } - - /** - * Emits the component event. It is transmitted to all registered listeners - * interested in such events. - */ - protected void fireComponentEvent() { - fireEvent(new Component.Event(this)); - } - - /** - * Emits the component error event. It is transmitted to all registered - * listeners interested in such events. - */ - protected void fireComponentErrorEvent() { - fireEvent(new Component.ErrorEvent(getComponentError(), this)); - } - - /** - * Sets the data object, that can be used for any application specific data. - * The component does not use or modify this data. - * - * @param data - * the Application specific data. - * @since 3.1 - */ - public void setData(Object data) { - applicationData = data; - } - - /** - * Gets the application specific data. See {@link #setData(Object)}. - * - * @return the Application specific data set with setData function. - * @since 3.1 - */ - public Object getData() { - return applicationData; - } - - /* Sizeable and other size related methods */ - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#getHeight() - */ - @Override - public float getHeight() { - return height; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#getHeightUnits() - */ - @Override - public Unit getHeightUnits() { - return heightUnit; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#getWidth() - */ - @Override - public float getWidth() { - return width; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#getWidthUnits() - */ - @Override - public Unit getWidthUnits() { - return widthUnit; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setHeight(float, Unit) - */ - @Override - public void setHeight(float height, Unit unit) { - if (unit == null) { - throw new IllegalArgumentException("Unit can not be null"); - } - this.height = height; - heightUnit = unit; - requestRepaint(); - // ComponentSizeValidator.setHeightLocation(this); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setSizeFull() - */ - @Override - public void setSizeFull() { - setWidth(100, Unit.PERCENTAGE); - setHeight(100, Unit.PERCENTAGE); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setSizeUndefined() - */ - @Override - public void setSizeUndefined() { - setWidth(-1, Unit.PIXELS); - setHeight(-1, Unit.PIXELS); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setWidth(float, Unit) - */ - @Override - public void setWidth(float width, Unit unit) { - if (unit == null) { - throw new IllegalArgumentException("Unit can not be null"); - } - this.width = width; - widthUnit = unit; - requestRepaint(); - // ComponentSizeValidator.setWidthLocation(this); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setWidth(java.lang.String) - */ - @Override - public void setWidth(String width) { - Size size = parseStringSize(width); - if (size != null) { - setWidth(size.getSize(), size.getUnit()); - } else { - setWidth(-1, Unit.PIXELS); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Sizeable#setHeight(java.lang.String) - */ - @Override - public void setHeight(String height) { - Size size = parseStringSize(height); - if (size != null) { - setHeight(size.getSize(), size.getUnit()); - } else { - setHeight(-1, Unit.PIXELS); - } - } - - /* - * Returns array with size in index 0 unit in index 1. Null or empty string - * will produce {-1,Unit#PIXELS} - */ - private static Size parseStringSize(String s) { - if (s == null) { - return null; - } - s = s.trim(); - if ("".equals(s)) { - return null; - } - float size = 0; - Unit unit = null; - Matcher matcher = sizePattern.matcher(s); - if (matcher.find()) { - size = Float.parseFloat(matcher.group(1)); - if (size < 0) { - size = -1; - unit = Unit.PIXELS; - } else { - String symbol = matcher.group(3); - unit = Unit.getUnitFromSymbol(symbol); - } - } else { - throw new IllegalArgumentException("Invalid size argument: \"" + s - + "\" (should match " + sizePattern.pattern() + ")"); - } - return new Size(size, unit); - } - - private static class Size implements Serializable { - float size; - Unit unit; - - public Size(float size, Unit unit) { - this.size = size; - this.unit = unit; - } - - public float getSize() { - return size; - } - - public Unit getUnit() { - return unit; - } - } - - public interface ComponentErrorEvent extends Terminal.ErrorEvent { - } - - public interface ComponentErrorHandler extends Serializable { - /** - * Handle the component error - * - * @param event - * @return True if the error has been handled False, otherwise - */ - public boolean handleComponentError(ComponentErrorEvent event); - } - - /** - * Gets the error handler for the component. - * - * The error handler is dispatched whenever there is an error processing the - * data coming from the client. - * - * @return - */ - public ComponentErrorHandler getErrorHandler() { - return errorHandler; - } - - /** - * Sets the error handler for the component. - * - * The error handler is dispatched whenever there is an error processing the - * data coming from the client. - * - * If the error handler is not set, the application error handler is used to - * handle the exception. - * - * @param errorHandler - * AbstractField specific error handler - */ - public void setErrorHandler(ComponentErrorHandler errorHandler) { - this.errorHandler = errorHandler; - } - - /** - * Handle the component error event. - * - * @param error - * Error event to handle - * @return True if the error has been handled False, otherwise. If the error - * haven't been handled by this component, it will be handled in the - * application error handler. - */ - public boolean handleError(ComponentErrorEvent error) { - if (errorHandler != null) { - return errorHandler.handleComponentError(error); - } - return false; - - } - - /* - * Actions - */ - - /** - * Gets the {@link ActionManager} used to manage the - * {@link ShortcutListener}s added to this {@link Field}. - * - * @return the ActionManager in use - */ - protected ActionManager getActionManager() { - if (actionManager == null) { - actionManager = new ActionManager(); - setActionManagerViewer(); - } - return actionManager; - } - - /** - * Set a viewer for the action manager to be the parent sub window (if the - * component is in a window) or the root (otherwise). This is still a - * simplification of the real case as this should be handled by the parent - * VOverlay (on the client side) if the component is inside an VOverlay - * component. - */ - private void setActionManagerViewer() { - if (actionManager != null && getRoot() != null) { - // Attached and has action manager - Window w = findAncestor(Window.class); - if (w != null) { - actionManager.setViewer(w); - } else { - actionManager.setViewer(getRoot()); - } - } - - } - - public void addShortcutListener(ShortcutListener shortcut) { - getActionManager().addAction(shortcut); - } - - public void removeShortcutListener(ShortcutListener shortcut) { - if (actionManager != null) { - actionManager.removeAction(shortcut); - } - } -} diff --git a/src/com/vaadin/ui/AbstractComponentContainer.java b/src/com/vaadin/ui/AbstractComponentContainer.java deleted file mode 100644 index bc27242bb8..0000000000 --- a/src/com/vaadin/ui/AbstractComponentContainer.java +++ /dev/null @@ -1,351 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.lang.reflect.Method; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; - -import com.vaadin.terminal.gwt.server.ComponentSizeValidator; - -/** - * Extension to {@link AbstractComponent} that defines the default - * implementation for the methods in {@link ComponentContainer}. Basic UI - * components that need to contain other components inherit this class to easily - * qualify as a component container. - * - * @author Vaadin Ltd - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public abstract class AbstractComponentContainer extends AbstractComponent - implements ComponentContainer { - - /** - * Constructs a new component container. - */ - public AbstractComponentContainer() { - super(); - } - - /** - * Removes all components from the container. This should probably be - * re-implemented in extending classes for a more powerful implementation. - */ - @Override - public void removeAllComponents() { - final LinkedList<Component> l = new LinkedList<Component>(); - - // Adds all components - for (final Iterator<Component> i = getComponentIterator(); i.hasNext();) { - l.add(i.next()); - } - - // Removes all component - for (final Iterator<Component> i = l.iterator(); i.hasNext();) { - removeComponent(i.next()); - } - } - - /* - * Moves all components from an another container into this container. Don't - * add a JavaDoc comment here, we use the default documentation from - * implemented interface. - */ - @Override - public void moveComponentsFrom(ComponentContainer source) { - final LinkedList<Component> components = new LinkedList<Component>(); - for (final Iterator<Component> i = source.getComponentIterator(); i - .hasNext();) { - components.add(i.next()); - } - - for (final Iterator<Component> i = components.iterator(); i.hasNext();) { - final Component c = i.next(); - source.removeComponent(c); - addComponent(c); - } - } - - /* Events */ - - private static final Method COMPONENT_ATTACHED_METHOD; - - private static final Method COMPONENT_DETACHED_METHOD; - - static { - try { - COMPONENT_ATTACHED_METHOD = ComponentAttachListener.class - .getDeclaredMethod("componentAttachedToContainer", - new Class[] { ComponentAttachEvent.class }); - COMPONENT_DETACHED_METHOD = ComponentDetachListener.class - .getDeclaredMethod("componentDetachedFromContainer", - new Class[] { ComponentDetachEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in AbstractComponentContainer"); - } - } - - /* documented in interface */ - @Override - public void addListener(ComponentAttachListener listener) { - addListener(ComponentContainer.ComponentAttachEvent.class, listener, - COMPONENT_ATTACHED_METHOD); - } - - /* documented in interface */ - @Override - public void addListener(ComponentDetachListener listener) { - addListener(ComponentContainer.ComponentDetachEvent.class, listener, - COMPONENT_DETACHED_METHOD); - } - - /* documented in interface */ - @Override - public void removeListener(ComponentAttachListener listener) { - removeListener(ComponentContainer.ComponentAttachEvent.class, listener, - COMPONENT_ATTACHED_METHOD); - } - - /* documented in interface */ - @Override - public void removeListener(ComponentDetachListener listener) { - removeListener(ComponentContainer.ComponentDetachEvent.class, listener, - COMPONENT_DETACHED_METHOD); - } - - /** - * Fires the component attached event. This should be called by the - * addComponent methods after the component have been added to this - * container. - * - * @param component - * the component that has been added to this container. - */ - protected void fireComponentAttachEvent(Component component) { - fireEvent(new ComponentAttachEvent(this, component)); - } - - /** - * Fires the component detached event. This should be called by the - * removeComponent methods after the component have been removed from this - * container. - * - * @param component - * the component that has been removed from this container. - */ - protected void fireComponentDetachEvent(Component component) { - fireEvent(new ComponentDetachEvent(this, component)); - } - - /** - * This only implements the events and component parent calls. The extending - * classes must implement component list maintenance and call this method - * after component list maintenance. - * - * @see com.vaadin.ui.ComponentContainer#addComponent(Component) - */ - @Override - public void addComponent(Component c) { - if (c instanceof ComponentContainer) { - // Make sure we're not adding the component inside it's own content - for (Component parent = this; parent != null; parent = parent - .getParent()) { - if (parent == c) { - throw new IllegalArgumentException( - "Component cannot be added inside it's own content"); - } - } - } - - if (c.getParent() != null) { - // If the component already has a parent, try to remove it - ComponentContainer oldParent = (ComponentContainer) c.getParent(); - oldParent.removeComponent(c); - - } - - c.setParent(this); - fireComponentAttachEvent(c); - } - - /** - * This only implements the events and component parent calls. The extending - * classes must implement component list maintenance and call this method - * before component list maintenance. - * - * @see com.vaadin.ui.ComponentContainer#removeComponent(Component) - */ - @Override - public void removeComponent(Component c) { - if (c.getParent() == this) { - c.setParent(null); - fireComponentDetachEvent(c); - } - } - - @Override - public void setVisible(boolean visible) { - if (getState().isVisible() == visible) { - return; - } - - super.setVisible(visible); - // If the visibility state is toggled it might affect all children - // aswell, e.g. make container visible should make children visible if - // they were only hidden because the container was hidden. - requestRepaintAll(); - } - - @Override - public void setWidth(float width, Unit unit) { - /* - * child tree repaints may be needed, due to our fall back support for - * invalid relative sizes - */ - Collection<Component> dirtyChildren = null; - boolean childrenMayBecomeUndefined = false; - if (getWidth() == SIZE_UNDEFINED && width != SIZE_UNDEFINED) { - // children currently in invalid state may need repaint - dirtyChildren = getInvalidSizedChildren(false); - } else if ((width == SIZE_UNDEFINED && getWidth() != SIZE_UNDEFINED) - || (unit == Unit.PERCENTAGE - && getWidthUnits() != Unit.PERCENTAGE && !ComponentSizeValidator - .parentCanDefineWidth(this))) { - /* - * relative width children may get to invalid state if width becomes - * invalid. Width may also become invalid if units become percentage - * due to the fallback support - */ - childrenMayBecomeUndefined = true; - dirtyChildren = getInvalidSizedChildren(false); - } - super.setWidth(width, unit); - repaintChangedChildTrees(dirtyChildren, childrenMayBecomeUndefined, - false); - } - - private void repaintChangedChildTrees( - Collection<Component> invalidChildren, - boolean childrenMayBecomeUndefined, boolean vertical) { - if (childrenMayBecomeUndefined) { - Collection<Component> previouslyInvalidComponents = invalidChildren; - invalidChildren = getInvalidSizedChildren(vertical); - if (previouslyInvalidComponents != null && invalidChildren != null) { - for (Iterator<Component> iterator = invalidChildren.iterator(); iterator - .hasNext();) { - Component component = iterator.next(); - if (previouslyInvalidComponents.contains(component)) { - // still invalid don't repaint - iterator.remove(); - } - } - } - } else if (invalidChildren != null) { - Collection<Component> stillInvalidChildren = getInvalidSizedChildren(vertical); - if (stillInvalidChildren != null) { - for (Component component : stillInvalidChildren) { - // didn't become valid - invalidChildren.remove(component); - } - } - } - if (invalidChildren != null) { - repaintChildTrees(invalidChildren); - } - } - - private Collection<Component> getInvalidSizedChildren(final boolean vertical) { - HashSet<Component> components = null; - if (this instanceof Panel) { - Panel p = (Panel) this; - ComponentContainer content = p.getContent(); - boolean valid = vertical ? ComponentSizeValidator - .checkHeights(content) : ComponentSizeValidator - .checkWidths(content); - - if (!valid) { - components = new HashSet<Component>(1); - components.add(content); - } - } else { - for (Iterator<Component> componentIterator = getComponentIterator(); componentIterator - .hasNext();) { - Component component = componentIterator.next(); - boolean valid = vertical ? ComponentSizeValidator - .checkHeights(component) : ComponentSizeValidator - .checkWidths(component); - if (!valid) { - if (components == null) { - components = new HashSet<Component>(); - } - components.add(component); - } - } - } - return components; - } - - private void repaintChildTrees(Collection<Component> dirtyChildren) { - for (Component c : dirtyChildren) { - if (c instanceof ComponentContainer) { - ComponentContainer cc = (ComponentContainer) c; - cc.requestRepaintAll(); - } else { - c.requestRepaint(); - } - } - } - - @Override - public void setHeight(float height, Unit unit) { - /* - * child tree repaints may be needed, due to our fall back support for - * invalid relative sizes - */ - Collection<Component> dirtyChildren = null; - boolean childrenMayBecomeUndefined = false; - if (getHeight() == SIZE_UNDEFINED && height != SIZE_UNDEFINED) { - // children currently in invalid state may need repaint - dirtyChildren = getInvalidSizedChildren(true); - } else if ((height == SIZE_UNDEFINED && getHeight() != SIZE_UNDEFINED) - || (unit == Unit.PERCENTAGE - && getHeightUnits() != Unit.PERCENTAGE && !ComponentSizeValidator - .parentCanDefineHeight(this))) { - /* - * relative height children may get to invalid state if height - * becomes invalid. Height may also become invalid if units become - * percentage due to the fallback support. - */ - childrenMayBecomeUndefined = true; - dirtyChildren = getInvalidSizedChildren(true); - } - super.setHeight(height, unit); - repaintChangedChildTrees(dirtyChildren, childrenMayBecomeUndefined, - true); - } - - @Override - public Iterator<Component> iterator() { - return getComponentIterator(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.ui.HasComponents#isComponentVisible(com.vaadin.ui.Component) - */ - @Override - public boolean isComponentVisible(Component childComponent) { - return true; - } -}
\ No newline at end of file diff --git a/src/com/vaadin/ui/AbstractField.java b/src/com/vaadin/ui/AbstractField.java deleted file mode 100644 index 6fe7f54df5..0000000000 --- a/src/com/vaadin/ui/AbstractField.java +++ /dev/null @@ -1,1657 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.logging.Logger; - -import com.vaadin.data.Buffered; -import com.vaadin.data.Property; -import com.vaadin.data.Validatable; -import com.vaadin.data.Validator; -import com.vaadin.data.Validator.InvalidValueException; -import com.vaadin.data.util.converter.Converter; -import com.vaadin.data.util.converter.Converter.ConversionException; -import com.vaadin.data.util.converter.ConverterUtil; -import com.vaadin.event.Action; -import com.vaadin.event.ShortcutAction; -import com.vaadin.event.ShortcutListener; -import com.vaadin.shared.AbstractFieldState; -import com.vaadin.terminal.AbstractErrorMessage; -import com.vaadin.terminal.CompositeErrorMessage; -import com.vaadin.terminal.ErrorMessage; - -/** - * <p> - * Abstract field component for implementing buffered property editors. The - * field may hold an internal value, or it may be connected to any data source - * that implements the {@link com.vaadin.data.Property}interface. - * <code>AbstractField</code> implements that interface itself, too, so - * accessing the Property value represented by it is straightforward. - * </p> - * - * <p> - * AbstractField also provides the {@link com.vaadin.data.Buffered} interface - * for buffering the data source value. By default the Field is in write - * through-mode and {@link #setWriteThrough(boolean)}should be called to enable - * buffering. - * </p> - * - * <p> - * The class also supports {@link com.vaadin.data.Validator validators} to make - * sure the value contained in the field is valid. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public abstract class AbstractField<T> extends AbstractComponent implements - Field<T>, Property.ReadOnlyStatusChangeListener, - Property.ReadOnlyStatusChangeNotifier, Action.ShortcutNotifier { - - /* Private members */ - - private static final Logger logger = Logger.getLogger(AbstractField.class - .getName()); - - /** - * Value of the abstract field. - */ - private T value; - - /** - * A converter used to convert from the data model type to the field type - * and vice versa. - */ - private Converter<T, Object> converter = null; - /** - * Connected data-source. - */ - private Property<?> dataSource = null; - - /** - * The list of validators. - */ - private LinkedList<Validator> validators = null; - - /** - * Auto commit mode. - */ - private boolean writeThroughMode = true; - - /** - * Reads the value from data-source, when it is not modified. - */ - private boolean readThroughMode = true; - - /** - * Flag to indicate that the field is currently committing its value to the - * datasource. - */ - private boolean committingValueToDataSource = false; - - /** - * Current source exception. - */ - private Buffered.SourceException currentBufferedSourceException = null; - - /** - * Are the invalid values allowed in fields ? - */ - private boolean invalidAllowed = true; - - /** - * Are the invalid values committed ? - */ - private boolean invalidCommitted = false; - - /** - * The error message for the exception that is thrown when the field is - * required but empty. - */ - private String requiredError = ""; - - /** - * The error message that is shown when the field value cannot be converted. - */ - private String conversionError = "Could not convert value to {0}"; - - /** - * Is automatic validation enabled. - */ - private boolean validationVisible = true; - - private boolean valueWasModifiedByDataSourceDuringCommit; - - /** - * Whether this field is currently registered as listening to events from - * its data source. - * - * @see #setPropertyDataSource(Property) - * @see #addPropertyListeners() - * @see #removePropertyListeners() - */ - private boolean isListeningToPropertyEvents = false; - - /* Component basics */ - - /* - * Paints the field. Don't add a JavaDoc comment here, we use the default - * documentation from the implemented interface. - */ - - /** - * Returns true if the error indicator be hidden when painting the component - * even when there are errors. - * - * This is a mostly internal method, but can be overridden in subclasses - * e.g. if the error indicator should also be shown for empty fields in some - * cases. - * - * @return true to hide the error indicator, false to use the normal logic - * to show it when there are errors - */ - protected boolean shouldHideErrors() { - // getErrorMessage() can still return something else than null based on - // validation etc. - return isRequired() && isEmpty() && getComponentError() == null; - } - - /** - * Returns the type of the Field. The methods <code>getValue</code> and - * <code>setValue</code> must be compatible with this type: one must be able - * to safely cast the value returned from <code>getValue</code> to the given - * type and pass any variable assignable to this type as an argument to - * <code>setValue</code>. - * - * @return the type of the Field - */ - @Override - public abstract Class<? extends T> getType(); - - /** - * The abstract field is read only also if the data source is in read only - * mode. - */ - @Override - public boolean isReadOnly() { - return super.isReadOnly() - || (dataSource != null && dataSource.isReadOnly()); - } - - /** - * Changes the readonly state and throw read-only status change events. - * - * @see com.vaadin.ui.Component#setReadOnly(boolean) - */ - @Override - public void setReadOnly(boolean readOnly) { - super.setReadOnly(readOnly); - fireReadOnlyStatusChange(); - } - - /** - * Tests if the invalid data is committed to datasource. - * - * @see com.vaadin.data.BufferedValidatable#isInvalidCommitted() - */ - @Override - public boolean isInvalidCommitted() { - return invalidCommitted; - } - - /** - * Sets if the invalid data should be committed to datasource. - * - * @see com.vaadin.data.BufferedValidatable#setInvalidCommitted(boolean) - */ - @Override - public void setInvalidCommitted(boolean isCommitted) { - invalidCommitted = isCommitted; - } - - /* - * Saves the current value to the data source Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - @Override - public void commit() throws Buffered.SourceException, InvalidValueException { - if (dataSource != null && !dataSource.isReadOnly()) { - if ((isInvalidCommitted() || isValid())) { - try { - - // Commits the value to datasource. - valueWasModifiedByDataSourceDuringCommit = false; - committingValueToDataSource = true; - getPropertyDataSource().setValue(getConvertedValue()); - } catch (final Throwable e) { - - // Sets the buffering state. - SourceException sourceException = new Buffered.SourceException( - this, e); - setCurrentBufferedSourceException(sourceException); - - // Throws the source exception. - throw sourceException; - } finally { - committingValueToDataSource = false; - } - } else { - /* An invalid value and we don't allow them, throw the exception */ - validate(); - } - } - - // The abstract field is not modified anymore - if (isModified()) { - setModified(false); - } - - // If successful, remove set the buffering state to be ok - if (getCurrentBufferedSourceException() != null) { - setCurrentBufferedSourceException(null); - } - - if (valueWasModifiedByDataSourceDuringCommit) { - valueWasModifiedByDataSourceDuringCommit = false; - fireValueChange(false); - } - - } - - /* - * Updates the value from the data source. Don't add a JavaDoc comment here, - * we use the default documentation from the implemented interface. - */ - @Override - public void discard() throws Buffered.SourceException { - if (dataSource != null) { - - // Gets the correct value from datasource - T newFieldValue; - try { - - // Discards buffer by overwriting from datasource - newFieldValue = convertFromDataSource(getDataSourceValue()); - - // If successful, remove set the buffering state to be ok - if (getCurrentBufferedSourceException() != null) { - setCurrentBufferedSourceException(null); - } - } catch (final Throwable e) { - // FIXME: What should really be done here if conversion fails? - - // Sets the buffering state - currentBufferedSourceException = new Buffered.SourceException( - this, e); - requestRepaint(); - - // Throws the source exception - throw currentBufferedSourceException; - } - - final boolean wasModified = isModified(); - setModified(false); - - // If the new value differs from the previous one - if (!equals(newFieldValue, getInternalValue())) { - setInternalValue(newFieldValue); - fireValueChange(false); - } else if (wasModified) { - // If the value did not change, but the modification status did - requestRepaint(); - } - } - } - - /** - * Gets the value from the data source. This is only here because of clarity - * in the code that handles both the data model value and the field value. - * - * @return The value of the property data source - */ - private Object getDataSourceValue() { - return dataSource.getValue(); - } - - /** - * Returns the field value. This is always identical to {@link #getValue()} - * and only here because of clarity in the code that handles both the data - * model value and the field value. - * - * @return The value of the field - */ - private T getFieldValue() { - // Give the value from abstract buffers if the field if possible - if (dataSource == null || !isReadThrough() || isModified()) { - return getInternalValue(); - } - - // There is no buffered value so use whatever the data model provides - return convertFromDataSource(getDataSourceValue()); - } - - /* - * Has the field been modified since the last commit()? Don't add a JavaDoc - * comment here, we use the default documentation from the implemented - * interface. - */ - @Override - public boolean isModified() { - return getState().isModified(); - } - - private void setModified(boolean modified) { - getState().setModified(modified); - requestRepaint(); - } - - /* - * Tests if the field is in write-through mode. Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - @Override - public boolean isWriteThrough() { - return writeThroughMode; - } - - /** - * Sets the field's write-through mode to the specified status. When - * switching the write-through mode on, a {@link #commit()} will be - * performed. - * - * @see #setBuffered(boolean) for an easier way to control read through and - * write through modes - * - * @param writeThrough - * Boolean value to indicate if the object should be in - * write-through mode after the call. - * @throws SourceException - * If the operation fails because of an exception is thrown by - * the data source. - * @throws InvalidValueException - * If the implicit commit operation fails because of a - * validation error. - * @deprecated Use {@link #setBuffered(boolean)} instead. Note that - * setReadThrough(true), setWriteThrough(true) equals - * setBuffered(false) - */ - @Override - @Deprecated - public void setWriteThrough(boolean writeThrough) - throws Buffered.SourceException, InvalidValueException { - if (writeThroughMode == writeThrough) { - return; - } - writeThroughMode = writeThrough; - if (writeThroughMode) { - commit(); - } - } - - /* - * Tests if the field is in read-through mode. Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - @Override - public boolean isReadThrough() { - return readThroughMode; - } - - /** - * Sets the field's read-through mode to the specified status. When - * switching read-through mode on, the object's value is updated from the - * data source. - * - * @see #setBuffered(boolean) for an easier way to control read through and - * write through modes - * - * @param readThrough - * Boolean value to indicate if the object should be in - * read-through mode after the call. - * - * @throws SourceException - * If the operation fails because of an exception is thrown by - * the data source. The cause is included in the exception. - * @deprecated Use {@link #setBuffered(boolean)} instead. Note that - * setReadThrough(true), setWriteThrough(true) equals - * setBuffered(false) - */ - @Override - @Deprecated - public void setReadThrough(boolean readThrough) - throws Buffered.SourceException { - if (readThroughMode == readThrough) { - return; - } - readThroughMode = readThrough; - if (!isModified() && readThroughMode && getPropertyDataSource() != null) { - setInternalValue(convertFromDataSource(getDataSourceValue())); - fireValueChange(false); - } - } - - /** - * Sets the buffered mode of this Field. - * <p> - * When the field is in buffered mode, changes will not be committed to the - * property data source until {@link #commit()} is called. - * </p> - * <p> - * Changing buffered mode will change the read through and write through - * state for the field. - * </p> - * <p> - * Mixing calls to {@link #setBuffered(boolean)} and - * {@link #setReadThrough(boolean)} or {@link #setWriteThrough(boolean)} is - * generally a bad idea. - * </p> - * - * @param buffered - * true if buffered mode should be turned on, false otherwise - */ - @Override - public void setBuffered(boolean buffered) { - setReadThrough(!buffered); - setWriteThrough(!buffered); - } - - /** - * Checks the buffered mode of this Field. - * <p> - * This method only returns true if both read and write buffering is used. - * - * @return true if buffered mode is on, false otherwise - */ - @Override - public boolean isBuffered() { - return !isReadThrough() && !isWriteThrough(); - } - - /* Property interface implementation */ - - /** - * Returns the (field) value converted to a String using toString(). - * - * @see java.lang.Object#toString() - * @deprecated Instead use {@link #getValue()} to get the value of the - * field, {@link #getConvertedValue()} to get the field value - * converted to the data model type or - * {@link #getPropertyDataSource()} .getValue() to get the value - * of the data source. - */ - @Deprecated - @Override - public String toString() { - logger.warning("You are using AbstractField.toString() to get the value for a " - + getClass().getSimpleName() - + ". This is not recommended and will not be supported in future versions."); - final Object value = getFieldValue(); - if (value == null) { - return null; - } - return value.toString(); - } - - /** - * Gets the current value of the field. - * - * <p> - * This is the visible, modified and possible invalid value the user have - * entered to the field. - * </p> - * - * <p> - * Note that the object returned is compatible with getType(). For example, - * if the type is String, this returns Strings even when the underlying - * datasource is of some other type. In order to access the converted value, - * use {@link #getConvertedValue()} and to access the value of the property - * data source, use {@link Property#getValue()} for the property data - * source. - * </p> - * - * <p> - * Since Vaadin 7.0, no implicit conversions between other data types and - * String are performed, but a converter is used if set. - * </p> - * - * @return the current value of the field. - */ - @Override - public T getValue() { - return getFieldValue(); - } - - /** - * Sets the value of the field. - * - * @param newFieldValue - * the New value of the field. - * @throws Property.ReadOnlyException - */ - @Override - public void setValue(Object newFieldValue) - throws Property.ReadOnlyException, Converter.ConversionException { - // This check is needed as long as setValue accepts Object instead of T - if (newFieldValue != null) { - if (!getType().isAssignableFrom(newFieldValue.getClass())) { - throw new Converter.ConversionException("Value of type " - + newFieldValue.getClass() + " cannot be assigned to " - + getType().getName()); - } - } - setValue((T) newFieldValue, false); - } - - /** - * Sets the value of the field. - * - * @param newFieldValue - * the New value of the field. - * @param repaintIsNotNeeded - * True iff caller is sure that repaint is not needed. - * @throws Property.ReadOnlyException - */ - protected void setValue(T newFieldValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException, Converter.ConversionException, - InvalidValueException { - - if (!equals(newFieldValue, getInternalValue())) { - - // Read only fields can not be changed - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - // Repaint is needed even when the client thinks that it knows the - // new state if validity of the component may change - if (repaintIsNotNeeded - && (isRequired() || getValidators() != null || getConverter() != null)) { - repaintIsNotNeeded = false; - } - - if (!isInvalidAllowed()) { - /* - * If invalid values are not allowed the value must be validated - * before it is set. If validation fails, the - * InvalidValueException is thrown and the internal value is not - * updated. - */ - validate(newFieldValue); - } - - // Changes the value - setInternalValue(newFieldValue); - setModified(dataSource != null); - - valueWasModifiedByDataSourceDuringCommit = false; - // In write through mode , try to commit - if (isWriteThrough() && dataSource != null - && (isInvalidCommitted() || isValid())) { - try { - - // Commits the value to datasource - committingValueToDataSource = true; - getPropertyDataSource().setValue( - convertToModel(newFieldValue)); - - // The buffer is now unmodified - setModified(false); - - } catch (final Throwable e) { - - // Sets the buffering state - currentBufferedSourceException = new Buffered.SourceException( - this, e); - requestRepaint(); - - // Throws the source exception - throw currentBufferedSourceException; - } finally { - committingValueToDataSource = false; - } - } - - // If successful, remove set the buffering state to be ok - if (getCurrentBufferedSourceException() != null) { - setCurrentBufferedSourceException(null); - } - - if (valueWasModifiedByDataSourceDuringCommit) { - /* - * Value was modified by datasource. Force repaint even if - * repaint was not requested. - */ - valueWasModifiedByDataSourceDuringCommit = repaintIsNotNeeded = false; - } - - // Fires the value change - fireValueChange(repaintIsNotNeeded); - - } - } - - private static boolean equals(Object value1, Object value2) { - if (value1 == null) { - return value2 == null; - } - return value1.equals(value2); - } - - /* External data source */ - - /** - * Gets the current data source of the field, if any. - * - * @return the current data source as a Property, or <code>null</code> if - * none defined. - */ - @Override - public Property getPropertyDataSource() { - return dataSource; - } - - /** - * <p> - * Sets the specified Property as the data source for the field. All - * uncommitted changes are replaced with a value from the new data source. - * </p> - * - * <p> - * If the datasource has any validators, the same validators are added to - * the field. Because the default behavior of the field is to allow invalid - * values, but not to allow committing them, this only adds visual error - * messages to fields and do not allow committing them as long as the value - * is invalid. After the value is valid, the error message is not shown and - * the commit can be done normally. - * </p> - * - * <p> - * If the data source implements - * {@link com.vaadin.data.Property.ValueChangeNotifier} and/or - * {@link com.vaadin.data.Property.ReadOnlyStatusChangeNotifier}, the field - * registers itself as a listener and updates itself according to the events - * it receives. To avoid memory leaks caused by references to a field no - * longer in use, the listener registrations are removed on - * {@link AbstractField#detach() detach} and re-added on - * {@link AbstractField#attach() attach}. - * </p> - * - * <p> - * Note: before 6.5 we actually called discard() method in the beginning of - * the method. This was removed to simplify implementation, avoid excess - * calls to backing property and to avoid odd value change events that were - * previously fired (developer expects 0-1 value change events if this - * method is called). Some complex field implementations might now need to - * override this method to do housekeeping similar to discard(). - * </p> - * - * @param newDataSource - * the new data source Property. - */ - @Override - public void setPropertyDataSource(Property newDataSource) { - - // Saves the old value - final Object oldValue = getInternalValue(); - - // Stop listening to the old data source - removePropertyListeners(); - - // Sets the new data source - dataSource = newDataSource; - getState().setPropertyReadOnly( - dataSource == null ? false : dataSource.isReadOnly()); - - // Check if the current converter is compatible. - if (newDataSource != null - && !ConverterUtil.canConverterHandle(getConverter(), getType(), - newDataSource.getType())) { - // Changing from e.g. Number -> Double should set a new converter, - // changing from Double -> Number can keep the old one (Property - // accepts Number) - - // Set a new converter if there is a new data source and - // there is no old converter or the old is incompatible. - setConverter(newDataSource.getType()); - } - // Gets the value from source - try { - if (dataSource != null) { - T fieldValue = convertFromDataSource(getDataSourceValue()); - setInternalValue(fieldValue); - } - setModified(false); - if (getCurrentBufferedSourceException() != null) { - setCurrentBufferedSourceException(null); - } - } catch (final Throwable e) { - setCurrentBufferedSourceException(new Buffered.SourceException( - this, e)); - setModified(true); - } - - // Listen to new data source if possible - addPropertyListeners(); - - // Copy the validators from the data source - if (dataSource instanceof Validatable) { - final Collection<Validator> validators = ((Validatable) dataSource) - .getValidators(); - if (validators != null) { - for (final Iterator<Validator> i = validators.iterator(); i - .hasNext();) { - addValidator(i.next()); - } - } - } - - // Fires value change if the value has changed - T value = getInternalValue(); - if ((value != oldValue) - && ((value != null && !value.equals(oldValue)) || value == null)) { - fireValueChange(false); - } - } - - /** - * Retrieves a converter for the field from the converter factory defined - * for the application. Clears the converter if no application reference is - * available or if the factory returns null. - * - * @param datamodelType - * The type of the data model that we want to be able to convert - * from - */ - public void setConverter(Class<?> datamodelType) { - Converter<T, ?> c = (Converter<T, ?>) ConverterUtil.getConverter( - getType(), datamodelType, getApplication()); - setConverter(c); - } - - /** - * Convert the given value from the data source type to the UI type. - * - * @param newValue - * The data source value to convert. - * @return The converted value that is compatible with the UI type or the - * original value if its type is compatible and no converter is set. - * @throws Converter.ConversionException - * if there is no converter and the type is not compatible with - * the data source type. - */ - private T convertFromDataSource(Object newValue) { - return ConverterUtil.convertFromModel(newValue, getType(), - getConverter(), getLocale()); - } - - /** - * Convert the given value from the UI type to the data source type. - * - * @param fieldValue - * The value to convert. Typically returned by - * {@link #getFieldValue()} - * @return The converted value that is compatible with the data source type. - * @throws Converter.ConversionException - * if there is no converter and the type is not compatible with - * the data source type. - */ - private Object convertToModel(T fieldValue) - throws Converter.ConversionException { - try { - Class<?> modelType = null; - Property pd = getPropertyDataSource(); - if (pd != null) { - modelType = pd.getType(); - } else if (getConverter() != null) { - modelType = getConverter().getModelType(); - } - return ConverterUtil.convertToModel(fieldValue, - (Class<Object>) modelType, getConverter(), getLocale()); - } catch (ConversionException e) { - throw new ConversionException( - getConversionError(converter.getModelType()), e); - } - } - - /** - * Returns the conversion error with {0} replaced by the data source type. - * - * @param dataSourceType - * The type of the data source - * @return The value conversion error string with parameters replaced. - */ - protected String getConversionError(Class<?> dataSourceType) { - if (dataSourceType == null) { - return getConversionError(); - } else { - return getConversionError().replace("{0}", - dataSourceType.getSimpleName()); - } - } - - /** - * Returns the current value (as returned by {@link #getValue()}) converted - * to the data source type. - * <p> - * This returns the same as {@link AbstractField#getValue()} if no converter - * has been set. The value is not necessarily the same as the data source - * value e.g. if the field is in buffered mode and has been modified. - * </p> - * - * @return The converted value that is compatible with the data source type - */ - public Object getConvertedValue() { - return convertToModel(getFieldValue()); - } - - /** - * Sets the value of the field using a value of the data source type. The - * value given is converted to the field type and then assigned to the - * field. This will update the property data source in the same way as when - * {@link #setValue(Object)} is called. - * - * @param value - * The value to set. Must be the same type as the data source. - */ - public void setConvertedValue(Object value) { - setValue(convertFromDataSource(value)); - } - - /* Validation */ - - /** - * Adds a new validator for the field's value. All validators added to a - * field are checked each time the its value changes. - * - * @param validator - * the new validator to be added. - */ - @Override - public void addValidator(Validator validator) { - if (validators == null) { - validators = new LinkedList<Validator>(); - } - validators.add(validator); - requestRepaint(); - } - - /** - * Gets the validators of the field. - * - * @return the Unmodifiable collection that holds all validators for the - * field. - */ - @Override - public Collection<Validator> getValidators() { - if (validators == null || validators.isEmpty()) { - return null; - } - return Collections.unmodifiableCollection(validators); - } - - /** - * Removes the validator from the field. - * - * @param validator - * the validator to remove. - */ - @Override - public void removeValidator(Validator validator) { - if (validators != null) { - validators.remove(validator); - } - requestRepaint(); - } - - /** - * Removes all validators from the field. - */ - public void removeAllValidators() { - if (validators != null) { - validators.clear(); - } - requestRepaint(); - } - - /** - * Tests the current value against registered validators if the field is not - * empty. If the field is empty it is considered valid if it is not required - * and invalid otherwise. Validators are never checked for empty fields. - * - * In most cases, {@link #validate()} should be used instead of - * {@link #isValid()} to also get the error message. - * - * @return <code>true</code> if all registered validators claim that the - * current value is valid or if the field is empty and not required, - * <code>false</code> otherwise. - */ - @Override - public boolean isValid() { - - try { - validate(); - return true; - } catch (InvalidValueException e) { - return false; - } - } - - /** - * Checks the validity of the Field. - * - * A field is invalid if it is set as required (using - * {@link #setRequired(boolean)} and is empty, if one or several of the - * validators added to the field indicate it is invalid or if the value - * cannot be converted provided a converter has been set. - * - * The "required" validation is a built-in validation feature. If the field - * is required and empty this method throws an EmptyValueException with the - * error message set using {@link #setRequiredError(String)}. - * - * @see com.vaadin.data.Validatable#validate() - */ - @Override - public void validate() throws Validator.InvalidValueException { - - if (isRequired() && isEmpty()) { - throw new Validator.EmptyValueException(requiredError); - } - validate(getFieldValue()); - } - - /** - * Validates that the given value pass the validators for the field. - * <p> - * This method does not check the requiredness of the field. - * - * @param fieldValue - * The value to check - * @throws Validator.InvalidValueException - * if one or several validators fail - */ - protected void validate(T fieldValue) - throws Validator.InvalidValueException { - - Object valueToValidate = fieldValue; - - // If there is a converter we start by converting the value as we want - // to validate the converted value - if (getConverter() != null) { - try { - valueToValidate = getConverter().convertToModel(fieldValue, - getLocale()); - } catch (Exception e) { - throw new InvalidValueException( - getConversionError(getConverter().getModelType())); - } - } - - List<InvalidValueException> validationExceptions = new ArrayList<InvalidValueException>(); - if (validators != null) { - // Gets all the validation errors - for (Validator v : validators) { - try { - v.validate(valueToValidate); - } catch (final Validator.InvalidValueException e) { - validationExceptions.add(e); - } - } - } - - // If there were no errors - if (validationExceptions.isEmpty()) { - return; - } - - // If only one error occurred, throw it forwards - if (validationExceptions.size() == 1) { - throw validationExceptions.get(0); - } - - InvalidValueException[] exceptionArray = validationExceptions - .toArray(new InvalidValueException[validationExceptions.size()]); - - // Create a composite validator and include all exceptions - throw new Validator.InvalidValueException(null, exceptionArray); - } - - /** - * Fields allow invalid values by default. In most cases this is wanted, - * because the field otherwise visually forget the user input immediately. - * - * @return true iff the invalid values are allowed. - * @see com.vaadin.data.Validatable#isInvalidAllowed() - */ - @Override - public boolean isInvalidAllowed() { - return invalidAllowed; - } - - /** - * Fields allow invalid values by default. In most cases this is wanted, - * because the field otherwise visually forget the user input immediately. - * <p> - * In common setting where the user wants to assure the correctness of the - * datasource, but allow temporarily invalid contents in the field, the user - * should add the validators to datasource, that should not allow invalid - * values. The validators are automatically copied to the field when the - * datasource is set. - * </p> - * - * @see com.vaadin.data.Validatable#setInvalidAllowed(boolean) - */ - @Override - public void setInvalidAllowed(boolean invalidAllowed) - throws UnsupportedOperationException { - this.invalidAllowed = invalidAllowed; - } - - /** - * Error messages shown by the fields are composites of the error message - * thrown by the superclasses (that is the component error message), - * validation errors and buffered source errors. - * - * @see com.vaadin.ui.AbstractComponent#getErrorMessage() - */ - @Override - public ErrorMessage getErrorMessage() { - - /* - * Check validation errors only if automatic validation is enabled. - * Empty, required fields will generate a validation error containing - * the requiredError string. For these fields the exclamation mark will - * be hidden but the error must still be sent to the client. - */ - Validator.InvalidValueException validationError = null; - if (isValidationVisible()) { - try { - validate(); - } catch (Validator.InvalidValueException e) { - if (!e.isInvisible()) { - validationError = e; - } - } - } - - // Check if there are any systems errors - final ErrorMessage superError = super.getErrorMessage(); - - // Return if there are no errors at all - if (superError == null && validationError == null - && getCurrentBufferedSourceException() == null) { - return null; - } - - // Throw combination of the error types - return new CompositeErrorMessage( - new ErrorMessage[] { - superError, - AbstractErrorMessage - .getErrorMessageForException(validationError), - AbstractErrorMessage - .getErrorMessageForException(getCurrentBufferedSourceException()) }); - - } - - /* Value change events */ - - private static final Method VALUE_CHANGE_METHOD; - - static { - try { - VALUE_CHANGE_METHOD = Property.ValueChangeListener.class - .getDeclaredMethod("valueChange", - new Class[] { Property.ValueChangeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in AbstractField"); - } - } - - /* - * Adds a value change listener for the field. Don't add a JavaDoc comment - * here, we use the default documentation from the implemented interface. - */ - @Override - public void addListener(Property.ValueChangeListener listener) { - addListener(AbstractField.ValueChangeEvent.class, listener, - VALUE_CHANGE_METHOD); - } - - /* - * Removes a value change listener from the field. Don't add a JavaDoc - * comment here, we use the default documentation from the implemented - * interface. - */ - @Override - public void removeListener(Property.ValueChangeListener listener) { - removeListener(AbstractField.ValueChangeEvent.class, listener, - VALUE_CHANGE_METHOD); - } - - /** - * Emits the value change event. The value contained in the field is - * validated before the event is created. - */ - protected void fireValueChange(boolean repaintIsNotNeeded) { - fireEvent(new AbstractField.ValueChangeEvent(this)); - if (!repaintIsNotNeeded) { - requestRepaint(); - } - } - - /* Read-only status change events */ - - private static final Method READ_ONLY_STATUS_CHANGE_METHOD; - - static { - try { - READ_ONLY_STATUS_CHANGE_METHOD = Property.ReadOnlyStatusChangeListener.class - .getDeclaredMethod( - "readOnlyStatusChange", - new Class[] { Property.ReadOnlyStatusChangeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in AbstractField"); - } - } - - /** - * React to read only status changes of the property by requesting a - * repaint. - * - * @see Property.ReadOnlyStatusChangeListener - */ - @Override - public void readOnlyStatusChange(Property.ReadOnlyStatusChangeEvent event) { - getState().setPropertyReadOnly(event.getProperty().isReadOnly()); - requestRepaint(); - } - - /** - * An <code>Event</code> object specifying the Property whose read-only - * status has changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class ReadOnlyStatusChangeEvent extends Component.Event - implements Property.ReadOnlyStatusChangeEvent, Serializable { - - /** - * New instance of text change event. - * - * @param source - * the Source of the event. - */ - public ReadOnlyStatusChangeEvent(AbstractField source) { - super(source); - } - - /** - * Property where the event occurred. - * - * @return the Source of the event. - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - } - - /* - * Adds a read-only status change listener for the field. Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. - */ - @Override - public void addListener(Property.ReadOnlyStatusChangeListener listener) { - addListener(Property.ReadOnlyStatusChangeEvent.class, listener, - READ_ONLY_STATUS_CHANGE_METHOD); - } - - /* - * Removes a read-only status change listener from the field. Don't add a - * JavaDoc comment here, we use the default documentation from the - * implemented interface. - */ - @Override - public void removeListener(Property.ReadOnlyStatusChangeListener listener) { - removeListener(Property.ReadOnlyStatusChangeEvent.class, listener, - READ_ONLY_STATUS_CHANGE_METHOD); - } - - /** - * Emits the read-only status change event. The value contained in the field - * is validated before the event is created. - */ - protected void fireReadOnlyStatusChange() { - fireEvent(new AbstractField.ReadOnlyStatusChangeEvent(this)); - } - - /** - * This method listens to data source value changes and passes the changes - * forwards. - * - * Changes are not forwarded to the listeners of the field during internal - * operations of the field to avoid duplicate notifications. - * - * @param event - * the value change event telling the data source contents have - * changed. - */ - @Override - public void valueChange(Property.ValueChangeEvent event) { - if (isReadThrough()) { - if (committingValueToDataSource) { - boolean propertyNotifiesOfTheBufferedValue = equals(event - .getProperty().getValue(), getInternalValue()); - if (!propertyNotifiesOfTheBufferedValue) { - /* - * Property (or chained property like PropertyFormatter) now - * reports different value than the one the field has just - * committed to it. In this case we respect the property - * value. - * - * Still, we don't fire value change yet, but instead - * postpone it until "commit" is done. See setValue(Object, - * boolean) and commit(). - */ - readValueFromProperty(event); - valueWasModifiedByDataSourceDuringCommit = true; - } - } else if (!isModified()) { - readValueFromProperty(event); - fireValueChange(false); - } - } - } - - private void readValueFromProperty(Property.ValueChangeEvent event) { - setInternalValue(convertFromDataSource(event.getProperty().getValue())); - } - - /** - * {@inheritDoc} - */ - @Override - public void focus() { - super.focus(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component.Focusable#getTabIndex() - */ - @Override - public int getTabIndex() { - return getState().getTabIndex(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component.Focusable#setTabIndex(int) - */ - @Override - public void setTabIndex(int tabIndex) { - getState().setTabIndex(tabIndex); - requestRepaint(); - } - - /** - * Returns the internal field value, which might not match the data source - * value e.g. if the field has been modified and is not in write-through - * mode. - * - * This method can be overridden by subclasses together with - * {@link #setInternalValue(Object)} to compute internal field value at - * runtime. When doing so, typically also {@link #isModified()} needs to be - * overridden and care should be taken in the management of the empty state - * and buffering support. - * - * @return internal field value - */ - protected T getInternalValue() { - return value; - } - - /** - * Sets the internal field value. This is purely used by AbstractField to - * change the internal Field value. It does not trigger valuechange events. - * It can be overridden by the inheriting classes to update all dependent - * variables. - * - * Subclasses can also override {@link #getInternalValue()} if necessary. - * - * @param newValue - * the new value to be set. - */ - protected void setInternalValue(T newValue) { - value = newValue; - if (validators != null && !validators.isEmpty()) { - requestRepaint(); - } - } - - /** - * Notifies the component that it is connected to an application. - * - * @see com.vaadin.ui.Component#attach() - */ - @Override - public void attach() { - super.attach(); - - if (!isListeningToPropertyEvents) { - addPropertyListeners(); - if (!isModified() && isReadThrough()) { - // Update value from data source - discard(); - } - } - } - - @Override - public void detach() { - super.detach(); - // Stop listening to data source events on detach to avoid a potential - // memory leak. See #6155. - removePropertyListeners(); - } - - /** - * Is this field required. Required fields must filled by the user. - * - * If the field is required, it is visually indicated in the user interface. - * Furthermore, setting field to be required implicitly adds "non-empty" - * validator and thus isValid() == false or any isEmpty() fields. In those - * cases validation errors are not painted as it is obvious that the user - * must fill in the required fields. - * - * On the other hand, for the non-required fields isValid() == true if the - * field isEmpty() regardless of any attached validators. - * - * - * @return <code>true</code> if the field is required, otherwise - * <code>false</code>. - */ - @Override - public boolean isRequired() { - return getState().isRequired(); - } - - /** - * Sets the field required. Required fields must filled by the user. - * - * If the field is required, it is visually indicated in the user interface. - * Furthermore, setting field to be required implicitly adds "non-empty" - * validator and thus isValid() == false or any isEmpty() fields. In those - * cases validation errors are not painted as it is obvious that the user - * must fill in the required fields. - * - * On the other hand, for the non-required fields isValid() == true if the - * field isEmpty() regardless of any attached validators. - * - * @param required - * Is the field required. - */ - @Override - public void setRequired(boolean required) { - getState().setRequired(required); - requestRepaint(); - } - - /** - * Set the error that is show if this field is required, but empty. When - * setting requiredMessage to be "" or null, no error pop-up or exclamation - * mark is shown for a empty required field. This faults to "". Even in - * those cases isValid() returns false for empty required fields. - * - * @param requiredMessage - * Message to be shown when this field is required, but empty. - */ - @Override - public void setRequiredError(String requiredMessage) { - requiredError = requiredMessage; - requestRepaint(); - } - - @Override - public String getRequiredError() { - return requiredError; - } - - /** - * Gets the error that is shown if the field value cannot be converted to - * the data source type. - * - * @return The error that is shown if conversion of the field value fails - */ - public String getConversionError() { - return conversionError; - } - - /** - * Sets the error that is shown if the field value cannot be converted to - * the data source type. If {0} is present in the message, it will be - * replaced by the simple name of the data source type. - * - * @param valueConversionError - * Message to be shown when conversion of the value fails - */ - public void setConversionError(String valueConversionError) { - this.conversionError = valueConversionError; - requestRepaint(); - } - - /** - * Is the field empty? - * - * In general, "empty" state is same as null. As an exception, TextField - * also treats empty string as "empty". - */ - protected boolean isEmpty() { - return (getFieldValue() == null); - } - - /** - * Is automatic, visible validation enabled? - * - * If automatic validation is enabled, any validators connected to this - * component are evaluated while painting the component and potential error - * messages are sent to client. If the automatic validation is turned off, - * isValid() and validate() methods still work, but one must show the - * validation in their own code. - * - * @return True, if automatic validation is enabled. - */ - public boolean isValidationVisible() { - return validationVisible; - } - - /** - * Enable or disable automatic, visible validation. - * - * If automatic validation is enabled, any validators connected to this - * component are evaluated while painting the component and potential error - * messages are sent to client. If the automatic validation is turned off, - * isValid() and validate() methods still work, but one must show the - * validation in their own code. - * - * @param validateAutomatically - * True, if automatic validation is enabled. - */ - public void setValidationVisible(boolean validateAutomatically) { - if (validationVisible != validateAutomatically) { - requestRepaint(); - validationVisible = validateAutomatically; - } - } - - /** - * Sets the current buffered source exception. - * - * @param currentBufferedSourceException - */ - public void setCurrentBufferedSourceException( - Buffered.SourceException currentBufferedSourceException) { - this.currentBufferedSourceException = currentBufferedSourceException; - requestRepaint(); - } - - /** - * Gets the current buffered source exception. - * - * @return The current source exception - */ - protected Buffered.SourceException getCurrentBufferedSourceException() { - return currentBufferedSourceException; - } - - /** - * A ready-made {@link ShortcutListener} that focuses the given - * {@link Focusable} (usually a {@link Field}) when the keyboard shortcut is - * invoked. - * - */ - public static class FocusShortcut extends ShortcutListener { - protected Focusable focusable; - - /** - * Creates a keyboard shortcut for focusing the given {@link Focusable} - * using the shorthand notation defined in {@link ShortcutAction}. - * - * @param focusable - * to focused when the shortcut is invoked - * @param shorthandCaption - * caption with keycode and modifiers indicated - */ - public FocusShortcut(Focusable focusable, String shorthandCaption) { - super(shorthandCaption); - this.focusable = focusable; - } - - /** - * Creates a keyboard shortcut for focusing the given {@link Focusable}. - * - * @param focusable - * to focused when the shortcut is invoked - * @param keyCode - * keycode that invokes the shortcut - * @param modifiers - * modifiers required to invoke the shortcut - */ - public FocusShortcut(Focusable focusable, int keyCode, int... modifiers) { - super(null, keyCode, modifiers); - this.focusable = focusable; - } - - /** - * Creates a keyboard shortcut for focusing the given {@link Focusable}. - * - * @param focusable - * to focused when the shortcut is invoked - * @param keyCode - * keycode that invokes the shortcut - */ - public FocusShortcut(Focusable focusable, int keyCode) { - this(focusable, keyCode, null); - } - - @Override - public void handleAction(Object sender, Object target) { - focusable.focus(); - } - } - - /** - * Gets the converter used to convert the property data source value to the - * field value. - * - * @return The converter or null if none is set. - */ - public Converter<T, Object> getConverter() { - return converter; - } - - /** - * Sets the converter used to convert the field value to property data - * source type. The converter must have a presentation type that matches the - * field type. - * - * @param converter - * The new converter to use. - */ - public void setConverter(Converter<T, ?> converter) { - this.converter = (Converter<T, Object>) converter; - requestRepaint(); - } - - @Override - public AbstractFieldState getState() { - return (AbstractFieldState) super.getState(); - } - - @Override - public void updateState() { - super.updateState(); - - // Hide the error indicator if needed - getState().setHideErrors(shouldHideErrors()); - } - - /** - * Registers this as an event listener for events sent by the data source - * (if any). Does nothing if - * <code>isListeningToPropertyEvents == true</code>. - */ - private void addPropertyListeners() { - if (!isListeningToPropertyEvents) { - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource).addListener(this); - } - if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .addListener(this); - } - isListeningToPropertyEvents = true; - } - } - - /** - * Stops listening to events sent by the data source (if any). Does nothing - * if <code>isListeningToPropertyEvents == false</code>. - */ - private void removePropertyListeners() { - if (isListeningToPropertyEvents) { - if (dataSource instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) dataSource) - .removeListener(this); - } - if (dataSource instanceof Property.ReadOnlyStatusChangeNotifier) { - ((Property.ReadOnlyStatusChangeNotifier) dataSource) - .removeListener(this); - } - isListeningToPropertyEvents = false; - } - } -} diff --git a/src/com/vaadin/ui/AbstractJavaScriptComponent.java b/src/com/vaadin/ui/AbstractJavaScriptComponent.java deleted file mode 100644 index 5ec80573ab..0000000000 --- a/src/com/vaadin/ui/AbstractJavaScriptComponent.java +++ /dev/null @@ -1,165 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import com.vaadin.shared.ui.JavaScriptComponentState; -import com.vaadin.terminal.JavaScriptCallbackHelper; -import com.vaadin.terminal.gwt.client.ApplicationConnection; -import com.vaadin.terminal.gwt.client.ui.JavaScriptWidget; - -/** - * Base class for Components with all client-side logic implemented using - * JavaScript. - * <p> - * When a new JavaScript component is initialized in the browser, the framework - * will look for a globally defined JavaScript function that will initialize the - * component. The name of the initialization function is formed by replacing . - * with _ in the name of the server-side class. If no such function is defined, - * each super class is used in turn until a match is found. The framework will - * thus first attempt with <code>com_example_MyComponent</code> for the - * server-side - * <code>com.example.MyComponent extends AbstractJavaScriptComponent</code> - * class. If MyComponent instead extends <code>com.example.SuperComponent</code> - * , then <code>com_example_SuperComponent</code> will also be attempted if - * <code>com_example_MyComponent</code> has not been defined. - * <p> - * JavaScript components have a very simple GWT widget ({@link JavaScriptWidget} - * ) just consisting of a <code>div</code> element to which the JavaScript code - * should initialize its own user interface. - * <p> - * The initialization function will be called with <code>this</code> pointing to - * a connector wrapper object providing integration to Vaadin with the following - * functions: - * <ul> - * <li><code>getConnectorId()</code> - returns a string with the id of the - * connector.</li> - * <li><code>getParentId([connectorId])</code> - returns a string with the id of - * the connector's parent. If <code>connectorId</code> is provided, the id of - * the parent of the corresponding connector with the passed id is returned - * instead.</li> - * <li><code>getElement([connectorId])</code> - returns the DOM Element that is - * the root of a connector's widget. <code>null</code> is returned if the - * connector can not be found or if the connector doesn't have a widget. If - * <code>connectorId</code> is not provided, the connector id of the current - * connector will be used.</li> - * <li><code>getState()</code> - returns an object corresponding to the shared - * state defined on the server. The scheme for conversion between Java and - * JavaScript types is described bellow.</li> - * <li><code>registerRpc([name, ] rpcObject)</code> - registers the - * <code>rpcObject</code> as a RPC handler. <code>rpcObject</code> should be an - * object with field containing functions for all eligible RPC functions. If - * <code>name</code> is provided, the RPC handler will only used for RPC calls - * for the RPC interface with the same fully qualified Java name. If no - * <code>name</code> is provided, the RPC handler will be used for all incoming - * RPC invocations where the RPC method name is defined as a function field in - * the handler. The scheme for conversion between Java types in the RPC - * interface definition and the JavaScript values passed as arguments to the - * handler functions is described bellow.</li> - * <li><code>getRpcProxy([name])</code> - returns an RPC proxy object. If - * <code>name</code> is provided, the proxy object will contain functions for - * all methods in the RPC interface with the same fully qualified name, provided - * a RPC handler has been registered by the server-side code. If no - * <code>name</code> is provided, the returned RPC proxy object will contain - * functions for all methods in all RPC interfaces registered for the connector - * on the server. If the same method name is present in multiple registered RPC - * interfaces, the corresponding function in the RPC proxy object will throw an - * exception when called. The scheme for conversion between Java types in the - * RPC interface and the JavaScript values that should be passed to the - * functions is described bellow.</li> - * <li><code>translateVaadinUri(uri)</code> - Translates a Vaadin URI to a URL - * that can be used in the browser. This is just way of accessing - * {@link ApplicationConnection#translateVaadinUri(String)}</li> - * </ul> - * The connector wrapper also supports these special functions: - * <ul> - * <li><code>onStateChange</code> - If the JavaScript code assigns a function to - * the field, that function is called whenever the contents of the shared state - * is changed.</li> - * <li>Any field name corresponding to a call to - * {@link #addFunction(String, JavaScriptFunction)} on the server will - * automatically be present as a function that triggers the registered function - * on the server.</li> - * <li>Any field name referred to using - * {@link #callFunction(String, Object...)} on the server will be called if a - * function has been assigned to the field.</li> - * </ul> - * <p> - * - * Values in the Shared State and in RPC calls are converted between Java and - * JavaScript using the following conventions: - * <ul> - * <li>Primitive Java numbers (byte, char, int, long, float, double) and their - * boxed types (Byte, Character, Integer, Long, Float, Double) are represented - * by JavaScript numbers.</li> - * <li>The primitive Java boolean and the boxed Boolean are represented by - * JavaScript booleans.</li> - * <li>Java Strings are represented by JavaScript strings.</li> - * <li>List, Set and all arrays in Java are represented by JavaScript arrays.</li> - * <li>Map<String, ?> in Java is represented by JavaScript object with fields - * corresponding to the map keys.</li> - * <li>Any other Java Map is represented by a JavaScript array containing two - * arrays, the first contains the keys and the second contains the values in the - * same order.</li> - * <li>A Java Bean is represented by a JavaScript object with fields - * corresponding to the bean's properties.</li> - * <li>A Java Connector is represented by a JavaScript string containing the - * connector's id.</li> - * <li>A pluggable serialization mechanism is provided for types not described - * here. Please refer to the documentation for specific types for serialization - * information.</li> - * </ul> - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public abstract class AbstractJavaScriptComponent extends AbstractComponent { - private JavaScriptCallbackHelper callbackHelper = new JavaScriptCallbackHelper( - this); - - @Override - protected <T> void registerRpc(T implementation, Class<T> rpcInterfaceType) { - super.registerRpc(implementation, rpcInterfaceType); - callbackHelper.registerRpc(rpcInterfaceType); - } - - /** - * Register a {@link JavaScriptFunction} that can be called from the - * JavaScript using the provided name. A JavaScript function with the - * provided name will be added to the connector wrapper object (initially - * available as <code>this</code>). Calling that JavaScript function will - * cause the call method in the registered {@link JavaScriptFunction} to be - * invoked with the same arguments. - * - * @param functionName - * the name that should be used for client-side function - * @param function - * the {@link JavaScriptFunction} object that will be invoked - * when the JavaScript function is called - */ - protected void addFunction(String functionName, JavaScriptFunction function) { - callbackHelper.registerCallback(functionName, function); - } - - /** - * Invoke a named function that the connector JavaScript has added to the - * JavaScript connector wrapper object. The arguments should only contain - * data types that can be represented in JavaScript including primitives, - * their boxed types, arrays, String, List, Set, Map, Connector and - * JavaBeans. - * - * @param name - * the name of the function - * @param arguments - * function arguments - */ - protected void callFunction(String name, Object... arguments) { - callbackHelper.invokeCallback(name, arguments); - } - - @Override - public JavaScriptComponentState getState() { - return (JavaScriptComponentState) super.getState(); - } -} diff --git a/src/com/vaadin/ui/AbstractLayout.java b/src/com/vaadin/ui/AbstractLayout.java deleted file mode 100644 index 7b3a537d06..0000000000 --- a/src/com/vaadin/ui/AbstractLayout.java +++ /dev/null @@ -1,77 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.shared.ui.AbstractLayoutState; -import com.vaadin.ui.Layout.MarginHandler; - -/** - * An abstract class that defines default implementation for the {@link Layout} - * interface. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -@SuppressWarnings("serial") -public abstract class AbstractLayout extends AbstractComponentContainer - implements Layout, MarginHandler { - - protected MarginInfo margins = new MarginInfo(false); - - @Override - public AbstractLayoutState getState() { - return (AbstractLayoutState) super.getState(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout#setMargin(boolean) - */ - @Override - public void setMargin(boolean enabled) { - margins.setMargins(enabled); - getState().setMarginsBitmask(margins.getBitMask()); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.MarginHandler#getMargin() - */ - @Override - public MarginInfo getMargin() { - return margins; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.MarginHandler#setMargin(MarginInfo) - */ - @Override - public void setMargin(MarginInfo marginInfo) { - margins.setMargins(marginInfo); - getState().setMarginsBitmask(margins.getBitMask()); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout#setMargin(boolean, boolean, boolean, boolean) - */ - @Override - public void setMargin(boolean topEnabled, boolean rightEnabled, - boolean bottomEnabled, boolean leftEnabled) { - margins.setMargins(topEnabled, rightEnabled, bottomEnabled, leftEnabled); - getState().setMarginsBitmask(margins.getBitMask()); - requestRepaint(); - } - -} diff --git a/src/com/vaadin/ui/AbstractMedia.java b/src/com/vaadin/ui/AbstractMedia.java deleted file mode 100644 index 71b2e38ef3..0000000000 --- a/src/com/vaadin/ui/AbstractMedia.java +++ /dev/null @@ -1,196 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.ArrayList; -import java.util.List; - -import com.vaadin.shared.communication.URLReference; -import com.vaadin.shared.ui.AbstractMediaState; -import com.vaadin.shared.ui.MediaControl; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.server.ResourceReference; - -/** - * Abstract base class for the HTML5 media components. - * - * @author Vaadin Ltd - */ -public abstract class AbstractMedia extends AbstractComponent { - - @Override - public AbstractMediaState getState() { - return (AbstractMediaState) super.getState(); - } - - /** - * Sets a single media file as the source of the media component. - * - * @param source - */ - public void setSource(Resource source) { - clearSources(); - - addSource(source); - } - - private void clearSources() { - getState().getSources().clear(); - getState().getSourceTypes().clear(); - } - - /** - * Adds an alternative media file to the sources list. Which of the sources - * is used is selected by the browser depending on which file formats it - * supports. See <a - * href="http://en.wikipedia.org/wiki/HTML5_video#Table">wikipedia</a> for a - * table of formats supported by different browsers. - * - * @param source - */ - public void addSource(Resource source) { - if (source != null) { - getState().getSources().add(new ResourceReference(source)); - getState().getSourceTypes().add(source.getMIMEType()); - requestRepaint(); - } - } - - /** - * Set multiple sources at once. Which of the sources is used is selected by - * the browser depending on which file formats it supports. See <a - * href="http://en.wikipedia.org/wiki/HTML5_video#Table">wikipedia</a> for a - * table of formats supported by different browsers. - * - * @param sources - */ - public void setSources(Resource... sources) { - clearSources(); - for (Resource source : sources) { - addSource(source); - } - } - - /** - * @return The sources pointed to in this media. - */ - public List<Resource> getSources() { - ArrayList<Resource> sources = new ArrayList<Resource>(); - for (URLReference ref : getState().getSources()) { - sources.add(((ResourceReference) ref).getResource()); - } - return sources; - } - - /** - * Sets whether or not the browser should show native media controls. - * - * @param showControls - */ - public void setShowControls(boolean showControls) { - getState().setShowControls(showControls); - requestRepaint(); - } - - /** - * @return true if the browser is to show native media controls. - */ - public boolean isShowControls() { - return getState().isShowControls(); - } - - /** - * Sets the alternative text to be displayed if the browser does not support - * HTML5. This text is rendered as HTML if - * {@link #setHtmlContentAllowed(boolean)} is set to true. With HTML - * rendering, this method can also be used to implement fallback to a - * flash-based player, see the <a href= - * "https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Using_Flash" - * >Mozilla Developer Network</a> for details. - * - * @param altText - */ - public void setAltText(String altText) { - getState().setAltText(altText); - requestRepaint(); - } - - /** - * @return The text/html that is displayed when a browser doesn't support - * HTML5. - */ - public String getAltText() { - return getState().getAltText(); - } - - /** - * Set whether the alternative text ({@link #setAltText(String)}) is - * rendered as HTML or not. - * - * @param htmlContentAllowed - */ - public void setHtmlContentAllowed(boolean htmlContentAllowed) { - getState().setHtmlContentAllowed(htmlContentAllowed); - requestRepaint(); - } - - /** - * @return true if the alternative text ({@link #setAltText(String)}) is to - * be rendered as HTML. - */ - public boolean isHtmlContentAllowed() { - return getState().isHtmlContentAllowed(); - } - - /** - * Sets whether the media is to automatically start playback when enough - * data has been loaded. - * - * @param autoplay - */ - public void setAutoplay(boolean autoplay) { - getState().setAutoplay(autoplay); - requestRepaint(); - } - - /** - * @return true if the media is set to automatically start playback. - */ - public boolean isAutoplay() { - return getState().isAutoplay(); - } - - /** - * Set whether to mute the audio or not. - * - * @param muted - */ - public void setMuted(boolean muted) { - getState().setMuted(muted); - requestRepaint(); - } - - /** - * @return true if the audio is muted. - */ - public boolean isMuted() { - return getState().isMuted(); - } - - /** - * Pauses the media. - */ - public void pause() { - getRpcProxy(MediaControl.class).pause(); - } - - /** - * Starts playback of the media. - */ - public void play() { - getRpcProxy(MediaControl.class).play(); - } - -} diff --git a/src/com/vaadin/ui/AbstractOrderedLayout.java b/src/com/vaadin/ui/AbstractOrderedLayout.java deleted file mode 100644 index 0581d0a279..0000000000 --- a/src/com/vaadin/ui/AbstractOrderedLayout.java +++ /dev/null @@ -1,383 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Iterator; -import java.util.LinkedList; - -import com.vaadin.event.LayoutEvents.LayoutClickEvent; -import com.vaadin.event.LayoutEvents.LayoutClickListener; -import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.shared.Connector; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutServerRpc; -import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState; -import com.vaadin.shared.ui.orderedlayout.AbstractOrderedLayoutState.ChildComponentData; -import com.vaadin.terminal.Sizeable; -import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; - -@SuppressWarnings("serial") -public abstract class AbstractOrderedLayout extends AbstractLayout implements - Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier { - - private AbstractOrderedLayoutServerRpc rpc = new AbstractOrderedLayoutServerRpc() { - - @Override - public void layoutClick(MouseEventDetails mouseDetails, - Connector clickedConnector) { - fireEvent(LayoutClickEvent.createEvent(AbstractOrderedLayout.this, - mouseDetails, clickedConnector)); - } - }; - - public static final Alignment ALIGNMENT_DEFAULT = Alignment.TOP_LEFT; - - /** - * Custom layout slots containing the components. - */ - protected LinkedList<Component> components = new LinkedList<Component>(); - - /* Child component alignments */ - - /** - * Mapping from components to alignments (horizontal + vertical). - */ - public AbstractOrderedLayout() { - registerRpc(rpc); - } - - @Override - public AbstractOrderedLayoutState getState() { - return (AbstractOrderedLayoutState) super.getState(); - } - - /** - * Add a component into this container. The component is added to the right - * or under the previous component. - * - * @param c - * the component to be added. - */ - @Override - public void addComponent(Component c) { - // Add to components before calling super.addComponent - // so that it is available to AttachListeners - components.add(c); - try { - super.addComponent(c); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - componentAdded(c); - } - - /** - * Adds a component into this container. The component is added to the left - * or on top of the other components. - * - * @param c - * the component to be added. - */ - public void addComponentAsFirst(Component c) { - // If c is already in this, we must remove it before proceeding - // see ticket #7668 - if (c.getParent() == this) { - removeComponent(c); - } - components.addFirst(c); - try { - super.addComponent(c); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - componentAdded(c); - - } - - /** - * Adds a component into indexed position in this container. - * - * @param c - * the component to be added. - * @param index - * the index of the component position. The components currently - * in and after the position are shifted forwards. - */ - public void addComponent(Component c, int index) { - // If c is already in this, we must remove it before proceeding - // see ticket #7668 - if (c.getParent() == this) { - // When c is removed, all components after it are shifted down - if (index > getComponentIndex(c)) { - index--; - } - removeComponent(c); - } - components.add(index, c); - try { - super.addComponent(c); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - - componentAdded(c); - } - - private void componentRemoved(Component c) { - getState().getChildData().remove(c); - requestRepaint(); - } - - private void componentAdded(Component c) { - getState().getChildData().put(c, new ChildComponentData()); - requestRepaint(); - - } - - /** - * Removes the component from this container. - * - * @param c - * the component to be removed. - */ - @Override - public void removeComponent(Component c) { - components.remove(c); - super.removeComponent(c); - componentRemoved(c); - } - - /** - * Gets the component container iterator for going trough all the components - * in the container. - * - * @return the Iterator of the components inside the container. - */ - @Override - public Iterator<Component> getComponentIterator() { - return components.iterator(); - } - - /** - * Gets the number of contained components. Consistent with the iterator - * returned by {@link #getComponentIterator()}. - * - * @return the number of contained components - */ - @Override - public int getComponentCount() { - return components.size(); - } - - /* Documented in superclass */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - - // Gets the locations - int oldLocation = -1; - int newLocation = -1; - int location = 0; - for (final Iterator<Component> i = components.iterator(); i.hasNext();) { - final Component component = i.next(); - - if (component == oldComponent) { - oldLocation = location; - } - if (component == newComponent) { - newLocation = location; - } - - location++; - } - - if (oldLocation == -1) { - addComponent(newComponent); - } else if (newLocation == -1) { - removeComponent(oldComponent); - addComponent(newComponent, oldLocation); - } else { - // Both old and new are in the layout - if (oldLocation > newLocation) { - components.remove(oldComponent); - components.add(newLocation, oldComponent); - components.remove(newComponent); - components.add(oldLocation, newComponent); - } else { - components.remove(newComponent); - components.add(oldLocation, newComponent); - components.remove(oldComponent); - components.add(newLocation, oldComponent); - } - - requestRepaint(); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.AlignmentHandler#setComponentAlignment(com - * .vaadin.ui.Component, int, int) - */ - @Override - public void setComponentAlignment(Component childComponent, - int horizontalAlignment, int verticalAlignment) { - Alignment a = new Alignment(horizontalAlignment + verticalAlignment); - setComponentAlignment(childComponent, a); - } - - @Override - public void setComponentAlignment(Component childComponent, - Alignment alignment) { - ChildComponentData childData = getState().getChildData().get( - childComponent); - if (childData != null) { - // Alignments are bit masks - childData.setAlignmentBitmask(alignment.getBitMask()); - requestRepaint(); - } else { - throw new IllegalArgumentException( - "Component must be added to layout before using setComponentAlignment()"); - } - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.AlignmentHandler#getComponentAlignment(com - * .vaadin.ui.Component) - */ - @Override - public Alignment getComponentAlignment(Component childComponent) { - ChildComponentData childData = getState().getChildData().get( - childComponent); - if (childData == null) { - throw new IllegalArgumentException( - "The given component is not a child of this layout"); - } - - return new Alignment(childData.getAlignmentBitmask()); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.SpacingHandler#setSpacing(boolean) - */ - @Override - public void setSpacing(boolean spacing) { - getState().setSpacing(spacing); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing() - */ - @Override - public boolean isSpacing() { - return getState().isSpacing(); - } - - /** - * <p> - * This method is used to control how excess space in layout is distributed - * among components. Excess space may exist if layout is sized and contained - * non relatively sized components don't consume all available space. - * - * <p> - * Example how to distribute 1:3 (33%) for component1 and 2:3 (67%) for - * component2 : - * - * <code> - * layout.setExpandRatio(component1, 1);<br> - * layout.setExpandRatio(component2, 2); - * </code> - * - * <p> - * If no ratios have been set, the excess space is distributed evenly among - * all components. - * - * <p> - * Note, that width or height (depending on orientation) needs to be defined - * for this method to have any effect. - * - * @see Sizeable - * - * @param component - * the component in this layout which expand ratio is to be set - * @param ratio - */ - public void setExpandRatio(Component component, float ratio) { - ChildComponentData childData = getState().getChildData().get(component); - if (childData == null) { - throw new IllegalArgumentException( - "The given component is not a child of this layout"); - } - - childData.setExpandRatio(ratio); - requestRepaint(); - }; - - /** - * Returns the expand ratio of given component. - * - * @param component - * which expand ratios is requested - * @return expand ratio of given component, 0.0f by default. - */ - public float getExpandRatio(Component component) { - ChildComponentData childData = getState().getChildData().get(component); - if (childData == null) { - throw new IllegalArgumentException( - "The given component is not a child of this layout"); - } - - return childData.getExpandRatio(); - } - - @Override - public void addListener(LayoutClickListener listener) { - addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener, - LayoutClickListener.clickMethod); - } - - @Override - public void removeListener(LayoutClickListener listener) { - removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener); - } - - /** - * Returns the index of the given component. - * - * @param component - * The component to look up. - * @return The index of the component or -1 if the component is not a child. - */ - public int getComponentIndex(Component component) { - return components.indexOf(component); - } - - /** - * Returns the component at the given position. - * - * @param index - * The position of the component. - * @return The component at the given index. - * @throws IndexOutOfBoundsException - * If the index is out of range. - */ - public Component getComponent(int index) throws IndexOutOfBoundsException { - return components.get(index); - } - -} diff --git a/src/com/vaadin/ui/AbstractSelect.java b/src/com/vaadin/ui/AbstractSelect.java deleted file mode 100644 index 0a97ceb649..0000000000 --- a/src/com/vaadin/ui/AbstractSelect.java +++ /dev/null @@ -1,2029 +0,0 @@ -/* - * @VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Set; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.data.util.IndexedContainer; -import com.vaadin.event.DataBoundTransferable; -import com.vaadin.event.Transferable; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.DropTarget; -import com.vaadin.event.dd.TargetDetailsImpl; -import com.vaadin.event.dd.acceptcriteria.ClientSideCriterion; -import com.vaadin.event.dd.acceptcriteria.ContainsDataFlavor; -import com.vaadin.event.dd.acceptcriteria.TargetDetailIs; -import com.vaadin.shared.ui.dd.VerticalDropLocation; -import com.vaadin.terminal.KeyMapper; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.ui.AbstractSelect.ItemCaptionMode; - -/** - * <p> - * A class representing a selection of items the user has selected in a UI. The - * set of choices is presented as a set of {@link com.vaadin.data.Item}s in a - * {@link com.vaadin.data.Container}. - * </p> - * - * <p> - * A <code>Select</code> component may be in single- or multiselect mode. - * Multiselect mode means that more than one item can be selected - * simultaneously. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -@SuppressWarnings("serial") -// TODO currently cannot specify type more precisely in case of multi-select -public abstract class AbstractSelect extends AbstractField<Object> implements - Container, Container.Viewer, Container.PropertySetChangeListener, - Container.PropertySetChangeNotifier, Container.ItemSetChangeNotifier, - Container.ItemSetChangeListener, Vaadin6Component { - - public enum ItemCaptionMode { - /** - * Item caption mode: Item's ID's <code>String</code> representation is - * used as caption. - */ - ID, - /** - * Item caption mode: Item's <code>String</code> representation is used - * as caption. - */ - ITEM, - /** - * Item caption mode: Index of the item is used as caption. The index - * mode can only be used with the containers implementing the - * {@link com.vaadin.data.Container.Indexed} interface. - */ - INDEX, - /** - * Item caption mode: If an Item has a caption it's used, if not, Item's - * ID's <code>String</code> representation is used as caption. <b>This - * is the default</b>. - */ - EXPLICIT_DEFAULTS_ID, - /** - * Item caption mode: Captions must be explicitly specified. - */ - EXPLICIT, - /** - * Item caption mode: Only icons are shown, captions are hidden. - */ - ICON_ONLY, - /** - * Item caption mode: Item captions are read from property specified - * with <code>setItemCaptionPropertyId</code>. - */ - PROPERTY; - } - - /** - * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead - */ - @Deprecated - public static final ItemCaptionMode ITEM_CAPTION_MODE_ID = ItemCaptionMode.ID; - - /** - * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead - */ - @Deprecated - public static final ItemCaptionMode ITEM_CAPTION_MODE_ITEM = ItemCaptionMode.ITEM; - - /** - * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead - */ - @Deprecated - public static final ItemCaptionMode ITEM_CAPTION_MODE_INDEX = ItemCaptionMode.INDEX; - - /** - * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead - */ - @Deprecated - public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID = ItemCaptionMode.EXPLICIT_DEFAULTS_ID; - - /** - * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead - */ - @Deprecated - public static final ItemCaptionMode ITEM_CAPTION_MODE_EXPLICIT = ItemCaptionMode.EXPLICIT; - - /** - * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead - */ - @Deprecated - public static final ItemCaptionMode ITEM_CAPTION_MODE_ICON_ONLY = ItemCaptionMode.ICON_ONLY; - - /** - * @deprecated from 7.0, use {@link ItemCaptionMode.ID} instead - */ - @Deprecated - public static final ItemCaptionMode ITEM_CAPTION_MODE_PROPERTY = ItemCaptionMode.PROPERTY; - - /** - * Interface for option filtering, used to filter options based on user - * entered value. The value is matched to the item caption. - * <code>FILTERINGMODE_OFF</code> (0) turns the filtering off. - * <code>FILTERINGMODE_STARTSWITH</code> (1) matches from the start of the - * caption. <code>FILTERINGMODE_CONTAINS</code> (1) matches anywhere in the - * caption. - */ - public interface Filtering extends Serializable { - public static final int FILTERINGMODE_OFF = 0; - public static final int FILTERINGMODE_STARTSWITH = 1; - public static final int FILTERINGMODE_CONTAINS = 2; - - /** - * Sets the option filtering mode. - * - * @param filteringMode - * the filtering mode to use - */ - public void setFilteringMode(int filteringMode); - - /** - * Gets the current filtering mode. - * - * @return the filtering mode in use - */ - public int getFilteringMode(); - - } - - /** - * Multi select modes that controls how multi select behaves. - */ - public enum MultiSelectMode { - /** - * The default behavior of the multi select mode - */ - DEFAULT, - - /** - * The previous more simple behavior of the multselect - */ - SIMPLE - } - - /** - * Is the select in multiselect mode? - */ - private boolean multiSelect = false; - - /** - * Select options. - */ - protected Container items; - - /** - * Is the user allowed to add new options? - */ - private boolean allowNewOptions; - - /** - * Keymapper used to map key values. - */ - protected KeyMapper<Object> itemIdMapper = new KeyMapper<Object>(); - - /** - * Item icons. - */ - private final HashMap<Object, Resource> itemIcons = new HashMap<Object, Resource>(); - - /** - * Item captions. - */ - private final HashMap<Object, String> itemCaptions = new HashMap<Object, String>(); - - /** - * Item caption mode. - */ - private ItemCaptionMode itemCaptionMode = ItemCaptionMode.EXPLICIT_DEFAULTS_ID; - - /** - * Item caption source property id. - */ - private Object itemCaptionPropertyId = null; - - /** - * Item icon source property id. - */ - private Object itemIconPropertyId = null; - - /** - * List of property set change event listeners. - */ - private Set<Container.PropertySetChangeListener> propertySetEventListeners = null; - - /** - * List of item set change event listeners. - */ - private Set<Container.ItemSetChangeListener> itemSetEventListeners = null; - - /** - * Item id that represents null selection of this select. - * - * <p> - * Data interface does not support nulls as item ids. Selecting the item - * identified by this id is the same as selecting no items at all. This - * setting only affects the single select mode. - * </p> - */ - private Object nullSelectionItemId = null; - - // Null (empty) selection is enabled by default - private boolean nullSelectionAllowed = true; - private NewItemHandler newItemHandler; - - // Caption (Item / Property) change listeners - CaptionChangeListener captionChangeListener; - - /* Constructors */ - - /** - * Creates an empty Select. The caption is not used. - */ - public AbstractSelect() { - setContainerDataSource(new IndexedContainer()); - } - - /** - * Creates an empty Select with caption. - */ - public AbstractSelect(String caption) { - setContainerDataSource(new IndexedContainer()); - setCaption(caption); - } - - /** - * Creates a new select that is connected to a data-source. - * - * @param caption - * the Caption of the component. - * @param dataSource - * the Container datasource to be selected from by this select. - */ - public AbstractSelect(String caption, Container dataSource) { - setCaption(caption); - setContainerDataSource(dataSource); - } - - /** - * Creates a new select that is filled from a collection of option values. - * - * @param caption - * the Caption of this field. - * @param options - * the Collection containing the options. - */ - public AbstractSelect(String caption, Collection<?> options) { - - // Creates the options container and add given options to it - final Container c = new IndexedContainer(); - if (options != null) { - for (final Iterator<?> i = options.iterator(); i.hasNext();) { - c.addItem(i.next()); - } - } - - setCaption(caption); - setContainerDataSource(c); - } - - /* Component methods */ - - /** - * Paints the content of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - - // Paints select attributes - if (isMultiSelect()) { - target.addAttribute("selectmode", "multi"); - } - if (isNewItemsAllowed()) { - target.addAttribute("allownewitem", true); - } - if (isNullSelectionAllowed()) { - target.addAttribute("nullselect", true); - if (getNullSelectionItemId() != null) { - target.addAttribute("nullselectitem", true); - } - } - - // Constructs selected keys array - String[] selectedKeys; - if (isMultiSelect()) { - selectedKeys = new String[((Set<?>) getValue()).size()]; - } else { - selectedKeys = new String[(getValue() == null - && getNullSelectionItemId() == null ? 0 : 1)]; - } - - // == - // first remove all previous item/property listeners - getCaptionChangeListener().clear(); - // Paints the options and create array of selected id keys - - target.startTag("options"); - int keyIndex = 0; - // Support for external null selection item id - final Collection<?> ids = getItemIds(); - if (isNullSelectionAllowed() && getNullSelectionItemId() != null - && !ids.contains(getNullSelectionItemId())) { - final Object id = getNullSelectionItemId(); - // Paints option - target.startTag("so"); - paintItem(target, id); - if (isSelected(id)) { - selectedKeys[keyIndex++] = itemIdMapper.key(id); - } - target.endTag("so"); - } - - final Iterator<?> i = getItemIds().iterator(); - // Paints the available selection options from data source - while (i.hasNext()) { - // Gets the option attribute values - final Object id = i.next(); - if (!isNullSelectionAllowed() && id != null - && id.equals(getNullSelectionItemId())) { - // Remove item if it's the null selection item but null - // selection is not allowed - continue; - } - final String key = itemIdMapper.key(id); - // add listener for each item, to cause repaint if an item changes - getCaptionChangeListener().addNotifierForItem(id); - target.startTag("so"); - paintItem(target, id); - if (isSelected(id) && keyIndex < selectedKeys.length) { - selectedKeys[keyIndex++] = key; - } - target.endTag("so"); - } - target.endTag("options"); - // == - - // Paint variables - target.addVariable(this, "selected", selectedKeys); - if (isNewItemsAllowed()) { - target.addVariable(this, "newitem", ""); - } - - } - - protected void paintItem(PaintTarget target, Object itemId) - throws PaintException { - final String key = itemIdMapper.key(itemId); - final String caption = getItemCaption(itemId); - final Resource icon = getItemIcon(itemId); - if (icon != null) { - target.addAttribute("icon", icon); - } - target.addAttribute("caption", caption); - if (itemId != null && itemId.equals(getNullSelectionItemId())) { - target.addAttribute("nullselection", true); - } - target.addAttribute("key", key); - if (isSelected(itemId)) { - target.addAttribute("selected", true); - } - } - - /** - * Invoked when the value of a variable has changed. - * - * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, - * java.util.Map) - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - - // New option entered (and it is allowed) - if (isNewItemsAllowed()) { - final String newitem = (String) variables.get("newitem"); - if (newitem != null && newitem.length() > 0) { - getNewItemHandler().addNewItem(newitem); - } - } - - // Selection change - if (variables.containsKey("selected")) { - final String[] clientSideSelectedKeys = (String[]) variables - .get("selected"); - - // Multiselect mode - if (isMultiSelect()) { - - // TODO Optimize by adding repaintNotNeeded when applicable - - // Converts the key-array to id-set - final LinkedList<Object> acceptedSelections = new LinkedList<Object>(); - for (int i = 0; i < clientSideSelectedKeys.length; i++) { - final Object id = itemIdMapper - .get(clientSideSelectedKeys[i]); - if (!isNullSelectionAllowed() - && (id == null || id == getNullSelectionItemId())) { - // skip empty selection if nullselection is not allowed - requestRepaint(); - } else if (id != null && containsId(id)) { - acceptedSelections.add(id); - } - } - - if (!isNullSelectionAllowed() && acceptedSelections.size() < 1) { - // empty selection not allowed, keep old value - requestRepaint(); - return; - } - - // Limits the deselection to the set of visible items - // (non-visible items can not be deselected) - Collection<?> visibleNotSelected = getVisibleItemIds(); - if (visibleNotSelected != null) { - visibleNotSelected = new HashSet<Object>(visibleNotSelected); - // Don't remove those that will be added to preserve order - visibleNotSelected.removeAll(acceptedSelections); - - @SuppressWarnings("unchecked") - Set<Object> newsel = (Set<Object>) getValue(); - if (newsel == null) { - newsel = new LinkedHashSet<Object>(); - } else { - newsel = new LinkedHashSet<Object>(newsel); - } - newsel.removeAll(visibleNotSelected); - newsel.addAll(acceptedSelections); - setValue(newsel, true); - } - } else { - // Single select mode - if (!isNullSelectionAllowed() - && (clientSideSelectedKeys.length == 0 - || clientSideSelectedKeys[0] == null || clientSideSelectedKeys[0] == getNullSelectionItemId())) { - requestRepaint(); - return; - } - if (clientSideSelectedKeys.length == 0) { - // Allows deselection only if the deselected item is - // visible - final Object current = getValue(); - final Collection<?> visible = getVisibleItemIds(); - if (visible != null && visible.contains(current)) { - setValue(null, true); - } - } else { - final Object id = itemIdMapper - .get(clientSideSelectedKeys[0]); - if (!isNullSelectionAllowed() && id == null) { - requestRepaint(); - } else if (id != null - && id.equals(getNullSelectionItemId())) { - setValue(null, true); - } else { - setValue(id, true); - } - } - } - } - } - - /** - * TODO refine doc Setter for new item handler that is called when user adds - * new item in newItemAllowed mode. - * - * @param newItemHandler - */ - public void setNewItemHandler(NewItemHandler newItemHandler) { - this.newItemHandler = newItemHandler; - } - - /** - * TODO refine doc - * - * @return - */ - public NewItemHandler getNewItemHandler() { - if (newItemHandler == null) { - newItemHandler = new DefaultNewItemHandler(); - } - return newItemHandler; - } - - public interface NewItemHandler extends Serializable { - void addNewItem(String newItemCaption); - } - - /** - * TODO refine doc - * - * This is a default class that handles adding new items that are typed by - * user to selects container. - * - * By extending this class one may implement some logic on new item addition - * like database inserts. - * - */ - public class DefaultNewItemHandler implements NewItemHandler { - @Override - public void addNewItem(String newItemCaption) { - // Checks for readonly - if (isReadOnly()) { - throw new Property.ReadOnlyException(); - } - - // Adds new option - if (addItem(newItemCaption) != null) { - - // Sets the caption property, if used - if (getItemCaptionPropertyId() != null) { - getContainerProperty(newItemCaption, - getItemCaptionPropertyId()) - .setValue(newItemCaption); - } - if (isMultiSelect()) { - Set values = new HashSet((Collection) getValue()); - values.add(newItemCaption); - setValue(values); - } else { - setValue(newItemCaption); - } - } - } - } - - /** - * Gets the visible item ids. In Select, this returns list of all item ids, - * but can be overriden in subclasses if they paint only part of the items - * to the terminal or null if no items is visible. - */ - public Collection<?> getVisibleItemIds() { - return getItemIds(); - } - - /* Property methods */ - - /** - * Returns the type of the property. <code>getValue</code> and - * <code>setValue</code> methods must be compatible with this type: one can - * safely cast <code>getValue</code> to given type and pass any variable - * assignable to this type as a parameter to <code>setValue</code>. - * - * @return the Type of the property. - */ - @Override - public Class<?> getType() { - if (isMultiSelect()) { - return Set.class; - } else { - return Object.class; - } - } - - /** - * Gets the selected item id or in multiselect mode a set of selected ids. - * - * @see com.vaadin.ui.AbstractField#getValue() - */ - @Override - public Object getValue() { - final Object retValue = super.getValue(); - - if (isMultiSelect()) { - - // If the return value is not a set - if (retValue == null) { - return new HashSet<Object>(); - } - if (retValue instanceof Set) { - return Collections.unmodifiableSet((Set<?>) retValue); - } else if (retValue instanceof Collection) { - return new HashSet<Object>((Collection<?>) retValue); - } else { - final Set<Object> s = new HashSet<Object>(); - if (items.containsId(retValue)) { - s.add(retValue); - } - return s; - } - - } else { - return retValue; - } - } - - /** - * Sets the visible value of the property. - * - * <p> - * The value of the select is the selected item id. If the select is in - * multiselect-mode, the value is a set of selected item keys. In - * multiselect mode all collections of id:s can be assigned. - * </p> - * - * @param newValue - * the New selected item or collection of selected items. - * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object) - */ - @Override - public void setValue(Object newValue) throws Property.ReadOnlyException { - if (newValue == getNullSelectionItemId()) { - newValue = null; - } - - setValue(newValue, false); - } - - /** - * Sets the visible value of the property. - * - * <p> - * The value of the select is the selected item id. If the select is in - * multiselect-mode, the value is a set of selected item keys. In - * multiselect mode all collections of id:s can be assigned. - * </p> - * - * @param newValue - * the New selected item or collection of selected items. - * @param repaintIsNotNeeded - * True if caller is sure that repaint is not needed. - * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object, - * java.lang.Boolean) - */ - @Override - protected void setValue(Object newValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException { - - if (isMultiSelect()) { - if (newValue == null) { - super.setValue(new LinkedHashSet<Object>(), repaintIsNotNeeded); - } else if (Collection.class.isAssignableFrom(newValue.getClass())) { - super.setValue(new LinkedHashSet<Object>( - (Collection<?>) newValue), repaintIsNotNeeded); - } - } else if (newValue == null || items.containsId(newValue)) { - super.setValue(newValue, repaintIsNotNeeded); - } - } - - /* Container methods */ - - /** - * Gets the item from the container with given id. If the container does not - * contain the requested item, null is returned. - * - * @param itemId - * the item id. - * @return the item from the container. - */ - @Override - public Item getItem(Object itemId) { - return items.getItem(itemId); - } - - /** - * Gets the item Id collection from the container. - * - * @return the Collection of item ids. - */ - @Override - public Collection<?> getItemIds() { - return items.getItemIds(); - } - - /** - * Gets the property Id collection from the container. - * - * @return the Collection of property ids. - */ - @Override - public Collection<?> getContainerPropertyIds() { - return items.getContainerPropertyIds(); - } - - /** - * Gets the property type. - * - * @param propertyId - * the Id identifying the property. - * @see com.vaadin.data.Container#getType(java.lang.Object) - */ - @Override - public Class<?> getType(Object propertyId) { - return items.getType(propertyId); - } - - /* - * Gets the number of items in the container. - * - * @return the Number of items in the container. - * - * @see com.vaadin.data.Container#size() - */ - @Override - public int size() { - return items.size(); - } - - /** - * Tests, if the collection contains an item with given id. - * - * @param itemId - * the Id the of item to be tested. - */ - @Override - public boolean containsId(Object itemId) { - if (itemId != null) { - return items.containsId(itemId); - } else { - return false; - } - } - - /** - * Gets the Property identified by the given itemId and propertyId from the - * Container - * - * @see com.vaadin.data.Container#getContainerProperty(Object, Object) - */ - @Override - public Property<?> getContainerProperty(Object itemId, Object propertyId) { - return items.getContainerProperty(itemId, propertyId); - } - - /** - * Adds the new property to all items. Adds a property with given id, type - * and default value to all items in the container. - * - * This functionality is optional. If the function is unsupported, it always - * returns false. - * - * @return True if the operation succeeded. - * @see com.vaadin.data.Container#addContainerProperty(java.lang.Object, - * java.lang.Class, java.lang.Object) - */ - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - - final boolean retval = items.addContainerProperty(propertyId, type, - defaultValue); - if (retval && !(items instanceof Container.PropertySetChangeNotifier)) { - firePropertySetChange(); - } - return retval; - } - - /** - * Removes all items from the container. - * - * This functionality is optional. If the function is unsupported, it always - * returns false. - * - * @return True if the operation succeeded. - * @see com.vaadin.data.Container#removeAllItems() - */ - @Override - public boolean removeAllItems() throws UnsupportedOperationException { - - final boolean retval = items.removeAllItems(); - itemIdMapper.removeAll(); - if (retval) { - setValue(null); - if (!(items instanceof Container.ItemSetChangeNotifier)) { - fireItemSetChange(); - } - } - return retval; - } - - /** - * Creates a new item into container with container managed id. The id of - * the created new item is returned. The item can be fetched with getItem() - * method. if the creation fails, null is returned. - * - * @return the Id of the created item or null in case of failure. - * @see com.vaadin.data.Container#addItem() - */ - @Override - public Object addItem() throws UnsupportedOperationException { - - final Object retval = items.addItem(); - if (retval != null - && !(items instanceof Container.ItemSetChangeNotifier)) { - fireItemSetChange(); - } - return retval; - } - - /** - * Create a new item into container. The created new item is returned and - * ready for setting property values. if the creation fails, null is - * returned. In case the container already contains the item, null is - * returned. - * - * This functionality is optional. If the function is unsupported, it always - * returns null. - * - * @param itemId - * the Identification of the item to be created. - * @return the Created item with the given id, or null in case of failure. - * @see com.vaadin.data.Container#addItem(java.lang.Object) - */ - @Override - public Item addItem(Object itemId) throws UnsupportedOperationException { - - final Item retval = items.addItem(itemId); - if (retval != null - && !(items instanceof Container.ItemSetChangeNotifier)) { - fireItemSetChange(); - } - return retval; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container#removeItem(java.lang.Object) - */ - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - - unselect(itemId); - final boolean retval = items.removeItem(itemId); - itemIdMapper.remove(itemId); - if (retval && !(items instanceof Container.ItemSetChangeNotifier)) { - fireItemSetChange(); - } - return retval; - } - - /** - * Removes the property from all items. Removes a property with given id - * from all the items in the container. - * - * This functionality is optional. If the function is unsupported, it always - * returns false. - * - * @return True if the operation succeeded. - * @see com.vaadin.data.Container#removeContainerProperty(java.lang.Object) - */ - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - - final boolean retval = items.removeContainerProperty(propertyId); - if (retval && !(items instanceof Container.PropertySetChangeNotifier)) { - firePropertySetChange(); - } - return retval; - } - - /* Container.Viewer methods */ - - /** - * Sets the Container that serves as the data source of the viewer. - * - * As a side-effect the fields value (selection) is set to null due old - * selection not necessary exists in new Container. - * - * @see com.vaadin.data.Container.Viewer#setContainerDataSource(Container) - * - * @param newDataSource - * the new data source. - */ - @Override - public void setContainerDataSource(Container newDataSource) { - if (newDataSource == null) { - newDataSource = new IndexedContainer(); - } - - getCaptionChangeListener().clear(); - - if (items != newDataSource) { - - // Removes listeners from the old datasource - if (items != null) { - if (items instanceof Container.ItemSetChangeNotifier) { - ((Container.ItemSetChangeNotifier) items) - .removeListener(this); - } - if (items instanceof Container.PropertySetChangeNotifier) { - ((Container.PropertySetChangeNotifier) items) - .removeListener(this); - } - } - - // Assigns new data source - items = newDataSource; - - // Clears itemIdMapper also - itemIdMapper.removeAll(); - - // Adds listeners - if (items != null) { - if (items instanceof Container.ItemSetChangeNotifier) { - ((Container.ItemSetChangeNotifier) items).addListener(this); - } - if (items instanceof Container.PropertySetChangeNotifier) { - ((Container.PropertySetChangeNotifier) items) - .addListener(this); - } - } - - /* - * We expect changing the data source should also clean value. See - * #810, #4607, #5281 - */ - setValue(null); - - requestRepaint(); - - } - } - - /** - * Gets the viewing data-source container. - * - * @see com.vaadin.data.Container.Viewer#getContainerDataSource() - */ - @Override - public Container getContainerDataSource() { - return items; - } - - /* Select attributes */ - - /** - * Is the select in multiselect mode? In multiselect mode - * - * @return the Value of property multiSelect. - */ - public boolean isMultiSelect() { - return multiSelect; - } - - /** - * Sets the multiselect mode. Setting multiselect mode false may lose - * selection information: if selected items set contains one or more - * selected items, only one of the selected items is kept as selected. - * - * Subclasses of AbstractSelect can choose not to support changing the - * multiselect mode, and may throw {@link UnsupportedOperationException}. - * - * @param multiSelect - * the New value of property multiSelect. - */ - public void setMultiSelect(boolean multiSelect) { - if (multiSelect && getNullSelectionItemId() != null) { - throw new IllegalStateException( - "Multiselect and NullSelectionItemId can not be set at the same time."); - } - if (multiSelect != this.multiSelect) { - - // Selection before mode change - final Object oldValue = getValue(); - - this.multiSelect = multiSelect; - - // Convert the value type - if (multiSelect) { - final Set<Object> s = new HashSet<Object>(); - if (oldValue != null) { - s.add(oldValue); - } - setValue(s); - } else { - final Set<?> s = (Set<?>) oldValue; - if (s == null || s.isEmpty()) { - setValue(null); - } else { - // Set the single select to contain only the first - // selected value in the multiselect - setValue(s.iterator().next()); - } - } - - requestRepaint(); - } - } - - /** - * Does the select allow adding new options by the user. If true, the new - * options can be added to the Container. The text entered by the user is - * used as id. Note that data-source must allow adding new items. - * - * @return True if additions are allowed. - */ - public boolean isNewItemsAllowed() { - - return allowNewOptions; - } - - /** - * Enables or disables possibility to add new options by the user. - * - * @param allowNewOptions - * the New value of property allowNewOptions. - */ - public void setNewItemsAllowed(boolean allowNewOptions) { - - // Only handle change requests - if (this.allowNewOptions != allowNewOptions) { - - this.allowNewOptions = allowNewOptions; - - requestRepaint(); - } - } - - /** - * Override the caption of an item. Setting caption explicitly overrides id, - * item and index captions. - * - * @param itemId - * the id of the item to be recaptioned. - * @param caption - * the New caption. - */ - public void setItemCaption(Object itemId, String caption) { - if (itemId != null) { - itemCaptions.put(itemId, caption); - requestRepaint(); - } - } - - /** - * Gets the caption of an item. The caption is generated as specified by the - * item caption mode. See <code>setItemCaptionMode()</code> for more - * details. - * - * @param itemId - * the id of the item to be queried. - * @return the caption for specified item. - */ - public String getItemCaption(Object itemId) { - - // Null items can not be found - if (itemId == null) { - return null; - } - - String caption = null; - - switch (getItemCaptionMode()) { - - case ID: - caption = itemId.toString(); - break; - - case INDEX: - if (items instanceof Container.Indexed) { - caption = String.valueOf(((Container.Indexed) items) - .indexOfId(itemId)); - } else { - caption = "ERROR: Container is not indexed"; - } - break; - - case ITEM: - final Item i = getItem(itemId); - if (i != null) { - caption = i.toString(); - } - break; - - case EXPLICIT: - caption = itemCaptions.get(itemId); - break; - - case EXPLICIT_DEFAULTS_ID: - caption = itemCaptions.get(itemId); - if (caption == null) { - caption = itemId.toString(); - } - break; - - case PROPERTY: - final Property<?> p = getContainerProperty(itemId, - getItemCaptionPropertyId()); - if (p != null) { - Object value = p.getValue(); - if (value != null) { - caption = value.toString(); - } - } - break; - } - - // All items must have some captions - return caption != null ? caption : ""; - } - - /** - * Sets tqhe icon for an item. - * - * @param itemId - * the id of the item to be assigned an icon. - * @param icon - * the icon to use or null. - */ - public void setItemIcon(Object itemId, Resource icon) { - if (itemId != null) { - if (icon == null) { - itemIcons.remove(itemId); - } else { - itemIcons.put(itemId, icon); - } - requestRepaint(); - } - } - - /** - * Gets the item icon. - * - * @param itemId - * the id of the item to be assigned an icon. - * @return the icon for the item or null, if not specified. - */ - public Resource getItemIcon(Object itemId) { - final Resource explicit = itemIcons.get(itemId); - if (explicit != null) { - return explicit; - } - - if (getItemIconPropertyId() == null) { - return null; - } - - final Property<?> ip = getContainerProperty(itemId, - getItemIconPropertyId()); - if (ip == null) { - return null; - } - final Object icon = ip.getValue(); - if (icon instanceof Resource) { - return (Resource) icon; - } - - return null; - } - - /** - * Sets the item caption mode. - * - * <p> - * The mode can be one of the following ones: - * <ul> - * <li><code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> : Items - * Id-objects <code>toString</code> is used as item caption. If caption is - * explicitly specified, it overrides the id-caption. - * <li><code>ITEM_CAPTION_MODE_ID</code> : Items Id-objects - * <code>toString</code> is used as item caption.</li> - * <li><code>ITEM_CAPTION_MODE_ITEM</code> : Item-objects - * <code>toString</code> is used as item caption.</li> - * <li><code>ITEM_CAPTION_MODE_INDEX</code> : The index of the item is used - * as item caption. The index mode can only be used with the containers - * implementing <code>Container.Indexed</code> interface.</li> - * <li><code>ITEM_CAPTION_MODE_EXPLICIT</code> : The item captions must be - * explicitly specified.</li> - * <li><code>ITEM_CAPTION_MODE_PROPERTY</code> : The item captions are read - * from property, that must be specified with - * <code>setItemCaptionPropertyId</code>.</li> - * </ul> - * The <code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> is the default - * mode. - * </p> - * - * @param mode - * the One of the modes listed above. - */ - public void setItemCaptionMode(ItemCaptionMode mode) { - if (mode != null) { - itemCaptionMode = mode; - requestRepaint(); - } - } - - /** - * Gets the item caption mode. - * - * <p> - * The mode can be one of the following ones: - * <ul> - * <li><code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> : Items - * Id-objects <code>toString</code> is used as item caption. If caption is - * explicitly specified, it overrides the id-caption. - * <li><code>ITEM_CAPTION_MODE_ID</code> : Items Id-objects - * <code>toString</code> is used as item caption.</li> - * <li><code>ITEM_CAPTION_MODE_ITEM</code> : Item-objects - * <code>toString</code> is used as item caption.</li> - * <li><code>ITEM_CAPTION_MODE_INDEX</code> : The index of the item is used - * as item caption. The index mode can only be used with the containers - * implementing <code>Container.Indexed</code> interface.</li> - * <li><code>ITEM_CAPTION_MODE_EXPLICIT</code> : The item captions must be - * explicitly specified.</li> - * <li><code>ITEM_CAPTION_MODE_PROPERTY</code> : The item captions are read - * from property, that must be specified with - * <code>setItemCaptionPropertyId</code>.</li> - * </ul> - * The <code>ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID</code> is the default - * mode. - * </p> - * - * @return the One of the modes listed above. - */ - public ItemCaptionMode getItemCaptionMode() { - return itemCaptionMode; - } - - /** - * Sets the item caption property. - * - * <p> - * Setting the id to a existing property implicitly sets the item caption - * mode to <code>ITEM_CAPTION_MODE_PROPERTY</code>. If the object is in - * <code>ITEM_CAPTION_MODE_PROPERTY</code> mode, setting caption property id - * null resets the item caption mode to - * <code>ITEM_CAPTION_EXPLICIT_DEFAULTS_ID</code>. - * </p> - * <p> - * Note that the type of the property used for caption must be String - * </p> - * <p> - * Setting the property id to null disables this feature. The id is null by - * default - * </p> - * . - * - * @param propertyId - * the id of the property. - * - */ - public void setItemCaptionPropertyId(Object propertyId) { - if (propertyId != null) { - itemCaptionPropertyId = propertyId; - setItemCaptionMode(ITEM_CAPTION_MODE_PROPERTY); - requestRepaint(); - } else { - itemCaptionPropertyId = null; - if (getItemCaptionMode() == ITEM_CAPTION_MODE_PROPERTY) { - setItemCaptionMode(ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID); - } - requestRepaint(); - } - } - - /** - * Gets the item caption property. - * - * @return the Id of the property used as item caption source. - */ - public Object getItemCaptionPropertyId() { - return itemCaptionPropertyId; - } - - /** - * Sets the item icon property. - * - * <p> - * If the property id is set to a valid value, each item is given an icon - * got from the given property of the items. The type of the property must - * be assignable to Resource. - * </p> - * - * <p> - * Note : The icons set with <code>setItemIcon</code> function override the - * icons from the property. - * </p> - * - * <p> - * Setting the property id to null disables this feature. The id is null by - * default - * </p> - * . - * - * @param propertyId - * the id of the property that specifies icons for items or null - * @throws IllegalArgumentException - * If the propertyId is not in the container or is not of a - * valid type - */ - public void setItemIconPropertyId(Object propertyId) - throws IllegalArgumentException { - if (propertyId == null) { - itemIconPropertyId = null; - } else if (!getContainerPropertyIds().contains(propertyId)) { - throw new IllegalArgumentException( - "Property id not found in the container"); - } else if (Resource.class.isAssignableFrom(getType(propertyId))) { - itemIconPropertyId = propertyId; - } else { - throw new IllegalArgumentException( - "Property type must be assignable to Resource"); - } - requestRepaint(); - } - - /** - * Gets the item icon property. - * - * <p> - * If the property id is set to a valid value, each item is given an icon - * got from the given property of the items. The type of the property must - * be assignable to Icon. - * </p> - * - * <p> - * Note : The icons set with <code>setItemIcon</code> function override the - * icons from the property. - * </p> - * - * <p> - * Setting the property id to null disables this feature. The id is null by - * default - * </p> - * . - * - * @return the Id of the property containing the item icons. - */ - public Object getItemIconPropertyId() { - return itemIconPropertyId; - } - - /** - * Tests if an item is selected. - * - * <p> - * In single select mode testing selection status of the item identified by - * {@link #getNullSelectionItemId()} returns true if the value of the - * property is null. - * </p> - * - * @param itemId - * the Id the of the item to be tested. - * @see #getNullSelectionItemId() - * @see #setNullSelectionItemId(Object) - * - */ - public boolean isSelected(Object itemId) { - if (itemId == null) { - return false; - } - if (isMultiSelect()) { - return ((Set<?>) getValue()).contains(itemId); - } else { - final Object value = getValue(); - return itemId.equals(value == null ? getNullSelectionItemId() - : value); - } - } - - /** - * Selects an item. - * - * <p> - * In single select mode selecting item identified by - * {@link #getNullSelectionItemId()} sets the value of the property to null. - * </p> - * - * @param itemId - * the identifier of Item to be selected. - * @see #getNullSelectionItemId() - * @see #setNullSelectionItemId(Object) - * - */ - public void select(Object itemId) { - if (!isMultiSelect()) { - setValue(itemId); - } else if (!isSelected(itemId) && itemId != null - && items.containsId(itemId)) { - final Set<Object> s = new HashSet<Object>((Set<?>) getValue()); - s.add(itemId); - setValue(s); - } - } - - /** - * Unselects an item. - * - * @param itemId - * the identifier of the Item to be unselected. - * @see #getNullSelectionItemId() - * @see #setNullSelectionItemId(Object) - * - */ - public void unselect(Object itemId) { - if (isSelected(itemId)) { - if (isMultiSelect()) { - final Set<Object> s = new HashSet<Object>((Set<?>) getValue()); - s.remove(itemId); - setValue(s); - } else { - setValue(null); - } - } - } - - /** - * Notifies this listener that the Containers contents has changed. - * - * @see com.vaadin.data.Container.PropertySetChangeListener#containerPropertySetChange(com.vaadin.data.Container.PropertySetChangeEvent) - */ - @Override - public void containerPropertySetChange( - Container.PropertySetChangeEvent event) { - firePropertySetChange(); - } - - /** - * Adds a new Property set change listener for this Container. - * - * @see com.vaadin.data.Container.PropertySetChangeNotifier#addListener(com.vaadin.data.Container.PropertySetChangeListener) - */ - @Override - public void addListener(Container.PropertySetChangeListener listener) { - if (propertySetEventListeners == null) { - propertySetEventListeners = new LinkedHashSet<Container.PropertySetChangeListener>(); - } - propertySetEventListeners.add(listener); - } - - /** - * Removes a previously registered Property set change listener. - * - * @see com.vaadin.data.Container.PropertySetChangeNotifier#removeListener(com.vaadin.data.Container.PropertySetChangeListener) - */ - @Override - public void removeListener(Container.PropertySetChangeListener listener) { - if (propertySetEventListeners != null) { - propertySetEventListeners.remove(listener); - if (propertySetEventListeners.isEmpty()) { - propertySetEventListeners = null; - } - } - } - - /** - * Adds an Item set change listener for the object. - * - * @see com.vaadin.data.Container.ItemSetChangeNotifier#addListener(com.vaadin.data.Container.ItemSetChangeListener) - */ - @Override - public void addListener(Container.ItemSetChangeListener listener) { - if (itemSetEventListeners == null) { - itemSetEventListeners = new LinkedHashSet<Container.ItemSetChangeListener>(); - } - itemSetEventListeners.add(listener); - } - - /** - * Removes the Item set change listener from the object. - * - * @see com.vaadin.data.Container.ItemSetChangeNotifier#removeListener(com.vaadin.data.Container.ItemSetChangeListener) - */ - @Override - public void removeListener(Container.ItemSetChangeListener listener) { - if (itemSetEventListeners != null) { - itemSetEventListeners.remove(listener); - if (itemSetEventListeners.isEmpty()) { - itemSetEventListeners = null; - } - } - } - - @Override - public Collection<?> getListeners(Class<?> eventType) { - if (Container.ItemSetChangeEvent.class.isAssignableFrom(eventType)) { - if (itemSetEventListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(itemSetEventListeners); - } - } else if (Container.PropertySetChangeEvent.class - .isAssignableFrom(eventType)) { - if (propertySetEventListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections - .unmodifiableCollection(propertySetEventListeners); - } - } - - return super.getListeners(eventType); - } - - /** - * Lets the listener know a Containers Item set has changed. - * - * @see com.vaadin.data.Container.ItemSetChangeListener#containerItemSetChange(com.vaadin.data.Container.ItemSetChangeEvent) - */ - @Override - public void containerItemSetChange(Container.ItemSetChangeEvent event) { - // Clears the item id mapping table - itemIdMapper.removeAll(); - - // Notify all listeners - fireItemSetChange(); - } - - /** - * Fires the property set change event. - */ - protected void firePropertySetChange() { - if (propertySetEventListeners != null - && !propertySetEventListeners.isEmpty()) { - final Container.PropertySetChangeEvent event = new PropertySetChangeEvent(); - final Object[] listeners = propertySetEventListeners.toArray(); - for (int i = 0; i < listeners.length; i++) { - ((Container.PropertySetChangeListener) listeners[i]) - .containerPropertySetChange(event); - } - } - requestRepaint(); - } - - /** - * Fires the item set change event. - */ - protected void fireItemSetChange() { - if (itemSetEventListeners != null && !itemSetEventListeners.isEmpty()) { - final Container.ItemSetChangeEvent event = new ItemSetChangeEvent(); - final Object[] listeners = itemSetEventListeners.toArray(); - for (int i = 0; i < listeners.length; i++) { - ((Container.ItemSetChangeListener) listeners[i]) - .containerItemSetChange(event); - } - } - requestRepaint(); - } - - /** - * Implementation of item set change event. - */ - private class ItemSetChangeEvent implements Serializable, - Container.ItemSetChangeEvent { - - /** - * Gets the Property where the event occurred. - * - * @see com.vaadin.data.Container.ItemSetChangeEvent#getContainer() - */ - @Override - public Container getContainer() { - return AbstractSelect.this; - } - - } - - /** - * Implementation of property set change event. - */ - private class PropertySetChangeEvent implements - Container.PropertySetChangeEvent, Serializable { - - /** - * Retrieves the Container whose contents have been modified. - * - * @see com.vaadin.data.Container.PropertySetChangeEvent#getContainer() - */ - @Override - public Container getContainer() { - return AbstractSelect.this; - } - - } - - /** - * For multi-selectable fields, also an empty collection of values is - * considered to be an empty field. - * - * @see AbstractField#isEmpty(). - */ - @Override - protected boolean isEmpty() { - if (!multiSelect) { - return super.isEmpty(); - } else { - Object value = getValue(); - return super.isEmpty() - || (value instanceof Collection && ((Collection<?>) value) - .isEmpty()); - } - } - - /** - * Allow or disallow empty selection by the user. If the select is in - * single-select mode, you can make an item represent the empty selection by - * calling <code>setNullSelectionItemId()</code>. This way you can for - * instance set an icon and caption for the null selection item. - * - * @param nullSelectionAllowed - * whether or not to allow empty selection - * @see #setNullSelectionItemId(Object) - * @see #isNullSelectionAllowed() - */ - public void setNullSelectionAllowed(boolean nullSelectionAllowed) { - if (nullSelectionAllowed != this.nullSelectionAllowed) { - this.nullSelectionAllowed = nullSelectionAllowed; - requestRepaint(); - } - } - - /** - * Checks if null empty selection is allowed by the user. - * - * @return whether or not empty selection is allowed - * @see #setNullSelectionAllowed(boolean) - */ - public boolean isNullSelectionAllowed() { - return nullSelectionAllowed; - } - - /** - * Returns the item id that represents null value of this select in single - * select mode. - * - * <p> - * Data interface does not support nulls as item ids. Selecting the item - * identified by this id is the same as selecting no items at all. This - * setting only affects the single select mode. - * </p> - * - * @return the Object Null value item id. - * @see #setNullSelectionItemId(Object) - * @see #isSelected(Object) - * @see #select(Object) - */ - public Object getNullSelectionItemId() { - return nullSelectionItemId; - } - - /** - * Sets the item id that represents null value of this select. - * - * <p> - * Data interface does not support nulls as item ids. Selecting the item - * identified by this id is the same as selecting no items at all. This - * setting only affects the single select mode. - * </p> - * - * @param nullSelectionItemId - * the nullSelectionItemId to set. - * @see #getNullSelectionItemId() - * @see #isSelected(Object) - * @see #select(Object) - */ - public void setNullSelectionItemId(Object nullSelectionItemId) { - if (nullSelectionItemId != null && isMultiSelect()) { - throw new IllegalStateException( - "Multiselect and NullSelectionItemId can not be set at the same time."); - } - this.nullSelectionItemId = nullSelectionItemId; - } - - /** - * Notifies the component that it is connected to an application. - * - * @see com.vaadin.ui.AbstractField#attach() - */ - @Override - public void attach() { - super.attach(); - } - - /** - * Detaches the component from application. - * - * @see com.vaadin.ui.AbstractComponent#detach() - */ - @Override - public void detach() { - getCaptionChangeListener().clear(); - super.detach(); - } - - // Caption change listener - protected CaptionChangeListener getCaptionChangeListener() { - if (captionChangeListener == null) { - captionChangeListener = new CaptionChangeListener(); - } - return captionChangeListener; - } - - /** - * This is a listener helper for Item and Property changes that should cause - * a repaint. It should be attached to all items that are displayed, and the - * default implementation does this in paintContent(). Especially - * "lazyloading" components should take care to add and remove listeners as - * appropriate. Call addNotifierForItem() for each painted item (and - * remember to clear). - * - * NOTE: singleton, use getCaptionChangeListener(). - * - */ - protected class CaptionChangeListener implements - Item.PropertySetChangeListener, Property.ValueChangeListener { - - // TODO clean this up - type is either Item.PropertySetChangeNotifier or - // Property.ValueChangeNotifier - HashSet<Object> captionChangeNotifiers = new HashSet<Object>(); - - public void addNotifierForItem(Object itemId) { - switch (getItemCaptionMode()) { - case ITEM: - final Item i = getItem(itemId); - if (i == null) { - return; - } - if (i instanceof Item.PropertySetChangeNotifier) { - ((Item.PropertySetChangeNotifier) i) - .addListener(getCaptionChangeListener()); - captionChangeNotifiers.add(i); - } - Collection<?> pids = i.getItemPropertyIds(); - if (pids != null) { - for (Iterator<?> it = pids.iterator(); it.hasNext();) { - Property<?> p = i.getItemProperty(it.next()); - if (p != null - && p instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) p) - .addListener(getCaptionChangeListener()); - captionChangeNotifiers.add(p); - } - } - - } - break; - case PROPERTY: - final Property<?> p = getContainerProperty(itemId, - getItemCaptionPropertyId()); - if (p != null && p instanceof Property.ValueChangeNotifier) { - ((Property.ValueChangeNotifier) p) - .addListener(getCaptionChangeListener()); - captionChangeNotifiers.add(p); - } - break; - - } - } - - public void clear() { - for (Iterator<Object> it = captionChangeNotifiers.iterator(); it - .hasNext();) { - Object notifier = it.next(); - if (notifier instanceof Item.PropertySetChangeNotifier) { - ((Item.PropertySetChangeNotifier) notifier) - .removeListener(getCaptionChangeListener()); - } else { - ((Property.ValueChangeNotifier) notifier) - .removeListener(getCaptionChangeListener()); - } - } - captionChangeNotifiers.clear(); - } - - @Override - public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) { - requestRepaint(); - } - - @Override - public void itemPropertySetChange( - com.vaadin.data.Item.PropertySetChangeEvent event) { - requestRepaint(); - } - - } - - /** - * Criterion which accepts a drop only if the drop target is (one of) the - * given Item identifier(s). Criterion can be used only on a drop targets - * that extends AbstractSelect like {@link Table} and {@link Tree}. The - * target and identifiers of valid Items are given in constructor. - * - * @since 6.3 - */ - public static class TargetItemIs extends AbstractItemSetCriterion { - - /** - * @param select - * the select implementation that is used as a drop target - * @param itemId - * the identifier(s) that are valid drop locations - */ - public TargetItemIs(AbstractSelect select, Object... itemId) { - super(select, itemId); - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dragEvent - .getTargetDetails(); - if (dropTargetData.getTarget() != select) { - return false; - } - return itemIds.contains(dropTargetData.getItemIdOver()); - } - - } - - /** - * Abstract helper class to implement item id based criterion. - * - * Note, inner class used not to open itemIdMapper for public access. - * - * @since 6.3 - * - */ - private static abstract class AbstractItemSetCriterion extends - ClientSideCriterion { - protected final Collection<Object> itemIds = new HashSet<Object>(); - protected AbstractSelect select; - - public AbstractItemSetCriterion(AbstractSelect select, Object... itemId) { - if (itemIds == null || select == null) { - throw new IllegalArgumentException( - "Accepted item identifiers must be accepted."); - } - Collections.addAll(itemIds, itemId); - this.select = select; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - String[] keys = new String[itemIds.size()]; - int i = 0; - for (Object itemId : itemIds) { - String key = select.itemIdMapper.key(itemId); - keys[i++] = key; - } - target.addAttribute("keys", keys); - target.addAttribute("s", select); - } - - } - - /** - * This criterion accepts a only a {@link Transferable} that contains given - * Item (practically its identifier) from a specific AbstractSelect. - * - * @since 6.3 - */ - public static class AcceptItem extends AbstractItemSetCriterion { - - /** - * @param select - * the select from which the item id's are checked - * @param itemId - * the item identifier(s) of the select that are accepted - */ - public AcceptItem(AbstractSelect select, Object... itemId) { - super(select, itemId); - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - DataBoundTransferable transferable = (DataBoundTransferable) dragEvent - .getTransferable(); - if (transferable.getSourceComponent() != select) { - return false; - } - return itemIds.contains(transferable.getItemId()); - } - - /** - * A simple accept criterion which ensures that {@link Transferable} - * contains an {@link Item} (or actually its identifier). In other words - * the criterion check that drag is coming from a {@link Container} like - * {@link Tree} or {@link Table}. - */ - public static final ClientSideCriterion ALL = new ContainsDataFlavor( - "itemId"); - - } - - /** - * TargetDetails implementation for subclasses of {@link AbstractSelect} - * that implement {@link DropTarget}. - * - * @since 6.3 - */ - public class AbstractSelectTargetDetails extends TargetDetailsImpl { - - /** - * The item id over which the drag event happened. - */ - protected Object idOver; - - /** - * Constructor that automatically converts itemIdOver key to - * corresponding item Id - * - */ - protected AbstractSelectTargetDetails(Map<String, Object> rawVariables) { - super(rawVariables, (DropTarget) AbstractSelect.this); - // eagar fetch itemid, mapper may be emptied - String keyover = (String) getData("itemIdOver"); - if (keyover != null) { - idOver = itemIdMapper.get(keyover); - } - } - - /** - * If the drag operation is currently over an {@link Item}, this method - * returns the identifier of that {@link Item}. - * - */ - public Object getItemIdOver() { - return idOver; - } - - /** - * Returns a detailed vertical location where the drop happened on Item. - */ - public VerticalDropLocation getDropLocation() { - String detail = (String) getData("detail"); - if (detail == null) { - return null; - } - return VerticalDropLocation.valueOf(detail); - } - - } - - /** - * An accept criterion to accept drops only on a specific vertical location - * of an item. - * <p> - * This accept criterion is currently usable in Tree and Table - * implementations. - */ - public static class VerticalLocationIs extends TargetDetailIs { - public static VerticalLocationIs TOP = new VerticalLocationIs( - VerticalDropLocation.TOP); - public static VerticalLocationIs BOTTOM = new VerticalLocationIs( - VerticalDropLocation.BOTTOM); - public static VerticalLocationIs MIDDLE = new VerticalLocationIs( - VerticalDropLocation.MIDDLE); - - private VerticalLocationIs(VerticalDropLocation l) { - super("detail", l.name()); - } - } - - /** - * Implement this interface and pass it to Tree.setItemDescriptionGenerator - * or Table.setItemDescriptionGenerator to generate mouse over descriptions - * ("tooltips") for the rows and cells in Table or for the items in Tree. - */ - public interface ItemDescriptionGenerator extends Serializable { - - /** - * Called by Table when a cell (and row) is painted or a item is painted - * in Tree - * - * @param source - * The source of the generator, the Tree or Table the - * generator is attached to - * @param itemId - * The itemId of the painted cell - * @param propertyId - * The propertyId of the cell, null when getting row - * description - * @return The description or "tooltip" of the item. - */ - public String generateDescription(Component source, Object itemId, - Object propertyId); - } -} diff --git a/src/com/vaadin/ui/AbstractSplitPanel.java b/src/com/vaadin/ui/AbstractSplitPanel.java deleted file mode 100644 index 90dc38ff65..0000000000 --- a/src/com/vaadin/ui/AbstractSplitPanel.java +++ /dev/null @@ -1,521 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Iterator; - -import com.vaadin.event.ComponentEventListener; -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelRpc; -import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelState; -import com.vaadin.shared.ui.splitpanel.AbstractSplitPanelState.SplitterState; -import com.vaadin.terminal.Sizeable; -import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; -import com.vaadin.tools.ReflectTools; - -/** - * AbstractSplitPanel. - * - * <code>AbstractSplitPanel</code> is base class for a component container that - * can contain two components. The components are split by a divider element. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.5 - */ -public abstract class AbstractSplitPanel extends AbstractComponentContainer { - - // TODO use Unit in AbstractSplitPanelState and remove these - private Unit posUnit; - private Unit posMinUnit; - private Unit posMaxUnit; - - private AbstractSplitPanelRpc rpc = new AbstractSplitPanelRpc() { - - @Override - public void splitterClick(MouseEventDetails mouseDetails) { - fireEvent(new SplitterClickEvent(AbstractSplitPanel.this, - mouseDetails)); - } - - @Override - public void setSplitterPosition(float position) { - getSplitterState().setPosition(position); - } - }; - - public AbstractSplitPanel() { - registerRpc(rpc); - setSplitPosition(50, Unit.PERCENTAGE, false); - setSplitPositionLimits(0, Unit.PERCENTAGE, 100, Unit.PERCENTAGE); - } - - /** - * Modifiable and Serializable Iterator for the components, used by - * {@link AbstractSplitPanel#getComponentIterator()}. - */ - private class ComponentIterator implements Iterator<Component>, - Serializable { - - int i = 0; - - @Override - public boolean hasNext() { - if (i < getComponentCount()) { - return true; - } - return false; - } - - @Override - public Component next() { - if (!hasNext()) { - return null; - } - i++; - if (i == 1) { - return (getFirstComponent() == null ? getSecondComponent() - : getFirstComponent()); - } else if (i == 2) { - return getSecondComponent(); - } - return null; - } - - @Override - public void remove() { - if (i == 1) { - if (getFirstComponent() != null) { - setFirstComponent(null); - i = 0; - } else { - setSecondComponent(null); - } - } else if (i == 2) { - setSecondComponent(null); - } - } - } - - /** - * Add a component into this container. The component is added to the right - * or under the previous component. - * - * @param c - * the component to be added. - */ - - @Override - public void addComponent(Component c) { - if (getFirstComponent() == null) { - setFirstComponent(c); - } else if (getSecondComponent() == null) { - setSecondComponent(c); - } else { - throw new UnsupportedOperationException( - "Split panel can contain only two components"); - } - } - - /** - * Sets the first component of this split panel. Depending on the direction - * the first component is shown at the top or to the left. - * - * @param c - * The component to use as first component - */ - public void setFirstComponent(Component c) { - if (getFirstComponent() == c) { - // Nothing to do - return; - } - - if (getFirstComponent() != null) { - // detach old - removeComponent(getFirstComponent()); - } - getState().setFirstChild(c); - if (c != null) { - super.addComponent(c); - } - - requestRepaint(); - } - - /** - * Sets the second component of this split panel. Depending on the direction - * the second component is shown at the bottom or to the left. - * - * @param c - * The component to use as first component - */ - public void setSecondComponent(Component c) { - if (getSecondComponent() == c) { - // Nothing to do - return; - } - - if (getSecondComponent() != null) { - // detach old - removeComponent(getSecondComponent()); - } - getState().setSecondChild(c); - if (c != null) { - super.addComponent(c); - } - requestRepaint(); - } - - /** - * Gets the first component of this split panel. Depending on the direction - * this is either the component shown at the top or to the left. - * - * @return the first component of this split panel - */ - public Component getFirstComponent() { - return (Component) getState().getFirstChild(); - } - - /** - * Gets the second component of this split panel. Depending on the direction - * this is either the component shown at the top or to the left. - * - * @return the second component of this split panel - */ - public Component getSecondComponent() { - return (Component) getState().getSecondChild(); - } - - /** - * Removes the component from this container. - * - * @param c - * the component to be removed. - */ - - @Override - public void removeComponent(Component c) { - super.removeComponent(c); - if (c == getFirstComponent()) { - getState().setFirstChild(null); - } else if (c == getSecondComponent()) { - getState().setSecondChild(null); - } - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.ComponentContainer#getComponentIterator() - */ - - @Override - public Iterator<Component> getComponentIterator() { - return new ComponentIterator(); - } - - /** - * Gets the number of contained components. Consistent with the iterator - * returned by {@link #getComponentIterator()}. - * - * @return the number of contained components (zero, one or two) - */ - - @Override - public int getComponentCount() { - int count = 0; - if (getFirstComponent() != null) { - count++; - } - if (getSecondComponent() != null) { - count++; - } - return count; - } - - /* Documented in superclass */ - - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - if (oldComponent == getFirstComponent()) { - setFirstComponent(newComponent); - } else if (oldComponent == getSecondComponent()) { - setSecondComponent(newComponent); - } - requestRepaint(); - } - - /** - * Moves the position of the splitter. - * - * @param pos - * the new size of the first region in the unit that was last - * used (default is percentage). Fractions are only allowed when - * unit is percentage. - */ - public void setSplitPosition(float pos) { - setSplitPosition(pos, posUnit, false); - } - - /** - * Moves the position of the splitter. - * - * @param pos - * the new size of the region in the unit that was last used - * (default is percentage). Fractions are only allowed when unit - * is percentage. - * - * @param reverse - * if set to true the split splitter position is measured by the - * second region else it is measured by the first region - */ - public void setSplitPosition(float pos, boolean reverse) { - setSplitPosition(pos, posUnit, reverse); - } - - /** - * Moves the position of the splitter with given position and unit. - * - * @param pos - * the new size of the first region. Fractions are only allowed - * when unit is percentage. - * @param unit - * the unit (from {@link Sizeable}) in which the size is given. - */ - public void setSplitPosition(float pos, Unit unit) { - setSplitPosition(pos, unit, false); - } - - /** - * Moves the position of the splitter with given position and unit. - * - * @param pos - * the new size of the first region. Fractions are only allowed - * when unit is percentage. - * @param unit - * the unit (from {@link Sizeable}) in which the size is given. - * @param reverse - * if set to true the split splitter position is measured by the - * second region else it is measured by the first region - * - */ - public void setSplitPosition(float pos, Unit unit, boolean reverse) { - if (unit != Unit.PERCENTAGE && unit != Unit.PIXELS) { - throw new IllegalArgumentException( - "Only percentage and pixel units are allowed"); - } - if (unit != Unit.PERCENTAGE) { - pos = Math.round(pos); - } - SplitterState splitterState = getSplitterState(); - splitterState.setPosition(pos); - splitterState.setPositionUnit(unit.getSymbol()); - splitterState.setPositionReversed(reverse); - posUnit = unit; - - requestRepaint(); - } - - /** - * Returns the current position of the splitter, in - * {@link #getSplitPositionUnit()} units. - * - * @return position of the splitter - */ - public float getSplitPosition() { - return getSplitterState().getPosition(); - } - - /** - * Returns the unit of position of the splitter - * - * @return unit of position of the splitter - */ - public Unit getSplitPositionUnit() { - return posUnit; - } - - /** - * Sets the minimum split position to the given position and unit. If the - * split position is reversed, maximum and minimum are also reversed. - * - * @param pos - * the minimum position of the split - * @param unit - * the unit (from {@link Sizeable}) in which the size is given. - * Allowed units are UNITS_PERCENTAGE and UNITS_PIXELS - */ - public void setMinSplitPosition(int pos, Unit unit) { - setSplitPositionLimits(pos, unit, getSplitterState().getMaxPosition(), - posMaxUnit); - } - - /** - * Returns the current minimum position of the splitter, in - * {@link #getMinSplitPositionUnit()} units. - * - * @return the minimum position of the splitter - */ - public float getMinSplitPosition() { - return getSplitterState().getMinPosition(); - } - - /** - * Returns the unit of the minimum position of the splitter. - * - * @return the unit of the minimum position of the splitter - */ - public Unit getMinSplitPositionUnit() { - return posMinUnit; - } - - /** - * Sets the maximum split position to the given position and unit. If the - * split position is reversed, maximum and minimum are also reversed. - * - * @param pos - * the maximum position of the split - * @param unit - * the unit (from {@link Sizeable}) in which the size is given. - * Allowed units are UNITS_PERCENTAGE and UNITS_PIXELS - */ - public void setMaxSplitPosition(float pos, Unit unit) { - setSplitPositionLimits(getSplitterState().getMinPosition(), posMinUnit, - pos, unit); - } - - /** - * Returns the current maximum position of the splitter, in - * {@link #getMaxSplitPositionUnit()} units. - * - * @return the maximum position of the splitter - */ - public float getMaxSplitPosition() { - return getSplitterState().getMaxPosition(); - } - - /** - * Returns the unit of the maximum position of the splitter - * - * @return the unit of the maximum position of the splitter - */ - public Unit getMaxSplitPositionUnit() { - return posMaxUnit; - } - - /** - * Sets the maximum and minimum position of the splitter. If the split - * position is reversed, maximum and minimum are also reversed. - * - * @param minPos - * the new minimum position - * @param minPosUnit - * the unit (from {@link Sizeable}) in which the minimum position - * is given. - * @param maxPos - * the new maximum position - * @param maxPosUnit - * the unit (from {@link Sizeable}) in which the maximum position - * is given. - */ - private void setSplitPositionLimits(float minPos, Unit minPosUnit, - float maxPos, Unit maxPosUnit) { - if ((minPosUnit != Unit.PERCENTAGE && minPosUnit != Unit.PIXELS) - || (maxPosUnit != Unit.PERCENTAGE && maxPosUnit != Unit.PIXELS)) { - throw new IllegalArgumentException( - "Only percentage and pixel units are allowed"); - } - - SplitterState state = getSplitterState(); - - state.setMinPosition(minPos); - state.setMinPositionUnit(minPosUnit.getSymbol()); - posMinUnit = minPosUnit; - - state.setMaxPosition(maxPos); - state.setMaxPositionUnit(maxPosUnit.getSymbol()); - posMaxUnit = maxPosUnit; - - requestRepaint(); - } - - /** - * Lock the SplitPanels position, disabling the user from dragging the split - * handle. - * - * @param locked - * Set <code>true</code> if locked, <code>false</code> otherwise. - */ - public void setLocked(boolean locked) { - getSplitterState().setLocked(locked); - requestRepaint(); - } - - /** - * Is the SplitPanel handle locked (user not allowed to change split - * position by dragging). - * - * @return <code>true</code> if locked, <code>false</code> otherwise. - */ - public boolean isLocked() { - return getSplitterState().isLocked(); - } - - /** - * <code>SplitterClickListener</code> interface for listening for - * <code>SplitterClickEvent</code> fired by a <code>SplitPanel</code>. - * - * @see SplitterClickEvent - * @since 6.2 - */ - public interface SplitterClickListener extends ComponentEventListener { - - public static final Method clickMethod = ReflectTools.findMethod( - SplitterClickListener.class, "splitterClick", - SplitterClickEvent.class); - - /** - * SplitPanel splitter has been clicked - * - * @param event - * SplitterClickEvent event. - */ - public void splitterClick(SplitterClickEvent event); - } - - public class SplitterClickEvent extends ClickEvent { - - public SplitterClickEvent(Component source, - MouseEventDetails mouseEventDetails) { - super(source, mouseEventDetails); - } - - } - - public void addListener(SplitterClickListener listener) { - addListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, - SplitterClickEvent.class, listener, - SplitterClickListener.clickMethod); - } - - public void removeListener(SplitterClickListener listener) { - removeListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, - SplitterClickEvent.class, listener); - } - - @Override - public AbstractSplitPanelState getState() { - return (AbstractSplitPanelState) super.getState(); - } - - private SplitterState getSplitterState() { - return getState().getSplitterState(); - } -} diff --git a/src/com/vaadin/ui/AbstractTextField.java b/src/com/vaadin/ui/AbstractTextField.java deleted file mode 100644 index 2326c07d97..0000000000 --- a/src/com/vaadin/ui/AbstractTextField.java +++ /dev/null @@ -1,674 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Map; - -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.BlurNotifier; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.event.FieldEvents.FocusNotifier; -import com.vaadin.event.FieldEvents.TextChangeEvent; -import com.vaadin.event.FieldEvents.TextChangeListener; -import com.vaadin.event.FieldEvents.TextChangeNotifier; -import com.vaadin.shared.ui.textfield.AbstractTextFieldState; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.textfield.VTextField; - -public abstract class AbstractTextField extends AbstractField<String> implements - BlurNotifier, FocusNotifier, TextChangeNotifier, Vaadin6Component { - - /** - * Null representation. - */ - private String nullRepresentation = "null"; - /** - * Is setting to null from non-null value allowed by setting with null - * representation . - */ - private boolean nullSettingAllowed = false; - /** - * The text content when the last messages to the server was sent. Cleared - * when value is changed. - */ - private String lastKnownTextContent; - - /** - * The position of the cursor when the last message to the server was sent. - */ - private int lastKnownCursorPosition; - - /** - * Flag indicating that a text change event is pending to be triggered. - * Cleared by {@link #setInternalValue(Object)} and when the event is fired. - */ - private boolean textChangeEventPending; - - private boolean isFiringTextChangeEvent = false; - - private TextChangeEventMode textChangeEventMode = TextChangeEventMode.LAZY; - - private final int DEFAULT_TEXTCHANGE_TIMEOUT = 400; - - private int textChangeEventTimeout = DEFAULT_TEXTCHANGE_TIMEOUT; - - /** - * Temporarily holds the new selection position. Cleared on paint. - */ - private int selectionPosition = -1; - - /** - * Temporarily holds the new selection length. - */ - private int selectionLength; - - /** - * Flag used to determine whether we are currently handling a state change - * triggered by a user. Used to properly fire text change event before value - * change event triggered by the client side. - */ - private boolean changingVariables; - - protected AbstractTextField() { - super(); - } - - @Override - public AbstractTextFieldState getState() { - return (AbstractTextFieldState) super.getState(); - } - - @Override - public void updateState() { - super.updateState(); - - String value = getValue(); - if (value == null) { - value = getNullRepresentation(); - } - getState().setText(value); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - - if (selectionPosition != -1) { - target.addAttribute("selpos", selectionPosition); - target.addAttribute("sellen", selectionLength); - selectionPosition = -1; - } - - if (hasListeners(TextChangeEvent.class)) { - target.addAttribute(VTextField.ATTR_TEXTCHANGE_EVENTMODE, - getTextChangeEventMode().toString()); - target.addAttribute(VTextField.ATTR_TEXTCHANGE_TIMEOUT, - getTextChangeTimeout()); - if (lastKnownTextContent != null) { - /* - * The field has be repainted for some reason (e.g. caption, - * size, stylename), but the value has not been changed since - * the last text change event. Let the client side know about - * the value the server side knows. Client side may then ignore - * the actual value, depending on its state. - */ - target.addAttribute( - VTextField.ATTR_NO_VALUE_CHANGE_BETWEEN_PAINTS, true); - } - } - - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - changingVariables = true; - - try { - - if (variables.containsKey(VTextField.VAR_CURSOR)) { - Integer object = (Integer) variables.get(VTextField.VAR_CURSOR); - lastKnownCursorPosition = object.intValue(); - } - - if (variables.containsKey(VTextField.VAR_CUR_TEXT)) { - /* - * NOTE, we might want to develop this further so that on a - * value change event the whole text content don't need to be - * sent from the client to server. Just "commit" the value from - * currentText to the value. - */ - handleInputEventTextChange(variables); - } - - // Sets the text - if (variables.containsKey("text") && !isReadOnly()) { - - // Only do the setting if the string representation of the value - // has been updated - String newValue = (String) variables.get("text"); - - // server side check for max length - if (getMaxLength() != -1 && newValue.length() > getMaxLength()) { - newValue = newValue.substring(0, getMaxLength()); - } - final String oldValue = getValue(); - if (newValue != null - && (oldValue == null || isNullSettingAllowed()) - && newValue.equals(getNullRepresentation())) { - newValue = null; - } - if (newValue != oldValue - && (newValue == null || !newValue.equals(oldValue))) { - boolean wasModified = isModified(); - setValue(newValue, true); - - // If the modified status changes, or if we have a - // formatter, repaint is needed after all. - if (wasModified != isModified()) { - requestRepaint(); - } - } - } - firePendingTextChangeEvent(); - - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } - if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } - } finally { - changingVariables = false; - - } - - } - - @Override - public Class<String> getType() { - return String.class; - } - - /** - * Gets the null-string representation. - * - * <p> - * The null-valued strings are represented on the user interface by - * replacing the null value with this string. If the null representation is - * set null (not 'null' string), painting null value throws exception. - * </p> - * - * <p> - * The default value is string 'null'. - * </p> - * - * @return the String Textual representation for null strings. - * @see TextField#isNullSettingAllowed() - */ - public String getNullRepresentation() { - return nullRepresentation; - } - - /** - * Is setting nulls with null-string representation allowed. - * - * <p> - * If this property is true, writing null-representation string to text - * field always sets the field value to real null. If this property is - * false, null setting is not made, but the null values are maintained. - * Maintenance of null-values is made by only converting the textfield - * contents to real null, if the text field matches the null-string - * representation and the current value of the field is null. - * </p> - * - * <p> - * By default this setting is false - * </p> - * - * @return boolean Should the null-string represenation be always converted - * to null-values. - * @see TextField#getNullRepresentation() - */ - public boolean isNullSettingAllowed() { - return nullSettingAllowed; - } - - /** - * Sets the null-string representation. - * - * <p> - * The null-valued strings are represented on the user interface by - * replacing the null value with this string. If the null representation is - * set null (not 'null' string), painting null value throws exception. - * </p> - * - * <p> - * The default value is string 'null' - * </p> - * - * @param nullRepresentation - * Textual representation for null strings. - * @see TextField#setNullSettingAllowed(boolean) - */ - public void setNullRepresentation(String nullRepresentation) { - this.nullRepresentation = nullRepresentation; - requestRepaint(); - } - - /** - * Sets the null conversion mode. - * - * <p> - * If this property is true, writing null-representation string to text - * field always sets the field value to real null. If this property is - * false, null setting is not made, but the null values are maintained. - * Maintenance of null-values is made by only converting the textfield - * contents to real null, if the text field matches the null-string - * representation and the current value of the field is null. - * </p> - * - * <p> - * By default this setting is false. - * </p> - * - * @param nullSettingAllowed - * Should the null-string representation always be converted to - * null-values. - * @see TextField#getNullRepresentation() - */ - public void setNullSettingAllowed(boolean nullSettingAllowed) { - this.nullSettingAllowed = nullSettingAllowed; - requestRepaint(); - } - - @Override - protected boolean isEmpty() { - return super.isEmpty() || getValue().length() == 0; - } - - /** - * Returns the maximum number of characters in the field. Value -1 is - * considered unlimited. Terminal may however have some technical limits. - * - * @return the maxLength - */ - public int getMaxLength() { - return getState().getMaxLength(); - } - - /** - * Sets the maximum number of characters in the field. Value -1 is - * considered unlimited. Terminal may however have some technical limits. - * - * @param maxLength - * the maxLength to set - */ - public void setMaxLength(int maxLength) { - getState().setMaxLength(maxLength); - requestRepaint(); - } - - /** - * Gets the number of columns in the editor. If the number of columns is set - * 0, the actual number of displayed columns is determined implicitly by the - * adapter. - * - * @return the number of columns in the editor. - */ - public int getColumns() { - return getState().getColumns(); - } - - /** - * Sets the number of columns in the editor. If the number of columns is set - * 0, the actual number of displayed columns is determined implicitly by the - * adapter. - * - * @param columns - * the number of columns to set. - */ - public void setColumns(int columns) { - if (columns < 0) { - columns = 0; - } - getState().setColumns(columns); - requestRepaint(); - } - - /** - * Gets the current input prompt. - * - * @see #setInputPrompt(String) - * @return the current input prompt, or null if not enabled - */ - public String getInputPrompt() { - return getState().getInputPrompt(); - } - - /** - * Sets the input prompt - a textual prompt that is displayed when the field - * would otherwise be empty, to prompt the user for input. - * - * @param inputPrompt - */ - public void setInputPrompt(String inputPrompt) { - getState().setInputPrompt(inputPrompt); - requestRepaint(); - } - - /* ** Text Change Events ** */ - - private void firePendingTextChangeEvent() { - if (textChangeEventPending && !isFiringTextChangeEvent) { - isFiringTextChangeEvent = true; - textChangeEventPending = false; - try { - fireEvent(new TextChangeEventImpl(this)); - } finally { - isFiringTextChangeEvent = false; - } - } - } - - @Override - protected void setInternalValue(String newValue) { - if (changingVariables && !textChangeEventPending) { - - /* - * TODO check for possible (minor?) issue (not tested) - * - * -field with e.g. PropertyFormatter. - * - * -TextChangeListener and it changes value. - * - * -if formatter again changes the value, do we get an extra - * simulated text change event ? - */ - - /* - * Fire a "simulated" text change event before value change event if - * change is coming from the client side. - * - * Iff there is both value change and textChangeEvent in same - * variable burst, it is a text field in non immediate mode and the - * text change event "flushed" queued value change event. In this - * case textChangeEventPending flag is already on and text change - * event will be fired after the value change event. - */ - if (newValue == null && lastKnownTextContent != null - && !lastKnownTextContent.equals(getNullRepresentation())) { - // Value was changed from something to null representation - lastKnownTextContent = getNullRepresentation(); - textChangeEventPending = true; - } else if (newValue != null - && !newValue.toString().equals(lastKnownTextContent)) { - // Value was changed to something else than null representation - lastKnownTextContent = newValue.toString(); - textChangeEventPending = true; - } - firePendingTextChangeEvent(); - } - - super.setInternalValue(newValue); - } - - @Override - public void setValue(Object newValue) throws ReadOnlyException { - super.setValue(newValue); - /* - * Make sure w reset lastKnownTextContent field on value change. The - * clearing must happen here as well because TextChangeListener can - * revert the original value. Client must respect the value in this - * case. AbstractField optimizes value change if the existing value is - * reset. Also we need to force repaint if the flag is on. - */ - if (lastKnownTextContent != null) { - lastKnownTextContent = null; - requestRepaint(); - } - } - - private void handleInputEventTextChange(Map<String, Object> variables) { - /* - * TODO we could vastly optimize the communication of values by using - * some sort of diffs instead of always sending the whole text content. - * Also on value change events we could use the mechanism. - */ - String object = (String) variables.get(VTextField.VAR_CUR_TEXT); - lastKnownTextContent = object; - textChangeEventPending = true; - } - - /** - * Sets the mode how the TextField triggers {@link TextChangeEvent}s. - * - * @param inputEventMode - * the new mode - * - * @see TextChangeEventMode - */ - public void setTextChangeEventMode(TextChangeEventMode inputEventMode) { - textChangeEventMode = inputEventMode; - requestRepaint(); - } - - /** - * @return the mode used to trigger {@link TextChangeEvent}s. - */ - public TextChangeEventMode getTextChangeEventMode() { - return textChangeEventMode; - } - - /** - * Different modes how the TextField can trigger {@link TextChangeEvent}s. - */ - public enum TextChangeEventMode { - - /** - * An event is triggered on each text content change, most commonly key - * press events. - */ - EAGER, - /** - * Each text change event in the UI causes the event to be communicated - * to the application after a timeout. The length of the timeout can be - * controlled with {@link TextField#setInputEventTimeout(int)}. Only the - * last input event is reported to the server side if several text - * change events happen during the timeout. - * <p> - * In case of a {@link ValueChangeEvent} the schedule is not kept - * strictly. Before a {@link ValueChangeEvent} a {@link TextChangeEvent} - * is triggered if the text content has changed since the previous - * TextChangeEvent regardless of the schedule. - */ - TIMEOUT, - /** - * An event is triggered when there is a pause of text modifications. - * The length of the pause can be modified with - * {@link TextField#setInputEventTimeout(int)}. Like with the - * {@link #TIMEOUT} mode, an event is forced before - * {@link ValueChangeEvent}s, even if the user did not keep a pause - * while entering the text. - * <p> - * This is the default mode. - */ - LAZY - } - - @Override - public void addListener(TextChangeListener listener) { - addListener(TextChangeListener.EVENT_ID, TextChangeEvent.class, - listener, TextChangeListener.EVENT_METHOD); - } - - @Override - public void removeListener(TextChangeListener listener) { - removeListener(TextChangeListener.EVENT_ID, TextChangeEvent.class, - listener); - } - - /** - * The text change timeout modifies how often text change events are - * communicated to the application when {@link #getTextChangeEventMode()} is - * {@link TextChangeEventMode#LAZY} or {@link TextChangeEventMode#TIMEOUT}. - * - * - * @see #getTextChangeEventMode() - * - * @param timeout - * the timeout in milliseconds - */ - public void setTextChangeTimeout(int timeout) { - textChangeEventTimeout = timeout; - requestRepaint(); - } - - /** - * Gets the timeout used to fire {@link TextChangeEvent}s when the - * {@link #getTextChangeEventMode()} is {@link TextChangeEventMode#LAZY} or - * {@link TextChangeEventMode#TIMEOUT}. - * - * @return the timeout value in milliseconds - */ - public int getTextChangeTimeout() { - return textChangeEventTimeout; - } - - public class TextChangeEventImpl extends TextChangeEvent { - private String curText; - private int cursorPosition; - - private TextChangeEventImpl(final AbstractTextField tf) { - super(tf); - curText = tf.getCurrentTextContent(); - cursorPosition = tf.getCursorPosition(); - } - - @Override - public AbstractTextField getComponent() { - return (AbstractTextField) super.getComponent(); - } - - @Override - public String getText() { - return curText; - } - - @Override - public int getCursorPosition() { - return cursorPosition; - } - - } - - /** - * Gets the current (or the last known) text content in the field. - * <p> - * Note the text returned by this method is not necessary the same that is - * returned by the {@link #getValue()} method. The value is updated when the - * terminal fires a value change event via e.g. blurring the field or by - * pressing enter. The value returned by this method is updated also on - * {@link TextChangeEvent}s. Due to this high dependency to the terminal - * implementation this method is (at least at this point) not published. - * - * @return the text which is currently displayed in the field. - */ - private String getCurrentTextContent() { - if (lastKnownTextContent != null) { - return lastKnownTextContent; - } else { - Object text = getValue(); - if (text == null) { - return getNullRepresentation(); - } - return text.toString(); - } - } - - /** - * Selects all text in the field. - * - * @since 6.4 - */ - public void selectAll() { - String text = getValue() == null ? "" : getValue().toString(); - setSelectionRange(0, text.length()); - } - - /** - * Sets the range of text to be selected. - * - * As a side effect the field will become focused. - * - * @since 6.4 - * - * @param pos - * the position of the first character to be selected - * @param length - * the number of characters to be selected - */ - public void setSelectionRange(int pos, int length) { - selectionPosition = pos; - selectionLength = length; - focus(); - requestRepaint(); - } - - /** - * Sets the cursor position in the field. As a side effect the field will - * become focused. - * - * @since 6.4 - * - * @param pos - * the position for the cursor - * */ - public void setCursorPosition(int pos) { - setSelectionRange(pos, 0); - lastKnownCursorPosition = pos; - } - - /** - * Returns the last known cursor position of the field. - * - * <p> - * Note that due to the client server nature or the GWT terminal, Vaadin - * cannot provide the exact value of the cursor position in most situations. - * The value is updated only when the client side terminal communicates to - * TextField, like on {@link ValueChangeEvent}s and {@link TextChangeEvent} - * s. This may change later if a deep push integration is built to Vaadin. - * - * @return the cursor position - */ - public int getCursorPosition() { - return lastKnownCursorPosition; - } - - @Override - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - @Override - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - } - - @Override - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - @Override - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - -} diff --git a/src/com/vaadin/ui/Accordion.java b/src/com/vaadin/ui/Accordion.java deleted file mode 100644 index b937c7bc2b..0000000000 --- a/src/com/vaadin/ui/Accordion.java +++ /dev/null @@ -1,19 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -/** - * An accordion is a component similar to a {@link TabSheet}, but with a - * vertical orientation and the selected component presented between tabs. - * - * Closable tabs are not supported by the accordion. - * - * The {@link Accordion} can be styled with the .v-accordion, .v-accordion-item, - * .v-accordion-item-first and .v-accordion-item-caption styles. - * - * @see TabSheet - */ -public class Accordion extends TabSheet { - -} diff --git a/src/com/vaadin/ui/Alignment.java b/src/com/vaadin/ui/Alignment.java deleted file mode 100644 index 0d73da8504..0000000000 --- a/src/com/vaadin/ui/Alignment.java +++ /dev/null @@ -1,158 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; - -import com.vaadin.shared.ui.AlignmentInfo.Bits; - -/** - * Class containing information about alignment of a component. Use the - * pre-instantiated classes. - */ -@SuppressWarnings("serial") -public final class Alignment implements Serializable { - - public static final Alignment TOP_RIGHT = new Alignment(Bits.ALIGNMENT_TOP - + Bits.ALIGNMENT_RIGHT); - public static final Alignment TOP_LEFT = new Alignment(Bits.ALIGNMENT_TOP - + Bits.ALIGNMENT_LEFT); - public static final Alignment TOP_CENTER = new Alignment(Bits.ALIGNMENT_TOP - + Bits.ALIGNMENT_HORIZONTAL_CENTER); - public static final Alignment MIDDLE_RIGHT = new Alignment( - Bits.ALIGNMENT_VERTICAL_CENTER + Bits.ALIGNMENT_RIGHT); - public static final Alignment MIDDLE_LEFT = new Alignment( - Bits.ALIGNMENT_VERTICAL_CENTER + Bits.ALIGNMENT_LEFT); - public static final Alignment MIDDLE_CENTER = new Alignment( - Bits.ALIGNMENT_VERTICAL_CENTER + Bits.ALIGNMENT_HORIZONTAL_CENTER); - public static final Alignment BOTTOM_RIGHT = new Alignment( - Bits.ALIGNMENT_BOTTOM + Bits.ALIGNMENT_RIGHT); - public static final Alignment BOTTOM_LEFT = new Alignment( - Bits.ALIGNMENT_BOTTOM + Bits.ALIGNMENT_LEFT); - public static final Alignment BOTTOM_CENTER = new Alignment( - Bits.ALIGNMENT_BOTTOM + Bits.ALIGNMENT_HORIZONTAL_CENTER); - - private final int bitMask; - - public Alignment(int bitMask) { - this.bitMask = bitMask; - } - - /** - * Returns a bitmask representation of the alignment value. Used internally - * by terminal. - * - * @return the bitmask representation of the alignment value - */ - public int getBitMask() { - return bitMask; - } - - /** - * Checks if component is aligned to the top of the available space. - * - * @return true if aligned top - */ - public boolean isTop() { - return (bitMask & Bits.ALIGNMENT_TOP) == Bits.ALIGNMENT_TOP; - } - - /** - * Checks if component is aligned to the bottom of the available space. - * - * @return true if aligned bottom - */ - public boolean isBottom() { - return (bitMask & Bits.ALIGNMENT_BOTTOM) == Bits.ALIGNMENT_BOTTOM; - } - - /** - * Checks if component is aligned to the left of the available space. - * - * @return true if aligned left - */ - public boolean isLeft() { - return (bitMask & Bits.ALIGNMENT_LEFT) == Bits.ALIGNMENT_LEFT; - } - - /** - * Checks if component is aligned to the right of the available space. - * - * @return true if aligned right - */ - public boolean isRight() { - return (bitMask & Bits.ALIGNMENT_RIGHT) == Bits.ALIGNMENT_RIGHT; - } - - /** - * Checks if component is aligned middle (vertically center) of the - * available space. - * - * @return true if aligned bottom - */ - public boolean isMiddle() { - return (bitMask & Bits.ALIGNMENT_VERTICAL_CENTER) == Bits.ALIGNMENT_VERTICAL_CENTER; - } - - /** - * Checks if component is aligned center (horizontally) of the available - * space. - * - * @return true if aligned center - */ - public boolean isCenter() { - return (bitMask & Bits.ALIGNMENT_HORIZONTAL_CENTER) == Bits.ALIGNMENT_HORIZONTAL_CENTER; - } - - /** - * Returns string representation of vertical alignment. - * - * @return vertical alignment as CSS value - */ - public String getVerticalAlignment() { - if (isBottom()) { - return "bottom"; - } else if (isMiddle()) { - return "middle"; - } - return "top"; - } - - /** - * Returns string representation of horizontal alignment. - * - * @return horizontal alignment as CSS value - */ - public String getHorizontalAlignment() { - if (isRight()) { - return "right"; - } else if (isCenter()) { - return "center"; - } - return "left"; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if ((obj == null) || (obj.getClass() != this.getClass())) { - return false; - } - Alignment a = (Alignment) obj; - return bitMask == a.bitMask; - } - - @Override - public int hashCode() { - return bitMask; - } - - @Override - public String toString() { - return String.valueOf(bitMask); - } - -} diff --git a/src/com/vaadin/ui/Audio.java b/src/com/vaadin/ui/Audio.java deleted file mode 100644 index ac2ee869a6..0000000000 --- a/src/com/vaadin/ui/Audio.java +++ /dev/null @@ -1,55 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.terminal.Resource; - -/** - * The Audio component translates into an HTML5 <audio> element and as - * such is only supported in browsers that support HTML5 media markup. Browsers - * that do not support HTML5 display the text or HTML set by calling - * {@link #setAltText(String)}. - * - * A flash-player fallback can be implemented by setting HTML content allowed ( - * {@link #setHtmlContentAllowed(boolean)} and calling - * {@link #setAltText(String)} with the flash player markup. An example of flash - * fallback can be found at the <a href= - * "https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Using_Flash" - * >Mozilla Developer Network</a>. - * - * Multiple sources can be specified. Which of the sources is used is selected - * by the browser depending on which file formats it supports. See <a - * href="http://en.wikipedia.org/wiki/HTML5_video#Table">wikipedia</a> for a - * table of formats supported by different browsers. - * - * @author Vaadin Ltd - * @since 6.7.0 - */ -public class Audio extends AbstractMedia { - - public Audio() { - this("", null); - } - - /** - * @param caption - * The caption of the audio component. - */ - public Audio(String caption) { - this(caption, null); - } - - /** - * @param caption - * The caption of the audio component - * @param source - * The audio file to play. - */ - public Audio(String caption, Resource source) { - setCaption(caption); - setSource(source); - setShowControls(true); - } -} diff --git a/src/com/vaadin/ui/Button.java b/src/com/vaadin/ui/Button.java deleted file mode 100644 index 0cb667d527..0000000000 --- a/src/com/vaadin/ui/Button.java +++ /dev/null @@ -1,539 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import com.vaadin.event.Action; -import com.vaadin.event.FieldEvents; -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.event.ShortcutAction; -import com.vaadin.event.ShortcutAction.KeyCode; -import com.vaadin.event.ShortcutAction.ModifierKey; -import com.vaadin.event.ShortcutListener; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.button.ButtonServerRpc; -import com.vaadin.shared.ui.button.ButtonState; -import com.vaadin.tools.ReflectTools; -import com.vaadin.ui.Component.Focusable; - -/** - * A generic button component. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Button extends AbstractComponent implements - FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Focusable, - Action.ShortcutNotifier { - - private ButtonServerRpc rpc = new ButtonServerRpc() { - - @Override - public void click(MouseEventDetails mouseEventDetails) { - fireClick(mouseEventDetails); - } - - @Override - public void disableOnClick() { - // Could be optimized so the button is not repainted because of - // this (client side has already disabled the button) - setEnabled(false); - } - }; - - FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) { - - @Override - protected void fireEvent(Event event) { - Button.this.fireEvent(event); - } - }; - - /** - * Creates a new push button. - */ - public Button() { - registerRpc(rpc); - registerRpc(focusBlurRpc); - } - - /** - * Creates a new push button with the given caption. - * - * @param caption - * the Button caption. - */ - public Button(String caption) { - this(); - setCaption(caption); - } - - /** - * Creates a new push button with a click listener. - * - * @param caption - * the Button caption. - * @param listener - * the Button click listener. - */ - public Button(String caption, ClickListener listener) { - this(caption); - addListener(listener); - } - - /** - * Click event. This event is thrown, when the button is clicked. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class ClickEvent extends Component.Event { - - private final MouseEventDetails details; - - /** - * New instance of text change event. - * - * @param source - * the Source of the event. - */ - public ClickEvent(Component source) { - super(source); - details = null; - } - - /** - * Constructor with mouse details - * - * @param source - * The source where the click took place - * @param details - * Details about the mouse click - */ - public ClickEvent(Component source, MouseEventDetails details) { - super(source); - this.details = details; - } - - /** - * Gets the Button where the event occurred. - * - * @return the Source of the event. - */ - public Button getButton() { - return (Button) getSource(); - } - - /** - * Returns the mouse position (x coordinate) when the click took place. - * The position is relative to the browser client area. - * - * @return The mouse cursor x position or -1 if unknown - */ - public int getClientX() { - if (null != details) { - return details.getClientX(); - } else { - return -1; - } - } - - /** - * Returns the mouse position (y coordinate) when the click took place. - * The position is relative to the browser client area. - * - * @return The mouse cursor y position or -1 if unknown - */ - public int getClientY() { - if (null != details) { - return details.getClientY(); - } else { - return -1; - } - } - - /** - * Returns the relative mouse position (x coordinate) when the click - * took place. The position is relative to the clicked component. - * - * @return The mouse cursor x position relative to the clicked layout - * component or -1 if no x coordinate available - */ - public int getRelativeX() { - if (null != details) { - return details.getRelativeX(); - } else { - return -1; - } - } - - /** - * Returns the relative mouse position (y coordinate) when the click - * took place. The position is relative to the clicked component. - * - * @return The mouse cursor y position relative to the clicked layout - * component or -1 if no y coordinate available - */ - public int getRelativeY() { - if (null != details) { - return details.getRelativeY(); - } else { - return -1; - } - } - - /** - * Checks if the Alt key was down when the mouse event took place. - * - * @return true if Alt was down when the event occured, false otherwise - * or if unknown - */ - public boolean isAltKey() { - if (null != details) { - return details.isAltKey(); - } else { - return false; - } - } - - /** - * Checks if the Ctrl key was down when the mouse event took place. - * - * @return true if Ctrl was pressed when the event occured, false - * otherwise or if unknown - */ - public boolean isCtrlKey() { - if (null != details) { - return details.isCtrlKey(); - } else { - return false; - } - } - - /** - * Checks if the Meta key was down when the mouse event took place. - * - * @return true if Meta was pressed when the event occured, false - * otherwise or if unknown - */ - public boolean isMetaKey() { - if (null != details) { - return details.isMetaKey(); - } else { - return false; - } - } - - /** - * Checks if the Shift key was down when the mouse event took place. - * - * @return true if Shift was pressed when the event occured, false - * otherwise or if unknown - */ - public boolean isShiftKey() { - if (null != details) { - return details.isShiftKey(); - } else { - return false; - } - } - } - - /** - * Interface for listening for a {@link ClickEvent} fired by a - * {@link Component}. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ClickListener extends Serializable { - - public static final Method BUTTON_CLICK_METHOD = ReflectTools - .findMethod(ClickListener.class, "buttonClick", - ClickEvent.class); - - /** - * Called when a {@link Button} has been clicked. A reference to the - * button is given by {@link ClickEvent#getButton()}. - * - * @param event - * An event containing information about the click. - */ - public void buttonClick(ClickEvent event); - - } - - /** - * Adds the button click listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(ClickListener listener) { - addListener(ClickEvent.class, listener, - ClickListener.BUTTON_CLICK_METHOD); - } - - /** - * Removes the button click listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(ClickListener listener) { - removeListener(ClickEvent.class, listener, - ClickListener.BUTTON_CLICK_METHOD); - } - - /** - * Simulates a button click, notifying all server-side listeners. - * - * No action is taken is the button is disabled. - */ - public void click() { - if (isEnabled() && !isReadOnly()) { - fireClick(); - } - } - - /** - * Fires a click event to all listeners without any event details. - * - * In subclasses, override {@link #fireClick(MouseEventDetails)} instead of - * this method. - */ - protected void fireClick() { - fireEvent(new Button.ClickEvent(this)); - } - - /** - * Fires a click event to all listeners. - * - * @param details - * MouseEventDetails from which keyboard modifiers and other - * information about the mouse click can be obtained. If the - * button was clicked by a keyboard event, some of the fields may - * be empty/undefined. - */ - protected void fireClick(MouseEventDetails details) { - fireEvent(new Button.ClickEvent(this, details)); - } - - @Override - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - @Override - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - @Override - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - @Override - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - - } - - /* - * Actions - */ - - protected ClickShortcut clickShortcut; - - /** - * Makes it possible to invoke a click on this button by pressing the given - * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/> - * The shortcut is global (bound to the containing Window). - * - * @param keyCode - * the keycode for invoking the shortcut - * @param modifiers - * the (optional) modifiers for invoking the shortcut, null for - * none - */ - public void setClickShortcut(int keyCode, int... modifiers) { - if (clickShortcut != null) { - removeShortcutListener(clickShortcut); - } - clickShortcut = new ClickShortcut(this, keyCode, modifiers); - addShortcutListener(clickShortcut); - getState().setClickShortcutKeyCode(clickShortcut.getKeyCode()); - } - - /** - * Removes the keyboard shortcut previously set with - * {@link #setClickShortcut(int, int...)}. - */ - public void removeClickShortcut() { - if (clickShortcut != null) { - removeShortcutListener(clickShortcut); - clickShortcut = null; - getState().setClickShortcutKeyCode(0); - } - } - - /** - * A {@link ShortcutListener} specifically made to define a keyboard - * shortcut that invokes a click on the given button. - * - */ - public static class ClickShortcut extends ShortcutListener { - protected Button button; - - /** - * Creates a keyboard shortcut for clicking the given button using the - * shorthand notation defined in {@link ShortcutAction}. - * - * @param button - * to be clicked when the shortcut is invoked - * @param shorthandCaption - * the caption with shortcut keycode and modifiers indicated - */ - public ClickShortcut(Button button, String shorthandCaption) { - super(shorthandCaption); - this.button = button; - } - - /** - * Creates a keyboard shortcut for clicking the given button using the - * given {@link KeyCode} and {@link ModifierKey}s. - * - * @param button - * to be clicked when the shortcut is invoked - * @param keyCode - * KeyCode to react to - * @param modifiers - * optional modifiers for shortcut - */ - public ClickShortcut(Button button, int keyCode, int... modifiers) { - super(null, keyCode, modifiers); - this.button = button; - } - - /** - * Creates a keyboard shortcut for clicking the given button using the - * given {@link KeyCode}. - * - * @param button - * to be clicked when the shortcut is invoked - * @param keyCode - * KeyCode to react to - */ - public ClickShortcut(Button button, int keyCode) { - this(button, keyCode, null); - } - - @Override - public void handleAction(Object sender, Object target) { - button.click(); - } - } - - /** - * Determines if a button is automatically disabled when clicked. See - * {@link #setDisableOnClick(boolean)} for details. - * - * @return true if the button is disabled when clicked, false otherwise - */ - public boolean isDisableOnClick() { - return getState().isDisableOnClick(); - } - - /** - * Determines if a button is automatically disabled when clicked. If this is - * set to true the button will be automatically disabled when clicked, - * typically to prevent (accidental) extra clicks on a button. - * - * @param disableOnClick - * true to disable button when it is clicked, false otherwise - */ - public void setDisableOnClick(boolean disableOnClick) { - getState().setDisableOnClick(disableOnClick); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component.Focusable#getTabIndex() - */ - @Override - public int getTabIndex() { - return getState().getTabIndex(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Component.Focusable#setTabIndex(int) - */ - @Override - public void setTabIndex(int tabIndex) { - getState().setTabIndex(tabIndex); - requestRepaint(); - } - - @Override - public void focus() { - // Overridden only to make public - super.focus(); - } - - @Override - public ButtonState getState() { - return (ButtonState) super.getState(); - } - - /** - * Set whether the caption text is rendered as HTML or not. You might need - * to retheme button to allow higher content than the original text style. - * - * If set to true, the captions are passed to the browser as html and the - * developer is responsible for ensuring no harmful html is used. If set to - * false, the content is passed to the browser as plain text. - * - * @param htmlContentAllowed - * <code>true</code> if caption is rendered as HTML, - * <code>false</code> otherwise - */ - public void setHtmlContentAllowed(boolean htmlContentAllowed) { - if (getState().isHtmlContentAllowed() != htmlContentAllowed) { - getState().setHtmlContentAllowed(htmlContentAllowed); - requestRepaint(); - } - } - - /** - * Return HTML rendering setting - * - * @return <code>true</code> if the caption text is to be rendered as HTML, - * <code>false</code> otherwise - */ - public boolean isHtmlContentAllowed() { - return getState().isHtmlContentAllowed(); - } - -} diff --git a/src/com/vaadin/ui/CheckBox.java b/src/com/vaadin/ui/CheckBox.java deleted file mode 100644 index 30ac9b4626..0000000000 --- a/src/com/vaadin/ui/CheckBox.java +++ /dev/null @@ -1,141 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.data.Property; -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.FocusAndBlurServerRpcImpl; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.checkbox.CheckBoxServerRpc; -import com.vaadin.shared.ui.checkbox.CheckBoxState; - -public class CheckBox extends AbstractField<Boolean> { - - private CheckBoxServerRpc rpc = new CheckBoxServerRpc() { - - @Override - public void setChecked(boolean checked, - MouseEventDetails mouseEventDetails) { - if (isReadOnly()) { - return; - } - - final Boolean oldValue = getValue(); - final Boolean newValue = checked; - - if (!newValue.equals(oldValue)) { - // The event is only sent if the switch state is changed - setValue(newValue); - } - - } - }; - - FocusAndBlurServerRpcImpl focusBlurRpc = new FocusAndBlurServerRpcImpl(this) { - @Override - protected void fireEvent(Event event) { - CheckBox.this.fireEvent(event); - } - }; - - /** - * Creates a new checkbox. - */ - public CheckBox() { - registerRpc(rpc); - registerRpc(focusBlurRpc); - setValue(Boolean.FALSE); - } - - /** - * Creates a new checkbox with a set caption. - * - * @param caption - * the Checkbox caption. - */ - public CheckBox(String caption) { - this(); - setCaption(caption); - } - - /** - * Creates a new checkbox with a caption and a set initial state. - * - * @param caption - * the caption of the checkbox - * @param initialState - * the initial state of the checkbox - */ - public CheckBox(String caption, boolean initialState) { - this(caption); - setValue(initialState); - } - - /** - * Creates a new checkbox that is connected to a boolean property. - * - * @param state - * the Initial state of the switch-button. - * @param dataSource - */ - public CheckBox(String caption, Property<?> dataSource) { - this(caption); - setPropertyDataSource(dataSource); - } - - @Override - public Class<Boolean> getType() { - return Boolean.class; - } - - @Override - public CheckBoxState getState() { - return (CheckBoxState) super.getState(); - } - - @Override - protected void setInternalValue(Boolean newValue) { - super.setInternalValue(newValue); - if (newValue == null) { - newValue = false; - } - getState().setChecked(newValue); - } - - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - } - - /** - * Get the boolean value of the button state. - * - * @return True iff the button is pressed down or checked. - * - * @deprecated Use {@link #getValue()} instead and, if needed, handle null - * values. - */ - @Deprecated - public boolean booleanValue() { - Boolean value = getValue(); - return (null == value) ? false : value.booleanValue(); - } -} diff --git a/src/com/vaadin/ui/ComboBox.java b/src/com/vaadin/ui/ComboBox.java deleted file mode 100644 index 6286dad124..0000000000 --- a/src/com/vaadin/ui/ComboBox.java +++ /dev/null @@ -1,116 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Collection; - -import com.vaadin.data.Container; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.combobox.VFilterSelect; - -/** - * A filtering dropdown single-select. Suitable for newItemsAllowed, but it's - * turned of by default to avoid mistakes. Items are filtered based on user - * input, and loaded dynamically ("lazy-loading") from the server. You can turn - * on newItemsAllowed and change filtering mode (and also turn it off), but you - * can not turn on multi-select mode. - * - */ -@SuppressWarnings("serial") -public class ComboBox extends Select { - - private String inputPrompt = null; - - /** - * If text input is not allowed, the ComboBox behaves like a pretty - * NativeSelect - the user can not enter any text and clicking the text - * field opens the drop down with options - */ - private boolean textInputAllowed = true; - - public ComboBox() { - setNewItemsAllowed(false); - } - - public ComboBox(String caption, Collection<?> options) { - super(caption, options); - setNewItemsAllowed(false); - } - - public ComboBox(String caption, Container dataSource) { - super(caption, dataSource); - setNewItemsAllowed(false); - } - - public ComboBox(String caption) { - super(caption); - setNewItemsAllowed(false); - } - - /** - * Gets the current input prompt. - * - * @see #setInputPrompt(String) - * @return the current input prompt, or null if not enabled - */ - public String getInputPrompt() { - return inputPrompt; - } - - /** - * Sets the input prompt - a textual prompt that is displayed when the - * select would otherwise be empty, to prompt the user for input. - * - * @param inputPrompt - * the desired input prompt, or null to disable - */ - public void setInputPrompt(String inputPrompt) { - this.inputPrompt = inputPrompt; - requestRepaint(); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (inputPrompt != null) { - target.addAttribute("prompt", inputPrompt); - } - super.paintContent(target); - - if (!textInputAllowed) { - target.addAttribute(VFilterSelect.ATTR_NO_TEXT_INPUT, true); - } - } - - /** - * Sets whether it is possible to input text into the field or whether the - * field area of the component is just used to show what is selected. By - * disabling text input, the comboBox will work in the same way as a - * {@link NativeSelect} - * - * @see #isTextInputAllowed() - * - * @param textInputAllowed - * true to allow entering text, false to just show the current - * selection - */ - public void setTextInputAllowed(boolean textInputAllowed) { - this.textInputAllowed = textInputAllowed; - requestRepaint(); - } - - /** - * Returns true if the user can enter text into the field to either filter - * the selections or enter a new value if {@link #isNewItemsAllowed()} - * returns true. If text input is disabled, the comboBox will work in the - * same way as a {@link NativeSelect} - * - * @return - */ - public boolean isTextInputAllowed() { - return textInputAllowed; - } - -} diff --git a/src/com/vaadin/ui/Component.java b/src/com/vaadin/ui/Component.java deleted file mode 100644 index a2c257ab68..0000000000 --- a/src/com/vaadin/ui/Component.java +++ /dev/null @@ -1,1047 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.EventListener; -import java.util.EventObject; -import java.util.Locale; - -import com.vaadin.Application; -import com.vaadin.event.FieldEvents; -import com.vaadin.shared.ComponentState; -import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Sizeable; -import com.vaadin.terminal.VariableOwner; -import com.vaadin.terminal.gwt.server.ClientConnector; - -/** - * {@code Component} is the top-level interface that is and must be implemented - * by all Vaadin components. {@code Component} is paired with - * {@link AbstractComponent}, which provides a default implementation for all - * the methods defined in this interface. - * - * <p> - * Components are laid out in the user interface hierarchically. The layout is - * managed by layout components, or more generally by components that implement - * the {@link ComponentContainer} interface. Such a container is the - * <i>parent</i> of the contained components. - * </p> - * - * <p> - * The {@link #getParent()} method allows retrieving the parent component of a - * component. While there is a {@link #setParent(Component) setParent()}, you - * rarely need it as you normally add components with the - * {@link ComponentContainer#addComponent(Component) addComponent()} method of - * the layout or other {@code ComponentContainer}, which automatically sets the - * parent. - * </p> - * - * <p> - * A component becomes <i>attached</i> to an application (and the - * {@link #attach()} is called) when it or one of its parents is attached to the - * main window of the application through its containment hierarchy. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Component extends ClientConnector, Sizeable, Serializable { - - /** - * Gets all user-defined CSS style names of a component. If the component - * has multiple style names defined, the return string is a space-separated - * list of style names. Built-in style names defined in Vaadin or GWT are - * not returned. - * - * <p> - * The style names are returned only in the basic form in which they were - * added; each user-defined style name shows as two CSS style class names in - * the rendered HTML: one as it was given and one prefixed with the - * component-specific style name. Only the former is returned. - * </p> - * - * @return the style name or a space-separated list of user-defined style - * names of the component - * @see #setStyleName(String) - * @see #addStyleName(String) - * @see #removeStyleName(String) - */ - public String getStyleName(); - - /** - * Sets one or more user-defined style names of the component, replacing any - * previous user-defined styles. Multiple styles can be specified as a - * space-separated list of style names. The style names must be valid CSS - * class names and should not conflict with any built-in style names in - * Vaadin or GWT. - * - * <pre> - * Label label = new Label("This text has a lot of style"); - * label.setStyleName("myonestyle myotherstyle"); - * </pre> - * - * <p> - * Each style name will occur in two versions: one as specified and one that - * is prefixed with the style name of the component. For example, if you - * have a {@code Button} component and give it "{@code mystyle}" style, the - * component will have both "{@code mystyle}" and "{@code v-button-mystyle}" - * styles. You could then style the component either with: - * </p> - * - * <pre> - * .myonestyle {background: blue;} - * </pre> - * - * <p> - * or - * </p> - * - * <pre> - * .v-button-myonestyle {background: blue;} - * </pre> - * - * <p> - * It is normally a good practice to use {@link #addStyleName(String) - * addStyleName()} rather than this setter, as different software - * abstraction layers can then add their own styles without accidentally - * removing those defined in other layers. - * </p> - * - * <p> - * This method will trigger a {@link RepaintRequestEvent}. - * </p> - * - * @param style - * the new style or styles of the component as a space-separated - * list - * @see #getStyleName() - * @see #addStyleName(String) - * @see #removeStyleName(String) - */ - public void setStyleName(String style); - - /** - * Adds a style name to component. The style name will be rendered as a HTML - * class name, which can be used in a CSS definition. - * - * <pre> - * Label label = new Label("This text has style"); - * label.addStyleName("mystyle"); - * </pre> - * - * <p> - * Each style name will occur in two versions: one as specified and one that - * is prefixed wil the style name of the component. For example, if you have - * a {@code Button} component and give it "{@code mystyle}" style, the - * component will have both "{@code mystyle}" and "{@code v-button-mystyle}" - * styles. You could then style the component either with: - * </p> - * - * <pre> - * .mystyle {font-style: italic;} - * </pre> - * - * <p> - * or - * </p> - * - * <pre> - * .v-button-mystyle {font-style: italic;} - * </pre> - * - * <p> - * This method will trigger a {@link RepaintRequestEvent}. - * </p> - * - * @param style - * the new style to be added to the component - * @see #getStyleName() - * @see #setStyleName(String) - * @see #removeStyleName(String) - */ - public void addStyleName(String style); - - /** - * Removes one or more style names from component. Multiple styles can be - * specified as a space-separated list of style names. - * - * <p> - * The parameter must be a valid CSS style name. Only user-defined style - * names added with {@link #addStyleName(String) addStyleName()} or - * {@link #setStyleName(String) setStyleName()} can be removed; built-in - * style names defined in Vaadin or GWT can not be removed. - * </p> - * - * * This method will trigger a {@link RepaintRequestEvent}. - * - * @param style - * the style name or style names to be removed - * @see #getStyleName() - * @see #setStyleName(String) - * @see #addStyleName(String) - */ - public void removeStyleName(String style); - - /** - * Tests whether the component is enabled or not. A user can not interact - * with disabled components. Disabled components are rendered in a style - * that indicates the status, usually in gray color. Children of a disabled - * component are also disabled. Components are enabled by default. - * - * <p> - * As a security feature, all updates for disabled components are blocked on - * the server-side. - * </p> - * - * <p> - * Note that this method only returns the status of the component and does - * not take parents into account. Even though this method returns true the - * component can be disabled to the user if a parent is disabled. - * </p> - * - * @return <code>true</code> if the component and its parent are enabled, - * <code>false</code> otherwise. - * @see VariableOwner#isEnabled() - */ - public boolean isEnabled(); - - /** - * Enables or disables the component. The user can not interact disabled - * components, which are shown with a style that indicates the status, - * usually shaded in light gray color. Components are enabled by default. - * - * <pre> - * Button enabled = new Button("Enabled"); - * enabled.setEnabled(true); // The default - * layout.addComponent(enabled); - * - * Button disabled = new Button("Disabled"); - * disabled.setEnabled(false); - * layout.addComponent(disabled); - * </pre> - * - * <p> - * This method will trigger a {@link RepaintRequestEvent} for the component - * and, if it is a {@link ComponentContainer}, for all its children - * recursively. - * </p> - * - * @param enabled - * a boolean value specifying if the component should be enabled - * or not - */ - public void setEnabled(boolean enabled); - - /** - * Tests the <i>visibility</i> property of the component. - * - * <p> - * Visible components are drawn in the user interface, while invisible ones - * are not. The effect is not merely a cosmetic CSS change - no information - * about an invisible component will be sent to the client. The effect is - * thus the same as removing the component from its parent. Making a - * component invisible through this property can alter the positioning of - * other components. - * </p> - * - * <p> - * A component is visible only if all its parents are also visible. This is - * not checked by this method though, so even if this method returns true, - * the component can be hidden from the user because a parent is set to - * invisible. - * </p> - * - * @return <code>true</code> if the component has been set to be visible in - * the user interface, <code>false</code> if not - * @see #setVisible(boolean) - * @see #attach() - */ - public boolean isVisible(); - - /** - * Sets the visibility of the component. - * - * <p> - * Visible components are drawn in the user interface, while invisible ones - * are not. The effect is not merely a cosmetic CSS change - no information - * about an invisible component will be sent to the client. The effect is - * thus the same as removing the component from its parent. - * </p> - * - * <pre> - * TextField readonly = new TextField("Read-Only"); - * readonly.setValue("You can't see this!"); - * readonly.setVisible(false); - * layout.addComponent(readonly); - * </pre> - * - * <p> - * A component is visible only if all of its parents are also visible. If a - * component is explicitly set to be invisible, changes in the visibility of - * its parents will not change the visibility of the component. - * </p> - * - * @param visible - * the boolean value specifying if the component should be - * visible after the call or not. - * @see #isVisible() - */ - public void setVisible(boolean visible); - - /** - * Gets the parent component of the component. - * - * <p> - * Components can be nested but a component can have only one parent. A - * component that contains other components, that is, can be a parent, - * should usually inherit the {@link ComponentContainer} interface. - * </p> - * - * @return the parent component - */ - @Override - public HasComponents getParent(); - - /** - * Tests whether the component is in the read-only mode. The user can not - * change the value of a read-only component. As only {@link Field} - * components normally have a value that can be input or changed by the - * user, this is mostly relevant only to field components, though not - * restricted to them. - * - * <p> - * Notice that the read-only mode only affects whether the user can change - * the <i>value</i> of the component; it is possible to, for example, scroll - * a read-only table. - * </p> - * - * <p> - * The method will return {@code true} if the component or any of its - * parents is in the read-only mode. - * </p> - * - * @return <code>true</code> if the component or any of its parents is in - * read-only mode, <code>false</code> if not. - * @see #setReadOnly(boolean) - */ - public boolean isReadOnly(); - - /** - * Sets the read-only mode of the component to the specified mode. The user - * can not change the value of a read-only component. - * - * <p> - * As only {@link Field} components normally have a value that can be input - * or changed by the user, this is mostly relevant only to field components, - * though not restricted to them. - * </p> - * - * <p> - * Notice that the read-only mode only affects whether the user can change - * the <i>value</i> of the component; it is possible to, for example, scroll - * a read-only table. - * </p> - * - * <p> - * This method will trigger a {@link RepaintRequestEvent}. - * </p> - * - * @param readOnly - * a boolean value specifying whether the component is put - * read-only mode or not - */ - public void setReadOnly(boolean readOnly); - - /** - * Gets the caption of the component. - * - * <p> - * See {@link #setCaption(String)} for a detailed description of the - * caption. - * </p> - * - * @return the caption of the component or {@code null} if the caption is - * not set. - * @see #setCaption(String) - */ - public String getCaption(); - - /** - * Sets the caption of the component. - * - * <p> - * A <i>caption</i> is an explanatory textual label accompanying a user - * interface component, usually shown above, left of, or inside the - * component. <i>Icon</i> (see {@link #setIcon(Resource) setIcon()} is - * closely related to caption and is usually displayed horizontally before - * or after it, depending on the component and the containing layout. - * </p> - * - * <p> - * The caption can usually also be given as the first parameter to a - * constructor, though some components do not support it. - * </p> - * - * <pre> - * RichTextArea area = new RichTextArea(); - * area.setCaption("You can edit stuff here"); - * area.setValue("<h1>Helpful Heading</h1>" - * + "<p>All this is for you to edit.</p>"); - * </pre> - * - * <p> - * The contents of a caption are automatically quoted, so no raw XHTML can - * be rendered in a caption. The validity of the used character encoding, - * usually UTF-8, is not checked. - * </p> - * - * <p> - * The caption of a component is, by default, managed and displayed by the - * layout component or component container in which the component is placed. - * For example, the {@link VerticalLayout} component shows the captions - * left-aligned above the contained components, while the {@link FormLayout} - * component shows the captions on the left side of the vertically laid - * components, with the captions and their associated components - * left-aligned in their own columns. The {@link CustomComponent} does not - * manage the caption of its composition root, so if the root component has - * a caption, it will not be rendered. Some components, such as - * {@link Button} and {@link Panel}, manage the caption themselves and - * display it inside the component. - * </p> - * - * <p> - * This method will trigger a {@link RepaintRequestEvent}. A - * reimplementation should call the superclass implementation. - * </p> - * - * @param caption - * the new caption for the component. If the caption is - * {@code null}, no caption is shown and it does not normally - * take any space - */ - public void setCaption(String caption); - - /** - * Gets the icon resource of the component. - * - * <p> - * See {@link #setIcon(Resource)} for a detailed description of the icon. - * </p> - * - * @return the icon resource of the component or {@code null} if the - * component has no icon - * @see #setIcon(Resource) - */ - public Resource getIcon(); - - /** - * Sets the icon of the component. - * - * <p> - * An icon is an explanatory graphical label accompanying a user interface - * component, usually shown above, left of, or inside the component. Icon is - * closely related to caption (see {@link #setCaption(String) setCaption()}) - * and is usually displayed horizontally before or after it, depending on - * the component and the containing layout. - * </p> - * - * <p> - * The image is loaded by the browser from a resource, typically a - * {@link com.vaadin.terminal.ThemeResource}. - * </p> - * - * <pre> - * // Component with an icon from a custom theme - * TextField name = new TextField("Name"); - * name.setIcon(new ThemeResource("icons/user.png")); - * layout.addComponent(name); - * - * // Component with an icon from another theme ('runo') - * Button ok = new Button("OK"); - * ok.setIcon(new ThemeResource("../runo/icons/16/ok.png")); - * layout.addComponent(ok); - * </pre> - * - * <p> - * The icon of a component is, by default, managed and displayed by the - * layout component or component container in which the component is placed. - * For example, the {@link VerticalLayout} component shows the icons - * left-aligned above the contained components, while the {@link FormLayout} - * component shows the icons on the left side of the vertically laid - * components, with the icons and their associated components left-aligned - * in their own columns. The {@link CustomComponent} does not manage the - * icon of its composition root, so if the root component has an icon, it - * will not be rendered. - * </p> - * - * <p> - * An icon will be rendered inside an HTML element that has the - * {@code v-icon} CSS style class. The containing layout may enclose an icon - * and a caption inside elements related to the caption, such as - * {@code v-caption} . - * </p> - * - * This method will trigger a {@link RepaintRequestEvent}. - * - * @param icon - * the icon of the component. If null, no icon is shown and it - * does not normally take any space. - * @see #getIcon() - * @see #setCaption(String) - */ - public void setIcon(Resource icon); - - /** - * Gets the Root the component is attached to. - * - * <p> - * If the component is not attached to a Root through a component - * containment hierarchy, <code>null</code> is returned. - * </p> - * - * @return the Root of the component or <code>null</code> if it is not - * attached to a Root - */ - @Override - public Root getRoot(); - - /** - * Gets the application object to which the component is attached. - * - * <p> - * The method will return {@code null} if the component is not currently - * attached to an application. - * </p> - * - * <p> - * Getting a null value is often a problem in constructors of regular - * components and in the initializers of custom composite components. A - * standard workaround is to use {@link Application#getCurrent()} to - * retrieve the application instance that the current request relates to. - * Another way is to move the problematic initialization to - * {@link #attach()}, as described in the documentation of the method. - * </p> - * - * @return the parent application of the component or <code>null</code>. - * @see #attach() - */ - public Application getApplication(); - - /** - * {@inheritDoc} - * - * <p> - * Reimplementing the {@code attach()} method is useful for tasks that need - * to get a reference to the parent, window, or application object with the - * {@link #getParent()}, {@link #getRoot()}, and {@link #getApplication()} - * methods. A component does not yet know these objects in the constructor, - * so in such case, the methods will return {@code null}. For example, the - * following is invalid: - * </p> - * - * <pre> - * public class AttachExample extends CustomComponent { - * public AttachExample() { - * // ERROR: We can't access the application object yet. - * ClassResource r = new ClassResource("smiley.jpg", getApplication()); - * Embedded image = new Embedded("Image:", r); - * setCompositionRoot(image); - * } - * } - * </pre> - * - * <p> - * Adding a component to an application triggers calling the - * {@link #attach()} method for the component. Correspondingly, removing a - * component from a container triggers calling the {@link #detach()} method. - * If the parent of an added component is already connected to the - * application, the {@code attach()} is called immediately from - * {@link #setParent(Component)}. - * </p> - * <p> - * This method must call {@link Root#componentAttached(Component)} to let - * the Root know that a new Component has been attached. - * </p> - * - * - * <pre> - * public class AttachExample extends CustomComponent { - * public AttachExample() { - * } - * - * @Override - * public void attach() { - * super.attach(); // Must call. - * - * // Now we know who ultimately owns us. - * ClassResource r = new ClassResource("smiley.jpg", getApplication()); - * Embedded image = new Embedded("Image:", r); - * setCompositionRoot(image); - * } - * } - * </pre> - */ - @Override - public void attach(); - - /** - * Gets the locale of the component. - * - * <p> - * If a component does not have a locale set, the locale of its parent is - * returned, and so on. Eventually, if no parent has locale set, the locale - * of the application is returned. If the application does not have a locale - * set, it is determined by <code>Locale.getDefault()</code>. - * </p> - * - * <p> - * As the component must be attached before its locale can be acquired, - * using this method in the internationalization of component captions, etc. - * is generally not feasible. For such use case, we recommend using an - * otherwise acquired reference to the application locale. - * </p> - * - * @return Locale of this component or {@code null} if the component and - * none of its parents has a locale set and the component is not yet - * attached to an application. - */ - public Locale getLocale(); - - /** - * Returns the current shared state bean for the component. The state (or - * changes to it) is communicated from the server to the client. - * - * Subclasses can use a more specific return type for this method. - * - * @return The state object for the component - * - * @since 7.0 - */ - @Override - public ComponentState getState(); - - /** - * Called before the shared state is sent to the client. Gives the component - * an opportunity to set computed/dynamic state values e.g. state values - * that depend on other component features. - * <p> - * This method must not alter the component hierarchy in any way. - * </p> - * - * @since 7.0 - */ - public void updateState(); - - /** - * Adds an unique id for component that get's transferred to terminal for - * testing purposes. Keeping identifiers unique is the responsibility of the - * programmer. - * - * @param id - * An alphanumeric id - */ - public void setDebugId(String id); - - /** - * Get's currently set debug identifier - * - * @return current debug id, null if not set - */ - public String getDebugId(); - - /* Component event framework */ - - /** - * Superclass of all component originated events. - * - * <p> - * Events are the basis of all user interaction handling in Vaadin. To - * handle events, you provide a listener object that receives the events of - * the particular event type. - * </p> - * - * <pre> - * Button button = new Button("Click Me!"); - * button.addListener(new Button.ClickListener() { - * public void buttonClick(ClickEvent event) { - * getWindow().showNotification("Thank You!"); - * } - * }); - * layout.addComponent(button); - * </pre> - * - * <p> - * Notice that while each of the event types have their corresponding - * listener types; the listener interfaces are not required to inherit the - * {@code Component.Listener} interface. - * </p> - * - * @see Component.Listener - */ - @SuppressWarnings("serial") - public class Event extends EventObject { - - /** - * Constructs a new event with the specified source component. - * - * @param source - * the source component of the event - */ - public Event(Component source) { - super(source); - } - - /** - * Gets the component where the event occurred. - * - * @return the source component of the event - */ - public Component getComponent() { - return (Component) getSource(); - } - } - - /** - * Listener interface for receiving <code>Component.Event</code>s. - * - * <p> - * Listener interfaces are the basis of all user interaction handling in - * Vaadin. You have or create a listener object that receives the events. - * All event types have their corresponding listener types; they are not, - * however, required to inherit the {@code Component.Listener} interface, - * and they rarely do so. - * </p> - * - * <p> - * This generic listener interface is useful typically when you wish to - * handle events from different component types in a single listener method - * ({@code componentEvent()}. If you handle component events in an anonymous - * listener class, you normally use the component specific listener class, - * such as {@link com.vaadin.ui.Button.ClickEvent}. - * </p> - * - * <pre> - * class Listening extends CustomComponent implements Listener { - * Button ok; // Stored for determining the source of an event - * - * Label status; // For displaying info about the event - * - * public Listening() { - * VerticalLayout layout = new VerticalLayout(); - * - * // Some miscellaneous component - * TextField name = new TextField("Say it all here"); - * name.addListener(this); - * name.setImmediate(true); - * layout.addComponent(name); - * - * // Handle button clicks as generic events instead - * // of Button.ClickEvent events - * ok = new Button("OK"); - * ok.addListener(this); - * layout.addComponent(ok); - * - * // For displaying information about an event - * status = new Label(""); - * layout.addComponent(status); - * - * setCompositionRoot(layout); - * } - * - * public void componentEvent(Event event) { - * // Act according to the source of the event - * if (event.getSource() == ok - * && event.getClass() == Button.ClickEvent.class) - * getWindow().showNotification("Click!"); - * - * // Display source component and event class names - * status.setValue("Event from " + event.getSource().getClass().getName() - * + ": " + event.getClass().getName()); - * } - * } - * - * Listening listening = new Listening(); - * layout.addComponent(listening); - * </pre> - * - * @see Component#addListener(Listener) - */ - public interface Listener extends EventListener, Serializable { - - /** - * Notifies the listener of a component event. - * - * <p> - * As the event can typically come from one of many source components, - * you may need to differentiate between the event source by component - * reference, class, etc. - * </p> - * - * <pre> - * public void componentEvent(Event event) { - * // Act according to the source of the event - * if (event.getSource() == ok && event.getClass() == Button.ClickEvent.class) - * getWindow().showNotification("Click!"); - * - * // Display source component and event class names - * status.setValue("Event from " + event.getSource().getClass().getName() - * + ": " + event.getClass().getName()); - * } - * </pre> - * - * @param event - * the event that has occured. - */ - public void componentEvent(Component.Event event); - } - - /** - * Registers a new (generic) component event listener for the component. - * - * <pre> - * class Listening extends CustomComponent implements Listener { - * // Stored for determining the source of an event - * Button ok; - * - * Label status; // For displaying info about the event - * - * public Listening() { - * VerticalLayout layout = new VerticalLayout(); - * - * // Some miscellaneous component - * TextField name = new TextField("Say it all here"); - * name.addListener(this); - * name.setImmediate(true); - * layout.addComponent(name); - * - * // Handle button clicks as generic events instead - * // of Button.ClickEvent events - * ok = new Button("OK"); - * ok.addListener(this); - * layout.addComponent(ok); - * - * // For displaying information about an event - * status = new Label(""); - * layout.addComponent(status); - * - * setCompositionRoot(layout); - * } - * - * public void componentEvent(Event event) { - * // Act according to the source of the event - * if (event.getSource() == ok) - * getWindow().showNotification("Click!"); - * - * status.setValue("Event from " + event.getSource().getClass().getName() - * + ": " + event.getClass().getName()); - * } - * } - * - * Listening listening = new Listening(); - * layout.addComponent(listening); - * </pre> - * - * @param listener - * the new Listener to be registered. - * @see Component.Event - * @see #removeListener(Listener) - */ - public void addListener(Component.Listener listener); - - /** - * Removes a previously registered component event listener from this - * component. - * - * @param listener - * the listener to be removed. - * @see #addListener(Listener) - */ - public void removeListener(Component.Listener listener); - - /** - * Class of all component originated error events. - * - * <p> - * The component error event is normally fired by - * {@link AbstractComponent#setComponentError(ErrorMessage)}. The component - * errors are set by the framework in some situations and can be set by user - * code. They are indicated in a component with an error indicator. - * </p> - */ - @SuppressWarnings("serial") - public class ErrorEvent extends Event { - - private final ErrorMessage message; - - /** - * Constructs a new event with a specified source component. - * - * @param message - * the error message. - * @param component - * the source component. - */ - public ErrorEvent(ErrorMessage message, Component component) { - super(component); - this.message = message; - } - - /** - * Gets the error message. - * - * @return the error message. - */ - public ErrorMessage getErrorMessage() { - return message; - } - } - - /** - * Listener interface for receiving <code>Component.Errors</code>s. - */ - public interface ErrorListener extends EventListener, Serializable { - - /** - * Notifies the listener of a component error. - * - * @param event - * the event that has occured. - */ - public void componentError(Component.ErrorEvent event); - } - - /** - * A sub-interface implemented by components that can obtain input focus. - * This includes all {@link Field} components as well as some other - * components, such as {@link Upload}. - * - * <p> - * Focus can be set with {@link #focus()}. This interface does not provide - * an accessor that would allow finding out the currently focused component; - * focus information can be acquired for some (but not all) {@link Field} - * components through the {@link com.vaadin.event.FieldEvents.FocusListener} - * and {@link com.vaadin.event.FieldEvents.BlurListener} interfaces. - * </p> - * - * @see FieldEvents - */ - public interface Focusable extends Component { - - /** - * Sets the focus to this component. - * - * <pre> - * Form loginBox = new Form(); - * loginBox.setCaption("Login"); - * layout.addComponent(loginBox); - * - * // Create the first field which will be focused - * TextField username = new TextField("User name"); - * loginBox.addField("username", username); - * - * // Set focus to the user name - * username.focus(); - * - * TextField password = new TextField("Password"); - * loginBox.addField("password", password); - * - * Button login = new Button("Login"); - * loginBox.getFooter().addComponent(login); - * </pre> - * - * <p> - * Notice that this interface does not provide an accessor that would - * allow finding out the currently focused component. Focus information - * can be acquired for some (but not all) {@link Field} components - * through the {@link com.vaadin.event.FieldEvents.FocusListener} and - * {@link com.vaadin.event.FieldEvents.BlurListener} interfaces. - * </p> - * - * @see com.vaadin.event.FieldEvents - * @see com.vaadin.event.FieldEvents.FocusEvent - * @see com.vaadin.event.FieldEvents.FocusListener - * @see com.vaadin.event.FieldEvents.BlurEvent - * @see com.vaadin.event.FieldEvents.BlurListener - */ - public void focus(); - - /** - * Gets the <i>tabulator index</i> of the {@code Focusable} component. - * - * @return tab index set for the {@code Focusable} component - * @see #setTabIndex(int) - */ - public int getTabIndex(); - - /** - * Sets the <i>tabulator index</i> of the {@code Focusable} component. - * The tab index property is used to specify the order in which the - * fields are focused when the user presses the Tab key. Components with - * a defined tab index are focused sequentially first, and then the - * components with no tab index. - * - * <pre> - * Form loginBox = new Form(); - * loginBox.setCaption("Login"); - * layout.addComponent(loginBox); - * - * // Create the first field which will be focused - * TextField username = new TextField("User name"); - * loginBox.addField("username", username); - * - * // Set focus to the user name - * username.focus(); - * - * TextField password = new TextField("Password"); - * loginBox.addField("password", password); - * - * Button login = new Button("Login"); - * loginBox.getFooter().addComponent(login); - * - * // An additional component which natural focus order would - * // be after the button. - * CheckBox remember = new CheckBox("Remember me"); - * loginBox.getFooter().addComponent(remember); - * - * username.setTabIndex(1); - * password.setTabIndex(2); - * remember.setTabIndex(3); // Different than natural place - * login.setTabIndex(4); - * </pre> - * - * <p> - * After all focusable user interface components are done, the browser - * can begin again from the component with the smallest tab index, or it - * can take the focus out of the page, for example, to the location bar. - * </p> - * - * <p> - * If the tab index is not set (is set to zero), the default tab order - * is used. The order is somewhat browser-dependent, but generally - * follows the HTML structure of the page. - * </p> - * - * <p> - * A negative value means that the component is completely removed from - * the tabulation order and can not be reached by pressing the Tab key - * at all. - * </p> - * - * @param tabIndex - * the tab order of this component. Indexes usually start - * from 1. Zero means that default tab order should be used. - * A negative value means that the field should not be - * included in the tabbing sequence. - * @see #getTabIndex() - */ - public void setTabIndex(int tabIndex); - - } - -} diff --git a/src/com/vaadin/ui/ComponentContainer.java b/src/com/vaadin/ui/ComponentContainer.java deleted file mode 100644 index 8182d54b56..0000000000 --- a/src/com/vaadin/ui/ComponentContainer.java +++ /dev/null @@ -1,222 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; - -/** - * Extension to the {@link Component} interface which adds to it the capacity to - * contain other components. All UI elements that can have child elements - * implement this interface. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface ComponentContainer extends HasComponents { - - /** - * Adds the component into this container. - * - * @param c - * the component to be added. - */ - public void addComponent(Component c); - - /** - * Removes the component from this container. - * - * @param c - * the component to be removed. - */ - public void removeComponent(Component c); - - /** - * Removes all components from this container. - */ - public void removeAllComponents(); - - /** - * Replaces the component in the container with another one without changing - * position. - * - * <p> - * This method replaces component with another one is such way that the new - * component overtakes the position of the old component. If the old - * component is not in the container, the new component is added to the - * container. If the both component are already in the container, their - * positions are swapped. Component attach and detach events should be taken - * care as with add and remove. - * </p> - * - * @param oldComponent - * the old component that will be replaced. - * @param newComponent - * the new component to be replaced. - */ - public void replaceComponent(Component oldComponent, Component newComponent); - - /** - * Gets the number of children this {@link ComponentContainer} has. This - * must be symmetric with what {@link #getComponentIterator()} returns. - * - * @return The number of child components this container has. - * @since 7.0.0 - */ - public int getComponentCount(); - - /** - * Moves all components from an another container into this container. The - * components are removed from <code>source</code>. - * - * @param source - * the container which contains the components that are to be - * moved to this container. - */ - public void moveComponentsFrom(ComponentContainer source); - - /** - * Listens the component attach events. - * - * @param listener - * the listener to add. - */ - public void addListener(ComponentAttachListener listener); - - /** - * Stops the listening component attach events. - * - * @param listener - * the listener to removed. - */ - public void removeListener(ComponentAttachListener listener); - - /** - * Listens the component detach events. - */ - public void addListener(ComponentDetachListener listener); - - /** - * Stops the listening component detach events. - */ - public void removeListener(ComponentDetachListener listener); - - /** - * Component attach listener interface. - */ - public interface ComponentAttachListener extends Serializable { - - /** - * A new component is attached to container. - * - * @param event - * the component attach event. - */ - public void componentAttachedToContainer(ComponentAttachEvent event); - } - - /** - * Component detach listener interface. - */ - public interface ComponentDetachListener extends Serializable { - - /** - * A component has been detached from container. - * - * @param event - * the component detach event. - */ - public void componentDetachedFromContainer(ComponentDetachEvent event); - } - - /** - * Component attach event sent when a component is attached to container. - */ - @SuppressWarnings("serial") - public class ComponentAttachEvent extends Component.Event { - - private final Component component; - - /** - * Creates a new attach event. - * - * @param container - * the component container the component has been detached - * to. - * @param attachedComponent - * the component that has been attached. - */ - public ComponentAttachEvent(ComponentContainer container, - Component attachedComponent) { - super(container); - component = attachedComponent; - } - - /** - * Gets the component container. - * - * @param the - * component container. - */ - public ComponentContainer getContainer() { - return (ComponentContainer) getSource(); - } - - /** - * Gets the attached component. - * - * @param the - * attach component. - */ - public Component getAttachedComponent() { - return component; - } - } - - /** - * Component detach event sent when a component is detached from container. - */ - @SuppressWarnings("serial") - public class ComponentDetachEvent extends Component.Event { - - private final Component component; - - /** - * Creates a new detach event. - * - * @param container - * the component container the component has been detached - * from. - * @param detachedComponent - * the component that has been detached. - */ - public ComponentDetachEvent(ComponentContainer container, - Component detachedComponent) { - super(container); - component = detachedComponent; - } - - /** - * Gets the component container. - * - * @param the - * component container. - */ - public ComponentContainer getContainer() { - return (ComponentContainer) getSource(); - } - - /** - * Gets the detached component. - * - * @return the detached component. - */ - public Component getDetachedComponent() { - return component; - } - } - -} diff --git a/src/com/vaadin/ui/ConnectorTracker.java b/src/com/vaadin/ui/ConnectorTracker.java deleted file mode 100644 index e3d1bf86db..0000000000 --- a/src/com/vaadin/ui/ConnectorTracker.java +++ /dev/null @@ -1,320 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.terminal.AbstractClientConnector; -import com.vaadin.terminal.gwt.client.ServerConnector; -import com.vaadin.terminal.gwt.server.ClientConnector; - -/** - * A class which takes care of book keeping of {@link ClientConnector}s for a - * Root. - * <p> - * Provides {@link #getConnector(String)} which can be used to lookup a - * connector from its id. This is for framework use only and should not be - * needed in applications. - * </p> - * <p> - * Tracks which {@link ClientConnector}s are dirty so they can be updated to the - * client when the following response is sent. A connector is dirty when an - * operation has been performed on it on the server and as a result of this - * operation new information needs to be sent to its {@link ServerConnector}. - * </p> - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - * - */ -public class ConnectorTracker implements Serializable { - - private final HashMap<String, ClientConnector> connectorIdToConnector = new HashMap<String, ClientConnector>(); - private Set<ClientConnector> dirtyConnectors = new HashSet<ClientConnector>(); - - private Root root; - - /** - * Gets a logger for this class - * - * @return A logger instance for logging within this class - * - */ - public static Logger getLogger() { - return Logger.getLogger(ConnectorTracker.class.getName()); - } - - /** - * Creates a new ConnectorTracker for the given root. A tracker is always - * attached to a root and the root cannot be changed during the lifetime of - * a {@link ConnectorTracker}. - * - * @param root - * The root to attach to. Cannot be null. - */ - public ConnectorTracker(Root root) { - this.root = root; - } - - /** - * Register the given connector. - * <p> - * The lookup method {@link #getConnector(String)} only returns registered - * connectors. - * </p> - * - * @param connector - * The connector to register. - */ - public void registerConnector(ClientConnector connector) { - String connectorId = connector.getConnectorId(); - ClientConnector previouslyRegistered = connectorIdToConnector - .get(connectorId); - if (previouslyRegistered == null) { - connectorIdToConnector.put(connectorId, connector); - getLogger().fine( - "Registered " + connector.getClass().getSimpleName() + " (" - + connectorId + ")"); - } else if (previouslyRegistered != connector) { - throw new RuntimeException("A connector with id " + connectorId - + " is already registered!"); - } else { - getLogger().warning( - "An already registered connector was registered again: " - + connector.getClass().getSimpleName() + " (" - + connectorId + ")"); - } - - } - - /** - * Unregister the given connector. - * - * <p> - * The lookup method {@link #getConnector(String)} only returns registered - * connectors. - * </p> - * - * @param connector - * The connector to unregister - */ - public void unregisterConnector(ClientConnector connector) { - String connectorId = connector.getConnectorId(); - if (!connectorIdToConnector.containsKey(connectorId)) { - getLogger().warning( - "Tried to unregister " - + connector.getClass().getSimpleName() + " (" - + connectorId + ") which is not registered"); - return; - } - if (connectorIdToConnector.get(connectorId) != connector) { - throw new RuntimeException("The given connector with id " - + connectorId - + " is not the one that was registered for that id"); - } - - getLogger().fine( - "Unregistered " + connector.getClass().getSimpleName() + " (" - + connectorId + ")"); - connectorIdToConnector.remove(connectorId); - } - - /** - * Gets a connector by its id. - * - * @param connectorId - * The connector id to look for - * @return The connector with the given id or null if no connector has the - * given id - */ - public ClientConnector getConnector(String connectorId) { - return connectorIdToConnector.get(connectorId); - } - - /** - * Cleans the connector map from all connectors that are no longer attached - * to the application. This should only be called by the framework. - */ - public void cleanConnectorMap() { - // remove detached components from paintableIdMap so they - // can be GC'ed - Iterator<String> iterator = connectorIdToConnector.keySet().iterator(); - - while (iterator.hasNext()) { - String connectorId = iterator.next(); - ClientConnector connector = connectorIdToConnector.get(connectorId); - if (getRootForConnector(connector) != root) { - // If connector is no longer part of this root, - // remove it from the map. If it is re-attached to the - // application at some point it will be re-added through - // registerConnector(connector) - - // This code should never be called as cleanup should take place - // in detach() - getLogger() - .warning( - "cleanConnectorMap unregistered connector " - + getConnectorAndParentInfo(connector) - + "). This should have been done when the connector was detached."); - iterator.remove(); - } - } - - } - - /** - * Finds the root that the connector is attached to. - * - * @param connector - * The connector to lookup - * @return The root the connector is attached to or null if it is not - * attached to any root. - */ - private Root getRootForConnector(ClientConnector connector) { - if (connector == null) { - return null; - } - if (connector instanceof Component) { - return ((Component) connector).getRoot(); - } - - return getRootForConnector(connector.getParent()); - } - - /** - * Mark the connector as dirty. - * - * @see #getDirtyConnectors() - * - * @param connector - * The connector that should be marked clean. - */ - public void markDirty(ClientConnector connector) { - if (getLogger().isLoggable(Level.FINE)) { - if (!dirtyConnectors.contains(connector)) { - getLogger().fine( - getConnectorAndParentInfo(connector) + " " - + "is now dirty"); - } - } - - dirtyConnectors.add(connector); - } - - /** - * Mark the connector as clean. - * - * @param connector - * The connector that should be marked clean. - */ - public void markClean(ClientConnector connector) { - if (getLogger().isLoggable(Level.FINE)) { - if (dirtyConnectors.contains(connector)) { - getLogger().fine( - getConnectorAndParentInfo(connector) + " " - + "is no longer dirty"); - } - } - - dirtyConnectors.remove(connector); - } - - /** - * Returns {@link #getConnectorString(ClientConnector)} for the connector - * and its parent (if it has a parent). - * - * @param connector - * The connector - * @return A string describing the connector and its parent - */ - private String getConnectorAndParentInfo(ClientConnector connector) { - String message = getConnectorString(connector); - if (connector.getParent() != null) { - message += " (parent: " + getConnectorString(connector.getParent()) - + ")"; - } - return message; - } - - /** - * Returns a string with the connector name and id. Useful mostly for - * debugging and logging. - * - * @param connector - * The connector - * @return A string that describes the connector - */ - private String getConnectorString(ClientConnector connector) { - if (connector == null) { - return "(null)"; - } - - String connectorId; - try { - connectorId = connector.getConnectorId(); - } catch (RuntimeException e) { - // This happens if the connector is not attached to the application. - // SHOULD not happen in this case but theoretically can. - connectorId = "@" + Integer.toHexString(connector.hashCode()); - } - return connector.getClass().getName() + "(" + connectorId + ")"; - } - - /** - * Mark all connectors in this root as dirty. - */ - public void markAllConnectorsDirty() { - markConnectorsDirtyRecursively(root); - getLogger().fine("All connectors are now dirty"); - } - - /** - * Mark all connectors in this root as clean. - */ - public void markAllConnectorsClean() { - dirtyConnectors.clear(); - getLogger().fine("All connectors are now clean"); - } - - /** - * Marks all visible connectors dirty, starting from the given connector and - * going downwards in the hierarchy. - * - * @param c - * The component to start iterating downwards from - */ - private void markConnectorsDirtyRecursively(ClientConnector c) { - if (c instanceof Component && !((Component) c).isVisible()) { - return; - } - markDirty(c); - for (ClientConnector child : AbstractClientConnector - .getAllChildrenIterable(c)) { - markConnectorsDirtyRecursively(child); - } - } - - /** - * Returns a collection of all connectors which have been marked as dirty. - * <p> - * The state and pending RPC calls for dirty connectors are sent to the - * client in the following request. - * </p> - * - * @return A collection of all dirty connectors for this root. This list may - * contain invisible connectors. - */ - public Collection<ClientConnector> getDirtyConnectors() { - return dirtyConnectors; - } - -} diff --git a/src/com/vaadin/ui/CssLayout.java b/src/com/vaadin/ui/CssLayout.java deleted file mode 100644 index 356f0a3843..0000000000 --- a/src/com/vaadin/ui/CssLayout.java +++ /dev/null @@ -1,308 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.util.Iterator; -import java.util.LinkedList; - -import com.vaadin.event.LayoutEvents.LayoutClickEvent; -import com.vaadin.event.LayoutEvents.LayoutClickListener; -import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.shared.Connector; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.csslayout.CssLayoutServerRpc; -import com.vaadin.shared.ui.csslayout.CssLayoutState; -import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; - -/** - * CssLayout is a layout component that can be used in browser environment only. - * It simply renders components and their captions into a same div element. - * Component layout can then be adjusted with css. - * <p> - * In comparison to {@link HorizontalLayout} and {@link VerticalLayout} - * <ul> - * <li>rather similar server side api - * <li>no spacing, alignment or expand ratios - * <li>much simpler DOM that can be styled by skilled web developer - * <li>no abstraction of browser differences (developer must ensure that the - * result works properly on each browser) - * <li>different kind of handling for relative sizes (that are set from server - * side) (*) - * <li>noticeably faster rendering time in some situations as we rely more on - * the browser's rendering engine. - * </ul> - * <p> - * With {@link CustomLayout} one can often achieve similar results (good looking - * layouts with web technologies), but with CustomLayout developer needs to work - * with fixed templates. - * <p> - * By extending CssLayout one can also inject some css rules straight to child - * components using {@link #getCss(Component)}. - * - * <p> - * (*) Relative sizes (set from server side) are treated bit differently than in - * other layouts in Vaadin. In cssLayout the size is calculated relatively to - * CSS layouts content area which is pretty much as in html and css. In other - * layouts the size of component is calculated relatively to the "slot" given by - * layout. - * <p> - * Also note that client side framework in Vaadin modifies inline style - * properties width and height. This happens on each update to component. If one - * wants to set component sizes with CSS, component must have undefined size on - * server side (which is not the default for all components) and the size must - * be defined with class styles - not by directly injecting width and height. - * - * @since 6.1 brought in from "FastLayouts" incubator project - * - */ -public class CssLayout extends AbstractLayout implements LayoutClickNotifier { - - private CssLayoutServerRpc rpc = new CssLayoutServerRpc() { - - @Override - public void layoutClick(MouseEventDetails mouseDetails, - Connector clickedConnector) { - fireEvent(LayoutClickEvent.createEvent(CssLayout.this, - mouseDetails, clickedConnector)); - } - }; - /** - * Custom layout slots containing the components. - */ - protected LinkedList<Component> components = new LinkedList<Component>(); - - public CssLayout() { - registerRpc(rpc); - } - - /** - * Add a component into this container. The component is added to the right - * or under the previous component. - * - * @param c - * the component to be added. - */ - @Override - public void addComponent(Component c) { - // Add to components before calling super.addComponent - // so that it is available to AttachListeners - components.add(c); - try { - super.addComponent(c); - requestRepaint(); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - } - - /** - * Adds a component into this container. The component is added to the left - * or on top of the other components. - * - * @param c - * the component to be added. - */ - public void addComponentAsFirst(Component c) { - // If c is already in this, we must remove it before proceeding - // see ticket #7668 - if (c.getParent() == this) { - removeComponent(c); - } - components.addFirst(c); - try { - super.addComponent(c); - requestRepaint(); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - } - - /** - * Adds a component into indexed position in this container. - * - * @param c - * the component to be added. - * @param index - * the index of the component position. The components currently - * in and after the position are shifted forwards. - */ - public void addComponent(Component c, int index) { - // If c is already in this, we must remove it before proceeding - // see ticket #7668 - if (c.getParent() == this) { - // When c is removed, all components after it are shifted down - if (index > getComponentIndex(c)) { - index--; - } - removeComponent(c); - } - components.add(index, c); - try { - super.addComponent(c); - requestRepaint(); - } catch (IllegalArgumentException e) { - components.remove(c); - throw e; - } - } - - /** - * Removes the component from this container. - * - * @param c - * the component to be removed. - */ - @Override - public void removeComponent(Component c) { - components.remove(c); - super.removeComponent(c); - requestRepaint(); - } - - /** - * Gets the component container iterator for going trough all the components - * in the container. - * - * @return the Iterator of the components inside the container. - */ - @Override - public Iterator<Component> getComponentIterator() { - return components.iterator(); - } - - /** - * Gets the number of contained components. Consistent with the iterator - * returned by {@link #getComponentIterator()}. - * - * @return the number of contained components - */ - @Override - public int getComponentCount() { - return components.size(); - } - - @Override - public void updateState() { - super.updateState(); - getState().getChildCss().clear(); - for (Iterator<Component> ci = getComponentIterator(); ci.hasNext();) { - Component child = ci.next(); - String componentCssString = getCss(child); - if (componentCssString != null) { - getState().getChildCss().put(child, componentCssString); - } - - } - } - - @Override - public CssLayoutState getState() { - return (CssLayoutState) super.getState(); - } - - /** - * Returns styles to be applied to given component. Override this method to - * inject custom style rules to components. - * - * <p> - * Note that styles are injected over previous styles before actual child - * rendering. Previous styles are not cleared, but overridden. - * - * <p> - * Note that one most often achieves better code style, by separating - * styling to theme (with custom theme and {@link #addStyleName(String)}. - * With own custom styles it is also very easy to break browser - * compatibility. - * - * @param c - * the component - * @return css rules to be applied to component - */ - protected String getCss(Component c) { - return null; - } - - /* Documented in superclass */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - - // Gets the locations - int oldLocation = -1; - int newLocation = -1; - int location = 0; - for (final Iterator<Component> i = components.iterator(); i.hasNext();) { - final Component component = i.next(); - - if (component == oldComponent) { - oldLocation = location; - } - if (component == newComponent) { - newLocation = location; - } - - location++; - } - - if (oldLocation == -1) { - addComponent(newComponent); - } else if (newLocation == -1) { - removeComponent(oldComponent); - addComponent(newComponent, oldLocation); - } else { - if (oldLocation > newLocation) { - components.remove(oldComponent); - components.add(newLocation, oldComponent); - components.remove(newComponent); - components.add(oldLocation, newComponent); - } else { - components.remove(newComponent); - components.add(oldLocation, newComponent); - components.remove(oldComponent); - components.add(newLocation, oldComponent); - } - - requestRepaint(); - } - } - - @Override - public void addListener(LayoutClickListener listener) { - addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener, - LayoutClickListener.clickMethod); - } - - @Override - public void removeListener(LayoutClickListener listener) { - removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener); - } - - /** - * Returns the index of the given component. - * - * @param component - * The component to look up. - * @return The index of the component or -1 if the component is not a child. - */ - public int getComponentIndex(Component component) { - return components.indexOf(component); - } - - /** - * Returns the component at the given position. - * - * @param index - * The position of the component. - * @return The component at the given index. - * @throws IndexOutOfBoundsException - * If the index is out of range. - */ - public Component getComponent(int index) throws IndexOutOfBoundsException { - return components.get(index); - } - -} diff --git a/src/com/vaadin/ui/CustomComponent.java b/src/com/vaadin/ui/CustomComponent.java deleted file mode 100644 index 40b5dcd636..0000000000 --- a/src/com/vaadin/ui/CustomComponent.java +++ /dev/null @@ -1,189 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.Iterator; - -/** - * Custom component provides simple implementation of Component interface for - * creation of new UI components by composition of existing components. - * <p> - * The component is used by inheriting the CustomComponent class and setting - * composite root inside the Custom component. The composite root itself can - * contain more components, but their interfaces are hidden from the users. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class CustomComponent extends AbstractComponentContainer { - - /** - * The root component implementing the custom component. - */ - private Component root = null; - - /** - * Constructs a new custom component. - * - * <p> - * The component is implemented by wrapping the methods of the composition - * root component given as parameter. The composition root must be set - * before the component can be used. - * </p> - */ - public CustomComponent() { - // expand horizontally by default - setWidth(100, UNITS_PERCENTAGE); - } - - /** - * Constructs a new custom component. - * - * <p> - * The component is implemented by wrapping the methods of the composition - * root component given as parameter. The composition root must not be null - * and can not be changed after the composition. - * </p> - * - * @param compositionRoot - * the root of the composition component tree. - */ - public CustomComponent(Component compositionRoot) { - this(); - setCompositionRoot(compositionRoot); - } - - /** - * Returns the composition root. - * - * @return the Component Composition root. - */ - protected Component getCompositionRoot() { - return root; - } - - /** - * Sets the compositions root. - * <p> - * The composition root must be set to non-null value before the component - * can be used. The composition root can only be set once. - * </p> - * - * @param compositionRoot - * the root of the composition component tree. - */ - protected void setCompositionRoot(Component compositionRoot) { - if (compositionRoot != root) { - if (root != null) { - // remove old component - super.removeComponent(root); - } - if (compositionRoot != null) { - // set new component - super.addComponent(compositionRoot); - } - root = compositionRoot; - requestRepaint(); - } - } - - /* Basic component features ------------------------------------------ */ - - private class ComponentIterator implements Iterator<Component>, - Serializable { - boolean first = getCompositionRoot() != null; - - @Override - public boolean hasNext() { - return first; - } - - @Override - public Component next() { - first = false; - return root; - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - @Override - public Iterator<Component> getComponentIterator() { - return new ComponentIterator(); - } - - /** - * Gets the number of contained components. Consistent with the iterator - * returned by {@link #getComponentIterator()}. - * - * @return the number of contained components (zero or one) - */ - @Override - public int getComponentCount() { - return (root != null ? 1 : 0); - } - - /** - * This method is not supported by CustomComponent. - * - * @see com.vaadin.ui.ComponentContainer#replaceComponent(com.vaadin.ui.Component, - * com.vaadin.ui.Component) - */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - throw new UnsupportedOperationException(); - } - - /** - * This method is not supported by CustomComponent. Use - * {@link CustomComponent#setCompositionRoot(Component)} to set - * CustomComponents "child". - * - * @see com.vaadin.ui.AbstractComponentContainer#addComponent(com.vaadin.ui.Component) - */ - @Override - public void addComponent(Component c) { - throw new UnsupportedOperationException(); - } - - /** - * This method is not supported by CustomComponent. - * - * @see com.vaadin.ui.AbstractComponentContainer#moveComponentsFrom(com.vaadin.ui.ComponentContainer) - */ - @Override - public void moveComponentsFrom(ComponentContainer source) { - throw new UnsupportedOperationException(); - } - - /** - * This method is not supported by CustomComponent. - * - * @see com.vaadin.ui.AbstractComponentContainer#removeAllComponents() - */ - @Override - public void removeAllComponents() { - throw new UnsupportedOperationException(); - } - - /** - * This method is not supported by CustomComponent. - * - * @see com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui.Component) - */ - @Override - public void removeComponent(Component c) { - throw new UnsupportedOperationException(); - } - -} diff --git a/src/com/vaadin/ui/CustomField.java b/src/com/vaadin/ui/CustomField.java deleted file mode 100644 index ab3797a58c..0000000000 --- a/src/com/vaadin/ui/CustomField.java +++ /dev/null @@ -1,237 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Iterator; - -import com.vaadin.data.Property; - -/** - * A {@link Field} whose UI content can be constructed by the user, enabling the - * creation of e.g. form fields by composing Vaadin components. Customization of - * both the visual presentation and the logic of the field is possible. - * - * Subclasses must implement {@link #getType()} and {@link #initContent()}. - * - * Most custom fields can simply compose a user interface that calls the methods - * {@link #setInternalValue(Object)} and {@link #getInternalValue()} when - * necessary. - * - * It is also possible to override {@link #validate()}, - * {@link #setInternalValue(Object)}, {@link #commit()}, - * {@link #setPropertyDataSource(Property)}, {@link #isEmpty()} and other logic - * of the field. Methods overriding {@link #setInternalValue(Object)} should - * also call the corresponding superclass method. - * - * @param <T> - * field value type - * - * @since 7.0 - */ -public abstract class CustomField<T> extends AbstractField<T> implements - ComponentContainer { - - /** - * The root component implementing the custom component. - */ - private Component root = null; - - /** - * Constructs a new custom field. - * - * <p> - * The component is implemented by wrapping the methods of the composition - * root component given as parameter. The composition root must be set - * before the component can be used. - * </p> - */ - public CustomField() { - // expand horizontally by default - setWidth(100, Unit.PERCENTAGE); - } - - /** - * Constructs the content and notifies it that the {@link CustomField} is - * attached to a window. - * - * @see com.vaadin.ui.Component#attach() - */ - @Override - public void attach() { - // First call super attach to notify all children (none if content has - // not yet been created) - super.attach(); - - // If the content has not yet been created, we create and attach it at - // this point. - if (root == null) { - // Ensure content is created and its parent is set. - // The getContent() call creates the content and attaches the - // content - fireComponentAttachEvent(getContent()); - } - } - - /** - * Returns the content (UI) of the custom component. - * - * @return Component - */ - protected Component getContent() { - if (null == root) { - root = initContent(); - root.setParent(this); - } - return root; - } - - /** - * Create the content component or layout for the field. Subclasses of - * {@link CustomField} should implement this method. - * - * Note that this method is called when the CustomField is attached to a - * layout or when {@link #getContent()} is called explicitly for the first - * time. It is only called once for a {@link CustomField}. - * - * @return {@link Component} representing the UI of the CustomField - */ - protected abstract Component initContent(); - - // Size related methods - // TODO might not be necessary to override but following the pattern from - // AbstractComponentContainer - - @Override - public void setHeight(float height, Unit unit) { - super.setHeight(height, unit); - requestRepaintAll(); - } - - @Override - public void setWidth(float height, Unit unit) { - super.setWidth(height, unit); - requestRepaintAll(); - } - - // ComponentContainer methods - - private class ComponentIterator implements Iterator<Component>, - Serializable { - boolean first = (root != null); - - @Override - public boolean hasNext() { - return first; - } - - @Override - public Component next() { - first = false; - return getContent(); - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - @Override - public Iterator<Component> getComponentIterator() { - return new ComponentIterator(); - } - - @Override - public Iterator<Component> iterator() { - return getComponentIterator(); - } - - @Override - public int getComponentCount() { - return (null != getContent()) ? 1 : 0; - } - - /** - * Fires the component attached event. This should be called by the - * addComponent methods after the component have been added to this - * container. - * - * @param component - * the component that has been added to this container. - */ - protected void fireComponentAttachEvent(Component component) { - fireEvent(new ComponentAttachEvent(this, component)); - } - - // TODO remove these methods when ComponentContainer interface is cleaned up - - @Override - public void addComponent(Component c) { - throw new UnsupportedOperationException(); - } - - @Override - public void removeComponent(Component c) { - throw new UnsupportedOperationException(); - } - - @Override - public void removeAllComponents() { - throw new UnsupportedOperationException(); - } - - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - throw new UnsupportedOperationException(); - } - - @Override - public void moveComponentsFrom(ComponentContainer source) { - throw new UnsupportedOperationException(); - } - - private static final Method COMPONENT_ATTACHED_METHOD; - - static { - try { - COMPONENT_ATTACHED_METHOD = ComponentAttachListener.class - .getDeclaredMethod("componentAttachedToContainer", - new Class[] { ComponentAttachEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in CustomField"); - } - } - - @Override - public void addListener(ComponentAttachListener listener) { - addListener(ComponentContainer.ComponentAttachEvent.class, listener, - COMPONENT_ATTACHED_METHOD); - } - - @Override - public void removeListener(ComponentAttachListener listener) { - removeListener(ComponentContainer.ComponentAttachEvent.class, listener, - COMPONENT_ATTACHED_METHOD); - } - - @Override - public void addListener(ComponentDetachListener listener) { - // content never detached - } - - @Override - public void removeListener(ComponentDetachListener listener) { - // content never detached - } - - @Override - public boolean isComponentVisible(Component childComponent) { - return true; - } -} diff --git a/src/com/vaadin/ui/CustomLayout.java b/src/com/vaadin/ui/CustomLayout.java deleted file mode 100644 index d7830603f0..0000000000 --- a/src/com/vaadin/ui/CustomLayout.java +++ /dev/null @@ -1,329 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.vaadin.shared.ui.customlayout.CustomLayoutState; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.server.JsonPaintTarget; - -/** - * <p> - * A container component with freely designed layout and style. The layout - * consists of items with textually represented locations. Each item contains - * one sub-component, which can be any Vaadin component, such as a layout. The - * adapter and theme are responsible for rendering the layout with a given style - * by placing the items in the defined locations. - * </p> - * - * <p> - * The placement of the locations is not fixed - different themes can define the - * locations in a way that is suitable for them. One typical example would be to - * create visual design for a web site as a custom layout: the visual design - * would define locations for "menu", "body", and "title", for example. The - * layout would then be implemented as an XHTML template for each theme. - * </p> - * - * <p> - * The default theme handles the styles that are not defined by drawing the - * subcomponents just as in OrderedLayout. - * </p> - * - * @author Vaadin Ltd. - * @author Duy B. Vo (<a - * href="mailto:devduy@gmail.com?subject=Vaadin">devduy@gmail.com</a>) - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class CustomLayout extends AbstractLayout implements Vaadin6Component { - - private static final int BUFFER_SIZE = 10000; - - /** - * Custom layout slots containing the components. - */ - private final HashMap<String, Component> slots = new HashMap<String, Component>(); - - /** - * Default constructor only used by subclasses. Subclasses are responsible - * for setting the appropriate fields. Either - * {@link #setTemplateName(String)}, that makes layout fetch the template - * from theme, or {@link #setTemplateContents(String)}. - */ - protected CustomLayout() { - setWidth(100, UNITS_PERCENTAGE); - } - - /** - * Constructs a custom layout with the template given in the stream. - * - * @param templateStream - * Stream containing template data. Must be using UTF-8 encoding. - * To use a String as a template use for instance new - * ByteArrayInputStream("<template>".getBytes()). - * @param streamLength - * Length of the templateStream - * @throws IOException - */ - public CustomLayout(InputStream templateStream) throws IOException { - this(); - initTemplateContentsFromInputStream(templateStream); - } - - /** - * Constructor for custom layout with given template name. Template file is - * fetched from "<theme>/layout/<templateName>". - */ - public CustomLayout(String template) { - this(); - setTemplateName(template); - } - - protected void initTemplateContentsFromInputStream( - InputStream templateStream) throws IOException { - InputStreamReader reader = new InputStreamReader(templateStream, - "UTF-8"); - StringBuilder b = new StringBuilder(BUFFER_SIZE); - - char[] cbuf = new char[BUFFER_SIZE]; - int offset = 0; - - while (true) { - int nrRead = reader.read(cbuf, offset, BUFFER_SIZE); - b.append(cbuf, 0, nrRead); - if (nrRead < BUFFER_SIZE) { - break; - } - } - - setTemplateContents(b.toString()); - } - - @Override - public CustomLayoutState getState() { - return (CustomLayoutState) super.getState(); - } - - /** - * Adds the component into this container to given location. If the location - * is already populated, the old component is removed. - * - * @param c - * the component to be added. - * @param location - * the location of the component. - */ - public void addComponent(Component c, String location) { - final Component old = slots.get(location); - if (old != null) { - removeComponent(old); - } - slots.put(location, c); - getState().getChildLocations().put(c, location); - c.setParent(this); - fireComponentAttachEvent(c); - requestRepaint(); - } - - /** - * Adds the component into this container. The component is added without - * specifying the location (empty string is then used as location). Only one - * component can be added to the default "" location and adding more - * components into that location overwrites the old components. - * - * @param c - * the component to be added. - */ - @Override - public void addComponent(Component c) { - this.addComponent(c, ""); - } - - /** - * Removes the component from this container. - * - * @param c - * the component to be removed. - */ - @Override - public void removeComponent(Component c) { - if (c == null) { - return; - } - slots.values().remove(c); - getState().getChildLocations().remove(c); - super.removeComponent(c); - requestRepaint(); - } - - /** - * Removes the component from this container from given location. - * - * @param location - * the Location identifier of the component. - */ - public void removeComponent(String location) { - this.removeComponent(slots.get(location)); - } - - /** - * Gets the component container iterator for going trough all the components - * in the container. - * - * @return the Iterator of the components inside the container. - */ - @Override - public Iterator<Component> getComponentIterator() { - return slots.values().iterator(); - } - - /** - * Gets the number of contained components. Consistent with the iterator - * returned by {@link #getComponentIterator()}. - * - * @return the number of contained components - */ - @Override - public int getComponentCount() { - return slots.values().size(); - } - - /** - * Gets the child-component by its location. - * - * @param location - * the name of the location where the requested component - * resides. - * @return the Component in the given location or null if not found. - */ - public Component getComponent(String location) { - return slots.get(location); - } - - /* Documented in superclass */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - - // Gets the locations - String oldLocation = null; - String newLocation = null; - for (final Iterator<String> i = slots.keySet().iterator(); i.hasNext();) { - final String location = i.next(); - final Component component = slots.get(location); - if (component == oldComponent) { - oldLocation = location; - } - if (component == newComponent) { - newLocation = location; - } - } - - if (oldLocation == null) { - addComponent(newComponent); - } else if (newLocation == null) { - removeComponent(oldLocation); - addComponent(newComponent, oldLocation); - } else { - slots.put(newLocation, oldComponent); - slots.put(oldLocation, newComponent); - getState().getChildLocations().put(newComponent, oldLocation); - getState().getChildLocations().put(oldComponent, newLocation); - requestRepaint(); - } - } - - /** Get the name of the template */ - public String getTemplateName() { - return getState().getTemplateName(); - } - - /** Get the contents of the template */ - public String getTemplateContents() { - return getState().getTemplateContents(); - } - - /** - * Set the name of the template used to draw custom layout. - * - * With GWT-adapter, the template with name 'templatename' is loaded from - * VAADIN/themes/themename/layouts/templatename.html. If the theme has not - * been set (with Application.setTheme()), themename is 'default'. - * - * @param templateName - */ - public void setTemplateName(String templateName) { - getState().setTemplateName(templateName); - getState().setTemplateContents(null); - requestRepaint(); - } - - /** - * Set the contents of the template used to draw the custom layout. - * - * @param templateContents - */ - public void setTemplateContents(String templateContents) { - getState().setTemplateContents(templateContents); - getState().setTemplateName(null); - requestRepaint(); - } - - /** - * Although most layouts support margins, CustomLayout does not. The - * behaviour of this layout is determined almost completely by the actual - * template. - * - * @throws UnsupportedOperationException - */ - @Override - public void setMargin(boolean enabled) { - throw new UnsupportedOperationException( - "CustomLayout does not support margins."); - } - - /** - * Although most layouts support margins, CustomLayout does not. The - * behaviour of this layout is determined almost completely by the actual - * template. - * - * @throws UnsupportedOperationException - */ - @Override - public void setMargin(boolean topEnabled, boolean rightEnabled, - boolean bottomEnabled, boolean leftEnabled) { - throw new UnsupportedOperationException( - "CustomLayout does not support margins."); - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // Nothing to see here - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - // Workaround to make the CommunicationManager read the template file - // and send it to the client - String templateName = getState().getTemplateName(); - if (templateName != null && templateName.length() != 0) { - Set<Object> usedResources = ((JsonPaintTarget) target) - .getUsedResources(); - String resourceName = "layouts/" + templateName + ".html"; - usedResources.add(resourceName); - } - } - -} diff --git a/src/com/vaadin/ui/DateField.java b/src/com/vaadin/ui/DateField.java deleted file mode 100644 index d0a22f3c29..0000000000 --- a/src/com/vaadin/ui/DateField.java +++ /dev/null @@ -1,869 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; - -import com.vaadin.data.Property; -import com.vaadin.data.Validator; -import com.vaadin.data.Validator.InvalidValueException; -import com.vaadin.data.util.converter.Converter; -import com.vaadin.event.FieldEvents; -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.datefield.VDateField; - -/** - * <p> - * A date editor component that can be bound to any {@link Property} that is - * compatible with <code>java.util.Date</code>. - * </p> - * <p> - * Since <code>DateField</code> extends <code>AbstractField</code> it implements - * the {@link com.vaadin.data.Buffered}interface. - * </p> - * <p> - * A <code>DateField</code> is in write-through mode by default, so - * {@link com.vaadin.ui.AbstractField#setWriteThrough(boolean)}must be called to - * enable buffering. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class DateField extends AbstractField<Date> implements - FieldEvents.BlurNotifier, FieldEvents.FocusNotifier, Vaadin6Component { - - /** - * Resolutions for DateFields - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 7.0 - */ - public enum Resolution { - SECOND(Calendar.SECOND), MINUTE(Calendar.MINUTE), HOUR( - Calendar.HOUR_OF_DAY), DAY(Calendar.DAY_OF_MONTH), MONTH( - Calendar.MONTH), YEAR(Calendar.YEAR); - - private int calendarField; - - private Resolution(int calendarField) { - this.calendarField = calendarField; - } - - /** - * Returns the field in {@link Calendar} that corresponds to this - * resolution. - * - * @return one of the field numbers used by Calendar - */ - public int getCalendarField() { - return calendarField; - } - - /** - * Returns the resolutions that are higher or equal to the given - * resolution, starting from the given resolution. In other words - * passing DAY to this methods returns DAY,MONTH,YEAR - * - * @param r - * The resolution to start from - * @return An iterable for the resolutions higher or equal to r - */ - public static Iterable<Resolution> getResolutionsHigherOrEqualTo( - Resolution r) { - List<Resolution> resolutions = new ArrayList<DateField.Resolution>(); - Resolution[] values = Resolution.values(); - for (int i = r.ordinal(); i < values.length; i++) { - resolutions.add(values[i]); - } - return resolutions; - } - - /** - * Returns the resolutions that are lower than the given resolution, - * starting from the given resolution. In other words passing DAY to - * this methods returns HOUR,MINUTE,SECOND. - * - * @param r - * The resolution to start from - * @return An iterable for the resolutions lower than r - */ - public static List<Resolution> getResolutionsLowerThan(Resolution r) { - List<Resolution> resolutions = new ArrayList<DateField.Resolution>(); - Resolution[] values = Resolution.values(); - for (int i = r.ordinal() - 1; i >= 0; i--) { - resolutions.add(values[i]); - } - return resolutions; - } - }; - - /** - * Resolution identifier: seconds. - * - * @deprecated Use {@link Resolution#SECOND} - */ - @Deprecated - public static final Resolution RESOLUTION_SEC = Resolution.SECOND; - - /** - * Resolution identifier: minutes. - * - * @deprecated Use {@link Resolution#MINUTE} - */ - @Deprecated - public static final Resolution RESOLUTION_MIN = Resolution.MINUTE; - - /** - * Resolution identifier: hours. - * - * @deprecated Use {@link Resolution#HOUR} - */ - @Deprecated - public static final Resolution RESOLUTION_HOUR = Resolution.HOUR; - - /** - * Resolution identifier: days. - * - * @deprecated Use {@link Resolution#DAY} - */ - @Deprecated - public static final Resolution RESOLUTION_DAY = Resolution.DAY; - - /** - * Resolution identifier: months. - * - * @deprecated Use {@link Resolution#MONTH} - */ - @Deprecated - public static final Resolution RESOLUTION_MONTH = Resolution.MONTH; - - /** - * Resolution identifier: years. - * - * @deprecated Use {@link Resolution#YEAR} - */ - @Deprecated - public static final Resolution RESOLUTION_YEAR = Resolution.YEAR; - - /** - * Specified smallest modifiable unit for the date field. - */ - private Resolution resolution = Resolution.DAY; - - /** - * The internal calendar to be used in java.utl.Date conversions. - */ - private transient Calendar calendar; - - /** - * Overridden format string - */ - private String dateFormat; - - private boolean lenient = false; - - private String dateString = null; - - /** - * Was the last entered string parsable? If this flag is false, datefields - * internal validator does not pass. - */ - private boolean uiHasValidDateString = true; - - /** - * Determines if week numbers are shown in the date selector. - */ - private boolean showISOWeekNumbers = false; - - private String currentParseErrorMessage; - - private String defaultParseErrorMessage = "Date format not recognized"; - - private TimeZone timeZone = null; - - private static Map<Resolution, String> variableNameForResolution = new HashMap<DateField.Resolution, String>(); - { - variableNameForResolution.put(Resolution.SECOND, "sec"); - variableNameForResolution.put(Resolution.MINUTE, "min"); - variableNameForResolution.put(Resolution.HOUR, "hour"); - variableNameForResolution.put(Resolution.DAY, "day"); - variableNameForResolution.put(Resolution.MONTH, "month"); - variableNameForResolution.put(Resolution.YEAR, "year"); - } - - /* Constructors */ - - /** - * Constructs an empty <code>DateField</code> with no caption. - */ - public DateField() { - } - - /** - * Constructs an empty <code>DateField</code> with caption. - * - * @param caption - * the caption of the datefield. - */ - public DateField(String caption) { - setCaption(caption); - } - - /** - * Constructs a new <code>DateField</code> that's bound to the specified - * <code>Property</code> and has the given caption <code>String</code>. - * - * @param caption - * the caption <code>String</code> for the editor. - * @param dataSource - * the Property to be edited with this editor. - */ - public DateField(String caption, Property dataSource) { - this(dataSource); - setCaption(caption); - } - - /** - * Constructs a new <code>DateField</code> that's bound to the specified - * <code>Property</code> and has no caption. - * - * @param dataSource - * the Property to be edited with this editor. - */ - public DateField(Property dataSource) throws IllegalArgumentException { - if (!Date.class.isAssignableFrom(dataSource.getType())) { - throw new IllegalArgumentException("Can't use " - + dataSource.getType().getName() - + " typed property as datasource"); - } - - setPropertyDataSource(dataSource); - } - - /** - * Constructs a new <code>DateField</code> with the given caption and - * initial text contents. The editor constructed this way will not be bound - * to a Property unless - * {@link com.vaadin.data.Property.Viewer#setPropertyDataSource(Property)} - * is called to bind it. - * - * @param caption - * the caption <code>String</code> for the editor. - * @param value - * the Date value. - */ - public DateField(String caption, Date value) { - setValue(value); - setCaption(caption); - } - - /* Component basic features */ - - /* - * Paints this component. Don't add a JavaDoc comment here, we use the - * default documentation from implemented interface. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - - // Adds the locale as attribute - final Locale l = getLocale(); - if (l != null) { - target.addAttribute("locale", l.toString()); - } - - if (getDateFormat() != null) { - target.addAttribute("format", dateFormat); - } - - if (!isLenient()) { - target.addAttribute("strict", true); - } - - target.addAttribute(VDateField.WEEK_NUMBERS, isShowISOWeekNumbers()); - target.addAttribute("parsable", uiHasValidDateString); - /* - * TODO communicate back the invalid date string? E.g. returning back to - * app or refresh. - */ - - // Gets the calendar - final Calendar calendar = getCalendar(); - final Date currentDate = getValue(); - - // Only paint variables for the resolution and up, e.g. Resolution DAY - // paints DAY,MONTH,YEAR - for (Resolution res : Resolution - .getResolutionsHigherOrEqualTo(resolution)) { - int value = -1; - if (currentDate != null) { - value = calendar.get(res.getCalendarField()); - if (res == Resolution.MONTH) { - // Calendar month is zero based - value++; - } - } - target.addVariable(this, variableNameForResolution.get(res), value); - } - } - - @Override - protected boolean shouldHideErrors() { - return super.shouldHideErrors() && uiHasValidDateString; - } - - /* - * Invoked when a variable of the component changes. Don't add a JavaDoc - * comment here, we use the default documentation from implemented - * interface. - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - - if (!isReadOnly() - && (variables.containsKey("year") - || variables.containsKey("month") - || variables.containsKey("day") - || variables.containsKey("hour") - || variables.containsKey("min") - || variables.containsKey("sec") - || variables.containsKey("msec") || variables - .containsKey("dateString"))) { - - // Old and new dates - final Date oldDate = getValue(); - Date newDate = null; - - // this enables analyzing invalid input on the server - final String newDateString = (String) variables.get("dateString"); - dateString = newDateString; - - // Gets the new date in parts - boolean hasChanges = false; - Map<Resolution, Integer> calendarFieldChanges = new HashMap<DateField.Resolution, Integer>(); - - for (Resolution r : Resolution - .getResolutionsHigherOrEqualTo(resolution)) { - // Only handle what the client is allowed to send. The same - // resolutions that are painted - String variableName = variableNameForResolution.get(r); - - if (variables.containsKey(variableName)) { - Integer value = (Integer) variables.get(variableName); - if (r == Resolution.MONTH) { - // Calendar MONTH is zero based - value--; - } - if (value >= 0) { - hasChanges = true; - calendarFieldChanges.put(r, value); - } - } - } - - // If no new variable values were received, use the previous value - if (!hasChanges) { - newDate = null; - } else { - // Clone the calendar for date operation - final Calendar cal = getCalendar(); - - // Update the value based on the received info - // Must set in this order to avoid invalid dates (or wrong - // dates if lenient is true) in calendar - for (int r = Resolution.YEAR.ordinal(); r >= 0; r--) { - Resolution res = Resolution.values()[r]; - if (calendarFieldChanges.containsKey(res)) { - - // Field resolution should be included. Others are - // skipped so that client can not make unexpected - // changes (e.g. day change even though resolution is - // year). - Integer newValue = calendarFieldChanges.get(res); - cal.set(res.getCalendarField(), newValue); - } - } - newDate = cal.getTime(); - } - - if (newDate == null && dateString != null && !"".equals(dateString)) { - try { - Date parsedDate = handleUnparsableDateString(dateString); - setValue(parsedDate, true); - - /* - * Ensure the value is sent to the client if the value is - * set to the same as the previous (#4304). Does not repaint - * if handleUnparsableDateString throws an exception. In - * this case the invalid text remains in the DateField. - */ - requestRepaint(); - } catch (Converter.ConversionException e) { - - /* - * Datefield now contains some text that could't be parsed - * into date. - */ - if (oldDate != null) { - /* - * Set the logic value to null. - */ - setValue(null); - /* - * Reset the dateString (overridden to null by setValue) - */ - dateString = newDateString; - } - - /* - * Saves the localized message of parse error. This can be - * overridden in handleUnparsableDateString. The message - * will later be used to show a validation error. - */ - currentParseErrorMessage = e.getLocalizedMessage(); - - /* - * The value of the DateField should be null if an invalid - * value has been given. Not using setValue() since we do - * not want to cause the client side value to change. - */ - uiHasValidDateString = false; - - /* - * Because of our custom implementation of isValid(), that - * also checks the parsingSucceeded flag, we must also - * notify the form (if this is used in one) that the - * validity of this field has changed. - * - * Normally fields validity doesn't change without value - * change and form depends on this implementation detail. - */ - notifyFormOfValidityChange(); - requestRepaint(); - } - } else if (newDate != oldDate - && (newDate == null || !newDate.equals(oldDate))) { - setValue(newDate, true); // Don't require a repaint, client - // updates itself - } else if (!uiHasValidDateString) { // oldDate == - // newDate == null - // Empty value set, previously contained unparsable date string, - // clear related internal fields - setValue(null); - } - } - - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } - - if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } - } - - /** - * This method is called to handle a non-empty date string from the client - * if the client could not parse it as a Date. - * - * By default, a Converter.ConversionException is thrown, and the current - * value is not modified. - * - * This can be overridden to handle conversions, to return null (equivalent - * to empty input), to throw an exception or to fire an event. - * - * @param dateString - * @return parsed Date - * @throws Converter.ConversionException - * to keep the old value and indicate an error - */ - protected Date handleUnparsableDateString(String dateString) - throws Converter.ConversionException { - currentParseErrorMessage = null; - throw new Converter.ConversionException(getParseErrorMessage()); - } - - /* Property features */ - - /* - * Gets the edited property's type. Don't add a JavaDoc comment here, we use - * the default documentation from implemented interface. - */ - @Override - public Class<Date> getType() { - return Date.class; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractField#setValue(java.lang.Object, boolean) - */ - @Override - protected void setValue(Date newValue, boolean repaintIsNotNeeded) - throws Property.ReadOnlyException { - - /* - * First handle special case when the client side component have a date - * string but value is null (e.g. unparsable date string typed in by the - * user). No value changes should happen, but we need to do some - * internal housekeeping. - */ - if (newValue == null && !uiHasValidDateString) { - /* - * Side-effects of setInternalValue clears possible previous strings - * and flags about invalid input. - */ - setInternalValue(null); - - /* - * Due to DateField's special implementation of isValid(), - * datefields validity may change although the logical value does - * not change. This is an issue for Form which expects that validity - * of Fields cannot change unless actual value changes. - * - * So we check if this field is inside a form and the form has - * registered this as a field. In this case we repaint the form. - * Without this hacky solution the form might not be able to clean - * validation errors etc. We could avoid this by firing an extra - * value change event, but feels like at least as bad solution as - * this. - */ - notifyFormOfValidityChange(); - requestRepaint(); - return; - } - - super.setValue(newValue, repaintIsNotNeeded); - } - - /** - * Detects if this field is used in a Form (logically) and if so, notifies - * it (by repainting it) that the validity of this field might have changed. - */ - private void notifyFormOfValidityChange() { - Component parenOfDateField = getParent(); - boolean formFound = false; - while (parenOfDateField != null || formFound) { - if (parenOfDateField instanceof Form) { - Form f = (Form) parenOfDateField; - Collection<?> visibleItemProperties = f.getItemPropertyIds(); - for (Object fieldId : visibleItemProperties) { - Field<?> field = f.getField(fieldId); - if (field == this) { - /* - * this datefield is logically in a form. Do the same - * thing as form does in its value change listener that - * it registers to all fields. - */ - f.requestRepaint(); - formFound = true; - break; - } - } - } - if (formFound) { - break; - } - parenOfDateField = parenOfDateField.getParent(); - } - } - - @Override - protected void setInternalValue(Date newValue) { - // Also set the internal dateString - if (newValue != null) { - dateString = newValue.toString(); - } else { - dateString = null; - } - - if (!uiHasValidDateString) { - // clear component error and parsing flag - setComponentError(null); - uiHasValidDateString = true; - currentParseErrorMessage = null; - } - - super.setInternalValue(newValue); - } - - /** - * Gets the resolution. - * - * @return int - */ - public Resolution getResolution() { - return resolution; - } - - /** - * Sets the resolution of the DateField. - * - * The default resolution is {@link Resolution#DAY} since Vaadin 7.0. - * - * @param resolution - * the resolution to set. - */ - public void setResolution(Resolution resolution) { - this.resolution = resolution; - requestRepaint(); - } - - /** - * Returns new instance calendar used in Date conversions. - * - * Returns new clone of the calendar object initialized using the the - * current date (if available) - * - * If this is no calendar is assigned the <code>Calendar.getInstance</code> - * is used. - * - * @return the Calendar. - * @see #setCalendar(Calendar) - */ - private Calendar getCalendar() { - - // Makes sure we have an calendar instance - if (calendar == null) { - calendar = Calendar.getInstance(); - // Start by a zeroed calendar to avoid having values for lower - // resolution variables e.g. time when resolution is day - for (Resolution r : Resolution.getResolutionsLowerThan(resolution)) { - calendar.set(r.getCalendarField(), 0); - } - calendar.set(Calendar.MILLISECOND, 0); - } - - // Clone the instance - final Calendar newCal = (Calendar) calendar.clone(); - - // Assigns the current time tom calendar. - final Date currentDate = getValue(); - if (currentDate != null) { - newCal.setTime(currentDate); - } - - final TimeZone currentTimeZone = getTimeZone(); - if (currentTimeZone != null) { - newCal.setTimeZone(currentTimeZone); - } - - return newCal; - } - - /** - * Sets formatting used by some component implementations. See - * {@link SimpleDateFormat} for format details. - * - * By default it is encouraged to used default formatting defined by Locale, - * but due some JVM bugs it is sometimes necessary to use this method to - * override formatting. See Vaadin issue #2200. - * - * @param dateFormat - * the dateFormat to set - * - * @see com.vaadin.ui.AbstractComponent#setLocale(Locale)) - */ - public void setDateFormat(String dateFormat) { - this.dateFormat = dateFormat; - requestRepaint(); - } - - /** - * Returns a format string used to format date value on client side or null - * if default formatting from {@link Component#getLocale()} is used. - * - * @return the dateFormat - */ - public String getDateFormat() { - return dateFormat; - } - - /** - * Specifies whether or not date/time interpretation in component is to be - * lenient. - * - * @see Calendar#setLenient(boolean) - * @see #isLenient() - * - * @param lenient - * true if the lenient mode is to be turned on; false if it is to - * be turned off. - */ - public void setLenient(boolean lenient) { - this.lenient = lenient; - requestRepaint(); - } - - /** - * Returns whether date/time interpretation is to be lenient. - * - * @see #setLenient(boolean) - * - * @return true if the interpretation mode of this calendar is lenient; - * false otherwise. - */ - public boolean isLenient() { - return lenient; - } - - @Override - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - @Override - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - } - - @Override - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - @Override - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - /** - * Checks whether ISO 8601 week numbers are shown in the date selector. - * - * @return true if week numbers are shown, false otherwise. - */ - public boolean isShowISOWeekNumbers() { - return showISOWeekNumbers; - } - - /** - * Sets the visibility of ISO 8601 week numbers in the date selector. ISO - * 8601 defines that a week always starts with a Monday so the week numbers - * are only shown if this is the case. - * - * @param showWeekNumbers - * true if week numbers should be shown, false otherwise. - */ - public void setShowISOWeekNumbers(boolean showWeekNumbers) { - showISOWeekNumbers = showWeekNumbers; - requestRepaint(); - } - - /** - * Validates the current value against registered validators if the field is - * not empty. Note that DateField is considered empty (value == null) and - * invalid if it contains text typed in by the user that couldn't be parsed - * into a Date value. - * - * @see com.vaadin.ui.AbstractField#validate() - */ - @Override - public void validate() throws InvalidValueException { - /* - * To work properly in form we must throw exception if there is - * currently a parsing error in the datefield. Parsing error is kind of - * an internal validator. - */ - if (!uiHasValidDateString) { - throw new UnparsableDateString(currentParseErrorMessage); - } - super.validate(); - } - - /** - * Return the error message that is shown if the user inputted value can't - * be parsed into a Date object. If - * {@link #handleUnparsableDateString(String)} is overridden and it throws a - * custom exception, the message returned by - * {@link Exception#getLocalizedMessage()} will be used instead of the value - * returned by this method. - * - * @see #setParseErrorMessage(String) - * - * @return the error message that the DateField uses when it can't parse the - * textual input from user to a Date object - */ - public String getParseErrorMessage() { - return defaultParseErrorMessage; - } - - /** - * Sets the default error message used if the DateField cannot parse the - * text input by user to a Date field. Note that if the - * {@link #handleUnparsableDateString(String)} method is overridden, the - * localized message from its exception is used. - * - * @see #getParseErrorMessage() - * @see #handleUnparsableDateString(String) - * @param parsingErrorMessage - */ - public void setParseErrorMessage(String parsingErrorMessage) { - defaultParseErrorMessage = parsingErrorMessage; - } - - /** - * Sets the time zone used by this date field. The time zone is used to - * convert the absolute time in a Date object to a logical time displayed in - * the selector and to convert the select time back to a Date object. - * - * If no time zone has been set, the current default time zone returned by - * {@code TimeZone.getDefault()} is used. - * - * @see #getTimeZone() - * @param timeZone - * the time zone to use for time calculations. - */ - public void setTimeZone(TimeZone timeZone) { - this.timeZone = timeZone; - requestRepaint(); - } - - /** - * Gets the time zone used by this field. The time zone is used to convert - * the absolute time in a Date object to a logical time displayed in the - * selector and to convert the select time back to a Date object. - * - * If {@code null} is returned, the current default time zone returned by - * {@code TimeZone.getDefault()} is used. - * - * @return the current time zone - */ - public TimeZone getTimeZone() { - return timeZone; - } - - public static class UnparsableDateString extends - Validator.InvalidValueException { - - public UnparsableDateString(String message) { - super(message); - } - - } -} diff --git a/src/com/vaadin/ui/DefaultFieldFactory.java b/src/com/vaadin/ui/DefaultFieldFactory.java deleted file mode 100644 index e17f08c1c6..0000000000 --- a/src/com/vaadin/ui/DefaultFieldFactory.java +++ /dev/null @@ -1,146 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.util.Date; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; - -/** - * This class contains a basic implementation for both {@link FormFieldFactory} - * and {@link TableFieldFactory}. The class is singleton, use {@link #get()} - * method to get reference to the instance. - * - * <p> - * There are also some static helper methods available for custom built field - * factories. - * - */ -public class DefaultFieldFactory implements FormFieldFactory, TableFieldFactory { - - private static final DefaultFieldFactory instance = new DefaultFieldFactory(); - - /** - * Singleton method to get an instance of DefaultFieldFactory. - * - * @return an instance of DefaultFieldFactory - */ - public static DefaultFieldFactory get() { - return instance; - } - - protected DefaultFieldFactory() { - } - - @Override - public Field<?> createField(Item item, Object propertyId, - Component uiContext) { - Class<?> type = item.getItemProperty(propertyId).getType(); - Field<?> field = createFieldByPropertyType(type); - field.setCaption(createCaptionByPropertyId(propertyId)); - return field; - } - - @Override - public Field<?> createField(Container container, Object itemId, - Object propertyId, Component uiContext) { - Property<?> containerProperty = container.getContainerProperty(itemId, - propertyId); - Class<?> type = containerProperty.getType(); - Field<?> field = createFieldByPropertyType(type); - field.setCaption(createCaptionByPropertyId(propertyId)); - return field; - } - - /** - * If name follows method naming conventions, convert the name to spaced - * upper case text. For example, convert "firstName" to "First Name" - * - * @param propertyId - * @return the formatted caption string - */ - public static String createCaptionByPropertyId(Object propertyId) { - String name = propertyId.toString(); - if (name.length() > 0) { - - int dotLocation = name.lastIndexOf('.'); - if (dotLocation > 0 && dotLocation < name.length() - 1) { - name = name.substring(dotLocation + 1); - } - if (name.indexOf(' ') < 0 - && name.charAt(0) == Character.toLowerCase(name.charAt(0)) - && name.charAt(0) != Character.toUpperCase(name.charAt(0))) { - StringBuffer out = new StringBuffer(); - out.append(Character.toUpperCase(name.charAt(0))); - int i = 1; - - while (i < name.length()) { - int j = i; - for (; j < name.length(); j++) { - char c = name.charAt(j); - if (Character.toLowerCase(c) != c - && Character.toUpperCase(c) == c) { - break; - } - } - if (j == name.length()) { - out.append(name.substring(i)); - } else { - out.append(name.substring(i, j)); - out.append(" " + name.charAt(j)); - } - i = j + 1; - } - - name = out.toString(); - } - } - return name; - } - - /** - * Creates fields based on the property type. - * <p> - * The default field type is {@link TextField}. Other field types generated - * by this method: - * <p> - * <b>Boolean</b>: {@link CheckBox}.<br/> - * <b>Date</b>: {@link DateField}(resolution: day).<br/> - * <b>Item</b>: {@link Form}. <br/> - * <b>default field type</b>: {@link TextField}. - * <p> - * - * @param type - * the type of the property - * @return the most suitable generic {@link Field} for given type - */ - public static Field<?> createFieldByPropertyType(Class<?> type) { - // Null typed properties can not be edited - if (type == null) { - return null; - } - - // Item field - if (Item.class.isAssignableFrom(type)) { - return new Form(); - } - - // Date field - if (Date.class.isAssignableFrom(type)) { - final DateField df = new DateField(); - df.setResolution(DateField.RESOLUTION_DAY); - return df; - } - - // Boolean field - if (Boolean.class.isAssignableFrom(type)) { - return new CheckBox(); - } - - return new TextField(); - } - -} diff --git a/src/com/vaadin/ui/DragAndDropWrapper.java b/src/com/vaadin/ui/DragAndDropWrapper.java deleted file mode 100644 index 67229a45fe..0000000000 --- a/src/com/vaadin/ui/DragAndDropWrapper.java +++ /dev/null @@ -1,407 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; - -import com.vaadin.event.Transferable; -import com.vaadin.event.TransferableImpl; -import com.vaadin.event.dd.DragSource; -import com.vaadin.event.dd.DropHandler; -import com.vaadin.event.dd.DropTarget; -import com.vaadin.event.dd.TargetDetails; -import com.vaadin.event.dd.TargetDetailsImpl; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.dd.HorizontalDropLocation; -import com.vaadin.shared.ui.dd.VerticalDropLocation; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.StreamVariable; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.draganddropwrapper.VDragAndDropWrapper; - -@SuppressWarnings("serial") -public class DragAndDropWrapper extends CustomComponent implements DropTarget, - DragSource, Vaadin6Component { - - public class WrapperTransferable extends TransferableImpl { - - private Html5File[] files; - - public WrapperTransferable(Component sourceComponent, - Map<String, Object> rawVariables) { - super(sourceComponent, rawVariables); - Integer fc = (Integer) rawVariables.get("filecount"); - if (fc != null) { - files = new Html5File[fc]; - for (int i = 0; i < fc; i++) { - Html5File file = new Html5File( - (String) rawVariables.get("fn" + i), // name - (Integer) rawVariables.get("fs" + i), // size - (String) rawVariables.get("ft" + i)); // mime - String id = (String) rawVariables.get("fi" + i); - files[i] = file; - receivers.put(id, file); - requestRepaint(); // paint Receivers - } - } - } - - /** - * The component in wrapper that is being dragged or null if the - * transferable is not a component (most likely an html5 drag). - * - * @return - */ - public Component getDraggedComponent() { - Component object = (Component) getData("component"); - return object; - } - - /** - * @return the mouse down event that started the drag and drop operation - */ - public MouseEventDetails getMouseDownEvent() { - return MouseEventDetails.deSerialize((String) getData("mouseDown")); - } - - public Html5File[] getFiles() { - return files; - } - - public String getText() { - String data = (String) getData("Text"); // IE, html5 - if (data == null) { - // check for "text/plain" (webkit) - data = (String) getData("text/plain"); - } - return data; - } - - public String getHtml() { - String data = (String) getData("Html"); // IE, html5 - if (data == null) { - // check for "text/plain" (webkit) - data = (String) getData("text/html"); - } - return data; - } - - } - - private Map<String, Html5File> receivers = new HashMap<String, Html5File>(); - - public class WrapperTargetDetails extends TargetDetailsImpl { - - public WrapperTargetDetails(Map<String, Object> rawDropData) { - super(rawDropData, DragAndDropWrapper.this); - } - - /** - * @return the absolute position of wrapper on the page - */ - public Integer getAbsoluteLeft() { - return (Integer) getData("absoluteLeft"); - } - - /** - * - * @return the absolute position of wrapper on the page - */ - public Integer getAbsoluteTop() { - return (Integer) getData("absoluteTop"); - } - - /** - * @return details about the actual event that caused the event details. - * Practically mouse move or mouse up. - */ - public MouseEventDetails getMouseEvent() { - return MouseEventDetails - .deSerialize((String) getData("mouseEvent")); - } - - /** - * @return a detail about the drags vertical position over the wrapper. - */ - public VerticalDropLocation getVerticalDropLocation() { - return VerticalDropLocation - .valueOf((String) getData("verticalLocation")); - } - - /** - * @return a detail about the drags horizontal position over the - * wrapper. - */ - public HorizontalDropLocation getHorizontalDropLocation() { - return HorizontalDropLocation - .valueOf((String) getData("horizontalLocation")); - } - - /** - * @deprecated use {@link #getVerticalDropLocation()} instead - */ - @Deprecated - public VerticalDropLocation verticalDropLocation() { - return getVerticalDropLocation(); - } - - /** - * @deprecated use {@link #getHorizontalDropLocation()} instead - */ - @Deprecated - public HorizontalDropLocation horizontalDropLocation() { - return getHorizontalDropLocation(); - } - - } - - public enum DragStartMode { - /** - * {@link DragAndDropWrapper} does not start drag events at all - */ - NONE, - /** - * The component on which the drag started will be shown as drag image. - */ - COMPONENT, - /** - * The whole wrapper is used as a drag image when dragging. - */ - WRAPPER, - /** - * The whole wrapper is used to start an HTML5 drag. - * - * NOTE: In Internet Explorer 6 to 8, this prevents user interactions - * with the wrapper's contents. For example, clicking a button inside - * the wrapper will no longer work. - */ - HTML5, - } - - private final Map<String, Object> html5DataFlavors = new LinkedHashMap<String, Object>(); - private DragStartMode dragStartMode = DragStartMode.NONE; - - /** - * Wraps given component in a {@link DragAndDropWrapper}. - * - * @param root - * the component to be wrapped - */ - public DragAndDropWrapper(Component root) { - super(root); - } - - /** - * Sets data flavors available in the DragAndDropWrapper is used to start an - * HTML5 style drags. Most commonly the "Text" flavor should be set. - * Multiple data types can be set. - * - * @param type - * the string identifier of the drag "payload". E.g. "Text" or - * "text/html" - * @param value - * the value - */ - public void setHTML5DataFlavor(String type, Object value) { - html5DataFlavors.put(type, value); - requestRepaint(); - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // TODO Remove once Vaadin6Component is no longer implemented - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - target.addAttribute(VDragAndDropWrapper.DRAG_START_MODE, - dragStartMode.ordinal()); - if (getDropHandler() != null) { - getDropHandler().getAcceptCriterion().paint(target); - } - if (receivers != null && receivers.size() > 0) { - for (Iterator<Entry<String, Html5File>> it = receivers.entrySet() - .iterator(); it.hasNext();) { - Entry<String, com.vaadin.ui.Html5File> entry = it.next(); - String id = entry.getKey(); - Html5File html5File = entry.getValue(); - if (html5File.getStreamVariable() != null) { - target.addVariable(this, "rec-" + id, new ProxyReceiver( - html5File)); - // these are cleaned from receivers once the upload has - // started - } else { - // instructs the client side not to send the file - target.addVariable(this, "rec-" + id, (String) null); - // forget the file from subsequent paints - it.remove(); - } - } - } - target.addAttribute(VDragAndDropWrapper.HTML5_DATA_FLAVORS, - html5DataFlavors); - } - - private DropHandler dropHandler; - - @Override - public DropHandler getDropHandler() { - return dropHandler; - } - - public void setDropHandler(DropHandler dropHandler) { - this.dropHandler = dropHandler; - requestRepaint(); - } - - @Override - public TargetDetails translateDropTargetDetails( - Map<String, Object> clientVariables) { - return new WrapperTargetDetails(clientVariables); - } - - @Override - public Transferable getTransferable(final Map<String, Object> rawVariables) { - return new WrapperTransferable(this, rawVariables); - } - - public void setDragStartMode(DragStartMode dragStartMode) { - this.dragStartMode = dragStartMode; - requestRepaint(); - } - - public DragStartMode getDragStartMode() { - return dragStartMode; - } - - final class ProxyReceiver implements StreamVariable { - - private Html5File file; - - public ProxyReceiver(Html5File file) { - this.file = file; - } - - private boolean listenProgressOfUploadedFile; - - @Override - public OutputStream getOutputStream() { - if (file.getStreamVariable() == null) { - return null; - } - return file.getStreamVariable().getOutputStream(); - } - - @Override - public boolean listenProgress() { - return file.getStreamVariable().listenProgress(); - } - - @Override - public void onProgress(StreamingProgressEvent event) { - file.getStreamVariable().onProgress( - new ReceivingEventWrapper(event)); - } - - @Override - public void streamingStarted(StreamingStartEvent event) { - listenProgressOfUploadedFile = file.getStreamVariable() != null; - if (listenProgressOfUploadedFile) { - file.getStreamVariable().streamingStarted( - new ReceivingEventWrapper(event)); - } - // no need tell to the client about this receiver on next paint - receivers.remove(file); - // let the terminal GC the streamvariable and not to accept other - // file uploads to this variable - event.disposeStreamVariable(); - } - - @Override - public void streamingFinished(StreamingEndEvent event) { - if (listenProgressOfUploadedFile) { - file.getStreamVariable().streamingFinished( - new ReceivingEventWrapper(event)); - } - } - - @Override - public void streamingFailed(final StreamingErrorEvent event) { - if (listenProgressOfUploadedFile) { - file.getStreamVariable().streamingFailed( - new ReceivingEventWrapper(event)); - } - } - - @Override - public boolean isInterrupted() { - return file.getStreamVariable().isInterrupted(); - } - - /* - * With XHR2 file posts we can't provide as much information from the - * terminal as with multipart request. This helper class wraps the - * terminal event and provides the lacking information from the - * Html5File. - */ - class ReceivingEventWrapper implements StreamingErrorEvent, - StreamingEndEvent, StreamingStartEvent, StreamingProgressEvent { - - private StreamingEvent wrappedEvent; - - ReceivingEventWrapper(StreamingEvent e) { - wrappedEvent = e; - } - - @Override - public String getMimeType() { - return file.getType(); - } - - @Override - public String getFileName() { - return file.getFileName(); - } - - @Override - public long getContentLength() { - return file.getFileSize(); - } - - public StreamVariable getReceiver() { - return ProxyReceiver.this; - } - - @Override - public Exception getException() { - if (wrappedEvent instanceof StreamingErrorEvent) { - return ((StreamingErrorEvent) wrappedEvent).getException(); - } - return null; - } - - @Override - public long getBytesReceived() { - return wrappedEvent.getBytesReceived(); - } - - /** - * Calling this method has no effect. DD files are receive only once - * anyway. - */ - @Override - public void disposeStreamVariable() { - - } - } - - } - -} diff --git a/src/com/vaadin/ui/Embedded.java b/src/com/vaadin/ui/Embedded.java deleted file mode 100644 index 6088c5aa66..0000000000 --- a/src/com/vaadin/ui/Embedded.java +++ /dev/null @@ -1,531 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.event.MouseEvents.ClickListener; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.embedded.EmbeddedServerRpc; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; -import com.vaadin.terminal.gwt.client.ui.embedded.EmbeddedConnector; - -/** - * Component for embedding external objects. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Embedded extends AbstractComponent implements Vaadin6Component { - - /** - * General object type. - */ - public static final int TYPE_OBJECT = 0; - - /** - * Image types. - */ - public static final int TYPE_IMAGE = 1; - - /** - * Browser ("iframe") type. - */ - public static final int TYPE_BROWSER = 2; - - /** - * Type of the object. - */ - private int type = TYPE_OBJECT; - - /** - * Source of the embedded object. - */ - private Resource source = null; - - /** - * Generic object attributes. - */ - private String mimeType = null; - - private String standby = null; - - /** - * Hash of object parameters. - */ - private final Map<String, String> parameters = new HashMap<String, String>(); - - /** - * Applet or other client side runnable properties. - */ - private String codebase = null; - - private String codetype = null; - - private String classId = null; - - private String archive = null; - - private String altText; - - private EmbeddedServerRpc rpc = new EmbeddedServerRpc() { - @Override - public void click(MouseEventDetails mouseDetails) { - fireEvent(new ClickEvent(Embedded.this, mouseDetails)); - } - }; - - /** - * Creates a new empty Embedded object. - */ - public Embedded() { - registerRpc(rpc); - } - - /** - * Creates a new empty Embedded object with caption. - * - * @param caption - */ - public Embedded(String caption) { - this(); - setCaption(caption); - } - - /** - * Creates a new Embedded object whose contents is loaded from given - * resource. The dimensions are assumed if possible. The type is guessed - * from resource. - * - * @param caption - * @param source - * the Source of the embedded object. - */ - public Embedded(String caption, Resource source) { - this(caption); - setSource(source); - } - - /** - * Invoked when the component state should be painted. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - - switch (type) { - case TYPE_IMAGE: - target.addAttribute("type", "image"); - break; - case TYPE_BROWSER: - target.addAttribute("type", "browser"); - break; - default: - break; - } - - if (getSource() != null) { - target.addAttribute("src", getSource()); - } - - if (mimeType != null && !"".equals(mimeType)) { - target.addAttribute("mimetype", mimeType); - } - if (classId != null && !"".equals(classId)) { - target.addAttribute("classid", classId); - } - if (codebase != null && !"".equals(codebase)) { - target.addAttribute("codebase", codebase); - } - if (codetype != null && !"".equals(codetype)) { - target.addAttribute("codetype", codetype); - } - if (standby != null && !"".equals(standby)) { - target.addAttribute("standby", standby); - } - if (archive != null && !"".equals(archive)) { - target.addAttribute("archive", archive); - } - if (altText != null && !"".equals(altText)) { - target.addAttribute(EmbeddedConnector.ALTERNATE_TEXT, altText); - } - - // Params - for (final Iterator<String> i = getParameterNames(); i.hasNext();) { - target.startTag("embeddedparam"); - final String key = i.next(); - target.addAttribute("name", key); - target.addAttribute("value", getParameter(key)); - target.endTag("embeddedparam"); - } - } - - /** - * Sets this component's "alt-text", that is, an alternate text that can be - * presented instead of this component's normal content, for accessibility - * purposes. Does not work when {@link #setType(int)} has been called with - * {@link #TYPE_BROWSER}. - * - * @param altText - * A short, human-readable description of this component's - * content. - * @since 6.8 - */ - public void setAlternateText(String altText) { - if (altText != this.altText - || (altText != null && !altText.equals(this.altText))) { - this.altText = altText; - requestRepaint(); - } - } - - /** - * Gets this component's "alt-text". - * - * @see #setAlternateText(String) - */ - public String getAlternateText() { - return altText; - } - - /** - * Sets an object parameter. Parameters are optional information, and they - * are passed to the instantiated object. Parameters are are stored as name - * value pairs. This overrides the previous value assigned to this - * parameter. - * - * @param name - * the name of the parameter. - * @param value - * the value of the parameter. - */ - public void setParameter(String name, String value) { - parameters.put(name, value); - requestRepaint(); - } - - /** - * Gets the value of an object parameter. Parameters are optional - * information, and they are passed to the instantiated object. Parameters - * are are stored as name value pairs. - * - * @return the Value of parameter or null if not found. - */ - public String getParameter(String name) { - return parameters.get(name); - } - - /** - * Removes an object parameter from the list. - * - * @param name - * the name of the parameter to remove. - */ - public void removeParameter(String name) { - parameters.remove(name); - requestRepaint(); - } - - /** - * Gets the embedded object parameter names. - * - * @return the Iterator of parameters names. - */ - public Iterator<String> getParameterNames() { - return parameters.keySet().iterator(); - } - - /** - * This attribute specifies the base path used to resolve relative URIs - * specified by the classid, data, and archive attributes. When absent, its - * default value is the base URI of the current document. - * - * @return the code base. - */ - public String getCodebase() { - return codebase; - } - - /** - * Gets the MIME-Type of the code. - * - * @return the MIME-Type of the code. - */ - public String getCodetype() { - return codetype; - } - - /** - * Gets the MIME-Type of the object. - * - * @return the MIME-Type of the object. - */ - public String getMimeType() { - return mimeType; - } - - /** - * This attribute specifies a message that a user agent may render while - * loading the object's implementation and data. - * - * @return The text displayed when loading - */ - public String getStandby() { - return standby; - } - - /** - * This attribute specifies the base path used to resolve relative URIs - * specified by the classid, data, and archive attributes. When absent, its - * default value is the base URI of the current document. - * - * @param codebase - * The base path - */ - public void setCodebase(String codebase) { - if (codebase != this.codebase - || (codebase != null && !codebase.equals(this.codebase))) { - this.codebase = codebase; - requestRepaint(); - } - } - - /** - * This attribute specifies the content type of data expected when - * downloading the object specified by classid. This attribute is optional - * but recommended when classid is specified since it allows the user agent - * to avoid loading information for unsupported content types. When absent, - * it defaults to the value of the type attribute. - * - * @param codetype - * the codetype to set. - */ - public void setCodetype(String codetype) { - if (codetype != this.codetype - || (codetype != null && !codetype.equals(this.codetype))) { - this.codetype = codetype; - requestRepaint(); - } - } - - /** - * Sets the mimeType, the MIME-Type of the object. - * - * @param mimeType - * the mimeType to set. - */ - public void setMimeType(String mimeType) { - if (mimeType != this.mimeType - || (mimeType != null && !mimeType.equals(this.mimeType))) { - this.mimeType = mimeType; - if ("application/x-shockwave-flash".equals(mimeType)) { - /* - * Automatically add wmode transparent as we use lots of - * floating layers in Vaadin. If developers need better flash - * performance, they can override this value programmatically - * back to "window" (the defautl). - */ - if (getParameter("wmode") == null) { - setParameter("wmode", "transparent"); - } - } - requestRepaint(); - } - } - - /** - * This attribute specifies a message that a user agent may render while - * loading the object's implementation and data. - * - * @param standby - * The text to display while loading - */ - public void setStandby(String standby) { - if (standby != this.standby - || (standby != null && !standby.equals(this.standby))) { - this.standby = standby; - requestRepaint(); - } - } - - /** - * This attribute may be used to specify the location of an object's - * implementation via a URI. - * - * @return the classid. - */ - public String getClassId() { - return classId; - } - - /** - * This attribute may be used to specify the location of an object's - * implementation via a URI. - * - * @param classId - * the classId to set. - */ - public void setClassId(String classId) { - if (classId != this.classId - || (classId != null && !classId.equals(this.classId))) { - this.classId = classId; - requestRepaint(); - } - } - - /** - * Gets the resource contained in the embedded object. - * - * @return the Resource - */ - public Resource getSource() { - return source; - } - - /** - * Gets the type of the embedded object. - * <p> - * This can be one of the following: - * <ul> - * <li>TYPE_OBJECT <i>(This is the default)</i> - * <li>TYPE_IMAGE - * </ul> - * </p> - * - * @return the type. - */ - public int getType() { - return type; - } - - /** - * Sets the object source resource. The dimensions are assumed if possible. - * The type is guessed from resource. - * - * @param source - * the source to set. - */ - public void setSource(Resource source) { - if (source != null && !source.equals(this.source)) { - this.source = source; - final String mt = source.getMIMEType(); - - if (mimeType == null) { - mimeType = mt; - } - - if (mt.equals("image/svg+xml")) { - type = TYPE_OBJECT; - } else if ((mt.substring(0, mt.indexOf("/")) - .equalsIgnoreCase("image"))) { - type = TYPE_IMAGE; - } else { - // Keep previous type - } - requestRepaint(); - } - } - - /** - * Sets the object type. - * <p> - * This can be one of the following: - * <ul> - * <li>TYPE_OBJECT <i>(This is the default)</i> - * <li>TYPE_IMAGE - * <li>TYPE_BROWSER - * </ul> - * </p> - * - * @param type - * the type to set. - */ - public void setType(int type) { - if (type != TYPE_OBJECT && type != TYPE_IMAGE && type != TYPE_BROWSER) { - throw new IllegalArgumentException("Unsupported type"); - } - if (type != this.type) { - this.type = type; - requestRepaint(); - } - } - - /** - * This attribute may be used to specify a space-separated list of URIs for - * archives containing resources relevant to the object, which may include - * the resources specified by the classid and data attributes. Preloading - * archives will generally result in reduced load times for objects. - * Archives specified as relative URIs should be interpreted relative to the - * codebase attribute. - * - * @return Space-separated list of URIs with resources relevant to the - * object - */ - public String getArchive() { - return archive; - } - - /** - * This attribute may be used to specify a space-separated list of URIs for - * archives containing resources relevant to the object, which may include - * the resources specified by the classid and data attributes. Preloading - * archives will generally result in reduced load times for objects. - * Archives specified as relative URIs should be interpreted relative to the - * codebase attribute. - * - * @param archive - * Space-separated list of URIs with resources relevant to the - * object - */ - public void setArchive(String archive) { - if (archive != this.archive - || (archive != null && !archive.equals(this.archive))) { - this.archive = archive; - requestRepaint(); - } - } - - /** - * Add a click listener to the component. The listener is called whenever - * the user clicks inside the component. Depending on the content the event - * may be blocked and in that case no event is fired. - * - * Use {@link #removeListener(ClickListener)} to remove the listener. - * - * @param listener - * The listener to add - */ - public void addListener(ClickListener listener) { - addListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, ClickEvent.class, - listener, ClickListener.clickMethod); - } - - /** - * Remove a click listener from the component. The listener should earlier - * have been added using {@link #addListener(ClickListener)}. - * - * @param listener - * The listener to remove - */ - public void removeListener(ClickListener listener) { - removeListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, - ClickEvent.class, listener); - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // TODO Remove once Vaadin6Component is no longer implemented - } - -} diff --git a/src/com/vaadin/ui/Field.java b/src/com/vaadin/ui/Field.java deleted file mode 100644 index 6dc40d192f..0000000000 --- a/src/com/vaadin/ui/Field.java +++ /dev/null @@ -1,97 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.data.BufferedValidatable; -import com.vaadin.data.Property; -import com.vaadin.ui.Component.Focusable; - -/** - * TODO document - * - * @author Vaadin Ltd. - * - * @param T - * the type of values in the field, which might not be the same type - * as that of the data source if converters are used - * - * @author IT Mill Ltd. - */ -public interface Field<T> extends Component, BufferedValidatable, Property<T>, - Property.ValueChangeNotifier, Property.ValueChangeListener, - Property.Editor, Focusable { - - /** - * Is this field required. - * - * Required fields must filled by the user. - * - * @return <code>true</code> if the field is required,otherwise - * <code>false</code>. - * @since 3.1 - */ - public boolean isRequired(); - - /** - * Sets the field required. Required fields must filled by the user. - * - * @param required - * Is the field required. - * @since 3.1 - */ - public void setRequired(boolean required); - - /** - * Sets the error message to be displayed if a required field is empty. - * - * @param requiredMessage - * Error message. - * @since 5.2.6 - */ - public void setRequiredError(String requiredMessage); - - /** - * Gets the error message that is to be displayed if a required field is - * empty. - * - * @return Error message. - * @since 5.2.6 - */ - public String getRequiredError(); - - /** - * An <code>Event</code> object specifying the Field whose value has been - * changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - @SuppressWarnings("serial") - public static class ValueChangeEvent extends Component.Event implements - Property.ValueChangeEvent { - - /** - * Constructs a new event object with the specified source field object. - * - * @param source - * the field that caused the event. - */ - public ValueChangeEvent(Field source) { - super(source); - } - - /** - * Gets the Property which triggered the event. - * - * @return the Source Property of the event. - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - } -} diff --git a/src/com/vaadin/ui/Form.java b/src/com/vaadin/ui/Form.java deleted file mode 100644 index fbc4d5a8e6..0000000000 --- a/src/com/vaadin/ui/Form.java +++ /dev/null @@ -1,1420 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; - -import com.vaadin.data.Buffered; -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.data.Validatable; -import com.vaadin.data.Validator; -import com.vaadin.data.Validator.InvalidValueException; -import com.vaadin.data.fieldgroup.FieldGroup; -import com.vaadin.data.util.BeanItem; -import com.vaadin.event.Action; -import com.vaadin.event.Action.Handler; -import com.vaadin.event.Action.ShortcutNotifier; -import com.vaadin.event.ActionManager; -import com.vaadin.shared.ui.form.FormState; -import com.vaadin.terminal.AbstractErrorMessage; -import com.vaadin.terminal.CompositeErrorMessage; -import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.UserError; -import com.vaadin.terminal.Vaadin6Component; - -/** - * Form component provides easy way of creating and managing sets fields. - * - * <p> - * <code>Form</code> is a container for fields implementing {@link Field} - * interface. It provides support for any layouts and provides buffering - * interface for easy connection of commit and discard buttons. All the form - * fields can be customized by adding validators, setting captions and icons, - * setting immediateness, etc. Also direct mechanism for replacing existing - * fields with selections is given. - * </p> - * - * <p> - * <code>Form</code> provides customizable editor for classes implementing - * {@link com.vaadin.data.Item} interface. Also the form itself implements this - * interface for easier connectivity to other items. To use the form as editor - * for an item, just connect the item to form with - * {@link Form#setItemDataSource(Item)}. If only a part of the item needs to be - * edited, {@link Form#setItemDataSource(Item,Collection)} can be used instead. - * After the item has been connected to the form, the automatically created - * fields can be customized and new fields can be added. If you need to connect - * a class that does not implement {@link com.vaadin.data.Item} interface, most - * properties of any class following bean pattern, can be accessed trough - * {@link com.vaadin.data.util.BeanItem}. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - * @deprecated Use {@link FieldGroup} instead of {@link Form} for more - * flexibility. - */ -@Deprecated -public class Form extends AbstractField<Object> implements Item.Editor, - Buffered, Item, Validatable, Action.Notifier, HasComponents, - Vaadin6Component { - - private Object propertyValue; - - /** - * Item connected to this form as datasource. - */ - private Item itemDatasource; - - /** - * Ordered list of property ids in this editor. - */ - private final LinkedList<Object> propertyIds = new LinkedList<Object>(); - - /** - * Current buffered source exception. - */ - private Buffered.SourceException currentBufferedSourceException = null; - - /** - * Is the form in write trough mode. - */ - private boolean writeThrough = true; - - /** - * Is the form in read trough mode. - */ - private boolean readThrough = true; - - /** - * Mapping from propertyName to corresponding field. - */ - private final HashMap<Object, Field<?>> fields = new HashMap<Object, Field<?>>(); - - /** - * Form may act as an Item, its own properties are stored here. - */ - private final HashMap<Object, Property<?>> ownProperties = new HashMap<Object, Property<?>>(); - - /** - * Field factory for this form. - */ - private FormFieldFactory fieldFactory; - - /** - * Visible item properties. - */ - private Collection<?> visibleItemProperties; - - /** - * Form needs to repaint itself if child fields value changes due possible - * change in form validity. - * - * TODO introduce ValidityChangeEvent (#6239) and start using it instead. - * See e.g. DateField#notifyFormOfValidityChange(). - */ - private final ValueChangeListener fieldValueChangeListener = new ValueChangeListener() { - @Override - public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) { - requestRepaint(); - } - }; - - /** - * If this is true, commit implicitly calls setValidationVisible(true). - */ - private boolean validationVisibleOnCommit = true; - - // special handling for gridlayout; remember initial cursor pos - private int gridlayoutCursorX = -1; - private int gridlayoutCursorY = -1; - - /** - * Keeps track of the Actions added to this component, and manages the - * painting and handling as well. Note that the extended AbstractField is a - * {@link ShortcutNotifier} and has a actionManager that delegates actions - * to the containing window. This one does not delegate. - */ - private ActionManager ownActionManager = new ActionManager(this); - - /** - * Constructs a new form with default layout. - * - * <p> - * By default the form uses {@link FormLayout}. - * </p> - */ - public Form() { - this(null); - setValidationVisible(false); - } - - /** - * Constructs a new form with given {@link Layout}. - * - * @param formLayout - * the layout of the form. - */ - public Form(Layout formLayout) { - this(formLayout, DefaultFieldFactory.get()); - } - - /** - * Constructs a new form with given {@link Layout} and - * {@link FormFieldFactory}. - * - * @param formLayout - * the layout of the form. - * @param fieldFactory - * the FieldFactory of the form. - */ - public Form(Layout formLayout, FormFieldFactory fieldFactory) { - super(); - setLayout(formLayout); - setFooter(null); - setFormFieldFactory(fieldFactory); - setValidationVisible(false); - setWidth(100, UNITS_PERCENTAGE); - } - - @Override - public FormState getState() { - return (FormState) super.getState(); - } - - /* Documented in interface */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (ownActionManager != null) { - ownActionManager.paintActions(null, target); - } - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // Actions - if (ownActionManager != null) { - ownActionManager.handleActions(variables, this); - } - } - - /** - * The error message of a Form is the error of the first field with a - * non-empty error. - * - * Empty error messages of the contained fields are skipped, because an - * empty error indicator would be confusing to the user, especially if there - * are errors that have something to display. This is also the reason why - * the calculation of the error message is separate from validation, because - * validation fails also on empty errors. - */ - @Override - public ErrorMessage getErrorMessage() { - - // Reimplement the checking of validation error by using - // getErrorMessage() recursively instead of validate(). - ErrorMessage validationError = null; - if (isValidationVisible()) { - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - Object f = fields.get(i.next()); - if (f instanceof AbstractComponent) { - AbstractComponent field = (AbstractComponent) f; - - validationError = field.getErrorMessage(); - if (validationError != null) { - // Show caption as error for fields with empty errors - if ("".equals(validationError.toString())) { - validationError = new UserError(field.getCaption()); - } - break; - } else if (f instanceof Field && !((Field<?>) f).isValid()) { - // Something is wrong with the field, but no proper - // error is given. Generate one. - validationError = new UserError(field.getCaption()); - break; - } - } - } - } - - // Return if there are no errors at all - if (getComponentError() == null && validationError == null - && currentBufferedSourceException == null) { - return null; - } - - // Throw combination of the error types - return new CompositeErrorMessage( - new ErrorMessage[] { - getComponentError(), - validationError, - AbstractErrorMessage - .getErrorMessageForException(currentBufferedSourceException) }); - } - - /** - * Controls the making validation visible implicitly on commit. - * - * Having commit() call setValidationVisible(true) implicitly is the default - * behaviour. You can disable the implicit setting by setting this property - * as false. - * - * It is useful, because you usually want to start with the form free of - * errors and only display them after the user clicks Ok. You can disable - * the implicit setting by setting this property as false. - * - * @param makeVisible - * If true (default), validation is made visible when commit() is - * called. If false, the visibility is left as it is. - */ - public void setValidationVisibleOnCommit(boolean makeVisible) { - validationVisibleOnCommit = makeVisible; - } - - /** - * Is validation made automatically visible on commit? - * - * See setValidationVisibleOnCommit(). - * - * @return true if validation is made automatically visible on commit. - */ - public boolean isValidationVisibleOnCommit() { - return validationVisibleOnCommit; - } - - /* - * Commit changes to the data source Don't add a JavaDoc comment here, we - * use the default one from the interface. - */ - @Override - public void commit() throws Buffered.SourceException, InvalidValueException { - - LinkedList<SourceException> problems = null; - - // Only commit on valid state if so requested - if (!isInvalidCommitted() && !isValid()) { - /* - * The values are not ok and we are told not to commit invalid - * values - */ - if (validationVisibleOnCommit) { - setValidationVisible(true); - } - - // Find the first invalid value and throw the exception - validate(); - } - - // Try to commit all - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - try { - final Field<?> f = (fields.get(i.next())); - // Commit only non-readonly fields. - if (!f.isReadOnly()) { - f.commit(); - } - } catch (final Buffered.SourceException e) { - if (problems == null) { - problems = new LinkedList<SourceException>(); - } - problems.add(e); - } - } - - // No problems occurred - if (problems == null) { - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - requestRepaint(); - } - return; - } - - // Commit problems - final Throwable[] causes = new Throwable[problems.size()]; - int index = 0; - for (final Iterator<SourceException> i = problems.iterator(); i - .hasNext();) { - causes[index++] = i.next(); - } - final Buffered.SourceException e = new Buffered.SourceException(this, - causes); - currentBufferedSourceException = e; - requestRepaint(); - throw e; - } - - /* - * Discards local changes and refresh values from the data source Don't add - * a JavaDoc comment here, we use the default one from the interface. - */ - @Override - public void discard() throws Buffered.SourceException { - - LinkedList<SourceException> problems = null; - - // Try to discard all changes - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - try { - (fields.get(i.next())).discard(); - } catch (final Buffered.SourceException e) { - if (problems == null) { - problems = new LinkedList<SourceException>(); - } - problems.add(e); - } - } - - // No problems occurred - if (problems == null) { - if (currentBufferedSourceException != null) { - currentBufferedSourceException = null; - requestRepaint(); - } - return; - } - - // Discards problems occurred - final Throwable[] causes = new Throwable[problems.size()]; - int index = 0; - for (final Iterator<SourceException> i = problems.iterator(); i - .hasNext();) { - causes[index++] = i.next(); - } - final Buffered.SourceException e = new Buffered.SourceException(this, - causes); - currentBufferedSourceException = e; - requestRepaint(); - throw e; - } - - /* - * Is the object modified but not committed? Don't add a JavaDoc comment - * here, we use the default one from the interface. - */ - @Override - public boolean isModified() { - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - final Field<?> f = fields.get(i.next()); - if (f != null && f.isModified()) { - return true; - } - - } - return false; - } - - /* - * Is the editor in a read-through mode? Don't add a JavaDoc comment here, - * we use the default one from the interface. - */ - @Override - @Deprecated - public boolean isReadThrough() { - return readThrough; - } - - /* - * Is the editor in a write-through mode? Don't add a JavaDoc comment here, - * we use the default one from the interface. - */ - @Override - @Deprecated - public boolean isWriteThrough() { - return writeThrough; - } - - /* - * Sets the editor's read-through mode to the specified status. Don't add a - * JavaDoc comment here, we use the default one from the interface. - */ - @Override - public void setReadThrough(boolean readThrough) { - if (readThrough != this.readThrough) { - this.readThrough = readThrough; - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - (fields.get(i.next())).setReadThrough(readThrough); - } - } - } - - /* - * Sets the editor's read-through mode to the specified status. Don't add a - * JavaDoc comment here, we use the default one from the interface. - */ - @Override - public void setWriteThrough(boolean writeThrough) throws SourceException, - InvalidValueException { - if (writeThrough != this.writeThrough) { - this.writeThrough = writeThrough; - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - (fields.get(i.next())).setWriteThrough(writeThrough); - } - } - } - - /** - * Adds a new property to form and create corresponding field. - * - * @see com.vaadin.data.Item#addItemProperty(Object, Property) - */ - @Override - public boolean addItemProperty(Object id, Property property) { - - // Checks inputs - if (id == null || property == null) { - throw new NullPointerException("Id and property must be non-null"); - } - - // Checks that the property id is not reserved - if (propertyIds.contains(id)) { - return false; - } - - propertyIds.add(id); - ownProperties.put(id, property); - - // Gets suitable field - final Field<?> field = fieldFactory.createField(this, id, this); - if (field == null) { - return false; - } - - // Configures the field - bindPropertyToField(id, property, field); - - // Register and attach the created field - addField(id, field); - - return true; - } - - /** - * Registers the field with the form and adds the field to the form layout. - * - * <p> - * The property id must not be already used in the form. - * </p> - * - * <p> - * This field is added to the layout using the - * {@link #attachField(Object, Field)} method. - * </p> - * - * @param propertyId - * the Property id the the field. - * @param field - * the field which should be added to the form. - */ - public void addField(Object propertyId, Field<?> field) { - registerField(propertyId, field); - attachField(propertyId, field); - requestRepaint(); - } - - /** - * Register the field with the form. All registered fields are validated - * when the form is validated and also committed when the form is committed. - * - * <p> - * The property id must not be already used in the form. - * </p> - * - * - * @param propertyId - * the Property id of the field. - * @param field - * the Field that should be registered - */ - private void registerField(Object propertyId, Field<?> field) { - if (propertyId == null || field == null) { - return; - } - - fields.put(propertyId, field); - field.addListener(fieldValueChangeListener); - if (!propertyIds.contains(propertyId)) { - // adding a field directly - propertyIds.addLast(propertyId); - } - - // Update the read and write through status and immediate to match the - // form. - // Should this also include invalidCommitted (#3993)? - field.setReadThrough(readThrough); - field.setWriteThrough(writeThrough); - if (isImmediate() && field instanceof AbstractComponent) { - ((AbstractComponent) field).setImmediate(true); - } - } - - /** - * Adds the field to the form layout. - * <p> - * The field is added to the form layout in the default position (the - * position used by {@link Layout#addComponent(Component)}. If the - * underlying layout is a {@link CustomLayout} the field is added to the - * CustomLayout location given by the string representation of the property - * id using {@link CustomLayout#addComponent(Component, String)}. - * </p> - * - * <p> - * Override this method to control how the fields are added to the layout. - * </p> - * - * @param propertyId - * @param field - */ - protected void attachField(Object propertyId, Field field) { - if (propertyId == null || field == null) { - return; - } - - Layout layout = getLayout(); - if (layout instanceof CustomLayout) { - ((CustomLayout) layout).addComponent(field, propertyId.toString()); - } else { - layout.addComponent(field); - } - - } - - /** - * The property identified by the property id. - * - * <p> - * The property data source of the field specified with property id is - * returned. If there is a (with specified property id) having no data - * source, the field is returned instead of the data source. - * </p> - * - * @see com.vaadin.data.Item#getItemProperty(Object) - */ - @Override - public Property<?> getItemProperty(Object id) { - final Field<?> field = fields.get(id); - if (field == null) { - // field does not exist or it is not (yet) created for this property - return ownProperties.get(id); - } - final Property<?> property = field.getPropertyDataSource(); - - if (property != null) { - return property; - } else { - return field; - } - } - - /** - * Gets the field identified by the propertyid. - * - * @param propertyId - * the id of the property. - */ - public Field<?> getField(Object propertyId) { - return fields.get(propertyId); - } - - /* Documented in interface */ - @Override - public Collection<?> getItemPropertyIds() { - return Collections.unmodifiableCollection(propertyIds); - } - - /** - * Removes the property and corresponding field from the form. - * - * @see com.vaadin.data.Item#removeItemProperty(Object) - */ - @Override - public boolean removeItemProperty(Object id) { - ownProperties.remove(id); - - final Field<?> field = fields.get(id); - - if (field != null) { - propertyIds.remove(id); - fields.remove(id); - detachField(field); - field.removeListener(fieldValueChangeListener); - return true; - } - - return false; - } - - /** - * Called when a form field is detached from a Form. Typically when a new - * Item is assigned to Form via {@link #setItemDataSource(Item)}. - * <p> - * Override this method to control how the fields are removed from the - * layout. - * </p> - * - * @param field - * the field to be detached from the forms layout. - */ - protected void detachField(final Field field) { - Component p = field.getParent(); - if (p instanceof ComponentContainer) { - ((ComponentContainer) p).removeComponent(field); - } - } - - /** - * Removes all properties and fields from the form. - * - * @return the Success of the operation. Removal of all fields succeeded if - * (and only if) the return value is <code>true</code>. - */ - public boolean removeAllProperties() { - final Object[] properties = propertyIds.toArray(); - boolean success = true; - - for (int i = 0; i < properties.length; i++) { - if (!removeItemProperty(properties[i])) { - success = false; - } - } - - return success; - } - - /* Documented in the interface */ - @Override - public Item getItemDataSource() { - return itemDatasource; - } - - /** - * Sets the item datasource for the form. - * - * <p> - * Setting item datasource clears any fields, the form might contain and - * adds all the properties as fields to the form. - * </p> - * - * @see com.vaadin.data.Item.Viewer#setItemDataSource(Item) - */ - @Override - public void setItemDataSource(Item newDataSource) { - setItemDataSource(newDataSource, - newDataSource != null ? newDataSource.getItemPropertyIds() - : null); - } - - /** - * Set the item datasource for the form, but limit the form contents to - * specified properties of the item. - * - * <p> - * Setting item datasource clears any fields, the form might contain and - * adds the specified the properties as fields to the form, in the specified - * order. - * </p> - * - * @see com.vaadin.data.Item.Viewer#setItemDataSource(Item) - */ - public void setItemDataSource(Item newDataSource, Collection<?> propertyIds) { - - if (getLayout() instanceof GridLayout) { - GridLayout gl = (GridLayout) getLayout(); - if (gridlayoutCursorX == -1) { - // first setItemDataSource, remember initial cursor - gridlayoutCursorX = gl.getCursorX(); - gridlayoutCursorY = gl.getCursorY(); - } else { - // restore initial cursor - gl.setCursorX(gridlayoutCursorX); - gl.setCursorY(gridlayoutCursorY); - } - } - - // Removes all fields first from the form - removeAllProperties(); - - // Sets the datasource - itemDatasource = newDataSource; - - // If the new datasource is null, just set null datasource - if (itemDatasource == null) { - requestRepaint(); - return; - } - - // Adds all the properties to this form - for (final Iterator<?> i = propertyIds.iterator(); i.hasNext();) { - final Object id = i.next(); - final Property<?> property = itemDatasource.getItemProperty(id); - if (id != null && property != null) { - final Field<?> f = fieldFactory.createField(itemDatasource, id, - this); - if (f != null) { - bindPropertyToField(id, property, f); - addField(id, f); - } - } - } - } - - /** - * Binds an item property to a field. The default behavior is to bind - * property straight to Field. If Property.Viewer type property (e.g. - * PropertyFormatter) is already set for field, the property is bound to - * that Property.Viewer. - * - * @param propertyId - * @param property - * @param field - * @since 6.7.3 - */ - protected void bindPropertyToField(final Object propertyId, - final Property property, final Field field) { - // check if field has a property that is Viewer set. In that case we - // expect developer has e.g. PropertyFormatter that he wishes to use and - // assign the property to the Viewer instead. - boolean hasFilterProperty = field.getPropertyDataSource() != null - && (field.getPropertyDataSource() instanceof Property.Viewer); - if (hasFilterProperty) { - ((Property.Viewer) field.getPropertyDataSource()) - .setPropertyDataSource(property); - } else { - field.setPropertyDataSource(property); - } - } - - /** - * Gets the layout of the form. - * - * <p> - * By default form uses <code>OrderedLayout</code> with <code>form</code> - * -style. - * </p> - * - * @return the Layout of the form. - */ - public Layout getLayout() { - return (Layout) getState().getLayout(); - } - - /** - * Sets the layout of the form. - * - * <p> - * If set to null then Form uses a FormLayout by default. - * </p> - * - * @param layout - * the layout of the form. - */ - public void setLayout(Layout layout) { - - // Use orderedlayout by default - if (layout == null) { - layout = new FormLayout(); - } - - // reset cursor memory - gridlayoutCursorX = -1; - gridlayoutCursorY = -1; - - // Move fields from previous layout - if (getLayout() != null) { - final Object[] properties = propertyIds.toArray(); - for (int i = 0; i < properties.length; i++) { - Field<?> f = getField(properties[i]); - detachField(f); - if (layout instanceof CustomLayout) { - ((CustomLayout) layout).addComponent(f, - properties[i].toString()); - } else { - layout.addComponent(f); - } - } - - getLayout().setParent(null); - } - - // Replace the previous layout - layout.setParent(this); - getState().setLayout(layout); - - // Hierarchy has changed so we need to repaint (this could be a - // hierarchy repaint only) - requestRepaint(); - } - - /** - * Sets the form field to be selectable from static list of changes. - * - * <p> - * The list values and descriptions are given as array. The value-array must - * contain the current value of the field and the lengths of the arrays must - * match. Null values are not supported. - * </p> - * - * Note: since Vaadin 7.0, returns an {@link AbstractSelect} instead of a - * {@link Select}. - * - * @param propertyId - * the id of the property. - * @param values - * @param descriptions - * @return the select property generated - */ - public AbstractSelect replaceWithSelect(Object propertyId, Object[] values, - Object[] descriptions) { - - // Checks the parameters - if (propertyId == null || values == null || descriptions == null) { - throw new NullPointerException("All parameters must be non-null"); - } - if (values.length != descriptions.length) { - throw new IllegalArgumentException( - "Value and description list are of different size"); - } - - // Gets the old field - final Field<?> oldField = fields.get(propertyId); - if (oldField == null) { - throw new IllegalArgumentException("Field with given propertyid '" - + propertyId.toString() + "' can not be found."); - } - final Object value = oldField.getPropertyDataSource() == null ? oldField - .getValue() : oldField.getPropertyDataSource().getValue(); - - // Checks that the value exists and check if the select should - // be forced in multiselect mode - boolean found = false; - boolean isMultiselect = false; - for (int i = 0; i < values.length && !found; i++) { - if (values[i] == value - || (value != null && value.equals(values[i]))) { - found = true; - } - } - if (value != null && !found) { - if (value instanceof Collection) { - for (final Iterator<?> it = ((Collection<?>) value).iterator(); it - .hasNext();) { - final Object val = it.next(); - found = false; - for (int i = 0; i < values.length && !found; i++) { - if (values[i] == val - || (val != null && val.equals(values[i]))) { - found = true; - } - } - if (!found) { - throw new IllegalArgumentException( - "Currently selected value '" + val - + "' of property '" - + propertyId.toString() - + "' was not found"); - } - } - isMultiselect = true; - } else { - throw new IllegalArgumentException("Current value '" + value - + "' of property '" + propertyId.toString() - + "' was not found"); - } - } - - // Creates the new field matching to old field parameters - final AbstractSelect newField = isMultiselect ? new ListSelect() - : new Select(); - newField.setCaption(oldField.getCaption()); - newField.setReadOnly(oldField.isReadOnly()); - newField.setReadThrough(oldField.isReadThrough()); - newField.setWriteThrough(oldField.isWriteThrough()); - - // Creates the options list - newField.addContainerProperty("desc", String.class, ""); - newField.setItemCaptionPropertyId("desc"); - for (int i = 0; i < values.length; i++) { - Object id = values[i]; - final Item item; - if (id == null) { - id = newField.addItem(); - item = newField.getItem(id); - newField.setNullSelectionItemId(id); - } else { - item = newField.addItem(id); - } - - if (item != null) { - item.getItemProperty("desc").setValue( - descriptions[i].toString()); - } - } - - // Sets the property data source - final Property<?> property = oldField.getPropertyDataSource(); - oldField.setPropertyDataSource(null); - newField.setPropertyDataSource(property); - - // Replaces the old field with new one - getLayout().replaceComponent(oldField, newField); - fields.put(propertyId, newField); - newField.addListener(fieldValueChangeListener); - oldField.removeListener(fieldValueChangeListener); - - return newField; - } - - /** - * Checks the validity of the Form and all of its fields. - * - * @see com.vaadin.data.Validatable#validate() - */ - @Override - public void validate() throws InvalidValueException { - super.validate(); - for (final Iterator<Object> i = propertyIds.iterator(); i.hasNext();) { - (fields.get(i.next())).validate(); - } - } - - /** - * Checks the validabtable object accept invalid values. - * - * @see com.vaadin.data.Validatable#isInvalidAllowed() - */ - @Override - public boolean isInvalidAllowed() { - return true; - } - - /** - * Should the validabtable object accept invalid values. - * - * @see com.vaadin.data.Validatable#setInvalidAllowed(boolean) - */ - @Override - public void setInvalidAllowed(boolean invalidValueAllowed) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - } - - /** - * Sets the component's to read-only mode to the specified state. - * - * @see com.vaadin.ui.Component#setReadOnly(boolean) - */ - @Override - public void setReadOnly(boolean readOnly) { - super.setReadOnly(readOnly); - for (final Iterator<?> i = propertyIds.iterator(); i.hasNext();) { - (fields.get(i.next())).setReadOnly(readOnly); - } - } - - /** - * Sets the field factory used by this Form to genarate Fields for - * properties. - * - * {@link FormFieldFactory} is used to create fields for form properties. - * {@link DefaultFieldFactory} is used by default. - * - * @param fieldFactory - * the new factory used to create the fields. - * @see Field - * @see FormFieldFactory - */ - public void setFormFieldFactory(FormFieldFactory fieldFactory) { - this.fieldFactory = fieldFactory; - } - - /** - * Get the field factory of the form. - * - * @return the FormFieldFactory Factory used to create the fields. - */ - public FormFieldFactory getFormFieldFactory() { - return fieldFactory; - } - - /** - * Gets the field type. - * - * @see com.vaadin.ui.AbstractField#getType() - */ - @Override - public Class<?> getType() { - if (getPropertyDataSource() != null) { - return getPropertyDataSource().getType(); - } - return Object.class; - } - - /** - * Sets the internal value. - * - * This is relevant when the Form is used as Field. - * - * @see com.vaadin.ui.AbstractField#setInternalValue(java.lang.Object) - */ - @Override - protected void setInternalValue(Object newValue) { - // Stores the old value - final Object oldValue = propertyValue; - - // Sets the current Value - super.setInternalValue(newValue); - propertyValue = newValue; - - // Ignores form updating if data object has not changed. - if (oldValue != newValue) { - setFormDataSource(newValue, getVisibleItemProperties()); - } - } - - /** - * Gets the first focusable field in form. If there are enabled, - * non-read-only fields, the first one of them is returned. Otherwise, the - * field for the first property (or null if none) is returned. - * - * @return the Field. - */ - private Field<?> getFirstFocusableField() { - if (getItemPropertyIds() != null) { - for (Object id : getItemPropertyIds()) { - if (id != null) { - Field<?> field = getField(id); - if (field.isEnabled() && !field.isReadOnly()) { - return field; - } - } - } - // fallback: first field if none of the fields is enabled and - // writable - Object id = getItemPropertyIds().iterator().next(); - if (id != null) { - return getField(id); - } - } - return null; - } - - /** - * Updates the internal form datasource. - * - * Method setFormDataSource. - * - * @param data - * @param properties - */ - protected void setFormDataSource(Object data, Collection<?> properties) { - - // If data is an item use it. - Item item = null; - if (data instanceof Item) { - item = (Item) data; - } else if (data != null) { - item = new BeanItem<Object>(data); - } - - // Sets the datasource to form - if (item != null && properties != null) { - // Shows only given properties - this.setItemDataSource(item, properties); - } else { - // Shows all properties - this.setItemDataSource(item); - } - } - - /** - * Returns the visibleProperties. - * - * @return the Collection of visible Item properites. - */ - public Collection<?> getVisibleItemProperties() { - return visibleItemProperties; - } - - /** - * Sets the visibleProperties. - * - * @param visibleProperties - * the visibleProperties to set. - */ - public void setVisibleItemProperties(Collection<?> visibleProperties) { - visibleItemProperties = visibleProperties; - Object value = getValue(); - if (value == null) { - value = itemDatasource; - } - setFormDataSource(value, getVisibleItemProperties()); - } - - /** - * Sets the visibleProperties. - * - * @param visibleProperties - * the visibleProperties to set. - */ - public void setVisibleItemProperties(Object[] visibleProperties) { - LinkedList<Object> v = new LinkedList<Object>(); - for (int i = 0; i < visibleProperties.length; i++) { - v.add(visibleProperties[i]); - } - setVisibleItemProperties(v); - } - - /** - * Focuses the first field in the form. - * - * @see com.vaadin.ui.Component.Focusable#focus() - */ - @Override - public void focus() { - final Field<?> f = getFirstFocusableField(); - if (f != null) { - f.focus(); - } - } - - /** - * Sets the Tabulator index of this Focusable component. - * - * @see com.vaadin.ui.Component.Focusable#setTabIndex(int) - */ - @Override - public void setTabIndex(int tabIndex) { - super.setTabIndex(tabIndex); - for (final Iterator<?> i = getItemPropertyIds().iterator(); i.hasNext();) { - (getField(i.next())).setTabIndex(tabIndex); - } - } - - /** - * Setting the form to be immediate also sets all the fields of the form to - * the same state. - */ - @Override - public void setImmediate(boolean immediate) { - super.setImmediate(immediate); - for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) { - Field<?> f = i.next(); - if (f instanceof AbstractComponent) { - ((AbstractComponent) f).setImmediate(immediate); - } - } - } - - /** Form is empty if all of its fields are empty. */ - @Override - protected boolean isEmpty() { - - for (Iterator<Field<?>> i = fields.values().iterator(); i.hasNext();) { - Field<?> f = i.next(); - if (f instanceof AbstractField) { - if (!((AbstractField<?>) f).isEmpty()) { - return false; - } - } - } - - return true; - } - - /** - * Adding validators directly to form is not supported. - * - * Add the validators to form fields instead. - */ - @Override - public void addValidator(Validator validator) { - throw new UnsupportedOperationException(); - } - - /** - * Returns a layout that is rendered below normal form contents. This area - * can be used for example to include buttons related to form contents. - * - * @return layout rendered below normal form contents. - */ - public Layout getFooter() { - return (Layout) getState().getFooter(); - } - - /** - * Sets the layout that is rendered below normal form contents. Setting this - * to null will cause an empty HorizontalLayout to be rendered in the - * footer. - * - * @param footer - * the new footer layout - */ - public void setFooter(Layout footer) { - if (getFooter() != null) { - getFooter().setParent(null); - } - if (footer == null) { - footer = new HorizontalLayout(); - } - - getState().setFooter(footer); - footer.setParent(this); - - // Hierarchy has changed so we need to repaint (this could be a - // hierarchy repaint only) - requestRepaint(); - - } - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - if (getParent() != null && !getParent().isEnabled()) { - // some ancestor still disabled, don't update children - return; - } else { - getLayout().requestRepaintAll(); - } - } - - /* - * ACTIONS - */ - - /** - * Gets the {@link ActionManager} responsible for handling {@link Action}s - * added to this Form.<br/> - * Note that Form has another ActionManager inherited from - * {@link AbstractField}. The ownActionManager handles Actions attached to - * this Form specifically, while the ActionManager in AbstractField - * delegates to the containing Window (i.e global Actions). - * - * @return - */ - protected ActionManager getOwnActionManager() { - if (ownActionManager == null) { - ownActionManager = new ActionManager(this); - } - return ownActionManager; - } - - @Override - public void addActionHandler(Handler actionHandler) { - getOwnActionManager().addActionHandler(actionHandler); - } - - @Override - public void removeActionHandler(Handler actionHandler) { - if (ownActionManager != null) { - ownActionManager.removeActionHandler(actionHandler); - } - } - - /** - * Removes all action handlers - */ - public void removeAllActionHandlers() { - if (ownActionManager != null) { - ownActionManager.removeAllActionHandlers(); - } - } - - @Override - public <T extends Action & com.vaadin.event.Action.Listener> void addAction( - T action) { - getOwnActionManager().addAction(action); - } - - @Override - public <T extends Action & com.vaadin.event.Action.Listener> void removeAction( - T action) { - if (ownActionManager != null) { - ownActionManager.removeAction(action); - } - } - - @Override - public Iterator<Component> iterator() { - return getComponentIterator(); - } - - /** - * Modifiable and Serializable Iterator for the components, used by - * {@link Form#getComponentIterator()}. - */ - private class ComponentIterator implements Iterator<Component>, - Serializable { - - int i = 0; - - @Override - public boolean hasNext() { - if (i < getComponentCount()) { - return true; - } - return false; - } - - @Override - public Component next() { - if (!hasNext()) { - return null; - } - i++; - if (i == 1) { - return getLayout() != null ? getLayout() : getFooter(); - } else if (i == 2) { - return getFooter(); - } - return null; - } - - @Override - public void remove() { - if (i == 1) { - if (getLayout() != null) { - setLayout(null); - i = 0; - } else { - setFooter(null); - } - } else if (i == 2) { - setFooter(null); - } - } - } - - @Override - public Iterator<Component> getComponentIterator() { - return new ComponentIterator(); - } - - public int getComponentCount() { - int count = 0; - if (getLayout() != null) { - count++; - } - if (getFooter() != null) { - count++; - } - - return count; - } - - @Override - public boolean isComponentVisible(Component childComponent) { - return true; - }; -} diff --git a/src/com/vaadin/ui/FormFieldFactory.java b/src/com/vaadin/ui/FormFieldFactory.java deleted file mode 100644 index 1efa05c5f5..0000000000 --- a/src/com/vaadin/ui/FormFieldFactory.java +++ /dev/null @@ -1,41 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; - -import com.vaadin.data.Item; - -/** - * Factory interface for creating new Field-instances based on {@link Item}, - * property id and uiContext (the component responsible for displaying fields). - * Currently this interface is used by {@link Form}, but might later be used by - * some other components for {@link Field} generation. - * - * <p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.0 - * @see TableFieldFactory - */ -public interface FormFieldFactory extends Serializable { - /** - * Creates a field based on the item, property id and the component (most - * commonly {@link Form}) where the Field will be presented. - * - * @param item - * the item where the property belongs to. - * @param propertyId - * the Id of the property. - * @param uiContext - * the component where the field is presented, most commonly this - * is {@link Form}. uiContext will not necessary be the parent - * component of the field, but the one that is responsible for - * creating it. - * @return Field the field suitable for editing the specified data. - */ - Field<?> createField(Item item, Object propertyId, Component uiContext); -} diff --git a/src/com/vaadin/ui/FormLayout.java b/src/com/vaadin/ui/FormLayout.java deleted file mode 100644 index c0be784a7b..0000000000 --- a/src/com/vaadin/ui/FormLayout.java +++ /dev/null @@ -1,31 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -/** - * FormLayout is used by {@link Form} to layout fields. It may also be used - * separately without {@link Form}. - * - * FormLayout is a close relative to vertical {@link OrderedLayout}, but in - * FormLayout caption is rendered on left side of component. Required and - * validation indicators are between captions and fields. - * - * FormLayout does not currently support some advanced methods from - * OrderedLayout like setExpandRatio and setComponentAlignment. - * - * FormLayout by default has component spacing on. Also margin top and margin - * bottom are by default on. - * - */ -public class FormLayout extends AbstractOrderedLayout { - - public FormLayout() { - super(); - setSpacing(true); - setMargin(true, false, true, false); - setWidth(100, UNITS_PERCENTAGE); - } - -} diff --git a/src/com/vaadin/ui/GridLayout.java b/src/com/vaadin/ui/GridLayout.java deleted file mode 100644 index 2391a9cd3a..0000000000 --- a/src/com/vaadin/ui/GridLayout.java +++ /dev/null @@ -1,1415 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Map; -import java.util.Map.Entry; - -import com.vaadin.event.LayoutEvents.LayoutClickEvent; -import com.vaadin.event.LayoutEvents.LayoutClickListener; -import com.vaadin.event.LayoutEvents.LayoutClickNotifier; -import com.vaadin.shared.Connector; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.gridlayout.GridLayoutServerRpc; -import com.vaadin.shared.ui.gridlayout.GridLayoutState; -import com.vaadin.terminal.LegacyPaint; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.LayoutClickEventHandler; - -/** - * A layout where the components are laid out on a grid using cell coordinates. - * - * <p> - * The GridLayout also maintains a cursor for adding components in - * left-to-right, top-to-bottom order. - * </p> - * - * <p> - * Each component in a <code>GridLayout</code> uses a defined - * {@link GridLayout.Area area} (column1,row1,column2,row2) from the grid. The - * components may not overlap with the existing components - if you try to do so - * you will get an {@link OverlapsException}. Adding a component with cursor - * automatically extends the grid by increasing the grid height. - * </p> - * - * <p> - * The grid coordinates, which are specified by a row and column index, always - * start from 0 for the topmost row and the leftmost column. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class GridLayout extends AbstractLayout implements - Layout.AlignmentHandler, Layout.SpacingHandler, LayoutClickNotifier, - Vaadin6Component { - - private GridLayoutServerRpc rpc = new GridLayoutServerRpc() { - - @Override - public void layoutClick(MouseEventDetails mouseDetails, - Connector clickedConnector) { - fireEvent(LayoutClickEvent.createEvent(GridLayout.this, - mouseDetails, clickedConnector)); - - } - }; - /** - * Cursor X position: this is where the next component with unspecified x,y - * is inserted - */ - private int cursorX = 0; - - /** - * Cursor Y position: this is where the next component with unspecified x,y - * is inserted - */ - private int cursorY = 0; - - /** - * Contains all items that are placed on the grid. These are components with - * grid area definition. - */ - private final LinkedList<Area> areas = new LinkedList<Area>(); - - /** - * Mapping from components to their respective areas. - */ - private final LinkedList<Component> components = new LinkedList<Component>(); - - /** - * Mapping from components to alignments (horizontal + vertical). - */ - private Map<Component, Alignment> componentToAlignment = new HashMap<Component, Alignment>(); - - private static final Alignment ALIGNMENT_DEFAULT = Alignment.TOP_LEFT; - - /** - * Has there been rows inserted or deleted in the middle of the layout since - * the last paint operation. - */ - private boolean structuralChange = false; - - private Map<Integer, Float> columnExpandRatio = new HashMap<Integer, Float>(); - private Map<Integer, Float> rowExpandRatio = new HashMap<Integer, Float>(); - - /** - * Constructor for a grid of given size (number of columns and rows). - * - * The grid may grow or shrink later. Grid grows automatically if you add - * components outside its area. - * - * @param columns - * Number of columns in the grid. - * @param rows - * Number of rows in the grid. - */ - public GridLayout(int columns, int rows) { - setColumns(columns); - setRows(rows); - registerRpc(rpc); - } - - /** - * Constructs an empty (1x1) grid layout that is extended as needed. - */ - public GridLayout() { - this(1, 1); - } - - @Override - public GridLayoutState getState() { - return (GridLayoutState) super.getState(); - } - - /** - * <p> - * Adds a component to the grid in the specified area. The area is defined - * by specifying the upper left corner (column1, row1) and the lower right - * corner (column2, row2) of the area. The coordinates are zero-based. - * </p> - * - * <p> - * If the area overlaps with any of the existing components already present - * in the grid, the operation will fail and an {@link OverlapsException} is - * thrown. - * </p> - * - * @param component - * the component to be added. - * @param column1 - * the column of the upper left corner of the area <code>c</code> - * is supposed to occupy. The leftmost column has index 0. - * @param row1 - * the row of the upper left corner of the area <code>c</code> is - * supposed to occupy. The topmost row has index 0. - * @param column2 - * the column of the lower right corner of the area - * <code>c</code> is supposed to occupy. - * @param row2 - * the row of the lower right corner of the area <code>c</code> - * is supposed to occupy. - * @throws OverlapsException - * if the new component overlaps with any of the components - * already in the grid. - * @throws OutOfBoundsException - * if the cells are outside the grid area. - */ - public void addComponent(Component component, int column1, int row1, - int column2, int row2) throws OverlapsException, - OutOfBoundsException { - - if (component == null) { - throw new NullPointerException("Component must not be null"); - } - - // Checks that the component does not already exist in the container - if (components.contains(component)) { - throw new IllegalArgumentException( - "Component is already in the container"); - } - - // Creates the area - final Area area = new Area(component, column1, row1, column2, row2); - - // Checks the validity of the coordinates - if (column2 < column1 || row2 < row1) { - throw new IllegalArgumentException( - "Illegal coordinates for the component"); - } - if (column1 < 0 || row1 < 0 || column2 >= getColumns() - || row2 >= getRows()) { - throw new OutOfBoundsException(area); - } - - // Checks that newItem does not overlap with existing items - checkExistingOverlaps(area); - - // Inserts the component to right place at the list - // Respect top-down, left-right ordering - // component.setParent(this); - final Iterator<Area> i = areas.iterator(); - int index = 0; - boolean done = false; - while (!done && i.hasNext()) { - final Area existingArea = i.next(); - if ((existingArea.row1 >= row1 && existingArea.column1 > column1) - || existingArea.row1 > row1) { - areas.add(index, area); - components.add(index, component); - done = true; - } - index++; - } - if (!done) { - areas.addLast(area); - components.addLast(component); - } - - // Attempt to add to super - try { - super.addComponent(component); - } catch (IllegalArgumentException e) { - areas.remove(area); - components.remove(component); - throw e; - } - - // update cursor position, if it's within this area; use first position - // outside this area, even if it's occupied - if (cursorX >= column1 && cursorX <= column2 && cursorY >= row1 - && cursorY <= row2) { - // cursor within area - cursorX = column2 + 1; // one right of area - if (cursorX >= getColumns()) { - // overflowed columns - cursorX = 0; // first col - // move one row down, or one row under the area - cursorY = (column1 == 0 ? row2 : row1) + 1; - } else { - cursorY = row1; - } - } - - requestRepaint(); - } - - /** - * Tests if the given area overlaps with any of the items already on the - * grid. - * - * @param area - * the Area to be checked for overlapping. - * @throws OverlapsException - * if <code>area</code> overlaps with any existing area. - */ - private void checkExistingOverlaps(Area area) throws OverlapsException { - for (final Iterator<Area> i = areas.iterator(); i.hasNext();) { - final Area existingArea = i.next(); - if (existingArea.overlaps(area)) { - // Component not added, overlaps with existing component - throw new OverlapsException(existingArea); - } - } - } - - /** - * Adds the component to the grid in cells column1,row1 (NortWest corner of - * the area.) End coordinates (SouthEast corner of the area) are the same as - * column1,row1. The coordinates are zero-based. Component width and height - * is 1. - * - * @param component - * the component to be added. - * @param column - * the column index, starting from 0. - * @param row - * the row index, starting from 0. - * @throws OverlapsException - * if the new component overlaps with any of the components - * already in the grid. - * @throws OutOfBoundsException - * if the cell is outside the grid area. - */ - public void addComponent(Component component, int column, int row) - throws OverlapsException, OutOfBoundsException { - this.addComponent(component, column, row, column, row); - } - - /** - * Forces the next component to be added at the beginning of the next line. - * - * <p> - * Sets the cursor column to 0 and increments the cursor row by one. - * </p> - * - * <p> - * By calling this function you can ensure that no more components are added - * right of the previous component. - * </p> - * - * @see #space() - */ - public void newLine() { - cursorX = 0; - cursorY++; - } - - /** - * Moves the cursor forward by one. If the cursor goes out of the right grid - * border, it is moved to the first column of the next row. - * - * @see #newLine() - */ - public void space() { - cursorX++; - if (cursorX >= getColumns()) { - cursorX = 0; - cursorY++; - } - } - - /** - * Adds the component into this container to the cursor position. If the - * cursor position is already occupied, the cursor is moved forwards to find - * free position. If the cursor goes out from the bottom of the grid, the - * grid is automatically extended. - * - * @param component - * the component to be added. - */ - @Override - public void addComponent(Component component) { - - // Finds first available place from the grid - Area area; - boolean done = false; - while (!done) { - try { - area = new Area(component, cursorX, cursorY, cursorX, cursorY); - checkExistingOverlaps(area); - done = true; - } catch (final OverlapsException e) { - space(); - } - } - - // Extends the grid if needed - if (cursorX >= getColumns()) { - setColumns(cursorX + 1); - } - if (cursorY >= getRows()) { - setRows(cursorY + 1); - } - - addComponent(component, cursorX, cursorY); - } - - /** - * Removes the specified component from the layout. - * - * @param component - * the component to be removed. - */ - @Override - public void removeComponent(Component component) { - - // Check that the component is contained in the container - if (component == null || !components.contains(component)) { - return; - } - - Area area = null; - for (final Iterator<Area> i = areas.iterator(); area == null - && i.hasNext();) { - final Area a = i.next(); - if (a.getComponent() == component) { - area = a; - } - } - - components.remove(component); - if (area != null) { - areas.remove(area); - } - - componentToAlignment.remove(component); - - super.removeComponent(component); - - requestRepaint(); - } - - /** - * Removes the component specified by its cell coordinates. - * - * @param column - * the component's column, starting from 0. - * @param row - * the component's row, starting from 0. - */ - public void removeComponent(int column, int row) { - - // Finds the area - for (final Iterator<Area> i = areas.iterator(); i.hasNext();) { - final Area area = i.next(); - if (area.getColumn1() == column && area.getRow1() == row) { - removeComponent(area.getComponent()); - return; - } - } - } - - /** - * Gets an Iterator for the components contained in the layout. By using the - * Iterator it is possible to step through the contents of the layout. - * - * @return the Iterator of the components inside the layout. - */ - @Override - public Iterator<Component> getComponentIterator() { - return Collections.unmodifiableCollection(components).iterator(); - } - - /** - * Gets the number of components contained in the layout. Consistent with - * the iterator returned by {@link #getComponentIterator()}. - * - * @return the number of contained components - */ - @Override - public int getComponentCount() { - return components.size(); - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // TODO Remove once Vaadin6Component is no longer implemented - } - - /** - * Paints the contents of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - // TODO refactor attribute names in future release. - target.addAttribute("structuralChange", structuralChange); - structuralChange = false; - - // Area iterator - final Iterator<Area> areaiterator = areas.iterator(); - - // Current item to be processed (fetch first item) - Area area = areaiterator.hasNext() ? (Area) areaiterator.next() : null; - - // Collects rowspan related information here - final HashMap<Integer, Integer> cellUsed = new HashMap<Integer, Integer>(); - - // Empty cell collector - int emptyCells = 0; - - final String[] alignmentsArray = new String[components.size()]; - final Integer[] columnExpandRatioArray = new Integer[getColumns()]; - final Integer[] rowExpandRatioArray = new Integer[getRows()]; - - int realColExpandRatioSum = 0; - float colSum = getExpandRatioSum(columnExpandRatio); - if (colSum == 0) { - // no columns has been expanded, all cols have same expand - // rate - float equalSize = 1 / (float) getColumns(); - int myRatio = Math.round(equalSize * 1000); - for (int i = 0; i < getColumns(); i++) { - columnExpandRatioArray[i] = myRatio; - } - realColExpandRatioSum = myRatio * getColumns(); - } else { - for (int i = 0; i < getColumns(); i++) { - int myRatio = Math - .round((getColumnExpandRatio(i) / colSum) * 1000); - columnExpandRatioArray[i] = myRatio; - realColExpandRatioSum += myRatio; - } - } - - boolean equallyDividedRows = false; - int realRowExpandRatioSum = 0; - float rowSum = getExpandRatioSum(rowExpandRatio); - if (rowSum == 0) { - // no rows have been expanded - equallyDividedRows = true; - float equalSize = 1 / (float) getRows(); - int myRatio = Math.round(equalSize * 1000); - for (int i = 0; i < getRows(); i++) { - rowExpandRatioArray[i] = myRatio; - } - realRowExpandRatioSum = myRatio * getRows(); - } - - int index = 0; - - // Iterates every applicable row - for (int cury = 0; cury < getRows(); cury++) { - target.startTag("gr"); - - if (!equallyDividedRows) { - int myRatio = Math - .round((getRowExpandRatio(cury) / rowSum) * 1000); - rowExpandRatioArray[cury] = myRatio; - realRowExpandRatioSum += myRatio; - - } - // Iterates every applicable column - for (int curx = 0; curx < getColumns(); curx++) { - - // Checks if current item is located at curx,cury - if (area != null && (area.row1 == cury) - && (area.column1 == curx)) { - - // First check if empty cell needs to be rendered - if (emptyCells > 0) { - target.startTag("gc"); - target.addAttribute("x", curx - emptyCells); - target.addAttribute("y", cury); - if (emptyCells > 1) { - target.addAttribute("w", emptyCells); - } - target.endTag("gc"); - emptyCells = 0; - } - - // Now proceed rendering current item - final int cols = (area.column2 - area.column1) + 1; - final int rows = (area.row2 - area.row1) + 1; - target.startTag("gc"); - - target.addAttribute("x", curx); - target.addAttribute("y", cury); - - if (cols > 1) { - target.addAttribute("w", cols); - } - if (rows > 1) { - target.addAttribute("h", rows); - } - LegacyPaint.paint(area.getComponent(), target); - - alignmentsArray[index++] = String - .valueOf(getComponentAlignment(area.getComponent()) - .getBitMask()); - - target.endTag("gc"); - - // Fetch next item - if (areaiterator.hasNext()) { - area = areaiterator.next(); - } else { - area = null; - } - - // Updates the cellUsed if rowspan needed - if (rows > 1) { - int spannedx = curx; - for (int j = 1; j <= cols; j++) { - cellUsed.put(new Integer(spannedx), new Integer( - cury + rows - 1)); - spannedx++; - } - } - - // Skips the current item's spanned columns - if (cols > 1) { - curx += cols - 1; - } - - } else { - - // Checks against cellUsed, render space or ignore cell - if (cellUsed.containsKey(new Integer(curx))) { - - // Current column contains already an item, - // check if rowspan affects at current x,y position - final int rowspanDepth = cellUsed - .get(new Integer(curx)).intValue(); - - if (rowspanDepth >= cury) { - - // ignore cell - // Check if empty cell needs to be rendered - if (emptyCells > 0) { - target.startTag("gc"); - target.addAttribute("x", curx - emptyCells); - target.addAttribute("y", cury); - if (emptyCells > 1) { - target.addAttribute("w", emptyCells); - } - target.endTag("gc"); - - emptyCells = 0; - } - } else { - - // empty cell is needed - emptyCells++; - - // Removes the cellUsed key as it has become - // obsolete - cellUsed.remove(Integer.valueOf(curx)); - } - } else { - - // empty cell is needed - emptyCells++; - } - } - - } // iterates every column - - // Last column handled of current row - - // Checks if empty cell needs to be rendered - if (emptyCells > 0) { - target.startTag("gc"); - target.addAttribute("x", getColumns() - emptyCells); - target.addAttribute("y", cury); - if (emptyCells > 1) { - target.addAttribute("w", emptyCells); - } - target.endTag("gc"); - - emptyCells = 0; - } - - target.endTag("gr"); - } // iterates every row - - // Last row handled - - // correct possible rounding error - if (rowExpandRatioArray.length > 0) { - rowExpandRatioArray[0] -= realRowExpandRatioSum - 1000; - } - if (columnExpandRatioArray.length > 0) { - columnExpandRatioArray[0] -= realColExpandRatioSum - 1000; - } - - target.addAttribute("colExpand", columnExpandRatioArray); - target.addAttribute("rowExpand", rowExpandRatioArray); - - // Add child component alignment info to layout tag - target.addAttribute("alignments", alignmentsArray); - - } - - private float getExpandRatioSum(Map<Integer, Float> ratioMap) { - float sum = 0; - for (Iterator<Entry<Integer, Float>> iterator = ratioMap.entrySet() - .iterator(); iterator.hasNext();) { - sum += iterator.next().getValue(); - } - return sum; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.AlignmentHandler#getComponentAlignment(com - * .vaadin.ui.Component) - */ - @Override - public Alignment getComponentAlignment(Component childComponent) { - Alignment alignment = componentToAlignment.get(childComponent); - if (alignment == null) { - return ALIGNMENT_DEFAULT; - } else { - return alignment; - } - } - - /** - * Defines a rectangular area of cells in a GridLayout. - * - * <p> - * Also maintains a reference to the component contained in the area. - * </p> - * - * <p> - * The area is specified by the cell coordinates of its upper left corner - * (column1,row1) and lower right corner (column2,row2). As otherwise with - * GridLayout, the column and row coordinates start from zero. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class Area implements Serializable { - - /** - * The column of the upper left corner cell of the area. - */ - private final int column1; - - /** - * The row of the upper left corner cell of the area. - */ - private int row1; - - /** - * The column of the lower right corner cell of the area. - */ - private final int column2; - - /** - * The row of the lower right corner cell of the area. - */ - private int row2; - - /** - * Component painted in the area. - */ - private Component component; - - /** - * <p> - * Construct a new area on a grid. - * </p> - * - * @param component - * the component connected to the area. - * @param column1 - * The column of the upper left corner cell of the area. The - * leftmost column has index 0. - * @param row1 - * The row of the upper left corner cell of the area. The - * topmost row has index 0. - * @param column2 - * The column of the lower right corner cell of the area. The - * leftmost column has index 0. - * @param row2 - * The row of the lower right corner cell of the area. The - * topmost row has index 0. - */ - public Area(Component component, int column1, int row1, int column2, - int row2) { - this.column1 = column1; - this.row1 = row1; - this.column2 = column2; - this.row2 = row2; - this.component = component; - } - - /** - * Tests if this Area overlaps with another Area. - * - * @param other - * the other Area that is to be tested for overlap with this - * area - * @return <code>true</code> if <code>other</code> area overlaps with - * this on, <code>false</code> if it does not. - */ - public boolean overlaps(Area other) { - return column1 <= other.getColumn2() && row1 <= other.getRow2() - && column2 >= other.getColumn1() && row2 >= other.getRow1(); - - } - - /** - * Gets the component connected to the area. - * - * @return the Component. - */ - public Component getComponent() { - return component; - } - - /** - * Sets the component connected to the area. - * - * <p> - * This function only sets the value in the data structure and does not - * send any events or set parents. - * </p> - * - * @param newComponent - * the new connected overriding the existing one. - */ - protected void setComponent(Component newComponent) { - component = newComponent; - } - - /** - * @deprecated Use {@link #getColumn1()} instead. - */ - @Deprecated - public int getX1() { - return getColumn1(); - } - - /** - * Gets the column of the top-left corner cell. - * - * @return the column of the top-left corner cell. - */ - public int getColumn1() { - return column1; - } - - /** - * @deprecated Use {@link #getColumn2()} instead. - */ - @Deprecated - public int getX2() { - return getColumn2(); - } - - /** - * Gets the column of the bottom-right corner cell. - * - * @return the column of the bottom-right corner cell. - */ - public int getColumn2() { - return column2; - } - - /** - * @deprecated Use {@link #getRow1()} instead. - */ - @Deprecated - public int getY1() { - return getRow1(); - } - - /** - * Gets the row of the top-left corner cell. - * - * @return the row of the top-left corner cell. - */ - public int getRow1() { - return row1; - } - - /** - * @deprecated Use {@link #getRow2()} instead. - */ - @Deprecated - public int getY2() { - return getRow2(); - } - - /** - * Gets the row of the bottom-right corner cell. - * - * @return the row of the bottom-right corner cell. - */ - public int getRow2() { - return row2; - } - - } - - /** - * Gridlayout does not support laying components on top of each other. An - * <code>OverlapsException</code> is thrown when a component already exists - * (even partly) at the same space on a grid with the new component. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class OverlapsException extends java.lang.RuntimeException { - - private final Area existingArea; - - /** - * Constructs an <code>OverlapsException</code>. - * - * @param existingArea - */ - public OverlapsException(Area existingArea) { - this.existingArea = existingArea; - } - - @Override - public String getMessage() { - StringBuilder sb = new StringBuilder(); - Component component = existingArea.getComponent(); - sb.append(component); - sb.append("( type = "); - sb.append(component.getClass().getName()); - if (component.getCaption() != null) { - sb.append(", caption = \""); - sb.append(component.getCaption()); - sb.append("\""); - } - sb.append(")"); - sb.append(" is already added to "); - sb.append(existingArea.column1); - sb.append(","); - sb.append(existingArea.column1); - sb.append(","); - sb.append(existingArea.row1); - sb.append(","); - sb.append(existingArea.row2); - sb.append("(column1, column2, row1, row2)."); - - return sb.toString(); - } - - /** - * Gets the area . - * - * @return the existing area. - */ - public Area getArea() { - return existingArea; - } - } - - /** - * An <code>Exception</code> object which is thrown when an area exceeds the - * bounds of the grid. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class OutOfBoundsException extends java.lang.RuntimeException { - - private final Area areaOutOfBounds; - - /** - * Constructs an <code>OoutOfBoundsException</code> with the specified - * detail message. - * - * @param areaOutOfBounds - */ - public OutOfBoundsException(Area areaOutOfBounds) { - this.areaOutOfBounds = areaOutOfBounds; - } - - /** - * Gets the area that is out of bounds. - * - * @return the area out of Bound. - */ - public Area getArea() { - return areaOutOfBounds; - } - } - - /** - * Sets the number of columns in the grid. The column count can not be - * reduced if there are any areas that would be outside of the shrunk grid. - * - * @param columns - * the new number of columns in the grid. - */ - public void setColumns(int columns) { - - // The the param - if (columns < 1) { - throw new IllegalArgumentException( - "The number of columns and rows in the grid must be at least 1"); - } - - // In case of no change - if (getColumns() == columns) { - return; - } - - // Checks for overlaps - if (getColumns() > columns) { - for (final Iterator<Area> i = areas.iterator(); i.hasNext();) { - final Area area = i.next(); - if (area.column2 >= columns) { - throw new OutOfBoundsException(area); - } - } - } - - getState().setColumns(columns); - - requestRepaint(); - } - - /** - * Get the number of columns in the grid. - * - * @return the number of columns in the grid. - */ - public int getColumns() { - return getState().getColumns(); - } - - /** - * Sets the number of rows in the grid. The number of rows can not be - * reduced if there are any areas that would be outside of the shrunk grid. - * - * @param rows - * the new number of rows in the grid. - */ - public void setRows(int rows) { - - // The the param - if (rows < 1) { - throw new IllegalArgumentException( - "The number of columns and rows in the grid must be at least 1"); - } - - // In case of no change - if (getRows() == rows) { - return; - } - - // Checks for overlaps - if (getRows() > rows) { - for (final Iterator<Area> i = areas.iterator(); i.hasNext();) { - final Area area = i.next(); - if (area.row2 >= rows) { - throw new OutOfBoundsException(area); - } - } - } - - getState().setRows(rows); - - requestRepaint(); - } - - /** - * Get the number of rows in the grid. - * - * @return the number of rows in the grid. - */ - public int getRows() { - return getState().getRows(); - } - - /** - * Gets the current x-position (column) of the cursor. - * - * <p> - * The cursor position points the position for the next component that is - * added without specifying its coordinates (grid cell). When the cursor - * position is occupied, the next component will be added to first free - * position after the cursor. - * </p> - * - * @return the grid column the cursor is on, starting from 0. - */ - public int getCursorX() { - return cursorX; - } - - /** - * Sets the current cursor x-position. This is usually handled automatically - * by GridLayout. - * - * @param cursorX - */ - public void setCursorX(int cursorX) { - this.cursorX = cursorX; - } - - /** - * Gets the current y-position (row) of the cursor. - * - * <p> - * The cursor position points the position for the next component that is - * added without specifying its coordinates (grid cell). When the cursor - * position is occupied, the next component will be added to the first free - * position after the cursor. - * </p> - * - * @return the grid row the Cursor is on. - */ - public int getCursorY() { - return cursorY; - } - - /** - * Sets the current y-coordinate (row) of the cursor. This is usually - * handled automatically by GridLayout. - * - * @param cursorY - * the row number, starting from 0 for the topmost row. - */ - public void setCursorY(int cursorY) { - this.cursorY = cursorY; - } - - /* Documented in superclass */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - - // Gets the locations - Area oldLocation = null; - Area newLocation = null; - for (final Iterator<Area> i = areas.iterator(); i.hasNext();) { - final Area location = i.next(); - final Component component = location.getComponent(); - if (component == oldComponent) { - oldLocation = location; - } - if (component == newComponent) { - newLocation = location; - } - } - - if (oldLocation == null) { - addComponent(newComponent); - } else if (newLocation == null) { - removeComponent(oldComponent); - addComponent(newComponent, oldLocation.getColumn1(), - oldLocation.getRow1(), oldLocation.getColumn2(), - oldLocation.getRow2()); - } else { - oldLocation.setComponent(newComponent); - newLocation.setComponent(oldComponent); - requestRepaint(); - } - } - - /* - * Removes all components from this container. - * - * @see com.vaadin.ui.ComponentContainer#removeAllComponents() - */ - @Override - public void removeAllComponents() { - super.removeAllComponents(); - componentToAlignment = new HashMap<Component, Alignment>(); - cursorX = 0; - cursorY = 0; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.AlignmentHandler#setComponentAlignment(com - * .vaadin.ui.Component, int, int) - */ - @Override - public void setComponentAlignment(Component childComponent, - int horizontalAlignment, int verticalAlignment) { - componentToAlignment.put(childComponent, new Alignment( - horizontalAlignment + verticalAlignment)); - requestRepaint(); - } - - @Override - public void setComponentAlignment(Component childComponent, - Alignment alignment) { - componentToAlignment.put(childComponent, alignment); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.SpacingHandler#setSpacing(boolean) - */ - @Override - public void setSpacing(boolean spacing) { - getState().setSpacing(spacing); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Layout.SpacingHandler#isSpacing() - */ - @Override - public boolean isSpacing() { - return getState().isSpacing(); - } - - /** - * Inserts an empty row at the specified position in the grid. - * - * @param row - * Index of the row before which the new row will be inserted. - * The leftmost row has index 0. - */ - public void insertRow(int row) { - if (row > getRows()) { - throw new IllegalArgumentException("Cannot insert row at " + row - + " in a gridlayout with height " + getRows()); - } - - for (Iterator<Area> i = areas.iterator(); i.hasNext();) { - Area existingArea = i.next(); - // Areas ending below the row needs to be moved down or stretched - if (existingArea.row2 >= row) { - existingArea.row2++; - - // Stretch areas that span over the selected row - if (existingArea.row1 >= row) { - existingArea.row1++; - } - - } - } - - if (cursorY >= row) { - cursorY++; - } - - setRows(getRows() + 1); - structuralChange = true; - requestRepaint(); - } - - /** - * Removes a row and all the components in the row. - * - * <p> - * Components which span over several rows are removed if the selected row - * is on the first row of such a component. - * </p> - * - * <p> - * If the last row is removed then all remaining components will be removed - * and the grid will be reduced to one row. The cursor will be moved to the - * upper left cell of the grid. - * </p> - * - * @param row - * Index of the row to remove. The leftmost row has index 0. - */ - public void removeRow(int row) { - if (row >= getRows()) { - throw new IllegalArgumentException("Cannot delete row " + row - + " from a gridlayout with height " + getRows()); - } - - // Remove all components in row - for (int col = 0; col < getColumns(); col++) { - removeComponent(col, row); - } - - // Shrink or remove areas in the selected row - for (Iterator<Area> i = areas.iterator(); i.hasNext();) { - Area existingArea = i.next(); - if (existingArea.row2 >= row) { - existingArea.row2--; - - if (existingArea.row1 > row) { - existingArea.row1--; - } - } - } - - if (getRows() == 1) { - /* - * Removing the last row means that the dimensions of the Grid - * layout will be truncated to 1 empty row and the cursor is moved - * to the first cell - */ - cursorX = 0; - cursorY = 0; - } else { - setRows(getRows() - 1); - if (cursorY > row) { - cursorY--; - } - } - - structuralChange = true; - requestRepaint(); - - } - - /** - * Sets the expand ratio of given column. - * - * <p> - * The expand ratio defines how excess space is distributed among columns. - * Excess space means space that is left over from components that are not - * sized relatively. By default, the excess space is distributed evenly. - * </p> - * - * <p> - * Note that the component width of the GridLayout must be defined (fixed or - * relative, as opposed to undefined) for this method to have any effect. - * </p> - * - * @see #setWidth(float, int) - * - * @param columnIndex - * @param ratio - */ - public void setColumnExpandRatio(int columnIndex, float ratio) { - columnExpandRatio.put(columnIndex, ratio); - requestRepaint(); - } - - /** - * Returns the expand ratio of given column - * - * @see #setColumnExpandRatio(int, float) - * - * @param columnIndex - * @return the expand ratio, 0.0f by default - */ - public float getColumnExpandRatio(int columnIndex) { - Float r = columnExpandRatio.get(columnIndex); - return r == null ? 0 : r.floatValue(); - } - - /** - * Sets the expand ratio of given row. - * - * <p> - * Expand ratio defines how excess space is distributed among rows. Excess - * space means the space left over from components that are not sized - * relatively. By default, the excess space is distributed evenly. - * </p> - * - * <p> - * Note, that height needs to be defined (fixed or relative, as opposed to - * undefined height) for this method to have any effect. - * </p> - * - * @see #setHeight(float, int) - * - * @param rowIndex - * The row index, starting from 0 for the topmost row. - * @param ratio - */ - public void setRowExpandRatio(int rowIndex, float ratio) { - rowExpandRatio.put(rowIndex, ratio); - requestRepaint(); - } - - /** - * Returns the expand ratio of given row. - * - * @see #setRowExpandRatio(int, float) - * - * @param rowIndex - * The row index, starting from 0 for the topmost row. - * @return the expand ratio, 0.0f by default - */ - public float getRowExpandRatio(int rowIndex) { - Float r = rowExpandRatio.get(rowIndex); - return r == null ? 0 : r.floatValue(); - } - - /** - * Gets the Component at given index. - * - * @param x - * The column index, starting from 0 for the leftmost column. - * @param y - * The row index, starting from 0 for the topmost row. - * @return Component in given cell or null if empty - */ - public Component getComponent(int x, int y) { - for (final Iterator<Area> iterator = areas.iterator(); iterator - .hasNext();) { - final Area area = iterator.next(); - if (area.getColumn1() <= x && x <= area.getColumn2() - && area.getRow1() <= y && y <= area.getRow2()) { - return area.getComponent(); - } - } - return null; - } - - /** - * Returns information about the area where given component is laid in the - * GridLayout. - * - * @param component - * the component whose area information is requested. - * @return an Area object that contains information how component is laid in - * the grid - */ - public Area getComponentArea(Component component) { - for (final Iterator<Area> iterator = areas.iterator(); iterator - .hasNext();) { - final Area area = iterator.next(); - if (area.getComponent() == component) { - return area; - } - } - return null; - } - - @Override - public void addListener(LayoutClickListener listener) { - addListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener, - LayoutClickListener.clickMethod); - } - - @Override - public void removeListener(LayoutClickListener listener) { - removeListener(LayoutClickEventHandler.LAYOUT_CLICK_EVENT_IDENTIFIER, - LayoutClickEvent.class, listener); - } - -} diff --git a/src/com/vaadin/ui/HasComponents.java b/src/com/vaadin/ui/HasComponents.java deleted file mode 100644 index 3ebd63bff2..0000000000 --- a/src/com/vaadin/ui/HasComponents.java +++ /dev/null @@ -1,49 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.util.Iterator; - -/** - * Interface that must be implemented by all {@link Component}s that contain - * other {@link Component}s. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - * - */ -public interface HasComponents extends Component, Iterable<Component> { - /** - * Gets an iterator to the collection of contained components. Using this - * iterator it is possible to step through all components contained in this - * container. - * - * @return the component iterator. - * - * @deprecated Use {@link #iterator()} instead. - */ - @Deprecated - public Iterator<Component> getComponentIterator(); - - /** - * Checks if the child component is visible. This method allows hiding a - * child component from updates and communication to and from the client. - * This is useful for components that show only a limited number of its - * children at any given time and want to allow updates only for the - * children that are visible (e.g. TabSheet has one tab open at a time). - * <p> - * Note that this will prevent updates from reaching the child even though - * the child itself is set to visible. Also if a child is set to invisible - * this will not force it to be visible. - * </p> - * - * @param childComponent - * The child component to check - * @return true if the child component is visible to the user, false - * otherwise - */ - public boolean isComponentVisible(Component childComponent); - -} diff --git a/src/com/vaadin/ui/HorizontalLayout.java b/src/com/vaadin/ui/HorizontalLayout.java deleted file mode 100644 index b9dc1c13ca..0000000000 --- a/src/com/vaadin/ui/HorizontalLayout.java +++ /dev/null @@ -1,24 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -/** - * Horizontal layout - * - * <code>HorizontalLayout</code> is a component container, which shows the - * subcomponents in the order of their addition (horizontally). - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.3 - */ -@SuppressWarnings("serial") -public class HorizontalLayout extends AbstractOrderedLayout { - - public HorizontalLayout() { - - } - -} diff --git a/src/com/vaadin/ui/HorizontalSplitPanel.java b/src/com/vaadin/ui/HorizontalSplitPanel.java deleted file mode 100644 index 5bd6c8a075..0000000000 --- a/src/com/vaadin/ui/HorizontalSplitPanel.java +++ /dev/null @@ -1,34 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -/** - * A horizontal split panel contains two components and lays them horizontally. - * The first component is on the left side. - * - * <pre> - * - * +---------------------++----------------------+ - * | || | - * | The first component || The second component | - * | || | - * +---------------------++----------------------+ - * - * ^ - * | - * the splitter - * - * </pre> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.5 - */ -public class HorizontalSplitPanel extends AbstractSplitPanel { - public HorizontalSplitPanel() { - super(); - setSizeFull(); - } -} diff --git a/src/com/vaadin/ui/Html5File.java b/src/com/vaadin/ui/Html5File.java deleted file mode 100644 index aa3fb558fa..0000000000 --- a/src/com/vaadin/ui/Html5File.java +++ /dev/null @@ -1,65 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; - -import com.vaadin.event.dd.DropHandler; -import com.vaadin.terminal.StreamVariable; - -/** - * {@link DragAndDropWrapper} can receive also files from client computer if - * appropriate HTML 5 features are supported on client side. This class wraps - * information about dragged file on server side. - */ -public class Html5File implements Serializable { - - private String name; - private long size; - private StreamVariable streamVariable; - private String type; - - Html5File(String name, long size, String mimeType) { - this.name = name; - this.size = size; - type = mimeType; - } - - public String getFileName() { - return name; - } - - public long getFileSize() { - return size; - } - - public String getType() { - return type; - } - - /** - * Sets the {@link StreamVariable} that into which the file contents will be - * written. Usage of StreamVariable is similar to {@link Upload} component. - * <p> - * If the {@link StreamVariable} is not set in the {@link DropHandler} the - * file contents will not be sent to server. - * <p> - * <em>Note!</em> receiving file contents is experimental feature depending - * on HTML 5 API's. It is supported only by modern web browsers like Firefox - * 3.6 and above and recent webkit based browsers (Safari 5, Chrome 6) at - * this time. - * - * @param streamVariable - * the callback that returns stream where the implementation - * writes the file contents as it arrives. - */ - public void setStreamVariable(StreamVariable streamVariable) { - this.streamVariable = streamVariable; - } - - public StreamVariable getStreamVariable() { - return streamVariable; - } - -}
\ No newline at end of file diff --git a/src/com/vaadin/ui/InlineDateField.java b/src/com/vaadin/ui/InlineDateField.java deleted file mode 100644 index cf61703318..0000000000 --- a/src/com/vaadin/ui/InlineDateField.java +++ /dev/null @@ -1,46 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Date; - -import com.vaadin.data.Property; - -/** - * <p> - * A date entry component, which displays the actual date selector inline. - * - * </p> - * - * @see DateField - * @see PopupDateField - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -public class InlineDateField extends DateField { - - public InlineDateField() { - super(); - } - - public InlineDateField(Property dataSource) throws IllegalArgumentException { - super(dataSource); - } - - public InlineDateField(String caption, Date value) { - super(caption, value); - } - - public InlineDateField(String caption, Property dataSource) { - super(caption, dataSource); - } - - public InlineDateField(String caption) { - super(caption); - } - -} diff --git a/src/com/vaadin/ui/JavaScript.java b/src/com/vaadin/ui/JavaScript.java deleted file mode 100644 index 0b4669728a..0000000000 --- a/src/com/vaadin/ui/JavaScript.java +++ /dev/null @@ -1,157 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.HashMap; -import java.util.Map; - -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.shared.communication.ServerRpc; -import com.vaadin.shared.extension.javascriptmanager.ExecuteJavaScriptRpc; -import com.vaadin.shared.extension.javascriptmanager.JavaScriptManagerState; -import com.vaadin.terminal.AbstractExtension; -import com.vaadin.terminal.Page; - -/** - * Provides access to JavaScript functionality in the web browser. To get an - * instance of JavaScript, either use Page.getJavaScript() or - * JavaScript.getCurrent() as a shorthand for getting the JavaScript object - * corresponding to the current Page. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public class JavaScript extends AbstractExtension { - private Map<String, JavaScriptFunction> functions = new HashMap<String, JavaScriptFunction>(); - - // Can not be defined in client package as this JSONArray is not available - // in GWT - public interface JavaScriptCallbackRpc extends ServerRpc { - public void call(String name, JSONArray arguments); - } - - /** - * Creates a new JavaScript object. You should typically not this, but - * instead use the JavaScript object already associated with your Page - * object. - */ - public JavaScript() { - registerRpc(new JavaScriptCallbackRpc() { - @Override - public void call(String name, JSONArray arguments) { - JavaScriptFunction function = functions.get(name); - // TODO handle situation if name is not registered - try { - function.call(arguments); - } catch (JSONException e) { - throw new IllegalArgumentException(e); - } - } - }); - } - - @Override - public JavaScriptManagerState getState() { - return (JavaScriptManagerState) super.getState(); - } - - /** - * Add a new function to the global JavaScript namespace (i.e. the window - * object). The <code>call</code> method in the passed - * {@link JavaScriptFunction} object will be invoked with the same - * parameters whenever the JavaScript function is called in the browser. - * - * A function added with the name <code>"myFunction"</code> can thus be - * invoked with the following JavaScript code: - * <code>window.myFunction(argument1, argument2)</code>. - * - * If the name parameter contains dots, simple objects are created on demand - * to allow calling the function using the same name (e.g. - * <code>window.myObject.myFunction</code>). - * - * @param name - * the name that the function should get in the global JavaScript - * namespace. - * @param function - * the JavaScriptFunction that will be invoked if the JavaScript - * function is called. - */ - public void addFunction(String name, JavaScriptFunction function) { - functions.put(name, function); - if (getState().getNames().add(name)) { - requestRepaint(); - } - } - - /** - * Removes a JavaScripFunction from the browser's global JavaScript - * namespace. - * - * If the name contains dots and intermediate objects were created by - * {@link #addFunction(String, JavaScriptFunction)}, these objects will not - * be removed by this method. - * - * @param name - * the name of the callback to remove - */ - public void removeFunction(String name) { - functions.remove(name); - if (getState().getNames().remove(name)) { - requestRepaint(); - } - } - - /** - * Executes the given JavaScript code in the browser. - * - * @param script - * The JavaScript code to run. - */ - public void execute(String script) { - getRpcProxy(ExecuteJavaScriptRpc.class).executeJavaScript(script); - } - - /** - * Executes the given JavaScript code in the browser. - * - * @param script - * The JavaScript code to run. - */ - public static void eval(String script) { - getCurrent().execute(script); - } - - /** - * Get the JavaScript object for the current Page, or null if there is no - * current page. - * - * @see Page#getCurrent() - * - * @return the JavaScript object corresponding to the current Page, or - * <code>null</code> if there is no current page. - */ - public static JavaScript getCurrent() { - Page page = Page.getCurrent(); - if (page == null) { - return null; - } - return page.getJavaScript(); - } - - /** - * JavaScript is not designed to be removed. - * - * @throws UnsupportedOperationException - * when invoked - */ - @Override - public void removeFromTarget() { - throw new UnsupportedOperationException( - "JavaScript is not designed to be removed."); - } - -} diff --git a/src/com/vaadin/ui/JavaScriptFunction.java b/src/com/vaadin/ui/JavaScriptFunction.java deleted file mode 100644 index e39ae9b87b..0000000000 --- a/src/com/vaadin/ui/JavaScriptFunction.java +++ /dev/null @@ -1,41 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; - -import com.vaadin.external.json.JSONArray; -import com.vaadin.external.json.JSONException; -import com.vaadin.terminal.AbstractJavaScriptExtension; - -/** - * Defines a method that is called by a client-side JavaScript function. When - * the corresponding JavaScript function is called, the {@link #call(JSONArray)} - * method is invoked. - * - * @see JavaScript#addFunction(String, JavaScriptCallback) - * @see AbstractJavaScriptComponent#addFunction(String, JavaScriptCallback) - * @see AbstractJavaScriptExtension#addFunction(String, JavaScriptCallback) - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0.0 - */ -public interface JavaScriptFunction extends Serializable { - /** - * Invoked whenever the corresponding JavaScript function is called in the - * browser. - * <p> - * Because of the asynchronous nature of the communication between client - * and server, no return value can be sent back to the browser. - * - * @param arguments - * an array with JSON representations of the arguments with which - * the JavaScript function was called. - * @throws JSONException - * if the arguments can not be interpreted - */ - public void call(JSONArray arguments) throws JSONException; -} diff --git a/src/com/vaadin/ui/Label.java b/src/com/vaadin/ui/Label.java deleted file mode 100644 index 7e50a37805..0000000000 --- a/src/com/vaadin/ui/Label.java +++ /dev/null @@ -1,483 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.lang.reflect.Method; -import java.util.logging.Logger; - -import com.vaadin.data.Property; -import com.vaadin.data.util.converter.Converter; -import com.vaadin.data.util.converter.ConverterUtil; -import com.vaadin.shared.ui.label.ContentMode; -import com.vaadin.shared.ui.label.LabelState; - -/** - * Label component for showing non-editable short texts. - * - * The label content can be set to the modes specified by {@link ContentMode} - * - * <p> - * The contents of the label may contain simple formatting: - * <ul> - * <li><b><b></b> Bold - * <li><b><i></b> Italic - * <li><b><u></b> Underlined - * <li><b><br/></b> Linebreak - * <li><b><ul><li>item 1</li><li>item 2</li></ul></b> List of - * items - * </ul> - * The <b>b</b>,<b>i</b>,<b>u</b> and <b>li</b> tags can contain all the tags in - * the list recursively. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Label extends AbstractComponent implements Property<String>, - Property.Viewer, Property.ValueChangeListener, - Property.ValueChangeNotifier, Comparable<Label> { - - private static final Logger logger = Logger - .getLogger(Label.class.getName()); - - /** - * @deprecated From 7.0, use {@link ContentMode#TEXT} instead - */ - @Deprecated - public static final ContentMode CONTENT_TEXT = ContentMode.TEXT; - - /** - * @deprecated From 7.0, use {@link ContentMode#PREFORMATTED} instead - */ - @Deprecated - public static final ContentMode CONTENT_PREFORMATTED = ContentMode.PREFORMATTED; - - /** - * @deprecated From 7.0, use {@link ContentMode#XHTML} instead - */ - @Deprecated - public static final ContentMode CONTENT_XHTML = ContentMode.XHTML; - - /** - * @deprecated From 7.0, use {@link ContentMode#XML} instead - */ - @Deprecated - public static final ContentMode CONTENT_XML = ContentMode.XML; - - /** - * @deprecated From 7.0, use {@link ContentMode#RAW} instead - */ - @Deprecated - public static final ContentMode CONTENT_RAW = ContentMode.RAW; - - /** - * @deprecated From 7.0, use {@link ContentMode#TEXT} instead - */ - @Deprecated - public static final ContentMode CONTENT_DEFAULT = ContentMode.TEXT; - - /** - * A converter used to convert from the data model type to the field type - * and vice versa. Label type is always String. - */ - private Converter<String, Object> converter = null; - - private Property<String> dataSource = null; - - /** - * Creates an empty Label. - */ - public Label() { - this(""); - } - - /** - * Creates a new instance of Label with text-contents. - * - * @param content - */ - public Label(String content) { - this(content, ContentMode.TEXT); - } - - /** - * Creates a new instance of Label with text-contents read from given - * datasource. - * - * @param contentSource - */ - public Label(Property contentSource) { - this(contentSource, ContentMode.TEXT); - } - - /** - * Creates a new instance of Label with text-contents. - * - * @param content - * @param contentMode - */ - public Label(String content, ContentMode contentMode) { - setValue(content); - setContentMode(contentMode); - setWidth(100, Unit.PERCENTAGE); - } - - /** - * Creates a new instance of Label with text-contents read from given - * datasource. - * - * @param contentSource - * @param contentMode - */ - public Label(Property contentSource, ContentMode contentMode) { - setPropertyDataSource(contentSource); - setContentMode(contentMode); - setWidth(100, Unit.PERCENTAGE); - } - - @Override - public LabelState getState() { - return (LabelState) super.getState(); - } - - /** - * Gets the value of the label. - * <p> - * The value of the label is the text that is shown to the end user. - * Depending on the {@link ContentMode} it is plain text or markup. - * </p> - * - * @return the value of the label. - */ - @Override - public String getValue() { - if (getPropertyDataSource() == null) { - // Use internal value if we are running without a data source - return getState().getText(); - } - return ConverterUtil.convertFromModel(getPropertyDataSource() - .getValue(), String.class, getConverter(), getLocale()); - } - - /** - * Set the value of the label. Value of the label is the XML contents of the - * label. - * - * @param newStringValue - * the New value of the label. - */ - @Override - public void setValue(Object newStringValue) { - if (newStringValue != null && newStringValue.getClass() != String.class) { - throw new Converter.ConversionException("Value of type " - + newStringValue.getClass() + " cannot be assigned to " - + String.class.getName()); - } - if (getPropertyDataSource() == null) { - getState().setText((String) newStringValue); - requestRepaint(); - } else { - throw new IllegalStateException( - "Label is only a Property.Viewer and cannot update its data source"); - } - } - - /** - * Returns the value displayed by this label. - * - * @see java.lang.Object#toString() - * @deprecated As of 7.0.0, use {@link #getValue()} to get the value of the - * label or {@link #getPropertyDataSource()} .getValue() to get - * the value of the data source. - */ - @Deprecated - @Override - public String toString() { - logger.warning("You are using Label.toString() to get the value for a " - + getClass().getSimpleName() - + ". This is not recommended and will not be supported in future versions."); - return getValue(); - } - - /** - * Gets the type of the Property. - * - * @see com.vaadin.data.Property#getType() - */ - @Override - public Class<String> getType() { - return String.class; - } - - /** - * Gets the viewing data-source property. - * - * @return the data source property. - * @see com.vaadin.data.Property.Viewer#getPropertyDataSource() - */ - @Override - public Property getPropertyDataSource() { - return dataSource; - } - - /** - * Sets the property as data-source for viewing. - * - * @param newDataSource - * the new data source Property - * @see com.vaadin.data.Property.Viewer#setPropertyDataSource(com.vaadin.data.Property) - */ - @Override - public void setPropertyDataSource(Property newDataSource) { - // Stops listening the old data source changes - if (dataSource != null - && Property.ValueChangeNotifier.class - .isAssignableFrom(dataSource.getClass())) { - ((Property.ValueChangeNotifier) dataSource).removeListener(this); - } - - if (!ConverterUtil.canConverterHandle(getConverter(), String.class, - newDataSource.getType())) { - // Try to find a converter - Converter<String, ?> c = ConverterUtil.getConverter(String.class, - newDataSource.getType(), getApplication()); - setConverter(c); - } - dataSource = newDataSource; - - // Listens the new data source if possible - if (dataSource != null - && Property.ValueChangeNotifier.class - .isAssignableFrom(dataSource.getClass())) { - ((Property.ValueChangeNotifier) dataSource).addListener(this); - } - requestRepaint(); - } - - /** - * Gets the content mode of the Label. - * - * @return the Content mode of the label. - * - * @see ContentMode - */ - public ContentMode getContentMode() { - return getState().getContentMode(); - } - - /** - * Sets the content mode of the Label. - * - * @param contentMode - * the New content mode of the label. - * - * @see ContentMode - */ - public void setContentMode(ContentMode contentMode) { - if (contentMode == null) { - throw new IllegalArgumentException("Content mode can not be null"); - } - - getState().setContentMode(contentMode); - requestRepaint(); - } - - /* Value change events */ - - private static final Method VALUE_CHANGE_METHOD; - - static { - try { - VALUE_CHANGE_METHOD = Property.ValueChangeListener.class - .getDeclaredMethod("valueChange", - new Class[] { Property.ValueChangeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in Label"); - } - } - - /** - * Value change event - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class ValueChangeEvent extends Component.Event implements - Property.ValueChangeEvent { - - /** - * New instance of text change event - * - * @param source - * the Source of the event. - */ - public ValueChangeEvent(Label source) { - super(source); - } - - /** - * Gets the Property that has been modified. - * - * @see com.vaadin.data.Property.ValueChangeEvent#getProperty() - */ - @Override - public Property getProperty() { - return (Property) getSource(); - } - } - - /** - * Adds the value change listener. - * - * @param listener - * the Listener to be added. - * @see com.vaadin.data.Property.ValueChangeNotifier#addListener(com.vaadin.data.Property.ValueChangeListener) - */ - @Override - public void addListener(Property.ValueChangeListener listener) { - addListener(Label.ValueChangeEvent.class, listener, VALUE_CHANGE_METHOD); - } - - /** - * Removes the value change listener. - * - * @param listener - * the Listener to be removed. - * @see com.vaadin.data.Property.ValueChangeNotifier#removeListener(com.vaadin.data.Property.ValueChangeListener) - */ - @Override - public void removeListener(Property.ValueChangeListener listener) { - removeListener(Label.ValueChangeEvent.class, listener, - VALUE_CHANGE_METHOD); - } - - /** - * Emits the options change event. - */ - protected void fireValueChange() { - // Set the error message - fireEvent(new Label.ValueChangeEvent(this)); - } - - /** - * Listens the value change events from data source. - * - * @see com.vaadin.data.Property.ValueChangeListener#valueChange(Property.ValueChangeEvent) - */ - @Override - public void valueChange(Property.ValueChangeEvent event) { - // Update the internal value from the data source - getState().setText(getValue()); - requestRepaint(); - - fireValueChange(); - } - - private String getComparableValue() { - String stringValue = getValue(); - if (stringValue == null) { - stringValue = ""; - } - - if (getContentMode() == ContentMode.XHTML - || getContentMode() == ContentMode.XML) { - return stripTags(stringValue); - } else { - return stringValue; - } - - } - - /** - * Compares the Label to other objects. - * - * <p> - * Labels can be compared to other labels for sorting label contents. This - * is especially handy for sorting table columns. - * </p> - * - * <p> - * In RAW, PREFORMATTED and TEXT modes, the label contents are compared as - * is. In XML, UIDL and XHTML modes, only CDATA is compared and tags - * ignored. If the other object is not a Label, its toString() return value - * is used in comparison. - * </p> - * - * @param other - * the Other object to compare to. - * @return a negative integer, zero, or a positive integer as this object is - * less than, equal to, or greater than the specified object. - * @see java.lang.Comparable#compareTo(java.lang.Object) - */ - @Override - public int compareTo(Label other) { - - String thisValue = getComparableValue(); - String otherValue = other.getComparableValue(); - - return thisValue.compareTo(otherValue); - } - - /** - * Strips the tags from the XML. - * - * @param xml - * the String containing a XML snippet. - * @return the original XML without tags. - */ - private String stripTags(String xml) { - - final StringBuffer res = new StringBuffer(); - - int processed = 0; - final int xmlLen = xml.length(); - while (processed < xmlLen) { - int next = xml.indexOf('<', processed); - if (next < 0) { - next = xmlLen; - } - res.append(xml.substring(processed, next)); - if (processed < xmlLen) { - next = xml.indexOf('>', processed); - if (next < 0) { - next = xmlLen; - } - processed = next + 1; - } - } - - return res.toString(); - } - - /** - * Gets the converter used to convert the property data source value to the - * label value. - * - * @return The converter or null if none is set. - */ - public Converter<String, Object> getConverter() { - return converter; - } - - /** - * Sets the converter used to convert the label value to the property data - * source type. The converter must have a presentation type of String. - * - * @param converter - * The new converter to use. - */ - public void setConverter(Converter<String, ?> converter) { - this.converter = (Converter<String, Object>) converter; - requestRepaint(); - } - -} diff --git a/src/com/vaadin/ui/Layout.java b/src/com/vaadin/ui/Layout.java deleted file mode 100644 index d083f9afdc..0000000000 --- a/src/com/vaadin/ui/Layout.java +++ /dev/null @@ -1,229 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; - -import com.vaadin.shared.ui.VMarginInfo; -import com.vaadin.shared.ui.AlignmentInfo.Bits; - -/** - * Extension to the {@link ComponentContainer} interface which adds the - * layouting control to the elements in the container. This is required by the - * various layout components to enable them to place other components in - * specific locations in the UI. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public interface Layout extends ComponentContainer, Serializable { - - /** - * Enable layout margins. Affects all four sides of the layout. This will - * tell the client-side implementation to leave extra space around the - * layout. The client-side implementation decides the actual amount, and it - * can vary between themes. - * - * @param enabled - */ - public void setMargin(boolean enabled); - - /** - * Enable specific layout margins. This will tell the client-side - * implementation to leave extra space around the layout in specified edges, - * clockwise from top (top, right, bottom, left). The client-side - * implementation decides the actual amount, and it can vary between themes. - * - * @param top - * @param right - * @param bottom - * @param left - */ - public void setMargin(boolean top, boolean right, boolean bottom, - boolean left); - - /** - * AlignmentHandler is most commonly an advanced {@link Layout} that can - * align its components. - */ - public interface AlignmentHandler extends Serializable { - - /** - * Contained component should be aligned horizontally to the left. - * - * @deprecated Use of {@link Alignment} class and its constants - */ - @Deprecated - public static final int ALIGNMENT_LEFT = Bits.ALIGNMENT_LEFT; - - /** - * Contained component should be aligned horizontally to the right. - * - * @deprecated Use of {@link Alignment} class and its constants - */ - @Deprecated - public static final int ALIGNMENT_RIGHT = Bits.ALIGNMENT_RIGHT; - - /** - * Contained component should be aligned vertically to the top. - * - * @deprecated Use of {@link Alignment} class and its constants - */ - @Deprecated - public static final int ALIGNMENT_TOP = Bits.ALIGNMENT_TOP; - - /** - * Contained component should be aligned vertically to the bottom. - * - * @deprecated Use of {@link Alignment} class and its constants - */ - @Deprecated - public static final int ALIGNMENT_BOTTOM = Bits.ALIGNMENT_BOTTOM; - - /** - * Contained component should be horizontally aligned to center. - * - * @deprecated Use of {@link Alignment} class and its constants - */ - @Deprecated - public static final int ALIGNMENT_HORIZONTAL_CENTER = Bits.ALIGNMENT_HORIZONTAL_CENTER; - - /** - * Contained component should be vertically aligned to center. - * - * @deprecated Use of {@link Alignment} class and its constants - */ - @Deprecated - public static final int ALIGNMENT_VERTICAL_CENTER = Bits.ALIGNMENT_VERTICAL_CENTER; - - /** - * Set alignment for one contained component in this layout. Alignment - * is calculated as a bit mask of the two passed values. - * - * @deprecated Use {@link #setComponentAlignment(Component, Alignment)} - * instead - * - * @param childComponent - * the component to align within it's layout cell. - * @param horizontalAlignment - * the horizontal alignment for the child component (left, - * center, right). Use ALIGNMENT constants. - * @param verticalAlignment - * the vertical alignment for the child component (top, - * center, bottom). Use ALIGNMENT constants. - */ - @Deprecated - public void setComponentAlignment(Component childComponent, - int horizontalAlignment, int verticalAlignment); - - /** - * Set alignment for one contained component in this layout. Use - * predefined alignments from Alignment class. - * - * Example: <code> - * layout.setComponentAlignment(myComponent, Alignment.TOP_RIGHT); - * </code> - * - * @param childComponent - * the component to align within it's layout cell. - * @param alignment - * the Alignment value to be set - */ - public void setComponentAlignment(Component childComponent, - Alignment alignment); - - /** - * Returns the current Alignment of given component. - * - * @param childComponent - * @return the {@link Alignment} - */ - public Alignment getComponentAlignment(Component childComponent); - - } - - /** - * This type of layout supports automatic addition of space between its - * components. - * - */ - public interface SpacingHandler extends Serializable { - /** - * Enable spacing between child components within this layout. - * - * <p> - * <strong>NOTE:</strong> This will only affect the space between - * components, not the space around all the components in the layout - * (i.e. do not confuse this with the cellspacing attribute of a HTML - * Table). Use {@link #setMargin(boolean)} to add space around the - * layout. - * </p> - * - * <p> - * See the reference manual for more information about CSS rules for - * defining the amount of spacing to use. - * </p> - * - * @param enabled - * true if spacing should be turned on, false if it should be - * turned off - */ - public void setSpacing(boolean enabled); - - /** - * - * @return true if spacing between child components within this layout - * is enabled, false otherwise - */ - public boolean isSpacing(); - } - - /** - * This type of layout supports automatic addition of margins (space around - * its components). - */ - public interface MarginHandler extends Serializable { - /** - * Enable margins for this layout. - * - * <p> - * <strong>NOTE:</strong> This will only affect the space around the - * components in the layout, not space between the components in the - * layout. Use {@link #setSpacing(boolean)} to add space between the - * components in the layout. - * </p> - * - * <p> - * See the reference manual for more information about CSS rules for - * defining the size of the margin. - * </p> - * - * @param marginInfo - * MarginInfo object containing the new margins. - */ - public void setMargin(MarginInfo marginInfo); - - /** - * - * @return MarginInfo containing the currently enabled margins. - */ - public MarginInfo getMargin(); - } - - @SuppressWarnings("serial") - public static class MarginInfo extends VMarginInfo implements Serializable { - - public MarginInfo(boolean enabled) { - super(enabled, enabled, enabled, enabled); - } - - public MarginInfo(boolean top, boolean right, boolean bottom, - boolean left) { - super(top, right, bottom, left); - } - } -} diff --git a/src/com/vaadin/ui/Link.java b/src/com/vaadin/ui/Link.java deleted file mode 100644 index fd105f3255..0000000000 --- a/src/com/vaadin/ui/Link.java +++ /dev/null @@ -1,242 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Map; - -import com.vaadin.terminal.Page; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Vaadin6Component; - -/** - * Link is used to create external or internal URL links. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Link extends AbstractComponent implements Vaadin6Component { - - /* Target window border type constant: No window border */ - public static final int TARGET_BORDER_NONE = Page.BORDER_NONE; - - /* Target window border type constant: Minimal window border */ - public static final int TARGET_BORDER_MINIMAL = Page.BORDER_MINIMAL; - - /* Target window border type constant: Default window border */ - public static final int TARGET_BORDER_DEFAULT = Page.BORDER_DEFAULT; - - private Resource resource = null; - - private String targetName; - - private int targetBorder = TARGET_BORDER_DEFAULT; - - private int targetWidth = -1; - - private int targetHeight = -1; - - /** - * Creates a new link. - */ - public Link() { - - } - - /** - * Creates a new instance of Link. - * - * @param caption - * @param resource - */ - public Link(String caption, Resource resource) { - setCaption(caption); - this.resource = resource; - } - - /** - * Creates a new instance of Link that opens a new window. - * - * - * @param caption - * the Link text. - * @param targetName - * the name of the target window where the link opens to. Empty - * name of null implies that the target is opened to the window - * containing the link. - * @param width - * the Width of the target window. - * @param height - * the Height of the target window. - * @param border - * the Border style of the target window. - * - */ - public Link(String caption, Resource resource, String targetName, - int width, int height, int border) { - setCaption(caption); - this.resource = resource; - setTargetName(targetName); - setTargetWidth(width); - setTargetHeight(height); - setTargetBorder(border); - } - - /** - * Paints the content of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - - if (resource != null) { - target.addAttribute("src", resource); - } else { - return; - } - - // Target window name - final String name = getTargetName(); - if (name != null && name.length() > 0) { - target.addAttribute("name", name); - } - - // Target window size - if (getTargetWidth() >= 0) { - target.addAttribute("targetWidth", getTargetWidth()); - } - if (getTargetHeight() >= 0) { - target.addAttribute("targetHeight", getTargetHeight()); - } - - // Target window border - switch (getTargetBorder()) { - case TARGET_BORDER_MINIMAL: - target.addAttribute("border", "minimal"); - break; - case TARGET_BORDER_NONE: - target.addAttribute("border", "none"); - break; - } - } - - /** - * Returns the target window border. - * - * @return the target window border. - */ - public int getTargetBorder() { - return targetBorder; - } - - /** - * Returns the target window height or -1 if not set. - * - * @return the target window height. - */ - public int getTargetHeight() { - return targetHeight < 0 ? -1 : targetHeight; - } - - /** - * Returns the target window name. Empty name of null implies that the - * target is opened to the window containing the link. - * - * @return the target window name. - */ - public String getTargetName() { - return targetName; - } - - /** - * Returns the target window width or -1 if not set. - * - * @return the target window width. - */ - public int getTargetWidth() { - return targetWidth < 0 ? -1 : targetWidth; - } - - /** - * Sets the border of the target window. - * - * @param targetBorder - * the targetBorder to set. - */ - public void setTargetBorder(int targetBorder) { - if (targetBorder == TARGET_BORDER_DEFAULT - || targetBorder == TARGET_BORDER_MINIMAL - || targetBorder == TARGET_BORDER_NONE) { - this.targetBorder = targetBorder; - requestRepaint(); - } - } - - /** - * Sets the target window height. - * - * @param targetHeight - * the targetHeight to set. - */ - public void setTargetHeight(int targetHeight) { - this.targetHeight = targetHeight; - requestRepaint(); - } - - /** - * Sets the target window name. - * - * @param targetName - * the targetName to set. - */ - public void setTargetName(String targetName) { - this.targetName = targetName; - requestRepaint(); - } - - /** - * Sets the target window width. - * - * @param targetWidth - * the targetWidth to set. - */ - public void setTargetWidth(int targetWidth) { - this.targetWidth = targetWidth; - requestRepaint(); - } - - /** - * Returns the resource this link opens. - * - * @return the Resource. - */ - public Resource getResource() { - return resource; - } - - /** - * Sets the resource this link opens. - * - * @param resource - * the resource to set. - */ - public void setResource(Resource resource) { - this.resource = resource; - requestRepaint(); - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // TODO Remove once Vaadin6Component is no longer implemented - } -} diff --git a/src/com/vaadin/ui/ListSelect.java b/src/com/vaadin/ui/ListSelect.java deleted file mode 100644 index 35ccb34b3c..0000000000 --- a/src/com/vaadin/ui/ListSelect.java +++ /dev/null @@ -1,96 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Collection; - -import com.vaadin.data.Container; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * This is a simple list select without, for instance, support for new items, - * lazyloading, and other advanced features. - */ -@SuppressWarnings("serial") -public class ListSelect extends AbstractSelect { - - private int columns = 0; - private int rows = 0; - - public ListSelect() { - super(); - } - - public ListSelect(String caption, Collection<?> options) { - super(caption, options); - } - - public ListSelect(String caption, Container dataSource) { - super(caption, dataSource); - } - - public ListSelect(String caption) { - super(caption); - } - - /** - * Sets the number of columns in the editor. If the number of columns is set - * 0, the actual number of displayed columns is determined implicitly by the - * adapter. - * - * @param columns - * the number of columns to set. - */ - public void setColumns(int columns) { - if (columns < 0) { - columns = 0; - } - if (this.columns != columns) { - this.columns = columns; - requestRepaint(); - } - } - - public int getColumns() { - return columns; - } - - public int getRows() { - return rows; - } - - /** - * Sets the number of rows in the editor. If the number of rows is set 0, - * the actual number of displayed rows is determined implicitly by the - * adapter. - * - * @param rows - * the number of rows to set. - */ - public void setRows(int rows) { - if (rows < 0) { - rows = 0; - } - if (this.rows != rows) { - this.rows = rows; - requestRepaint(); - } - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - target.addAttribute("type", "list"); - // Adds the number of columns - if (columns != 0) { - target.addAttribute("cols", columns); - } - // Adds the number of rows - if (rows != 0) { - target.addAttribute("rows", rows); - } - super.paintContent(target); - } -} diff --git a/src/com/vaadin/ui/LoginForm.java b/src/com/vaadin/ui/LoginForm.java deleted file mode 100644 index db7e5f9dd9..0000000000 --- a/src/com/vaadin/ui/LoginForm.java +++ /dev/null @@ -1,353 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.Serializable; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import com.vaadin.Application; -import com.vaadin.terminal.ApplicationResource; -import com.vaadin.terminal.DownloadStream; -import com.vaadin.terminal.RequestHandler; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedResponse; -import com.vaadin.terminal.gwt.client.ApplicationConnection; - -/** - * LoginForm is a Vaadin component to handle common problem among Ajax - * applications: browsers password managers don't fill dynamically created forms - * like all those UI elements created by Vaadin. - * <p> - * For developer it is easy to use: add component to a desired place in you UI - * and add LoginListener to validate form input. Behind the curtain LoginForm - * creates an iframe with static html that browsers detect. - * <p> - * Login form is by default 100% width and height, so consider using it inside a - * sized {@link Panel} or {@link Window}. - * <p> - * Login page html can be overridden by replacing protected getLoginHTML method. - * As the login page is actually an iframe, styles must be handled manually. By - * default component tries to guess the right place for theme css. - * - * @since 5.3 - */ -public class LoginForm extends CustomComponent { - - private String usernameCaption = "Username"; - private String passwordCaption = "Password"; - private String loginButtonCaption = "Login"; - - private Embedded iframe = new Embedded(); - - private ApplicationResource loginPage = new ApplicationResource() { - - @Override - public Application getApplication() { - return LoginForm.this.getApplication(); - } - - @Override - public int getBufferSize() { - return getLoginHTML().length; - } - - @Override - public long getCacheTime() { - return -1; - } - - @Override - public String getFilename() { - return "login"; - } - - @Override - public DownloadStream getStream() { - return new DownloadStream(new ByteArrayInputStream(getLoginHTML()), - getMIMEType(), getFilename()); - } - - @Override - public String getMIMEType() { - return "text/html; charset=utf-8"; - } - }; - - private final RequestHandler requestHandler = new RequestHandler() { - @Override - public boolean handleRequest(Application application, - WrappedRequest request, WrappedResponse response) - throws IOException { - String requestPathInfo = request.getRequestPathInfo(); - if ("/loginHandler".equals(requestPathInfo)) { - response.setCacheTime(-1); - response.setContentType("text/html; charset=utf-8"); - response.getWriter() - .write("<html><body>Login form handled." - + "<script type='text/javascript'>parent.parent.vaadin.forceSync();" - + "</script></body></html>"); - - Map<String, String[]> parameters = request.getParameterMap(); - - HashMap<String, String> params = new HashMap<String, String>(); - // expecting single params - for (Iterator<String> it = parameters.keySet().iterator(); it - .hasNext();) { - String key = it.next(); - String value = (parameters.get(key))[0]; - params.put(key, value); - } - LoginEvent event = new LoginEvent(params); - fireEvent(event); - return true; - } - return false; - } - }; - - public LoginForm() { - iframe.setType(Embedded.TYPE_BROWSER); - iframe.setSizeFull(); - setSizeFull(); - setCompositionRoot(iframe); - addStyleName("v-loginform"); - } - - /** - * Returns byte array containing login page html. If you need to override - * the login html, use the default html as basis. Login page sets its target - * with javascript. - * - * @return byte array containing login page html - */ - protected byte[] getLoginHTML() { - String appUri = getApplication().getURL().toString(); - - try { - return ("<!DOCTYPE html PUBLIC \"-//W3C//DTD " - + "XHTML 1.0 Transitional//EN\" " - + "\"http://www.w3.org/TR/xhtml1/" - + "DTD/xhtml1-transitional.dtd\">\n" + "<html>" - + "<head><script type='text/javascript'>" - + "var setTarget = function() {" + "var uri = '" - + appUri - + "loginHandler" - + "'; var f = document.getElementById('loginf');" - + "document.forms[0].action = uri;document.forms[0].username.focus();};" - + "" - + "var styles = window.parent.document.styleSheets;" - + "for(var j = 0; j < styles.length; j++) {\n" - + "if(styles[j].href) {" - + "var stylesheet = document.createElement('link');\n" - + "stylesheet.setAttribute('rel', 'stylesheet');\n" - + "stylesheet.setAttribute('type', 'text/css');\n" - + "stylesheet.setAttribute('href', styles[j].href);\n" - + "document.getElementsByTagName('head')[0].appendChild(stylesheet);\n" - + "}" - + "}\n" - + "function submitOnEnter(e) { var keycode = e.keyCode || e.which;" - + " if (keycode == 13) {document.forms[0].submit();} } \n" - + "</script>" - + "</head><body onload='setTarget();' style='margin:0;padding:0; background:transparent;' class=\"" - + ApplicationConnection.GENERATED_BODY_CLASSNAME - + "\">" - + "<div class='v-app v-app-loginpage' style=\"background:transparent;\">" - + "<iframe name='logintarget' style='width:0;height:0;" - + "border:0;margin:0;padding:0;'></iframe>" - + "<form id='loginf' target='logintarget' onkeypress=\"submitOnEnter(event)\" method=\"post\">" - + "<div>" - + usernameCaption - + "</div><div >" - + "<input class='v-textfield v-connector' style='display:block;' type='text' name='username'></div>" - + "<div>" - + passwordCaption - + "</div>" - + "<div><input class='v-textfield v-connector' style='display:block;' type='password' name='password'></div>" - + "<div><div onclick=\"document.forms[0].submit();\" tabindex=\"0\" class=\"v-button\" role=\"button\" ><span class=\"v-button-wrap\"><span class=\"v-button-caption\">" - + loginButtonCaption - + "</span></span></div></div></form></div>" + "</body></html>") - .getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not avalable", e); - } - } - - @Override - public void attach() { - super.attach(); - getApplication().addResource(loginPage); - getApplication().addRequestHandler(requestHandler); - iframe.setSource(loginPage); - } - - @Override - public void detach() { - getApplication().removeResource(loginPage); - getApplication().removeRequestHandler(requestHandler); - - super.detach(); - } - - /** - * This event is sent when login form is submitted. - */ - public class LoginEvent extends Event { - - private Map<String, String> params; - - private LoginEvent(Map<String, String> params) { - super(LoginForm.this); - this.params = params; - } - - /** - * Access method to form values by field names. - * - * @param name - * @return value in given field - */ - public String getLoginParameter(String name) { - if (params.containsKey(name)) { - return params.get(name); - } else { - return null; - } - } - } - - /** - * Login listener is a class capable to listen LoginEvents sent from - * LoginBox - */ - public interface LoginListener extends Serializable { - /** - * This method is fired on each login form post. - * - * @param event - */ - public void onLogin(LoginForm.LoginEvent event); - } - - private static final Method ON_LOGIN_METHOD; - - private static final String UNDEFINED_HEIGHT = "140px"; - private static final String UNDEFINED_WIDTH = "200px"; - - static { - try { - ON_LOGIN_METHOD = LoginListener.class.getDeclaredMethod("onLogin", - new Class[] { LoginEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in LoginForm"); - } - } - - /** - * Adds LoginListener to handle login logic - * - * @param listener - */ - public void addListener(LoginListener listener) { - addListener(LoginEvent.class, listener, ON_LOGIN_METHOD); - } - - /** - * Removes LoginListener - * - * @param listener - */ - public void removeListener(LoginListener listener) { - removeListener(LoginEvent.class, listener, ON_LOGIN_METHOD); - } - - @Override - public void setWidth(float width, Unit unit) { - super.setWidth(width, unit); - if (iframe != null) { - if (width < 0) { - iframe.setWidth(UNDEFINED_WIDTH); - } else { - iframe.setWidth("100%"); - } - } - } - - @Override - public void setHeight(float height, Unit unit) { - super.setHeight(height, unit); - if (iframe != null) { - if (height < 0) { - iframe.setHeight(UNDEFINED_HEIGHT); - } else { - iframe.setHeight("100%"); - } - } - } - - /** - * Returns the caption for the user name field. - * - * @return String - */ - public String getUsernameCaption() { - return usernameCaption; - } - - /** - * Sets the caption to show for the user name field. The caption cannot be - * changed after the form has been shown to the user. - * - * @param usernameCaption - */ - public void setUsernameCaption(String usernameCaption) { - this.usernameCaption = usernameCaption; - } - - /** - * Returns the caption for the password field. - * - * @return String - */ - public String getPasswordCaption() { - return passwordCaption; - } - - /** - * Sets the caption to show for the password field. The caption cannot be - * changed after the form has been shown to the user. - * - * @param passwordCaption - */ - public void setPasswordCaption(String passwordCaption) { - this.passwordCaption = passwordCaption; - } - - /** - * Returns the caption for the login button. - * - * @return String - */ - public String getLoginButtonCaption() { - return loginButtonCaption; - } - - /** - * Sets the caption (button text) to show for the login button. The caption - * cannot be changed after the form has been shown to the user. - * - * @param loginButtonCaption - */ - public void setLoginButtonCaption(String loginButtonCaption) { - this.loginButtonCaption = loginButtonCaption; - } - -} diff --git a/src/com/vaadin/ui/MenuBar.java b/src/com/vaadin/ui/MenuBar.java deleted file mode 100644 index 5b5dc13e20..0000000000 --- a/src/com/vaadin/ui/MenuBar.java +++ /dev/null @@ -1,890 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Stack; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.menubar.VMenuBar; - -/** - * <p> - * A class representing a horizontal menu bar. The menu can contain MenuItem - * objects, which in turn can contain more MenuBars. These sub-level MenuBars - * are represented as vertical menu. - * </p> - */ -@SuppressWarnings("serial") -public class MenuBar extends AbstractComponent implements Vaadin6Component { - - // Items of the top-level menu - private final List<MenuItem> menuItems; - - // Number of items in this menu - private int numberOfItems = 0; - - private MenuItem moreItem; - - private boolean openRootOnHover; - - private boolean htmlContentAllowed; - - /** Paint (serialise) the component for the client. */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - target.addAttribute(VMenuBar.OPEN_ROOT_MENU_ON_HOWER, openRootOnHover); - - if (isHtmlContentAllowed()) { - target.addAttribute(VMenuBar.HTML_CONTENT_ALLOWED, true); - } - - target.startTag("options"); - - if (getWidth() > -1) { - target.startTag("moreItem"); - target.addAttribute("text", moreItem.getText()); - if (moreItem.getIcon() != null) { - target.addAttribute("icon", moreItem.getIcon()); - } - target.endTag("moreItem"); - } - - target.endTag("options"); - target.startTag("items"); - - // This generates the tree from the contents of the menu - for (MenuItem item : menuItems) { - paintItem(target, item); - } - - target.endTag("items"); - } - - private void paintItem(PaintTarget target, MenuItem item) - throws PaintException { - if (!item.isVisible()) { - return; - } - - target.startTag("item"); - - target.addAttribute("id", item.getId()); - - if (item.getStyleName() != null) { - target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_STYLE, - item.getStyleName()); - } - - if (item.isSeparator()) { - target.addAttribute("separator", true); - } else { - target.addAttribute("text", item.getText()); - - Command command = item.getCommand(); - if (command != null) { - target.addAttribute("command", true); - } - - Resource icon = item.getIcon(); - if (icon != null) { - target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_ICON, icon); - } - - if (!item.isEnabled()) { - target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_DISABLED, true); - } - - String description = item.getDescription(); - if (description != null && description.length() > 0) { - target.addAttribute(VMenuBar.ATTRIBUTE_ITEM_DESCRIPTION, - description); - } - if (item.isCheckable()) { - // if the "checked" attribute is present (either true or false), - // the item is checkable - target.addAttribute(VMenuBar.ATTRIBUTE_CHECKED, - item.isChecked()); - } - if (item.hasChildren()) { - for (MenuItem child : item.getChildren()) { - paintItem(target, child); - } - } - - } - - target.endTag("item"); - } - - /** Deserialize changes received from client. */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - Stack<MenuItem> items = new Stack<MenuItem>(); - boolean found = false; - - if (variables.containsKey("clickedId")) { - - Integer clickedId = (Integer) variables.get("clickedId"); - Iterator<MenuItem> itr = getItems().iterator(); - while (itr.hasNext()) { - items.push(itr.next()); - } - - MenuItem tmpItem = null; - - // Go through all the items in the menu - while (!found && !items.empty()) { - tmpItem = items.pop(); - found = (clickedId.intValue() == tmpItem.getId()); - - if (tmpItem.hasChildren()) { - itr = tmpItem.getChildren().iterator(); - while (itr.hasNext()) { - items.push(itr.next()); - } - } - - }// while - - // If we got the clicked item, launch the command. - if (found && tmpItem.isEnabled()) { - if (tmpItem.isCheckable()) { - tmpItem.setChecked(!tmpItem.isChecked()); - } - if (null != tmpItem.getCommand()) { - tmpItem.getCommand().menuSelected(tmpItem); - } - } - }// if - }// changeVariables - - /** - * Constructs an empty, horizontal menu - */ - public MenuBar() { - menuItems = new ArrayList<MenuItem>(); - setMoreMenuItem(null); - } - - /** - * Add a new item to the menu bar. Command can be null, but a caption must - * be given. - * - * @param caption - * the text for the menu item - * @param command - * the command for the menu item - * @throws IllegalArgumentException - */ - public MenuBar.MenuItem addItem(String caption, MenuBar.Command command) { - return addItem(caption, null, command); - } - - /** - * Add a new item to the menu bar. Icon and command can be null, but a - * caption must be given. - * - * @param caption - * the text for the menu item - * @param icon - * the icon for the menu item - * @param command - * the command for the menu item - * @throws IllegalArgumentException - */ - public MenuBar.MenuItem addItem(String caption, Resource icon, - MenuBar.Command command) { - if (caption == null) { - throw new IllegalArgumentException("caption cannot be null"); - } - MenuItem newItem = new MenuItem(caption, icon, command); - menuItems.add(newItem); - requestRepaint(); - - return newItem; - - } - - /** - * Add an item before some item. If the given item does not exist the item - * is added at the end of the menu. Icon and command can be null, but a - * caption must be given. - * - * @param caption - * the text for the menu item - * @param icon - * the icon for the menu item - * @param command - * the command for the menu item - * @param itemToAddBefore - * the item that will be after the new item - * @throws IllegalArgumentException - */ - public MenuBar.MenuItem addItemBefore(String caption, Resource icon, - MenuBar.Command command, MenuBar.MenuItem itemToAddBefore) { - if (caption == null) { - throw new IllegalArgumentException("caption cannot be null"); - } - - MenuItem newItem = new MenuItem(caption, icon, command); - if (menuItems.contains(itemToAddBefore)) { - int index = menuItems.indexOf(itemToAddBefore); - menuItems.add(index, newItem); - - } else { - menuItems.add(newItem); - } - - requestRepaint(); - - return newItem; - } - - /** - * Returns a list with all the MenuItem objects in the menu bar - * - * @return a list containing the MenuItem objects in the menu bar - */ - public List<MenuItem> getItems() { - return menuItems; - } - - /** - * Remove first occurrence the specified item from the main menu - * - * @param item - * The item to be removed - */ - public void removeItem(MenuBar.MenuItem item) { - if (item != null) { - menuItems.remove(item); - } - requestRepaint(); - } - - /** - * Empty the menu bar - */ - public void removeItems() { - menuItems.clear(); - requestRepaint(); - } - - /** - * Returns the size of the menu. - * - * @return The size of the menu - */ - public int getSize() { - return menuItems.size(); - } - - /** - * Set the item that is used when collapsing the top level menu. All - * "overflowing" items will be added below this. The item command will be - * ignored. If set to null, the default item with a downwards arrow is used. - * - * The item command (if specified) is ignored. - * - * @param item - */ - public void setMoreMenuItem(MenuItem item) { - if (item != null) { - moreItem = item; - } else { - moreItem = new MenuItem("", null, null); - } - requestRepaint(); - } - - /** - * Get the MenuItem used as the collapse menu item. - * - * @return - */ - public MenuItem getMoreMenuItem() { - return moreItem; - } - - /** - * Using this method menubar can be put into a special mode where top level - * menus opens without clicking on the menu, but automatically when mouse - * cursor is moved over the menu. In this mode the menu also closes itself - * if the mouse is moved out of the opened menu. - * <p> - * Note, that on touch devices the menu still opens on a click event. - * - * @param autoOpenTopLevelMenu - * true if menus should be opened without click, the default is - * false - */ - public void setAutoOpen(boolean autoOpenTopLevelMenu) { - if (autoOpenTopLevelMenu != openRootOnHover) { - openRootOnHover = autoOpenTopLevelMenu; - requestRepaint(); - } - } - - /** - * Detects whether the menubar is in a mode where top level menus are - * automatically opened when the mouse cursor is moved over the menu. - * Normally root menu opens only by clicking on the menu. Submenus always - * open automatically. - * - * @return true if the root menus open without click, the default is false - */ - public boolean isAutoOpen() { - return openRootOnHover; - } - - /** - * Sets whether html is allowed in the item captions. If set to true, the - * captions are passed to the browser as html and the developer is - * responsible for ensuring no harmful html is used. If set to false, the - * content is passed to the browser as plain text. - * - * @param htmlContentAllowed - * true if the captions are used as html, false if used as plain - * text - */ - public void setHtmlContentAllowed(boolean htmlContentAllowed) { - this.htmlContentAllowed = htmlContentAllowed; - requestRepaint(); - } - - /** - * Checks whether item captions are interpreted as html or plain text. - * - * @return true if the captions are used as html, false if used as plain - * text - * @see #setHtmlContentAllowed(boolean) - */ - public boolean isHtmlContentAllowed() { - return htmlContentAllowed; - } - - /** - * This interface contains the layer for menu commands of the - * {@link com.vaadin.ui.MenuBar} class. It's method will fire when the user - * clicks on the containing {@link com.vaadin.ui.MenuBar.MenuItem}. The - * selected item is given as an argument. - */ - public interface Command extends Serializable { - public void menuSelected(MenuBar.MenuItem selectedItem); - } - - /** - * A composite class for menu items and sub-menus. You can set commands to - * be fired on user click by implementing the - * {@link com.vaadin.ui.MenuBar.Command} interface. You can also add - * multiple MenuItems to a MenuItem and create a sub-menu. - * - */ - public class MenuItem implements Serializable { - - /** Private members * */ - private final int itsId; - private Command itsCommand; - private String itsText; - private List<MenuItem> itsChildren; - private Resource itsIcon; - private MenuItem itsParent; - private boolean enabled = true; - private boolean visible = true; - private boolean isSeparator = false; - private String styleName; - private String description; - private boolean checkable = false; - private boolean checked = false; - - /** - * Constructs a new menu item that can optionally have an icon and a - * command associated with it. Icon and command can be null, but a - * caption must be given. - * - * @param text - * The text associated with the command - * @param command - * The command to be fired - * @throws IllegalArgumentException - */ - public MenuItem(String caption, Resource icon, MenuBar.Command command) { - if (caption == null) { - throw new IllegalArgumentException("caption cannot be null"); - } - itsId = ++numberOfItems; - itsText = caption; - itsIcon = icon; - itsCommand = command; - } - - /** - * Checks if the item has children (if it is a sub-menu). - * - * @return True if this item has children - */ - public boolean hasChildren() { - return !isSeparator() && itsChildren != null; - } - - /** - * Adds a separator to this menu. A separator is a way to visually group - * items in a menu, to make it easier for users to find what they are - * looking for in the menu. - * - * @author Jouni Koivuviita / Vaadin Ltd. - * @since 6.2.0 - */ - public MenuBar.MenuItem addSeparator() { - MenuItem item = addItem("", null, null); - item.setSeparator(true); - return item; - } - - public MenuBar.MenuItem addSeparatorBefore(MenuItem itemToAddBefore) { - MenuItem item = addItemBefore("", null, null, itemToAddBefore); - item.setSeparator(true); - return item; - } - - /** - * Add a new item inside this item, thus creating a sub-menu. Command - * can be null, but a caption must be given. - * - * @param caption - * the text for the menu item - * @param command - * the command for the menu item - */ - public MenuBar.MenuItem addItem(String caption, MenuBar.Command command) { - return addItem(caption, null, command); - } - - /** - * Add a new item inside this item, thus creating a sub-menu. Icon and - * command can be null, but a caption must be given. - * - * @param caption - * the text for the menu item - * @param icon - * the icon for the menu item - * @param command - * the command for the menu item - * @throws IllegalStateException - * If the item is checkable and thus cannot have children. - */ - public MenuBar.MenuItem addItem(String caption, Resource icon, - MenuBar.Command command) throws IllegalStateException { - if (isSeparator()) { - throw new UnsupportedOperationException( - "Cannot add items to a separator"); - } - if (isCheckable()) { - throw new IllegalStateException( - "A checkable item cannot have children"); - } - if (caption == null) { - throw new IllegalArgumentException("Caption cannot be null"); - } - - if (itsChildren == null) { - itsChildren = new ArrayList<MenuItem>(); - } - - MenuItem newItem = new MenuItem(caption, icon, command); - - // The only place where the parent is set - newItem.setParent(this); - itsChildren.add(newItem); - - requestRepaint(); - - return newItem; - } - - /** - * Add an item before some item. If the given item does not exist the - * item is added at the end of the menu. Icon and command can be null, - * but a caption must be given. - * - * @param caption - * the text for the menu item - * @param icon - * the icon for the menu item - * @param command - * the command for the menu item - * @param itemToAddBefore - * the item that will be after the new item - * @throws IllegalStateException - * If the item is checkable and thus cannot have children. - */ - public MenuBar.MenuItem addItemBefore(String caption, Resource icon, - MenuBar.Command command, MenuBar.MenuItem itemToAddBefore) - throws IllegalStateException { - if (isCheckable()) { - throw new IllegalStateException( - "A checkable item cannot have children"); - } - MenuItem newItem = null; - - if (hasChildren() && itsChildren.contains(itemToAddBefore)) { - int index = itsChildren.indexOf(itemToAddBefore); - newItem = new MenuItem(caption, icon, command); - newItem.setParent(this); - itsChildren.add(index, newItem); - } else { - newItem = addItem(caption, icon, command); - } - - requestRepaint(); - - return newItem; - } - - /** - * For the associated command. - * - * @return The associated command, or null if there is none - */ - public Command getCommand() { - return itsCommand; - } - - /** - * Gets the objects icon. - * - * @return The icon of the item, null if the item doesn't have an icon - */ - public Resource getIcon() { - return itsIcon; - } - - /** - * For the containing item. This will return null if the item is in the - * top-level menu bar. - * - * @return The containing {@link com.vaadin.ui.MenuBar.MenuItem} , or - * null if there is none - */ - public MenuBar.MenuItem getParent() { - return itsParent; - } - - /** - * This will return the children of this item or null if there are none. - * - * @return List of children items, or null if there are none - */ - public List<MenuItem> getChildren() { - return itsChildren; - } - - /** - * Gets the objects text - * - * @return The text - */ - public java.lang.String getText() { - return itsText; - } - - /** - * Returns the number of children. - * - * @return The number of child items - */ - public int getSize() { - if (itsChildren != null) { - return itsChildren.size(); - } - return -1; - } - - /** - * Get the unique identifier for this item. - * - * @return The id of this item - */ - public int getId() { - return itsId; - } - - /** - * Set the command for this item. Set null to remove. - * - * @param command - * The MenuCommand of this item - */ - public void setCommand(MenuBar.Command command) { - itsCommand = command; - } - - /** - * Sets the icon. Set null to remove. - * - * @param icon - * The icon for this item - */ - public void setIcon(Resource icon) { - itsIcon = icon; - requestRepaint(); - } - - /** - * Set the text of this object. - * - * @param text - * Text for this object - */ - public void setText(java.lang.String text) { - if (text != null) { - itsText = text; - } - requestRepaint(); - } - - /** - * Remove the first occurrence of the item. - * - * @param item - * The item to be removed - */ - public void removeChild(MenuBar.MenuItem item) { - if (item != null && itsChildren != null) { - itsChildren.remove(item); - if (itsChildren.isEmpty()) { - itsChildren = null; - } - requestRepaint(); - } - } - - /** - * Empty the list of children items. - */ - public void removeChildren() { - if (itsChildren != null) { - itsChildren.clear(); - itsChildren = null; - requestRepaint(); - } - } - - /** - * Set the parent of this item. This is called by the addItem method. - * - * @param parent - * The parent item - */ - protected void setParent(MenuBar.MenuItem parent) { - itsParent = parent; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - requestRepaint(); - } - - public boolean isEnabled() { - return enabled; - } - - public void setVisible(boolean visible) { - this.visible = visible; - requestRepaint(); - } - - public boolean isVisible() { - return visible; - } - - private void setSeparator(boolean isSeparator) { - this.isSeparator = isSeparator; - requestRepaint(); - } - - public boolean isSeparator() { - return isSeparator; - } - - public void setStyleName(String styleName) { - this.styleName = styleName; - requestRepaint(); - } - - public String getStyleName() { - return styleName; - } - - /** - * Sets the items's description. See {@link #getDescription()} for more - * information on what the description is. This method will trigger a - * {@link RepaintRequestEvent}. - * - * @param description - * the new description string for the component. - */ - public void setDescription(String description) { - this.description = description; - requestRepaint(); - } - - /** - * <p> - * Gets the items's description. The description can be used to briefly - * describe the state of the item to the user. The description string - * may contain certain XML tags: - * </p> - * - * <p> - * <table border=1> - * <tr> - * <td width=120><b>Tag</b></td> - * <td width=120><b>Description</b></td> - * <td width=120><b>Example</b></td> - * </tr> - * <tr> - * <td><b></td> - * <td>bold</td> - * <td><b>bold text</b></td> - * </tr> - * <tr> - * <td><i></td> - * <td>italic</td> - * <td><i>italic text</i></td> - * </tr> - * <tr> - * <td><u></td> - * <td>underlined</td> - * <td><u>underlined text</u></td> - * </tr> - * <tr> - * <td><br></td> - * <td>linebreak</td> - * <td>N/A</td> - * </tr> - * <tr> - * <td><ul><br> - * <li>item1<br> - * <li>item1<br> - * </ul></td> - * <td>item list</td> - * <td> - * <ul> - * <li>item1 - * <li>item2 - * </ul> - * </td> - * </tr> - * </table> - * </p> - * - * <p> - * These tags may be nested. - * </p> - * - * @return item's description <code>String</code> - */ - public String getDescription() { - return description; - } - - /** - * Gets the checkable state of the item - whether the item has checked - * and unchecked states. If an item is checkable its checked state (as - * returned by {@link #isChecked()}) is indicated in the UI. - * - * <p> - * An item is not checkable by default. - * </p> - * - * @return true if the item is checkable, false otherwise - * @since 6.6.2 - */ - public boolean isCheckable() { - return checkable; - } - - /** - * Sets the checkable state of the item. If an item is checkable its - * checked state (as returned by {@link #isChecked()}) is indicated in - * the UI. - * - * <p> - * An item is not checkable by default. - * </p> - * - * <p> - * Items with sub items cannot be checkable. - * </p> - * - * @param checkable - * true if the item should be checkable, false otherwise - * @throws IllegalStateException - * If the item has children - * @since 6.6.2 - */ - public void setCheckable(boolean checkable) - throws IllegalStateException { - if (hasChildren()) { - throw new IllegalStateException( - "A menu item with children cannot be checkable"); - } - this.checkable = checkable; - requestRepaint(); - } - - /** - * Gets the checked state of the item (checked or unchecked). Only used - * if the item is checkable (as indicated by {@link #isCheckable()}). - * The checked state is indicated in the UI with the item, if the item - * is checkable. - * - * <p> - * An item is not checked by default. - * </p> - * - * <p> - * The CSS style corresponding to the checked state is "-checked". - * </p> - * - * @return true if the item is checked, false otherwise - * @since 6.6.2 - */ - public boolean isChecked() { - return checked; - } - - /** - * Sets the checked state of the item. Only used if the item is - * checkable (indicated by {@link #isCheckable()}). The checked state is - * indicated in the UI with the item, if the item is checkable. - * - * <p> - * An item is not checked by default. - * </p> - * - * <p> - * The CSS style corresponding to the checked state is "-checked". - * </p> - * - * @return true if the item is checked, false otherwise - * @since 6.6.2 - */ - public void setChecked(boolean checked) { - this.checked = checked; - requestRepaint(); - } - - }// class MenuItem - -}// class MenuBar diff --git a/src/com/vaadin/ui/NativeButton.java b/src/com/vaadin/ui/NativeButton.java deleted file mode 100644 index 6eb4379261..0000000000 --- a/src/com/vaadin/ui/NativeButton.java +++ /dev/null @@ -1,21 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -@SuppressWarnings("serial") -public class NativeButton extends Button { - - public NativeButton() { - super(); - } - - public NativeButton(String caption) { - super(caption); - } - - public NativeButton(String caption, ClickListener listener) { - super(caption, listener); - } - -} diff --git a/src/com/vaadin/ui/NativeSelect.java b/src/com/vaadin/ui/NativeSelect.java deleted file mode 100644 index 1f85f57c97..0000000000 --- a/src/com/vaadin/ui/NativeSelect.java +++ /dev/null @@ -1,91 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Collection; - -import com.vaadin.data.Container; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * This is a simple drop-down select without, for instance, support for - * multiselect, new items, lazyloading, and other advanced features. Sometimes - * "native" select without all the bells-and-whistles of the ComboBox is a - * better choice. - */ -@SuppressWarnings("serial") -public class NativeSelect extends AbstractSelect { - - // width in characters, mimics TextField - private int columns = 0; - - public NativeSelect() { - super(); - } - - public NativeSelect(String caption, Collection<?> options) { - super(caption, options); - } - - public NativeSelect(String caption, Container dataSource) { - super(caption, dataSource); - } - - public NativeSelect(String caption) { - super(caption); - } - - /** - * Sets the number of columns in the editor. If the number of columns is set - * 0, the actual number of displayed columns is determined implicitly by the - * adapter. - * - * @param columns - * the number of columns to set. - */ - public void setColumns(int columns) { - if (columns < 0) { - columns = 0; - } - if (this.columns != columns) { - this.columns = columns; - requestRepaint(); - } - } - - public int getColumns() { - return columns; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - target.addAttribute("type", "native"); - // Adds the number of columns - if (columns != 0) { - target.addAttribute("cols", columns); - } - - super.paintContent(target); - } - - @Override - public void setMultiSelect(boolean multiSelect) - throws UnsupportedOperationException { - if (multiSelect == true) { - throw new UnsupportedOperationException("Multiselect not supported"); - } - } - - @Override - public void setNewItemsAllowed(boolean allowNewOptions) - throws UnsupportedOperationException { - if (allowNewOptions == true) { - throw new UnsupportedOperationException( - "newItemsAllowed not supported"); - } - } - -} diff --git a/src/com/vaadin/ui/Notification.java b/src/com/vaadin/ui/Notification.java deleted file mode 100644 index 502e5ff788..0000000000 --- a/src/com/vaadin/ui/Notification.java +++ /dev/null @@ -1,367 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; - -import com.vaadin.terminal.Page; -import com.vaadin.terminal.Resource; - -/** - * A notification message, used to display temporary messages to the user - for - * example "Document saved", or "Save failed". - * <p> - * The notification message can consist of several parts: caption, description - * and icon. It is usually used with only caption - one should be wary of - * filling the notification with too much information. - * </p> - * <p> - * The notification message tries to be as unobtrusive as possible, while still - * drawing needed attention. There are several basic types of messages that can - * be used in different situations: - * <ul> - * <li>TYPE_HUMANIZED_MESSAGE fades away quickly as soon as the user uses the - * mouse or types something. It can be used to show fairly unimportant messages, - * such as feedback that an operation succeeded ("Document Saved") - the kind of - * messages the user ignores once the application is familiar.</li> - * <li>TYPE_WARNING_MESSAGE is shown for a short while after the user uses the - * mouse or types something. It's default style is also more noticeable than the - * humanized message. It can be used for messages that do not contain a lot of - * important information, but should be noticed by the user. Despite the name, - * it does not have to be a warning, but can be used instead of the humanized - * message whenever you want to make the message a little more noticeable.</li> - * <li>TYPE_ERROR_MESSAGE requires to user to click it before disappearing, and - * can be used for critical messages.</li> - * <li>TYPE_TRAY_NOTIFICATION is shown for a while in the lower left corner of - * the window, and can be used for "convenience notifications" that do not have - * to be noticed immediately, and should not interfere with the current task - - * for instance to show "You have a new message in your inbox" while the user is - * working in some other area of the application.</li> - * </ul> - * </p> - * <p> - * In addition to the basic pre-configured types, a Notification can also be - * configured to show up in a custom position, for a specified time (or until - * clicked), and with a custom stylename. An icon can also be added. - * </p> - * - */ -public class Notification implements Serializable { - public static final int TYPE_HUMANIZED_MESSAGE = 1; - public static final int TYPE_WARNING_MESSAGE = 2; - public static final int TYPE_ERROR_MESSAGE = 3; - public static final int TYPE_TRAY_NOTIFICATION = 4; - - public static final int POSITION_CENTERED = 1; - public static final int POSITION_CENTERED_TOP = 2; - public static final int POSITION_CENTERED_BOTTOM = 3; - public static final int POSITION_TOP_LEFT = 4; - public static final int POSITION_TOP_RIGHT = 5; - public static final int POSITION_BOTTOM_LEFT = 6; - public static final int POSITION_BOTTOM_RIGHT = 7; - - public static final int DELAY_FOREVER = -1; - public static final int DELAY_NONE = 0; - - private String caption; - private String description; - private Resource icon; - private int position = POSITION_CENTERED; - private int delayMsec = 0; - private String styleName; - private boolean htmlContentAllowed; - - /** - * Creates a "humanized" notification message. - * - * The caption is rendered as plain text with HTML automatically escaped. - * - * @param caption - * The message to show - */ - public Notification(String caption) { - this(caption, null, TYPE_HUMANIZED_MESSAGE); - } - - /** - * Creates a notification message of the specified type. - * - * The caption is rendered as plain text with HTML automatically escaped. - * - * @param caption - * The message to show - * @param type - * The type of message - */ - public Notification(String caption, int type) { - this(caption, null, type); - } - - /** - * Creates a "humanized" notification message with a bigger caption and - * smaller description. - * - * The caption and description are rendered as plain text with HTML - * automatically escaped. - * - * @param caption - * The message caption - * @param description - * The message description - */ - public Notification(String caption, String description) { - this(caption, description, TYPE_HUMANIZED_MESSAGE); - } - - /** - * Creates a notification message of the specified type, with a bigger - * caption and smaller description. - * - * The caption and description are rendered as plain text with HTML - * automatically escaped. - * - * @param caption - * The message caption - * @param description - * The message description - * @param type - * The type of message - */ - public Notification(String caption, String description, int type) { - this(caption, description, type, false); - } - - /** - * Creates a notification message of the specified type, with a bigger - * caption and smaller description. - * - * Care should be taken to to avoid XSS vulnerabilities if html is allowed. - * - * @param caption - * The message caption - * @param description - * The message description - * @param type - * The type of message - * @param htmlContentAllowed - * Whether html in the caption and description should be - * displayed as html or as plain text - */ - public Notification(String caption, String description, int type, - boolean htmlContentAllowed) { - this.caption = caption; - this.description = description; - this.htmlContentAllowed = htmlContentAllowed; - setType(type); - } - - private void setType(int type) { - switch (type) { - case TYPE_WARNING_MESSAGE: - delayMsec = 1500; - styleName = "warning"; - break; - case TYPE_ERROR_MESSAGE: - delayMsec = -1; - styleName = "error"; - break; - case TYPE_TRAY_NOTIFICATION: - delayMsec = 3000; - position = POSITION_BOTTOM_RIGHT; - styleName = "tray"; - - case TYPE_HUMANIZED_MESSAGE: - default: - break; - } - - } - - /** - * Gets the caption part of the notification message. - * - * @return The message caption - */ - public String getCaption() { - return caption; - } - - /** - * Sets the caption part of the notification message - * - * @param caption - * The message caption - */ - public void setCaption(String caption) { - this.caption = caption; - } - - /** - * Gets the description part of the notification message. - * - * @return The message description. - */ - public String getDescription() { - return description; - } - - /** - * Sets the description part of the notification message. - * - * @param description - */ - public void setDescription(String description) { - this.description = description; - } - - /** - * Gets the position of the notification message. - * - * @return The position - */ - public int getPosition() { - return position; - } - - /** - * Sets the position of the notification message. - * - * @param position - * The desired notification position - */ - public void setPosition(int position) { - this.position = position; - } - - /** - * Gets the icon part of the notification message. - * - * @return The message icon - */ - public Resource getIcon() { - return icon; - } - - /** - * Sets the icon part of the notification message. - * - * @param icon - * The desired message icon - */ - public void setIcon(Resource icon) { - this.icon = icon; - } - - /** - * Gets the delay before the notification disappears. - * - * @return the delay in msec, -1 indicates the message has to be clicked. - */ - public int getDelayMsec() { - return delayMsec; - } - - /** - * Sets the delay before the notification disappears. - * - * @param delayMsec - * the desired delay in msec, -1 to require the user to click the - * message - */ - public void setDelayMsec(int delayMsec) { - this.delayMsec = delayMsec; - } - - /** - * Sets the style name for the notification message. - * - * @param styleName - * The desired style name. - */ - public void setStyleName(String styleName) { - this.styleName = styleName; - } - - /** - * Gets the style name for the notification message. - * - * @return - */ - public String getStyleName() { - return styleName; - } - - /** - * Sets whether html is allowed in the caption and description. If set to - * true, the texts are passed to the browser as html and the developer is - * responsible for ensuring no harmful html is used. If set to false, the - * texts are passed to the browser as plain text. - * - * @param htmlContentAllowed - * true if the texts are used as html, false if used as plain - * text - */ - public void setHtmlContentAllowed(boolean htmlContentAllowed) { - this.htmlContentAllowed = htmlContentAllowed; - } - - /** - * Checks whether caption and description are interpreted as html or plain - * text. - * - * @return true if the texts are used as html, false if used as plain text - * @see #setHtmlContentAllowed(boolean) - */ - public boolean isHtmlContentAllowed() { - return htmlContentAllowed; - } - - /** - * Shows this notification on a Page. - * - * @param page - * The page on which the notification should be shown - */ - public void show(Page page) { - // TODO Can avoid deprecated API when Notification extends Extension - page.showNotification(this); - } - - /** - * Shows a notification message on the middle of the current page. The - * message automatically disappears ("humanized message"). - * - * The caption is rendered as plain text with HTML automatically escaped. - * - * @see #Notification(String) - * @see #show(Page) - * - * @param caption - * The message - */ - public static void show(String caption) { - new Notification(caption).show(Page.getCurrent()); - } - - /** - * Shows a notification message the current page. The position and behavior - * of the message depends on the type, which is one of the basic types - * defined in {@link Notification}, for instance - * Notification.TYPE_WARNING_MESSAGE. - * - * The caption is rendered as plain text with HTML automatically escaped. - * - * @see #Notification(String, int) - * @see #show(Page) - * - * @param caption - * The message - * @param type - * The message type - */ - public static void show(String caption, int type) { - new Notification(caption, type).show(Page.getCurrent()); - } -}
\ No newline at end of file diff --git a/src/com/vaadin/ui/OptionGroup.java b/src/com/vaadin/ui/OptionGroup.java deleted file mode 100644 index e3bcdd61b7..0000000000 --- a/src/com/vaadin/ui/OptionGroup.java +++ /dev/null @@ -1,203 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.vaadin.data.Container; -import com.vaadin.event.FieldEvents; -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.optiongroup.VOptionGroup; - -/** - * Configures select to be used as an option group. - */ -@SuppressWarnings("serial") -public class OptionGroup extends AbstractSelect implements - FieldEvents.BlurNotifier, FieldEvents.FocusNotifier { - - private Set<Object> disabledItemIds = new HashSet<Object>(); - private boolean htmlContentAllowed = false; - - public OptionGroup() { - super(); - } - - public OptionGroup(String caption, Collection<?> options) { - super(caption, options); - } - - public OptionGroup(String caption, Container dataSource) { - super(caption, dataSource); - } - - public OptionGroup(String caption) { - super(caption); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - target.addAttribute("type", "optiongroup"); - if (isHtmlContentAllowed()) { - target.addAttribute(VOptionGroup.HTML_CONTENT_ALLOWED, true); - } - super.paintContent(target); - } - - @Override - protected void paintItem(PaintTarget target, Object itemId) - throws PaintException { - super.paintItem(target, itemId); - if (!isItemEnabled(itemId)) { - target.addAttribute(VOptionGroup.ATTRIBUTE_OPTION_DISABLED, true); - } - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } - if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } - } - - @Override - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - @Override - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - @Override - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - @Override - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - - } - - @Override - protected void setValue(Object newValue, boolean repaintIsNotNeeded) { - if (repaintIsNotNeeded) { - /* - * Check that value from changeVariables() doesn't contain unallowed - * selections: In the multi select mode, the user has selected or - * deselected a disabled item. In the single select mode, the user - * has selected a disabled item. - */ - if (isMultiSelect()) { - Set<?> currentValueSet = (Set<?>) getValue(); - Set<?> newValueSet = (Set<?>) newValue; - for (Object itemId : currentValueSet) { - if (!isItemEnabled(itemId) && !newValueSet.contains(itemId)) { - requestRepaint(); - return; - } - } - for (Object itemId : newValueSet) { - if (!isItemEnabled(itemId) - && !currentValueSet.contains(itemId)) { - requestRepaint(); - return; - } - } - } else { - if (newValue == null) { - newValue = getNullSelectionItemId(); - } - if (!isItemEnabled(newValue)) { - requestRepaint(); - return; - } - } - } - super.setValue(newValue, repaintIsNotNeeded); - } - - /** - * Sets an item disabled or enabled. In the multiselect mode, a disabled - * item cannot be selected or deselected by the user. In the single - * selection mode, a disable item cannot be selected. - * - * However, programmatical selection or deselection of an disable item is - * possible. By default, items are enabled. - * - * @param itemId - * the id of the item to be disabled or enabled - * @param enabled - * if true the item is enabled, otherwise the item is disabled - */ - public void setItemEnabled(Object itemId, boolean enabled) { - if (itemId != null) { - if (enabled) { - disabledItemIds.remove(itemId); - } else { - disabledItemIds.add(itemId); - } - requestRepaint(); - } - } - - /** - * Returns true if the item is enabled. - * - * @param itemId - * the id of the item to be checked - * @return true if the item is enabled, false otherwise - * @see #setItemEnabled(Object, boolean) - */ - public boolean isItemEnabled(Object itemId) { - if (itemId != null) { - return !disabledItemIds.contains(itemId); - } - return true; - } - - /** - * Sets whether html is allowed in the item captions. If set to true, the - * captions are passed to the browser as html and the developer is - * responsible for ensuring no harmful html is used. If set to false, the - * content is passed to the browser as plain text. - * - * @param htmlContentAllowed - * true if the captions are used as html, false if used as plain - * text - */ - public void setHtmlContentAllowed(boolean htmlContentAllowed) { - this.htmlContentAllowed = htmlContentAllowed; - requestRepaint(); - } - - /** - * Checks whether captions are interpreted as html or plain text. - * - * @return true if the captions are used as html, false if used as plain - * text - * @see #setHtmlContentAllowed(boolean) - */ - public boolean isHtmlContentAllowed() { - return htmlContentAllowed; - } -} diff --git a/src/com/vaadin/ui/Panel.java b/src/com/vaadin/ui/Panel.java deleted file mode 100644 index 3c26b73f09..0000000000 --- a/src/com/vaadin/ui/Panel.java +++ /dev/null @@ -1,486 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; - -import com.vaadin.event.Action; -import com.vaadin.event.Action.Handler; -import com.vaadin.event.ActionManager; -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.event.MouseEvents.ClickListener; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.panel.PanelServerRpc; -import com.vaadin.shared.ui.panel.PanelState; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Scrollable; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.ClickEventHandler; -import com.vaadin.ui.Component.Focusable; - -/** - * Panel - a simple single component container. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Panel extends AbstractComponentContainer implements Scrollable, - ComponentContainer.ComponentAttachListener, - ComponentContainer.ComponentDetachListener, Action.Notifier, Focusable, - Vaadin6Component { - - /** - * Content of the panel. - */ - private ComponentContainer content; - - /** - * Keeps track of the Actions added to this component, and manages the - * painting and handling as well. - */ - protected ActionManager actionManager; - - private PanelServerRpc rpc = new PanelServerRpc() { - @Override - public void click(MouseEventDetails mouseDetails) { - fireEvent(new ClickEvent(Panel.this, mouseDetails)); - } - }; - - /** - * Creates a new empty panel. A VerticalLayout is used as content. - */ - public Panel() { - this((ComponentContainer) null); - } - - /** - * Creates a new empty panel which contains the given content. The content - * cannot be null. - * - * @param content - * the content for the panel. - */ - public Panel(ComponentContainer content) { - registerRpc(rpc); - setContent(content); - setWidth(100, Unit.PERCENTAGE); - getState().setTabIndex(-1); - } - - /** - * Creates a new empty panel with caption. Default layout is used. - * - * @param caption - * the caption used in the panel (HTML/XHTML). - */ - public Panel(String caption) { - this(caption, null); - } - - /** - * Creates a new empty panel with the given caption and content. - * - * @param caption - * the caption of the panel (HTML/XHTML). - * @param content - * the content used in the panel. - */ - public Panel(String caption, ComponentContainer content) { - this(content); - setCaption(caption); - } - - /** - * Sets the caption of the panel. - * - * Note that the caption is interpreted as HTML/XHTML and therefore care - * should be taken not to enable HTML injection and XSS attacks using panel - * captions. This behavior may change in future versions. - * - * @see AbstractComponent#setCaption(String) - */ - @Override - public void setCaption(String caption) { - super.setCaption(caption); - } - - /** - * Returns the content of the Panel. - * - * @return - */ - public ComponentContainer getContent() { - return content; - } - - /** - * - * Set the content of the Panel. If null is given as the new content then a - * layout is automatically created and set as the content. - * - * @param content - * The new content - */ - public void setContent(ComponentContainer newContent) { - - // If the content is null we create the default content - if (newContent == null) { - newContent = createDefaultContent(); - } - - // if (newContent == null) { - // throw new IllegalArgumentException("Content cannot be null"); - // } - - if (newContent == content) { - // don't set the same content twice - return; - } - - // detach old content if present - if (content != null) { - content.setParent(null); - content.removeListener((ComponentContainer.ComponentAttachListener) this); - content.removeListener((ComponentContainer.ComponentDetachListener) this); - } - - // Sets the panel to be parent for the content - newContent.setParent(this); - - // Sets the new content - content = newContent; - - // Adds the event listeners for new content - newContent - .addListener((ComponentContainer.ComponentAttachListener) this); - newContent - .addListener((ComponentContainer.ComponentDetachListener) this); - - content = newContent; - requestRepaint(); - } - - /** - * Create a ComponentContainer which is added by default to the Panel if - * user does not specify any content. - * - * @return - */ - private ComponentContainer createDefaultContent() { - VerticalLayout layout = new VerticalLayout(); - // Force margins by default - layout.setMargin(true); - return layout; - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.terminal.Vaadin6Component#paintContent(com.vaadin.terminal - * .PaintTarget) - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (actionManager != null) { - actionManager.paintActions(null, target); - } - } - - /** - * Adds the component into this container. - * - * @param c - * the component to be added. - * @see com.vaadin.ui.AbstractComponentContainer#addComponent(com.vaadin.ui.Component) - */ - @Override - public void addComponent(Component c) { - content.addComponent(c); - // No repaint request is made as we except the underlying container to - // request repaints - } - - /** - * Removes the component from this container. - * - * @param c - * The component to be removed. - * @see com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui.Component) - */ - @Override - public void removeComponent(Component c) { - content.removeComponent(c); - // No repaint request is made as we except the underlying container to - // request repaints - } - - /** - * Gets the component container iterator for going through all the - * components in the container. - * - * @return the Iterator of the components inside the container. - * @see com.vaadin.ui.ComponentContainer#getComponentIterator() - */ - @Override - public Iterator<Component> getComponentIterator() { - return Collections.singleton((Component) content).iterator(); - } - - /** - * Called when one or more variables handled by the implementing class are - * changed. - * - * @see com.vaadin.terminal.VariableOwner#changeVariables(Object, Map) - */ - @Override - @SuppressWarnings("unchecked") - public void changeVariables(Object source, Map<String, Object> variables) { - // Get new size - final Integer newWidth = (Integer) variables.get("width"); - final Integer newHeight = (Integer) variables.get("height"); - if (newWidth != null && newWidth.intValue() != getWidth()) { - setWidth(newWidth.intValue(), UNITS_PIXELS); - } - if (newHeight != null && newHeight.intValue() != getHeight()) { - setHeight(newHeight.intValue(), UNITS_PIXELS); - } - - // Scrolling - final Integer newScrollX = (Integer) variables.get("scrollLeft"); - final Integer newScrollY = (Integer) variables.get("scrollTop"); - if (newScrollX != null && newScrollX.intValue() != getScrollLeft()) { - // set internally, not to fire request repaint - getState().setScrollLeft(newScrollX.intValue()); - } - if (newScrollY != null && newScrollY.intValue() != getScrollTop()) { - // set internally, not to fire request repaint - getState().setScrollTop(newScrollY.intValue()); - } - - // Actions - if (actionManager != null) { - actionManager.handleActions(variables, this); - } - - } - - /* Scrolling functionality */ - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Scrollable#setScrollable(boolean) - */ - @Override - public int getScrollLeft() { - return getState().getScrollLeft(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Scrollable#setScrollable(boolean) - */ - @Override - public int getScrollTop() { - return getState().getScrollTop(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Scrollable#setScrollLeft(int) - */ - @Override - public void setScrollLeft(int scrollLeft) { - if (scrollLeft < 0) { - throw new IllegalArgumentException( - "Scroll offset must be at least 0"); - } - getState().setScrollLeft(scrollLeft); - requestRepaint(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.terminal.Scrollable#setScrollTop(int) - */ - @Override - public void setScrollTop(int scrollTop) { - if (scrollTop < 0) { - throw new IllegalArgumentException( - "Scroll offset must be at least 0"); - } - getState().setScrollTop(scrollTop); - requestRepaint(); - } - - /* Documented in superclass */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - - content.replaceComponent(oldComponent, newComponent); - } - - /** - * A new component is attached to container. - * - * @see com.vaadin.ui.ComponentContainer.ComponentAttachListener#componentAttachedToContainer(com.vaadin.ui.ComponentContainer.ComponentAttachEvent) - */ - @Override - public void componentAttachedToContainer(ComponentAttachEvent event) { - if (event.getContainer() == content) { - fireComponentAttachEvent(event.getAttachedComponent()); - } - } - - /** - * A component has been detached from container. - * - * @see com.vaadin.ui.ComponentContainer.ComponentDetachListener#componentDetachedFromContainer(com.vaadin.ui.ComponentContainer.ComponentDetachEvent) - */ - @Override - public void componentDetachedFromContainer(ComponentDetachEvent event) { - if (event.getContainer() == content) { - fireComponentDetachEvent(event.getDetachedComponent()); - } - } - - /** - * Removes all components from this container. - * - * @see com.vaadin.ui.ComponentContainer#removeAllComponents() - */ - @Override - public void removeAllComponents() { - content.removeAllComponents(); - } - - /* - * ACTIONS - */ - @Override - protected ActionManager getActionManager() { - if (actionManager == null) { - actionManager = new ActionManager(this); - } - return actionManager; - } - - @Override - public <T extends Action & com.vaadin.event.Action.Listener> void addAction( - T action) { - getActionManager().addAction(action); - } - - @Override - public <T extends Action & com.vaadin.event.Action.Listener> void removeAction( - T action) { - if (actionManager != null) { - actionManager.removeAction(action); - } - } - - @Override - public void addActionHandler(Handler actionHandler) { - getActionManager().addActionHandler(actionHandler); - } - - @Override - public void removeActionHandler(Handler actionHandler) { - if (actionManager != null) { - actionManager.removeActionHandler(actionHandler); - } - } - - /** - * Removes all action handlers - */ - public void removeAllActionHandlers() { - if (actionManager != null) { - actionManager.removeAllActionHandlers(); - } - } - - /** - * Add a click listener to the Panel. The listener is called whenever the - * user clicks inside the Panel. Also when the click targets a component - * inside the Panel, provided the targeted component does not prevent the - * click event from propagating. - * - * Use {@link #removeListener(ClickListener)} to remove the listener. - * - * @param listener - * The listener to add - */ - public void addListener(ClickListener listener) { - addListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, ClickEvent.class, - listener, ClickListener.clickMethod); - } - - /** - * Remove a click listener from the Panel. The listener should earlier have - * been added using {@link #addListener(ClickListener)}. - * - * @param listener - * The listener to remove - */ - public void removeListener(ClickListener listener) { - removeListener(ClickEventHandler.CLICK_EVENT_IDENTIFIER, - ClickEvent.class, listener); - } - - /** - * {@inheritDoc} - */ - @Override - public int getTabIndex() { - return getState().getTabIndex(); - } - - /** - * {@inheritDoc} - */ - @Override - public void setTabIndex(int tabIndex) { - getState().setTabIndex(tabIndex); - requestRepaint(); - } - - /** - * Moves keyboard focus to the component. {@see Focusable#focus()} - * - */ - @Override - public void focus() { - super.focus(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.ComponentContainer#getComponentCount() - */ - @Override - public int getComponentCount() { - // This is so wrong... (#2924) - return content.getComponentCount(); - } - - @Override - public PanelState getState() { - return (PanelState) super.getState(); - } - -} diff --git a/src/com/vaadin/ui/PasswordField.java b/src/com/vaadin/ui/PasswordField.java deleted file mode 100644 index c1fccebbfe..0000000000 --- a/src/com/vaadin/ui/PasswordField.java +++ /dev/null @@ -1,67 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import com.vaadin.data.Property; - -/** - * A field that is used to enter secret text information like passwords. The - * entered text is not displayed on the screen. - */ -public class PasswordField extends AbstractTextField { - - /** - * Constructs an empty PasswordField. - */ - public PasswordField() { - setValue(""); - } - - /** - * Constructs a PasswordField with given property data source. - * - * @param dataSource - * the property data source for the field - */ - public PasswordField(Property dataSource) { - setPropertyDataSource(dataSource); - } - - /** - * Constructs a PasswordField with given caption and property data source. - * - * @param caption - * the caption for the field - * @param dataSource - * the property data source for the field - */ - public PasswordField(String caption, Property dataSource) { - this(dataSource); - setCaption(caption); - } - - /** - * Constructs a PasswordField with given value and caption. - * - * @param caption - * the caption for the field - * @param value - * the value for the field - */ - public PasswordField(String caption, String value) { - setValue(value); - setCaption(caption); - } - - /** - * Constructs a PasswordField with given caption. - * - * @param caption - * the caption for the field - */ - public PasswordField(String caption) { - this(); - setCaption(caption); - } -} diff --git a/src/com/vaadin/ui/PopupDateField.java b/src/com/vaadin/ui/PopupDateField.java deleted file mode 100644 index 3688d4035f..0000000000 --- a/src/com/vaadin/ui/PopupDateField.java +++ /dev/null @@ -1,80 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Date; - -import com.vaadin.data.Property; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; - -/** - * <p> - * A date entry component, which displays the actual date selector as a popup. - * - * </p> - * - * @see DateField - * @see InlineDateField - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ -public class PopupDateField extends DateField { - - private String inputPrompt = null; - - public PopupDateField() { - super(); - } - - public PopupDateField(Property dataSource) throws IllegalArgumentException { - super(dataSource); - } - - public PopupDateField(String caption, Date value) { - super(caption, value); - } - - public PopupDateField(String caption, Property dataSource) { - super(caption, dataSource); - } - - public PopupDateField(String caption) { - super(caption); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - - if (inputPrompt != null) { - target.addAttribute("prompt", inputPrompt); - } - } - - /** - * Gets the current input prompt. - * - * @see #setInputPrompt(String) - * @return the current input prompt, or null if not enabled - */ - public String getInputPrompt() { - return inputPrompt; - } - - /** - * Sets the input prompt - a textual prompt that is displayed when the field - * would otherwise be empty, to prompt the user for input. - * - * @param inputPrompt - */ - public void setInputPrompt(String inputPrompt) { - this.inputPrompt = inputPrompt; - requestRepaint(); - } - -} diff --git a/src/com/vaadin/ui/PopupView.java b/src/com/vaadin/ui/PopupView.java deleted file mode 100644 index 766181b50f..0000000000 --- a/src/com/vaadin/ui/PopupView.java +++ /dev/null @@ -1,453 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Iterator; -import java.util.Map; - -import com.vaadin.terminal.LegacyPaint; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; - -/** - * - * A component for displaying a two different views to data. The minimized view - * is normally used to render the component, and when it is clicked the full - * view is displayed on a popup. The inner class {@link PopupView.Content} is - * used to deliver contents to this component. - * - * @author Vaadin Ltd. - */ -@SuppressWarnings("serial") -public class PopupView extends AbstractComponentContainer implements - Vaadin6Component { - - private Content content; - private boolean hideOnMouseOut; - private Component visibleComponent; - - private static final Method POPUP_VISIBILITY_METHOD; - static { - try { - POPUP_VISIBILITY_METHOD = PopupVisibilityListener.class - .getDeclaredMethod("popupVisibilityChange", - new Class[] { PopupVisibilityEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in PopupView"); - } - } - - /** - * Iterator for the visible components (zero or one components), used by - * {@link PopupView#getComponentIterator()}. - */ - private static class SingleComponentIterator implements - Iterator<Component>, Serializable { - - private final Component component; - private boolean first; - - public SingleComponentIterator(Component component) { - this.component = component; - first = (component == null); - } - - @Override - public boolean hasNext() { - return !first; - } - - @Override - public Component next() { - if (!first) { - first = true; - return component; - } else { - return null; - } - } - - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - } - - /* Constructors */ - - /** - * A simple way to create a PopupPanel. Note that the minimal representation - * may not be dynamically updated, in order to achieve this create your own - * Content object and use {@link PopupView#PopupView(Content)}. - * - * @param small - * the minimal textual representation as HTML - * @param large - * the full, Component-type representation - */ - public PopupView(final java.lang.String small, final Component large) { - this(new PopupView.Content() { - @Override - public java.lang.String getMinimizedValueAsHTML() { - return small; - } - - @Override - public Component getPopupComponent() { - return large; - } - }); - - } - - /** - * Creates a PopupView through the PopupView.Content interface. This allows - * the creator to dynamically change the contents of the PopupView. - * - * @param content - * the PopupView.Content that contains the information for this - */ - public PopupView(PopupView.Content content) { - super(); - hideOnMouseOut = true; - setContent(content); - } - - /** - * This method will replace the current content of the panel with a new one. - * - * @param newContent - * PopupView.Content object containing new information for the - * PopupView - * @throws IllegalArgumentException - * if the method is passed a null value, or if one of the - * content methods returns null - */ - public void setContent(PopupView.Content newContent) - throws IllegalArgumentException { - if (newContent == null) { - throw new IllegalArgumentException("Content must not be null"); - } - content = newContent; - requestRepaint(); - } - - /** - * Returns the content-package for this PopupView. - * - * @return the PopupView.Content for this object or null - */ - public PopupView.Content getContent() { - return content; - } - - /** - * @deprecated Use {@link #setPopupVisible()} instead. - */ - @Deprecated - public void setPopupVisibility(boolean visible) { - setPopupVisible(visible); - } - - /** - * @deprecated Use {@link #isPopupVisible()} instead. - */ - @Deprecated - public boolean getPopupVisibility() { - return isPopupVisible(); - } - - /** - * Set the visibility of the popup. Does not hide the minimal - * representation. - * - * @param visible - */ - public void setPopupVisible(boolean visible) { - if (isPopupVisible() != visible) { - if (visible) { - visibleComponent = content.getPopupComponent(); - if (visibleComponent == null) { - throw new java.lang.IllegalStateException( - "PopupView.Content did not return Component to set visible"); - } - super.addComponent(visibleComponent); - } else { - super.removeComponent(visibleComponent); - visibleComponent = null; - } - fireEvent(new PopupVisibilityEvent(this)); - requestRepaint(); - } - } - - /** - * Return whether the popup is visible. - * - * @return true if the popup is showing - */ - public boolean isPopupVisible() { - return visibleComponent != null; - } - - /** - * Check if this popup will be hidden when the user takes the mouse cursor - * out of the popup area. - * - * @return true if the popup is hidden on mouse out, false otherwise - */ - public boolean isHideOnMouseOut() { - return hideOnMouseOut; - } - - /** - * Should the popup automatically hide when the user takes the mouse cursor - * out of the popup area? If this is false, the user must click outside the - * popup to close it. The default is true. - * - * @param hideOnMouseOut - * - */ - public void setHideOnMouseOut(boolean hideOnMouseOut) { - this.hideOnMouseOut = hideOnMouseOut; - } - - /* - * Methods inherited from AbstractComponentContainer. These are unnecessary - * (but mandatory). Most of them are not supported in this implementation. - */ - - /** - * This class only contains other components when the popup is showing. - * - * @see com.vaadin.ui.ComponentContainer#getComponentIterator() - */ - @Override - public Iterator<Component> getComponentIterator() { - return new SingleComponentIterator(visibleComponent); - } - - /** - * Gets the number of contained components. Consistent with the iterator - * returned by {@link #getComponentIterator()}. - * - * @return the number of contained components (zero or one) - */ - @Override - public int getComponentCount() { - return (visibleComponent != null ? 1 : 0); - } - - /** - * Not supported in this implementation. - * - * @see com.vaadin.ui.AbstractComponentContainer#removeAllComponents() - * @throws UnsupportedOperationException - */ - @Override - public void removeAllComponents() { - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this implementation. - * - * @see com.vaadin.ui.AbstractComponentContainer#moveComponentsFrom(com.vaadin.ui.ComponentContainer) - * @throws UnsupportedOperationException - */ - @Override - public void moveComponentsFrom(ComponentContainer source) - throws UnsupportedOperationException { - - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this implementation. - * - * @see com.vaadin.ui.AbstractComponentContainer#addComponent(com.vaadin.ui.Component) - * @throws UnsupportedOperationException - */ - @Override - public void addComponent(Component c) throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - - } - - /** - * Not supported in this implementation. - * - * @see com.vaadin.ui.ComponentContainer#replaceComponent(com.vaadin.ui.Component, - * com.vaadin.ui.Component) - * @throws UnsupportedOperationException - */ - @Override - public void replaceComponent(Component oldComponent, Component newComponent) - throws UnsupportedOperationException { - - throw new UnsupportedOperationException(); - } - - /** - * Not supported in this implementation - * - * @see com.vaadin.ui.AbstractComponentContainer#removeComponent(com.vaadin.ui.Component) - */ - @Override - public void removeComponent(Component c) - throws UnsupportedOperationException { - throw new UnsupportedOperationException(); - - } - - /* - * Methods for server-client communications. - */ - - /** - * Paint (serialize) the component for the client. - * - * @see com.vaadin.ui.AbstractComponent#paintContent(com.vaadin.terminal.PaintTarget) - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - String html = content.getMinimizedValueAsHTML(); - if (html == null) { - html = ""; - } - target.addAttribute("html", html); - target.addAttribute("hideOnMouseOut", hideOnMouseOut); - - // Only paint component to client if we know that the popup is showing - if (isPopupVisible()) { - target.startTag("popupComponent"); - LegacyPaint.paint(visibleComponent, target); - target.endTag("popupComponent"); - } - - target.addVariable(this, "popupVisibility", isPopupVisible()); - } - - /** - * Deserialize changes received from client. - * - * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, - * java.util.Map) - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - if (variables.containsKey("popupVisibility")) { - setPopupVisible(((Boolean) variables.get("popupVisibility")) - .booleanValue()); - } - } - - /** - * Used to deliver customized content-packages to the PopupView. These are - * dynamically loaded when they are redrawn. The user must take care that - * neither of these methods ever return null. - */ - public interface Content extends Serializable { - - /** - * This should return a small view of the full data. - * - * @return value in HTML format - */ - public String getMinimizedValueAsHTML(); - - /** - * This should return the full Component representing the data - * - * @return a Component for the value - */ - public Component getPopupComponent(); - } - - /** - * Add a listener that is called whenever the visibility of the popup is - * changed. - * - * @param listener - * the listener to add - * @see PopupVisibilityListener - * @see PopupVisibilityEvent - * @see #removeListener(PopupVisibilityListener) - * - */ - public void addListener(PopupVisibilityListener listener) { - addListener(PopupVisibilityEvent.class, listener, - POPUP_VISIBILITY_METHOD); - } - - /** - * Removes a previously added listener, so that it no longer receives events - * when the visibility of the popup changes. - * - * @param listener - * the listener to remove - * @see PopupVisibilityListener - * @see #addListener(PopupVisibilityListener) - */ - public void removeListener(PopupVisibilityListener listener) { - removeListener(PopupVisibilityEvent.class, listener, - POPUP_VISIBILITY_METHOD); - } - - /** - * This event is received by the PopupVisibilityListeners when the - * visibility of the popup changes. You can get the new visibility directly - * with {@link #isPopupVisible()}, or get the PopupView that produced the - * event with {@link #getPopupView()}. - * - */ - public class PopupVisibilityEvent extends Event { - - public PopupVisibilityEvent(PopupView source) { - super(source); - } - - /** - * Get the PopupView instance that is the source of this event. - * - * @return the source PopupView - */ - public PopupView getPopupView() { - return (PopupView) getSource(); - } - - /** - * Returns the current visibility of the popup. - * - * @return true if the popup is visible - */ - public boolean isPopupVisible() { - return getPopupView().isPopupVisible(); - } - } - - /** - * Defines a listener that can receive a PopupVisibilityEvent when the - * visibility of the popup changes. - * - */ - public interface PopupVisibilityListener extends Serializable { - /** - * Pass to {@link PopupView#PopupVisibilityEvent} to start listening for - * popup visibility changes. - * - * @param event - * the event - * - * @see {@link PopupVisibilityEvent} - * @see {@link PopupView#addListener(PopupVisibilityListener)} - */ - public void popupVisibilityChange(PopupVisibilityEvent event); - } -} diff --git a/src/com/vaadin/ui/ProgressIndicator.java b/src/com/vaadin/ui/ProgressIndicator.java deleted file mode 100644 index fef54a267c..0000000000 --- a/src/com/vaadin/ui/ProgressIndicator.java +++ /dev/null @@ -1,257 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Map; - -import com.vaadin.data.Property; -import com.vaadin.data.util.ObjectProperty; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; - -/** - * <code>ProgressIndicator</code> is component that shows user state of a - * process (like long computing or file upload) - * - * <code>ProgressIndicator</code> has two mainmodes. One for indeterminate - * processes and other (default) for processes which progress can be measured - * - * May view an other property that indicates progress 0...1 - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 4 - */ -@SuppressWarnings("serial") -public class ProgressIndicator extends AbstractField<Number> implements - Property.Viewer, Property.ValueChangeListener, Vaadin6Component { - - /** - * Content mode, where the label contains only plain text. The getValue() - * result is coded to XML when painting. - */ - public static final int CONTENT_TEXT = 0; - - /** - * Content mode, where the label contains preformatted text. - */ - public static final int CONTENT_PREFORMATTED = 1; - - private boolean indeterminate = false; - - private Property dataSource; - - private int pollingInterval = 1000; - - /** - * Creates an a new ProgressIndicator. - */ - public ProgressIndicator() { - setPropertyDataSource(new ObjectProperty<Float>(new Float(0), - Float.class)); - } - - /** - * Creates a new instance of ProgressIndicator with given state. - * - * @param value - */ - public ProgressIndicator(Float value) { - setPropertyDataSource(new ObjectProperty<Float>(value, Float.class)); - } - - /** - * Creates a new instance of ProgressIndicator with stae read from given - * datasource. - * - * @param contentSource - */ - public ProgressIndicator(Property contentSource) { - setPropertyDataSource(contentSource); - } - - /** - * Sets the component to read-only. Readonly is not used in - * ProgressIndicator. - * - * @param readOnly - * True to enable read-only mode, False to disable it. - */ - @Override - public void setReadOnly(boolean readOnly) { - if (dataSource == null) { - throw new IllegalStateException("Datasource must be se"); - } - dataSource.setReadOnly(readOnly); - } - - /** - * Is the component read-only ? Readonly is not used in ProgressIndicator - - * this returns allways false. - * - * @return True if the component is in read only mode. - */ - @Override - public boolean isReadOnly() { - if (dataSource == null) { - throw new IllegalStateException("Datasource must be se"); - } - return dataSource.isReadOnly(); - } - - /** - * Paints the content of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the Paint Operation fails. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - target.addAttribute("indeterminate", indeterminate); - target.addAttribute("pollinginterval", pollingInterval); - target.addAttribute("state", getValue().toString()); - } - - /** - * Gets the value of the ProgressIndicator. Value of the ProgressIndicator - * is Float between 0 and 1. - * - * @return the Value of the ProgressIndicator. - * @see com.vaadin.ui.AbstractField#getValue() - */ - @Override - public Number getValue() { - if (dataSource == null) { - throw new IllegalStateException("Datasource must be set"); - } - // TODO conversions to eliminate cast - return (Number) dataSource.getValue(); - } - - /** - * Sets the value of the ProgressIndicator. Value of the ProgressIndicator - * is the Float between 0 and 1. - * - * @param newValue - * the New value of the ProgressIndicator. - * @see com.vaadin.ui.AbstractField#setValue() - */ - @Override - public void setValue(Object newValue) { - if (dataSource == null) { - throw new IllegalStateException("Datasource must be set"); - } - dataSource.setValue(newValue); - } - - /** - * @see com.vaadin.ui.AbstractField#getType() - */ - @Override - public Class<? extends Number> getType() { - if (dataSource == null) { - throw new IllegalStateException("Datasource must be set"); - } - return dataSource.getType(); - } - - /** - * Gets the viewing data-source property. - * - * @return the datasource. - * @see com.vaadin.ui.AbstractField#getPropertyDataSource() - */ - @Override - public Property getPropertyDataSource() { - return dataSource; - } - - /** - * Sets the property as data-source for viewing. - * - * @param newDataSource - * the new data source. - * @see com.vaadin.ui.AbstractField#setPropertyDataSource(com.vaadin.data.Property) - */ - @Override - public void setPropertyDataSource(Property newDataSource) { - // Stops listening the old data source changes - if (dataSource != null - && Property.ValueChangeNotifier.class - .isAssignableFrom(dataSource.getClass())) { - ((Property.ValueChangeNotifier) dataSource).removeListener(this); - } - - // Sets the new data source - dataSource = newDataSource; - - // Listens the new data source if possible - if (dataSource != null - && Property.ValueChangeNotifier.class - .isAssignableFrom(dataSource.getClass())) { - ((Property.ValueChangeNotifier) dataSource).addListener(this); - } - } - - /** - * Gets the mode of ProgressIndicator. - * - * @return true if in indeterminate mode. - */ - public boolean getContentMode() { - return indeterminate; - } - - /** - * Sets wheter or not the ProgressIndicator is indeterminate. - * - * @param newValue - * true to set to indeterminate mode. - */ - public void setIndeterminate(boolean newValue) { - indeterminate = newValue; - requestRepaint(); - } - - /** - * Gets whether or not the ProgressIndicator is indeterminate. - * - * @return true to set to indeterminate mode. - */ - public boolean isIndeterminate() { - return indeterminate; - } - - /** - * Sets the interval that component checks for progress. - * - * @param newValue - * the interval in milliseconds. - */ - public void setPollingInterval(int newValue) { - pollingInterval = newValue; - requestRepaint(); - } - - /** - * Gets the interval that component checks for progress. - * - * @return the interval in milliseconds. - */ - public int getPollingInterval() { - return pollingInterval; - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // TODO Remove once Vaadin6Component is no longer implemented - - } - -} diff --git a/src/com/vaadin/ui/RichTextArea.java b/src/com/vaadin/ui/RichTextArea.java deleted file mode 100644 index cec952926b..0000000000 --- a/src/com/vaadin/ui/RichTextArea.java +++ /dev/null @@ -1,344 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.text.Format; -import java.util.Map; - -import com.vaadin.data.Property; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; - -/** - * A simple RichTextArea to edit HTML format text. - * - * Note, that using {@link TextField#setMaxLength(int)} method in - * {@link RichTextArea} may produce unexpected results as formatting is counted - * into length of field. - */ -public class RichTextArea extends AbstractField<String> implements - Vaadin6Component { - - /** - * Value formatter used to format the string contents. - */ - @Deprecated - private Format format; - - /** - * Null representation. - */ - private String nullRepresentation = "null"; - - /** - * Is setting to null from non-null value allowed by setting with null - * representation . - */ - private boolean nullSettingAllowed = false; - - /** - * Temporary flag that indicates all content will be selected after the next - * paint. Reset to false after painted. - */ - private boolean selectAll = false; - - /** - * Constructs an empty <code>RichTextArea</code> with no caption. - */ - public RichTextArea() { - setValue(""); - } - - /** - * - * Constructs an empty <code>RichTextArea</code> with the given caption. - * - * @param caption - * the caption for the editor. - */ - public RichTextArea(String caption) { - this(); - setCaption(caption); - } - - /** - * Constructs a new <code>RichTextArea</code> that's bound to the specified - * <code>Property</code> and has no caption. - * - * @param dataSource - * the data source for the editor value - */ - public RichTextArea(Property dataSource) { - setPropertyDataSource(dataSource); - } - - /** - * Constructs a new <code>RichTextArea</code> that's bound to the specified - * <code>Property</code> and has the given caption. - * - * @param caption - * the caption for the editor. - * @param dataSource - * the data source for the editor value - */ - public RichTextArea(String caption, Property dataSource) { - this(dataSource); - setCaption(caption); - } - - /** - * Constructs a new <code>RichTextArea</code> with the given caption and - * initial text contents. - * - * @param caption - * the caption for the editor. - * @param value - * the initial text content of the editor. - */ - public RichTextArea(String caption, String value) { - setValue(value); - setCaption(caption); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (selectAll) { - target.addAttribute("selectAll", true); - selectAll = false; - } - - // Adds the content as variable - String value = getFormattedValue(); - if (value == null) { - value = getNullRepresentation(); - } - if (value == null) { - throw new IllegalStateException( - "Null values are not allowed if the null-representation is null"); - } - target.addVariable(this, "text", value); - - } - - @Override - public void setReadOnly(boolean readOnly) { - super.setReadOnly(readOnly); - // IE6 cannot support multi-classname selectors properly - // TODO Can be optimized now that support for I6 is dropped - if (readOnly) { - addStyleName("v-richtextarea-readonly"); - } else { - removeStyleName("v-richtextarea-readonly"); - } - } - - /** - * Selects all text in the rich text area. As a side effect, focuses the - * rich text area. - * - * @since 6.5 - */ - public void selectAll() { - /* - * Set selection range functionality is currently being - * planned/developed for GWT RTA. Only selecting all is currently - * supported. Consider moving selectAll and other selection related - * functions to AbstractTextField at that point to share the - * implementation. Some third party components extending - * AbstractTextField might however not want to support them. - */ - selectAll = true; - focus(); - requestRepaint(); - } - - /** - * Gets the formatted string value. Sets the field value by using the - * assigned Format. - * - * @return the Formatted value. - * @see #setFormat(Format) - * @see Format - * @deprecated - */ - @Deprecated - protected String getFormattedValue() { - Object v = getValue(); - if (v == null) { - return null; - } - return v.toString(); - } - - @Override - public String getValue() { - String v = super.getValue(); - if (format == null || v == null) { - return v; - } - try { - return format.format(v); - } catch (final IllegalArgumentException e) { - return v; - } - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // Sets the text - if (variables.containsKey("text") && !isReadOnly()) { - - // Only do the setting if the string representation of the value - // has been updated - String newValue = (String) variables.get("text"); - - final String oldValue = getFormattedValue(); - if (newValue != null - && (oldValue == null || isNullSettingAllowed()) - && newValue.equals(getNullRepresentation())) { - newValue = null; - } - if (newValue != oldValue - && (newValue == null || !newValue.equals(oldValue))) { - boolean wasModified = isModified(); - setValue(newValue, true); - - // If the modified status changes, or if we have a formatter, - // repaint is needed after all. - if (format != null || wasModified != isModified()) { - requestRepaint(); - } - } - } - - } - - @Override - public Class<String> getType() { - return String.class; - } - - /** - * Gets the null-string representation. - * - * <p> - * The null-valued strings are represented on the user interface by - * replacing the null value with this string. If the null representation is - * set null (not 'null' string), painting null value throws exception. - * </p> - * - * <p> - * The default value is string 'null'. - * </p> - * - * @return the String Textual representation for null strings. - * @see TextField#isNullSettingAllowed() - */ - public String getNullRepresentation() { - return nullRepresentation; - } - - /** - * Is setting nulls with null-string representation allowed. - * - * <p> - * If this property is true, writing null-representation string to text - * field always sets the field value to real null. If this property is - * false, null setting is not made, but the null values are maintained. - * Maintenance of null-values is made by only converting the textfield - * contents to real null, if the text field matches the null-string - * representation and the current value of the field is null. - * </p> - * - * <p> - * By default this setting is false - * </p> - * - * @return boolean Should the null-string represenation be always converted - * to null-values. - * @see TextField#getNullRepresentation() - */ - public boolean isNullSettingAllowed() { - return nullSettingAllowed; - } - - /** - * Sets the null-string representation. - * - * <p> - * The null-valued strings are represented on the user interface by - * replacing the null value with this string. If the null representation is - * set null (not 'null' string), painting null value throws exception. - * </p> - * - * <p> - * The default value is string 'null' - * </p> - * - * @param nullRepresentation - * Textual representation for null strings. - * @see TextField#setNullSettingAllowed(boolean) - */ - public void setNullRepresentation(String nullRepresentation) { - this.nullRepresentation = nullRepresentation; - } - - /** - * Sets the null conversion mode. - * - * <p> - * If this property is true, writing null-representation string to text - * field always sets the field value to real null. If this property is - * false, null setting is not made, but the null values are maintained. - * Maintenance of null-values is made by only converting the textfield - * contents to real null, if the text field matches the null-string - * representation and the current value of the field is null. - * </p> - * - * <p> - * By default this setting is false. - * </p> - * - * @param nullSettingAllowed - * Should the null-string represenation be always converted to - * null-values. - * @see TextField#getNullRepresentation() - */ - public void setNullSettingAllowed(boolean nullSettingAllowed) { - this.nullSettingAllowed = nullSettingAllowed; - } - - /** - * Gets the value formatter of TextField. - * - * @return the Format used to format the value. - * @deprecated replaced by {@link com.vaadin.data.util.PropertyFormatter} - */ - @Deprecated - public Format getFormat() { - return format; - } - - /** - * Gets the value formatter of TextField. - * - * @param format - * the Format used to format the value. Null disables the - * formatting. - * @deprecated replaced by {@link com.vaadin.data.util.PropertyFormatter} - */ - @Deprecated - public void setFormat(Format format) { - this.format = format; - requestRepaint(); - } - - @Override - protected boolean isEmpty() { - return super.isEmpty() || getValue().length() == 0; - } - -} diff --git a/src/com/vaadin/ui/Root.java b/src/com/vaadin/ui/Root.java deleted file mode 100644 index bd4842632b..0000000000 --- a/src/com/vaadin/ui/Root.java +++ /dev/null @@ -1,1227 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; - -import com.vaadin.Application; -import com.vaadin.annotations.EagerInit; -import com.vaadin.event.Action; -import com.vaadin.event.Action.Handler; -import com.vaadin.event.ActionManager; -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.event.MouseEvents.ClickListener; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.root.RootServerRpc; -import com.vaadin.shared.ui.root.RootState; -import com.vaadin.terminal.Page; -import com.vaadin.terminal.Page.BrowserWindowResizeEvent; -import com.vaadin.terminal.Page.BrowserWindowResizeListener; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.WrappedRequest; -import com.vaadin.terminal.WrappedRequest.BrowserDetails; -import com.vaadin.terminal.gwt.client.ui.root.VRoot; -import com.vaadin.ui.Window.CloseListener; - -/** - * The topmost component in any component hierarchy. There is one root for every - * Vaadin instance in a browser window. A root may either represent an entire - * browser window (or tab) or some part of a html page where a Vaadin - * application is embedded. - * <p> - * The root is the server side entry point for various client side features that - * are not represented as components added to a layout, e.g notifications, sub - * windows, and executing javascript in the browser. - * </p> - * <p> - * When a new application instance is needed, typically because the user opens - * the application in a browser window, - * {@link Application#gerRoot(WrappedRequest)} is invoked to get a root. That - * method does by default create a root according to the - * {@value Application#ROOT_PARAMETER} parameter from web.xml. - * </p> - * <p> - * After a root has been created by the application, it is initialized using - * {@link #init(WrappedRequest)}. This method is intended to be overridden by - * the developer to add components to the user interface and initialize - * non-component functionality. The component hierarchy is initialized by - * passing a {@link ComponentContainer} with the main layout of the view to - * {@link #setContent(ComponentContainer)}. - * </p> - * <p> - * If a {@link EagerInit} annotation is present on a class extending - * <code>Root</code>, the framework will use a faster initialization method - * which will not ensure that {@link BrowserDetails} are present in the - * {@link WrappedRequest} passed to the init method. - * </p> - * - * @see #init(WrappedRequest) - * @see Application#getRoot(WrappedRequest) - * - * @since 7.0 - */ -public abstract class Root extends AbstractComponentContainer implements - Action.Container, Action.Notifier, Vaadin6Component { - - /** - * Helper class to emulate the main window from Vaadin 6 using roots. This - * class should be used in the same way as Window used as a browser level - * window in Vaadin 6 with {@link com.vaadin.Application.LegacyApplication} - */ - @Deprecated - @EagerInit - public static class LegacyWindow extends Root { - private String name; - - /** - * Create a new legacy window - */ - public LegacyWindow() { - super(); - } - - /** - * Creates a new legacy window with the given caption - * - * @param caption - * the caption of the window - */ - public LegacyWindow(String caption) { - super(caption); - } - - /** - * Creates a legacy window with the given caption and content layout - * - * @param caption - * @param content - */ - public LegacyWindow(String caption, ComponentContainer content) { - super(caption, content); - } - - @Override - protected void init(WrappedRequest request) { - // Just empty - } - - /** - * Gets the unique name of the window. The name of the window is used to - * uniquely identify it. - * <p> - * The name also determines the URL that can be used for direct access - * to a window. All windows can be accessed through - * {@code http://host:port/app/win} where {@code http://host:port/app} - * is the application URL (as returned by {@link Application#getURL()} - * and {@code win} is the window name. - * </p> - * <p> - * Note! Portlets do not support direct window access through URLs. - * </p> - * - * @return the Name of the Window. - */ - public String getName() { - return name; - } - - /** - * Sets the unique name of the window. The name of the window is used to - * uniquely identify it inside the application. - * <p> - * The name also determines the URL that can be used for direct access - * to a window. All windows can be accessed through - * {@code http://host:port/app/win} where {@code http://host:port/app} - * is the application URL (as returned by {@link Application#getURL()} - * and {@code win} is the window name. - * </p> - * <p> - * This method can only be called before the window is added to an - * application. - * <p> - * Note! Portlets do not support direct window access through URLs. - * </p> - * - * @param name - * the new name for the window or null if the application - * should automatically assign a name to it - * @throws IllegalStateException - * if the window is attached to an application - */ - public void setName(String name) { - this.name = name; - // The name can not be changed in application - if (getApplication() != null) { - throw new IllegalStateException( - "Window name can not be changed while " - + "the window is in application"); - } - - } - - /** - * Gets the full URL of the window. The returned URL is window specific - * and can be used to directly refer to the window. - * <p> - * Note! This method can not be used for portlets. - * </p> - * - * @return the URL of the window or null if the window is not attached - * to an application - */ - public URL getURL() { - Application application = getApplication(); - if (application == null) { - return null; - } - - try { - return new URL(application.getURL(), getName() + "/"); - } catch (MalformedURLException e) { - throw new RuntimeException( - "Internal problem getting window URL, please report"); - } - } - - /** - * Opens the given resource in this root. The contents of this Root is - * replaced by the {@code Resource}. - * - * @param resource - * the resource to show in this root - * - * @deprecated As of 7.0, use getPage().open instead - */ - @Deprecated - public void open(Resource resource) { - getPage().open(resource); - } - - /* ********************************************************************* */ - - /** - * Opens the given resource in a window with the given name. - * <p> - * The supplied {@code windowName} is used as the target name in a - * window.open call in the client. This means that special values such - * as "_blank", "_self", "_top", "_parent" have special meaning. An - * empty or <code>null</code> window name is also a special case. - * </p> - * <p> - * "", null and "_self" as {@code windowName} all causes the resource to - * be opened in the current window, replacing any old contents. For - * downloadable content you should avoid "_self" as "_self" causes the - * client to skip rendering of any other changes as it considers them - * irrelevant (the page will be replaced by the resource). This can - * speed up the opening of a resource, but it might also put the client - * side into an inconsistent state if the window content is not - * completely replaced e.g., if the resource is downloaded instead of - * displayed in the browser. - * </p> - * <p> - * "_blank" as {@code windowName} causes the resource to always be - * opened in a new window or tab (depends on the browser and browser - * settings). - * </p> - * <p> - * "_top" and "_parent" as {@code windowName} works as specified by the - * HTML standard. - * </p> - * <p> - * Any other {@code windowName} will open the resource in a window with - * that name, either by opening a new window/tab in the browser or by - * replacing the contents of an existing window with that name. - * </p> - * - * @param resource - * the resource. - * @param windowName - * the name of the window. - * @deprecated As of 7.0, use getPage().open instead - */ - @Deprecated - public void open(Resource resource, String windowName) { - getPage().open(resource, windowName); - } - - /** - * Opens the given resource in a window with the given size, border and - * name. For more information on the meaning of {@code windowName}, see - * {@link #open(Resource, String)}. - * - * @param resource - * the resource. - * @param windowName - * the name of the window. - * @param width - * the width of the window in pixels - * @param height - * the height of the window in pixels - * @param border - * the border style of the window. See {@link #BORDER_NONE - * Window.BORDER_* constants} - * @deprecated As of 7.0, use getPage().open instead - */ - @Deprecated - public void open(Resource resource, String windowName, int width, - int height, int border) { - getPage().open(resource, windowName, width, height, border); - } - - /** - * Adds a new {@link BrowserWindowResizeListener} to this root. The - * listener will be notified whenever the browser window within which - * this root resides is resized. - * - * @param resizeListener - * the listener to add - * - * @see BrowserWindowResizeListener#browserWindowResized(BrowserWindowResizeEvent) - * @see #setResizeLazy(boolean) - * - * @deprecated As of 7.0, use the similarly named api in Page instead - */ - @Deprecated - public void addListener(BrowserWindowResizeListener resizeListener) { - getPage().addListener(resizeListener); - } - - /** - * Removes a {@link BrowserWindowResizeListener} from this root. The - * listener will no longer be notified when the browser window is - * resized. - * - * @param resizeListener - * the listener to remove - * @deprecated As of 7.0, use the similarly named api in Page instead - */ - @Deprecated - public void removeListener(BrowserWindowResizeListener resizeListener) { - getPage().removeListener(resizeListener); - } - - /** - * Gets the last known height of the browser window in which this root - * resides. - * - * @return the browser window height in pixels - * @deprecated As of 7.0, use the similarly named api in Page instead - */ - @Deprecated - public int getBrowserWindowHeight() { - return getPage().getBrowserWindowHeight(); - } - - /** - * Gets the last known width of the browser window in which this root - * resides. - * - * @return the browser window width in pixels - * - * @deprecated As of 7.0, use the similarly named api in Page instead - */ - @Deprecated - public int getBrowserWindowWidth() { - return getPage().getBrowserWindowWidth(); - } - - /** - * Executes JavaScript in this window. - * - * <p> - * This method allows one to inject javascript from the server to - * client. A client implementation is not required to implement this - * functionality, but currently all web-based clients do implement this. - * </p> - * - * <p> - * Executing javascript this way often leads to cross-browser - * compatibility issues and regressions that are hard to resolve. Use of - * this method should be avoided and instead it is recommended to create - * new widgets with GWT. For more info on creating own, reusable - * client-side widgets in Java, read the corresponding chapter in Book - * of Vaadin. - * </p> - * - * @param script - * JavaScript snippet that will be executed. - * - * @deprecated as of 7.0, use JavaScript.getCurrent().execute(String) - * instead - */ - @Deprecated - public void executeJavaScript(String script) { - getPage().getJavaScript().execute(script); - } - - @Override - public void setCaption(String caption) { - // Override to provide backwards compatibility - getState().setCaption(caption); - getPage().setTitle(caption); - } - - } - - /** - * The application to which this root belongs - */ - private Application application; - - /** - * List of windows in this root. - */ - private final LinkedHashSet<Window> windows = new LinkedHashSet<Window>(); - - /** - * The component that should be scrolled into view after the next repaint. - * Null if nothing should be scrolled into view. - */ - private Component scrollIntoView; - - /** - * The id of this root, used to find the server side instance of the root - * form which a request originates. A negative value indicates that the root - * id has not yet been assigned by the Application. - * - * @see Application#nextRootId - */ - private int rootId = -1; - - /** - * Keeps track of the Actions added to this component, and manages the - * painting and handling as well. - */ - protected ActionManager actionManager; - - /** - * Thread local for keeping track of the current root. - */ - private static final ThreadLocal<Root> currentRoot = new ThreadLocal<Root>(); - - /** Identifies the click event */ - private static final String CLICK_EVENT_ID = VRoot.CLICK_EVENT_ID; - - private ConnectorTracker connectorTracker = new ConnectorTracker(this); - - private Page page = new Page(this); - - private RootServerRpc rpc = new RootServerRpc() { - @Override - public void click(MouseEventDetails mouseDetails) { - fireEvent(new ClickEvent(Root.this, mouseDetails)); - } - }; - - /** - * Creates a new empty root without a caption. This root will have a - * {@link VerticalLayout} with margins enabled as its content. - */ - public Root() { - this((ComponentContainer) null); - } - - /** - * Creates a new root with the given component container as its content. - * - * @param content - * the content container to use as this roots content. - * - * @see #setContent(ComponentContainer) - */ - public Root(ComponentContainer content) { - registerRpc(rpc); - setSizeFull(); - setContent(content); - } - - /** - * Creates a new empty root with the given caption. This root will have a - * {@link VerticalLayout} with margins enabled as its content. - * - * @param caption - * the caption of the root, used as the page title if there's - * nothing but the application on the web page - * - * @see #setCaption(String) - */ - public Root(String caption) { - this((ComponentContainer) null); - setCaption(caption); - } - - /** - * Creates a new root with the given caption and content. - * - * @param caption - * the caption of the root, used as the page title if there's - * nothing but the application on the web page - * @param content - * the content container to use as this roots content. - * - * @see #setContent(ComponentContainer) - * @see #setCaption(String) - */ - public Root(String caption, ComponentContainer content) { - this(content); - setCaption(caption); - } - - @Override - public RootState getState() { - return (RootState) super.getState(); - } - - @Override - public Class<? extends RootState> getStateType() { - // This is a workaround for a problem with creating the correct state - // object during build - return RootState.class; - } - - /** - * Overridden to return a value instead of referring to the parent. - * - * @return this root - * - * @see com.vaadin.ui.AbstractComponent#getRoot() - */ - @Override - public Root getRoot() { - return this; - } - - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - throw new UnsupportedOperationException(); - } - - @Override - public Application getApplication() { - return application; - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - page.paintContent(target); - - if (scrollIntoView != null) { - target.addAttribute("scrollTo", scrollIntoView); - scrollIntoView = null; - } - - if (pendingFocus != null) { - // ensure focused component is still attached to this main window - if (pendingFocus.getRoot() == this - || (pendingFocus.getRoot() != null && pendingFocus - .getRoot().getParent() == this)) { - target.addAttribute("focused", pendingFocus); - } - pendingFocus = null; - } - - if (actionManager != null) { - actionManager.paintActions(null, target); - } - - if (isResizeLazy()) { - target.addAttribute(VRoot.RESIZE_LAZY, true); - } - } - - /** - * Fire a click event to all click listeners. - * - * @param object - * The raw "value" of the variable change from the client side. - */ - private void fireClick(Map<String, Object> parameters) { - MouseEventDetails mouseDetails = MouseEventDetails - .deSerialize((String) parameters.get("mouseDetails")); - fireEvent(new ClickEvent(this, mouseDetails)); - } - - @Override - @SuppressWarnings("unchecked") - public void changeVariables(Object source, Map<String, Object> variables) { - if (variables.containsKey(CLICK_EVENT_ID)) { - fireClick((Map<String, Object>) variables.get(CLICK_EVENT_ID)); - } - - // Actions - if (actionManager != null) { - actionManager.handleActions(variables, this); - } - - if (variables.containsKey(VRoot.FRAGMENT_VARIABLE)) { - String fragment = (String) variables.get(VRoot.FRAGMENT_VARIABLE); - getPage().setFragment(fragment, true); - } - - if (variables.containsKey("height") || variables.containsKey("width")) { - getPage().setBrowserWindowSize((Integer) variables.get("width"), - (Integer) variables.get("height")); - } - - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.ComponentContainer#getComponentIterator() - */ - @Override - public Iterator<Component> getComponentIterator() { - // TODO could directly create some kind of combined iterator instead of - // creating a new ArrayList - ArrayList<Component> components = new ArrayList<Component>(); - - if (getContent() != null) { - components.add(getContent()); - } - - components.addAll(windows); - - return components.iterator(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.ComponentContainer#getComponentCount() - */ - @Override - public int getComponentCount() { - return windows.size() + (getContent() == null ? 0 : 1); - } - - /** - * Sets the application to which this root is assigned. It is not legal to - * change the application once it has been set nor to set a - * <code>null</code> application. - * <p> - * This method is mainly intended for internal use by the framework. - * </p> - * - * @param application - * the application to set - * - * @throws IllegalStateException - * if the application has already been set - * - * @see #getApplication() - */ - public void setApplication(Application application) { - if ((application == null) == (this.application == null)) { - throw new IllegalStateException("Application has already been set"); - } else { - this.application = application; - } - - if (application != null) { - attach(); - } else { - detach(); - } - } - - /** - * Sets the id of this root within its application. The root id is used to - * route requests to the right root. - * <p> - * This method is mainly intended for internal use by the framework. - * </p> - * - * @param rootId - * the id of this root - * - * @throws IllegalStateException - * if the root id has already been set - * - * @see #getRootId() - */ - public void setRootId(int rootId) { - if (this.rootId != -1) { - throw new IllegalStateException("Root id has already been defined"); - } - this.rootId = rootId; - } - - /** - * Gets the id of the root, used to identify this root within its - * application when processing requests. The root id should be present in - * every request to the server that originates from this root. - * {@link Application#getRootForRequest(WrappedRequest)} uses this id to - * find the route to which the request belongs. - * - * @return - */ - public int getRootId() { - return rootId; - } - - /** - * Adds a window as a subwindow inside this root. To open a new browser - * window or tab, you should instead use {@link open(Resource)} with an url - * pointing to this application and ensure - * {@link Application#getRoot(WrappedRequest)} returns an appropriate root - * for the request. - * - * @param window - * @throws IllegalArgumentException - * if the window is already added to an application - * @throws NullPointerException - * if the given <code>Window</code> is <code>null</code>. - */ - public void addWindow(Window window) throws IllegalArgumentException, - NullPointerException { - - if (window == null) { - throw new NullPointerException("Argument must not be null"); - } - - if (window.getApplication() != null) { - throw new IllegalArgumentException( - "Window is already attached to an application."); - } - - attachWindow(window); - } - - /** - * Helper method to attach a window. - * - * @param w - * the window to add - */ - private void attachWindow(Window w) { - windows.add(w); - w.setParent(this); - requestRepaint(); - } - - /** - * Remove the given subwindow from this root. - * - * Since Vaadin 6.5, {@link CloseListener}s are called also when explicitly - * removing a window by calling this method. - * - * Since Vaadin 6.5, returns a boolean indicating if the window was removed - * or not. - * - * @param window - * Window to be removed. - * @return true if the subwindow was removed, false otherwise - */ - public boolean removeWindow(Window window) { - if (!windows.remove(window)) { - // Window window is not a subwindow of this root. - return false; - } - window.setParent(null); - window.fireClose(); - requestRepaint(); - - return true; - } - - /** - * Gets all the windows added to this root. - * - * @return an unmodifiable collection of windows - */ - public Collection<Window> getWindows() { - return Collections.unmodifiableCollection(windows); - } - - @Override - public void focus() { - super.focus(); - } - - /** - * Component that should be focused after the next repaint. Null if no focus - * change should take place. - */ - private Focusable pendingFocus; - - private boolean resizeLazy = false; - - /** - * This method is used by Component.Focusable objects to request focus to - * themselves. Focus renders must be handled at window level (instead of - * Component.Focusable) due we want the last focused component to be focused - * in client too. Not the one that is rendered last (the case we'd get if - * implemented in Focusable only). - * - * To focus component from Vaadin application, use Focusable.focus(). See - * {@link Focusable}. - * - * @param focusable - * to be focused on next paint - */ - public void setFocusedComponent(Focusable focusable) { - pendingFocus = focusable; - requestRepaint(); - } - - /** - * Scrolls any component between the component and root to a suitable - * position so the component is visible to the user. The given component - * must belong to this root. - * - * @param component - * the component to be scrolled into view - * @throws IllegalArgumentException - * if {@code component} does not belong to this root - */ - public void scrollIntoView(Component component) - throws IllegalArgumentException { - if (component.getRoot() != this) { - throw new IllegalArgumentException( - "The component where to scroll must belong to this root."); - } - scrollIntoView = component; - requestRepaint(); - } - - /** - * Gets the content of this root. The content is a component container that - * serves as the outermost item of the visual contents of this root. - * - * @return a component container to use as content - * - * @see #setContent(ComponentContainer) - * @see #createDefaultLayout() - */ - public ComponentContainer getContent() { - return (ComponentContainer) getState().getContent(); - } - - /** - * Helper method to create the default content layout that is used if no - * content has not been explicitly defined. - * - * @return a newly created layout - */ - private static VerticalLayout createDefaultLayout() { - VerticalLayout layout = new VerticalLayout(); - layout.setMargin(true); - return layout; - } - - /** - * Sets the content of this root. The content is a component container that - * serves as the outermost item of the visual contents of this root. If no - * content has been set, a {@link VerticalLayout} with margins enabled will - * be used by default - see {@link #createDefaultLayout()}. The content can - * also be set in a constructor. - * - * @return a component container to use as content - * - * @see #Root(ComponentContainer) - * @see #createDefaultLayout() - */ - public void setContent(ComponentContainer content) { - if (content == null) { - content = createDefaultLayout(); - } - - if (getState().getContent() != null) { - super.removeComponent((Component) getState().getContent()); - } - getState().setContent(content); - if (content != null) { - super.addComponent(content); - } - - requestRepaint(); - } - - /** - * Adds a component to this root. The component is not added directly to the - * root, but instead to the content container ({@link #getContent()}). - * - * @param component - * the component to add to this root - * - * @see #getContent() - */ - @Override - public void addComponent(Component component) { - getContent().addComponent(component); - } - - /** - * This implementation removes the component from the content container ( - * {@link #getContent()}) instead of from the actual root. - */ - @Override - public void removeComponent(Component component) { - getContent().removeComponent(component); - } - - /** - * This implementation removes the components from the content container ( - * {@link #getContent()}) instead of from the actual root. - */ - @Override - public void removeAllComponents() { - getContent().removeAllComponents(); - } - - /** - * Internal initialization method, should not be overridden. This method is - * not declared as final because that would break compatibility with e.g. - * CDI. - * - * @param request - * the initialization request - */ - public void doInit(WrappedRequest request) { - getPage().init(request); - - // Call the init overridden by the application developer - init(request); - } - - /** - * Initializes this root. This method is intended to be overridden by - * subclasses to build the view and configure non-component functionality. - * Performing the initialization in a constructor is not suggested as the - * state of the root is not properly set up when the constructor is invoked. - * <p> - * The {@link WrappedRequest} can be used to get information about the - * request that caused this root to be created. By default, the - * {@link BrowserDetails} will be available in the request. If the browser - * details are not required, loading the application in the browser can take - * some shortcuts giving a faster initial rendering. This can be indicated - * by adding the {@link EagerInit} annotation to the Root class. - * </p> - * - * @param request - * the wrapped request that caused this root to be created - */ - protected abstract void init(WrappedRequest request); - - /** - * Sets the thread local for the current root. This method is used by the - * framework to set the current application whenever a new request is - * processed and it is cleared when the request has been processed. - * <p> - * The application developer can also use this method to define the current - * root outside the normal request handling, e.g. when initiating custom - * background threads. - * </p> - * - * @param root - * the root to register as the current root - * - * @see #getCurrent() - * @see ThreadLocal - */ - public static void setCurrent(Root root) { - currentRoot.set(root); - } - - /** - * Gets the currently used root. The current root is automatically defined - * when processing requests to the server. In other cases, (e.g. from - * background threads), the current root is not automatically defined. - * - * @return the current root instance if available, otherwise - * <code>null</code> - * - * @see #setCurrent(Root) - */ - public static Root getCurrent() { - return currentRoot.get(); - } - - public void setScrollTop(int scrollTop) { - throw new RuntimeException("Not yet implemented"); - } - - @Override - protected ActionManager getActionManager() { - if (actionManager == null) { - actionManager = new ActionManager(this); - } - return actionManager; - } - - @Override - public <T extends Action & com.vaadin.event.Action.Listener> void addAction( - T action) { - getActionManager().addAction(action); - } - - @Override - public <T extends Action & com.vaadin.event.Action.Listener> void removeAction( - T action) { - if (actionManager != null) { - actionManager.removeAction(action); - } - } - - @Override - public void addActionHandler(Handler actionHandler) { - getActionManager().addActionHandler(actionHandler); - } - - @Override - public void removeActionHandler(Handler actionHandler) { - if (actionManager != null) { - actionManager.removeActionHandler(actionHandler); - } - } - - /** - * Should resize operations be lazy, i.e. should there be a delay before - * layout sizes are recalculated. Speeds up resize operations in slow UIs - * with the penalty of slightly decreased usability. - * <p> - * Default value: <code>false</code> - * - * @param resizeLazy - * true to use a delay before recalculating sizes, false to - * calculate immediately. - */ - public void setResizeLazy(boolean resizeLazy) { - this.resizeLazy = resizeLazy; - requestRepaint(); - } - - /** - * Checks whether lazy resize is enabled. - * - * @return <code>true</code> if lazy resize is enabled, <code>false</code> - * if lazy resize is not enabled - */ - public boolean isResizeLazy() { - return resizeLazy; - } - - /** - * Add a click listener to the Root. The listener is called whenever the - * user clicks inside the Root. Also when the click targets a component - * inside the Root, provided the targeted component does not prevent the - * click event from propagating. - * - * Use {@link #removeListener(ClickListener)} to remove the listener. - * - * @param listener - * The listener to add - */ - public void addListener(ClickListener listener) { - addListener(CLICK_EVENT_ID, ClickEvent.class, listener, - ClickListener.clickMethod); - } - - /** - * Remove a click listener from the Root. The listener should earlier have - * been added using {@link #addListener(ClickListener)}. - * - * @param listener - * The listener to remove - */ - public void removeListener(ClickListener listener) { - removeListener(CLICK_EVENT_ID, ClickEvent.class, listener); - } - - @Override - public boolean isConnectorEnabled() { - // TODO How can a Root be invisible? What does it mean? - return isVisible() && isEnabled(); - } - - public ConnectorTracker getConnectorTracker() { - return connectorTracker; - } - - public Page getPage() { - return page; - } - - /** - * Setting the caption of a Root is not supported. To set the title of the - * HTML page, use Page.setTitle - * - * @deprecated as of 7.0.0, use {@link Page#setTitle(String)} - */ - @Override - @Deprecated - public void setCaption(String caption) { - throw new IllegalStateException( - "You can not set the title of a Root. To set the title of the HTML page, use Page.setTitle"); - } - - /** - * Shows a notification message on the middle of the root. The message - * automatically disappears ("humanized message"). - * - * Care should be taken to to avoid XSS vulnerabilities as the caption is - * rendered as html. - * - * @see #showNotification(Notification) - * @see Notification - * - * @param caption - * The message - * - * @deprecated As of 7.0, use Notification.show instead but be aware that - * Notification.show does not allow HTML. - */ - @Deprecated - public void showNotification(String caption) { - Notification notification = new Notification(caption); - notification.setHtmlContentAllowed(true);// Backwards compatibility - getPage().showNotification(notification); - } - - /** - * Shows a notification message the root. The position and behavior of the - * message depends on the type, which is one of the basic types defined in - * {@link Notification}, for instance Notification.TYPE_WARNING_MESSAGE. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption is - * rendered as html. - * - * @see #showNotification(Notification) - * @see Notification - * - * @param caption - * The message - * @param type - * The message type - * - * @deprecated As of 7.0, use Notification.show instead but be aware that - * Notification.show does not allow HTML. - */ - @Deprecated - public void showNotification(String caption, int type) { - Notification notification = new Notification(caption, type); - notification.setHtmlContentAllowed(true);// Backwards compatibility - getPage().showNotification(notification); - } - - /** - * Shows a notification consisting of a bigger caption and a smaller - * description on the middle of the root. The message automatically - * disappears ("humanized message"). - * - * Care should be taken to to avoid XSS vulnerabilities as the caption and - * description are rendered as html. - * - * @see #showNotification(Notification) - * @see Notification - * - * @param caption - * The caption of the message - * @param description - * The message description - * - * @deprecated As of 7.0, use new Notification(...).show(Page) instead but - * be aware that HTML by default not allowed. - */ - @Deprecated - public void showNotification(String caption, String description) { - Notification notification = new Notification(caption, description); - notification.setHtmlContentAllowed(true);// Backwards compatibility - getPage().showNotification(notification); - } - - /** - * Shows a notification consisting of a bigger caption and a smaller - * description. The position and behavior of the message depends on the - * type, which is one of the basic types defined in {@link Notification} , - * for instance Notification.TYPE_WARNING_MESSAGE. - * - * Care should be taken to to avoid XSS vulnerabilities as the caption and - * description are rendered as html. - * - * @see #showNotification(Notification) - * @see Notification - * - * @param caption - * The caption of the message - * @param description - * The message description - * @param type - * The message type - * - * @deprecated As of 7.0, use new Notification(...).show(Page) instead but - * be aware that HTML by default not allowed. - */ - @Deprecated - public void showNotification(String caption, String description, int type) { - Notification notification = new Notification(caption, description, type); - notification.setHtmlContentAllowed(true);// Backwards compatibility - getPage().showNotification(notification); - } - - /** - * Shows a notification consisting of a bigger caption and a smaller - * description. The position and behavior of the message depends on the - * type, which is one of the basic types defined in {@link Notification} , - * for instance Notification.TYPE_WARNING_MESSAGE. - * - * Care should be taken to avoid XSS vulnerabilities if html content is - * allowed. - * - * @see #showNotification(Notification) - * @see Notification - * - * @param caption - * The message caption - * @param description - * The message description - * @param type - * The type of message - * @param htmlContentAllowed - * Whether html in the caption and description should be - * displayed as html or as plain text - * - * @deprecated As of 7.0, use new Notification(...).show(Page). - */ - @Deprecated - public void showNotification(String caption, String description, int type, - boolean htmlContentAllowed) { - getPage() - .showNotification( - new Notification(caption, description, type, - htmlContentAllowed)); - } - - /** - * Shows a notification message. - * - * @see Notification - * @see #showNotification(String) - * @see #showNotification(String, int) - * @see #showNotification(String, String) - * @see #showNotification(String, String, int) - * - * @param notification - * The notification message to show - * - * @deprecated As of 7.0, use Notification.show instead - */ - @Deprecated - public void showNotification(Notification notification) { - getPage().showNotification(notification); - } - -} diff --git a/src/com/vaadin/ui/Select.java b/src/com/vaadin/ui/Select.java deleted file mode 100644 index f60935c64b..0000000000 --- a/src/com/vaadin/ui/Select.java +++ /dev/null @@ -1,803 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.vaadin.data.Container; -import com.vaadin.data.util.filter.SimpleStringFilter; -import com.vaadin.event.FieldEvents; -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; - -/** - * <p> - * A class representing a selection of items the user has selected in a UI. The - * set of choices is presented as a set of {@link com.vaadin.data.Item}s in a - * {@link com.vaadin.data.Container}. - * </p> - * - * <p> - * A <code>Select</code> component may be in single- or multiselect mode. - * Multiselect mode means that more than one item can be selected - * simultaneously. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Select extends AbstractSelect implements AbstractSelect.Filtering, - FieldEvents.BlurNotifier, FieldEvents.FocusNotifier { - - /** - * Holds value of property pageLength. 0 disables paging. - */ - protected int pageLength = 10; - - private int columns = 0; - - // Current page when the user is 'paging' trough options - private int currentPage = -1; - - private int filteringMode = FILTERINGMODE_STARTSWITH; - - private String filterstring; - private String prevfilterstring; - - /** - * Number of options that pass the filter, excluding the null item if any. - */ - private int filteredSize; - - /** - * Cache of filtered options, used only by the in-memory filtering system. - */ - private List<Object> filteredOptions; - - /** - * Flag to indicate that request repaint is called by filter request only - */ - private boolean optionRequest; - - /** - * True if the container is being filtered temporarily and item set change - * notifications should be suppressed. - */ - private boolean filteringContainer; - - /** - * Flag to indicate whether to scroll the selected item visible (select the - * page on which it is) when opening the popup or not. Only applies to - * single select mode. - * - * This requires finding the index of the item, which can be expensive in - * many large lazy loading containers. - */ - private boolean scrollToSelectedItem = true; - - /* Constructors */ - - /* Component methods */ - - public Select() { - super(); - } - - public Select(String caption, Collection<?> options) { - super(caption, options); - } - - public Select(String caption, Container dataSource) { - super(caption, dataSource); - } - - public Select(String caption) { - super(caption); - } - - /** - * Paints the content of this component. - * - * @param target - * the Paint Event. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (isMultiSelect()) { - // background compatibility hack. This object shouldn't be used for - // multiselect lists anymore (ListSelect instead). This fallbacks to - // a simpler paint method in super class. - super.paintContent(target); - // Fix for #4553 - target.addAttribute("type", "legacy-multi"); - return; - } - - // clear caption change listeners - getCaptionChangeListener().clear(); - - // The tab ordering number - if (getTabIndex() != 0) { - target.addAttribute("tabindex", getTabIndex()); - } - - // If the field is modified, but not committed, set modified attribute - if (isModified()) { - target.addAttribute("modified", true); - } - - if (isNewItemsAllowed()) { - target.addAttribute("allownewitem", true); - } - - boolean needNullSelectOption = false; - if (isNullSelectionAllowed()) { - target.addAttribute("nullselect", true); - needNullSelectOption = (getNullSelectionItemId() == null); - if (!needNullSelectOption) { - target.addAttribute("nullselectitem", true); - } - } - - // Constructs selected keys array - String[] selectedKeys; - if (isMultiSelect()) { - selectedKeys = new String[((Set<?>) getValue()).size()]; - } else { - selectedKeys = new String[(getValue() == null - && getNullSelectionItemId() == null ? 0 : 1)]; - } - - target.addAttribute("pagelength", pageLength); - - target.addAttribute("filteringmode", getFilteringMode()); - - // Paints the options and create array of selected id keys - int keyIndex = 0; - - target.startTag("options"); - - if (currentPage < 0) { - optionRequest = false; - currentPage = 0; - filterstring = ""; - } - - boolean nullFilteredOut = filterstring != null - && !"".equals(filterstring) - && filteringMode != FILTERINGMODE_OFF; - // null option is needed and not filtered out, even if not on current - // page - boolean nullOptionVisible = needNullSelectOption && !nullFilteredOut; - - // first try if using container filters is possible - List<?> options = getOptionsWithFilter(nullOptionVisible); - if (null == options) { - // not able to use container filters, perform explicit in-memory - // filtering - options = getFilteredOptions(); - filteredSize = options.size(); - options = sanitetizeList(options, nullOptionVisible); - } - - final boolean paintNullSelection = needNullSelectOption - && currentPage == 0 && !nullFilteredOut; - - if (paintNullSelection) { - target.startTag("so"); - target.addAttribute("caption", ""); - target.addAttribute("key", ""); - target.endTag("so"); - } - - final Iterator<?> i = options.iterator(); - // Paints the available selection options from data source - - while (i.hasNext()) { - - final Object id = i.next(); - - if (!isNullSelectionAllowed() && id != null - && id.equals(getNullSelectionItemId()) && !isSelected(id)) { - continue; - } - - // Gets the option attribute values - final String key = itemIdMapper.key(id); - final String caption = getItemCaption(id); - final Resource icon = getItemIcon(id); - getCaptionChangeListener().addNotifierForItem(id); - - // Paints the option - target.startTag("so"); - if (icon != null) { - target.addAttribute("icon", icon); - } - target.addAttribute("caption", caption); - if (id != null && id.equals(getNullSelectionItemId())) { - target.addAttribute("nullselection", true); - } - target.addAttribute("key", key); - if (isSelected(id) && keyIndex < selectedKeys.length) { - target.addAttribute("selected", true); - selectedKeys[keyIndex++] = key; - } - target.endTag("so"); - } - target.endTag("options"); - - target.addAttribute("totalitems", size() - + (needNullSelectOption ? 1 : 0)); - if (filteredSize > 0 || nullOptionVisible) { - target.addAttribute("totalMatches", filteredSize - + (nullOptionVisible ? 1 : 0)); - } - - // Paint variables - target.addVariable(this, "selected", selectedKeys); - if (isNewItemsAllowed()) { - target.addVariable(this, "newitem", ""); - } - - target.addVariable(this, "filter", filterstring); - target.addVariable(this, "page", currentPage); - - currentPage = -1; // current page is always set by client - - optionRequest = true; - } - - /** - * Returns the filtered options for the current page using a container - * filter. - * - * As a size effect, {@link #filteredSize} is set to the total number of - * items passing the filter. - * - * The current container must be {@link Filterable} and {@link Indexed}, and - * the filtering mode must be suitable for container filtering (tested with - * {@link #canUseContainerFilter()}). - * - * Use {@link #getFilteredOptions()} and - * {@link #sanitetizeList(List, boolean)} if this is not the case. - * - * @param needNullSelectOption - * @return filtered list of options (may be empty) or null if cannot use - * container filters - */ - protected List<?> getOptionsWithFilter(boolean needNullSelectOption) { - Container container = getContainerDataSource(); - - if (pageLength == 0) { - // no paging: return all items - filteredSize = container.size(); - return new ArrayList<Object>(container.getItemIds()); - } - - if (!(container instanceof Filterable) - || !(container instanceof Indexed) - || getItemCaptionMode() != ITEM_CAPTION_MODE_PROPERTY) { - return null; - } - - Filterable filterable = (Filterable) container; - - Filter filter = buildFilter(filterstring, filteringMode); - - // adding and removing filters leads to extraneous item set - // change events from the underlying container, but the ComboBox does - // not process or propagate them based on the flag filteringContainer - if (filter != null) { - filteringContainer = true; - filterable.addContainerFilter(filter); - } - - Indexed indexed = (Indexed) container; - - int indexToEnsureInView = -1; - - // if not an option request (item list when user changes page), go - // to page with the selected item after filtering if accepted by - // filter - Object selection = getValue(); - if (isScrollToSelectedItem() && !optionRequest && !isMultiSelect() - && selection != null) { - // ensure proper page - indexToEnsureInView = indexed.indexOfId(selection); - } - - filteredSize = container.size(); - currentPage = adjustCurrentPage(currentPage, needNullSelectOption, - indexToEnsureInView, filteredSize); - int first = getFirstItemIndexOnCurrentPage(needNullSelectOption, - filteredSize); - int last = getLastItemIndexOnCurrentPage(needNullSelectOption, - filteredSize, first); - - List<Object> options = new ArrayList<Object>(); - for (int i = first; i <= last && i < filteredSize; ++i) { - options.add(indexed.getIdByIndex(i)); - } - - // to the outside, filtering should not be visible - if (filter != null) { - filterable.removeContainerFilter(filter); - filteringContainer = false; - } - - return options; - } - - /** - * Constructs a filter instance to use when using a Filterable container in - * the <code>ITEM_CAPTION_MODE_PROPERTY</code> mode. - * - * Note that the client side implementation expects the filter string to - * apply to the item caption string it sees, so changing the behavior of - * this method can cause problems. - * - * @param filterString - * @param filteringMode - * @return - */ - protected Filter buildFilter(String filterString, int filteringMode) { - Filter filter = null; - - if (null != filterString && !"".equals(filterString)) { - switch (filteringMode) { - case FILTERINGMODE_OFF: - break; - case FILTERINGMODE_STARTSWITH: - filter = new SimpleStringFilter(getItemCaptionPropertyId(), - filterString, true, true); - break; - case FILTERINGMODE_CONTAINS: - filter = new SimpleStringFilter(getItemCaptionPropertyId(), - filterString, true, false); - break; - } - } - return filter; - } - - @Override - public void containerItemSetChange(Container.ItemSetChangeEvent event) { - if (!filteringContainer) { - super.containerItemSetChange(event); - } - } - - /** - * Makes correct sublist of given list of options. - * - * If paint is not an option request (affected by page or filter change), - * page will be the one where possible selection exists. - * - * Detects proper first and last item in list to return right page of - * options. Also, if the current page is beyond the end of the list, it will - * be adjusted. - * - * @param options - * @param needNullSelectOption - * flag to indicate if nullselect option needs to be taken into - * consideration - */ - private List<?> sanitetizeList(List<?> options, boolean needNullSelectOption) { - - if (pageLength != 0 && options.size() > pageLength) { - - int indexToEnsureInView = -1; - - // if not an option request (item list when user changes page), go - // to page with the selected item after filtering if accepted by - // filter - Object selection = getValue(); - if (isScrollToSelectedItem() && !optionRequest && !isMultiSelect() - && selection != null) { - // ensure proper page - indexToEnsureInView = options.indexOf(selection); - } - - int size = options.size(); - currentPage = adjustCurrentPage(currentPage, needNullSelectOption, - indexToEnsureInView, size); - int first = getFirstItemIndexOnCurrentPage(needNullSelectOption, - size); - int last = getLastItemIndexOnCurrentPage(needNullSelectOption, - size, first); - return options.subList(first, last + 1); - } else { - return options; - } - } - - /** - * Returns the index of the first item on the current page. The index is to - * the underlying (possibly filtered) contents. The null item, if any, does - * not have an index but takes up a slot on the first page. - * - * @param needNullSelectOption - * true if a null option should be shown before any other options - * (takes up the first slot on the first page, not counted in - * index) - * @param size - * number of items after filtering (not including the null item, - * if any) - * @return first item to show on the UI (index to the filtered list of - * options, not taking the null item into consideration if any) - */ - private int getFirstItemIndexOnCurrentPage(boolean needNullSelectOption, - int size) { - // Not all options are visible, find out which ones are on the - // current "page". - int first = currentPage * pageLength; - if (needNullSelectOption && currentPage > 0) { - first--; - } - return first; - } - - /** - * Returns the index of the last item on the current page. The index is to - * the underlying (possibly filtered) contents. If needNullSelectOption is - * true, the null item takes up the first slot on the first page, - * effectively reducing the first page size by one. - * - * @param needNullSelectOption - * true if a null option should be shown before any other options - * (takes up the first slot on the first page, not counted in - * index) - * @param size - * number of items after filtering (not including the null item, - * if any) - * @param first - * index in the filtered view of the first item of the page - * @return index in the filtered view of the last item on the page - */ - private int getLastItemIndexOnCurrentPage(boolean needNullSelectOption, - int size, int first) { - // page length usable for non-null items - int effectivePageLength = pageLength - - (needNullSelectOption && (currentPage == 0) ? 1 : 0); - return Math.min(size - 1, first + effectivePageLength - 1); - } - - /** - * Adjusts the index of the current page if necessary: make sure the current - * page is not after the end of the contents, and optionally go to the page - * containg a specific item. There are no side effects but the adjusted page - * index is returned. - * - * @param page - * page number to use as the starting point - * @param needNullSelectOption - * true if a null option should be shown before any other options - * (takes up the first slot on the first page, not counted in - * index) - * @param indexToEnsureInView - * index of an item that should be included on the page (in the - * data set, not counting the null item if any), -1 for none - * @param size - * number of items after filtering (not including the null item, - * if any) - */ - private int adjustCurrentPage(int page, boolean needNullSelectOption, - int indexToEnsureInView, int size) { - if (indexToEnsureInView != -1) { - int newPage = (indexToEnsureInView + (needNullSelectOption ? 1 : 0)) - / pageLength; - page = newPage; - } - // adjust the current page if beyond the end of the list - if (page * pageLength > size) { - page = (size + (needNullSelectOption ? 1 : 0)) / pageLength; - } - return page; - } - - /** - * Filters the options in memory and returns the full filtered list. - * - * This can be less efficient than using container filters, so use - * {@link #getOptionsWithFilter(boolean)} if possible (filterable container - * and suitable item caption mode etc.). - * - * @return - */ - protected List<?> getFilteredOptions() { - if (null == filterstring || "".equals(filterstring) - || FILTERINGMODE_OFF == filteringMode) { - prevfilterstring = null; - filteredOptions = new LinkedList<Object>(getItemIds()); - return filteredOptions; - } - - if (filterstring.equals(prevfilterstring)) { - return filteredOptions; - } - - Collection<?> items; - if (prevfilterstring != null - && filterstring.startsWith(prevfilterstring)) { - items = filteredOptions; - } else { - items = getItemIds(); - } - prevfilterstring = filterstring; - - filteredOptions = new LinkedList<Object>(); - for (final Iterator<?> it = items.iterator(); it.hasNext();) { - final Object itemId = it.next(); - String caption = getItemCaption(itemId); - if (caption == null || caption.equals("")) { - continue; - } else { - caption = caption.toLowerCase(); - } - switch (filteringMode) { - case FILTERINGMODE_CONTAINS: - if (caption.indexOf(filterstring) > -1) { - filteredOptions.add(itemId); - } - break; - case FILTERINGMODE_STARTSWITH: - default: - if (caption.startsWith(filterstring)) { - filteredOptions.add(itemId); - } - break; - } - } - - return filteredOptions; - } - - /** - * Invoked when the value of a variable has changed. - * - * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, - * java.util.Map) - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - // Not calling super.changeVariables due the history of select - // component hierarchy - - // Selection change - if (variables.containsKey("selected")) { - final String[] ka = (String[]) variables.get("selected"); - - if (isMultiSelect()) { - // Multiselect mode - - // TODO Optimize by adding repaintNotNeeded whan applicaple - - // Converts the key-array to id-set - final LinkedList<Object> s = new LinkedList<Object>(); - for (int i = 0; i < ka.length; i++) { - final Object id = itemIdMapper.get(ka[i]); - if (id != null && containsId(id)) { - s.add(id); - } - } - - // Limits the deselection to the set of visible items - // (non-visible items can not be deselected) - final Collection<?> visible = getVisibleItemIds(); - if (visible != null) { - @SuppressWarnings("unchecked") - Set<Object> newsel = (Set<Object>) getValue(); - if (newsel == null) { - newsel = new HashSet<Object>(); - } else { - newsel = new HashSet<Object>(newsel); - } - newsel.removeAll(visible); - newsel.addAll(s); - setValue(newsel, true); - } - } else { - // Single select mode - if (ka.length == 0) { - - // Allows deselection only if the deselected item is visible - final Object current = getValue(); - final Collection<?> visible = getVisibleItemIds(); - if (visible != null && visible.contains(current)) { - setValue(null, true); - } - } else { - final Object id = itemIdMapper.get(ka[0]); - if (id != null && id.equals(getNullSelectionItemId())) { - setValue(null, true); - } else { - setValue(id, true); - } - } - } - } - - String newFilter; - if ((newFilter = (String) variables.get("filter")) != null) { - // this is a filter request - currentPage = ((Integer) variables.get("page")).intValue(); - filterstring = newFilter; - if (filterstring != null) { - filterstring = filterstring.toLowerCase(); - } - optionRepaint(); - } else if (isNewItemsAllowed()) { - // New option entered (and it is allowed) - final String newitem = (String) variables.get("newitem"); - if (newitem != null && newitem.length() > 0) { - getNewItemHandler().addNewItem(newitem); - // rebuild list - filterstring = null; - prevfilterstring = null; - } - } - - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } - if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } - - } - - @Override - public void requestRepaint() { - super.requestRepaint(); - optionRequest = false; - prevfilterstring = filterstring; - filterstring = null; - } - - private void optionRepaint() { - super.requestRepaint(); - } - - @Override - public void setFilteringMode(int filteringMode) { - this.filteringMode = filteringMode; - } - - @Override - public int getFilteringMode() { - return filteringMode; - } - - /** - * Note, one should use more generic setWidth(String) method instead of - * this. This now days actually converts columns to width with em css unit. - * - * Sets the number of columns in the editor. If the number of columns is set - * 0, the actual number of displayed columns is determined implicitly by the - * adapter. - * - * @deprecated - * - * @param columns - * the number of columns to set. - */ - @Deprecated - public void setColumns(int columns) { - if (columns < 0) { - columns = 0; - } - if (this.columns != columns) { - this.columns = columns; - setWidth(columns, Select.UNITS_EM); - requestRepaint(); - } - } - - /** - * @deprecated see setter function - * @return - */ - @Deprecated - public int getColumns() { - return columns; - } - - @Override - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - @Override - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - @Override - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - @Override - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - - } - - /** - * @deprecated use {@link ListSelect}, {@link OptionGroup} or - * {@link TwinColSelect} instead - * @see com.vaadin.ui.AbstractSelect#setMultiSelect(boolean) - * @throws UnsupportedOperationException - * if trying to activate multiselect mode - */ - @Deprecated - @Override - public void setMultiSelect(boolean multiSelect) { - if (multiSelect) { - throw new UnsupportedOperationException("Multiselect not supported"); - } - } - - /** - * @deprecated use {@link ListSelect}, {@link OptionGroup} or - * {@link TwinColSelect} instead - * - * @see com.vaadin.ui.AbstractSelect#isMultiSelect() - */ - @Deprecated - @Override - public boolean isMultiSelect() { - return super.isMultiSelect(); - } - - /** - * Sets whether to scroll the selected item visible (directly open the page - * on which it is) when opening the combo box popup or not. Only applies to - * single select mode. - * - * This requires finding the index of the item, which can be expensive in - * many large lazy loading containers. - * - * @param scrollToSelectedItem - * true to find the page with the selected item when opening the - * selection popup - */ - public void setScrollToSelectedItem(boolean scrollToSelectedItem) { - this.scrollToSelectedItem = scrollToSelectedItem; - } - - /** - * Returns true if the select should find the page with the selected item - * when opening the popup (single select combo box only). - * - * @see #setScrollToSelectedItem(boolean) - * - * @return true if the page with the selected item will be shown when - * opening the popup - */ - public boolean isScrollToSelectedItem() { - return scrollToSelectedItem; - } - -} diff --git a/src/com/vaadin/ui/Slider.java b/src/com/vaadin/ui/Slider.java deleted file mode 100644 index 94afe4e2bd..0000000000 --- a/src/com/vaadin/ui/Slider.java +++ /dev/null @@ -1,372 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Map; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; - -/** - * A component for selecting a numerical value within a range. - * - * Example code: <code> - * class MyPlayer extends CustomComponent implements ValueChangeListener { - * - * Label volumeIndicator = new Label(); - * Slider slider; - * - * public MyPlayer() { - * VerticalLayout vl = new VerticalLayout(); - * setCompositionRoot(vl); - * slider = new Slider("Volume", 0, 100); - * slider.setImmediate(true); - * slider.setValue(new Double(50)); - * vl.addComponent(slider); - * vl.addComponent(volumeIndicator); - * volumeIndicator.setValue("Current volume:" + 50.0); - * slider.addListener(this); - * - * } - * - * public void setVolume(double d) { - * volumeIndicator.setValue("Current volume: " + d); - * } - * - * public void valueChange(ValueChangeEvent event) { - * Double d = (Double) event.getProperty().getValue(); - * setVolume(d.doubleValue()); - * } - * } - * - * </code> - * - * @author Vaadin Ltd. - */ -public class Slider extends AbstractField<Double> implements Vaadin6Component { - - public static final int ORIENTATION_HORIZONTAL = 0; - - public static final int ORIENTATION_VERTICAL = 1; - - /** Minimum value of slider */ - private double min = 0; - - /** Maximum value of slider */ - private double max = 100; - - /** - * Resolution, how many digits are considered relevant after the decimal - * point. Must be a non-negative value - */ - private int resolution = 0; - - /** - * Slider orientation (horizontal/vertical), defaults . - */ - private int orientation = ORIENTATION_HORIZONTAL; - - /** - * Default slider constructor. Sets all values to defaults and the slide - * handle at minimum value. - * - */ - public Slider() { - super(); - super.setValue(new Double(min)); - } - - /** - * Create a new slider with the caption given as parameter. - * - * The range of the slider is set to 0-100 and only integer values are - * allowed. - * - * @param caption - * The caption for this slider (e.g. "Volume"). - */ - public Slider(String caption) { - this(); - setCaption(caption); - } - - /** - * Create a new slider with the given range and resolution. - * - * @param min - * The minimum value of the slider - * @param max - * The maximum value of the slider - * @param resolution - * The number of digits after the decimal point. - */ - public Slider(double min, double max, int resolution) { - this(); - setMin(min); - setMax(max); - setResolution(resolution); - } - - /** - * Create a new slider with the given range that only allows integer values. - * - * @param min - * The minimum value of the slider - * @param max - * The maximum value of the slider - */ - public Slider(int min, int max) { - this(); - setMin(min); - setMax(max); - setResolution(0); - } - - /** - * Create a new slider with the given caption and range that only allows - * integer values. - * - * @param caption - * The caption for the slider - * @param min - * The minimum value of the slider - * @param max - * The maximum value of the slider - */ - public Slider(String caption, int min, int max) { - this(min, max); - setCaption(caption); - } - - /** - * Gets the maximum slider value - * - * @return the largest value the slider can have - */ - public double getMax() { - return max; - } - - /** - * Set the maximum slider value. If the current value of the slider is - * larger than this, the value is set to the new maximum. - * - * @param max - * The new maximum slider value - */ - public void setMax(double max) { - this.max = max; - if (getValue() > max) { - setValue(max); - } - requestRepaint(); - } - - /** - * Gets the minimum slider value - * - * @return the smallest value the slider can have - */ - public double getMin() { - return min; - } - - /** - * Set the minimum slider value. If the current value of the slider is - * smaller than this, the value is set to the new minimum. - * - * @param max - * The new minimum slider value - */ - public void setMin(double min) { - this.min = min; - if (getValue() < min) { - setValue(min); - } - requestRepaint(); - } - - /** - * Get the current orientation of the slider (horizontal or vertical). - * - * @return {@link #ORIENTATION_HORIZONTAL} or - * {@link #ORIENTATION_HORIZONTAL} - */ - public int getOrientation() { - return orientation; - } - - /** - * Set the orientation of the slider. - * - * @param The - * new orientation, either {@link #ORIENTATION_HORIZONTAL} or - * {@link #ORIENTATION_VERTICAL} - */ - public void setOrientation(int orientation) { - this.orientation = orientation; - requestRepaint(); - } - - /** - * Get the current resolution of the slider. The resolution is the number of - * digits after the decimal point. - * - * @return resolution - */ - public int getResolution() { - return resolution; - } - - /** - * Set a new resolution for the slider. The resolution is the number of - * digits after the decimal point. - * - * @param resolution - */ - public void setResolution(int resolution) { - if (resolution < 0) { - return; - } - this.resolution = resolution; - requestRepaint(); - } - - /** - * Sets the value of the slider. - * - * @param value - * The new value of the slider. - * @param repaintIsNotNeeded - * If true, client-side is not requested to repaint itself. - * @throws ValueOutOfBoundsException - * If the given value is not inside the range of the slider. - * @see #setMin(double) {@link #setMax(double)} - */ - @Override - protected void setValue(Double value, boolean repaintIsNotNeeded) { - final double v = value.doubleValue(); - double newValue; - if (resolution > 0) { - // Round up to resolution - newValue = (int) (v * Math.pow(10, resolution)); - newValue = newValue / Math.pow(10, resolution); - if (min > newValue || max < newValue) { - throw new ValueOutOfBoundsException(value); - } - } else { - newValue = (int) v; - if (min > newValue || max < newValue) { - throw new ValueOutOfBoundsException(value); - } - } - super.setValue(newValue, repaintIsNotNeeded); - } - - @Override - public void setValue(Object newFieldValue) - throws com.vaadin.data.Property.ReadOnlyException { - if (newFieldValue != null && newFieldValue instanceof Number - && !(newFieldValue instanceof Double)) { - // Support setting all types of Numbers - newFieldValue = ((Number) newFieldValue).doubleValue(); - } - - super.setValue(newFieldValue); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - - target.addAttribute("min", min); - if (max > min) { - target.addAttribute("max", max); - } else { - target.addAttribute("max", min); - } - target.addAttribute("resolution", resolution); - - if (resolution > 0) { - target.addVariable(this, "value", getValue().doubleValue()); - } else { - target.addVariable(this, "value", getValue().intValue()); - } - - if (orientation == ORIENTATION_VERTICAL) { - target.addAttribute("vertical", true); - } - - } - - /** - * Invoked when the value of a variable has changed. Slider listeners are - * notified if the slider value has changed. - * - * @param source - * @param variables - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - if (variables.containsKey("value")) { - final Object value = variables.get("value"); - final Double newValue = new Double(value.toString()); - if (newValue != null && newValue != getValue() - && !newValue.equals(getValue())) { - try { - setValue(newValue, true); - } catch (final ValueOutOfBoundsException e) { - // Convert to nearest bound - double out = e.getValue().doubleValue(); - if (out < min) { - out = min; - } - if (out > max) { - out = max; - } - super.setValue(new Double(out), false); - } - } - } - } - - /** - * Thrown when the value of the slider is about to be set to a value that is - * outside the valid range of the slider. - * - * @author Vaadin Ltd. - * - */ - public class ValueOutOfBoundsException extends RuntimeException { - - private final Double value; - - /** - * Constructs an <code>ValueOutOfBoundsException</code> with the - * specified detail message. - * - * @param valueOutOfBounds - */ - public ValueOutOfBoundsException(Double valueOutOfBounds) { - value = valueOutOfBounds; - } - - /** - * Gets the value that is outside the valid range of the slider. - * - * @return the value that is out of bounds - */ - public Double getValue() { - return value; - } - - } - - @Override - public Class<Double> getType() { - return Double.class; - } - -} diff --git a/src/com/vaadin/ui/TabSheet.java b/src/com/vaadin/ui/TabSheet.java deleted file mode 100644 index c52e9394c0..0000000000 --- a/src/com/vaadin/ui/TabSheet.java +++ /dev/null @@ -1,1328 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.BlurNotifier; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.event.FieldEvents.FocusNotifier; -import com.vaadin.terminal.ErrorMessage; -import com.vaadin.terminal.KeyMapper; -import com.vaadin.terminal.LegacyPaint; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.tabsheet.TabsheetBaseConnector; -import com.vaadin.terminal.gwt.client.ui.tabsheet.VTabsheet; -import com.vaadin.ui.Component.Focusable; -import com.vaadin.ui.themes.Reindeer; -import com.vaadin.ui.themes.Runo; - -/** - * TabSheet component. - * - * Tabs are typically identified by the component contained on the tab (see - * {@link ComponentContainer}), and tab metadata (including caption, icon, - * visibility, enabledness, closability etc.) is kept in separate {@link Tab} - * instances. - * - * Tabs added with {@link #addComponent(Component)} get the caption and the icon - * of the component at the time when the component is created, and these are not - * automatically updated after tab creation. - * - * A tab sheet can have multiple tab selection listeners and one tab close - * handler ({@link CloseHandler}), which by default removes the tab from the - * TabSheet. - * - * The {@link TabSheet} can be styled with the .v-tabsheet, .v-tabsheet-tabs and - * .v-tabsheet-content styles. Themes may also have pre-defined variations of - * the tab sheet presentation, such as {@link Reindeer#TABSHEET_BORDERLESS}, - * {@link Runo#TABSHEET_SMALL} and several other styles in {@link Reindeer}. - * - * The current implementation does not load the tabs to the UI before the first - * time they are shown, but this may change in future releases. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -public class TabSheet extends AbstractComponentContainer implements Focusable, - FocusNotifier, BlurNotifier, Vaadin6Component { - - /** - * List of component tabs (tab contents). In addition to being on this list, - * there is a {@link Tab} object in tabs for each tab with meta-data about - * the tab. - */ - private final ArrayList<Component> components = new ArrayList<Component>(); - - /** - * Map containing information related to the tabs (caption, icon etc). - */ - private final HashMap<Component, Tab> tabs = new HashMap<Component, Tab>(); - - /** - * Selected tab content component. - */ - private Component selected = null; - - /** - * Mapper between server-side component instances (tab contents) and keys - * given to the client that identify tabs. - */ - private final KeyMapper<Component> keyMapper = new KeyMapper<Component>(); - - /** - * When true, the tab selection area is not displayed to the user. - */ - private boolean tabsHidden; - - /** - * Handler to be called when a tab is closed. - */ - private CloseHandler closeHandler; - - private int tabIndex; - - /** - * Constructs a new Tabsheet. Tabsheet is immediate by default, and the - * default close handler removes the tab being closed. - */ - public TabSheet() { - super(); - // expand horizontally by default - setWidth(100, UNITS_PERCENTAGE); - setImmediate(true); - setCloseHandler(new CloseHandler() { - - @Override - public void onTabClose(TabSheet tabsheet, Component c) { - tabsheet.removeComponent(c); - } - }); - } - - /** - * Gets the component container iterator for going through all the - * components (tab contents). - * - * @return the unmodifiable Iterator of the tab content components - */ - - @Override - public Iterator<Component> getComponentIterator() { - return Collections.unmodifiableList(components).iterator(); - } - - /** - * Gets the number of contained components (tabs). Consistent with the - * iterator returned by {@link #getComponentIterator()}. - * - * @return the number of contained components - */ - - @Override - public int getComponentCount() { - return components.size(); - } - - /** - * Removes a component and its corresponding tab. - * - * If the tab was selected, the first eligible (visible and enabled) - * remaining tab is selected. - * - * @param c - * the component to be removed. - */ - - @Override - public void removeComponent(Component c) { - if (c != null && components.contains(c)) { - super.removeComponent(c); - keyMapper.remove(c); - components.remove(c); - tabs.remove(c); - if (c.equals(selected)) { - if (components.isEmpty()) { - setSelected(null); - } else { - // select the first enabled and visible tab, if any - updateSelection(); - fireSelectedTabChange(); - } - } - requestRepaint(); - } - } - - /** - * Removes a {@link Tab} and the component associated with it, as previously - * added with {@link #addTab(Component)}, - * {@link #addTab(Component, String, Resource)} or - * {@link #addComponent(Component)}. - * <p> - * If the tab was selected, the first eligible (visible and enabled) - * remaining tab is selected. - * </p> - * - * @see #addTab(Component) - * @see #addTab(Component, String, Resource) - * @see #addComponent(Component) - * @see #removeComponent(Component) - * @param tab - * the Tab to remove - */ - public void removeTab(Tab tab) { - removeComponent(tab.getComponent()); - } - - /** - * Adds a new tab into TabSheet. Component caption and icon are copied to - * the tab metadata at creation time. - * - * @see #addTab(Component) - * - * @param c - * the component to be added. - */ - - @Override - public void addComponent(Component c) { - addTab(c); - } - - /** - * Adds a new tab into TabSheet. - * - * The first tab added to a tab sheet is automatically selected and a tab - * selection event is fired. - * - * If the component is already present in the tab sheet, changes its caption - * and returns the corresponding (old) tab, preserving other tab metadata. - * - * @param c - * the component to be added onto tab - should not be null. - * @param caption - * the caption to be set for the component and used rendered in - * tab bar - * @return the created {@link Tab} - */ - public Tab addTab(Component c, String caption) { - return addTab(c, caption, null); - } - - /** - * Adds a new tab into TabSheet. - * - * The first tab added to a tab sheet is automatically selected and a tab - * selection event is fired. - * - * If the component is already present in the tab sheet, changes its caption - * and icon and returns the corresponding (old) tab, preserving other tab - * metadata. - * - * @param c - * the component to be added onto tab - should not be null. - * @param caption - * the caption to be set for the component and used rendered in - * tab bar - * @param icon - * the icon to be set for the component and used rendered in tab - * bar - * @return the created {@link Tab} - */ - public Tab addTab(Component c, String caption, Resource icon) { - return addTab(c, caption, icon, components.size()); - } - - /** - * Adds a new tab into TabSheet. - * - * The first tab added to a tab sheet is automatically selected and a tab - * selection event is fired. - * - * If the component is already present in the tab sheet, changes its caption - * and icon and returns the corresponding (old) tab, preserving other tab - * metadata like the position. - * - * @param c - * the component to be added onto tab - should not be null. - * @param caption - * the caption to be set for the component and used rendered in - * tab bar - * @param icon - * the icon to be set for the component and used rendered in tab - * bar - * @param position - * the position at where the the tab should be added. - * @return the created {@link Tab} - */ - public Tab addTab(Component c, String caption, Resource icon, int position) { - if (c == null) { - return null; - } else if (tabs.containsKey(c)) { - Tab tab = tabs.get(c); - tab.setCaption(caption); - tab.setIcon(icon); - return tab; - } else { - components.add(position, c); - - Tab tab = new TabSheetTabImpl(caption, icon); - - tabs.put(c, tab); - if (selected == null) { - setSelected(c); - fireSelectedTabChange(); - } - super.addComponent(c); - requestRepaint(); - return tab; - } - } - - /** - * Adds a new tab into TabSheet. Component caption and icon are copied to - * the tab metadata at creation time. - * - * If the tab sheet already contains the component, its tab is returned. - * - * @param c - * the component to be added onto tab - should not be null. - * @return the created {@link Tab} - */ - public Tab addTab(Component c) { - return addTab(c, components.size()); - } - - /** - * Adds a new tab into TabSheet. Component caption and icon are copied to - * the tab metadata at creation time. - * - * If the tab sheet already contains the component, its tab is returned. - * - * @param c - * the component to be added onto tab - should not be null. - * @param position - * The position where the tab should be added - * @return the created {@link Tab} - */ - public Tab addTab(Component c, int position) { - if (c == null) { - return null; - } else if (tabs.containsKey(c)) { - return tabs.get(c); - } else { - return addTab(c, c.getCaption(), c.getIcon(), position); - } - } - - /** - * Moves all components from another container to this container. The - * components are removed from the other container. - * - * If the source container is a {@link TabSheet}, component captions and - * icons are copied from it. - * - * @param source - * the container components are removed from. - */ - - @Override - public void moveComponentsFrom(ComponentContainer source) { - for (final Iterator<Component> i = source.getComponentIterator(); i - .hasNext();) { - final Component c = i.next(); - String caption = null; - Resource icon = null; - if (TabSheet.class.isAssignableFrom(source.getClass())) { - caption = ((TabSheet) source).getTabCaption(c); - icon = ((TabSheet) source).getTabIcon(c); - } - source.removeComponent(c); - addTab(c, caption, icon); - - } - } - - /** - * Paints the content of this component. - * - * @param target - * the paint target - * @throws PaintException - * if the paint operation failed. - */ - - @Override - public void paintContent(PaintTarget target) throws PaintException { - - if (areTabsHidden()) { - target.addAttribute("hidetabs", true); - } - - if (tabIndex != 0) { - target.addAttribute("tabindex", tabIndex); - } - - target.startTag("tabs"); - - for (final Iterator<Component> i = getComponentIterator(); i.hasNext();) { - final Component component = i.next(); - - Tab tab = tabs.get(component); - - target.startTag("tab"); - if (!tab.isEnabled() && tab.isVisible()) { - target.addAttribute( - TabsheetBaseConnector.ATTRIBUTE_TAB_DISABLED, true); - } - - if (!tab.isVisible()) { - target.addAttribute("hidden", true); - } - - if (tab.isClosable()) { - target.addAttribute("closable", true); - } - - // tab icon, caption and description, but used via - // VCaption.updateCaption(uidl) - final Resource icon = tab.getIcon(); - if (icon != null) { - target.addAttribute(TabsheetBaseConnector.ATTRIBUTE_TAB_ICON, - icon); - } - final String caption = tab.getCaption(); - if (caption != null && caption.length() > 0) { - target.addAttribute( - TabsheetBaseConnector.ATTRIBUTE_TAB_CAPTION, caption); - } - ErrorMessage tabError = tab.getComponentError(); - if (tabError != null) { - target.addAttribute( - TabsheetBaseConnector.ATTRIBUTE_TAB_ERROR_MESSAGE, - tabError.getFormattedHtmlMessage()); - } - final String description = tab.getDescription(); - if (description != null) { - target.addAttribute( - TabsheetBaseConnector.ATTRIBUTE_TAB_DESCRIPTION, - description); - } - - final String styleName = tab.getStyleName(); - if (styleName != null && styleName.length() != 0) { - target.addAttribute(VTabsheet.TAB_STYLE_NAME, styleName); - } - - target.addAttribute("key", keyMapper.key(component)); - if (component.equals(selected)) { - target.addAttribute("selected", true); - LegacyPaint.paint(component, target); - } - target.endTag("tab"); - } - - target.endTag("tabs"); - - if (selected != null) { - target.addVariable(this, "selected", keyMapper.key(selected)); - } - - } - - /** - * Are the tab selection parts ("tabs") hidden. - * - * @return true if the tabs are hidden in the UI - */ - public boolean areTabsHidden() { - return tabsHidden; - } - - /** - * Hides or shows the tab selection parts ("tabs"). - * - * @param tabsHidden - * true if the tabs should be hidden - */ - public void hideTabs(boolean tabsHidden) { - this.tabsHidden = tabsHidden; - requestRepaint(); - } - - /** - * Gets tab caption. The tab is identified by the tab content component. - * - * @param c - * the component in the tab - * @deprecated Use {@link #getTab(Component)} and {@link Tab#getCaption()} - * instead. - */ - @Deprecated - public String getTabCaption(Component c) { - Tab info = tabs.get(c); - if (info == null) { - return ""; - } else { - return info.getCaption(); - } - } - - /** - * Sets tab caption. The tab is identified by the tab content component. - * - * @param c - * the component in the tab - * @param caption - * the caption to set. - * @deprecated Use {@link #getTab(Component)} and - * {@link Tab#setCaption(String)} instead. - */ - @Deprecated - public void setTabCaption(Component c, String caption) { - Tab info = tabs.get(c); - if (info != null) { - info.setCaption(caption); - requestRepaint(); - } - } - - /** - * Gets the icon for a tab. The tab is identified by the tab content - * component. - * - * @param c - * the component in the tab - * @deprecated Use {@link #getTab(Component)} and {@link Tab#getIcon()} - * instead. - */ - @Deprecated - public Resource getTabIcon(Component c) { - Tab info = tabs.get(c); - if (info == null) { - return null; - } else { - return info.getIcon(); - } - } - - /** - * Sets icon for the given component. The tab is identified by the tab - * content component. - * - * @param c - * the component in the tab - * @param icon - * the icon to set - * @deprecated Use {@link #getTab(Component)} and - * {@link Tab#setIcon(Resource)} instead. - */ - @Deprecated - public void setTabIcon(Component c, Resource icon) { - Tab info = tabs.get(c); - if (info != null) { - info.setIcon(icon); - requestRepaint(); - } - } - - /** - * Returns the {@link Tab} (metadata) for a component. The {@link Tab} - * object can be used for setting caption,icon, etc for the tab. - * - * @param c - * the component - * @return The tab instance associated with the given component, or null if - * the tabsheet does not contain the component. - */ - public Tab getTab(Component c) { - return tabs.get(c); - } - - /** - * Returns the {@link Tab} (metadata) for a component. The {@link Tab} - * object can be used for setting caption,icon, etc for the tab. - * - * @param position - * the position of the tab - * @return The tab in the given position, or null if the position is out of - * bounds. - */ - public Tab getTab(int position) { - if (position >= 0 && position < getComponentCount()) { - return getTab(components.get(position)); - } else { - return null; - } - } - - /** - * Sets the selected tab. The tab is identified by the tab content - * component. Does nothing if the tabsheet doesn't contain the component. - * - * @param c - */ - public void setSelectedTab(Component c) { - if (c != null && components.contains(c) && !c.equals(selected)) { - setSelected(c); - updateSelection(); - fireSelectedTabChange(); - requestRepaint(); - } - } - - /** - * Sets the selected tab in the TabSheet. Ensures that the selected tab is - * repainted if needed. - * - * @param c - * The new selection or null for no selection - */ - private void setSelected(Component c) { - selected = c; - // Repaint of the selected component is needed as only the selected - // component is communicated to the client. Otherwise this will be a - // "cached" update even though the client knows nothing about the - // connector - if (selected instanceof ComponentContainer) { - ((ComponentContainer) selected).requestRepaintAll(); - } else if (selected instanceof Table) { - // Workaround until there's a generic way of telling a component - // that there is no client side state to rely on. See #8642 - ((Table) selected).refreshRowCache(); - } else if (selected != null) { - selected.requestRepaint(); - } - - } - - /** - * Sets the selected tab. The tab is identified by the corresponding - * {@link Tab Tab} instance. Does nothing if the tabsheet doesn't contain - * the given tab. - * - * @param tab - */ - public void setSelectedTab(Tab tab) { - if (tab != null) { - setSelectedTab(tab.getComponent()); - } - } - - /** - * Sets the selected tab, identified by its position. Does nothing if the - * position is out of bounds. - * - * @param position - */ - public void setSelectedTab(int position) { - setSelectedTab(getTab(position)); - } - - /** - * Checks if the current selection is valid, and updates the selection if - * the previously selected component is not visible and enabled. The first - * visible and enabled tab is selected if the current selection is empty or - * invalid. - * - * This method does not fire tab change events, but the caller should do so - * if appropriate. - * - * @return true if selection was changed, false otherwise - */ - private boolean updateSelection() { - Component originalSelection = selected; - for (final Iterator<Component> i = getComponentIterator(); i.hasNext();) { - final Component component = i.next(); - - Tab tab = tabs.get(component); - - /* - * If we have no selection, if the current selection is invisible or - * if the current selection is disabled (but the whole component is - * not) we select this tab instead - */ - Tab selectedTabInfo = null; - if (selected != null) { - selectedTabInfo = tabs.get(selected); - } - if (selected == null || selectedTabInfo == null - || !selectedTabInfo.isVisible() - || !selectedTabInfo.isEnabled()) { - - // The current selection is not valid so we need to change - // it - if (tab.isEnabled() && tab.isVisible()) { - setSelected(component); - break; - } else { - /* - * The current selection is not valid but this tab cannot be - * selected either. - */ - setSelected(null); - } - } - } - return originalSelection != selected; - } - - /** - * Gets the selected tab content component. - * - * @return the selected tab contents - */ - public Component getSelectedTab() { - return selected; - } - - // inherits javadoc - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - if (variables.containsKey("selected")) { - setSelectedTab(keyMapper.get((String) variables.get("selected"))); - } - if (variables.containsKey("close")) { - final Component tab = keyMapper - .get((String) variables.get("close")); - if (tab != null) { - closeHandler.onTabClose(this, tab); - } - } - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } - if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } - } - - /** - * Replaces a component (tab content) with another. This can be used to - * change tab contents or to rearrange tabs. The tab position and some - * metadata are preserved when moving components within the same - * {@link TabSheet}. - * - * If the oldComponent is not present in the tab sheet, the new one is added - * at the end. - * - * If the oldComponent is already in the tab sheet but the newComponent - * isn't, the old tab is replaced with a new one, and the caption and icon - * of the old one are copied to the new tab. - * - * If both old and new components are present, their positions are swapped. - * - * {@inheritDoc} - */ - - @Override - public void replaceComponent(Component oldComponent, Component newComponent) { - - if (selected == oldComponent) { - // keep selection w/o selectedTabChange event - setSelected(newComponent); - } - - Tab newTab = tabs.get(newComponent); - Tab oldTab = tabs.get(oldComponent); - - // Gets the locations - int oldLocation = -1; - int newLocation = -1; - int location = 0; - for (final Iterator<Component> i = components.iterator(); i.hasNext();) { - final Component component = i.next(); - - if (component == oldComponent) { - oldLocation = location; - } - if (component == newComponent) { - newLocation = location; - } - - location++; - } - - if (oldLocation == -1) { - addComponent(newComponent); - } else if (newLocation == -1) { - removeComponent(oldComponent); - newTab = addTab(newComponent, oldLocation); - // Copy all relevant metadata to the new tab (#8793) - // TODO Should reuse the old tab instance instead? - copyTabMetadata(oldTab, newTab); - } else { - components.set(oldLocation, newComponent); - components.set(newLocation, oldComponent); - - // Tab associations are not changed, but metadata is swapped between - // the instances - // TODO Should reassociate the instances instead? - Tab tmp = new TabSheetTabImpl(null, null); - copyTabMetadata(newTab, tmp); - copyTabMetadata(oldTab, newTab); - copyTabMetadata(tmp, oldTab); - - requestRepaint(); - } - - } - - /* Click event */ - - private static final Method SELECTED_TAB_CHANGE_METHOD; - static { - try { - SELECTED_TAB_CHANGE_METHOD = SelectedTabChangeListener.class - .getDeclaredMethod("selectedTabChange", - new Class[] { SelectedTabChangeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in TabSheet"); - } - } - - /** - * Selected tab change event. This event is sent when the selected (shown) - * tab in the tab sheet is changed. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public class SelectedTabChangeEvent extends Component.Event { - - /** - * New instance of selected tab change event - * - * @param source - * the Source of the event. - */ - public SelectedTabChangeEvent(Component source) { - super(source); - } - - /** - * TabSheet where the event occurred. - * - * @return the Source of the event. - */ - public TabSheet getTabSheet() { - return (TabSheet) getSource(); - } - } - - /** - * Selected tab change event listener. The listener is called whenever - * another tab is selected, including when adding the first tab to a - * tabsheet. - * - * @author Vaadin Ltd. - * - * @version - * @VERSION@ - * @since 3.0 - */ - public interface SelectedTabChangeListener extends Serializable { - - /** - * Selected (shown) tab in tab sheet has has been changed. - * - * @param event - * the selected tab change event. - */ - public void selectedTabChange(SelectedTabChangeEvent event); - } - - /** - * Adds a tab selection listener - * - * @param listener - * the Listener to be added. - */ - public void addListener(SelectedTabChangeListener listener) { - addListener(SelectedTabChangeEvent.class, listener, - SELECTED_TAB_CHANGE_METHOD); - } - - /** - * Removes a tab selection listener - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(SelectedTabChangeListener listener) { - removeListener(SelectedTabChangeEvent.class, listener, - SELECTED_TAB_CHANGE_METHOD); - } - - /** - * Sends an event that the currently selected tab has changed. - */ - protected void fireSelectedTabChange() { - fireEvent(new SelectedTabChangeEvent(this)); - } - - /** - * Tab meta-data for a component in a {@link TabSheet}. - * - * The meta-data includes the tab caption, icon, visibility and enabledness, - * closability, description (tooltip) and an optional component error shown - * in the tab. - * - * Tabs are identified by the component contained on them in most cases, and - * the meta-data can be obtained with {@link TabSheet#getTab(Component)}. - */ - public interface Tab extends Serializable { - /** - * Returns the visible status for the tab. An invisible tab is not shown - * in the tab bar and cannot be selected. - * - * @return true for visible, false for hidden - */ - public boolean isVisible(); - - /** - * Sets the visible status for the tab. An invisible tab is not shown in - * the tab bar and cannot be selected, selection is changed - * automatically when there is an attempt to select an invisible tab. - * - * @param visible - * true for visible, false for hidden - */ - public void setVisible(boolean visible); - - /** - * Returns the closability status for the tab. - * - * @return true if the tab is allowed to be closed by the end user, - * false for not allowing closing - */ - public boolean isClosable(); - - /** - * Sets the closability status for the tab. A closable tab can be closed - * by the user through the user interface. This also controls if a close - * button is shown to the user or not. - * <p> - * Note! Currently only supported by TabSheet, not Accordion. - * </p> - * - * @param visible - * true if the end user is allowed to close the tab, false - * for not allowing to close. Should default to false. - */ - public void setClosable(boolean closable); - - /** - * Returns the enabled status for the tab. A disabled tab is shown as - * such in the tab bar and cannot be selected. - * - * @return true for enabled, false for disabled - */ - public boolean isEnabled(); - - /** - * Sets the enabled status for the tab. A disabled tab is shown as such - * in the tab bar and cannot be selected. - * - * @param enabled - * true for enabled, false for disabled - */ - public void setEnabled(boolean enabled); - - /** - * Sets the caption for the tab. - * - * @param caption - * the caption to set - */ - public void setCaption(String caption); - - /** - * Gets the caption for the tab. - */ - public String getCaption(); - - /** - * Gets the icon for the tab. - */ - public Resource getIcon(); - - /** - * Sets the icon for the tab. - * - * @param icon - * the icon to set - */ - public void setIcon(Resource icon); - - /** - * Gets the description for the tab. The description can be used to - * briefly describe the state of the tab to the user, and is typically - * shown as a tooltip when hovering over the tab. - * - * @return the description for the tab - */ - public String getDescription(); - - /** - * Sets the description for the tab. The description can be used to - * briefly describe the state of the tab to the user, and is typically - * shown as a tooltip when hovering over the tab. - * - * @param description - * the new description string for the tab. - */ - public void setDescription(String description); - - /** - * Sets an error indicator to be shown in the tab. This can be used e.g. - * to communicate to the user that there is a problem in the contents of - * the tab. - * - * @see AbstractComponent#setComponentError(ErrorMessage) - * - * @param componentError - * error message or null for none - */ - public void setComponentError(ErrorMessage componentError); - - /** - * Gets the current error message shown for the tab. - * - * TODO currently not sent to the client - * - * @see AbstractComponent#setComponentError(ErrorMessage) - */ - public ErrorMessage getComponentError(); - - /** - * Get the component related to the Tab - */ - public Component getComponent(); - - /** - * Sets a style name for the tab. The style name will be rendered as a - * HTML class name, which can be used in a CSS definition. - * - * <pre> - * Tab tab = tabsheet.addTab(tabContent, "Tab text"); - * tab.setStyleName("mystyle"); - * </pre> - * <p> - * The used style name will be prefixed with " - * {@code v-tabsheet-tabitemcell-}". For example, if you give a tab the - * style "{@code mystyle}", the tab will get a " - * {@code v-tabsheet-tabitemcell-mystyle}" style. You could then style - * the component with: - * </p> - * - * <pre> - * .v-tabsheet-tabitemcell-mystyle {font-style: italic;} - * </pre> - * - * <p> - * This method will trigger a {@link RepaintRequestEvent} on the - * TabSheet to which the Tab belongs. - * </p> - * - * @param styleName - * the new style to be set for tab - * @see #getStyleName() - */ - public void setStyleName(String styleName); - - /** - * Gets the user-defined CSS style name of the tab. Built-in style names - * defined in Vaadin or GWT are not returned. - * - * @return the style name or of the tab - * @see #setStyleName(String) - */ - public String getStyleName(); - } - - /** - * TabSheet's implementation of {@link Tab} - tab metadata. - */ - public class TabSheetTabImpl implements Tab { - - private String caption = ""; - private Resource icon = null; - private boolean enabled = true; - private boolean visible = true; - private boolean closable = false; - private String description = null; - private ErrorMessage componentError = null; - private String styleName; - - public TabSheetTabImpl(String caption, Resource icon) { - if (caption == null) { - caption = ""; - } - this.caption = caption; - this.icon = icon; - } - - /** - * Returns the tab caption. Can never be null. - */ - - @Override - public String getCaption() { - return caption; - } - - @Override - public void setCaption(String caption) { - this.caption = caption; - requestRepaint(); - } - - @Override - public Resource getIcon() { - return icon; - } - - @Override - public void setIcon(Resource icon) { - this.icon = icon; - requestRepaint(); - } - - @Override - public boolean isEnabled() { - return enabled; - } - - @Override - public void setEnabled(boolean enabled) { - this.enabled = enabled; - if (updateSelection()) { - fireSelectedTabChange(); - } - requestRepaint(); - } - - @Override - public boolean isVisible() { - return visible; - } - - @Override - public void setVisible(boolean visible) { - this.visible = visible; - if (updateSelection()) { - fireSelectedTabChange(); - } - requestRepaint(); - } - - @Override - public boolean isClosable() { - return closable; - } - - @Override - public void setClosable(boolean closable) { - this.closable = closable; - requestRepaint(); - } - - public void close() { - - } - - @Override - public String getDescription() { - return description; - } - - @Override - public void setDescription(String description) { - this.description = description; - requestRepaint(); - } - - @Override - public ErrorMessage getComponentError() { - return componentError; - } - - @Override - public void setComponentError(ErrorMessage componentError) { - this.componentError = componentError; - requestRepaint(); - } - - @Override - public Component getComponent() { - for (Map.Entry<Component, Tab> entry : tabs.entrySet()) { - if (entry.getValue() == this) { - return entry.getKey(); - } - } - return null; - } - - @Override - public void setStyleName(String styleName) { - this.styleName = styleName; - requestRepaint(); - } - - @Override - public String getStyleName() { - return styleName; - } - } - - /** - * CloseHandler is used to process tab closing events. Default behavior is - * to remove the tab from the TabSheet. - * - * @author Jouni Koivuviita / Vaadin Ltd. - * @since 6.2.0 - * - */ - public interface CloseHandler extends Serializable { - - /** - * Called when a user has pressed the close icon of a tab in the client - * side widget. - * - * @param tabsheet - * the TabSheet to which the tab belongs to - * @param tabContent - * the component that corresponds to the tab whose close - * button was clicked - */ - void onTabClose(final TabSheet tabsheet, final Component tabContent); - } - - /** - * Provide a custom {@link CloseHandler} for this TabSheet if you wish to - * perform some additional tasks when a user clicks on a tabs close button, - * e.g. show a confirmation dialogue before removing the tab. - * - * To remove the tab, if you provide your own close handler, you must call - * {@link #removeComponent(Component)} yourself. - * - * The default CloseHandler for TabSheet will only remove the tab. - * - * @param handler - */ - public void setCloseHandler(CloseHandler handler) { - closeHandler = handler; - } - - /** - * Sets the position of the tab. - * - * @param tab - * The tab - * @param position - * The new position of the tab - */ - public void setTabPosition(Tab tab, int position) { - int oldPosition = getTabPosition(tab); - components.remove(oldPosition); - components.add(position, tab.getComponent()); - requestRepaint(); - } - - /** - * Gets the position of the tab - * - * @param tab - * The tab - * @return - */ - public int getTabPosition(Tab tab) { - return components.indexOf(tab.getComponent()); - } - - @Override - public void focus() { - super.focus(); - } - - @Override - public int getTabIndex() { - return tabIndex; - } - - @Override - public void setTabIndex(int tabIndex) { - this.tabIndex = tabIndex; - requestRepaint(); - } - - @Override - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - @Override - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - @Override - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - @Override - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - - } - - @Override - public boolean isComponentVisible(Component childComponent) { - return childComponent == getSelectedTab(); - } - - /** - * Copies properties from one Tab to another. - * - * @param from - * The tab whose data to copy. - * @param to - * The tab to which copy the data. - */ - private static void copyTabMetadata(Tab from, Tab to) { - to.setCaption(from.getCaption()); - to.setIcon(from.getIcon()); - to.setDescription(from.getDescription()); - to.setVisible(from.isVisible()); - to.setEnabled(from.isEnabled()); - to.setClosable(from.isClosable()); - to.setStyleName(from.getStyleName()); - to.setComponentError(from.getComponentError()); - } -} diff --git a/src/com/vaadin/ui/Table.java b/src/com/vaadin/ui/Table.java deleted file mode 100644 index 39b7fb7473..0000000000 --- a/src/com/vaadin/ui/Table.java +++ /dev/null @@ -1,5449 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.logging.Level; -import java.util.logging.Logger; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.Property; -import com.vaadin.data.util.ContainerOrderedWrapper; -import com.vaadin.data.util.IndexedContainer; -import com.vaadin.data.util.converter.Converter; -import com.vaadin.data.util.converter.ConverterUtil; -import com.vaadin.event.Action; -import com.vaadin.event.Action.Handler; -import com.vaadin.event.DataBoundTransferable; -import com.vaadin.event.ItemClickEvent; -import com.vaadin.event.ItemClickEvent.ItemClickListener; -import com.vaadin.event.ItemClickEvent.ItemClickNotifier; -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.DragSource; -import com.vaadin.event.dd.DropHandler; -import com.vaadin.event.dd.DropTarget; -import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.terminal.KeyMapper; -import com.vaadin.terminal.LegacyPaint; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.table.VScrollTable; - -/** - * <p> - * <code>Table</code> is used for representing data or components in a pageable - * and selectable table. - * </p> - * - * <p> - * Scalability of the Table is largely dictated by the container. A table does - * not have a limit for the number of items and is just as fast with hundreds of - * thousands of items as with just a few. The current GWT implementation with - * scrolling however limits the number of rows to around 500000, depending on - * the browser and the pixel height of rows. - * </p> - * - * <p> - * Components in a Table will not have their caption nor icon rendered. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings({ "deprecation" }) -public class Table extends AbstractSelect implements Action.Container, - Container.Ordered, Container.Sortable, ItemClickNotifier, DragSource, - DropTarget, HasComponents { - - private transient Logger logger = null; - - /** - * Modes that Table support as drag sourse. - */ - public enum TableDragMode { - /** - * Table does not start drag and drop events. HTM5 style events started - * by browser may still happen. - */ - NONE, - /** - * Table starts drag with a one row only. - */ - ROW, - /** - * Table drags selected rows, if drag starts on a selected rows. Else it - * starts like in ROW mode. Note, that in Transferable there will still - * be only the row on which the drag started, other dragged rows need to - * be checked from the source Table. - */ - MULTIROW - } - - protected static final int CELL_KEY = 0; - - protected static final int CELL_HEADER = 1; - - protected static final int CELL_ICON = 2; - - protected static final int CELL_ITEMID = 3; - - protected static final int CELL_GENERATED_ROW = 4; - - protected static final int CELL_FIRSTCOL = 5; - - public enum Align { - /** - * Left column alignment. <b>This is the default behaviour. </b> - */ - LEFT("b"), - - /** - * Center column alignment. - */ - CENTER("c"), - - /** - * Right column alignment. - */ - RIGHT("e"); - - private String alignment; - - private Align(String alignment) { - this.alignment = alignment; - } - - @Override - public String toString() { - return alignment; - } - - public Align convertStringToAlign(String string) { - if (string == null) { - return null; - } - if (string.equals("b")) { - return Align.LEFT; - } else if (string.equals("c")) { - return Align.CENTER; - } else if (string.equals("e")) { - return Align.RIGHT; - } else { - return null; - } - } - } - - /** - * @deprecated from 7.0, use {@link Align#LEFT} instead - */ - @Deprecated - public static final Align ALIGN_LEFT = Align.LEFT; - - /** - * @deprecated from 7.0, use {@link Align#CENTER} instead - */ - @Deprecated - public static final Align ALIGN_CENTER = Align.CENTER; - - /** - * @deprecated from 7.0, use {@link Align#RIGHT} instead - */ - @Deprecated - public static final Align ALIGN_RIGHT = Align.RIGHT; - - public enum ColumnHeaderMode { - /** - * Column headers are hidden. - */ - HIDDEN, - /** - * Property ID:s are used as column headers. - */ - ID, - /** - * Column headers are explicitly specified with - * {@link #setColumnHeaders(String[])}. - */ - EXPLICIT, - /** - * Column headers are explicitly specified with - * {@link #setColumnHeaders(String[])}. If a header is not specified for - * a given property, its property id is used instead. - * <p> - * <b>This is the default behavior. </b> - */ - EXPLICIT_DEFAULTS_ID - } - - /** - * @deprecated from 7.0, use {@link ColumnHeaderMode#HIDDEN} instead - */ - @Deprecated - public static final ColumnHeaderMode COLUMN_HEADER_MODE_HIDDEN = ColumnHeaderMode.HIDDEN; - - /** - * @deprecated from 7.0, use {@link ColumnHeaderMode#ID} instead - */ - @Deprecated - public static final ColumnHeaderMode COLUMN_HEADER_MODE_ID = ColumnHeaderMode.ID; - - /** - * @deprecated from 7.0, use {@link ColumnHeaderMode#EXPLICIT} instead - */ - @Deprecated - public static final ColumnHeaderMode COLUMN_HEADER_MODE_EXPLICIT = ColumnHeaderMode.EXPLICIT; - - /** - * @deprecated from 7.0, use {@link ColumnHeaderMode#EXPLICIT_DEFAULTS_ID} - * instead - */ - @Deprecated - public static final ColumnHeaderMode COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID = ColumnHeaderMode.EXPLICIT_DEFAULTS_ID; - - public enum RowHeaderMode { - /** - * Row caption mode: The row headers are hidden. <b>This is the default - * mode. </b> - */ - HIDDEN(null), - /** - * Row caption mode: Items Id-objects toString is used as row caption. - */ - ID(ItemCaptionMode.ID), - /** - * Row caption mode: Item-objects toString is used as row caption. - */ - ITEM(ItemCaptionMode.ITEM), - /** - * Row caption mode: Index of the item is used as item caption. The - * index mode can only be used with the containers implementing the - * {@link com.vaadin.data.Container.Indexed} interface. - */ - INDEX(ItemCaptionMode.INDEX), - /** - * Row caption mode: Item captions are explicitly specified, but if the - * caption is missing, the item id objects <code>toString()</code> is - * used instead. - */ - EXPLICIT_DEFAULTS_ID(ItemCaptionMode.EXPLICIT_DEFAULTS_ID), - /** - * Row caption mode: Item captions are explicitly specified. - */ - EXPLICIT(ItemCaptionMode.EXPLICIT), - /** - * Row caption mode: Only icons are shown, the captions are hidden. - */ - ICON_ONLY(ItemCaptionMode.ICON_ONLY), - /** - * Row caption mode: Item captions are read from property specified with - * {@link #setItemCaptionPropertyId(Object)}. - */ - PROPERTY(ItemCaptionMode.PROPERTY); - - ItemCaptionMode mode; - - private RowHeaderMode(ItemCaptionMode mode) { - this.mode = mode; - } - - public ItemCaptionMode getItemCaptionMode() { - return mode; - } - } - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#HIDDEN} instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_HIDDEN = RowHeaderMode.HIDDEN; - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#ID} instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_ID = RowHeaderMode.ID; - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#ITEM} instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_ITEM = RowHeaderMode.ITEM; - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#INDEX} instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_INDEX = RowHeaderMode.INDEX; - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#EXPLICIT_DEFAULTS_ID} - * instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID = RowHeaderMode.EXPLICIT_DEFAULTS_ID; - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#EXPLICIT} instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_EXPLICIT = RowHeaderMode.EXPLICIT; - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#ICON_ONLY} instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_ICON_ONLY = RowHeaderMode.ICON_ONLY; - - /** - * @deprecated from 7.0, use {@link RowHeaderMode#PROPERTY} instead - */ - @Deprecated - public static final RowHeaderMode ROW_HEADER_MODE_PROPERTY = RowHeaderMode.PROPERTY; - - /** - * The default rate that table caches rows for smooth scrolling. - */ - private static final double CACHE_RATE_DEFAULT = 2; - - private static final String ROW_HEADER_COLUMN_KEY = "0"; - private static final Object ROW_HEADER_FAKE_PROPERTY_ID = new UniqueSerializable() { - }; - - /* Private table extensions to Select */ - - /** - * True if column collapsing is allowed. - */ - private boolean columnCollapsingAllowed = false; - - /** - * True if reordering of columns is allowed on the client side. - */ - private boolean columnReorderingAllowed = false; - - /** - * Keymapper for column ids. - */ - private final KeyMapper<Object> columnIdMap = new KeyMapper<Object>(); - - /** - * Holds visible column propertyIds - in order. - */ - private LinkedList<Object> visibleColumns = new LinkedList<Object>(); - - /** - * Holds noncollapsible columns. - */ - private HashSet<Object> noncollapsibleColumns = new HashSet<Object>(); - - /** - * Holds propertyIds of currently collapsed columns. - */ - private final HashSet<Object> collapsedColumns = new HashSet<Object>(); - - /** - * Holds headers for visible columns (by propertyId). - */ - private final HashMap<Object, String> columnHeaders = new HashMap<Object, String>(); - - /** - * Holds footers for visible columns (by propertyId). - */ - private final HashMap<Object, String> columnFooters = new HashMap<Object, String>(); - - /** - * Holds icons for visible columns (by propertyId). - */ - private final HashMap<Object, Resource> columnIcons = new HashMap<Object, Resource>(); - - /** - * Holds alignments for visible columns (by propertyId). - */ - private HashMap<Object, Align> columnAlignments = new HashMap<Object, Align>(); - - /** - * Holds column widths in pixels (Integer) or expand ratios (Float) for - * visible columns (by propertyId). - */ - private final HashMap<Object, Object> columnWidths = new HashMap<Object, Object>(); - - /** - * Holds column generators - */ - private final HashMap<Object, ColumnGenerator> columnGenerators = new LinkedHashMap<Object, ColumnGenerator>(); - - /** - * Holds value of property pageLength. 0 disables paging. - */ - private int pageLength = 15; - - /** - * Id the first item on the current page. - */ - private Object currentPageFirstItemId = null; - - /** - * Index of the first item on the current page. - */ - private int currentPageFirstItemIndex = 0; - - /** - * Holds value of property selectable. - */ - private boolean selectable = false; - - /** - * Holds value of property columnHeaderMode. - */ - private ColumnHeaderMode columnHeaderMode = ColumnHeaderMode.EXPLICIT_DEFAULTS_ID; - - /** - * Holds value of property rowHeaderMode. - */ - private RowHeaderMode rowHeaderMode = RowHeaderMode.EXPLICIT_DEFAULTS_ID; - - /** - * Should the Table footer be visible? - */ - private boolean columnFootersVisible = false; - - /** - * Page contents buffer used in buffered mode. - */ - private Object[][] pageBuffer = null; - - /** - * Set of properties listened - the list is kept to release the listeners - * later. - */ - private HashSet<Property<?>> listenedProperties = null; - - /** - * Set of visible components - the is used for needsRepaint calculation. - */ - private HashSet<Component> visibleComponents = null; - - /** - * List of action handlers. - */ - private LinkedList<Handler> actionHandlers = null; - - /** - * Action mapper. - */ - private KeyMapper<Action> actionMapper = null; - - /** - * Table cell editor factory. - */ - private TableFieldFactory fieldFactory = DefaultFieldFactory.get(); - - /** - * Is table editable. - */ - private boolean editable = false; - - /** - * Current sorting direction. - */ - private boolean sortAscending = true; - - /** - * Currently table is sorted on this propertyId. - */ - private Object sortContainerPropertyId = null; - - /** - * Is table sorting by the user enabled. - */ - private boolean sortEnabled = true; - - /** - * Number of rows explicitly requested by the client to be painted on next - * paint. This is -1 if no request by the client is made. Painting the - * component will automatically reset this to -1. - */ - private int reqRowsToPaint = -1; - - /** - * Index of the first rows explicitly requested by the client to be painted. - * This is -1 if no request by the client is made. Painting the component - * will automatically reset this to -1. - */ - private int reqFirstRowToPaint = -1; - - private int firstToBeRenderedInClient = -1; - - private int lastToBeRenderedInClient = -1; - - private boolean isContentRefreshesEnabled = true; - - private int pageBufferFirstIndex; - - private boolean containerChangeToBeRendered = false; - - /** - * Table cell specific style generator - */ - private CellStyleGenerator cellStyleGenerator = null; - - /** - * Table cell specific tooltip generator - */ - private ItemDescriptionGenerator itemDescriptionGenerator; - - /* - * EXPERIMENTAL feature: will tell the client to re-calculate column widths - * if set to true. Currently no setter: extend to enable. - */ - protected boolean alwaysRecalculateColumnWidths = false; - - private double cacheRate = CACHE_RATE_DEFAULT; - - private TableDragMode dragMode = TableDragMode.NONE; - - private DropHandler dropHandler; - - private MultiSelectMode multiSelectMode = MultiSelectMode.DEFAULT; - - private boolean rowCacheInvalidated; - - private RowGenerator rowGenerator = null; - - private final Map<Field<?>, Property<?>> associatedProperties = new HashMap<Field<?>, Property<?>>(); - - private boolean painted = false; - - private HashMap<Object, Converter<String, Object>> propertyValueConverters = new HashMap<Object, Converter<String, Object>>(); - - /** - * Set to true if the client-side should be informed that the key mapper has - * been reset so it can avoid sending back references to keys that are no - * longer present. - */ - private boolean keyMapperReset; - - /* Table constructors */ - - /** - * Creates a new empty table. - */ - public Table() { - setRowHeaderMode(ROW_HEADER_MODE_HIDDEN); - } - - /** - * Creates a new empty table with caption. - * - * @param caption - */ - public Table(String caption) { - this(); - setCaption(caption); - } - - /** - * Creates a new table with caption and connect it to a Container. - * - * @param caption - * @param dataSource - */ - public Table(String caption, Container dataSource) { - this(); - setCaption(caption); - setContainerDataSource(dataSource); - } - - /* Table functionality */ - - /** - * Gets the array of visible column id:s, including generated columns. - * - * <p> - * The columns are show in the order of their appearance in this array. - * </p> - * - * @return an array of currently visible propertyIds and generated column - * ids. - */ - public Object[] getVisibleColumns() { - if (visibleColumns == null) { - return null; - } - return visibleColumns.toArray(); - } - - /** - * Sets the array of visible column property id:s. - * - * <p> - * The columns are show in the order of their appearance in this array. - * </p> - * - * @param visibleColumns - * the Array of shown property id:s. - */ - public void setVisibleColumns(Object[] visibleColumns) { - - // Visible columns must exist - if (visibleColumns == null) { - throw new NullPointerException( - "Can not set visible columns to null value"); - } - - // TODO add error check that no duplicate identifiers exist - - // Checks that the new visible columns contains no nulls and properties - // exist - final Collection<?> properties = getContainerPropertyIds(); - for (int i = 0; i < visibleColumns.length; i++) { - if (visibleColumns[i] == null) { - throw new NullPointerException("Ids must be non-nulls"); - } else if (!properties.contains(visibleColumns[i]) - && !columnGenerators.containsKey(visibleColumns[i])) { - throw new IllegalArgumentException( - "Ids must exist in the Container or as a generated column , missing id: " - + visibleColumns[i]); - } - } - - // If this is called before the constructor is finished, it might be - // uninitialized - final LinkedList<Object> newVC = new LinkedList<Object>(); - for (int i = 0; i < visibleColumns.length; i++) { - newVC.add(visibleColumns[i]); - } - - // Removes alignments, icons and headers from hidden columns - if (this.visibleColumns != null) { - boolean disabledHere = disableContentRefreshing(); - try { - for (final Iterator<Object> i = this.visibleColumns.iterator(); i - .hasNext();) { - final Object col = i.next(); - if (!newVC.contains(col)) { - setColumnHeader(col, null); - setColumnAlignment(col, (Align) null); - setColumnIcon(col, null); - } - } - } finally { - if (disabledHere) { - enableContentRefreshing(false); - } - } - } - - this.visibleColumns = newVC; - - // Assures visual refresh - refreshRowCache(); - } - - /** - * Gets the headers of the columns. - * - * <p> - * The headers match the property id:s given my the set visible column - * headers. The table must be set in either - * {@link #COLUMN_HEADER_MODE_EXPLICIT} or - * {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the - * headers. In the defaults mode any nulls in the headers array are replaced - * with id.toString(). - * </p> - * - * @return the Array of column headers. - */ - public String[] getColumnHeaders() { - if (columnHeaders == null) { - return null; - } - final String[] headers = new String[visibleColumns.size()]; - int i = 0; - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext(); i++) { - headers[i] = getColumnHeader(it.next()); - } - return headers; - } - - /** - * Sets the headers of the columns. - * - * <p> - * The headers match the property id:s given my the set visible column - * headers. The table must be set in either - * {@link #COLUMN_HEADER_MODE_EXPLICIT} or - * {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the - * headers. In the defaults mode any nulls in the headers array are replaced - * with id.toString() outputs when rendering. - * </p> - * - * @param columnHeaders - * the Array of column headers that match the - * {@link #getVisibleColumns()} method. - */ - public void setColumnHeaders(String[] columnHeaders) { - - if (columnHeaders.length != visibleColumns.size()) { - throw new IllegalArgumentException( - "The length of the headers array must match the number of visible columns"); - } - - this.columnHeaders.clear(); - int i = 0; - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext() && i < columnHeaders.length; i++) { - this.columnHeaders.put(it.next(), columnHeaders[i]); - } - - requestRepaint(); - } - - /** - * Gets the icons of the columns. - * - * <p> - * The icons in headers match the property id:s given my the set visible - * column headers. The table must be set in either - * {@link #COLUMN_HEADER_MODE_EXPLICIT} or - * {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the headers - * with icons. - * </p> - * - * @return the Array of icons that match the {@link #getVisibleColumns()}. - */ - public Resource[] getColumnIcons() { - if (columnIcons == null) { - return null; - } - final Resource[] icons = new Resource[visibleColumns.size()]; - int i = 0; - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext(); i++) { - icons[i] = columnIcons.get(it.next()); - } - - return icons; - } - - /** - * Sets the icons of the columns. - * - * <p> - * The icons in headers match the property id:s given my the set visible - * column headers. The table must be set in either - * {@link #COLUMN_HEADER_MODE_EXPLICIT} or - * {@link #COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID} mode to show the headers - * with icons. - * </p> - * - * @param columnIcons - * the Array of icons that match the {@link #getVisibleColumns()} - * . - */ - public void setColumnIcons(Resource[] columnIcons) { - - if (columnIcons.length != visibleColumns.size()) { - throw new IllegalArgumentException( - "The length of the icons array must match the number of visible columns"); - } - - this.columnIcons.clear(); - int i = 0; - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext() && i < columnIcons.length; i++) { - this.columnIcons.put(it.next(), columnIcons[i]); - } - - requestRepaint(); - } - - /** - * Gets the array of column alignments. - * - * <p> - * The items in the array must match the properties identified by - * {@link #getVisibleColumns()}. The possible values for the alignments - * include: - * <ul> - * <li>{@link Align#LEFT}: Left alignment</li> - * <li>{@link Align#CENTER}: Centered</li> - * <li>{@link Align#RIGHT}: Right alignment</li> - * </ul> - * The alignments default to {@link Align#LEFT}: any null values are - * rendered as align lefts. - * </p> - * - * @return the Column alignments array. - */ - public Align[] getColumnAlignments() { - if (columnAlignments == null) { - return null; - } - final Align[] alignments = new Align[visibleColumns.size()]; - int i = 0; - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext(); i++) { - alignments[i] = getColumnAlignment(it.next()); - } - - return alignments; - } - - /** - * Sets the column alignments. - * - * <p> - * The amount of items in the array must match the amount of properties - * identified by {@link #getVisibleColumns()}. The possible values for the - * alignments include: - * <ul> - * <li>{@link Align#LEFT}: Left alignment</li> - * <li>{@link Align#CENTER}: Centered</li> - * <li>{@link Align#RIGHT}: Right alignment</li> - * </ul> - * The alignments default to {@link Align#LEFT} - * </p> - * - * @param columnAlignments - * the Column alignments array. - */ - public void setColumnAlignments(Align... columnAlignments) { - - if (columnAlignments.length != visibleColumns.size()) { - throw new IllegalArgumentException( - "The length of the alignments array must match the number of visible columns"); - } - - // Resets the alignments - final HashMap<Object, Align> newCA = new HashMap<Object, Align>(); - int i = 0; - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext() && i < columnAlignments.length; i++) { - newCA.put(it.next(), columnAlignments[i]); - } - this.columnAlignments = newCA; - - // Assures the visual refresh. No need to reset the page buffer before - // as the content has not changed, only the alignments. - refreshRenderedCells(); - } - - /** - * Sets columns width (in pixels). Theme may not necessary respect very - * small or very big values. Setting width to -1 (default) means that theme - * will make decision of width. - * - * <p> - * Column can either have a fixed width or expand ratio. The latter one set - * is used. See @link {@link #setColumnExpandRatio(Object, float)}. - * - * @param propertyId - * colunmns property id - * @param width - * width to be reserved for colunmns content - * @since 4.0.3 - */ - public void setColumnWidth(Object propertyId, int width) { - if (propertyId == null) { - // Since propertyId is null, this is the row header. Use the magic - // id to store the width of the row header. - propertyId = ROW_HEADER_FAKE_PROPERTY_ID; - } - if (width < 0) { - columnWidths.remove(propertyId); - } else { - columnWidths.put(propertyId, Integer.valueOf(width)); - } - requestRepaint(); - } - - /** - * Sets the column expand ratio for given column. - * <p> - * Expand ratios can be defined to customize the way how excess space is - * divided among columns. Table can have excess space if it has its width - * defined and there is horizontally more space than columns consume - * naturally. Excess space is the space that is not used by columns with - * explicit width (see {@link #setColumnWidth(Object, int)}) or with natural - * width (no width nor expand ratio). - * - * <p> - * By default (without expand ratios) the excess space is divided - * proportionally to columns natural widths. - * - * <p> - * Only expand ratios of visible columns are used in final calculations. - * - * <p> - * Column can either have a fixed width or expand ratio. The latter one set - * is used. - * - * <p> - * A column with expand ratio is considered to be minimum width by default - * (if no excess space exists). The minimum width is defined by terminal - * implementation. - * - * <p> - * If terminal implementation supports re-sizable columns the column becomes - * fixed width column if users resizes the column. - * - * @param propertyId - * columns property id - * @param expandRatio - * the expandRatio used to divide excess space for this column - */ - public void setColumnExpandRatio(Object propertyId, float expandRatio) { - if (expandRatio < 0) { - columnWidths.remove(propertyId); - } else { - columnWidths.put(propertyId, new Float(expandRatio)); - } - } - - public float getColumnExpandRatio(Object propertyId) { - final Object width = columnWidths.get(propertyId); - if (width == null || !(width instanceof Float)) { - return -1; - } - final Float value = (Float) width; - return value.floatValue(); - - } - - /** - * Gets the pixel width of column - * - * @param propertyId - * @return width of column or -1 when value not set - */ - public int getColumnWidth(Object propertyId) { - if (propertyId == null) { - // Since propertyId is null, this is the row header. Use the magic - // id to retrieve the width of the row header. - propertyId = ROW_HEADER_FAKE_PROPERTY_ID; - } - final Object width = columnWidths.get(propertyId); - if (width == null || !(width instanceof Integer)) { - return -1; - } - final Integer value = (Integer) width; - return value.intValue(); - } - - /** - * Gets the page length. - * - * <p> - * Setting page length 0 disables paging. - * </p> - * - * @return the Length of one page. - */ - public int getPageLength() { - return pageLength; - } - - /** - * Sets the page length. - * - * <p> - * Setting page length 0 disables paging. The page length defaults to 15. - * </p> - * - * <p> - * If Table has width set ({@link #setWidth(float, int)} ) the client side - * may update the page length automatically the correct value. - * </p> - * - * @param pageLength - * the length of one page. - */ - public void setPageLength(int pageLength) { - if (pageLength >= 0 && this.pageLength != pageLength) { - this.pageLength = pageLength; - // Assures the visual refresh - refreshRowCache(); - } - } - - /** - * This method adjusts a possible caching mechanism of table implementation. - * - * <p> - * Table component may fetch and render some rows outside visible area. With - * complex tables (for example containing layouts and components), the - * client side may become unresponsive. Setting the value lower, UI will - * become more responsive. With higher values scrolling in client will hit - * server less frequently. - * - * <p> - * The amount of cached rows will be cacheRate multiplied with pageLength ( - * {@link #setPageLength(int)} both below and above visible area.. - * - * @param cacheRate - * a value over 0 (fastest rendering time). Higher value will - * cache more rows on server (smoother scrolling). Default value - * is 2. - */ - public void setCacheRate(double cacheRate) { - if (cacheRate < 0) { - throw new IllegalArgumentException( - "cacheRate cannot be less than zero"); - } - if (this.cacheRate != cacheRate) { - this.cacheRate = cacheRate; - requestRepaint(); - } - } - - /** - * @see #setCacheRate(double) - * - * @return the current cache rate value - */ - public double getCacheRate() { - return cacheRate; - } - - /** - * Getter for property currentPageFirstItem. - * - * @return the Value of property currentPageFirstItem. - */ - public Object getCurrentPageFirstItemId() { - - // Priorise index over id if indexes are supported - if (items instanceof Container.Indexed) { - final int index = getCurrentPageFirstItemIndex(); - Object id = null; - if (index >= 0 && index < size()) { - id = getIdByIndex(index); - } - if (id != null && !id.equals(currentPageFirstItemId)) { - currentPageFirstItemId = id; - } - } - - // If there is no item id at all, use the first one - if (currentPageFirstItemId == null) { - currentPageFirstItemId = firstItemId(); - } - - return currentPageFirstItemId; - } - - protected Object getIdByIndex(int index) { - return ((Container.Indexed) items).getIdByIndex(index); - } - - /** - * Setter for property currentPageFirstItemId. - * - * @param currentPageFirstItemId - * the New value of property currentPageFirstItemId. - */ - public void setCurrentPageFirstItemId(Object currentPageFirstItemId) { - - // Gets the corresponding index - int index = -1; - if (items instanceof Container.Indexed) { - index = indexOfId(currentPageFirstItemId); - } else { - // If the table item container does not have index, we have to - // calculates the index by hand - Object id = firstItemId(); - while (id != null && !id.equals(currentPageFirstItemId)) { - index++; - id = nextItemId(id); - } - if (id == null) { - index = -1; - } - } - - // If the search for item index was successful - if (index >= 0) { - /* - * The table is not capable of displaying an item in the container - * as the first if there are not enough items following the selected - * item so the whole table (pagelength) is filled. - */ - int maxIndex = size() - pageLength; - if (maxIndex < 0) { - maxIndex = 0; - } - - if (index > maxIndex) { - // Note that we pass index, not maxIndex, letting - // setCurrentPageFirstItemIndex handle the situation. - setCurrentPageFirstItemIndex(index); - return; - } - - this.currentPageFirstItemId = currentPageFirstItemId; - currentPageFirstItemIndex = index; - } - - // Assures the visual refresh - refreshRowCache(); - - } - - protected int indexOfId(Object itemId) { - return ((Container.Indexed) items).indexOfId(itemId); - } - - /** - * Gets the icon Resource for the specified column. - * - * @param propertyId - * the propertyId indentifying the column. - * @return the icon for the specified column; null if the column has no icon - * set, or if the column is not visible. - */ - public Resource getColumnIcon(Object propertyId) { - return columnIcons.get(propertyId); - } - - /** - * Sets the icon Resource for the specified column. - * <p> - * Throws IllegalArgumentException if the specified column is not visible. - * </p> - * - * @param propertyId - * the propertyId identifying the column. - * @param icon - * the icon Resource to set. - */ - public void setColumnIcon(Object propertyId, Resource icon) { - - if (icon == null) { - columnIcons.remove(propertyId); - } else { - columnIcons.put(propertyId, icon); - } - - requestRepaint(); - } - - /** - * Gets the header for the specified column. - * - * @param propertyId - * the propertyId identifying the column. - * @return the header for the specified column if it has one. - */ - public String getColumnHeader(Object propertyId) { - if (getColumnHeaderMode() == ColumnHeaderMode.HIDDEN) { - return null; - } - - String header = columnHeaders.get(propertyId); - if ((header == null && getColumnHeaderMode() == ColumnHeaderMode.EXPLICIT_DEFAULTS_ID) - || getColumnHeaderMode() == ColumnHeaderMode.ID) { - header = propertyId.toString(); - } - - return header; - } - - /** - * Sets the column header for the specified column; - * - * @param propertyId - * the propertyId identifying the column. - * @param header - * the header to set. - */ - public void setColumnHeader(Object propertyId, String header) { - - if (header == null) { - columnHeaders.remove(propertyId); - } else { - columnHeaders.put(propertyId, header); - } - - requestRepaint(); - } - - /** - * Gets the specified column's alignment. - * - * @param propertyId - * the propertyID identifying the column. - * @return the specified column's alignment if it as one; null otherwise. - */ - public Align getColumnAlignment(Object propertyId) { - final Align a = columnAlignments.get(propertyId); - return a == null ? Align.LEFT : a; - } - - /** - * Sets the specified column's alignment. - * - * <p> - * Throws IllegalArgumentException if the alignment is not one of the - * following: {@link Align#LEFT}, {@link Align#CENTER} or - * {@link Align#RIGHT} - * </p> - * - * @param propertyId - * the propertyID identifying the column. - * @param alignment - * the desired alignment. - */ - public void setColumnAlignment(Object propertyId, Align alignment) { - if (alignment == null || alignment == Align.LEFT) { - columnAlignments.remove(propertyId); - } else { - columnAlignments.put(propertyId, alignment); - } - - // Assures the visual refresh. No need to reset the page buffer before - // as the content has not changed, only the alignments. - refreshRenderedCells(); - } - - /** - * Checks if the specified column is collapsed. - * - * @param propertyId - * the propertyID identifying the column. - * @return true if the column is collapsed; false otherwise; - */ - public boolean isColumnCollapsed(Object propertyId) { - return collapsedColumns != null - && collapsedColumns.contains(propertyId); - } - - /** - * Sets whether the specified column is collapsed or not. - * - * - * @param propertyId - * the propertyID identifying the column. - * @param collapsed - * the desired collapsedness. - * @throws IllegalStateException - * if column collapsing is not allowed - */ - public void setColumnCollapsed(Object propertyId, boolean collapsed) - throws IllegalStateException { - if (!isColumnCollapsingAllowed()) { - throw new IllegalStateException("Column collapsing not allowed!"); - } - if (collapsed && noncollapsibleColumns.contains(propertyId)) { - throw new IllegalStateException("The column is noncollapsible!"); - } - - if (collapsed) { - collapsedColumns.add(propertyId); - } else { - collapsedColumns.remove(propertyId); - } - - // Assures the visual refresh - refreshRowCache(); - } - - /** - * Checks if column collapsing is allowed. - * - * @return true if columns can be collapsed; false otherwise. - */ - public boolean isColumnCollapsingAllowed() { - return columnCollapsingAllowed; - } - - /** - * Sets whether column collapsing is allowed or not. - * - * @param collapsingAllowed - * specifies whether column collapsing is allowed. - */ - public void setColumnCollapsingAllowed(boolean collapsingAllowed) { - columnCollapsingAllowed = collapsingAllowed; - - if (!collapsingAllowed) { - collapsedColumns.clear(); - } - - // Assures the visual refresh. No need to reset the page buffer before - // as the content has not changed, only the alignments. - refreshRenderedCells(); - } - - /** - * Sets whether the given column is collapsible. Note that collapsible - * columns can only be actually collapsed (via UI or with - * {@link #setColumnCollapsed(Object, boolean) setColumnCollapsed()}) if - * {@link #isColumnCollapsingAllowed()} is true. By default all columns are - * collapsible. - * - * @param propertyId - * the propertyID identifying the column. - * @param collapsible - * true if the column should be collapsible, false otherwise. - */ - public void setColumnCollapsible(Object propertyId, boolean collapsible) { - if (collapsible) { - noncollapsibleColumns.remove(propertyId); - } else { - noncollapsibleColumns.add(propertyId); - collapsedColumns.remove(propertyId); - } - refreshRowCache(); - } - - /** - * Checks if the given column is collapsible. Note that even if this method - * returns <code>true</code>, the column can only be actually collapsed (via - * UI or with {@link #setColumnCollapsed(Object, boolean) - * setColumnCollapsed()}) if {@link #isColumnCollapsingAllowed()} is also - * true. - * - * @return true if the column can be collapsed; false otherwise. - */ - public boolean isColumnCollapsible(Object propertyId) { - return !noncollapsibleColumns.contains(propertyId); - } - - /** - * Checks if column reordering is allowed. - * - * @return true if columns can be reordered; false otherwise. - */ - public boolean isColumnReorderingAllowed() { - return columnReorderingAllowed; - } - - /** - * Sets whether column reordering is allowed or not. - * - * @param columnReorderingAllowed - * specifies whether column reordering is allowed. - */ - public void setColumnReorderingAllowed(boolean columnReorderingAllowed) { - if (columnReorderingAllowed != this.columnReorderingAllowed) { - this.columnReorderingAllowed = columnReorderingAllowed; - requestRepaint(); - } - } - - /* - * Arranges visible columns according to given columnOrder. Silently ignores - * colimnId:s that are not visible columns, and keeps the internal order of - * visible columns left out of the ordering (trailing). Silently does - * nothing if columnReordering is not allowed. - */ - private void setColumnOrder(Object[] columnOrder) { - if (columnOrder == null || !isColumnReorderingAllowed()) { - return; - } - final LinkedList<Object> newOrder = new LinkedList<Object>(); - for (int i = 0; i < columnOrder.length; i++) { - if (columnOrder[i] != null - && visibleColumns.contains(columnOrder[i])) { - visibleColumns.remove(columnOrder[i]); - newOrder.add(columnOrder[i]); - } - } - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext();) { - final Object columnId = it.next(); - if (!newOrder.contains(columnId)) { - newOrder.add(columnId); - } - } - visibleColumns = newOrder; - - // Assure visual refresh - refreshRowCache(); - } - - /** - * Getter for property currentPageFirstItem. - * - * @return the Value of property currentPageFirstItem. - */ - public int getCurrentPageFirstItemIndex() { - return currentPageFirstItemIndex; - } - - void setCurrentPageFirstItemIndex(int newIndex, boolean needsPageBufferReset) { - - if (newIndex < 0) { - newIndex = 0; - } - - /* - * minimize Container.size() calls which may be expensive. For example - * it may cause sql query. - */ - final int size = size(); - - /* - * The table is not capable of displaying an item in the container as - * the first if there are not enough items following the selected item - * so the whole table (pagelength) is filled. - */ - int maxIndex = size - pageLength; - if (maxIndex < 0) { - maxIndex = 0; - } - - /* - * FIXME #7607 Take somehow into account the case where we want to - * scroll to the bottom so that the last row is completely visible even - * if (table height) / (row height) is not an integer. Reverted the - * original fix because of #8662 regression. - */ - if (newIndex > maxIndex) { - newIndex = maxIndex; - } - - // Refresh first item id - if (items instanceof Container.Indexed) { - try { - currentPageFirstItemId = getIdByIndex(newIndex); - } catch (final IndexOutOfBoundsException e) { - currentPageFirstItemId = null; - } - currentPageFirstItemIndex = newIndex; - } else { - - // For containers not supporting indexes, we must iterate the - // container forwards / backwards - // next available item forward or backward - - currentPageFirstItemId = firstItemId(); - - // Go forwards in the middle of the list (respect borders) - while (currentPageFirstItemIndex < newIndex - && !isLastId(currentPageFirstItemId)) { - currentPageFirstItemIndex++; - currentPageFirstItemId = nextItemId(currentPageFirstItemId); - } - - // If we did hit the border - if (isLastId(currentPageFirstItemId)) { - currentPageFirstItemIndex = size - 1; - } - - // Go backwards in the middle of the list (respect borders) - while (currentPageFirstItemIndex > newIndex - && !isFirstId(currentPageFirstItemId)) { - currentPageFirstItemIndex--; - currentPageFirstItemId = prevItemId(currentPageFirstItemId); - } - - // If we did hit the border - if (isFirstId(currentPageFirstItemId)) { - currentPageFirstItemIndex = 0; - } - - // Go forwards once more - while (currentPageFirstItemIndex < newIndex - && !isLastId(currentPageFirstItemId)) { - currentPageFirstItemIndex++; - currentPageFirstItemId = nextItemId(currentPageFirstItemId); - } - - // If for some reason we do hit border again, override - // the user index request - if (isLastId(currentPageFirstItemId)) { - newIndex = currentPageFirstItemIndex = size - 1; - } - } - if (needsPageBufferReset) { - // Assures the visual refresh - refreshRowCache(); - } - } - - /** - * Setter for property currentPageFirstItem. - * - * @param newIndex - * the New value of property currentPageFirstItem. - */ - public void setCurrentPageFirstItemIndex(int newIndex) { - setCurrentPageFirstItemIndex(newIndex, true); - } - - /** - * Getter for property pageBuffering. - * - * @deprecated functionality is not needed in ajax rendering model - * - * @return the Value of property pageBuffering. - */ - @Deprecated - public boolean isPageBufferingEnabled() { - return true; - } - - /** - * Setter for property pageBuffering. - * - * @deprecated functionality is not needed in ajax rendering model - * - * @param pageBuffering - * the New value of property pageBuffering. - */ - @Deprecated - public void setPageBufferingEnabled(boolean pageBuffering) { - - } - - /** - * Getter for property selectable. - * - * <p> - * The table is not selectable by default. - * </p> - * - * @return the Value of property selectable. - */ - public boolean isSelectable() { - return selectable; - } - - /** - * Setter for property selectable. - * - * <p> - * The table is not selectable by default. - * </p> - * - * @param selectable - * the New value of property selectable. - */ - public void setSelectable(boolean selectable) { - if (this.selectable != selectable) { - this.selectable = selectable; - requestRepaint(); - } - } - - /** - * Getter for property columnHeaderMode. - * - * @return the Value of property columnHeaderMode. - */ - public ColumnHeaderMode getColumnHeaderMode() { - return columnHeaderMode; - } - - /** - * Setter for property columnHeaderMode. - * - * @param columnHeaderMode - * the New value of property columnHeaderMode. - */ - public void setColumnHeaderMode(ColumnHeaderMode columnHeaderMode) { - if (columnHeaderMode == null) { - throw new IllegalArgumentException( - "Column header mode can not be null"); - } - if (columnHeaderMode != this.columnHeaderMode) { - this.columnHeaderMode = columnHeaderMode; - requestRepaint(); - } - - } - - /** - * Refreshes the rows in the internal cache. Only if - * {@link #resetPageBuffer()} is called before this then all values are - * guaranteed to be recreated. - */ - protected void refreshRenderedCells() { - if (getParent() == null) { - return; - } - - if (!isContentRefreshesEnabled) { - return; - } - - // Collects the basic facts about the table page - final int pagelen = getPageLength(); - int rows, totalRows; - rows = totalRows = size(); - int firstIndex = Math - .min(getCurrentPageFirstItemIndex(), totalRows - 1); - if (rows > 0 && firstIndex >= 0) { - rows -= firstIndex; - } - if (pagelen > 0 && pagelen < rows) { - rows = pagelen; - } - - // If "to be painted next" variables are set, use them - if (lastToBeRenderedInClient - firstToBeRenderedInClient > 0) { - rows = lastToBeRenderedInClient - firstToBeRenderedInClient + 1; - } - if (firstToBeRenderedInClient >= 0) { - if (firstToBeRenderedInClient < totalRows) { - firstIndex = firstToBeRenderedInClient; - } else { - firstIndex = totalRows - 1; - } - } else { - // initial load - - // #8805 send one extra row in the beginning in case a partial - // row is shown on the UI - if (firstIndex > 0) { - firstIndex = firstIndex - 1; - rows = rows + 1; - } - firstToBeRenderedInClient = firstIndex; - } - if (totalRows > 0) { - if (rows + firstIndex > totalRows) { - rows = totalRows - firstIndex; - } - } else { - rows = 0; - } - - // Saves the results to internal buffer - pageBuffer = getVisibleCellsNoCache(firstIndex, rows, true); - - if (rows > 0) { - pageBufferFirstIndex = firstIndex; - } - - setRowCacheInvalidated(true); - requestRepaint(); - } - - /** - * Requests that the Table should be repainted as soon as possible. - * - * Note that a {@code Table} does not necessarily repaint its contents when - * this method has been called. See {@link #refreshRowCache()} for forcing - * an update of the contents. - */ - - @Override - public void requestRepaint() { - // Overridden only for javadoc - super.requestRepaint(); - } - - @Override - public void requestRepaintAll() { - super.requestRepaintAll(); - - // Avoid sending a partial repaint (#8714) - refreshRowCache(); - } - - private void removeRowsFromCacheAndFillBottom(int firstIndex, int rows) { - int totalCachedRows = pageBuffer[CELL_ITEMID].length; - int totalRows = size(); - int firstIndexInPageBuffer = firstIndex - pageBufferFirstIndex; - - /* - * firstIndexInPageBuffer is the first row to be removed. "rows" rows - * after that should be removed. If the page buffer does not contain - * that many rows, we only remove the rows that actually are in the page - * buffer. - */ - if (firstIndexInPageBuffer + rows > totalCachedRows) { - rows = totalCachedRows - firstIndexInPageBuffer; - } - - /* - * Unregister components that will no longer be in the page buffer to - * make sure that no components leak. - */ - unregisterComponentsAndPropertiesInRows(firstIndex, rows); - - /* - * The number of rows that should be in the cache after this operation - * is done (pageBuffer currently contains the expanded items). - */ - int newCachedRowCount = totalCachedRows; - if (newCachedRowCount + pageBufferFirstIndex > totalRows) { - newCachedRowCount = totalRows - pageBufferFirstIndex; - } - - /* - * The index at which we should render the first row that does not come - * from the previous page buffer. - */ - int firstAppendedRowInPageBuffer = totalCachedRows - rows; - int firstAppendedRow = firstAppendedRowInPageBuffer - + pageBufferFirstIndex; - - /* - * Calculate the maximum number of new rows that we can add to the page - * buffer. Less than the rows we removed if the container does not - * contain that many items afterwards. - */ - int maxRowsToRender = (totalRows - firstAppendedRow); - int rowsToAdd = rows; - if (rowsToAdd > maxRowsToRender) { - rowsToAdd = maxRowsToRender; - } - - Object[][] cells = null; - if (rowsToAdd > 0) { - cells = getVisibleCellsNoCache(firstAppendedRow, rowsToAdd, false); - } - /* - * Create the new cache buffer by copying the first rows from the old - * buffer, moving the following rows upwards and appending more rows if - * applicable. - */ - Object[][] newPageBuffer = new Object[pageBuffer.length][newCachedRowCount]; - - for (int i = 0; i < pageBuffer.length; i++) { - for (int row = 0; row < firstIndexInPageBuffer; row++) { - // Copy the first rows - newPageBuffer[i][row] = pageBuffer[i][row]; - } - for (int row = firstIndexInPageBuffer; row < firstAppendedRowInPageBuffer; row++) { - // Move the rows that were after the expanded rows - newPageBuffer[i][row] = pageBuffer[i][row + rows]; - } - for (int row = firstAppendedRowInPageBuffer; row < newCachedRowCount; row++) { - // Add the newly rendered rows. Only used if rowsToAdd > 0 - // (cells != null) - newPageBuffer[i][row] = cells[i][row - - firstAppendedRowInPageBuffer]; - } - } - pageBuffer = newPageBuffer; - } - - private Object[][] getVisibleCellsUpdateCacheRows(int firstIndex, int rows) { - Object[][] cells = getVisibleCellsNoCache(firstIndex, rows, false); - int cacheIx = firstIndex - pageBufferFirstIndex; - // update the new rows in the cache. - int totalCachedRows = pageBuffer[CELL_ITEMID].length; - int end = Math.min(cacheIx + rows, totalCachedRows); - for (int ix = cacheIx; ix < end; ix++) { - for (int i = 0; i < pageBuffer.length; i++) { - pageBuffer[i][ix] = cells[i][ix - cacheIx]; - } - } - return cells; - } - - /** - * @param firstIndex - * The position where new rows should be inserted - * @param rows - * The maximum number of rows that should be inserted at position - * firstIndex. Less rows will be inserted if the page buffer is - * too small. - * @return - */ - private Object[][] getVisibleCellsInsertIntoCache(int firstIndex, int rows) { - getLogger().finest( - "Insert " + rows + " rows at index " + firstIndex - + " to existing page buffer requested"); - - // Page buffer must not become larger than pageLength*cacheRate before - // or after the current page - int minPageBufferIndex = getCurrentPageFirstItemIndex() - - (int) (getPageLength() * getCacheRate()); - if (minPageBufferIndex < 0) { - minPageBufferIndex = 0; - } - - int maxPageBufferIndex = getCurrentPageFirstItemIndex() - + (int) (getPageLength() * (1 + getCacheRate())); - int maxBufferSize = maxPageBufferIndex - minPageBufferIndex; - - if (getPageLength() == 0) { - // If pageLength == 0 then all rows should be rendered - maxBufferSize = pageBuffer[0].length + rows; - } - /* - * Number of rows that were previously cached. This is not necessarily - * the same as pageLength if we do not have enough rows in the - * container. - */ - int currentlyCachedRowCount = pageBuffer[CELL_ITEMID].length; - - /* - * firstIndexInPageBuffer is the offset in pageBuffer where the new rows - * will be inserted (firstIndex is the index in the whole table). - * - * E.g. scrolled down to row 1000: firstIndex==1010, - * pageBufferFirstIndex==1000 -> cacheIx==10 - */ - int firstIndexInPageBuffer = firstIndex - pageBufferFirstIndex; - - /* If rows > size available in page buffer */ - if (firstIndexInPageBuffer + rows > maxBufferSize) { - rows = maxBufferSize - firstIndexInPageBuffer; - } - - /* - * "rows" rows will be inserted at firstIndex. Find out how many old - * rows fall outside the new buffer so we can unregister components in - * the cache. - */ - - /* All rows until the insertion point remain, always. */ - int firstCacheRowToRemoveInPageBuffer = firstIndexInPageBuffer; - - /* - * IF there is space remaining in the buffer after the rows have been - * inserted, we can keep more rows. - */ - int numberOfOldRowsAfterInsertedRows = maxBufferSize - - firstIndexInPageBuffer - rows; - if (numberOfOldRowsAfterInsertedRows > 0) { - firstCacheRowToRemoveInPageBuffer += numberOfOldRowsAfterInsertedRows; - } - - if (firstCacheRowToRemoveInPageBuffer <= currentlyCachedRowCount) { - /* - * Unregister all components that fall beyond the cache limits after - * inserting the new rows. - */ - unregisterComponentsAndPropertiesInRows( - firstCacheRowToRemoveInPageBuffer + pageBufferFirstIndex, - currentlyCachedRowCount - firstCacheRowToRemoveInPageBuffer - + pageBufferFirstIndex); - } - - // Calculate the new cache size - int newCachedRowCount = currentlyCachedRowCount; - if (maxBufferSize == 0 || currentlyCachedRowCount < maxBufferSize) { - newCachedRowCount = currentlyCachedRowCount + rows; - if (maxBufferSize > 0 && newCachedRowCount > maxBufferSize) { - newCachedRowCount = maxBufferSize; - } - } - - /* Paint the new rows into a separate buffer */ - Object[][] cells = getVisibleCellsNoCache(firstIndex, rows, false); - - /* - * Create the new cache buffer and fill it with the data from the old - * buffer as well as the inserted rows. - */ - Object[][] newPageBuffer = new Object[pageBuffer.length][newCachedRowCount]; - - for (int i = 0; i < pageBuffer.length; i++) { - for (int row = 0; row < firstIndexInPageBuffer; row++) { - // Copy the first rows - newPageBuffer[i][row] = pageBuffer[i][row]; - } - for (int row = firstIndexInPageBuffer; row < firstIndexInPageBuffer - + rows; row++) { - // Copy the newly created rows - newPageBuffer[i][row] = cells[i][row - firstIndexInPageBuffer]; - } - for (int row = firstIndexInPageBuffer + rows; row < newCachedRowCount; row++) { - // Move the old rows down below the newly inserted rows - newPageBuffer[i][row] = pageBuffer[i][row - rows]; - } - } - pageBuffer = newPageBuffer; - getLogger().finest( - "Page Buffer now contains " - + pageBuffer[CELL_ITEMID].length - + " rows (" - + pageBufferFirstIndex - + "-" - + (pageBufferFirstIndex - + pageBuffer[CELL_ITEMID].length - 1) + ")"); - return cells; - } - - /** - * Render rows with index "firstIndex" to "firstIndex+rows-1" to a new - * buffer. - * - * Reuses values from the current page buffer if the rows are found there. - * - * @param firstIndex - * @param rows - * @param replaceListeners - * @return - */ - private Object[][] getVisibleCellsNoCache(int firstIndex, int rows, - boolean replaceListeners) { - getLogger().finest( - "Render visible cells for rows " + firstIndex + "-" - + (firstIndex + rows - 1)); - final Object[] colids = getVisibleColumns(); - final int cols = colids.length; - - HashSet<Property<?>> oldListenedProperties = listenedProperties; - HashSet<Component> oldVisibleComponents = visibleComponents; - - if (replaceListeners) { - // initialize the listener collections, this should only be done if - // the entire cache is refreshed (through refreshRenderedCells) - listenedProperties = new HashSet<Property<?>>(); - visibleComponents = new HashSet<Component>(); - } - - Object[][] cells = new Object[cols + CELL_FIRSTCOL][rows]; - if (rows == 0) { - unregisterPropertiesAndComponents(oldListenedProperties, - oldVisibleComponents); - return cells; - } - - // Gets the first item id - Object id; - if (items instanceof Container.Indexed) { - id = getIdByIndex(firstIndex); - } else { - id = firstItemId(); - for (int i = 0; i < firstIndex; i++) { - id = nextItemId(id); - } - } - - final RowHeaderMode headmode = getRowHeaderMode(); - final boolean[] iscomponent = new boolean[cols]; - for (int i = 0; i < cols; i++) { - iscomponent[i] = columnGenerators.containsKey(colids[i]) - || Component.class.isAssignableFrom(getType(colids[i])); - } - int firstIndexNotInCache; - if (pageBuffer != null && pageBuffer[CELL_ITEMID].length > 0) { - firstIndexNotInCache = pageBufferFirstIndex - + pageBuffer[CELL_ITEMID].length; - } else { - firstIndexNotInCache = -1; - } - - // Creates the page contents - int filledRows = 0; - for (int i = 0; i < rows && id != null; i++) { - cells[CELL_ITEMID][i] = id; - cells[CELL_KEY][i] = itemIdMapper.key(id); - if (headmode != ROW_HEADER_MODE_HIDDEN) { - switch (headmode) { - case INDEX: - cells[CELL_HEADER][i] = String.valueOf(i + firstIndex + 1); - break; - default: - cells[CELL_HEADER][i] = getItemCaption(id); - } - cells[CELL_ICON][i] = getItemIcon(id); - } - - GeneratedRow generatedRow = rowGenerator != null ? rowGenerator - .generateRow(this, id) : null; - cells[CELL_GENERATED_ROW][i] = generatedRow; - - for (int j = 0; j < cols; j++) { - if (isColumnCollapsed(colids[j])) { - continue; - } - Property<?> p = null; - Object value = ""; - boolean isGeneratedRow = generatedRow != null; - boolean isGeneratedColumn = columnGenerators - .containsKey(colids[j]); - boolean isGenerated = isGeneratedRow || isGeneratedColumn; - - if (!isGenerated) { - p = getContainerProperty(id, colids[j]); - } - - if (isGeneratedRow) { - if (generatedRow.isSpanColumns() && j > 0) { - value = null; - } else if (generatedRow.isSpanColumns() && j == 0 - && generatedRow.getValue() instanceof Component) { - value = generatedRow.getValue(); - } else if (generatedRow.getText().length > j) { - value = generatedRow.getText()[j]; - } - } else { - // check in current pageBuffer already has row - int index = firstIndex + i; - if (p != null || isGenerated) { - int indexInOldBuffer = index - pageBufferFirstIndex; - if (index < firstIndexNotInCache - && index >= pageBufferFirstIndex - && pageBuffer[CELL_GENERATED_ROW][indexInOldBuffer] == null - && id.equals(pageBuffer[CELL_ITEMID][indexInOldBuffer])) { - // we already have data in our cache, - // recycle it instead of fetching it via - // getValue/getPropertyValue - value = pageBuffer[CELL_FIRSTCOL + j][indexInOldBuffer]; - if (!isGeneratedColumn && iscomponent[j] - || !(value instanceof Component)) { - listenProperty(p, oldListenedProperties); - } - } else { - if (isGeneratedColumn) { - ColumnGenerator cg = columnGenerators - .get(colids[j]); - value = cg.generateCell(this, id, colids[j]); - if (value != null - && !(value instanceof Component) - && !(value instanceof String)) { - // Avoid errors if a generator returns - // something - // other than a Component or a String - value = value.toString(); - } - } else if (iscomponent[j]) { - value = p.getValue(); - listenProperty(p, oldListenedProperties); - } else if (p != null) { - value = getPropertyValue(id, colids[j], p); - /* - * If returned value is Component (via - * fieldfactory or overridden getPropertyValue) - * we excpect it to listen property value - * changes. Otherwise if property emits value - * change events, table will start to listen - * them and refresh content when needed. - */ - if (!(value instanceof Component)) { - listenProperty(p, oldListenedProperties); - } - } else { - value = getPropertyValue(id, colids[j], null); - } - } - } - } - - if (value instanceof Component) { - registerComponent((Component) value); - } - cells[CELL_FIRSTCOL + j][i] = value; - } - - // Gets the next item id - if (items instanceof Container.Indexed) { - int index = firstIndex + i + 1; - if (index < size()) { - id = getIdByIndex(index); - } else { - id = null; - } - } else { - id = nextItemId(id); - } - - filledRows++; - } - - // Assures that all the rows of the cell-buffer are valid - if (filledRows != cells[0].length) { - final Object[][] temp = new Object[cells.length][filledRows]; - for (int i = 0; i < cells.length; i++) { - for (int j = 0; j < filledRows; j++) { - temp[i][j] = cells[i][j]; - } - } - cells = temp; - } - - unregisterPropertiesAndComponents(oldListenedProperties, - oldVisibleComponents); - - return cells; - } - - protected void registerComponent(Component component) { - getLogger().finest( - "Registered " + component.getClass().getSimpleName() + ": " - + component.getCaption()); - if (component.getParent() != this) { - component.setParent(this); - } - visibleComponents.add(component); - } - - private void listenProperty(Property<?> p, - HashSet<Property<?>> oldListenedProperties) { - if (p instanceof Property.ValueChangeNotifier) { - if (oldListenedProperties == null - || !oldListenedProperties.contains(p)) { - ((Property.ValueChangeNotifier) p).addListener(this); - } - /* - * register listened properties, so we can do proper cleanup to free - * memory. Essential if table has loads of data and it is used for a - * long time. - */ - listenedProperties.add(p); - - } - } - - /** - * @param firstIx - * Index of the first row to process. Global index, not relative - * to page buffer. - * @param count - */ - private void unregisterComponentsAndPropertiesInRows(int firstIx, int count) { - getLogger().finest( - "Unregistering components in rows " + firstIx + "-" - + (firstIx + count - 1)); - Object[] colids = getVisibleColumns(); - if (pageBuffer != null && pageBuffer[CELL_ITEMID].length > 0) { - int bufSize = pageBuffer[CELL_ITEMID].length; - int ix = firstIx - pageBufferFirstIndex; - ix = ix < 0 ? 0 : ix; - if (ix < bufSize) { - count = count > bufSize - ix ? bufSize - ix : count; - for (int i = 0; i < count; i++) { - for (int c = 0; c < colids.length; c++) { - Object cellVal = pageBuffer[CELL_FIRSTCOL + c][i + ix]; - if (cellVal instanceof Component - && visibleComponents.contains(cellVal)) { - visibleComponents.remove(cellVal); - unregisterComponent((Component) cellVal); - } else { - Property<?> p = getContainerProperty( - pageBuffer[CELL_ITEMID][i + ix], colids[c]); - if (p instanceof ValueChangeNotifier - && listenedProperties.contains(p)) { - listenedProperties.remove(p); - ((ValueChangeNotifier) p).removeListener(this); - } - } - } - } - } - } - } - - /** - * Helper method to remove listeners and maintain correct component - * hierarchy. Detaches properties and components if those are no more - * rendered in client. - * - * @param oldListenedProperties - * set of properties that where listened in last render - * @param oldVisibleComponents - * set of components that where attached in last render - */ - private void unregisterPropertiesAndComponents( - HashSet<Property<?>> oldListenedProperties, - HashSet<Component> oldVisibleComponents) { - if (oldVisibleComponents != null) { - for (final Iterator<Component> i = oldVisibleComponents.iterator(); i - .hasNext();) { - Component c = i.next(); - if (!visibleComponents.contains(c)) { - unregisterComponent(c); - } - } - } - - if (oldListenedProperties != null) { - for (final Iterator<Property<?>> i = oldListenedProperties - .iterator(); i.hasNext();) { - Property.ValueChangeNotifier o = (ValueChangeNotifier) i.next(); - if (!listenedProperties.contains(o)) { - o.removeListener(this); - } - } - } - } - - /** - * This method cleans up a Component that has been generated when Table is - * in editable mode. The component needs to be detached from its parent and - * if it is a field, it needs to be detached from its property data source - * in order to allow garbage collection to take care of removing the unused - * component from memory. - * - * Override this method and getPropertyValue(Object, Object, Property) with - * custom logic if you need to deal with buffered fields. - * - * @see #getPropertyValue(Object, Object, Property) - * - * @param oldVisibleComponents - * a set of components that should be unregistered. - */ - protected void unregisterComponent(Component component) { - getLogger().finest( - "Unregistered " + component.getClass().getSimpleName() + ": " - + component.getCaption()); - component.setParent(null); - /* - * Also remove property data sources to unregister listeners keeping the - * fields in memory. - */ - if (component instanceof Field) { - Field<?> field = (Field<?>) component; - Property<?> associatedProperty = associatedProperties - .remove(component); - if (associatedProperty != null - && field.getPropertyDataSource() == associatedProperty) { - // Remove the property data source only if it's the one we - // added in getPropertyValue - field.setPropertyDataSource(null); - } - } - } - - /** - * Refreshes the current page contents. - * - * @deprecated should not need to be used - */ - @Deprecated - public void refreshCurrentPage() { - - } - - /** - * Sets the row header mode. - * <p> - * The mode can be one of the following ones: - * <ul> - * <li>{@link #ROW_HEADER_MODE_HIDDEN}: The row captions are hidden.</li> - * <li>{@link #ROW_HEADER_MODE_ID}: Items Id-objects <code>toString()</code> - * is used as row caption. - * <li>{@link #ROW_HEADER_MODE_ITEM}: Item-objects <code>toString()</code> - * is used as row caption. - * <li>{@link #ROW_HEADER_MODE_PROPERTY}: Property set with - * {@link #setItemCaptionPropertyId(Object)} is used as row header. - * <li>{@link #ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID}: Items Id-objects - * <code>toString()</code> is used as row header. If caption is explicitly - * specified, it overrides the id-caption. - * <li>{@link #ROW_HEADER_MODE_EXPLICIT}: The row headers must be explicitly - * specified.</li> - * <li>{@link #ROW_HEADER_MODE_INDEX}: The index of the item is used as row - * caption. The index mode can only be used with the containers implementing - * <code>Container.Indexed</code> interface.</li> - * </ul> - * The default value is {@link #ROW_HEADER_MODE_HIDDEN} - * </p> - * - * @param mode - * the One of the modes listed above. - */ - public void setRowHeaderMode(RowHeaderMode mode) { - if (mode != null) { - rowHeaderMode = mode; - if (mode != RowHeaderMode.HIDDEN) { - setItemCaptionMode(mode.getItemCaptionMode()); - } - // Assures the visual refresh. No need to reset the page buffer - // before - // as the content has not changed, only the alignments. - refreshRenderedCells(); - } - } - - /** - * Gets the row header mode. - * - * @return the Row header mode. - * @see #setRowHeaderMode(int) - */ - public RowHeaderMode getRowHeaderMode() { - return rowHeaderMode; - } - - /** - * Adds the new row to table and fill the visible cells (except generated - * columns) with given values. - * - * @param cells - * the Object array that is used for filling the visible cells - * new row. The types must be settable to visible column property - * types. - * @param itemId - * the Id the new row. If null, a new id is automatically - * assigned. If given, the table cant already have a item with - * given id. - * @return Returns item id for the new row. Returns null if operation fails. - */ - public Object addItem(Object[] cells, Object itemId) - throws UnsupportedOperationException { - - // remove generated columns from the list of columns being assigned - final LinkedList<Object> availableCols = new LinkedList<Object>(); - for (Iterator<Object> it = visibleColumns.iterator(); it.hasNext();) { - Object id = it.next(); - if (!columnGenerators.containsKey(id)) { - availableCols.add(id); - } - } - // Checks that a correct number of cells are given - if (cells.length != availableCols.size()) { - return null; - } - - // Creates new item - Item item; - if (itemId == null) { - itemId = items.addItem(); - if (itemId == null) { - return null; - } - item = items.getItem(itemId); - } else { - item = items.addItem(itemId); - } - if (item == null) { - return null; - } - - // Fills the item properties - for (int i = 0; i < availableCols.size(); i++) { - item.getItemProperty(availableCols.get(i)).setValue(cells[i]); - } - - if (!(items instanceof Container.ItemSetChangeNotifier)) { - refreshRowCache(); - } - - return itemId; - } - - /** - * Discards and recreates the internal row cache. Call this if you make - * changes that affect the rows but the information about the changes are - * not automatically propagated to the Table. - * <p> - * Do not call this e.g. if you have updated the data model through a - * Property. These types of changes are automatically propagated to the - * Table. - * <p> - * A typical case when this is needed is if you update a generator (e.g. - * CellStyleGenerator) and want to ensure that the rows are redrawn with new - * styles. - * <p> - * <i>Note that calling this method is not cheap so avoid calling it - * unnecessarily.</i> - * - * @since 6.7.2 - */ - public void refreshRowCache() { - resetPageBuffer(); - refreshRenderedCells(); - } - - @Override - public void setContainerDataSource(Container newDataSource) { - - disableContentRefreshing(); - - if (newDataSource == null) { - newDataSource = new IndexedContainer(); - } - - // Assures that the data source is ordered by making unordered - // containers ordered by wrapping them - if (newDataSource instanceof Container.Ordered) { - super.setContainerDataSource(newDataSource); - } else { - super.setContainerDataSource(new ContainerOrderedWrapper( - newDataSource)); - } - - // Resets page position - currentPageFirstItemId = null; - currentPageFirstItemIndex = 0; - - // Resets column properties - if (collapsedColumns != null) { - collapsedColumns.clear(); - } - - // columnGenerators 'override' properties, don't add the same id twice - Collection<Object> col = new LinkedList<Object>(); - for (Iterator<?> it = getContainerPropertyIds().iterator(); it - .hasNext();) { - Object id = it.next(); - if (columnGenerators == null || !columnGenerators.containsKey(id)) { - col.add(id); - } - } - // generators added last - if (columnGenerators != null && columnGenerators.size() > 0) { - col.addAll(columnGenerators.keySet()); - } - - setVisibleColumns(col.toArray()); - - // Assure visual refresh - resetPageBuffer(); - - enableContentRefreshing(true); - } - - /** - * Gets items ids from a range of key values - * - * @param startRowKey - * The start key - * @param endRowKey - * The end key - * @return - */ - private LinkedHashSet<Object> getItemIdsInRange(Object itemId, - final int length) { - LinkedHashSet<Object> ids = new LinkedHashSet<Object>(); - for (int i = 0; i < length; i++) { - assert itemId != null; // should not be null unless client-server - // are out of sync - ids.add(itemId); - itemId = nextItemId(itemId); - } - return ids; - } - - /** - * Handles selection if selection is a multiselection - * - * @param variables - * The variables - */ - private void handleSelectedItems(Map<String, Object> variables) { - final String[] ka = (String[]) variables.get("selected"); - final String[] ranges = (String[]) variables.get("selectedRanges"); - - Set<Object> renderedButNotSelectedItemIds = getCurrentlyRenderedItemIds(); - - @SuppressWarnings("unchecked") - HashSet<Object> newValue = new LinkedHashSet<Object>( - (Collection<Object>) getValue()); - - if (variables.containsKey("clearSelections")) { - // the client side has instructed to swipe all previous selections - newValue.clear(); - } - - /* - * Then add (possibly some of them back) rows that are currently - * selected on the client side (the ones that the client side is aware - * of). - */ - for (int i = 0; i < ka.length; i++) { - // key to id - final Object id = itemIdMapper.get(ka[i]); - if (!isNullSelectionAllowed() - && (id == null || id == getNullSelectionItemId())) { - // skip empty selection if nullselection is not allowed - requestRepaint(); - } else if (id != null && containsId(id)) { - newValue.add(id); - renderedButNotSelectedItemIds.remove(id); - } - } - - /* Add range items aka shift clicked multiselection areas */ - if (ranges != null) { - for (String range : ranges) { - String[] split = range.split("-"); - Object startItemId = itemIdMapper.get(split[0]); - int length = Integer.valueOf(split[1]); - LinkedHashSet<Object> itemIdsInRange = getItemIdsInRange( - startItemId, length); - newValue.addAll(itemIdsInRange); - renderedButNotSelectedItemIds.removeAll(itemIdsInRange); - } - } - /* - * finally clear all currently rendered rows (the ones that the client - * side counterpart is aware of) that the client didn't send as selected - */ - newValue.removeAll(renderedButNotSelectedItemIds); - - if (!isNullSelectionAllowed() && newValue.isEmpty()) { - // empty selection not allowed, keep old value - requestRepaint(); - return; - } - - setValue(newValue, true); - - } - - private Set<Object> getCurrentlyRenderedItemIds() { - HashSet<Object> ids = new HashSet<Object>(); - if (pageBuffer != null) { - for (int i = 0; i < pageBuffer[CELL_ITEMID].length; i++) { - ids.add(pageBuffer[CELL_ITEMID][i]); - } - } - return ids; - } - - /* Component basics */ - - /** - * Invoked when the value of a variable has changed. - * - * @see com.vaadin.ui.Select#changeVariables(java.lang.Object, - * java.util.Map) - */ - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - - boolean clientNeedsContentRefresh = false; - - handleClickEvent(variables); - - handleColumnResizeEvent(variables); - - handleColumnWidthUpdates(variables); - - disableContentRefreshing(); - - if (!isSelectable() && variables.containsKey("selected")) { - // Not-selectable is a special case, AbstractSelect does not support - // TODO could be optimized. - variables = new HashMap<String, Object>(variables); - variables.remove("selected"); - } - - /* - * The AbstractSelect cannot handle the multiselection properly, instead - * we handle it ourself - */ - else if (isSelectable() && isMultiSelect() - && variables.containsKey("selected") - && multiSelectMode == MultiSelectMode.DEFAULT) { - handleSelectedItems(variables); - variables = new HashMap<String, Object>(variables); - variables.remove("selected"); - } - - super.changeVariables(source, variables); - - // Client might update the pagelength if Table height is fixed - if (variables.containsKey("pagelength")) { - // Sets pageLength directly to avoid repaint that setter causes - pageLength = (Integer) variables.get("pagelength"); - } - - // Page start index - if (variables.containsKey("firstvisible")) { - final Integer value = (Integer) variables.get("firstvisible"); - if (value != null) { - setCurrentPageFirstItemIndex(value.intValue(), false); - } - } - - // Sets requested firstrow and rows for the next paint - if (variables.containsKey("reqfirstrow") - || variables.containsKey("reqrows")) { - - try { - firstToBeRenderedInClient = ((Integer) variables - .get("firstToBeRendered")).intValue(); - lastToBeRenderedInClient = ((Integer) variables - .get("lastToBeRendered")).intValue(); - } catch (Exception e) { - // FIXME: Handle exception - getLogger().log(Level.FINER, - "Could not parse the first and/or last rows.", e); - } - - // respect suggested rows only if table is not otherwise updated - // (row caches emptied by other event) - if (!containerChangeToBeRendered) { - Integer value = (Integer) variables.get("reqfirstrow"); - if (value != null) { - reqFirstRowToPaint = value.intValue(); - } - value = (Integer) variables.get("reqrows"); - if (value != null) { - reqRowsToPaint = value.intValue(); - // sanity check - if (reqFirstRowToPaint + reqRowsToPaint > size()) { - reqRowsToPaint = size() - reqFirstRowToPaint; - } - } - } - getLogger().finest( - "Client wants rows " + reqFirstRowToPaint + "-" - + (reqFirstRowToPaint + reqRowsToPaint - 1)); - clientNeedsContentRefresh = true; - } - - if (isSortEnabled()) { - // Sorting - boolean doSort = false; - if (variables.containsKey("sortcolumn")) { - final String colId = (String) variables.get("sortcolumn"); - if (colId != null && !"".equals(colId) && !"null".equals(colId)) { - final Object id = columnIdMap.get(colId); - setSortContainerPropertyId(id, false); - doSort = true; - } - } - if (variables.containsKey("sortascending")) { - final boolean state = ((Boolean) variables.get("sortascending")) - .booleanValue(); - if (state != sortAscending) { - setSortAscending(state, false); - doSort = true; - } - } - if (doSort) { - this.sort(); - resetPageBuffer(); - } - } - - // Dynamic column hide/show and order - // Update visible columns - if (isColumnCollapsingAllowed()) { - if (variables.containsKey("collapsedcolumns")) { - try { - final Object[] ids = (Object[]) variables - .get("collapsedcolumns"); - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext();) { - setColumnCollapsed(it.next(), false); - } - for (int i = 0; i < ids.length; i++) { - setColumnCollapsed(columnIdMap.get(ids[i].toString()), - true); - } - } catch (final Exception e) { - // FIXME: Handle exception - getLogger().log(Level.FINER, - "Could not determine column collapsing state", e); - } - clientNeedsContentRefresh = true; - } - } - if (isColumnReorderingAllowed()) { - if (variables.containsKey("columnorder")) { - try { - final Object[] ids = (Object[]) variables - .get("columnorder"); - // need a real Object[], ids can be a String[] - final Object[] idsTemp = new Object[ids.length]; - for (int i = 0; i < ids.length; i++) { - idsTemp[i] = columnIdMap.get(ids[i].toString()); - } - setColumnOrder(idsTemp); - if (hasListeners(ColumnReorderEvent.class)) { - fireEvent(new ColumnReorderEvent(this)); - } - } catch (final Exception e) { - // FIXME: Handle exception - getLogger().log(Level.FINER, - "Could not determine column reordering state", e); - } - clientNeedsContentRefresh = true; - } - } - - enableContentRefreshing(clientNeedsContentRefresh); - - // Actions - if (variables.containsKey("action")) { - final StringTokenizer st = new StringTokenizer( - (String) variables.get("action"), ","); - if (st.countTokens() == 2) { - final Object itemId = itemIdMapper.get(st.nextToken()); - final Action action = actionMapper.get(st.nextToken()); - - if (action != null && (itemId == null || containsId(itemId)) - && actionHandlers != null) { - for (Handler ah : actionHandlers) { - ah.handleAction(action, this, itemId); - } - } - } - } - - } - - /** - * Handles click event - * - * @param variables - */ - private void handleClickEvent(Map<String, Object> variables) { - - // Item click event - if (variables.containsKey("clickEvent")) { - String key = (String) variables.get("clickedKey"); - Object itemId = itemIdMapper.get(key); - Object propertyId = null; - String colkey = (String) variables.get("clickedColKey"); - // click is not necessary on a property - if (colkey != null) { - propertyId = columnIdMap.get(colkey); - } - MouseEventDetails evt = MouseEventDetails - .deSerialize((String) variables.get("clickEvent")); - Item item = getItem(itemId); - if (item != null) { - fireEvent(new ItemClickEvent(this, item, itemId, propertyId, - evt)); - } - } - - // Header click event - else if (variables.containsKey("headerClickEvent")) { - - MouseEventDetails details = MouseEventDetails - .deSerialize((String) variables.get("headerClickEvent")); - - Object cid = variables.get("headerClickCID"); - Object propertyId = null; - if (cid != null) { - propertyId = columnIdMap.get(cid.toString()); - } - fireEvent(new HeaderClickEvent(this, propertyId, details)); - } - - // Footer click event - else if (variables.containsKey("footerClickEvent")) { - MouseEventDetails details = MouseEventDetails - .deSerialize((String) variables.get("footerClickEvent")); - - Object cid = variables.get("footerClickCID"); - Object propertyId = null; - if (cid != null) { - propertyId = columnIdMap.get(cid.toString()); - } - fireEvent(new FooterClickEvent(this, propertyId, details)); - } - } - - /** - * Handles the column resize event sent by the client. - * - * @param variables - */ - private void handleColumnResizeEvent(Map<String, Object> variables) { - if (variables.containsKey("columnResizeEventColumn")) { - Object cid = variables.get("columnResizeEventColumn"); - Object propertyId = null; - if (cid != null) { - propertyId = columnIdMap.get(cid.toString()); - - Object prev = variables.get("columnResizeEventPrev"); - int previousWidth = -1; - if (prev != null) { - previousWidth = Integer.valueOf(prev.toString()); - } - - Object curr = variables.get("columnResizeEventCurr"); - int currentWidth = -1; - if (curr != null) { - currentWidth = Integer.valueOf(curr.toString()); - } - - fireColumnResizeEvent(propertyId, previousWidth, currentWidth); - } - } - } - - private void fireColumnResizeEvent(Object propertyId, int previousWidth, - int currentWidth) { - /* - * Update the sizes on the server side. If a column previously had a - * expand ratio and the user resized the column then the expand ratio - * will be turned into a static pixel size. - */ - setColumnWidth(propertyId, currentWidth); - - fireEvent(new ColumnResizeEvent(this, propertyId, previousWidth, - currentWidth)); - } - - private void handleColumnWidthUpdates(Map<String, Object> variables) { - if (variables.containsKey("columnWidthUpdates")) { - String[] events = (String[]) variables.get("columnWidthUpdates"); - for (String str : events) { - String[] eventDetails = str.split(":"); - Object propertyId = columnIdMap.get(eventDetails[0]); - if (propertyId == null) { - propertyId = ROW_HEADER_FAKE_PROPERTY_ID; - } - int width = Integer.valueOf(eventDetails[1]); - setColumnWidth(propertyId, width); - } - } - } - - /** - * Go to mode where content updates are not done. This is due we want to - * bypass expensive content for some reason (like when we know we may have - * other content changes on their way). - * - * @return true if content refresh flag was enabled prior this call - */ - protected boolean disableContentRefreshing() { - boolean wasDisabled = isContentRefreshesEnabled; - isContentRefreshesEnabled = false; - return wasDisabled; - } - - /** - * Go to mode where content content refreshing has effect. - * - * @param refreshContent - * true if content refresh needs to be done - */ - protected void enableContentRefreshing(boolean refreshContent) { - isContentRefreshesEnabled = true; - if (refreshContent) { - refreshRenderedCells(); - // Ensure that client gets a response - requestRepaint(); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractSelect#paintContent(com.vaadin. - * terminal.PaintTarget) - */ - - @Override - public void paintContent(PaintTarget target) throws PaintException { - /* - * Body actions - Actions which has the target null and can be invoked - * by right clicking on the table body. - */ - final Set<Action> actionSet = findAndPaintBodyActions(target); - - final Object[][] cells = getVisibleCells(); - int rows = findNumRowsToPaint(target, cells); - - int total = size(); - if (shouldHideNullSelectionItem()) { - total--; - rows--; - } - - // Table attributes - paintTableAttributes(target, rows, total); - - paintVisibleColumnOrder(target); - - // Rows - if (isPartialRowUpdate() && painted && !target.isFullRepaint()) { - paintPartialRowUpdate(target, actionSet); - /* - * Send the page buffer indexes to ensure that the client side stays - * in sync. Otherwise we _might_ have the situation where the client - * side discards too few or too many rows, causing out of sync - * issues. - * - * This could probably be done for full repaints also to simplify - * the client side. - */ - int pageBufferLastIndex = pageBufferFirstIndex - + pageBuffer[CELL_ITEMID].length - 1; - target.addAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_FIRST, - pageBufferFirstIndex); - target.addAttribute(VScrollTable.ATTRIBUTE_PAGEBUFFER_LAST, - pageBufferLastIndex); - } else if (target.isFullRepaint() || isRowCacheInvalidated()) { - paintRows(target, cells, actionSet); - setRowCacheInvalidated(false); - } - - paintSorting(target); - - resetVariablesAndPageBuffer(target); - - // Actions - paintActions(target, actionSet); - - paintColumnOrder(target); - - // Available columns - paintAvailableColumns(target); - - paintVisibleColumns(target); - - if (keyMapperReset) { - keyMapperReset = false; - target.addAttribute(VScrollTable.ATTRIBUTE_KEY_MAPPER_RESET, true); - } - - if (dropHandler != null) { - dropHandler.getAcceptCriterion().paint(target); - } - - painted = true; - } - - private void setRowCacheInvalidated(boolean invalidated) { - rowCacheInvalidated = invalidated; - } - - protected boolean isRowCacheInvalidated() { - return rowCacheInvalidated; - } - - private void paintPartialRowUpdate(PaintTarget target, Set<Action> actionSet) - throws PaintException { - paintPartialRowUpdates(target, actionSet); - paintPartialRowAdditions(target, actionSet); - } - - private void paintPartialRowUpdates(PaintTarget target, - Set<Action> actionSet) throws PaintException { - final boolean[] iscomponent = findCellsWithComponents(); - - int firstIx = getFirstUpdatedItemIndex(); - int count = getUpdatedRowCount(); - - target.startTag("urows"); - target.addAttribute("firsturowix", firstIx); - target.addAttribute("numurows", count); - - // Partial row updates bypass the normal caching mechanism. - Object[][] cells = getVisibleCellsUpdateCacheRows(firstIx, count); - for (int indexInRowbuffer = 0; indexInRowbuffer < count; indexInRowbuffer++) { - final Object itemId = cells[CELL_ITEMID][indexInRowbuffer]; - - if (shouldHideNullSelectionItem()) { - // Remove null selection item if null selection is not allowed - continue; - } - - paintRow(target, cells, isEditable(), actionSet, iscomponent, - indexInRowbuffer, itemId); - } - target.endTag("urows"); - } - - private void paintPartialRowAdditions(PaintTarget target, - Set<Action> actionSet) throws PaintException { - final boolean[] iscomponent = findCellsWithComponents(); - - int firstIx = getFirstAddedItemIndex(); - int count = getAddedRowCount(); - - target.startTag("prows"); - - if (!shouldHideAddedRows()) { - getLogger().finest( - "Paint rows for add. Index: " + firstIx + ", count: " - + count + "."); - - // Partial row additions bypass the normal caching mechanism. - Object[][] cells = getVisibleCellsInsertIntoCache(firstIx, count); - if (cells[0].length < count) { - // delete the rows below, since they will fall beyond the cache - // page. - target.addAttribute("delbelow", true); - count = cells[0].length; - } - - for (int indexInRowbuffer = 0; indexInRowbuffer < count; indexInRowbuffer++) { - final Object itemId = cells[CELL_ITEMID][indexInRowbuffer]; - if (shouldHideNullSelectionItem()) { - // Remove null selection item if null selection is not - // allowed - continue; - } - - paintRow(target, cells, isEditable(), actionSet, iscomponent, - indexInRowbuffer, itemId); - } - } else { - getLogger().finest( - "Paint rows for remove. Index: " + firstIx + ", count: " - + count + "."); - removeRowsFromCacheAndFillBottom(firstIx, count); - target.addAttribute("hide", true); - } - - target.addAttribute("firstprowix", firstIx); - target.addAttribute("numprows", count); - target.endTag("prows"); - } - - /** - * Subclass and override this to enable partial row updates and additions, - * which bypass the normal caching mechanism. This is useful for e.g. - * TreeTable. - * - * @return true if this update is a partial row update, false if not. For - * plain Table it is always false. - */ - protected boolean isPartialRowUpdate() { - return false; - } - - /** - * Subclass and override this to enable partial row additions, bypassing the - * normal caching mechanism. This is useful for e.g. TreeTable, where - * expanding a node should only fetch and add the items inside of that node. - * - * @return The index of the first added item. For plain Table it is always - * 0. - */ - protected int getFirstAddedItemIndex() { - return 0; - } - - /** - * Subclass and override this to enable partial row additions, bypassing the - * normal caching mechanism. This is useful for e.g. TreeTable, where - * expanding a node should only fetch and add the items inside of that node. - * - * @return the number of rows to be added, starting at the index returned by - * {@link #getFirstAddedItemIndex()}. For plain Table it is always - * 0. - */ - protected int getAddedRowCount() { - return 0; - } - - /** - * Subclass and override this to enable removing of rows, bypassing the - * normal caching and lazy loading mechanism. This is useful for e.g. - * TreeTable, when you need to hide certain rows as a node is collapsed. - * - * This should return true if the rows pointed to by - * {@link #getFirstAddedItemIndex()} and {@link #getAddedRowCount()} should - * be hidden instead of added. - * - * @return whether the rows to add (see {@link #getFirstAddedItemIndex()} - * and {@link #getAddedRowCount()}) should be added or hidden. For - * plain Table it is always false. - */ - protected boolean shouldHideAddedRows() { - return false; - } - - /** - * Subclass and override this to enable partial row updates, bypassing the - * normal caching and lazy loading mechanism. This is useful for updating - * the state of certain rows, e.g. in the TreeTable the collapsed state of a - * single node is updated using this mechanism. - * - * @return the index of the first item to be updated. For plain Table it is - * always 0. - */ - protected int getFirstUpdatedItemIndex() { - return 0; - } - - /** - * Subclass and override this to enable partial row updates, bypassing the - * normal caching and lazy loading mechanism. This is useful for updating - * the state of certain rows, e.g. in the TreeTable the collapsed state of a - * single node is updated using this mechanism. - * - * @return the number of rows to update, starting at the index returned by - * {@link #getFirstUpdatedItemIndex()}. For plain table it is always - * 0. - */ - protected int getUpdatedRowCount() { - return 0; - } - - private void paintTableAttributes(PaintTarget target, int rows, int total) - throws PaintException { - paintTabIndex(target); - paintDragMode(target); - paintSelectMode(target); - - if (cacheRate != CACHE_RATE_DEFAULT) { - target.addAttribute("cr", cacheRate); - } - - target.addAttribute("cols", getVisibleColumns().length); - target.addAttribute("rows", rows); - - target.addAttribute("firstrow", - (reqFirstRowToPaint >= 0 ? reqFirstRowToPaint - : firstToBeRenderedInClient)); - target.addAttribute("totalrows", total); - if (getPageLength() != 0) { - target.addAttribute("pagelength", getPageLength()); - } - if (areColumnHeadersEnabled()) { - target.addAttribute("colheaders", true); - } - if (rowHeadersAreEnabled()) { - target.addAttribute("rowheaders", true); - } - - target.addAttribute("colfooters", columnFootersVisible); - - // The cursors are only shown on pageable table - if (getCurrentPageFirstItemIndex() != 0 || getPageLength() > 0) { - target.addVariable(this, "firstvisible", - getCurrentPageFirstItemIndex()); - } - } - - /** - * Resets and paints "to be painted next" variables. Also reset pageBuffer - */ - private void resetVariablesAndPageBuffer(PaintTarget target) - throws PaintException { - reqFirstRowToPaint = -1; - reqRowsToPaint = -1; - containerChangeToBeRendered = false; - target.addVariable(this, "reqrows", reqRowsToPaint); - target.addVariable(this, "reqfirstrow", reqFirstRowToPaint); - } - - private boolean areColumnHeadersEnabled() { - return getColumnHeaderMode() != ColumnHeaderMode.HIDDEN; - } - - private void paintVisibleColumns(PaintTarget target) throws PaintException { - target.startTag("visiblecolumns"); - if (rowHeadersAreEnabled()) { - target.startTag("column"); - target.addAttribute("cid", ROW_HEADER_COLUMN_KEY); - paintColumnWidth(target, ROW_HEADER_FAKE_PROPERTY_ID); - target.endTag("column"); - } - final Collection<?> sortables = getSortableContainerPropertyIds(); - for (Object colId : visibleColumns) { - if (colId != null) { - target.startTag("column"); - target.addAttribute("cid", columnIdMap.key(colId)); - final String head = getColumnHeader(colId); - target.addAttribute("caption", (head != null ? head : "")); - final String foot = getColumnFooter(colId); - target.addAttribute("fcaption", (foot != null ? foot : "")); - if (isColumnCollapsed(colId)) { - target.addAttribute("collapsed", true); - } - if (areColumnHeadersEnabled()) { - if (getColumnIcon(colId) != null) { - target.addAttribute("icon", getColumnIcon(colId)); - } - if (sortables.contains(colId)) { - target.addAttribute("sortable", true); - } - } - if (!Align.LEFT.equals(getColumnAlignment(colId))) { - target.addAttribute("align", getColumnAlignment(colId) - .toString()); - } - paintColumnWidth(target, colId); - target.endTag("column"); - } - } - target.endTag("visiblecolumns"); - } - - private void paintAvailableColumns(PaintTarget target) - throws PaintException { - if (columnCollapsingAllowed) { - final HashSet<Object> collapsedCols = new HashSet<Object>(); - for (Object colId : visibleColumns) { - if (isColumnCollapsed(colId)) { - collapsedCols.add(colId); - } - } - final String[] collapsedKeys = new String[collapsedCols.size()]; - int nextColumn = 0; - for (Object colId : visibleColumns) { - if (isColumnCollapsed(colId)) { - collapsedKeys[nextColumn++] = columnIdMap.key(colId); - } - } - target.addVariable(this, "collapsedcolumns", collapsedKeys); - - final String[] noncollapsibleKeys = new String[noncollapsibleColumns - .size()]; - nextColumn = 0; - for (Object colId : noncollapsibleColumns) { - noncollapsibleKeys[nextColumn++] = columnIdMap.key(colId); - } - target.addVariable(this, "noncollapsiblecolumns", - noncollapsibleKeys); - } - - } - - private void paintActions(PaintTarget target, final Set<Action> actionSet) - throws PaintException { - if (!actionSet.isEmpty()) { - target.addVariable(this, "action", ""); - target.startTag("actions"); - for (Action a : actionSet) { - target.startTag("action"); - if (a.getCaption() != null) { - target.addAttribute("caption", a.getCaption()); - } - if (a.getIcon() != null) { - target.addAttribute("icon", a.getIcon()); - } - target.addAttribute("key", actionMapper.key(a)); - target.endTag("action"); - } - target.endTag("actions"); - } - } - - private void paintColumnOrder(PaintTarget target) throws PaintException { - if (columnReorderingAllowed) { - final String[] colorder = new String[visibleColumns.size()]; - int i = 0; - for (Object colId : visibleColumns) { - colorder[i++] = columnIdMap.key(colId); - } - target.addVariable(this, "columnorder", colorder); - } - } - - private void paintSorting(PaintTarget target) throws PaintException { - // Sorting - if (getContainerDataSource() instanceof Container.Sortable) { - target.addVariable(this, "sortcolumn", - columnIdMap.key(sortContainerPropertyId)); - target.addVariable(this, "sortascending", sortAscending); - } - } - - private void paintRows(PaintTarget target, final Object[][] cells, - final Set<Action> actionSet) throws PaintException { - final boolean[] iscomponent = findCellsWithComponents(); - - target.startTag("rows"); - // cells array contains all that are supposed to be visible on client, - // but we'll start from the one requested by client - int start = 0; - if (reqFirstRowToPaint != -1 && firstToBeRenderedInClient != -1) { - start = reqFirstRowToPaint - firstToBeRenderedInClient; - } - int end = cells[0].length; - if (reqRowsToPaint != -1) { - end = start + reqRowsToPaint; - } - // sanity check - if (lastToBeRenderedInClient != -1 && lastToBeRenderedInClient < end) { - end = lastToBeRenderedInClient + 1; - } - if (start > cells[CELL_ITEMID].length || start < 0) { - start = 0; - } - if (end > cells[CELL_ITEMID].length) { - end = cells[CELL_ITEMID].length; - } - - for (int indexInRowbuffer = start; indexInRowbuffer < end; indexInRowbuffer++) { - final Object itemId = cells[CELL_ITEMID][indexInRowbuffer]; - - if (shouldHideNullSelectionItem()) { - // Remove null selection item if null selection is not allowed - continue; - } - - paintRow(target, cells, isEditable(), actionSet, iscomponent, - indexInRowbuffer, itemId); - } - target.endTag("rows"); - } - - private boolean[] findCellsWithComponents() { - final boolean[] isComponent = new boolean[visibleColumns.size()]; - int ix = 0; - for (Object columnId : visibleColumns) { - if (columnGenerators.containsKey(columnId)) { - isComponent[ix++] = true; - } else { - final Class<?> colType = getType(columnId); - isComponent[ix++] = colType != null - && Component.class.isAssignableFrom(colType); - } - } - return isComponent; - } - - private void paintVisibleColumnOrder(PaintTarget target) { - // Visible column order - final ArrayList<String> visibleColOrder = new ArrayList<String>(); - for (Object columnId : visibleColumns) { - if (!isColumnCollapsed(columnId)) { - visibleColOrder.add(columnIdMap.key(columnId)); - } - } - target.addAttribute("vcolorder", visibleColOrder.toArray()); - } - - private Set<Action> findAndPaintBodyActions(PaintTarget target) { - Set<Action> actionSet = new LinkedHashSet<Action>(); - if (actionHandlers != null) { - final ArrayList<String> keys = new ArrayList<String>(); - for (Handler ah : actionHandlers) { - // Getting actions for the null item, which in this case means - // the body item - final Action[] actions = ah.getActions(null, this); - if (actions != null) { - for (Action action : actions) { - actionSet.add(action); - keys.add(actionMapper.key(action)); - } - } - } - target.addAttribute("alb", keys.toArray()); - } - return actionSet; - } - - private boolean shouldHideNullSelectionItem() { - return !isNullSelectionAllowed() && getNullSelectionItemId() != null - && containsId(getNullSelectionItemId()); - } - - private int findNumRowsToPaint(PaintTarget target, final Object[][] cells) - throws PaintException { - int rows; - if (reqRowsToPaint >= 0) { - rows = reqRowsToPaint; - } else { - rows = cells[0].length; - if (alwaysRecalculateColumnWidths) { - // TODO experimental feature for now: tell the client to - // recalculate column widths. - // We'll only do this for paints that do not originate from - // table scroll/cache requests (i.e when reqRowsToPaint<0) - target.addAttribute("recalcWidths", true); - } - } - return rows; - } - - private void paintSelectMode(PaintTarget target) throws PaintException { - if (multiSelectMode != MultiSelectMode.DEFAULT) { - target.addAttribute("multiselectmode", multiSelectMode.ordinal()); - } - if (isSelectable()) { - target.addAttribute("selectmode", (isMultiSelect() ? "multi" - : "single")); - } else { - target.addAttribute("selectmode", "none"); - } - if (!isNullSelectionAllowed()) { - target.addAttribute("nsa", false); - } - - // selection support - // The select variable is only enabled if selectable - if (isSelectable()) { - target.addVariable(this, "selected", findSelectedKeys()); - } - } - - private String[] findSelectedKeys() { - LinkedList<String> selectedKeys = new LinkedList<String>(); - if (isMultiSelect()) { - HashSet<?> sel = new HashSet<Object>((Set<?>) getValue()); - Collection<?> vids = getVisibleItemIds(); - for (Iterator<?> it = vids.iterator(); it.hasNext();) { - Object id = it.next(); - if (sel.contains(id)) { - selectedKeys.add(itemIdMapper.key(id)); - } - } - } else { - Object value = getValue(); - if (value == null) { - value = getNullSelectionItemId(); - } - if (value != null) { - selectedKeys.add(itemIdMapper.key(value)); - } - } - return selectedKeys.toArray(new String[selectedKeys.size()]); - } - - private void paintDragMode(PaintTarget target) throws PaintException { - if (dragMode != TableDragMode.NONE) { - target.addAttribute("dragmode", dragMode.ordinal()); - } - } - - private void paintTabIndex(PaintTarget target) throws PaintException { - // The tab ordering number - if (getTabIndex() > 0) { - target.addAttribute("tabindex", getTabIndex()); - } - } - - private void paintColumnWidth(PaintTarget target, final Object columnId) - throws PaintException { - if (columnWidths.containsKey(columnId)) { - if (getColumnWidth(columnId) > -1) { - target.addAttribute("width", - String.valueOf(getColumnWidth(columnId))); - } else { - target.addAttribute("er", getColumnExpandRatio(columnId)); - } - } - } - - private boolean rowHeadersAreEnabled() { - return getRowHeaderMode() != ROW_HEADER_MODE_HIDDEN; - } - - private void paintRow(PaintTarget target, final Object[][] cells, - final boolean iseditable, final Set<Action> actionSet, - final boolean[] iscomponent, int indexInRowbuffer, - final Object itemId) throws PaintException { - target.startTag("tr"); - - paintRowAttributes(target, cells, actionSet, indexInRowbuffer, itemId); - - // cells - int currentColumn = 0; - for (final Iterator<Object> it = visibleColumns.iterator(); it - .hasNext(); currentColumn++) { - final Object columnId = it.next(); - if (columnId == null || isColumnCollapsed(columnId)) { - continue; - } - /* - * For each cell, if a cellStyleGenerator is specified, get the - * specific style for the cell. If there is any, add it to the - * target. - */ - if (cellStyleGenerator != null) { - String cellStyle = cellStyleGenerator - .getStyle(itemId, columnId); - if (cellStyle != null && !cellStyle.equals("")) { - target.addAttribute("style-" + columnIdMap.key(columnId), - cellStyle); - } - } - - if ((iscomponent[currentColumn] || iseditable || cells[CELL_GENERATED_ROW][indexInRowbuffer] != null) - && Component.class.isInstance(cells[CELL_FIRSTCOL - + currentColumn][indexInRowbuffer])) { - final Component c = (Component) cells[CELL_FIRSTCOL - + currentColumn][indexInRowbuffer]; - if (c == null) { - target.addText(""); - paintCellTooltips(target, itemId, columnId); - } else { - LegacyPaint.paint(c, target); - } - } else { - target.addText((String) cells[CELL_FIRSTCOL + currentColumn][indexInRowbuffer]); - paintCellTooltips(target, itemId, columnId); - } - } - - target.endTag("tr"); - } - - private void paintCellTooltips(PaintTarget target, Object itemId, - Object columnId) throws PaintException { - if (itemDescriptionGenerator != null) { - String itemDescription = itemDescriptionGenerator - .generateDescription(this, itemId, columnId); - if (itemDescription != null && !itemDescription.equals("")) { - target.addAttribute("descr-" + columnIdMap.key(columnId), - itemDescription); - } - } - } - - private void paintRowTooltips(PaintTarget target, Object itemId) - throws PaintException { - if (itemDescriptionGenerator != null) { - String rowDescription = itemDescriptionGenerator - .generateDescription(this, itemId, null); - if (rowDescription != null && !rowDescription.equals("")) { - target.addAttribute("rowdescr", rowDescription); - } - } - } - - private void paintRowAttributes(PaintTarget target, final Object[][] cells, - final Set<Action> actionSet, int indexInRowbuffer, - final Object itemId) throws PaintException { - // tr attributes - - paintRowIcon(target, cells, indexInRowbuffer); - paintRowHeader(target, cells, indexInRowbuffer); - paintGeneratedRowInfo(target, cells, indexInRowbuffer); - target.addAttribute("key", - Integer.parseInt(cells[CELL_KEY][indexInRowbuffer].toString())); - - if (isSelected(itemId)) { - target.addAttribute("selected", true); - } - - // Actions - if (actionHandlers != null) { - final ArrayList<String> keys = new ArrayList<String>(); - for (Handler ah : actionHandlers) { - final Action[] aa = ah.getActions(itemId, this); - if (aa != null) { - for (int ai = 0; ai < aa.length; ai++) { - final String key = actionMapper.key(aa[ai]); - actionSet.add(aa[ai]); - keys.add(key); - } - } - } - target.addAttribute("al", keys.toArray()); - } - - /* - * For each row, if a cellStyleGenerator is specified, get the specific - * style for the cell, using null as propertyId. If there is any, add it - * to the target. - */ - if (cellStyleGenerator != null) { - String rowStyle = cellStyleGenerator.getStyle(itemId, null); - if (rowStyle != null && !rowStyle.equals("")) { - target.addAttribute("rowstyle", rowStyle); - } - } - - paintRowTooltips(target, itemId); - - paintRowAttributes(target, itemId); - } - - private void paintGeneratedRowInfo(PaintTarget target, Object[][] cells, - int indexInRowBuffer) throws PaintException { - GeneratedRow generatedRow = (GeneratedRow) cells[CELL_GENERATED_ROW][indexInRowBuffer]; - if (generatedRow != null) { - target.addAttribute("gen_html", generatedRow.isHtmlContentAllowed()); - target.addAttribute("gen_span", generatedRow.isSpanColumns()); - target.addAttribute("gen_widget", - generatedRow.getValue() instanceof Component); - } - } - - protected void paintRowHeader(PaintTarget target, Object[][] cells, - int indexInRowbuffer) throws PaintException { - if (rowHeadersAreEnabled()) { - if (cells[CELL_HEADER][indexInRowbuffer] != null) { - target.addAttribute("caption", - (String) cells[CELL_HEADER][indexInRowbuffer]); - } - } - - } - - protected void paintRowIcon(PaintTarget target, final Object[][] cells, - int indexInRowbuffer) throws PaintException { - if (rowHeadersAreEnabled() - && cells[CELL_ICON][indexInRowbuffer] != null) { - target.addAttribute("icon", - (Resource) cells[CELL_ICON][indexInRowbuffer]); - } - } - - /** - * A method where extended Table implementations may add their custom - * attributes for rows. - * - * @param target - * @param itemId - */ - protected void paintRowAttributes(PaintTarget target, Object itemId) - throws PaintException { - - } - - /** - * Gets the cached visible table contents. - * - * @return the cached visible table contents. - */ - private Object[][] getVisibleCells() { - if (pageBuffer == null) { - refreshRenderedCells(); - } - return pageBuffer; - } - - /** - * Gets the value of property. - * - * By default if the table is editable the fieldFactory is used to create - * editors for table cells. Otherwise formatPropertyValue is used to format - * the value representation. - * - * @param rowId - * the Id of the row (same as item Id). - * @param colId - * the Id of the column. - * @param property - * the Property to be presented. - * @return Object Either formatted value or Component for field. - * @see #setTableFieldFactory(TableFieldFactory) - */ - protected Object getPropertyValue(Object rowId, Object colId, - Property property) { - if (isEditable() && fieldFactory != null) { - final Field<?> f = fieldFactory.createField( - getContainerDataSource(), rowId, colId, this); - if (f != null) { - // Remember that we have made this association so we can remove - // it when the component is removed - associatedProperties.put(f, property); - bindPropertyToField(rowId, colId, property, f); - return f; - } - } - - return formatPropertyValue(rowId, colId, property); - } - - /** - * Binds an item property to a field generated by TableFieldFactory. The - * default behavior is to bind property straight to Field. If - * Property.Viewer type property (e.g. PropertyFormatter) is already set for - * field, the property is bound to that Property.Viewer. - * - * @param rowId - * @param colId - * @param property - * @param field - * @since 6.7.3 - */ - protected void bindPropertyToField(Object rowId, Object colId, - Property property, Field field) { - // check if field has a property that is Viewer set. In that case we - // expect developer has e.g. PropertyFormatter that he wishes to use and - // assign the property to the Viewer instead. - boolean hasFilterProperty = field.getPropertyDataSource() != null - && (field.getPropertyDataSource() instanceof Property.Viewer); - if (hasFilterProperty) { - ((Property.Viewer) field.getPropertyDataSource()) - .setPropertyDataSource(property); - } else { - field.setPropertyDataSource(property); - } - } - - /** - * Formats table cell property values. By default the property.toString() - * and return a empty string for null properties. - * - * @param rowId - * the Id of the row (same as item Id). - * @param colId - * the Id of the column. - * @param property - * the Property to be formatted. - * @return the String representation of property and its value. - * @since 3.1 - */ - protected String formatPropertyValue(Object rowId, Object colId, - Property<?> property) { - if (property == null) { - return ""; - } - Converter<String, Object> converter = null; - - if (hasConverter(colId)) { - converter = getConverter(colId); - } else { - ConverterUtil.getConverter(String.class, property.getType(), - getApplication()); - } - Object value = property.getValue(); - if (converter != null) { - return converter.convertToPresentation(value, getLocale()); - } - return (null != value) ? value.toString() : ""; - } - - /* Action container */ - - /** - * Registers a new action handler for this container - * - * @see com.vaadin.event.Action.Container#addActionHandler(Action.Handler) - */ - - @Override - public void addActionHandler(Action.Handler actionHandler) { - - if (actionHandler != null) { - - if (actionHandlers == null) { - actionHandlers = new LinkedList<Handler>(); - actionMapper = new KeyMapper<Action>(); - } - - if (!actionHandlers.contains(actionHandler)) { - actionHandlers.add(actionHandler); - // Assures the visual refresh. No need to reset the page buffer - // before as the content has not changed, only the action - // handlers. - refreshRenderedCells(); - } - - } - } - - /** - * Removes a previously registered action handler for the contents of this - * container. - * - * @see com.vaadin.event.Action.Container#removeActionHandler(Action.Handler) - */ - - @Override - public void removeActionHandler(Action.Handler actionHandler) { - - if (actionHandlers != null && actionHandlers.contains(actionHandler)) { - - actionHandlers.remove(actionHandler); - - if (actionHandlers.isEmpty()) { - actionHandlers = null; - actionMapper = null; - } - - // Assures the visual refresh. No need to reset the page buffer - // before as the content has not changed, only the action - // handlers. - refreshRenderedCells(); - } - } - - /** - * Removes all action handlers - */ - public void removeAllActionHandlers() { - actionHandlers = null; - actionMapper = null; - // Assures the visual refresh. No need to reset the page buffer - // before as the content has not changed, only the action - // handlers. - refreshRenderedCells(); - } - - /* Property value change listening support */ - - /** - * Notifies this listener that the Property's value has changed. - * - * Also listens changes in rendered items to refresh content area. - * - * @see com.vaadin.data.Property.ValueChangeListener#valueChange(Property.ValueChangeEvent) - */ - - @Override - public void valueChange(Property.ValueChangeEvent event) { - if (event.getProperty() == this - || event.getProperty() == getPropertyDataSource()) { - super.valueChange(event); - } else { - refreshRowCache(); - containerChangeToBeRendered = true; - } - requestRepaint(); - } - - /** - * Clears the current page buffer. Call this before - * {@link #refreshRenderedCells()} to ensure that all content is updated - * from the properties. - */ - protected void resetPageBuffer() { - firstToBeRenderedInClient = -1; - lastToBeRenderedInClient = -1; - reqFirstRowToPaint = -1; - reqRowsToPaint = -1; - pageBuffer = null; - } - - /** - * Notifies the component that it is connected to an application. - * - * @see com.vaadin.ui.Component#attach() - */ - - @Override - public void attach() { - super.attach(); - - refreshRenderedCells(); - } - - /** - * Notifies the component that it is detached from the application - * - * @see com.vaadin.ui.Component#detach() - */ - - @Override - public void detach() { - super.detach(); - } - - /** - * Removes all Items from the Container. - * - * @see com.vaadin.data.Container#removeAllItems() - */ - - @Override - public boolean removeAllItems() { - currentPageFirstItemId = null; - currentPageFirstItemIndex = 0; - return super.removeAllItems(); - } - - /** - * Removes the Item identified by <code>ItemId</code> from the Container. - * - * @see com.vaadin.data.Container#removeItem(Object) - */ - - @Override - public boolean removeItem(Object itemId) { - final Object nextItemId = nextItemId(itemId); - final boolean ret = super.removeItem(itemId); - if (ret && (itemId != null) && (itemId.equals(currentPageFirstItemId))) { - currentPageFirstItemId = nextItemId; - } - if (!(items instanceof Container.ItemSetChangeNotifier)) { - refreshRowCache(); - } - return ret; - } - - /** - * Removes a Property specified by the given Property ID from the Container. - * - * @see com.vaadin.data.Container#removeContainerProperty(Object) - */ - - @Override - public boolean removeContainerProperty(Object propertyId) - throws UnsupportedOperationException { - - // If a visible property is removed, remove the corresponding column - visibleColumns.remove(propertyId); - columnAlignments.remove(propertyId); - columnIcons.remove(propertyId); - columnHeaders.remove(propertyId); - columnFooters.remove(propertyId); - - return super.removeContainerProperty(propertyId); - } - - /** - * Adds a new property to the table and show it as a visible column. - * - * @param propertyId - * the Id of the proprty. - * @param type - * the class of the property. - * @param defaultValue - * the default value given for all existing items. - * @see com.vaadin.data.Container#addContainerProperty(Object, Class, - * Object) - */ - - @Override - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue) throws UnsupportedOperationException { - - boolean visibleColAdded = false; - if (!visibleColumns.contains(propertyId)) { - visibleColumns.add(propertyId); - visibleColAdded = true; - } - - if (!super.addContainerProperty(propertyId, type, defaultValue)) { - if (visibleColAdded) { - visibleColumns.remove(propertyId); - } - return false; - } - if (!(items instanceof Container.PropertySetChangeNotifier)) { - refreshRowCache(); - } - return true; - } - - /** - * Adds a new property to the table and show it as a visible column. - * - * @param propertyId - * the Id of the proprty - * @param type - * the class of the property - * @param defaultValue - * the default value given for all existing items - * @param columnHeader - * the Explicit header of the column. If explicit header is not - * needed, this should be set null. - * @param columnIcon - * the Icon of the column. If icon is not needed, this should be - * set null. - * @param columnAlignment - * the Alignment of the column. Null implies align left. - * @throws UnsupportedOperationException - * if the operation is not supported. - * @see com.vaadin.data.Container#addContainerProperty(Object, Class, - * Object) - */ - public boolean addContainerProperty(Object propertyId, Class<?> type, - Object defaultValue, String columnHeader, Resource columnIcon, - Align columnAlignment) throws UnsupportedOperationException { - if (!this.addContainerProperty(propertyId, type, defaultValue)) { - return false; - } - setColumnAlignment(propertyId, columnAlignment); - setColumnHeader(propertyId, columnHeader); - setColumnIcon(propertyId, columnIcon); - return true; - } - - /** - * Adds a generated column to the Table. - * <p> - * A generated column is a column that exists only in the Table, not as a - * property in the underlying Container. It shows up just as a regular - * column. - * </p> - * <p> - * A generated column will override a property with the same id, so that the - * generated column is shown instead of the column representing the - * property. Note that getContainerProperty() will still get the real - * property. - * </p> - * <p> - * Table will not listen to value change events from properties overridden - * by generated columns. If the content of your generated column depends on - * properties that are not directly visible in the table, attach value - * change listener to update the content on all depended properties. - * Otherwise your UI might not get updated as expected. - * </p> - * <p> - * Also note that getVisibleColumns() will return the generated columns, - * while getContainerPropertyIds() will not. - * </p> - * - * @param id - * the id of the column to be added - * @param generatedColumn - * the {@link ColumnGenerator} to use for this column - */ - public void addGeneratedColumn(Object id, ColumnGenerator generatedColumn) { - if (generatedColumn == null) { - throw new IllegalArgumentException( - "Can not add null as a GeneratedColumn"); - } - if (columnGenerators.containsKey(id)) { - throw new IllegalArgumentException( - "Can not add the same GeneratedColumn twice, id:" + id); - } else { - columnGenerators.put(id, generatedColumn); - /* - * add to visible column list unless already there (overriding - * column from DS) - */ - if (!visibleColumns.contains(id)) { - visibleColumns.add(id); - } - refreshRowCache(); - } - } - - /** - * Returns the ColumnGenerator used to generate the given column. - * - * @param columnId - * The id of the generated column - * @return The ColumnGenerator used for the given columnId or null. - */ - public ColumnGenerator getColumnGenerator(Object columnId) - throws IllegalArgumentException { - return columnGenerators.get(columnId); - } - - /** - * Removes a generated column previously added with addGeneratedColumn. - * - * @param columnId - * id of the generated column to remove - * @return true if the column could be removed (existed in the Table) - */ - public boolean removeGeneratedColumn(Object columnId) { - if (columnGenerators.containsKey(columnId)) { - columnGenerators.remove(columnId); - // remove column from visibleColumns list unless it exists in - // container (generator previously overrode this column) - if (!items.getContainerPropertyIds().contains(columnId)) { - visibleColumns.remove(columnId); - } - refreshRowCache(); - return true; - } else { - return false; - } - } - - /** - * Returns item identifiers of the items which are currently rendered on the - * client. - * <p> - * Note, that some due to historical reasons the name of the method is bit - * misleading. Some items may be partly or totally out of the viewport of - * the table's scrollable area. Actually detecting rows which can be - * actually seen by the end user may be problematic due to the client server - * architecture. Using {@link #getCurrentPageFirstItemId()} combined with - * {@link #getPageLength()} may produce good enough estimates in some - * situations. - * - * @see com.vaadin.ui.Select#getVisibleItemIds() - */ - - @Override - public Collection<?> getVisibleItemIds() { - - final LinkedList<Object> visible = new LinkedList<Object>(); - - final Object[][] cells = getVisibleCells(); - // may be null if the table has not been rendered yet (e.g. not attached - // to a layout) - if (null != cells) { - for (int i = 0; i < cells[CELL_ITEMID].length; i++) { - visible.add(cells[CELL_ITEMID][i]); - } - } - - return visible; - } - - /** - * Container datasource item set change. Table must flush its buffers on - * change. - * - * @see com.vaadin.data.Container.ItemSetChangeListener#containerItemSetChange(com.vaadin.data.Container.ItemSetChangeEvent) - */ - - @Override - public void containerItemSetChange(Container.ItemSetChangeEvent event) { - super.containerItemSetChange(event); - - // super method clears the key map, must inform client about this to - // avoid getting invalid keys back (#8584) - keyMapperReset = true; - - // ensure that page still has first item in page, ignore buffer refresh - // (forced in this method) - setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex(), false); - refreshRowCache(); - } - - /** - * Container datasource property set change. Table must flush its buffers on - * change. - * - * @see com.vaadin.data.Container.PropertySetChangeListener#containerPropertySetChange(com.vaadin.data.Container.PropertySetChangeEvent) - */ - - @Override - public void containerPropertySetChange( - Container.PropertySetChangeEvent event) { - disableContentRefreshing(); - super.containerPropertySetChange(event); - - // sanitetize visibleColumns. note that we are not adding previously - // non-existing properties as columns - Collection<?> containerPropertyIds = getContainerDataSource() - .getContainerPropertyIds(); - - LinkedList<Object> newVisibleColumns = new LinkedList<Object>( - visibleColumns); - for (Iterator<Object> iterator = newVisibleColumns.iterator(); iterator - .hasNext();) { - Object id = iterator.next(); - if (!(containerPropertyIds.contains(id) || columnGenerators - .containsKey(id))) { - iterator.remove(); - } - } - setVisibleColumns(newVisibleColumns.toArray()); - // same for collapsed columns - for (Iterator<Object> iterator = collapsedColumns.iterator(); iterator - .hasNext();) { - Object id = iterator.next(); - if (!(containerPropertyIds.contains(id) || columnGenerators - .containsKey(id))) { - iterator.remove(); - } - } - - resetPageBuffer(); - enableContentRefreshing(true); - } - - /** - * Adding new items is not supported. - * - * @throws UnsupportedOperationException - * if set to true. - * @see com.vaadin.ui.Select#setNewItemsAllowed(boolean) - */ - - @Override - public void setNewItemsAllowed(boolean allowNewOptions) - throws UnsupportedOperationException { - if (allowNewOptions) { - throw new UnsupportedOperationException(); - } - } - - /** - * Gets the ID of the Item following the Item that corresponds to itemId. - * - * @see com.vaadin.data.Container.Ordered#nextItemId(java.lang.Object) - */ - - @Override - public Object nextItemId(Object itemId) { - return ((Container.Ordered) items).nextItemId(itemId); - } - - /** - * Gets the ID of the Item preceding the Item that corresponds to the - * itemId. - * - * @see com.vaadin.data.Container.Ordered#prevItemId(java.lang.Object) - */ - - @Override - public Object prevItemId(Object itemId) { - return ((Container.Ordered) items).prevItemId(itemId); - } - - /** - * Gets the ID of the first Item in the Container. - * - * @see com.vaadin.data.Container.Ordered#firstItemId() - */ - - @Override - public Object firstItemId() { - return ((Container.Ordered) items).firstItemId(); - } - - /** - * Gets the ID of the last Item in the Container. - * - * @see com.vaadin.data.Container.Ordered#lastItemId() - */ - - @Override - public Object lastItemId() { - return ((Container.Ordered) items).lastItemId(); - } - - /** - * Tests if the Item corresponding to the given Item ID is the first Item in - * the Container. - * - * @see com.vaadin.data.Container.Ordered#isFirstId(java.lang.Object) - */ - - @Override - public boolean isFirstId(Object itemId) { - return ((Container.Ordered) items).isFirstId(itemId); - } - - /** - * Tests if the Item corresponding to the given Item ID is the last Item in - * the Container. - * - * @see com.vaadin.data.Container.Ordered#isLastId(java.lang.Object) - */ - - @Override - public boolean isLastId(Object itemId) { - return ((Container.Ordered) items).isLastId(itemId); - } - - /** - * Adds new item after the given item. - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object) - */ - - @Override - public Object addItemAfter(Object previousItemId) - throws UnsupportedOperationException { - Object itemId = ((Container.Ordered) items) - .addItemAfter(previousItemId); - if (!(items instanceof Container.ItemSetChangeNotifier)) { - refreshRowCache(); - } - return itemId; - } - - /** - * Adds new item after the given item. - * - * @see com.vaadin.data.Container.Ordered#addItemAfter(java.lang.Object, - * java.lang.Object) - */ - - @Override - public Item addItemAfter(Object previousItemId, Object newItemId) - throws UnsupportedOperationException { - Item item = ((Container.Ordered) items).addItemAfter(previousItemId, - newItemId); - if (!(items instanceof Container.ItemSetChangeNotifier)) { - refreshRowCache(); - } - return item; - } - - /** - * Sets the TableFieldFactory that is used to create editor for table cells. - * - * The TableFieldFactory is only used if the Table is editable. By default - * the DefaultFieldFactory is used. - * - * @param fieldFactory - * the field factory to set. - * @see #isEditable - * @see DefaultFieldFactory - */ - public void setTableFieldFactory(TableFieldFactory fieldFactory) { - this.fieldFactory = fieldFactory; - - // Assure visual refresh - refreshRowCache(); - } - - /** - * Gets the TableFieldFactory that is used to create editor for table cells. - * - * The FieldFactory is only used if the Table is editable. - * - * @return TableFieldFactory used to create the Field instances. - * @see #isEditable - */ - public TableFieldFactory getTableFieldFactory() { - return fieldFactory; - } - - /** - * Is table editable. - * - * If table is editable a editor of type Field is created for each table - * cell. The assigned FieldFactory is used to create the instances. - * - * To provide custom editors for table cells create a class implementins the - * FieldFactory interface, and assign it to table, and set the editable - * property to true. - * - * @return true if table is editable, false oterwise. - * @see Field - * @see FieldFactory - * - */ - public boolean isEditable() { - return editable; - } - - /** - * Sets the editable property. - * - * If table is editable a editor of type Field is created for each table - * cell. The assigned FieldFactory is used to create the instances. - * - * To provide custom editors for table cells create a class implementins the - * FieldFactory interface, and assign it to table, and set the editable - * property to true. - * - * @param editable - * true if table should be editable by user. - * @see Field - * @see FieldFactory - * - */ - public void setEditable(boolean editable) { - this.editable = editable; - - // Assure visual refresh - refreshRowCache(); - } - - /** - * Sorts the table. - * - * @throws UnsupportedOperationException - * if the container data source does not implement - * Container.Sortable - * @see com.vaadin.data.Container.Sortable#sort(java.lang.Object[], - * boolean[]) - * - */ - - @Override - public void sort(Object[] propertyId, boolean[] ascending) - throws UnsupportedOperationException { - final Container c = getContainerDataSource(); - if (c instanceof Container.Sortable) { - final int pageIndex = getCurrentPageFirstItemIndex(); - ((Container.Sortable) c).sort(propertyId, ascending); - setCurrentPageFirstItemIndex(pageIndex); - refreshRowCache(); - - } else if (c != null) { - throw new UnsupportedOperationException( - "Underlying Data does not allow sorting"); - } - } - - /** - * Sorts the table by currently selected sorting column. - * - * @throws UnsupportedOperationException - * if the container data source does not implement - * Container.Sortable - */ - public void sort() { - if (getSortContainerPropertyId() == null) { - return; - } - sort(new Object[] { sortContainerPropertyId }, - new boolean[] { sortAscending }); - } - - /** - * Gets the container property IDs, which can be used to sort the item. - * <p> - * Note that the {@link #isSortEnabled()} state affects what this method - * returns. Disabling sorting causes this method to always return an empty - * collection. - * </p> - * - * @see com.vaadin.data.Container.Sortable#getSortableContainerPropertyIds() - */ - - @Override - public Collection<?> getSortableContainerPropertyIds() { - final Container c = getContainerDataSource(); - if (c instanceof Container.Sortable && isSortEnabled()) { - return ((Container.Sortable) c).getSortableContainerPropertyIds(); - } else { - return Collections.EMPTY_LIST; - } - } - - /** - * Gets the currently sorted column property ID. - * - * @return the Container property id of the currently sorted column. - */ - public Object getSortContainerPropertyId() { - return sortContainerPropertyId; - } - - /** - * Sets the currently sorted column property id. - * - * @param propertyId - * the Container property id of the currently sorted column. - */ - public void setSortContainerPropertyId(Object propertyId) { - setSortContainerPropertyId(propertyId, true); - } - - /** - * Internal method to set currently sorted column property id. With doSort - * flag actual sorting may be bypassed. - * - * @param propertyId - * @param doSort - */ - private void setSortContainerPropertyId(Object propertyId, boolean doSort) { - if ((sortContainerPropertyId != null && !sortContainerPropertyId - .equals(propertyId)) - || (sortContainerPropertyId == null && propertyId != null)) { - sortContainerPropertyId = propertyId; - - if (doSort) { - sort(); - // Assures the visual refresh. This should not be necessary as - // sort() calls refreshRowCache - refreshRenderedCells(); - } - } - } - - /** - * Is the table currently sorted in ascending order. - * - * @return <code>true</code> if ascending, <code>false</code> if descending. - */ - public boolean isSortAscending() { - return sortAscending; - } - - /** - * Sets the table in ascending order. - * - * @param ascending - * <code>true</code> if ascending, <code>false</code> if - * descending. - */ - public void setSortAscending(boolean ascending) { - setSortAscending(ascending, true); - } - - /** - * Internal method to set sort ascending. With doSort flag actual sort can - * be bypassed. - * - * @param ascending - * @param doSort - */ - private void setSortAscending(boolean ascending, boolean doSort) { - if (sortAscending != ascending) { - sortAscending = ascending; - if (doSort) { - sort(); - // Assures the visual refresh. This should not be necessary as - // sort() calls refreshRowCache - refreshRenderedCells(); - } - } - } - - /** - * Is sorting disabled altogether. - * - * True iff no sortable columns are given even in the case where data source - * would support this. - * - * @return True iff sorting is disabled. - * @deprecated Use {@link #isSortEnabled()} instead - */ - @Deprecated - public boolean isSortDisabled() { - return !isSortEnabled(); - } - - /** - * Checks if sorting is enabled. - * - * @return true if sorting by the user is allowed, false otherwise - */ - public boolean isSortEnabled() { - return sortEnabled; - } - - /** - * Disables the sorting by the user altogether. - * - * @param sortDisabled - * True iff sorting is disabled. - * @deprecated Use {@link #setSortEnabled(boolean)} instead - */ - @Deprecated - public void setSortDisabled(boolean sortDisabled) { - setSortEnabled(!sortDisabled); - } - - /** - * Enables or disables sorting. - * <p> - * Setting this to false disallows sorting by the user. It is still possible - * to call {@link #sort()}. - * </p> - * - * @param sortEnabled - * true to allow the user to sort the table, false to disallow it - */ - public void setSortEnabled(boolean sortEnabled) { - if (this.sortEnabled != sortEnabled) { - this.sortEnabled = sortEnabled; - requestRepaint(); - } - } - - /** - * Used to create "generated columns"; columns that exist only in the Table, - * not in the underlying Container. Implement this interface and pass it to - * Table.addGeneratedColumn along with an id for the column to be generated. - * - */ - public interface ColumnGenerator extends Serializable { - - /** - * Called by Table when a cell in a generated column needs to be - * generated. - * - * @param source - * the source Table - * @param itemId - * the itemId (aka rowId) for the of the cell to be generated - * @param columnId - * the id for the generated column (as specified in - * addGeneratedColumn) - * @return A {@link Component} that should be rendered in the cell or a - * {@link String} that should be displayed in the cell. Other - * return values are not supported. - */ - public abstract Object generateCell(Table source, Object itemId, - Object columnId); - } - - /** - * Set cell style generator for Table. - * - * @param cellStyleGenerator - * New cell style generator or null to remove generator. - */ - public void setCellStyleGenerator(CellStyleGenerator cellStyleGenerator) { - this.cellStyleGenerator = cellStyleGenerator; - // Assures the visual refresh. No need to reset the page buffer - // before as the content has not changed, only the style generators - refreshRenderedCells(); - - } - - /** - * Get the current cell style generator. - * - */ - public CellStyleGenerator getCellStyleGenerator() { - return cellStyleGenerator; - } - - /** - * Allow to define specific style on cells (and rows) contents. Implements - * this interface and pass it to Table.setCellStyleGenerator. Row styles are - * generated when porpertyId is null. The CSS class name that will be added - * to the cell content is <tt>v-table-cell-content-[style name]</tt>, and - * the row style will be <tt>v-table-row-[style name]</tt>. - */ - public interface CellStyleGenerator extends Serializable { - - /** - * Called by Table when a cell (and row) is painted. - * - * @param itemId - * The itemId of the painted cell - * @param propertyId - * The propertyId of the cell, null when getting row style - * @return The style name to add to this cell or row. (the CSS class - * name will be v-table-cell-content-[style name], or - * v-table-row-[style name] for rows) - */ - public abstract String getStyle(Object itemId, Object propertyId); - } - - @Override - public void addListener(ItemClickListener listener) { - addListener(VScrollTable.ITEM_CLICK_EVENT_ID, ItemClickEvent.class, - listener, ItemClickEvent.ITEM_CLICK_METHOD); - } - - @Override - public void removeListener(ItemClickListener listener) { - removeListener(VScrollTable.ITEM_CLICK_EVENT_ID, ItemClickEvent.class, - listener); - } - - // Identical to AbstractCompoenentContainer.setEnabled(); - - @Override - public void setEnabled(boolean enabled) { - super.setEnabled(enabled); - if (getParent() != null && !getParent().isEnabled()) { - // some ancestor still disabled, don't update children - return; - } else { - requestRepaintAll(); - } - } - - /** - * Sets the drag start mode of the Table. Drag start mode controls how Table - * behaves as a drag source. - * - * @param newDragMode - */ - public void setDragMode(TableDragMode newDragMode) { - dragMode = newDragMode; - requestRepaint(); - } - - /** - * @return the current start mode of the Table. Drag start mode controls how - * Table behaves as a drag source. - */ - public TableDragMode getDragMode() { - return dragMode; - } - - /** - * Concrete implementation of {@link DataBoundTransferable} for data - * transferred from a table. - * - * @see {@link DataBoundTransferable}. - * - * @since 6.3 - */ - public class TableTransferable extends DataBoundTransferable { - - protected TableTransferable(Map<String, Object> rawVariables) { - super(Table.this, rawVariables); - Object object = rawVariables.get("itemId"); - if (object != null) { - setData("itemId", itemIdMapper.get((String) object)); - } - object = rawVariables.get("propertyId"); - if (object != null) { - setData("propertyId", columnIdMap.get((String) object)); - } - } - - @Override - public Object getItemId() { - return getData("itemId"); - } - - @Override - public Object getPropertyId() { - return getData("propertyId"); - } - - @Override - public Table getSourceComponent() { - return (Table) super.getSourceComponent(); - } - - } - - @Override - public TableTransferable getTransferable(Map<String, Object> rawVariables) { - TableTransferable transferable = new TableTransferable(rawVariables); - return transferable; - } - - @Override - public DropHandler getDropHandler() { - return dropHandler; - } - - public void setDropHandler(DropHandler dropHandler) { - this.dropHandler = dropHandler; - } - - @Override - public AbstractSelectTargetDetails translateDropTargetDetails( - Map<String, Object> clientVariables) { - return new AbstractSelectTargetDetails(clientVariables); - } - - /** - * Sets the behavior of how the multi-select mode should behave when the - * table is both selectable and in multi-select mode. - * <p> - * Note, that on some clients the mode may not be respected. E.g. on touch - * based devices CTRL/SHIFT base selection method is invalid, so touch based - * browsers always use the {@link MultiSelectMode#SIMPLE}. - * - * @param mode - * The select mode of the table - */ - public void setMultiSelectMode(MultiSelectMode mode) { - multiSelectMode = mode; - requestRepaint(); - } - - /** - * Returns the select mode in which multi-select is used. - * - * @return The multi select mode - */ - public MultiSelectMode getMultiSelectMode() { - return multiSelectMode; - } - - /** - * Lazy loading accept criterion for Table. Accepted target rows are loaded - * from server once per drag and drop operation. Developer must override one - * method that decides on which rows the currently dragged data can be - * dropped. - * - * <p> - * Initially pretty much no data is sent to client. On first required - * criterion check (per drag request) the client side data structure is - * initialized from server and no subsequent requests requests are needed - * during that drag and drop operation. - */ - public static abstract class TableDropCriterion extends ServerSideCriterion { - - private Table table; - - private Set<Object> allowedItemIds; - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.acceptcriteria.ServerSideCriterion#getIdentifier - * () - */ - - @Override - protected String getIdentifier() { - return TableDropCriterion.class.getCanonicalName(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.acceptcriteria.AcceptCriterion#accepts(com.vaadin - * .event.dd.DragAndDropEvent) - */ - @Override - @SuppressWarnings("unchecked") - public boolean accept(DragAndDropEvent dragEvent) { - AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dragEvent - .getTargetDetails(); - table = (Table) dragEvent.getTargetDetails().getTarget(); - Collection<?> visibleItemIds = table.getVisibleItemIds(); - allowedItemIds = getAllowedItemIds(dragEvent, table, - (Collection<Object>) visibleItemIds); - - return allowedItemIds.contains(dropTargetData.getItemIdOver()); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.acceptcriteria.AcceptCriterion#paintResponse( - * com.vaadin.terminal.PaintTarget) - */ - - @Override - public void paintResponse(PaintTarget target) throws PaintException { - /* - * send allowed nodes to client so subsequent requests can be - * avoided - */ - Object[] array = allowedItemIds.toArray(); - for (int i = 0; i < array.length; i++) { - String key = table.itemIdMapper.key(array[i]); - array[i] = key; - } - target.addAttribute("allowedIds", array); - } - - /** - * @param dragEvent - * @param table - * the table for which the allowed item identifiers are - * defined - * @param visibleItemIds - * the list of currently rendered item identifiers, accepted - * item id's need to be detected only for these visible items - * @return the set of identifiers for items on which the dragEvent will - * be accepted - */ - protected abstract Set<Object> getAllowedItemIds( - DragAndDropEvent dragEvent, Table table, - Collection<Object> visibleItemIds); - - } - - /** - * Click event fired when clicking on the Table headers. The event includes - * a reference the the Table the event originated from, the property id of - * the column which header was pressed and details about the mouse event - * itself. - */ - public static class HeaderClickEvent extends ClickEvent { - public static final Method HEADER_CLICK_METHOD; - - static { - try { - // Set the header click method - HEADER_CLICK_METHOD = HeaderClickListener.class - .getDeclaredMethod("headerClick", - new Class[] { HeaderClickEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException(e); - } - } - - // The property id of the column which header was pressed - private final Object columnPropertyId; - - public HeaderClickEvent(Component source, Object propertyId, - MouseEventDetails details) { - super(source, details); - columnPropertyId = propertyId; - } - - /** - * Gets the property id of the column which header was pressed - * - * @return The column propety id - */ - public Object getPropertyId() { - return columnPropertyId; - } - } - - /** - * Click event fired when clicking on the Table footers. The event includes - * a reference the the Table the event originated from, the property id of - * the column which header was pressed and details about the mouse event - * itself. - */ - public static class FooterClickEvent extends ClickEvent { - public static final Method FOOTER_CLICK_METHOD; - - static { - try { - // Set the header click method - FOOTER_CLICK_METHOD = FooterClickListener.class - .getDeclaredMethod("footerClick", - new Class[] { FooterClickEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException(e); - } - } - - // The property id of the column which header was pressed - private final Object columnPropertyId; - - /** - * Constructor - * - * @param source - * The source of the component - * @param propertyId - * The propertyId of the column - * @param details - * The mouse details of the click - */ - public FooterClickEvent(Component source, Object propertyId, - MouseEventDetails details) { - super(source, details); - columnPropertyId = propertyId; - } - - /** - * Gets the property id of the column which header was pressed - * - * @return The column propety id - */ - public Object getPropertyId() { - return columnPropertyId; - } - } - - /** - * Interface for the listener for column header mouse click events. The - * headerClick method is called when the user presses a header column cell. - */ - public interface HeaderClickListener extends Serializable { - - /** - * Called when a user clicks a header column cell - * - * @param event - * The event which contains information about the column and - * the mouse click event - */ - public void headerClick(HeaderClickEvent event); - } - - /** - * Interface for the listener for column footer mouse click events. The - * footerClick method is called when the user presses a footer column cell. - */ - public interface FooterClickListener extends Serializable { - - /** - * Called when a user clicks a footer column cell - * - * @param event - * The event which contains information about the column and - * the mouse click event - */ - public void footerClick(FooterClickEvent event); - } - - /** - * Adds a header click listener which handles the click events when the user - * clicks on a column header cell in the Table. - * <p> - * The listener will receive events which contain information about which - * column was clicked and some details about the mouse event. - * </p> - * - * @param listener - * The handler which should handle the header click events. - */ - public void addListener(HeaderClickListener listener) { - addListener(VScrollTable.HEADER_CLICK_EVENT_ID, HeaderClickEvent.class, - listener, HeaderClickEvent.HEADER_CLICK_METHOD); - } - - /** - * Removes a header click listener - * - * @param listener - * The listener to remove. - */ - public void removeListener(HeaderClickListener listener) { - removeListener(VScrollTable.HEADER_CLICK_EVENT_ID, - HeaderClickEvent.class, listener); - } - - /** - * Adds a footer click listener which handles the click events when the user - * clicks on a column footer cell in the Table. - * <p> - * The listener will receive events which contain information about which - * column was clicked and some details about the mouse event. - * </p> - * - * @param listener - * The handler which should handle the footer click events. - */ - public void addListener(FooterClickListener listener) { - addListener(VScrollTable.FOOTER_CLICK_EVENT_ID, FooterClickEvent.class, - listener, FooterClickEvent.FOOTER_CLICK_METHOD); - } - - /** - * Removes a footer click listener - * - * @param listener - * The listener to remove. - */ - public void removeListener(FooterClickListener listener) { - removeListener(VScrollTable.FOOTER_CLICK_EVENT_ID, - FooterClickEvent.class, listener); - } - - /** - * Gets the footer caption beneath the rows - * - * @param propertyId - * The propertyId of the column * - * @return The caption of the footer or NULL if not set - */ - public String getColumnFooter(Object propertyId) { - return columnFooters.get(propertyId); - } - - /** - * Sets the column footer caption. The column footer caption is the text - * displayed beneath the column if footers have been set visible. - * - * @param propertyId - * The properyId of the column - * - * @param footer - * The caption of the footer - */ - public void setColumnFooter(Object propertyId, String footer) { - if (footer == null) { - columnFooters.remove(propertyId); - } else { - columnFooters.put(propertyId, footer); - } - - requestRepaint(); - } - - /** - * Sets the footer visible in the bottom of the table. - * <p> - * The footer can be used to add column related data like sums to the bottom - * of the Table using setColumnFooter(Object propertyId, String footer). - * </p> - * - * @param visible - * Should the footer be visible - */ - public void setFooterVisible(boolean visible) { - if (visible != columnFootersVisible) { - columnFootersVisible = visible; - requestRepaint(); - } - } - - /** - * Is the footer currently visible? - * - * @return Returns true if visible else false - */ - public boolean isFooterVisible() { - return columnFootersVisible; - } - - /** - * This event is fired when a column is resized. The event contains the - * columns property id which was fired, the previous width of the column and - * the width of the column after the resize. - */ - public static class ColumnResizeEvent extends Component.Event { - public static final Method COLUMN_RESIZE_METHOD; - - static { - try { - COLUMN_RESIZE_METHOD = ColumnResizeListener.class - .getDeclaredMethod("columnResize", - new Class[] { ColumnResizeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException(e); - } - } - - private final int previousWidth; - private final int currentWidth; - private final Object columnPropertyId; - - /** - * Constructor - * - * @param source - * The source of the event - * @param propertyId - * The columns property id - * @param previous - * The width in pixels of the column before the resize event - * @param current - * The width in pixels of the column after the resize event - */ - public ColumnResizeEvent(Component source, Object propertyId, - int previous, int current) { - super(source); - previousWidth = previous; - currentWidth = current; - columnPropertyId = propertyId; - } - - /** - * Get the column property id of the column that was resized. - * - * @return The column property id - */ - public Object getPropertyId() { - return columnPropertyId; - } - - /** - * Get the width in pixels of the column before the resize event - * - * @return Width in pixels - */ - public int getPreviousWidth() { - return previousWidth; - } - - /** - * Get the width in pixels of the column after the resize event - * - * @return Width in pixels - */ - public int getCurrentWidth() { - return currentWidth; - } - } - - /** - * Interface for listening to column resize events. - */ - public interface ColumnResizeListener extends Serializable { - - /** - * This method is triggered when the column has been resized - * - * @param event - * The event which contains the column property id, the - * previous width of the column and the current width of the - * column - */ - public void columnResize(ColumnResizeEvent event); - } - - /** - * Adds a column resize listener to the Table. A column resize listener is - * called when a user resizes a columns width. - * - * @param listener - * The listener to attach to the Table - */ - public void addListener(ColumnResizeListener listener) { - addListener(VScrollTable.COLUMN_RESIZE_EVENT_ID, - ColumnResizeEvent.class, listener, - ColumnResizeEvent.COLUMN_RESIZE_METHOD); - } - - /** - * Removes a column resize listener from the Table. - * - * @param listener - * The listener to remove - */ - public void removeListener(ColumnResizeListener listener) { - removeListener(VScrollTable.COLUMN_RESIZE_EVENT_ID, - ColumnResizeEvent.class, listener); - } - - /** - * This event is fired when a columns are reordered by the end user user. - */ - public static class ColumnReorderEvent extends Component.Event { - public static final Method METHOD; - - static { - try { - METHOD = ColumnReorderListener.class.getDeclaredMethod( - "columnReorder", - new Class[] { ColumnReorderEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException(e); - } - } - - /** - * Constructor - * - * @param source - * The source of the event - */ - public ColumnReorderEvent(Component source) { - super(source); - } - - } - - /** - * Interface for listening to column reorder events. - */ - public interface ColumnReorderListener extends Serializable { - - /** - * This method is triggered when the column has been reordered - * - * @param event - */ - public void columnReorder(ColumnReorderEvent event); - } - - /** - * Adds a column reorder listener to the Table. A column reorder listener is - * called when a user reorders columns. - * - * @param listener - * The listener to attach to the Table - */ - public void addListener(ColumnReorderListener listener) { - addListener(VScrollTable.COLUMN_REORDER_EVENT_ID, - ColumnReorderEvent.class, listener, ColumnReorderEvent.METHOD); - } - - /** - * Removes a column reorder listener from the Table. - * - * @param listener - * The listener to remove - */ - public void removeListener(ColumnReorderListener listener) { - removeListener(VScrollTable.COLUMN_REORDER_EVENT_ID, - ColumnReorderEvent.class, listener); - } - - /** - * Set the item description generator which generates tooltips for cells and - * rows in the Table - * - * @param generator - * The generator to use or null to disable - */ - public void setItemDescriptionGenerator(ItemDescriptionGenerator generator) { - if (generator != itemDescriptionGenerator) { - itemDescriptionGenerator = generator; - // Assures the visual refresh. No need to reset the page buffer - // before as the content has not changed, only the descriptions - refreshRenderedCells(); - } - } - - /** - * Get the item description generator which generates tooltips for cells and - * rows in the Table. - */ - public ItemDescriptionGenerator getItemDescriptionGenerator() { - return itemDescriptionGenerator; - } - - /** - * Row generators can be used to replace certain items in a table with a - * generated string. The generator is called each time the table is - * rendered, which means that new strings can be generated each time. - * - * Row generators can be used for e.g. summary rows or grouping of items. - */ - public interface RowGenerator extends Serializable { - /** - * Called for every row that is painted in the Table. Returning a - * GeneratedRow object will cause the row to be painted based on the - * contents of the GeneratedRow. A generated row is by default styled - * similarly to a header or footer row. - * <p> - * The GeneratedRow data object contains the text that should be - * rendered in the row. The itemId in the container thus works only as a - * placeholder. - * <p> - * If GeneratedRow.setSpanColumns(true) is used, there will be one - * String spanning all columns (use setText("Spanning text")). Otherwise - * you can define one String per visible column. - * <p> - * If GeneratedRow.setRenderAsHtml(true) is used, the strings can - * contain HTML markup, otherwise all strings will be rendered as text - * (the default). - * <p> - * A "v-table-generated-row" CSS class is added to all generated rows. - * For custom styling of a generated row you can combine a RowGenerator - * with a CellStyleGenerator. - * <p> - * - * @param table - * The Table that is being painted - * @param itemId - * The itemId for the row - * @return A GeneratedRow describing how the row should be painted or - * null to paint the row with the contents from the container - */ - public GeneratedRow generateRow(Table table, Object itemId); - } - - public static class GeneratedRow implements Serializable { - private boolean htmlContentAllowed = false; - private boolean spanColumns = false; - private String[] text = null; - - /** - * Creates a new generated row. If only one string is passed in, columns - * are automatically spanned. - * - * @param text - */ - public GeneratedRow(String... text) { - setHtmlContentAllowed(false); - setSpanColumns(text == null || text.length == 1); - setText(text); - } - - /** - * Pass one String if spanColumns is used, one String for each visible - * column otherwise - */ - public void setText(String... text) { - if (text == null || (text.length == 1 && text[0] == null)) { - text = new String[] { "" }; - } - this.text = text; - } - - protected String[] getText() { - return text; - } - - protected Object getValue() { - return getText(); - } - - protected boolean isHtmlContentAllowed() { - return htmlContentAllowed; - } - - /** - * If set to true, all strings passed to {@link #setText(String...)} - * will be rendered as HTML. - * - * @param htmlContentAllowed - */ - public void setHtmlContentAllowed(boolean htmlContentAllowed) { - this.htmlContentAllowed = htmlContentAllowed; - } - - protected boolean isSpanColumns() { - return spanColumns; - } - - /** - * If set to true, only one string will be rendered, spanning the entire - * row. - * - * @param spanColumns - */ - public void setSpanColumns(boolean spanColumns) { - this.spanColumns = spanColumns; - } - } - - /** - * Assigns a row generator to the table. The row generator will be able to - * replace rows in the table when it is rendered. - * - * @param generator - * the new row generator - */ - public void setRowGenerator(RowGenerator generator) { - rowGenerator = generator; - refreshRowCache(); - } - - /** - * @return the current row generator - */ - public RowGenerator getRowGenerator() { - return rowGenerator; - } - - /** - * Sets a converter for a property id. - * <p> - * The converter is used to format the the data for the given property id - * before displaying it in the table. - * </p> - * - * @param propertyId - * The propertyId to format using the converter - * @param converter - * The converter to use for the property id - */ - public void setConverter(Object propertyId, Converter<String, ?> converter) { - if (!getContainerPropertyIds().contains(propertyId)) { - throw new IllegalArgumentException("PropertyId " + propertyId - + " must be in the container"); - } - // FIXME: This check should be here but primitive types like Boolean - // formatter for boolean property must be handled - - // if (!converter.getSourceType().isAssignableFrom(getType(propertyId))) - // { - // throw new IllegalArgumentException("Property type (" - // + getType(propertyId) - // + ") must match converter source type (" - // + converter.getSourceType() + ")"); - // } - propertyValueConverters.put(propertyId, - (Converter<String, Object>) converter); - refreshRowCache(); - } - - /** - * Checks if there is a converter set explicitly for the given property id. - * - * @param propertyId - * The propertyId to check - * @return true if a converter has been set for the property id, false - * otherwise - */ - protected boolean hasConverter(Object propertyId) { - return propertyValueConverters.containsKey(propertyId); - } - - /** - * Returns the converter used to format the given propertyId. - * - * @param propertyId - * The propertyId to check - * @return The converter used to format the propertyId or null if no - * converter has been set - */ - public Converter<String, Object> getConverter(Object propertyId) { - return propertyValueConverters.get(propertyId); - } - - @Override - public void setVisible(boolean visible) { - if (visible) { - // We need to ensure that the rows are sent to the client when the - // Table is made visible if it has been rendered as invisible. - setRowCacheInvalidated(true); - } - super.setVisible(visible); - } - - @Override - public Iterator<Component> iterator() { - return getComponentIterator(); - } - - @Override - public Iterator<Component> getComponentIterator() { - if (visibleComponents == null) { - Collection<Component> empty = Collections.emptyList(); - return empty.iterator(); - } - - return visibleComponents.iterator(); - } - - @Override - public boolean isComponentVisible(Component childComponent) { - return true; - } - - private final Logger getLogger() { - if (logger == null) { - logger = Logger.getLogger(Table.class.getName()); - } - return logger; - } -} diff --git a/src/com/vaadin/ui/TableFieldFactory.java b/src/com/vaadin/ui/TableFieldFactory.java deleted file mode 100644 index 6c9a641aa8..0000000000 --- a/src/com/vaadin/ui/TableFieldFactory.java +++ /dev/null @@ -1,45 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; - -import com.vaadin.data.Container; - -/** - * Factory interface for creating new Field-instances based on Container - * (datasource), item id, property id and uiContext (the component responsible - * for displaying fields). Currently this interface is used by {@link Table}, - * but might later be used by some other components for {@link Field} - * generation. - * - * <p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 6.0 - * @see FormFieldFactory - */ -public interface TableFieldFactory extends Serializable { - /** - * Creates a field based on the Container, item id, property id and the - * component responsible for displaying the field (most commonly - * {@link Table}). - * - * @param container - * the Container where the property belongs to. - * @param itemId - * the item Id. - * @param propertyId - * the Id of the property. - * @param uiContext - * the component where the field is presented. - * @return A field suitable for editing the specified data or null if the - * property should not be editable. - */ - Field<?> createField(Container container, Object itemId, Object propertyId, - Component uiContext); - -} diff --git a/src/com/vaadin/ui/TextArea.java b/src/com/vaadin/ui/TextArea.java deleted file mode 100644 index d7837dd33f..0000000000 --- a/src/com/vaadin/ui/TextArea.java +++ /dev/null @@ -1,121 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.data.Property; -import com.vaadin.shared.ui.textarea.TextAreaState; - -/** - * A text field that supports multi line editing. - */ -public class TextArea extends AbstractTextField { - - /** - * Constructs an empty TextArea. - */ - public TextArea() { - setValue(""); - } - - /** - * Constructs an empty TextArea with given caption. - * - * @param caption - * the caption for the field. - */ - public TextArea(String caption) { - this(); - setCaption(caption); - } - - /** - * Constructs a TextArea with given property data source. - * - * @param dataSource - * the data source for the field - */ - public TextArea(Property dataSource) { - this(); - setPropertyDataSource(dataSource); - } - - /** - * Constructs a TextArea with given caption and property data source. - * - * @param caption - * the caption for the field - * @param dataSource - * the data source for the field - */ - public TextArea(String caption, Property dataSource) { - this(dataSource); - setCaption(caption); - } - - /** - * Constructs a TextArea with given caption and value. - * - * @param caption - * the caption for the field - * @param value - * the value for the field - */ - public TextArea(String caption, String value) { - this(caption); - setValue(value); - - } - - @Override - public TextAreaState getState() { - return (TextAreaState) super.getState(); - } - - /** - * Sets the number of rows in the text area. - * - * @param rows - * the number of rows for this text area. - */ - public void setRows(int rows) { - if (rows < 0) { - rows = 0; - } - getState().setRows(rows); - requestRepaint(); - } - - /** - * Gets the number of rows in the text area. - * - * @return number of explicitly set rows. - */ - public int getRows() { - return getState().getRows(); - } - - /** - * Sets the text area's word-wrap mode on or off. - * - * @param wordwrap - * the boolean value specifying if the text area should be in - * word-wrap mode. - */ - public void setWordwrap(boolean wordwrap) { - getState().setWordwrap(wordwrap); - requestRepaint(); - } - - /** - * Tests if the text area is in word-wrap mode. - * - * @return <code>true</code> if the component is in word-wrap mode, - * <code>false</code> if not. - */ - public boolean isWordwrap() { - return getState().isWordwrap(); - } - -} diff --git a/src/com/vaadin/ui/TextField.java b/src/com/vaadin/ui/TextField.java deleted file mode 100644 index 567e9c1c10..0000000000 --- a/src/com/vaadin/ui/TextField.java +++ /dev/null @@ -1,92 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.data.Property; - -/** - * <p> - * A text editor component that can be bound to any bindable Property. The text - * editor supports both multiline and single line modes, default is one-line - * mode. - * </p> - * - * <p> - * Since <code>TextField</code> extends <code>AbstractField</code> it implements - * the {@link com.vaadin.data.Buffered} interface. A <code>TextField</code> is - * in write-through mode by default, so - * {@link com.vaadin.ui.AbstractField#setWriteThrough(boolean)} must be called - * to enable buffering. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class TextField extends AbstractTextField { - - /** - * Constructs an empty <code>TextField</code> with no caption. - */ - public TextField() { - setValue(""); - } - - /** - * Constructs an empty <code>TextField</code> with given caption. - * - * @param caption - * the caption <code>String</code> for the editor. - */ - public TextField(String caption) { - this(); - setCaption(caption); - } - - /** - * Constructs a new <code>TextField</code> that's bound to the specified - * <code>Property</code> and has no caption. - * - * @param dataSource - * the Property to be edited with this editor. - */ - public TextField(Property dataSource) { - setPropertyDataSource(dataSource); - } - - /** - * Constructs a new <code>TextField</code> that's bound to the specified - * <code>Property</code> and has the given caption <code>String</code>. - * - * @param caption - * the caption <code>String</code> for the editor. - * @param dataSource - * the Property to be edited with this editor. - */ - public TextField(String caption, Property dataSource) { - this(dataSource); - setCaption(caption); - } - - /** - * Constructs a new <code>TextField</code> with the given caption and - * initial text contents. The editor constructed this way will not be bound - * to a Property unless - * {@link com.vaadin.data.Property.Viewer#setPropertyDataSource(Property)} - * is called to bind it. - * - * @param caption - * the caption <code>String</code> for the editor. - * @param value - * the initial text content of the editor. - */ - public TextField(String caption, String value) { - setValue(value); - setCaption(caption); - } - -} diff --git a/src/com/vaadin/ui/Tree.java b/src/com/vaadin/ui/Tree.java deleted file mode 100644 index c15975d879..0000000000 --- a/src/com/vaadin/ui/Tree.java +++ /dev/null @@ -1,1615 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.LinkedList; -import java.util.Map; -import java.util.Set; -import java.util.Stack; -import java.util.StringTokenizer; - -import com.vaadin.data.Container; -import com.vaadin.data.Item; -import com.vaadin.data.util.ContainerHierarchicalWrapper; -import com.vaadin.data.util.IndexedContainer; -import com.vaadin.event.Action; -import com.vaadin.event.Action.Handler; -import com.vaadin.event.DataBoundTransferable; -import com.vaadin.event.ItemClickEvent; -import com.vaadin.event.ItemClickEvent.ItemClickListener; -import com.vaadin.event.ItemClickEvent.ItemClickNotifier; -import com.vaadin.event.Transferable; -import com.vaadin.event.dd.DragAndDropEvent; -import com.vaadin.event.dd.DragSource; -import com.vaadin.event.dd.DropHandler; -import com.vaadin.event.dd.DropTarget; -import com.vaadin.event.dd.TargetDetails; -import com.vaadin.event.dd.acceptcriteria.ClientSideCriterion; -import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion; -import com.vaadin.event.dd.acceptcriteria.TargetDetailIs; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.dd.VerticalDropLocation; -import com.vaadin.terminal.KeyMapper; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.tree.TreeConnector; -import com.vaadin.terminal.gwt.client.ui.tree.VTree; -import com.vaadin.tools.ReflectTools; - -/** - * Tree component. A Tree can be used to select an item (or multiple items) from - * a hierarchical set of items. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings({ "serial", "deprecation" }) -public class Tree extends AbstractSelect implements Container.Hierarchical, - Action.Container, ItemClickNotifier, DragSource, DropTarget { - - /* Private members */ - - /** - * Set of expanded nodes. - */ - private final HashSet<Object> expanded = new HashSet<Object>(); - - /** - * List of action handlers. - */ - private LinkedList<Action.Handler> actionHandlers = null; - - /** - * Action mapper. - */ - private KeyMapper<Action> actionMapper = null; - - /** - * Is the tree selectable on the client side. - */ - private boolean selectable = true; - - /** - * Flag to indicate sub-tree loading - */ - private boolean partialUpdate = false; - - /** - * Holds a itemId which was recently expanded - */ - private Object expandedItemId; - - /** - * a flag which indicates initial paint. After this flag set true partial - * updates are allowed. - */ - private boolean initialPaint = true; - - /** - * Item tooltip generator - */ - private ItemDescriptionGenerator itemDescriptionGenerator; - - /** - * Supported drag modes for Tree. - */ - public enum TreeDragMode { - /** - * When drag mode is NONE, dragging from Tree is not supported. Browsers - * may still support selecting text/icons from Tree which can initiate - * HTML 5 style drag and drop operation. - */ - NONE, - /** - * When drag mode is NODE, users can initiate drag from Tree nodes that - * represent {@link Item}s in from the backed {@link Container}. - */ - NODE - // , SUBTREE - } - - private TreeDragMode dragMode = TreeDragMode.NONE; - - private MultiSelectMode multiSelectMode = MultiSelectMode.DEFAULT; - - /* Tree constructors */ - - /** - * Creates a new empty tree. - */ - public Tree() { - } - - /** - * Creates a new empty tree with caption. - * - * @param caption - */ - public Tree(String caption) { - setCaption(caption); - } - - /** - * Creates a new tree with caption and connect it to a Container. - * - * @param caption - * @param dataSource - */ - public Tree(String caption, Container dataSource) { - setCaption(caption); - setContainerDataSource(dataSource); - } - - /* Expanding and collapsing */ - - /** - * Check is an item is expanded - * - * @param itemId - * the item id. - * @return true iff the item is expanded. - */ - public boolean isExpanded(Object itemId) { - return expanded.contains(itemId); - } - - /** - * Expands an item. - * - * @param itemId - * the item id. - * @return True iff the expand operation succeeded - */ - public boolean expandItem(Object itemId) { - boolean success = expandItem(itemId, true); - requestRepaint(); - return success; - } - - /** - * Expands an item. - * - * @param itemId - * the item id. - * @param sendChildTree - * flag to indicate if client needs subtree or not (may be - * cached) - * @return True iff the expand operation succeeded - */ - private boolean expandItem(Object itemId, boolean sendChildTree) { - - // Succeeds if the node is already expanded - if (isExpanded(itemId)) { - return true; - } - - // Nodes that can not have children are not expandable - if (!areChildrenAllowed(itemId)) { - return false; - } - - // Expands - expanded.add(itemId); - - expandedItemId = itemId; - if (initialPaint) { - requestRepaint(); - } else if (sendChildTree) { - requestPartialRepaint(); - } - fireExpandEvent(itemId); - - return true; - } - - @Override - public void requestRepaint() { - super.requestRepaint(); - partialUpdate = false; - } - - private void requestPartialRepaint() { - super.requestRepaint(); - partialUpdate = true; - } - - /** - * Expands the items recursively - * - * Expands all the children recursively starting from an item. Operation - * succeeds only if all expandable items are expanded. - * - * @param startItemId - * @return True iff the expand operation succeeded - */ - public boolean expandItemsRecursively(Object startItemId) { - - boolean result = true; - - // Initial stack - final Stack<Object> todo = new Stack<Object>(); - todo.add(startItemId); - - // Expands recursively - while (!todo.isEmpty()) { - final Object id = todo.pop(); - if (areChildrenAllowed(id) && !expandItem(id, false)) { - result = false; - } - if (hasChildren(id)) { - todo.addAll(getChildren(id)); - } - } - requestRepaint(); - return result; - } - - /** - * Collapses an item. - * - * @param itemId - * the item id. - * @return True iff the collapse operation succeeded - */ - public boolean collapseItem(Object itemId) { - - // Succeeds if the node is already collapsed - if (!isExpanded(itemId)) { - return true; - } - - // Collapse - expanded.remove(itemId); - requestRepaint(); - fireCollapseEvent(itemId); - - return true; - } - - /** - * Collapses the items recursively. - * - * Collapse all the children recursively starting from an item. Operation - * succeeds only if all expandable items are collapsed. - * - * @param startItemId - * @return True iff the collapse operation succeeded - */ - public boolean collapseItemsRecursively(Object startItemId) { - - boolean result = true; - - // Initial stack - final Stack<Object> todo = new Stack<Object>(); - todo.add(startItemId); - - // Collapse recursively - while (!todo.isEmpty()) { - final Object id = todo.pop(); - if (areChildrenAllowed(id) && !collapseItem(id)) { - result = false; - } - if (hasChildren(id)) { - todo.addAll(getChildren(id)); - } - } - - return result; - } - - /** - * Returns the current selectable state. Selectable determines if the a node - * can be selected on the client side. Selectable does not affect - * {@link #setValue(Object)} or {@link #select(Object)}. - * - * <p> - * The tree is selectable by default. - * </p> - * - * @return the current selectable state. - */ - public boolean isSelectable() { - return selectable; - } - - /** - * Sets the selectable state. Selectable determines if the a node can be - * selected on the client side. Selectable does not affect - * {@link #setValue(Object)} or {@link #select(Object)}. - * - * <p> - * The tree is selectable by default. - * </p> - * - * @param selectable - * The new selectable state. - */ - public void setSelectable(boolean selectable) { - if (this.selectable != selectable) { - this.selectable = selectable; - requestRepaint(); - } - } - - /** - * Sets the behavior of the multiselect mode - * - * @param mode - * The mode to set - */ - public void setMultiselectMode(MultiSelectMode mode) { - if (multiSelectMode != mode && mode != null) { - multiSelectMode = mode; - requestRepaint(); - } - } - - /** - * Returns the mode the multiselect is in. The mode controls how - * multiselection can be done. - * - * @return The mode - */ - public MultiSelectMode getMultiselectMode() { - return multiSelectMode; - } - - /* Component API */ - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.AbstractSelect#changeVariables(java.lang.Object, - * java.util.Map) - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - - if (variables.containsKey("clickedKey")) { - String key = (String) variables.get("clickedKey"); - - Object id = itemIdMapper.get(key); - MouseEventDetails details = MouseEventDetails - .deSerialize((String) variables.get("clickEvent")); - Item item = getItem(id); - if (item != null) { - fireEvent(new ItemClickEvent(this, item, id, null, details)); - } - } - - if (!isSelectable() && variables.containsKey("selected")) { - // Not-selectable is a special case, AbstractSelect does not support - // TODO could be optimized. - variables = new HashMap<String, Object>(variables); - variables.remove("selected"); - } - - // Collapses the nodes - if (variables.containsKey("collapse")) { - final String[] keys = (String[]) variables.get("collapse"); - for (int i = 0; i < keys.length; i++) { - final Object id = itemIdMapper.get(keys[i]); - if (id != null && isExpanded(id)) { - expanded.remove(id); - fireCollapseEvent(id); - } - } - } - - // Expands the nodes - if (variables.containsKey("expand")) { - boolean sendChildTree = false; - if (variables.containsKey("requestChildTree")) { - sendChildTree = true; - } - final String[] keys = (String[]) variables.get("expand"); - for (int i = 0; i < keys.length; i++) { - final Object id = itemIdMapper.get(keys[i]); - if (id != null) { - expandItem(id, sendChildTree); - } - } - } - - // AbstractSelect cannot handle multiselection so we handle - // it ourself - if (variables.containsKey("selected") && isMultiSelect() - && multiSelectMode == MultiSelectMode.DEFAULT) { - handleSelectedItems(variables); - variables = new HashMap<String, Object>(variables); - variables.remove("selected"); - } - - // Selections are handled by the select component - super.changeVariables(source, variables); - - // Actions - if (variables.containsKey("action")) { - final StringTokenizer st = new StringTokenizer( - (String) variables.get("action"), ","); - if (st.countTokens() == 2) { - final Object itemId = itemIdMapper.get(st.nextToken()); - final Action action = actionMapper.get(st.nextToken()); - if (action != null && (itemId == null || containsId(itemId)) - && actionHandlers != null) { - for (Handler ah : actionHandlers) { - ah.handleAction(action, this, itemId); - } - } - } - } - } - - /** - * Handles the selection - * - * @param variables - * The variables sent to the server from the client - */ - private void handleSelectedItems(Map<String, Object> variables) { - final String[] ka = (String[]) variables.get("selected"); - - // Converts the key-array to id-set - final LinkedList<Object> s = new LinkedList<Object>(); - for (int i = 0; i < ka.length; i++) { - final Object id = itemIdMapper.get(ka[i]); - if (!isNullSelectionAllowed() - && (id == null || id == getNullSelectionItemId())) { - // skip empty selection if nullselection is not allowed - requestRepaint(); - } else if (id != null && containsId(id)) { - s.add(id); - } - } - - if (!isNullSelectionAllowed() && s.size() < 1) { - // empty selection not allowed, keep old value - requestRepaint(); - return; - } - - setValue(s, true); - } - - /** - * Paints any needed component-specific things to the given UIDL stream. - * - * @see com.vaadin.ui.AbstractComponent#paintContent(PaintTarget) - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - initialPaint = false; - - if (partialUpdate) { - target.addAttribute("partialUpdate", true); - target.addAttribute("rootKey", itemIdMapper.key(expandedItemId)); - } else { - getCaptionChangeListener().clear(); - - // The tab ordering number - if (getTabIndex() > 0) { - target.addAttribute("tabindex", getTabIndex()); - } - - // Paint tree attributes - if (isSelectable()) { - target.addAttribute("selectmode", (isMultiSelect() ? "multi" - : "single")); - if (isMultiSelect()) { - target.addAttribute("multiselectmode", - multiSelectMode.ordinal()); - } - } else { - target.addAttribute("selectmode", "none"); - } - if (isNewItemsAllowed()) { - target.addAttribute("allownewitem", true); - } - - if (isNullSelectionAllowed()) { - target.addAttribute("nullselect", true); - } - - if (dragMode != TreeDragMode.NONE) { - target.addAttribute("dragMode", dragMode.ordinal()); - } - - } - - // Initialize variables - final Set<Action> actionSet = new LinkedHashSet<Action>(); - - // rendered selectedKeys - LinkedList<String> selectedKeys = new LinkedList<String>(); - - final LinkedList<String> expandedKeys = new LinkedList<String>(); - - // Iterates through hierarchical tree using a stack of iterators - final Stack<Iterator<?>> iteratorStack = new Stack<Iterator<?>>(); - Collection<?> ids; - if (partialUpdate) { - ids = getChildren(expandedItemId); - } else { - ids = rootItemIds(); - } - - if (ids != null) { - iteratorStack.push(ids.iterator()); - } - - /* - * Body actions - Actions which has the target null and can be invoked - * by right clicking on the Tree body - */ - if (actionHandlers != null) { - final ArrayList<String> keys = new ArrayList<String>(); - for (Handler ah : actionHandlers) { - - // Getting action for the null item, which in this case - // means the body item - final Action[] aa = ah.getActions(null, this); - if (aa != null) { - for (int ai = 0; ai < aa.length; ai++) { - final String akey = actionMapper.key(aa[ai]); - actionSet.add(aa[ai]); - keys.add(akey); - } - } - } - target.addAttribute("alb", keys.toArray()); - } - - while (!iteratorStack.isEmpty()) { - - // Gets the iterator for current tree level - final Iterator<?> i = iteratorStack.peek(); - - // If the level is finished, back to previous tree level - if (!i.hasNext()) { - - // Removes used iterator from the stack - iteratorStack.pop(); - - // Closes node - if (!iteratorStack.isEmpty()) { - target.endTag("node"); - } - } - - // Adds the item on current level - else { - final Object itemId = i.next(); - - // Starts the item / node - final boolean isNode = areChildrenAllowed(itemId); - if (isNode) { - target.startTag("node"); - } else { - target.startTag("leaf"); - } - - if (itemStyleGenerator != null) { - String stylename = itemStyleGenerator.getStyle(itemId); - if (stylename != null) { - target.addAttribute(TreeConnector.ATTRIBUTE_NODE_STYLE, - stylename); - } - } - - if (itemDescriptionGenerator != null) { - String description = itemDescriptionGenerator - .generateDescription(this, itemId, null); - if (description != null && !description.equals("")) { - target.addAttribute("descr", description); - } - } - - // Adds the attributes - target.addAttribute(TreeConnector.ATTRIBUTE_NODE_CAPTION, - getItemCaption(itemId)); - final Resource icon = getItemIcon(itemId); - if (icon != null) { - target.addAttribute(TreeConnector.ATTRIBUTE_NODE_ICON, - getItemIcon(itemId)); - } - final String key = itemIdMapper.key(itemId); - target.addAttribute("key", key); - if (isSelected(itemId)) { - target.addAttribute("selected", true); - selectedKeys.add(key); - } - if (areChildrenAllowed(itemId) && isExpanded(itemId)) { - target.addAttribute("expanded", true); - expandedKeys.add(key); - } - - // Add caption change listener - getCaptionChangeListener().addNotifierForItem(itemId); - - // Actions - if (actionHandlers != null) { - final ArrayList<String> keys = new ArrayList<String>(); - final Iterator<Action.Handler> ahi = actionHandlers - .iterator(); - while (ahi.hasNext()) { - final Action[] aa = ahi.next().getActions(itemId, this); - if (aa != null) { - for (int ai = 0; ai < aa.length; ai++) { - final String akey = actionMapper.key(aa[ai]); - actionSet.add(aa[ai]); - keys.add(akey); - } - } - } - target.addAttribute("al", keys.toArray()); - } - - // Adds the children if expanded, or close the tag - if (isExpanded(itemId) && hasChildren(itemId) - && areChildrenAllowed(itemId)) { - iteratorStack.push(getChildren(itemId).iterator()); - } else { - if (isNode) { - target.endTag("node"); - } else { - target.endTag("leaf"); - } - } - } - } - - // Actions - if (!actionSet.isEmpty()) { - target.addVariable(this, "action", ""); - target.startTag("actions"); - final Iterator<Action> i = actionSet.iterator(); - while (i.hasNext()) { - final Action a = i.next(); - target.startTag("action"); - if (a.getCaption() != null) { - target.addAttribute(TreeConnector.ATTRIBUTE_ACTION_CAPTION, - a.getCaption()); - } - if (a.getIcon() != null) { - target.addAttribute(TreeConnector.ATTRIBUTE_ACTION_ICON, - a.getIcon()); - } - target.addAttribute("key", actionMapper.key(a)); - target.endTag("action"); - } - target.endTag("actions"); - } - - if (partialUpdate) { - partialUpdate = false; - } else { - // Selected - target.addVariable(this, "selected", - selectedKeys.toArray(new String[selectedKeys.size()])); - - // Expand and collapse - target.addVariable(this, "expand", new String[] {}); - target.addVariable(this, "collapse", new String[] {}); - - // New items - target.addVariable(this, "newitem", new String[] {}); - - if (dropHandler != null) { - dropHandler.getAcceptCriterion().paint(target); - } - - } - } - - /* Container.Hierarchical API */ - - /** - * Tests if the Item with given ID can have any children. - * - * @see com.vaadin.data.Container.Hierarchical#areChildrenAllowed(Object) - */ - @Override - public boolean areChildrenAllowed(Object itemId) { - return ((Container.Hierarchical) items).areChildrenAllowed(itemId); - } - - /** - * Gets the IDs of all Items that are children of the specified Item. - * - * @see com.vaadin.data.Container.Hierarchical#getChildren(Object) - */ - @Override - public Collection<?> getChildren(Object itemId) { - return ((Container.Hierarchical) items).getChildren(itemId); - } - - /** - * Gets the ID of the parent Item of the specified Item. - * - * @see com.vaadin.data.Container.Hierarchical#getParent(Object) - */ - @Override - public Object getParent(Object itemId) { - return ((Container.Hierarchical) items).getParent(itemId); - } - - /** - * Tests if the Item specified with <code>itemId</code> has child Items. - * - * @see com.vaadin.data.Container.Hierarchical#hasChildren(Object) - */ - @Override - public boolean hasChildren(Object itemId) { - return ((Container.Hierarchical) items).hasChildren(itemId); - } - - /** - * Tests if the Item specified with <code>itemId</code> is a root Item. - * - * @see com.vaadin.data.Container.Hierarchical#isRoot(Object) - */ - @Override - public boolean isRoot(Object itemId) { - return ((Container.Hierarchical) items).isRoot(itemId); - } - - /** - * Gets the IDs of all Items in the container that don't have a parent. - * - * @see com.vaadin.data.Container.Hierarchical#rootItemIds() - */ - @Override - public Collection<?> rootItemIds() { - return ((Container.Hierarchical) items).rootItemIds(); - } - - /** - * Sets the given Item's capability to have children. - * - * @see com.vaadin.data.Container.Hierarchical#setChildrenAllowed(Object, - * boolean) - */ - @Override - public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) { - final boolean success = ((Container.Hierarchical) items) - .setChildrenAllowed(itemId, areChildrenAllowed); - if (success) { - requestRepaint(); - } - return success; - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.data.Container.Hierarchical#setParent(java.lang.Object , - * java.lang.Object) - */ - @Override - public boolean setParent(Object itemId, Object newParentId) { - final boolean success = ((Container.Hierarchical) items).setParent( - itemId, newParentId); - if (success) { - requestRepaint(); - } - return success; - } - - /* Overriding select behavior */ - - /** - * Sets the Container that serves as the data source of the viewer. - * - * @see com.vaadin.data.Container.Viewer#setContainerDataSource(Container) - */ - @Override - public void setContainerDataSource(Container newDataSource) { - if (newDataSource == null) { - // Note: using wrapped IndexedContainer to match constructor (super - // creates an IndexedContainer, which is then wrapped). - newDataSource = new ContainerHierarchicalWrapper( - new IndexedContainer()); - } - - // Assure that the data source is ordered by making unordered - // containers ordered by wrapping them - if (Container.Hierarchical.class.isAssignableFrom(newDataSource - .getClass())) { - super.setContainerDataSource(newDataSource); - } else { - super.setContainerDataSource(new ContainerHierarchicalWrapper( - newDataSource)); - } - } - - /* Expand event and listener */ - - /** - * Event to fired when a node is expanded. ExapandEvent is fired when a node - * is to be expanded. it can me used to dynamically fill the sub-nodes of - * the node. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class ExpandEvent extends Component.Event { - - private final Object expandedItemId; - - /** - * New instance of options change event - * - * @param source - * the Source of the event. - * @param expandedItemId - */ - public ExpandEvent(Component source, Object expandedItemId) { - super(source); - this.expandedItemId = expandedItemId; - } - - /** - * Node where the event occurred. - * - * @return the Source of the event. - */ - public Object getItemId() { - return expandedItemId; - } - } - - /** - * Expand event listener. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface ExpandListener extends Serializable { - - public static final Method EXPAND_METHOD = ReflectTools.findMethod( - ExpandListener.class, "nodeExpand", ExpandEvent.class); - - /** - * A node has been expanded. - * - * @param event - * the Expand event. - */ - public void nodeExpand(ExpandEvent event); - } - - /** - * Adds the expand listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(ExpandListener listener) { - addListener(ExpandEvent.class, listener, ExpandListener.EXPAND_METHOD); - } - - /** - * Removes the expand listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(ExpandListener listener) { - removeListener(ExpandEvent.class, listener, - ExpandListener.EXPAND_METHOD); - } - - /** - * Emits the expand event. - * - * @param itemId - * the item id. - */ - protected void fireExpandEvent(Object itemId) { - fireEvent(new ExpandEvent(this, itemId)); - } - - /* Collapse event */ - - /** - * Collapse event - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class CollapseEvent extends Component.Event { - - private final Object collapsedItemId; - - /** - * New instance of options change event. - * - * @param source - * the Source of the event. - * @param collapsedItemId - */ - public CollapseEvent(Component source, Object collapsedItemId) { - super(source); - this.collapsedItemId = collapsedItemId; - } - - /** - * Gets tge Collapsed Item id. - * - * @return the collapsed item id. - */ - public Object getItemId() { - return collapsedItemId; - } - } - - /** - * Collapse event listener. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface CollapseListener extends Serializable { - - public static final Method COLLAPSE_METHOD = ReflectTools.findMethod( - CollapseListener.class, "nodeCollapse", CollapseEvent.class); - - /** - * A node has been collapsed. - * - * @param event - * the Collapse event. - */ - public void nodeCollapse(CollapseEvent event); - } - - /** - * Adds the collapse listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(CollapseListener listener) { - addListener(CollapseEvent.class, listener, - CollapseListener.COLLAPSE_METHOD); - } - - /** - * Removes the collapse listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(CollapseListener listener) { - removeListener(CollapseEvent.class, listener, - CollapseListener.COLLAPSE_METHOD); - } - - /** - * Emits collapse event. - * - * @param itemId - * the item id. - */ - protected void fireCollapseEvent(Object itemId) { - fireEvent(new CollapseEvent(this, itemId)); - } - - /* Action container */ - - /** - * Adds an action handler. - * - * @see com.vaadin.event.Action.Container#addActionHandler(Action.Handler) - */ - @Override - public void addActionHandler(Action.Handler actionHandler) { - - if (actionHandler != null) { - - if (actionHandlers == null) { - actionHandlers = new LinkedList<Action.Handler>(); - actionMapper = new KeyMapper<Action>(); - } - - if (!actionHandlers.contains(actionHandler)) { - actionHandlers.add(actionHandler); - requestRepaint(); - } - } - } - - /** - * Removes an action handler. - * - * @see com.vaadin.event.Action.Container#removeActionHandler(Action.Handler) - */ - @Override - public void removeActionHandler(Action.Handler actionHandler) { - - if (actionHandlers != null && actionHandlers.contains(actionHandler)) { - - actionHandlers.remove(actionHandler); - - if (actionHandlers.isEmpty()) { - actionHandlers = null; - actionMapper = null; - } - - requestRepaint(); - } - } - - /** - * Removes all action handlers - */ - public void removeAllActionHandlers() { - actionHandlers = null; - actionMapper = null; - requestRepaint(); - } - - /** - * Gets the visible item ids. - * - * @see com.vaadin.ui.Select#getVisibleItemIds() - */ - @Override - public Collection<?> getVisibleItemIds() { - - final LinkedList<Object> visible = new LinkedList<Object>(); - - // Iterates trough hierarchical tree using a stack of iterators - final Stack<Iterator<?>> iteratorStack = new Stack<Iterator<?>>(); - final Collection<?> ids = rootItemIds(); - if (ids != null) { - iteratorStack.push(ids.iterator()); - } - while (!iteratorStack.isEmpty()) { - - // Gets the iterator for current tree level - final Iterator<?> i = iteratorStack.peek(); - - // If the level is finished, back to previous tree level - if (!i.hasNext()) { - - // Removes used iterator from the stack - iteratorStack.pop(); - } - - // Adds the item on current level - else { - final Object itemId = i.next(); - - visible.add(itemId); - - // Adds children if expanded, or close the tag - if (isExpanded(itemId) && hasChildren(itemId)) { - iteratorStack.push(getChildren(itemId).iterator()); - } - } - } - - return visible; - } - - /** - * Tree does not support <code>setNullSelectionItemId</code>. - * - * @see com.vaadin.ui.AbstractSelect#setNullSelectionItemId(java.lang.Object) - */ - @Override - public void setNullSelectionItemId(Object nullSelectionItemId) - throws UnsupportedOperationException { - if (nullSelectionItemId != null) { - throw new UnsupportedOperationException(); - } - - } - - /** - * Adding new items is not supported. - * - * @throws UnsupportedOperationException - * if set to true. - * @see com.vaadin.ui.Select#setNewItemsAllowed(boolean) - */ - @Override - public void setNewItemsAllowed(boolean allowNewOptions) - throws UnsupportedOperationException { - if (allowNewOptions) { - throw new UnsupportedOperationException(); - } - } - - /** - * Tree does not support lazy options loading mode. Setting this true will - * throw UnsupportedOperationException. - * - * @see com.vaadin.ui.Select#setLazyLoading(boolean) - */ - public void setLazyLoading(boolean useLazyLoading) { - if (useLazyLoading) { - throw new UnsupportedOperationException( - "Lazy options loading is not supported by Tree."); - } - } - - private ItemStyleGenerator itemStyleGenerator; - - private DropHandler dropHandler; - - @Override - public void addListener(ItemClickListener listener) { - addListener(VTree.ITEM_CLICK_EVENT_ID, ItemClickEvent.class, listener, - ItemClickEvent.ITEM_CLICK_METHOD); - } - - @Override - public void removeListener(ItemClickListener listener) { - removeListener(VTree.ITEM_CLICK_EVENT_ID, ItemClickEvent.class, - listener); - } - - /** - * Sets the {@link ItemStyleGenerator} to be used with this tree. - * - * @param itemStyleGenerator - * item style generator or null to remove generator - */ - public void setItemStyleGenerator(ItemStyleGenerator itemStyleGenerator) { - if (this.itemStyleGenerator != itemStyleGenerator) { - this.itemStyleGenerator = itemStyleGenerator; - requestRepaint(); - } - } - - /** - * @return the current {@link ItemStyleGenerator} for this tree. Null if - * {@link ItemStyleGenerator} is not set. - */ - public ItemStyleGenerator getItemStyleGenerator() { - return itemStyleGenerator; - } - - /** - * ItemStyleGenerator can be used to add custom styles to tree items. The - * CSS class name that will be added to the cell content is - * <tt>v-tree-node-[style name]</tt>. - */ - public interface ItemStyleGenerator extends Serializable { - - /** - * Called by Tree when an item is painted. - * - * @param itemId - * The itemId of the item to be painted - * @return The style name to add to this item. (the CSS class name will - * be v-tree-node-[style name] - */ - public abstract String getStyle(Object itemId); - } - - // Overriden so javadoc comes from Container.Hierarchical - @Override - public boolean removeItem(Object itemId) - throws UnsupportedOperationException { - return super.removeItem(itemId); - } - - @Override - public DropHandler getDropHandler() { - return dropHandler; - } - - public void setDropHandler(DropHandler dropHandler) { - this.dropHandler = dropHandler; - } - - /** - * A {@link TargetDetails} implementation with Tree specific api. - * - * @since 6.3 - */ - public class TreeTargetDetails extends AbstractSelectTargetDetails { - - TreeTargetDetails(Map<String, Object> rawVariables) { - super(rawVariables); - } - - @Override - public Tree getTarget() { - return (Tree) super.getTarget(); - } - - /** - * If the event is on a node that can not have children (see - * {@link Tree#areChildrenAllowed(Object)}), this method returns the - * parent item id of the target item (see {@link #getItemIdOver()} ). - * The identifier of the parent node is also returned if the cursor is - * on the top part of node. Else this method returns the same as - * {@link #getItemIdOver()}. - * <p> - * In other words this method returns the identifier of the "folder" - * into the drag operation is targeted. - * <p> - * If the method returns null, the current target is on a root node or - * on other undefined area over the tree component. - * <p> - * The default Tree implementation marks the targetted tree node with - * CSS classnames v-tree-node-dragfolder and - * v-tree-node-caption-dragfolder (for the caption element). - */ - public Object getItemIdInto() { - - Object itemIdOver = getItemIdOver(); - if (areChildrenAllowed(itemIdOver) - && getDropLocation() == VerticalDropLocation.MIDDLE) { - return itemIdOver; - } - return getParent(itemIdOver); - } - - /** - * If drop is targeted into "folder node" (see {@link #getItemIdInto()} - * ), this method returns the item id of the node after the drag was - * targeted. This method is useful when implementing drop into specific - * location (between specific nodes) in tree. - * - * @return the id of the item after the user targets the drop or null if - * "target" is a first item in node list (or the first in root - * node list) - */ - public Object getItemIdAfter() { - Object itemIdOver = getItemIdOver(); - Object itemIdInto2 = getItemIdInto(); - if (itemIdOver.equals(itemIdInto2)) { - return null; - } - VerticalDropLocation dropLocation = getDropLocation(); - if (VerticalDropLocation.TOP == dropLocation) { - // if on top of the caption area, add before - Collection<?> children; - Object itemIdInto = getItemIdInto(); - if (itemIdInto != null) { - // seek the previous from child list - children = getChildren(itemIdInto); - } else { - children = rootItemIds(); - } - Object ref = null; - for (Object object : children) { - if (object.equals(itemIdOver)) { - return ref; - } - ref = object; - } - } - return itemIdOver; - } - - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.DropTarget#translateDropTargetDetails(java.util.Map) - */ - @Override - public TreeTargetDetails translateDropTargetDetails( - Map<String, Object> clientVariables) { - return new TreeTargetDetails(clientVariables); - } - - /** - * Helper API for {@link TreeDropCriterion} - * - * @param itemId - * @return - */ - private String key(Object itemId) { - return itemIdMapper.key(itemId); - } - - /** - * Sets the drag mode that controls how Tree behaves as a {@link DragSource} - * . - * - * @param dragMode - */ - public void setDragMode(TreeDragMode dragMode) { - this.dragMode = dragMode; - requestRepaint(); - } - - /** - * @return the drag mode that controls how Tree behaves as a - * {@link DragSource}. - * - * @see TreeDragMode - */ - public TreeDragMode getDragMode() { - return dragMode; - } - - /** - * Concrete implementation of {@link DataBoundTransferable} for data - * transferred from a tree. - * - * @see {@link DataBoundTransferable}. - * - * @since 6.3 - */ - protected class TreeTransferable extends DataBoundTransferable { - - public TreeTransferable(Component sourceComponent, - Map<String, Object> rawVariables) { - super(sourceComponent, rawVariables); - } - - @Override - public Object getItemId() { - return getData("itemId"); - } - - @Override - public Object getPropertyId() { - return getItemCaptionPropertyId(); - } - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.event.dd.DragSource#getTransferable(java.util.Map) - */ - @Override - public Transferable getTransferable(Map<String, Object> payload) { - TreeTransferable transferable = new TreeTransferable(this, payload); - // updating drag source variables - Object object = payload.get("itemId"); - if (object != null) { - transferable.setData("itemId", itemIdMapper.get((String) object)); - } - - return transferable; - } - - /** - * Lazy loading accept criterion for Tree. Accepted target nodes are loaded - * from server once per drag and drop operation. Developer must override one - * method that decides accepted tree nodes for the whole Tree. - * - * <p> - * Initially pretty much no data is sent to client. On first required - * criterion check (per drag request) the client side data structure is - * initialized from server and no subsequent requests requests are needed - * during that drag and drop operation. - */ - public static abstract class TreeDropCriterion extends ServerSideCriterion { - - private Tree tree; - - private Set<Object> allowedItemIds; - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.acceptCriteria.ServerSideCriterion#getIdentifier - * () - */ - @Override - protected String getIdentifier() { - return TreeDropCriterion.class.getCanonicalName(); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.acceptCriteria.AcceptCriterion#accepts(com.vaadin - * .event.dd.DragAndDropEvent) - */ - @Override - public boolean accept(DragAndDropEvent dragEvent) { - AbstractSelectTargetDetails dropTargetData = (AbstractSelectTargetDetails) dragEvent - .getTargetDetails(); - tree = (Tree) dragEvent.getTargetDetails().getTarget(); - allowedItemIds = getAllowedItemIds(dragEvent, tree); - - return allowedItemIds.contains(dropTargetData.getItemIdOver()); - } - - /* - * (non-Javadoc) - * - * @see - * com.vaadin.event.dd.acceptCriteria.AcceptCriterion#paintResponse( - * com.vaadin.terminal.PaintTarget) - */ - @Override - public void paintResponse(PaintTarget target) throws PaintException { - /* - * send allowed nodes to client so subsequent requests can be - * avoided - */ - Object[] array = allowedItemIds.toArray(); - for (int i = 0; i < array.length; i++) { - String key = tree.key(array[i]); - array[i] = key; - } - target.addAttribute("allowedIds", array); - } - - protected abstract Set<Object> getAllowedItemIds( - DragAndDropEvent dragEvent, Tree tree); - - } - - /** - * A criterion that accepts {@link Transferable} only directly on a tree - * node that can have children. - * <p> - * Class is singleton, use {@link TargetItemAllowsChildren#get()} to get the - * instance. - * - * @see Tree#setChildrenAllowed(Object, boolean) - * - * @since 6.3 - */ - public static class TargetItemAllowsChildren extends TargetDetailIs { - - private static TargetItemAllowsChildren instance = new TargetItemAllowsChildren(); - - public static TargetItemAllowsChildren get() { - return instance; - } - - private TargetItemAllowsChildren() { - super("itemIdOverIsNode", Boolean.TRUE); - } - - /* - * Uses enhanced server side check - */ - @Override - public boolean accept(DragAndDropEvent dragEvent) { - try { - // must be over tree node and in the middle of it (not top or - // bottom - // part) - TreeTargetDetails eventDetails = (TreeTargetDetails) dragEvent - .getTargetDetails(); - - Object itemIdOver = eventDetails.getItemIdOver(); - if (!eventDetails.getTarget().areChildrenAllowed(itemIdOver)) { - return false; - } - // return true if directly over - return eventDetails.getDropLocation() == VerticalDropLocation.MIDDLE; - } catch (Exception e) { - return false; - } - } - - } - - /** - * An accept criterion that checks the parent node (or parent hierarchy) for - * the item identifier given in constructor. If the parent is found, content - * is accepted. Criterion can be used to accepts drags on a specific sub - * tree only. - * <p> - * The root items is also consider to be valid target. - */ - public class TargetInSubtree extends ClientSideCriterion { - - private Object rootId; - private int depthToCheck = -1; - - /** - * Constructs a criteria that accepts the drag if the targeted Item is a - * descendant of Item identified by given id - * - * @param parentItemId - * the item identifier of the parent node - */ - public TargetInSubtree(Object parentItemId) { - rootId = parentItemId; - } - - /** - * Constructs a criteria that accepts drops within given level below the - * subtree root identified by given id. - * - * @param rootId - * the item identifier to be sought for - * @param depthToCheck - * the depth that tree is traversed upwards to seek for the - * parent, -1 means that the whole structure should be - * checked - */ - public TargetInSubtree(Object rootId, int depthToCheck) { - this.rootId = rootId; - this.depthToCheck = depthToCheck; - } - - @Override - public boolean accept(DragAndDropEvent dragEvent) { - try { - TreeTargetDetails eventDetails = (TreeTargetDetails) dragEvent - .getTargetDetails(); - - if (eventDetails.getItemIdOver() != null) { - Object itemId = eventDetails.getItemIdOver(); - int i = 0; - while (itemId != null - && (depthToCheck == -1 || i <= depthToCheck)) { - if (itemId.equals(rootId)) { - return true; - } - itemId = getParent(itemId); - i++; - } - } - return false; - } catch (Exception e) { - return false; - } - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - super.paintContent(target); - target.addAttribute("depth", depthToCheck); - target.addAttribute("key", key(rootId)); - } - - } - - /** - * Set the item description generator which generates tooltips for the tree - * items - * - * @param generator - * The generator to use or null to disable - */ - public void setItemDescriptionGenerator(ItemDescriptionGenerator generator) { - if (generator != itemDescriptionGenerator) { - itemDescriptionGenerator = generator; - requestRepaint(); - } - } - - /** - * Get the item description generator which generates tooltips for tree - * items - */ - public ItemDescriptionGenerator getItemDescriptionGenerator() { - return itemDescriptionGenerator; - } - -} diff --git a/src/com/vaadin/ui/TreeTable.java b/src/com/vaadin/ui/TreeTable.java deleted file mode 100644 index 6132b652f7..0000000000 --- a/src/com/vaadin/ui/TreeTable.java +++ /dev/null @@ -1,824 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - -import com.vaadin.data.Collapsible; -import com.vaadin.data.Container; -import com.vaadin.data.Container.Hierarchical; -import com.vaadin.data.Container.ItemSetChangeEvent; -import com.vaadin.data.util.ContainerHierarchicalWrapper; -import com.vaadin.data.util.HierarchicalContainer; -import com.vaadin.data.util.HierarchicalContainerOrderedWrapper; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.client.ui.treetable.TreeTableConnector; -import com.vaadin.ui.Tree.CollapseEvent; -import com.vaadin.ui.Tree.CollapseListener; -import com.vaadin.ui.Tree.ExpandEvent; -import com.vaadin.ui.Tree.ExpandListener; - -/** - * TreeTable extends the {@link Table} component so that it can also visualize a - * hierarchy of its Items in a similar manner that {@link Tree} does. The tree - * hierarchy is always displayed in the first actual column of the TreeTable. - * <p> - * The TreeTable supports the usual {@link Table} features like lazy loading, so - * it should be no problem to display lots of items at once. Only required rows - * and some cache rows are sent to the client. - * <p> - * TreeTable supports standard {@link Hierarchical} container interfaces, but - * also a more fine tuned version - {@link Collapsible}. A container - * implementing the {@link Collapsible} interface stores the collapsed/expanded - * state internally and can this way scale better on the server side than with - * standard Hierarchical implementations. Developer must however note that - * {@link Collapsible} containers can not be shared among several users as they - * share UI state in the container. - */ -@SuppressWarnings({ "serial" }) -public class TreeTable extends Table implements Hierarchical { - - private interface ContainerStrategy extends Serializable { - public int size(); - - public boolean isNodeOpen(Object itemId); - - public int getDepth(Object itemId); - - public void toggleChildVisibility(Object itemId); - - public Object getIdByIndex(int index); - - public int indexOfId(Object id); - - public Object nextItemId(Object itemId); - - public Object lastItemId(); - - public Object prevItemId(Object itemId); - - public boolean isLastId(Object itemId); - - public Collection<?> getItemIds(); - - public void containerItemSetChange(ItemSetChangeEvent event); - } - - private abstract class AbstractStrategy implements ContainerStrategy { - - /** - * Consider adding getDepth to {@link Collapsible}, might help - * scalability with some container implementations. - */ - - @Override - public int getDepth(Object itemId) { - int depth = 0; - Hierarchical hierarchicalContainer = getContainerDataSource(); - while (!hierarchicalContainer.isRoot(itemId)) { - depth++; - itemId = hierarchicalContainer.getParent(itemId); - } - return depth; - } - - @Override - public void containerItemSetChange(ItemSetChangeEvent event) { - } - - } - - /** - * This strategy is used if current container implements {@link Collapsible} - * . - * - * open-collapsed logic diverted to container, otherwise use default - * implementations. - */ - private class CollapsibleStrategy extends AbstractStrategy { - - private Collapsible c() { - return (Collapsible) getContainerDataSource(); - } - - @Override - public void toggleChildVisibility(Object itemId) { - c().setCollapsed(itemId, !c().isCollapsed(itemId)); - } - - @Override - public boolean isNodeOpen(Object itemId) { - return !c().isCollapsed(itemId); - } - - @Override - public int size() { - return TreeTable.super.size(); - } - - @Override - public Object getIdByIndex(int index) { - return TreeTable.super.getIdByIndex(index); - } - - @Override - public int indexOfId(Object id) { - return TreeTable.super.indexOfId(id); - } - - @Override - public boolean isLastId(Object itemId) { - // using the default impl - return TreeTable.super.isLastId(itemId); - } - - @Override - public Object lastItemId() { - // using the default impl - return TreeTable.super.lastItemId(); - } - - @Override - public Object nextItemId(Object itemId) { - return TreeTable.super.nextItemId(itemId); - } - - @Override - public Object prevItemId(Object itemId) { - return TreeTable.super.prevItemId(itemId); - } - - @Override - public Collection<?> getItemIds() { - return TreeTable.super.getItemIds(); - } - - } - - /** - * Strategy for Hierarchical but not Collapsible container like - * {@link HierarchicalContainer}. - * - * Store collapsed/open states internally, fool Table to use preorder when - * accessing items from container via Ordered/Indexed methods. - */ - private class HierarchicalStrategy extends AbstractStrategy { - - private final HashSet<Object> openItems = new HashSet<Object>(); - - @Override - public boolean isNodeOpen(Object itemId) { - return openItems.contains(itemId); - } - - @Override - public int size() { - return getPreOrder().size(); - } - - @Override - public Collection<Object> getItemIds() { - return Collections.unmodifiableCollection(getPreOrder()); - } - - @Override - public boolean isLastId(Object itemId) { - if (itemId == null) { - return false; - } - - return itemId.equals(lastItemId()); - } - - @Override - public Object lastItemId() { - if (getPreOrder().size() > 0) { - return getPreOrder().get(getPreOrder().size() - 1); - } else { - return null; - } - } - - @Override - public Object nextItemId(Object itemId) { - int indexOf = getPreOrder().indexOf(itemId); - if (indexOf == -1) { - return null; - } - indexOf++; - if (indexOf == getPreOrder().size()) { - return null; - } else { - return getPreOrder().get(indexOf); - } - } - - @Override - public Object prevItemId(Object itemId) { - int indexOf = getPreOrder().indexOf(itemId); - indexOf--; - if (indexOf < 0) { - return null; - } else { - return getPreOrder().get(indexOf); - } - } - - @Override - public void toggleChildVisibility(Object itemId) { - boolean removed = openItems.remove(itemId); - if (!removed) { - openItems.add(itemId); - getLogger().finest("Item " + itemId + " is now expanded"); - } else { - getLogger().finest("Item " + itemId + " is now collapsed"); - } - clearPreorderCache(); - } - - private void clearPreorderCache() { - preOrder = null; // clear preorder cache - } - - List<Object> preOrder; - - /** - * Preorder of ids currently visible - * - * @return - */ - private List<Object> getPreOrder() { - if (preOrder == null) { - preOrder = new ArrayList<Object>(); - Collection<?> rootItemIds = getContainerDataSource() - .rootItemIds(); - for (Object id : rootItemIds) { - preOrder.add(id); - addVisibleChildTree(id); - } - } - return preOrder; - } - - private void addVisibleChildTree(Object id) { - if (isNodeOpen(id)) { - Collection<?> children = getContainerDataSource().getChildren( - id); - if (children != null) { - for (Object childId : children) { - preOrder.add(childId); - addVisibleChildTree(childId); - } - } - } - - } - - @Override - public int indexOfId(Object id) { - return getPreOrder().indexOf(id); - } - - @Override - public Object getIdByIndex(int index) { - return getPreOrder().get(index); - } - - @Override - public void containerItemSetChange(ItemSetChangeEvent event) { - // preorder becomes invalid on sort, item additions etc. - clearPreorderCache(); - super.containerItemSetChange(event); - } - - } - - /** - * Creates an empty TreeTable with a default container. - */ - public TreeTable() { - super(null, new HierarchicalContainer()); - } - - /** - * Creates an empty TreeTable with a default container. - * - * @param caption - * the caption for the TreeTable - */ - public TreeTable(String caption) { - this(); - setCaption(caption); - } - - /** - * Creates a TreeTable instance with given captions and data source. - * - * @param caption - * the caption for the component - * @param dataSource - * the dataSource that is used to list items in the component - */ - public TreeTable(String caption, Container dataSource) { - super(caption, dataSource); - } - - private ContainerStrategy cStrategy; - private Object focusedRowId = null; - private Object hierarchyColumnId; - - /** - * The item id that was expanded or collapsed during this request. Reset at - * the end of paint and only used for determining if a partial or full paint - * should be done. - * - * Can safely be reset to null whenever a change occurs that would prevent a - * partial update from rendering the correct result, e.g. rows added or - * removed during an expand operation. - */ - private Object toggledItemId; - private boolean animationsEnabled; - private boolean clearFocusedRowPending; - - /** - * If the container does not send item set change events, always do a full - * repaint instead of a partial update when expanding/collapsing nodes. - */ - private boolean containerSupportsPartialUpdates; - - private ContainerStrategy getContainerStrategy() { - if (cStrategy == null) { - if (getContainerDataSource() instanceof Collapsible) { - cStrategy = new CollapsibleStrategy(); - } else { - cStrategy = new HierarchicalStrategy(); - } - } - return cStrategy; - } - - @Override - protected void paintRowAttributes(PaintTarget target, Object itemId) - throws PaintException { - super.paintRowAttributes(target, itemId); - target.addAttribute("depth", getContainerStrategy().getDepth(itemId)); - if (getContainerDataSource().areChildrenAllowed(itemId)) { - target.addAttribute("ca", true); - target.addAttribute("open", - getContainerStrategy().isNodeOpen(itemId)); - } - } - - @Override - protected void paintRowIcon(PaintTarget target, Object[][] cells, - int indexInRowbuffer) throws PaintException { - // always paint if present (in parent only if row headers visible) - if (getRowHeaderMode() == ROW_HEADER_MODE_HIDDEN) { - Resource itemIcon = getItemIcon(cells[CELL_ITEMID][indexInRowbuffer]); - if (itemIcon != null) { - target.addAttribute("icon", itemIcon); - } - } else if (cells[CELL_ICON][indexInRowbuffer] != null) { - target.addAttribute("icon", - (Resource) cells[CELL_ICON][indexInRowbuffer]); - } - } - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - super.changeVariables(source, variables); - - if (variables.containsKey("toggleCollapsed")) { - String object = (String) variables.get("toggleCollapsed"); - Object itemId = itemIdMapper.get(object); - toggledItemId = itemId; - toggleChildVisibility(itemId, false); - if (variables.containsKey("selectCollapsed")) { - // ensure collapsed is selected unless opened with selection - // head - if (isSelectable()) { - select(itemId); - } - } - } else if (variables.containsKey("focusParent")) { - String key = (String) variables.get("focusParent"); - Object refId = itemIdMapper.get(key); - Object itemId = getParent(refId); - focusParent(itemId); - } - } - - private void focusParent(Object itemId) { - boolean inView = false; - Object inPageId = getCurrentPageFirstItemId(); - for (int i = 0; inPageId != null && i < getPageLength(); i++) { - if (inPageId.equals(itemId)) { - inView = true; - break; - } - inPageId = nextItemId(inPageId); - i++; - } - if (!inView) { - setCurrentPageFirstItemId(itemId); - } - // Select the row if it is selectable. - if (isSelectable()) { - if (isMultiSelect()) { - setValue(Collections.singleton(itemId)); - } else { - setValue(itemId); - } - } - setFocusedRow(itemId); - } - - private void setFocusedRow(Object itemId) { - focusedRowId = itemId; - if (focusedRowId == null) { - // Must still inform the client that the focusParent request has - // been processed - clearFocusedRowPending = true; - } - requestRepaint(); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (focusedRowId != null) { - target.addAttribute("focusedRow", itemIdMapper.key(focusedRowId)); - focusedRowId = null; - } else if (clearFocusedRowPending) { - // Must still inform the client that the focusParent request has - // been processed - target.addAttribute("clearFocusPending", true); - clearFocusedRowPending = false; - } - target.addAttribute("animate", animationsEnabled); - if (hierarchyColumnId != null) { - Object[] visibleColumns2 = getVisibleColumns(); - for (int i = 0; i < visibleColumns2.length; i++) { - Object object = visibleColumns2[i]; - if (hierarchyColumnId.equals(object)) { - target.addAttribute( - TreeTableConnector.ATTRIBUTE_HIERARCHY_COLUMN_INDEX, - i); - break; - } - } - } - super.paintContent(target); - toggledItemId = null; - } - - /* - * Override methods for partial row updates and additions when expanding / - * collapsing nodes. - */ - - @Override - protected boolean isPartialRowUpdate() { - return toggledItemId != null && containerSupportsPartialUpdates - && !isRowCacheInvalidated(); - } - - @Override - protected int getFirstAddedItemIndex() { - return indexOfId(toggledItemId) + 1; - } - - @Override - protected int getAddedRowCount() { - return countSubNodesRecursively(getContainerDataSource(), toggledItemId); - } - - private int countSubNodesRecursively(Hierarchical hc, Object itemId) { - int count = 0; - // we need the number of children for toggledItemId no matter if its - // collapsed or expanded. Other items' children are only counted if the - // item is expanded. - if (getContainerStrategy().isNodeOpen(itemId) - || itemId == toggledItemId) { - Collection<?> children = hc.getChildren(itemId); - if (children != null) { - count += children != null ? children.size() : 0; - for (Object id : children) { - count += countSubNodesRecursively(hc, id); - } - } - } - return count; - } - - @Override - protected int getFirstUpdatedItemIndex() { - return indexOfId(toggledItemId); - } - - @Override - protected int getUpdatedRowCount() { - return 1; - } - - @Override - protected boolean shouldHideAddedRows() { - return !getContainerStrategy().isNodeOpen(toggledItemId); - } - - private void toggleChildVisibility(Object itemId, boolean forceFullRefresh) { - getContainerStrategy().toggleChildVisibility(itemId); - // ensure that page still has first item in page, DON'T clear the - // caches. - setCurrentPageFirstItemIndex(getCurrentPageFirstItemIndex(), false); - - if (isCollapsed(itemId)) { - fireCollapseEvent(itemId); - } else { - fireExpandEvent(itemId); - } - - if (containerSupportsPartialUpdates && !forceFullRefresh) { - requestRepaint(); - } else { - // For containers that do not send item set change events, always do - // full repaint instead of partial row update. - refreshRowCache(); - } - } - - @Override - public int size() { - return getContainerStrategy().size(); - } - - @Override - public Hierarchical getContainerDataSource() { - return (Hierarchical) super.getContainerDataSource(); - } - - @Override - public void setContainerDataSource(Container newDataSource) { - cStrategy = null; - - // FIXME: This disables partial updates until TreeTable is fixed so it - // does not change component hierarchy during paint - containerSupportsPartialUpdates = (newDataSource instanceof ItemSetChangeNotifier) && false; - - if (!(newDataSource instanceof Hierarchical)) { - newDataSource = new ContainerHierarchicalWrapper(newDataSource); - } - - if (!(newDataSource instanceof Ordered)) { - newDataSource = new HierarchicalContainerOrderedWrapper( - (Hierarchical) newDataSource); - } - - super.setContainerDataSource(newDataSource); - } - - @Override - public void containerItemSetChange( - com.vaadin.data.Container.ItemSetChangeEvent event) { - // Can't do partial repaints if items are added or removed during the - // expand/collapse request - toggledItemId = null; - getContainerStrategy().containerItemSetChange(event); - super.containerItemSetChange(event); - } - - @Override - protected Object getIdByIndex(int index) { - return getContainerStrategy().getIdByIndex(index); - } - - @Override - protected int indexOfId(Object itemId) { - return getContainerStrategy().indexOfId(itemId); - } - - @Override - public Object nextItemId(Object itemId) { - return getContainerStrategy().nextItemId(itemId); - } - - @Override - public Object lastItemId() { - return getContainerStrategy().lastItemId(); - } - - @Override - public Object prevItemId(Object itemId) { - return getContainerStrategy().prevItemId(itemId); - } - - @Override - public boolean isLastId(Object itemId) { - return getContainerStrategy().isLastId(itemId); - } - - @Override - public Collection<?> getItemIds() { - return getContainerStrategy().getItemIds(); - } - - @Override - public boolean areChildrenAllowed(Object itemId) { - return getContainerDataSource().areChildrenAllowed(itemId); - } - - @Override - public Collection<?> getChildren(Object itemId) { - return getContainerDataSource().getChildren(itemId); - } - - @Override - public Object getParent(Object itemId) { - return getContainerDataSource().getParent(itemId); - } - - @Override - public boolean hasChildren(Object itemId) { - return getContainerDataSource().hasChildren(itemId); - } - - @Override - public boolean isRoot(Object itemId) { - return getContainerDataSource().isRoot(itemId); - } - - @Override - public Collection<?> rootItemIds() { - return getContainerDataSource().rootItemIds(); - } - - @Override - public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) - throws UnsupportedOperationException { - return getContainerDataSource().setChildrenAllowed(itemId, - areChildrenAllowed); - } - - @Override - public boolean setParent(Object itemId, Object newParentId) - throws UnsupportedOperationException { - return getContainerDataSource().setParent(itemId, newParentId); - } - - /** - * Sets the Item specified by given identifier as collapsed or expanded. If - * the Item is collapsed, its children are not displayed to the user. - * - * @param itemId - * the identifier of the Item - * @param collapsed - * true if the Item should be collapsed, false if expanded - */ - public void setCollapsed(Object itemId, boolean collapsed) { - if (isCollapsed(itemId) != collapsed) { - if (null == toggledItemId && !isRowCacheInvalidated() - && getVisibleItemIds().contains(itemId)) { - // optimization: partial refresh if only one item is - // collapsed/expanded - toggledItemId = itemId; - toggleChildVisibility(itemId, false); - } else { - // make sure a full refresh takes place - otherwise neither - // partial nor full repaint of table content is performed - toggledItemId = null; - toggleChildVisibility(itemId, true); - } - } - } - - /** - * Checks if Item with given identifier is collapsed in the UI. - * - * <p> - * - * @param itemId - * the identifier of the checked Item - * @return true if the Item with given id is collapsed - * @see Collapsible#isCollapsed(Object) - */ - public boolean isCollapsed(Object itemId) { - return !getContainerStrategy().isNodeOpen(itemId); - } - - /** - * Explicitly sets the column in which the TreeTable visualizes the - * hierarchy. If hierarchyColumnId is not set, the hierarchy is visualized - * in the first visible column. - * - * @param hierarchyColumnId - */ - public void setHierarchyColumn(Object hierarchyColumnId) { - this.hierarchyColumnId = hierarchyColumnId; - } - - /** - * @return the identifier of column into which the hierarchy will be - * visualized or null if the column is not explicitly defined. - */ - public Object getHierarchyColumnId() { - return hierarchyColumnId; - } - - /** - * Adds an expand listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(ExpandListener listener) { - addListener(ExpandEvent.class, listener, ExpandListener.EXPAND_METHOD); - } - - /** - * Removes an expand listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(ExpandListener listener) { - removeListener(ExpandEvent.class, listener, - ExpandListener.EXPAND_METHOD); - } - - /** - * Emits an expand event. - * - * @param itemId - * the item id. - */ - protected void fireExpandEvent(Object itemId) { - fireEvent(new ExpandEvent(this, itemId)); - } - - /** - * Adds a collapse listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(CollapseListener listener) { - addListener(CollapseEvent.class, listener, - CollapseListener.COLLAPSE_METHOD); - } - - /** - * Removes a collapse listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(CollapseListener listener) { - removeListener(CollapseEvent.class, listener, - CollapseListener.COLLAPSE_METHOD); - } - - /** - * Emits a collapse event. - * - * @param itemId - * the item id. - */ - protected void fireCollapseEvent(Object itemId) { - fireEvent(new CollapseEvent(this, itemId)); - } - - /** - * @return true if animations are enabled - */ - public boolean isAnimationsEnabled() { - return animationsEnabled; - } - - /** - * Animations can be enabled by passing true to this method. Currently - * expanding rows slide in from the top and collapsing rows slide out the - * same way. NOTE! not supported in Internet Explorer 6 or 7. - * - * @param animationsEnabled - * true or false whether to enable animations or not. - */ - public void setAnimationsEnabled(boolean animationsEnabled) { - this.animationsEnabled = animationsEnabled; - requestRepaint(); - } - - private static final Logger getLogger() { - return Logger.getLogger(TreeTable.class.getName()); - } - -} diff --git a/src/com/vaadin/ui/TwinColSelect.java b/src/com/vaadin/ui/TwinColSelect.java deleted file mode 100644 index 5539236f77..0000000000 --- a/src/com/vaadin/ui/TwinColSelect.java +++ /dev/null @@ -1,180 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.util.Collection; - -import com.vaadin.data.Container; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.gwt.client.ui.twincolselect.VTwinColSelect; - -/** - * Multiselect component with two lists: left side for available items and right - * side for selected items. - */ -@SuppressWarnings("serial") -public class TwinColSelect extends AbstractSelect { - - private int columns = 0; - private int rows = 0; - - private String leftColumnCaption; - private String rightColumnCaption; - - /** - * - */ - public TwinColSelect() { - super(); - setMultiSelect(true); - } - - /** - * @param caption - */ - public TwinColSelect(String caption) { - super(caption); - setMultiSelect(true); - } - - /** - * @param caption - * @param dataSource - */ - public TwinColSelect(String caption, Container dataSource) { - super(caption, dataSource); - setMultiSelect(true); - } - - /** - * Sets the number of columns in the editor. If the number of columns is set - * 0, the actual number of displayed columns is determined implicitly by the - * adapter. - * <p> - * The number of columns overrides the value set by setWidth. Only if - * columns are set to 0 (default) the width set using - * {@link #setWidth(float, int)} or {@link #setWidth(String)} is used. - * - * @param columns - * the number of columns to set. - */ - public void setColumns(int columns) { - if (columns < 0) { - columns = 0; - } - if (this.columns != columns) { - this.columns = columns; - requestRepaint(); - } - } - - public int getColumns() { - return columns; - } - - public int getRows() { - return rows; - } - - /** - * Sets the number of rows in the editor. If the number of rows is set to 0, - * the actual number of displayed rows is determined implicitly by the - * adapter. - * <p> - * If a height if set (using {@link #setHeight(String)} or - * {@link #setHeight(float, int)}) it overrides the number of rows. Leave - * the height undefined to use this method. This is the opposite of how - * {@link #setColumns(int)} work. - * - * - * @param rows - * the number of rows to set. - */ - public void setRows(int rows) { - if (rows < 0) { - rows = 0; - } - if (this.rows != rows) { - this.rows = rows; - requestRepaint(); - } - } - - /** - * @param caption - * @param options - */ - public TwinColSelect(String caption, Collection<?> options) { - super(caption, options); - setMultiSelect(true); - } - - @Override - public void paintContent(PaintTarget target) throws PaintException { - target.addAttribute("type", "twincol"); - // Adds the number of columns - if (columns != 0) { - target.addAttribute("cols", columns); - } - // Adds the number of rows - if (rows != 0) { - target.addAttribute("rows", rows); - } - - // Right and left column captions and/or icons (if set) - String lc = getLeftColumnCaption(); - String rc = getRightColumnCaption(); - if (lc != null) { - target.addAttribute(VTwinColSelect.ATTRIBUTE_LEFT_CAPTION, lc); - } - if (rc != null) { - target.addAttribute(VTwinColSelect.ATTRIBUTE_RIGHT_CAPTION, rc); - } - - super.paintContent(target); - } - - /** - * Sets the text shown above the right column. - * - * @param caption - * The text to show - */ - public void setRightColumnCaption(String rightColumnCaption) { - this.rightColumnCaption = rightColumnCaption; - requestRepaint(); - } - - /** - * Returns the text shown above the right column. - * - * @return The text shown or null if not set. - */ - public String getRightColumnCaption() { - return rightColumnCaption; - } - - /** - * Sets the text shown above the left column. - * - * @param caption - * The text to show - */ - public void setLeftColumnCaption(String leftColumnCaption) { - this.leftColumnCaption = leftColumnCaption; - requestRepaint(); - } - - /** - * Returns the text shown above the left column. - * - * @return The text shown or null if not set. - */ - public String getLeftColumnCaption() { - return leftColumnCaption; - } - -} diff --git a/src/com/vaadin/ui/UniqueSerializable.java b/src/com/vaadin/ui/UniqueSerializable.java deleted file mode 100644 index 828b285538..0000000000 --- a/src/com/vaadin/ui/UniqueSerializable.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -import java.io.Serializable; - -/** - * A base class for generating an unique object that is serializable. - * <p> - * This class is abstract but has no abstract methods to force users to create - * an anonymous inner class. Otherwise each instance will not be unique. - * - * @author Vaadin Ltd - * @version @VERSION@ - * @since 7.0 - * - */ -public abstract class UniqueSerializable implements Serializable { - - @Override - public int hashCode() { - return getClass().hashCode(); - } - - @Override - public boolean equals(Object obj) { - return getClass() == obj.getClass(); - } -} diff --git a/src/com/vaadin/ui/Upload.java b/src/com/vaadin/ui/Upload.java deleted file mode 100644 index 9d533b67f6..0000000000 --- a/src/com/vaadin/ui/Upload.java +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * @VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.OutputStream; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.Map; - -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.StreamVariable.StreamingProgressEvent; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.server.NoInputStreamException; -import com.vaadin.terminal.gwt.server.NoOutputStreamException; - -/** - * Component for uploading files from client to server. - * - * <p> - * The visible component consists of a file name input box and a browse button - * and an upload submit button to start uploading. - * - * <p> - * The Upload component needs a java.io.OutputStream to write the uploaded data. - * You need to implement the Upload.Receiver interface and return the output - * stream in the receiveUpload() method. - * - * <p> - * You can get an event regarding starting (StartedEvent), progress - * (ProgressEvent), and finishing (FinishedEvent) of upload by implementing - * StartedListener, ProgressListener, and FinishedListener, respectively. The - * FinishedListener is called for both failed and succeeded uploads. If you wish - * to separate between these two cases, you can use SucceededListener - * (SucceededEvenet) and FailedListener (FailedEvent). - * - * <p> - * The upload component does not itself show upload progress, but you can use - * the ProgressIndicator for providing progress feedback by implementing - * ProgressListener and updating the indicator in updateProgress(). - * - * <p> - * Setting upload component immediate initiates the upload as soon as a file is - * selected, instead of the common pattern of file selection field and upload - * button. - * - * <p> - * Note! Because of browser dependent implementations of <input type="file"> - * element, setting size for Upload component is not supported. For some - * browsers setting size may work to some extend. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Upload extends AbstractComponent implements Component.Focusable, - Vaadin6Component { - - /** - * Should the field be focused on next repaint? - */ - private final boolean focus = false; - - /** - * The tab order number of this field. - */ - private int tabIndex = 0; - - /** - * The output of the upload is redirected to this receiver. - */ - private Receiver receiver; - - private boolean isUploading; - - private long contentLength = -1; - - private int totalBytes; - - private String buttonCaption = "Upload"; - - /** - * ProgressListeners to which information about progress is sent during - * upload - */ - private LinkedHashSet<ProgressListener> progressListeners; - - private boolean interrupted = false; - - private boolean notStarted; - - private int nextid; - - /** - * Flag to indicate that submitting file has been requested. - */ - private boolean forceSubmit; - - /** - * Creates a new instance of Upload. - * - * The receiver must be set before performing an upload. - */ - public Upload() { - } - - public Upload(String caption, Receiver uploadReceiver) { - setCaption(caption); - receiver = uploadReceiver; - } - - /** - * Invoked when the value of a variable has changed. - * - * @see com.vaadin.ui.AbstractComponent#changeVariables(java.lang.Object, - * java.util.Map) - */ - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - if (variables.containsKey("pollForStart")) { - int id = (Integer) variables.get("pollForStart"); - if (!isUploading && id == nextid) { - notStarted = true; - requestRepaint(); - } else { - } - } - } - - /** - * Paints the content of this component. - * - * @param target - * Target to paint the content on. - * @throws PaintException - * if the paint operation failed. - */ - @Override - public void paintContent(PaintTarget target) throws PaintException { - if (notStarted) { - target.addAttribute("notStarted", true); - notStarted = false; - return; - } - if (forceSubmit) { - target.addAttribute("forceSubmit", true); - forceSubmit = true; - return; - } - // The field should be focused - if (focus) { - target.addAttribute("focus", true); - } - - // The tab ordering number - if (tabIndex >= 0) { - target.addAttribute("tabindex", tabIndex); - } - - target.addAttribute("state", isUploading); - - if (buttonCaption != null) { - target.addAttribute("buttoncaption", buttonCaption); - } - - target.addAttribute("nextid", nextid); - - // Post file to this strean variable - target.addVariable(this, "action", getStreamVariable()); - - } - - /** - * Interface that must be implemented by the upload receivers to provide the - * Upload component an output stream to write the uploaded data. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface Receiver extends Serializable { - - /** - * Invoked when a new upload arrives. - * - * @param filename - * the desired filename of the upload, usually as specified - * by the client. - * @param mimeType - * the MIME type of the uploaded file. - * @return Stream to which the uploaded file should be written. - */ - public OutputStream receiveUpload(String filename, String mimeType); - - } - - /* Upload events */ - - private static final Method UPLOAD_FINISHED_METHOD; - - private static final Method UPLOAD_FAILED_METHOD; - - private static final Method UPLOAD_SUCCEEDED_METHOD; - - private static final Method UPLOAD_STARTED_METHOD; - - static { - try { - UPLOAD_FINISHED_METHOD = FinishedListener.class.getDeclaredMethod( - "uploadFinished", new Class[] { FinishedEvent.class }); - UPLOAD_FAILED_METHOD = FailedListener.class.getDeclaredMethod( - "uploadFailed", new Class[] { FailedEvent.class }); - UPLOAD_STARTED_METHOD = StartedListener.class.getDeclaredMethod( - "uploadStarted", new Class[] { StartedEvent.class }); - UPLOAD_SUCCEEDED_METHOD = SucceededListener.class - .getDeclaredMethod("uploadSucceeded", - new Class[] { SucceededEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error finding methods in Upload"); - } - } - - /** - * Upload.FinishedEvent is sent when the upload receives a file, regardless - * of whether the reception was successful or failed. If you wish to - * distinguish between the two cases, use either SucceededEvent or - * FailedEvent, which are both subclasses of the FinishedEvent. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class FinishedEvent extends Component.Event { - - /** - * Length of the received file. - */ - private final long length; - - /** - * MIME type of the received file. - */ - private final String type; - - /** - * Received file name. - */ - private final String filename; - - /** - * - * @param source - * the source of the file. - * @param filename - * the received file name. - * @param MIMEType - * the MIME type of the received file. - * @param length - * the length of the received file. - */ - public FinishedEvent(Upload source, String filename, String MIMEType, - long length) { - super(source); - type = MIMEType; - this.filename = filename; - this.length = length; - } - - /** - * Uploads where the event occurred. - * - * @return the Source of the event. - */ - public Upload getUpload() { - return (Upload) getSource(); - } - - /** - * Gets the file name. - * - * @return the filename. - */ - public String getFilename() { - return filename; - } - - /** - * Gets the MIME Type of the file. - * - * @return the MIME type. - */ - public String getMIMEType() { - return type; - } - - /** - * Gets the length of the file. - * - * @return the length. - */ - public long getLength() { - return length; - } - - } - - /** - * Upload.FailedEvent event is sent when the upload is received, but the - * reception is interrupted for some reason. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class FailedEvent extends FinishedEvent { - - private Exception reason = null; - - /** - * - * @param source - * @param filename - * @param MIMEType - * @param length - * @param exception - */ - public FailedEvent(Upload source, String filename, String MIMEType, - long length, Exception reason) { - this(source, filename, MIMEType, length); - this.reason = reason; - } - - /** - * - * @param source - * @param filename - * @param MIMEType - * @param length - * @param exception - */ - public FailedEvent(Upload source, String filename, String MIMEType, - long length) { - super(source, filename, MIMEType, length); - } - - /** - * Gets the exception that caused the failure. - * - * @return the exception that caused the failure, null if n/a - */ - public Exception getReason() { - return reason; - } - - } - - /** - * FailedEvent that indicates that an output stream could not be obtained. - */ - public static class NoOutputStreamEvent extends FailedEvent { - - /** - * - * @param source - * @param filename - * @param MIMEType - * @param length - */ - public NoOutputStreamEvent(Upload source, String filename, - String MIMEType, long length) { - super(source, filename, MIMEType, length); - } - } - - /** - * FailedEvent that indicates that an input stream could not be obtained. - */ - public static class NoInputStreamEvent extends FailedEvent { - - /** - * - * @param source - * @param filename - * @param MIMEType - * @param length - */ - public NoInputStreamEvent(Upload source, String filename, - String MIMEType, long length) { - super(source, filename, MIMEType, length); - } - - } - - /** - * Upload.SucceededEvent event is sent when the upload is received - * successfully. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public static class SucceededEvent extends FinishedEvent { - - /** - * - * @param source - * @param filename - * @param MIMEType - * @param length - */ - public SucceededEvent(Upload source, String filename, String MIMEType, - long length) { - super(source, filename, MIMEType, length); - } - - } - - /** - * Upload.StartedEvent event is sent when the upload is started to received. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ - public static class StartedEvent extends Component.Event { - - private final String filename; - private final String type; - /** - * Length of the received file. - */ - private final long length; - - /** - * - * @param source - * @param filename - * @param MIMEType - * @param length - */ - public StartedEvent(Upload source, String filename, String MIMEType, - long contentLength) { - super(source); - this.filename = filename; - type = MIMEType; - length = contentLength; - } - - /** - * Uploads where the event occurred. - * - * @return the Source of the event. - */ - public Upload getUpload() { - return (Upload) getSource(); - } - - /** - * Gets the file name. - * - * @return the filename. - */ - public String getFilename() { - return filename; - } - - /** - * Gets the MIME Type of the file. - * - * @return the MIME type. - */ - public String getMIMEType() { - return type; - } - - /** - * @return the length of the file that is being uploaded - */ - public long getContentLength() { - return length; - } - - } - - /** - * Receives the events when the upload starts. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.0 - */ - public interface StartedListener extends Serializable { - - /** - * Upload has started. - * - * @param event - * the Upload started event. - */ - public void uploadStarted(StartedEvent event); - } - - /** - * Receives the events when the uploads are ready. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface FinishedListener extends Serializable { - - /** - * Upload has finished. - * - * @param event - * the Upload finished event. - */ - public void uploadFinished(FinishedEvent event); - } - - /** - * Receives events when the uploads are finished, but unsuccessful. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface FailedListener extends Serializable { - - /** - * Upload has finished unsuccessfully. - * - * @param event - * the Upload failed event. - */ - public void uploadFailed(FailedEvent event); - } - - /** - * Receives events when the uploads are successfully finished. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ - public interface SucceededListener extends Serializable { - - /** - * Upload successfull.. - * - * @param event - * the Upload successfull event. - */ - public void uploadSucceeded(SucceededEvent event); - } - - /** - * Adds the upload started event listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(StartedListener listener) { - addListener(StartedEvent.class, listener, UPLOAD_STARTED_METHOD); - } - - /** - * Removes the upload started event listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(StartedListener listener) { - removeListener(StartedEvent.class, listener, UPLOAD_STARTED_METHOD); - } - - /** - * Adds the upload received event listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(FinishedListener listener) { - addListener(FinishedEvent.class, listener, UPLOAD_FINISHED_METHOD); - } - - /** - * Removes the upload received event listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(FinishedListener listener) { - removeListener(FinishedEvent.class, listener, UPLOAD_FINISHED_METHOD); - } - - /** - * Adds the upload interrupted event listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(FailedListener listener) { - addListener(FailedEvent.class, listener, UPLOAD_FAILED_METHOD); - } - - /** - * Removes the upload interrupted event listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(FailedListener listener) { - removeListener(FailedEvent.class, listener, UPLOAD_FAILED_METHOD); - } - - /** - * Adds the upload success event listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(SucceededListener listener) { - addListener(SucceededEvent.class, listener, UPLOAD_SUCCEEDED_METHOD); - } - - /** - * Removes the upload success event listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(SucceededListener listener) { - removeListener(SucceededEvent.class, listener, UPLOAD_SUCCEEDED_METHOD); - } - - /** - * Adds the upload success event listener. - * - * @param listener - * the Listener to be added. - */ - public void addListener(ProgressListener listener) { - if (progressListeners == null) { - progressListeners = new LinkedHashSet<ProgressListener>(); - } - progressListeners.add(listener); - } - - /** - * Removes the upload success event listener. - * - * @param listener - * the Listener to be removed. - */ - public void removeListener(ProgressListener listener) { - if (progressListeners != null) { - progressListeners.remove(listener); - } - } - - /** - * Emit upload received event. - * - * @param filename - * @param MIMEType - * @param length - */ - protected void fireStarted(String filename, String MIMEType) { - fireEvent(new Upload.StartedEvent(this, filename, MIMEType, - contentLength)); - } - - /** - * Emits the upload failed event. - * - * @param filename - * @param MIMEType - * @param length - */ - protected void fireUploadInterrupted(String filename, String MIMEType, - long length) { - fireEvent(new Upload.FailedEvent(this, filename, MIMEType, length)); - } - - protected void fireNoInputStream(String filename, String MIMEType, - long length) { - fireEvent(new Upload.NoInputStreamEvent(this, filename, MIMEType, - length)); - } - - protected void fireNoOutputStream(String filename, String MIMEType, - long length) { - fireEvent(new Upload.NoOutputStreamEvent(this, filename, MIMEType, - length)); - } - - protected void fireUploadInterrupted(String filename, String MIMEType, - long length, Exception e) { - fireEvent(new Upload.FailedEvent(this, filename, MIMEType, length, e)); - } - - /** - * Emits the upload success event. - * - * @param filename - * @param MIMEType - * @param length - * - */ - protected void fireUploadSuccess(String filename, String MIMEType, - long length) { - fireEvent(new Upload.SucceededEvent(this, filename, MIMEType, length)); - } - - /** - * Emits the progress event. - * - * @param totalBytes - * bytes received so far - * @param contentLength - * actual size of the file being uploaded, if known - * - */ - protected void fireUpdateProgress(long totalBytes, long contentLength) { - // this is implemented differently than other listeners to maintain - // backwards compatibility - if (progressListeners != null) { - for (Iterator<ProgressListener> it = progressListeners.iterator(); it - .hasNext();) { - ProgressListener l = it.next(); - l.updateProgress(totalBytes, contentLength); - } - } - } - - /** - * Returns the current receiver. - * - * @return the StreamVariable. - */ - public Receiver getReceiver() { - return receiver; - } - - /** - * Sets the receiver. - * - * @param receiver - * the receiver to set. - */ - public void setReceiver(Receiver receiver) { - this.receiver = receiver; - } - - /** - * {@inheritDoc} - */ - @Override - public void focus() { - super.focus(); - } - - /** - * Gets the Tabulator index of this Focusable component. - * - * @see com.vaadin.ui.Component.Focusable#getTabIndex() - */ - @Override - public int getTabIndex() { - return tabIndex; - } - - /** - * Sets the Tabulator index of this Focusable component. - * - * @see com.vaadin.ui.Component.Focusable#setTabIndex(int) - */ - @Override - public void setTabIndex(int tabIndex) { - this.tabIndex = tabIndex; - } - - /** - * Go into upload state. This is to prevent double uploading on same - * component. - * - * Warning: this is an internal method used by the framework and should not - * be used by user of the Upload component. Using it results in the Upload - * component going in wrong state and not working. It is currently public - * because it is used by another class. - */ - public void startUpload() { - if (isUploading) { - throw new IllegalStateException("uploading already started"); - } - isUploading = true; - nextid++; - } - - /** - * Interrupts the upload currently being received. The interruption will be - * done by the receiving tread so this method will return immediately and - * the actual interrupt will happen a bit later. - */ - public void interruptUpload() { - if (isUploading) { - interrupted = true; - } - } - - /** - * Go into state where new uploading can begin. - * - * Warning: this is an internal method used by the framework and should not - * be used by user of the Upload component. - */ - private void endUpload() { - isUploading = false; - contentLength = -1; - interrupted = false; - requestRepaint(); - } - - public boolean isUploading() { - return isUploading; - } - - /** - * Gets read bytes of the file currently being uploaded. - * - * @return bytes - */ - public long getBytesRead() { - return totalBytes; - } - - /** - * Returns size of file currently being uploaded. Value sane only during - * upload. - * - * @return size in bytes - */ - public long getUploadSize() { - return contentLength; - } - - /** - * This method is deprecated, use addListener(ProgressListener) instead. - * - * @deprecated Use addListener(ProgressListener) instead. - * @param progressListener - */ - @Deprecated - public void setProgressListener(ProgressListener progressListener) { - addListener(progressListener); - } - - /** - * This method is deprecated. - * - * @deprecated Replaced with addListener/removeListener - * @return listener - * - */ - @Deprecated - public ProgressListener getProgressListener() { - if (progressListeners == null || progressListeners.isEmpty()) { - return null; - } else { - return progressListeners.iterator().next(); - } - } - - /** - * ProgressListener receives events to track progress of upload. - */ - public interface ProgressListener extends Serializable { - /** - * Updates progress to listener - * - * @param readBytes - * bytes transferred - * @param contentLength - * total size of file currently being uploaded, -1 if unknown - */ - public void updateProgress(long readBytes, long contentLength); - } - - /** - * @return String to be rendered into button that fires uploading - */ - public String getButtonCaption() { - return buttonCaption; - } - - /** - * In addition to the actual file chooser, upload components have button - * that starts actual upload progress. This method is used to set text in - * that button. - * <p> - * In case the button text is set to null, the button is hidden. In this - * case developer must explicitly initiate the upload process with - * {@link #submitUpload()}. - * <p> - * In case the Upload is used in immediate mode using - * {@link #setImmediate(boolean)}, the file choose (html input with type - * "file") is hidden and only the button with this text is shown. - * <p> - * - * <p> - * <strong>Note</strong> the string given is set as is to the button. HTML - * formatting is not stripped. Be sure to properly validate your value - * according to your needs. - * - * @param buttonCaption - * text for upload components button. - */ - public void setButtonCaption(String buttonCaption) { - this.buttonCaption = buttonCaption; - requestRepaint(); - } - - /** - * Forces the upload the send selected file to the server. - * <p> - * In case developer wants to use this feature, he/she will most probably - * want to hide the uploads internal submit button by setting its caption to - * null with {@link #setButtonCaption(String)} method. - * <p> - * Note, that the upload runs asynchronous. Developer should use normal - * upload listeners to trac the process of upload. If the field is empty - * uploaded the file name will be empty string and file length 0 in the - * upload finished event. - * <p> - * Also note, that the developer should not remove or modify the upload in - * the same user transaction where the upload submit is requested. The - * upload may safely be hidden or removed once the upload started event is - * fired. - */ - public void submitUpload() { - requestRepaint(); - forceSubmit = true; - } - - @Override - public void requestRepaint() { - forceSubmit = false; - super.requestRepaint(); - } - - /* - * Handle to terminal via Upload monitors and controls the upload during it - * is being streamed. - */ - private com.vaadin.terminal.StreamVariable streamVariable; - - protected com.vaadin.terminal.StreamVariable getStreamVariable() { - if (streamVariable == null) { - streamVariable = new com.vaadin.terminal.StreamVariable() { - private StreamingStartEvent lastStartedEvent; - - @Override - public boolean listenProgress() { - return (progressListeners != null && !progressListeners - .isEmpty()); - } - - @Override - public void onProgress(StreamingProgressEvent event) { - fireUpdateProgress(event.getBytesReceived(), - event.getContentLength()); - } - - @Override - public boolean isInterrupted() { - return interrupted; - } - - @Override - public OutputStream getOutputStream() { - OutputStream receiveUpload = receiver.receiveUpload( - lastStartedEvent.getFileName(), - lastStartedEvent.getMimeType()); - lastStartedEvent = null; - return receiveUpload; - } - - @Override - public void streamingStarted(StreamingStartEvent event) { - startUpload(); - contentLength = event.getContentLength(); - fireStarted(event.getFileName(), event.getMimeType()); - lastStartedEvent = event; - } - - @Override - public void streamingFinished(StreamingEndEvent event) { - fireUploadSuccess(event.getFileName(), event.getMimeType(), - event.getContentLength()); - endUpload(); - requestRepaint(); - } - - @Override - public void streamingFailed(StreamingErrorEvent event) { - Exception exception = event.getException(); - if (exception instanceof NoInputStreamException) { - fireNoInputStream(event.getFileName(), - event.getMimeType(), 0); - } else if (exception instanceof NoOutputStreamException) { - fireNoOutputStream(event.getFileName(), - event.getMimeType(), 0); - } else { - fireUploadInterrupted(event.getFileName(), - event.getMimeType(), 0, exception); - } - endUpload(); - } - }; - } - return streamVariable; - } - - @Override - public java.util.Collection<?> getListeners(java.lang.Class<?> eventType) { - if (StreamingProgressEvent.class.isAssignableFrom(eventType)) { - if (progressListeners == null) { - return Collections.EMPTY_LIST; - } else { - return Collections.unmodifiableCollection(progressListeners); - } - - } - return super.getListeners(eventType); - }; -} diff --git a/src/com/vaadin/ui/VerticalLayout.java b/src/com/vaadin/ui/VerticalLayout.java deleted file mode 100644 index a04d052d98..0000000000 --- a/src/com/vaadin/ui/VerticalLayout.java +++ /dev/null @@ -1,25 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -/** - * Vertical layout - * - * <code>VerticalLayout</code> is a component container, which shows the - * subcomponents in the order of their addition (vertically). A vertical layout - * is by default 100% wide. - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 5.3 - */ -@SuppressWarnings("serial") -public class VerticalLayout extends AbstractOrderedLayout { - - public VerticalLayout() { - setWidth("100%"); - } - -} diff --git a/src/com/vaadin/ui/VerticalSplitPanel.java b/src/com/vaadin/ui/VerticalSplitPanel.java deleted file mode 100644 index 0630240e9c..0000000000 --- a/src/com/vaadin/ui/VerticalSplitPanel.java +++ /dev/null @@ -1,30 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui; - -/** - * A vertical split panel contains two components and lays them vertically. The - * first component is above the second component. - * - * <pre> - * +--------------------------+ - * | | - * | The first component | - * | | - * +==========================+ <-- splitter - * | | - * | The second component | - * | | - * +--------------------------+ - * </pre> - * - */ -public class VerticalSplitPanel extends AbstractSplitPanel { - - public VerticalSplitPanel() { - super(); - setSizeFull(); - } - -} diff --git a/src/com/vaadin/ui/Video.java b/src/com/vaadin/ui/Video.java deleted file mode 100644 index d4f95a5be3..0000000000 --- a/src/com/vaadin/ui/Video.java +++ /dev/null @@ -1,81 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import com.vaadin.shared.ui.video.VideoState; -import com.vaadin.terminal.Resource; -import com.vaadin.terminal.gwt.server.ResourceReference; - -/** - * The Video component translates into an HTML5 <video> element and as - * such is only supported in browsers that support HTML5 media markup. Browsers - * that do not support HTML5 display the text or HTML set by calling - * {@link #setAltText(String)}. - * - * A flash-player fallback can be implemented by setting HTML content allowed ( - * {@link #setHtmlContentAllowed(boolean)} and calling - * {@link #setAltText(String)} with the flash player markup. An example of flash - * fallback can be found at the <a href= - * "https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox#Using_Flash" - * >Mozilla Developer Network</a>. - * - * Multiple sources can be specified. Which of the sources is used is selected - * by the browser depending on which file formats it supports. See <a - * href="http://en.wikipedia.org/wiki/HTML5_video#Table">wikipedia</a> for a - * table of formats supported by different browsers. - * - * @author Vaadin Ltd - * @since 6.7.0 - */ -public class Video extends AbstractMedia { - - @Override - public VideoState getState() { - return (VideoState) super.getState(); - } - - public Video() { - this("", null); - } - - /** - * @param caption - * The caption for this video. - */ - public Video(String caption) { - this(caption, null); - } - - /** - * @param caption - * The caption for this video. - * @param source - * The Resource containing the video to play. - */ - public Video(String caption, Resource source) { - setCaption(caption); - setSource(source); - setShowControls(true); - } - - /** - * Sets the poster image, which is shown in place of the video before the - * user presses play. - * - * @param poster - */ - public void setPoster(Resource poster) { - getState().setPoster(ResourceReference.create(poster)); - requestRepaint(); - } - - /** - * @return The poster image. - */ - public Resource getPoster() { - return ResourceReference.getResource(getState().getPoster()); - } - -} diff --git a/src/com/vaadin/ui/Window.java b/src/com/vaadin/ui/Window.java deleted file mode 100644 index e413d35e6d..0000000000 --- a/src/com/vaadin/ui/Window.java +++ /dev/null @@ -1,853 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ - -package com.vaadin.ui; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Map; - -import com.vaadin.event.FieldEvents.BlurEvent; -import com.vaadin.event.FieldEvents.BlurListener; -import com.vaadin.event.FieldEvents.BlurNotifier; -import com.vaadin.event.FieldEvents.FocusEvent; -import com.vaadin.event.FieldEvents.FocusListener; -import com.vaadin.event.FieldEvents.FocusNotifier; -import com.vaadin.event.MouseEvents.ClickEvent; -import com.vaadin.event.ShortcutAction; -import com.vaadin.event.ShortcutAction.KeyCode; -import com.vaadin.event.ShortcutAction.ModifierKey; -import com.vaadin.event.ShortcutListener; -import com.vaadin.shared.MouseEventDetails; -import com.vaadin.shared.ui.window.WindowServerRpc; -import com.vaadin.shared.ui.window.WindowState; -import com.vaadin.terminal.PaintException; -import com.vaadin.terminal.PaintTarget; -import com.vaadin.terminal.Vaadin6Component; -import com.vaadin.terminal.gwt.client.ui.root.VRoot; - -/** - * A component that represents a floating popup window that can be added to a - * {@link Root}. A window is added to a {@code Root} using - * {@link Root#addWindow(Window)}. </p> - * <p> - * The contents of a window is set using {@link #setContent(ComponentContainer)} - * or by using the {@link #Window(String, ComponentContainer)} constructor. The - * contents can in turn contain other components. By default, a - * {@link VerticalLayout} is used as content. - * </p> - * <p> - * A window can be positioned on the screen using absolute coordinates (pixels) - * or set to be centered using {@link #center()} - * </p> - * <p> - * The caption is displayed in the window header. - * </p> - * <p> - * In Vaadin versions prior to 7.0.0, Window was also used as application level - * windows. This function is now covered by the {@link Root} class. - * </p> - * - * @author Vaadin Ltd. - * @version - * @VERSION@ - * @since 3.0 - */ -@SuppressWarnings("serial") -public class Window extends Panel implements FocusNotifier, BlurNotifier, - Vaadin6Component { - - private WindowServerRpc rpc = new WindowServerRpc() { - - @Override - public void click(MouseEventDetails mouseDetails) { - fireEvent(new ClickEvent(Window.this, mouseDetails)); - } - }; - - private int browserWindowWidth = -1; - - private int browserWindowHeight = -1; - - /** - * Creates a new unnamed window with a default layout. - */ - public Window() { - this("", null); - } - - /** - * Creates a new unnamed window with a default layout and given title. - * - * @param caption - * the title of the window. - */ - public Window(String caption) { - this(caption, null); - } - - /** - * Creates a new unnamed window with the given content and title. - * - * @param caption - * the title of the window. - * @param content - * the contents of the window - */ - public Window(String caption, ComponentContainer content) { - super(caption, content); - registerRpc(rpc); - setSizeUndefined(); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Panel#addComponent(com.vaadin.ui.Component) - */ - - @Override - public void addComponent(Component c) { - if (c instanceof Window) { - throw new IllegalArgumentException( - "Window cannot be added to another via addComponent. " - + "Use addWindow(Window) instead."); - } - super.addComponent(c); - } - - /* ********************************************************************* */ - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Panel#paintContent(com.vaadin.terminal.PaintTarget) - */ - - @Override - public synchronized void paintContent(PaintTarget target) - throws PaintException { - if (bringToFront != null) { - target.addAttribute("bringToFront", bringToFront.intValue()); - bringToFront = null; - } - - // Contents of the window panel is painted - super.paintContent(target); - } - - /* - * (non-Javadoc) - * - * @see com.vaadin.ui.Panel#changeVariables(java.lang.Object, java.util.Map) - */ - - @Override - public void changeVariables(Object source, Map<String, Object> variables) { - - // TODO Are these for top level windows or sub windows? - boolean sizeHasChanged = false; - // size is handled in super class, but resize events only in windows -> - // so detect if size change occurs before super.changeVariables() - if (variables.containsKey("height") - && (getHeightUnits() != Unit.PIXELS || (Integer) variables - .get("height") != getHeight())) { - sizeHasChanged = true; - } - if (variables.containsKey("width") - && (getWidthUnits() != Unit.PIXELS || (Integer) variables - .get("width") != getWidth())) { - sizeHasChanged = true; - } - Integer browserHeightVar = (Integer) variables - .get(VRoot.BROWSER_HEIGHT_VAR); - if (browserHeightVar != null - && browserHeightVar.intValue() != browserWindowHeight) { - browserWindowHeight = browserHeightVar.intValue(); - sizeHasChanged = true; - } - Integer browserWidthVar = (Integer) variables - .get(VRoot.BROWSER_WIDTH_VAR); - if (browserWidthVar != null - && browserWidthVar.intValue() != browserWindowWidth) { - browserWindowWidth = browserWidthVar.intValue(); - sizeHasChanged = true; - } - - super.changeVariables(source, variables); - - // Positioning - final Integer positionx = (Integer) variables.get("positionx"); - if (positionx != null) { - final int x = positionx.intValue(); - // This is information from the client so it is already using the - // position. No need to repaint. - setPositionX(x < 0 ? -1 : x, false); - } - final Integer positiony = (Integer) variables.get("positiony"); - if (positiony != null) { - final int y = positiony.intValue(); - // This is information from the client so it is already using the - // position. No need to repaint. - setPositionY(y < 0 ? -1 : y, false); - } - - if (isClosable()) { - // Closing - final Boolean close = (Boolean) variables.get("close"); - if (close != null && close.booleanValue()) { - close(); - } - } - - // fire event if size has really changed - if (sizeHasChanged) { - fireResize(); - } - - if (variables.containsKey(FocusEvent.EVENT_ID)) { - fireEvent(new FocusEvent(this)); - } else if (variables.containsKey(BlurEvent.EVENT_ID)) { - fireEvent(new BlurEvent(this)); - } - - } - - /** - * Method that handles window closing (from UI). - * - * <p> - * By default, sub-windows are removed from their respective parent windows - * and thus visually closed on browser-side. Browser-level windows also - * closed on the client-side, but they are not implicitly removed from the - * application. - * </p> - * - * <p> - * To explicitly close a sub-window, use {@link #removeWindow(Window)}. To - * react to a window being closed (after it is closed), register a - * {@link CloseListener}. - * </p> - */ - public void close() { - Root root = getRoot(); - - // Don't do anything if not attached to a root - if (root != null) { - // focus is restored to the parent window - root.focus(); - // subwindow is removed from the root - root.removeWindow(this); - } - } - - /** - * Gets the distance of Window left border in pixels from left border of the - * containing (main window). - * - * @return the Distance of Window left border in pixels from left border of - * the containing (main window). or -1 if unspecified. - * @since 4.0.0 - */ - public int getPositionX() { - return getState().getPositionX(); - } - - /** - * Sets the distance of Window left border in pixels from left border of the - * containing (main window). - * - * @param positionX - * the Distance of Window left border in pixels from left border - * of the containing (main window). or -1 if unspecified. - * @since 4.0.0 - */ - public void setPositionX(int positionX) { - setPositionX(positionX, true); - } - - /** - * Sets the distance of Window left border in pixels from left border of the - * containing (main window). - * - * @param positionX - * the Distance of Window left border in pixels from left border - * of the containing (main window). or -1 if unspecified. - * @param repaintRequired - * true if the window needs to be repainted, false otherwise - * @since 6.3.4 - */ - private void setPositionX(int positionX, boolean repaintRequired) { - getState().setPositionX(positionX); - getState().setCentered(false); - if (repaintRequired) { - requestRepaint(); - } - } - - /** - * Gets the distance of Window top border in pixels from top border of the - * containing (main window). - * - * @return Distance of Window top border in pixels from top border of the - * containing (main window). or -1 if unspecified . - * - * @since 4.0.0 - */ - public int getPositionY() { - return getState().getPositionY(); - } - - /** - * Sets the distance of Window top border in pixels from top border of the - * containing (main window). - * - * @param positionY - * the Distance of Window top border in pixels from top border of - * the containing (main window). or -1 if unspecified - * - * @since 4.0.0 - */ - public void setPositionY(int positionY) { - setPositionY(positionY, true); - } - - /** - * Sets the distance of Window top border in pixels from top border of the - * containing (main window). - * - * @param positionY - * the Distance of Window top border in pixels from top border of - * the containing (main window). or -1 if unspecified - * @param repaintRequired - * true if the window needs to be repainted, false otherwise - * - * @since 6.3.4 - */ - private void setPositionY(int positionY, boolean repaintRequired) { - getState().setPositionY(positionY); - getState().setCentered(false); - if (repaintRequired) { - requestRepaint(); - } - } - - private static final Method WINDOW_CLOSE_METHOD; - static { - try { - WINDOW_CLOSE_METHOD = CloseListener.class.getDeclaredMethod( - "windowClose", new Class[] { CloseEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error, window close method not found"); - } - } - - public class CloseEvent extends Component.Event { - - /** - * - * @param source - */ - public CloseEvent(Component source) { - super(source); - } - - /** - * Gets the Window. - * - * @return the window. - */ - public Window getWindow() { - return (Window) getSource(); - } - } - - /** - * An interface used for listening to Window close events. Add the - * CloseListener to a browser level window or a sub window and - * {@link CloseListener#windowClose(CloseEvent)} will be called whenever the - * user closes the window. - * - * <p> - * Since Vaadin 6.5, removing a window using {@link #removeWindow(Window)} - * fires the CloseListener. - * </p> - */ - public interface CloseListener extends Serializable { - /** - * Called when the user closes a window. Use - * {@link CloseEvent#getWindow()} to get a reference to the - * {@link Window} that was closed. - * - * @param e - * Event containing - */ - public void windowClose(CloseEvent e); - } - - /** - * Adds a CloseListener to the window. - * - * For a sub window the CloseListener is fired when the user closes it - * (clicks on the close button). - * - * For a browser level window the CloseListener is fired when the browser - * level window is closed. Note that closing a browser level window does not - * mean it will be destroyed. Also note that Opera does not send events like - * all other browsers and therefore the close listener might not be called - * if Opera is used. - * - * <p> - * Since Vaadin 6.5, removing windows using {@link #removeWindow(Window)} - * does fire the CloseListener. - * </p> - * - * @param listener - * the CloseListener to add. - */ - public void addListener(CloseListener listener) { - addListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD); - } - - /** - * Removes the CloseListener from the window. - * - * <p> - * For more information on CloseListeners see {@link CloseListener}. - * </p> - * - * @param listener - * the CloseListener to remove. - */ - public void removeListener(CloseListener listener) { - removeListener(CloseEvent.class, listener, WINDOW_CLOSE_METHOD); - } - - protected void fireClose() { - fireEvent(new Window.CloseEvent(this)); - } - - /** - * Method for the resize event. - */ - private static final Method WINDOW_RESIZE_METHOD; - static { - try { - WINDOW_RESIZE_METHOD = ResizeListener.class.getDeclaredMethod( - "windowResized", new Class[] { ResizeEvent.class }); - } catch (final java.lang.NoSuchMethodException e) { - // This should never happen - throw new java.lang.RuntimeException( - "Internal error, window resized method not found"); - } - } - - /** - * Resize events are fired whenever the client-side fires a resize-event - * (e.g. the browser window is resized). The frequency may vary across - * browsers. - */ - public class ResizeEvent extends Component.Event { - - /** - * - * @param source - */ - public ResizeEvent(Component source) { - super(source); - } - - /** - * Get the window form which this event originated - * - * @return the window - */ - public Window getWindow() { - return (Window) getSource(); - } - } - - /** - * Listener for window resize events. - * - * @see com.vaadin.ui.Window.ResizeEvent - */ - public interface ResizeListener extends Serializable { - public void windowResized(ResizeEvent e); - } - - /** - * Add a resize listener. - * - * @param listener - */ - public void addListener(ResizeListener listener) { - addListener(ResizeEvent.class, listener, WINDOW_RESIZE_METHOD); - } - - /** - * Remove a resize listener. - * - * @param listener - */ - public void removeListener(ResizeListener listener) { - removeListener(ResizeEvent.class, listener); - } - - /** - * Fire the resize event. - */ - protected void fireResize() { - fireEvent(new ResizeEvent(this)); - } - - /** - * Used to keep the right order of windows if multiple windows are brought - * to front in a single changeset. If this is not used, the order is quite - * random (depends on the order getting to dirty list. e.g. which window got - * variable changes). - */ - private Integer bringToFront = null; - - /** - * If there are currently several windows visible, calling this method makes - * this window topmost. - * <p> - * This method can only be called if this window connected a root. Else an - * illegal state exception is thrown. Also if there are modal windows and - * this window is not modal, and illegal state exception is thrown. - * <p> - */ - public void bringToFront() { - Root root = getRoot(); - if (root == null) { - throw new IllegalStateException( - "Window must be attached to parent before calling bringToFront method."); - } - int maxBringToFront = -1; - for (Window w : root.getWindows()) { - if (!isModal() && w.isModal()) { - throw new IllegalStateException( - "The root contains modal windows, non-modal window cannot be brought to front."); - } - if (w.bringToFront != null) { - maxBringToFront = Math.max(maxBringToFront, - w.bringToFront.intValue()); - } - } - bringToFront = Integer.valueOf(maxBringToFront + 1); - requestRepaint(); - } - - /** - * Sets sub-window modal, so that widgets behind it cannot be accessed. - * <b>Note:</b> affects sub-windows only. - * - * @param modal - * true if modality is to be turned on - */ - public void setModal(boolean modal) { - getState().setModal(modal); - center(); - requestRepaint(); - } - - /** - * @return true if this window is modal. - */ - public boolean isModal() { - return getState().isModal(); - } - - /** - * Sets sub-window resizable. <b>Note:</b> affects sub-windows only. - * - * @param resizable - * true if resizability is to be turned on - */ - public void setResizable(boolean resizable) { - getState().setResizable(resizable); - requestRepaint(); - } - - /** - * - * @return true if window is resizable by the end-user, otherwise false. - */ - public boolean isResizable() { - return getState().isResizable(); - } - - /** - * - * @return true if a delay is used before recalculating sizes, false if - * sizes are recalculated immediately. - */ - public boolean isResizeLazy() { - return getState().isResizeLazy(); - } - - /** - * Should resize operations be lazy, i.e. should there be a delay before - * layout sizes are recalculated. Speeds up resize operations in slow UIs - * with the penalty of slightly decreased usability. - * - * Note, some browser send false resize events for the browser window and - * are therefore always lazy. - * - * @param resizeLazy - * true to use a delay before recalculating sizes, false to - * calculate immediately. - */ - public void setResizeLazy(boolean resizeLazy) { - getState().setResizeLazy(resizeLazy); - requestRepaint(); - } - - /** - * Sets this window to be centered relative to its parent window. Affects - * sub-windows only. If the window is resized as a result of the size of its - * content changing, it will keep itself centered as long as its position is - * not explicitly changed programmatically or by the user. - * <p> - * <b>NOTE:</b> This method has several issues as currently implemented. - * Please refer to http://dev.vaadin.com/ticket/8971 for details. - */ - public void center() { - getState().setCentered(true); - requestRepaint(); - } - - /** - * Returns the closable status of the sub window. If a sub window is - * closable it typically shows an X in the upper right corner. Clicking on - * the X sends a close event to the server. Setting closable to false will - * remove the X from the sub window and prevent the user from closing the - * window. - * - * Note! For historical reasons readonly controls the closability of the sub - * window and therefore readonly and closable affect each other. Setting - * readonly to true will set closable to false and vice versa. - * <p/> - * Closable only applies to sub windows, not to browser level windows. - * - * @return true if the sub window can be closed by the user. - */ - public boolean isClosable() { - return !isReadOnly(); - } - - /** - * Sets the closable status for the sub window. If a sub window is closable - * it typically shows an X in the upper right corner. Clicking on the X - * sends a close event to the server. Setting closable to false will remove - * the X from the sub window and prevent the user from closing the window. - * - * Note! For historical reasons readonly controls the closability of the sub - * window and therefore readonly and closable affect each other. Setting - * readonly to true will set closable to false and vice versa. - * <p/> - * Closable only applies to sub windows, not to browser level windows. - * - * @param closable - * determines if the sub window can be closed by the user. - */ - public void setClosable(boolean closable) { - setReadOnly(!closable); - } - - /** - * Indicates whether a sub window can be dragged or not. By default a sub - * window is draggable. - * <p/> - * Draggable only applies to sub windows, not to browser level windows. - * - * @param draggable - * true if the sub window can be dragged by the user - */ - public boolean isDraggable() { - return getState().isDraggable(); - } - - /** - * Enables or disables that a sub window can be dragged (moved) by the user. - * By default a sub window is draggable. - * <p/> - * Draggable only applies to sub windows, not to browser level windows. - * - * @param draggable - * true if the sub window can be dragged by the user - */ - public void setDraggable(boolean draggable) { - getState().setDraggable(draggable); - requestRepaint(); - } - - /* - * Actions - */ - protected CloseShortcut closeShortcut; - - /** - * Makes is possible to close the window by pressing the given - * {@link KeyCode} and (optional) {@link ModifierKey}s.<br/> - * Note that this shortcut only reacts while the window has focus, closing - * itself - if you want to close a subwindow from a parent window, use - * {@link #addAction(com.vaadin.event.Action)} of the parent window instead. - * - * @param keyCode - * the keycode for invoking the shortcut - * @param modifiers - * the (optional) modifiers for invoking the shortcut, null for - * none - */ - public void setCloseShortcut(int keyCode, int... modifiers) { - if (closeShortcut != null) { - removeAction(closeShortcut); - } - closeShortcut = new CloseShortcut(this, keyCode, modifiers); - addAction(closeShortcut); - } - - /** - * Removes the keyboard shortcut previously set with - * {@link #setCloseShortcut(int, int...)}. - */ - public void removeCloseShortcut() { - if (closeShortcut != null) { - removeAction(closeShortcut); - closeShortcut = null; - } - } - - /** - * A {@link ShortcutListener} specifically made to define a keyboard - * shortcut that closes the window. - * - * <pre> - * <code> - * // within the window using helper - * subWindow.setCloseShortcut(KeyCode.ESCAPE, null); - * - * // or globally - * getWindow().addAction(new Window.CloseShortcut(subWindow, KeyCode.ESCAPE)); - * </code> - * </pre> - * - */ - public static class CloseShortcut extends ShortcutListener { - protected Window window; - - /** - * Creates a keyboard shortcut for closing the given window using the - * shorthand notation defined in {@link ShortcutAction}. - * - * @param window - * to be closed when the shortcut is invoked - * @param shorthandCaption - * the caption with shortcut keycode and modifiers indicated - */ - public CloseShortcut(Window window, String shorthandCaption) { - super(shorthandCaption); - this.window = window; - } - - /** - * Creates a keyboard shortcut for closing the given window using the - * given {@link KeyCode} and {@link ModifierKey}s. - * - * @param window - * to be closed when the shortcut is invoked - * @param keyCode - * KeyCode to react to - * @param modifiers - * optional modifiers for shortcut - */ - public CloseShortcut(Window window, int keyCode, int... modifiers) { - super(null, keyCode, modifiers); - this.window = window; - } - - /** - * Creates a keyboard shortcut for closing the given window using the - * given {@link KeyCode}. - * - * @param window - * to be closed when the shortcut is invoked - * @param keyCode - * KeyCode to react to - */ - public CloseShortcut(Window window, int keyCode) { - this(window, keyCode, null); - } - - @Override - public void handleAction(Object sender, Object target) { - window.close(); - } - } - - /** - * Note, that focus/blur listeners in Window class are only supported by sub - * windows. Also note that Window is not considered focused if its contained - * component currently has focus. - * - * @see com.vaadin.event.FieldEvents.FocusNotifier#addListener(com.vaadin.event.FieldEvents.FocusListener) - */ - - @Override - public void addListener(FocusListener listener) { - addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener, - FocusListener.focusMethod); - } - - @Override - public void removeListener(FocusListener listener) { - removeListener(FocusEvent.EVENT_ID, FocusEvent.class, listener); - } - - /** - * Note, that focus/blur listeners in Window class are only supported by sub - * windows. Also note that Window is not considered focused if its contained - * component currently has focus. - * - * @see com.vaadin.event.FieldEvents.BlurNotifier#addListener(com.vaadin.event.FieldEvents.BlurListener) - */ - - @Override - public void addListener(BlurListener listener) { - addListener(BlurEvent.EVENT_ID, BlurEvent.class, listener, - BlurListener.blurMethod); - } - - @Override - public void removeListener(BlurListener listener) { - removeListener(BlurEvent.EVENT_ID, BlurEvent.class, listener); - } - - /** - * {@inheritDoc} - * - * If the window is a sub-window focusing will cause the sub-window to be - * brought on top of other sub-windows on gain keyboard focus. - */ - - @Override - public void focus() { - /* - * When focusing a sub-window it basically means it should be brought to - * the front. Instead of just moving the keyboard focus we focus the - * window and bring it top-most. - */ - super.focus(); - bringToFront(); - } - - @Override - public WindowState getState() { - return (WindowState) super.getState(); - } -} diff --git a/src/com/vaadin/ui/doc-files/component_class_hierarchy.gif b/src/com/vaadin/ui/doc-files/component_class_hierarchy.gif Binary files differdeleted file mode 100644 index 936c220d11..0000000000 --- a/src/com/vaadin/ui/doc-files/component_class_hierarchy.gif +++ /dev/null diff --git a/src/com/vaadin/ui/doc-files/component_interfaces.gif b/src/com/vaadin/ui/doc-files/component_interfaces.gif Binary files differdeleted file mode 100644 index 44c99826bb..0000000000 --- a/src/com/vaadin/ui/doc-files/component_interfaces.gif +++ /dev/null diff --git a/src/com/vaadin/ui/package.html b/src/com/vaadin/ui/package.html deleted file mode 100644 index 6b19a28fe7..0000000000 --- a/src/com/vaadin/ui/package.html +++ /dev/null @@ -1,76 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> -<html> -<head> - -</head> - -<body bgcolor="white"> - -<!-- Package summary here --> - -<p>Provides interfaces and classes in Vaadin.</p> - -<h2>Package Specification</h2> - -<p><strong>Interface hierarchy</strong></p> - -<p>The general interface hierarchy looks like this:</p> - -<p style="text-align: center;"><img - src="doc-files/component_interfaces.gif" /></p> - -<p><i>Note that the above picture includes only the main -interfaces. This package includes several other lesser sub-interfaces -which are not significant in this scope. The interfaces not appearing -here are documented with the classes that define them.</i></p> - -<p>The {@link com.vaadin.ui.Component} interface is the top-level -interface which must be implemented by all user interface components in -Vaadin. It defines the common properties of the components and how the -framework will handle them. Most simple components, such as {@link -com.vaadin.ui.Button}, for example, do not need to implement the -lower-level interfaces described below. Notice that also the classes and -interfaces required by the component event framework are defined in -{@link com.vaadin.ui.Component}.</p> - -<p>The next level in the component hierarchy are the classes -implementing the {@link com.vaadin.ui.ComponentContainer} interface. It -adds the capacity to contain other components to {@link -com.vaadin.ui.Component} with a simple API.</p> - -<p>The third and last level is the {@link com.vaadin.ui.Layout}, -which adds the concept of location to the components contained in a -{@link com.vaadin.ui.ComponentContainer}. It can be used to create -containers which contents can be positioned.</p> - -<p><strong>Component class hierarchy</strong></p> - -<p>The actual component classes form a hierarchy like this:</p> - -<center><img src="doc-files/component_class_hierarchy.gif" /></center> -<br /> - -<center><i>Underlined classes are abstract.</i></center> - -<p>At the top level is {@link com.vaadin.ui.AbstractComponent} which -implements the {@link com.vaadin.ui.Component} interface. As the name -suggests it is abstract, but it does include a default implementation -for all methods defined in <code>Component</code> so that a component is -free to override only those functionalities it needs.</p> - -<p>As seen in the picture, <code>AbstractComponent</code> serves as -the superclass for several "real" components, but it also has a some -abstract extensions. {@link com.vaadin.ui.AbstractComponentContainer} -serves as the root class for all components (for example, panels and -windows) who can contain other components. {@link -com.vaadin.ui.AbstractField}, on the other hand, implements several -interfaces to provide a base class for components that are used for data -display and manipulation.</p> - - -<!-- Package spec here --> - -<!-- Put @see and @since tags down here. --> - -</body> -</html> diff --git a/src/com/vaadin/ui/themes/BaseTheme.java b/src/com/vaadin/ui/themes/BaseTheme.java deleted file mode 100644 index 6f448746bf..0000000000 --- a/src/com/vaadin/ui/themes/BaseTheme.java +++ /dev/null @@ -1,59 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui.themes; - -/** - * <p> - * The Base theme is the foundation for all Vaadin themes. Although it is not - * necessary to use it as the starting point for all other themes, it is heavily - * encouraged, since it abstracts and hides away many necessary style properties - * that the Vaadin terminal expects and needs. - * </p> - * <p> - * When creating your own theme, either extend this class and specify the styles - * implemented in your theme here, or extend some other theme that has a class - * file specified (e.g. Reindeer or Runo). - * </p> - * <p> - * All theme class files should follow the convention of specifying the theme - * name as a string constant <code>THEME_NAME</code>. - * - * @since 6.3.0 - * - */ -public class BaseTheme { - - public static final String THEME_NAME = "base"; - - /** - * Creates a button that looks like a regular hypertext link but still acts - * like a normal button. - */ - public static final String BUTTON_LINK = "link"; - - /** - * Removes extra decorations from the panel. - * - * @deprecated Base theme does not implement this style, but it is defined - * here since it has been a part of the framework before - * multiple themes were available. Use the constant provided by - * the theme you're using instead, e.g. - * {@link Reindeer#PANEL_LIGHT} or {@link Runo#PANEL_LIGHT}. - */ - @Deprecated - public static final String PANEL_LIGHT = "light"; - - /** - * Adds the connector lines between a parent node and its child nodes to - * indicate the tree hierarchy better. - */ - public static final String TREE_CONNECTORS = "connectors"; - - /** - * Clips the component so it will be constrained to its given size and not - * overflow. - */ - public static final String CLIP = "v-clip"; - -}
\ No newline at end of file diff --git a/src/com/vaadin/ui/themes/ChameleonTheme.java b/src/com/vaadin/ui/themes/ChameleonTheme.java deleted file mode 100644 index 5ae8cd4e57..0000000000 --- a/src/com/vaadin/ui/themes/ChameleonTheme.java +++ /dev/null @@ -1,365 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui.themes; - -public class ChameleonTheme extends BaseTheme { - - public static final String THEME_NAME = "chameleon"; - - /*************************************************************************** - * Label styles - **************************************************************************/ - - /** - * Large font for main application headings - */ - public static final String LABEL_H1 = "h1"; - - /** - * Large font for different sections in the application - */ - public static final String LABEL_H2 = "h2"; - - /** - * Font for sub-section headers - */ - public static final String LABEL_H3 = "h3"; - - /** - * Font for paragraphs headers - */ - public static final String LABEL_H4 = "h4"; - - /** - * Big font for important or emphasized texts - */ - public static final String LABEL_BIG = "big"; - - /** - * Small and a little lighter font - */ - public static final String LABEL_SMALL = "small"; - - /** - * Very small and lighter font for things such as footnotes and component - * specific informations. Use carefully, since this style will usually - * reduce legibility. - */ - public static final String LABEL_TINY = "tiny"; - - /** - * Adds color to the text (usually the alternate color of the theme) - */ - public static final String LABEL_COLOR = "color"; - - /** - * Adds a warning icon on the left side and a yellow background to the label - */ - public static final String LABEL_WARNING = "warning"; - - /** - * Adds an error icon on the left side and a red background to the label - */ - public static final String LABEL_ERROR = "error"; - - /** - * Adds a spinner icon on the left side of the label - */ - public static final String LABEL_LOADING = "loading"; - - /*************************************************************************** - * Button styles - **************************************************************************/ - - /** - * Default action style for buttons (the button that gets activated when - * user presses 'enter' in a form). Use sparingly, only one default button - * per screen should be visible. - */ - public static final String BUTTON_DEFAULT = "default"; - - /** - * Small sized button, use for context specific actions for example - */ - public static final String BUTTON_SMALL = "small"; - - /** - * Big button, use to get more attention for the button action - */ - public static final String BUTTON_BIG = "big"; - - /** - * Adds more padding on the sides of the button. Makes it easier for the - * user to hit the button. - */ - public static final String BUTTON_WIDE = "wide"; - - /** - * Adds more padding on the top and on the bottom of the button. Makes it - * easier for the user to hit the button. - */ - public static final String BUTTON_TALL = "tall"; - - /** - * Removes all graphics from the button, leaving only the caption and the - * icon visible. Useful for making icon-only buttons and toolbar buttons. - */ - public static final String BUTTON_BORDERLESS = "borderless"; - - /** - * Places the button icon on top of the caption. By default the icon is on - * the left side of the button caption. - */ - public static final String BUTTON_ICON_ON_TOP = "icon-on-top"; - - /** - * Places the button icon on the right side of the caption. By default the - * icon is on the left side of the button caption. - */ - public static final String BUTTON_ICON_ON_RIGHT = "icon-on-right"; - - /** - * Removes the button caption and only shows its icon - */ - public static final String BUTTON_ICON_ONLY = "icon-only"; - - /** - * Makes the button look like it is pressed down. Useful for creating a - * toggle button. - */ - public static final String BUTTON_DOWN = "down"; - - /*************************************************************************** - * TextField styles - **************************************************************************/ - - /** - * Small sized text field with small font - */ - public static final String TEXTFIELD_SMALL = "small"; - - /** - * Large sized text field with big font - */ - public static final String TEXTFIELD_BIG = "big"; - - /** - * Adds a magnifier icon on the left side of the fields text - */ - public static final String TEXTFIELD_SEARCH = "search"; - - /*************************************************************************** - * Select styles - **************************************************************************/ - - /** - * Small sized select with small font - */ - public static final String SELECT_SMALL = "small"; - - /** - * Large sized select with big font - */ - public static final String SELECT_BIG = "big"; - - /** - * Adds a magnifier icon on the left side of the fields text - */ - public static final String COMBOBOX_SEARCH = "search"; - - /** - * Adds a magnifier icon on the left side of the fields text - */ - public static final String COMBOBOX_SELECT_BUTTON = "select-button"; - - /*************************************************************************** - * DateField styles - **************************************************************************/ - - /** - * Small sized date field with small font - */ - public static final String DATEFIELD_SMALL = "small"; - - /** - * Large sized date field with big font - */ - public static final String DATEFIELD_BIG = "big"; - - /*************************************************************************** - * Panel styles - **************************************************************************/ - - /** - * Removes borders and background color from the panel - */ - public static final String PANEL_BORDERLESS = "borderless"; - - /** - * Adds a more vibrant header for the panel, using the alternate color of - * the theme, and adds slight rounded corners (not supported in all - * browsers) - */ - public static final String PANEL_BUBBLE = "bubble"; - - /** - * Removes borders and background color from the panel - */ - public static final String PANEL_LIGHT = "light"; - - /*************************************************************************** - * SplitPanel styles - **************************************************************************/ - - /** - * Reduces the split handle to a minimal size (1 pixel) - */ - public static final String SPLITPANEL_SMALL = "small"; - - /*************************************************************************** - * TabSheet styles - **************************************************************************/ - - /** - * Removes borders and background color from the tab sheet - */ - public static final String TABSHEET_BORDERLESS = "borderless"; - - /*************************************************************************** - * Accordion styles - **************************************************************************/ - - /** - * Makes the accordion background opaque (non-transparent) - */ - public static final String ACCORDION_OPAQUE = "opaque"; - - /*************************************************************************** - * Table styles - **************************************************************************/ - - /** - * Removes borders and background color from the table - */ - public static final String TABLE_BORDERLESS = "borderless"; - - /** - * Makes the column header and content font size smaller inside the table - */ - public static final String TABLE_SMALL = "small"; - - /** - * Makes the column header and content font size bigger inside the table - */ - public static final String TABLE_BIG = "big"; - - /** - * Adds a light alternate background color to even rows in the table. - */ - public static final String TABLE_STRIPED = "striped"; - - /*************************************************************************** - * ProgressIndicator styles - **************************************************************************/ - - /** - * Reduces the height of the progress bar - */ - public static final String PROGRESS_INDICATOR_SMALL = "small"; - - /** - * Increases the height of the progress bar. If the indicator is in - * indeterminate mode, shows a bigger spinner than the regular indeterminate - * indicator. - */ - public static final String PROGRESS_INDICATOR_BIG = "big"; - - /** - * Displays an indeterminate progress indicator as a bar with animated - * background stripes. This style can be used in combination with the - * "small" and "big" styles. - */ - public static final String PROGRESS_INDICATOR_INDETERMINATE_BAR = "bar"; - - /*************************************************************************** - * Window styles - **************************************************************************/ - - /** - * Sub-window style that makes the window background opaque (i.e. not - * semi-transparent). - */ - public static final String WINDOW_OPAQUE = "opaque"; - - /*************************************************************************** - * Compound styles - **************************************************************************/ - - /** - * Creates a context for a segment button control. Place buttons inside the - * segment, and add "<code>first</code>" and "<code>last</code>" style names - * for the first and last button in the segment. Then use the - * {@link #BUTTON_DOWN} style to indicate button states. - * - * E.g. - * - * <pre> - * HorizontalLayout ("segment") - * + Button ("first down") - * + Button ("down") - * + Button - * ... - * + Button ("last") - * </pre> - * - * You can also use most of the different button styles for the contained - * buttons (e.g. {@link #BUTTON_BIG}, {@link #BUTTON_ICON_ONLY} etc.). - */ - public static final String COMPOUND_HORIZONTAL_LAYOUT_SEGMENT = "segment"; - - /** - * Use this mixin-style in combination with the - * {@link #COMPOUND_HORIZONTAL_LAYOUT_SEGMENT} style to make buttons with - * the "down" style use the themes alternate color (e.g. blue instead of - * gray). - * - * E.g. - * - * <pre> - * HorizontalLayout ("segment segment-alternate") - * + Button ("first down") - * + Button ("down") - * + Button - * ... - * + Button ("last") - * </pre> - */ - public static final String COMPOUND_HORIZONTAL_LAYOUT_SEGMENT_ALTERNATE = "segment-alternate"; - - /** - * Creates an iTunes-like menu from a CssLayout or a VerticalLayout. Place - * plain Labels and NativeButtons inside the layout, and you're all set. - * - * E.g. - * - * <pre> - * CssLayout ("sidebar-menu") - * + Label - * + NativeButton - * + NativeButton - * ... - * + Label - * + NativeButton - * </pre> - */ - public static final String COMPOUND_LAYOUT_SIDEBAR_MENU = "sidebar-menu"; - - /** - * Adds a toolbar-like background for the layout, and aligns Buttons and - * Segments horizontally. Feel free to use different buttons styles inside - * the toolbar, like {@link #BUTTON_ICON_ON_TOP} and - * {@link #BUTTON_BORDERLESS} - */ - public static final String COMPOUND_CSSLAYOUT_TOOLBAR = "toolbar"; -} diff --git a/src/com/vaadin/ui/themes/LiferayTheme.java b/src/com/vaadin/ui/themes/LiferayTheme.java deleted file mode 100644 index 9b48306ac2..0000000000 --- a/src/com/vaadin/ui/themes/LiferayTheme.java +++ /dev/null @@ -1,31 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui.themes; - -public class LiferayTheme extends BaseTheme { - - public static final String THEME_NAME = "liferay"; - - /*************************************************************************** - * - * Panel styles - * - **************************************************************************/ - - /** - * Removes borders and background from the panel - */ - public static final String PANEL_LIGHT = "light"; - - /*************************************************************************** - * - * SplitPanel styles - * - **************************************************************************/ - - /** - * Reduces the split handle to a minimal size (1 pixel) - */ - public static final String SPLITPANEL_SMALL = "small"; -} diff --git a/src/com/vaadin/ui/themes/Reindeer.java b/src/com/vaadin/ui/themes/Reindeer.java deleted file mode 100644 index 7aaae8faa2..0000000000 --- a/src/com/vaadin/ui/themes/Reindeer.java +++ /dev/null @@ -1,217 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui.themes; - -import com.vaadin.ui.CssLayout; -import com.vaadin.ui.FormLayout; -import com.vaadin.ui.GridLayout; -import com.vaadin.ui.HorizontalLayout; -import com.vaadin.ui.HorizontalSplitPanel; -import com.vaadin.ui.VerticalLayout; -import com.vaadin.ui.VerticalSplitPanel; - -public class Reindeer extends BaseTheme { - - public static final String THEME_NAME = "reindeer"; - - /*************************************************************************** - * - * Label styles - * - **************************************************************************/ - - /** - * Large font for main application headings - */ - public static final String LABEL_H1 = "h1"; - - /** - * Large font for different sections in the application - */ - public static final String LABEL_H2 = "h2"; - - /** - * Small and a little lighter font - */ - public static final String LABEL_SMALL = "light"; - - /** - * @deprecated Use {@link #LABEL_SMALL} instead. - */ - @Deprecated - public static final String LABEL_LIGHT = "small"; - - /*************************************************************************** - * - * Button styles - * - **************************************************************************/ - - /** - * Default action style for buttons (the button that should get activated - * when the user presses 'enter' in a form). Use sparingly, only one default - * button per view should be visible. - */ - public static final String BUTTON_DEFAULT = "primary"; - - /** - * @deprecated Use {@link #BUTTON_DEFAULT} instead - */ - @Deprecated - public static final String BUTTON_PRIMARY = BUTTON_DEFAULT; - - /** - * Small sized button, use for context specific actions for example - */ - public static final String BUTTON_SMALL = "small"; - - /*************************************************************************** - * - * TextField styles - * - **************************************************************************/ - - /** - * Small sized text field with small font - */ - public static final String TEXTFIELD_SMALL = "small"; - - /*************************************************************************** - * - * Panel styles - * - **************************************************************************/ - - /** - * Removes borders and background color from the panel - */ - public static final String PANEL_LIGHT = "light"; - - /*************************************************************************** - * - * SplitPanel styles - * - **************************************************************************/ - - /** - * Reduces the split handle to a minimal size (1 pixel) - */ - public static final String SPLITPANEL_SMALL = "small"; - - /*************************************************************************** - * - * TabSheet styles - * - **************************************************************************/ - - /** - * Removes borders from the default tab sheet style. - */ - public static final String TABSHEET_BORDERLESS = "borderless"; - - /** - * Removes borders and background color from the tab sheet, and shows the - * tabs as a small bar. - */ - public static final String TABSHEET_SMALL = "bar"; - - /** - * @deprecated Use {@link #TABSHEET_SMALL} instead. - */ - @Deprecated - public static final String TABSHEET_BAR = TABSHEET_SMALL; - - /** - * Removes borders and background color from the tab sheet. The tabs are - * presented with minimal lines indicating the selected tab. - */ - public static final String TABSHEET_MINIMAL = "minimal"; - - /** - * Makes the tab close buttons visible only when the user is hovering over - * the tab. - */ - public static final String TABSHEET_HOVER_CLOSABLE = "hover-closable"; - - /** - * Makes the tab close buttons visible only when the tab is selected. - */ - public static final String TABSHEET_SELECTED_CLOSABLE = "selected-closable"; - - /*************************************************************************** - * - * Table styles - * - **************************************************************************/ - - /** - * Removes borders from the table - */ - public static final String TABLE_BORDERLESS = "borderless"; - - /** - * Makes the table headers dark and more prominent. - */ - public static final String TABLE_STRONG = "strong"; - - /*************************************************************************** - * - * Layout styles - * - **************************************************************************/ - - /** - * Changes the background of a layout to white. Applies to - * {@link VerticalLayout}, {@link HorizontalLayout}, {@link GridLayout}, - * {@link FormLayout}, {@link CssLayout}, {@link VerticalSplitPanel} and - * {@link HorizontalSplitPanel}. - * <p> - * <em>Does not revert any contained components back to normal if some - * parent layout has style {@link #LAYOUT_BLACK} applied.</em> - */ - public static final String LAYOUT_WHITE = "white"; - - /** - * Changes the background of a layout to a shade of blue. Applies to - * {@link VerticalLayout}, {@link HorizontalLayout}, {@link GridLayout}, - * {@link FormLayout}, {@link CssLayout}, {@link VerticalSplitPanel} and - * {@link HorizontalSplitPanel}. - * <p> - * <em>Does not revert any contained components back to normal if some - * parent layout has style {@link #LAYOUT_BLACK} applied.</em> - */ - public static final String LAYOUT_BLUE = "blue"; - - /** - * <p> - * Changes the background of a layout to almost black, and at the same time - * transforms contained components to their black style correspondents when - * available. At least texts, buttons, text fields, selects, date fields, - * tables and a few other component styles should change. - * </p> - * <p> - * Applies to {@link VerticalLayout}, {@link HorizontalLayout}, - * {@link GridLayout}, {@link FormLayout} and {@link CssLayout}. - * </p> - * - */ - public static final String LAYOUT_BLACK = "black"; - - /*************************************************************************** - * - * Window styles - * - **************************************************************************/ - - /** - * Makes the whole window white and increases the font size of the title. - */ - public static final String WINDOW_LIGHT = "light"; - - /** - * Makes the whole window black, and changes contained components in the - * same way as {@link #LAYOUT_BLACK} does. - */ - public static final String WINDOW_BLACK = "black"; -} diff --git a/src/com/vaadin/ui/themes/Runo.java b/src/com/vaadin/ui/themes/Runo.java deleted file mode 100644 index 28a19e8dcd..0000000000 --- a/src/com/vaadin/ui/themes/Runo.java +++ /dev/null @@ -1,183 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.ui.themes; - -public class Runo extends BaseTheme { - - public static final String THEME_NAME = "runo"; - - public static String themeName() { - return THEME_NAME.toLowerCase(); - } - - /*************************************************************************** - * - * Button styles - * - **************************************************************************/ - - /** - * Small sized button, use for context specific actions for example - */ - public static final String BUTTON_SMALL = "small"; - - /** - * Big sized button, use to gather much attention for some particular action - */ - public static final String BUTTON_BIG = "big"; - - /** - * Default action style for buttons (the button that should get activated - * when the user presses 'enter' in a form). Use sparingly, only one default - * button per view should be visible. - */ - public static final String BUTTON_DEFAULT = "default"; - - /*************************************************************************** - * - * Panel styles - * - **************************************************************************/ - - /** - * Removes borders and background color from the panel - */ - public static final String PANEL_LIGHT = "light"; - - /*************************************************************************** - * - * TabSheet styles - * - **************************************************************************/ - - /** - * Smaller tabs, no border and background for content area - */ - public static final String TABSHEET_SMALL = "light"; - - /*************************************************************************** - * - * SplitPanel styles - * - **************************************************************************/ - - /** - * Reduces the width/height of the split handle. Useful when you don't want - * the split handle to touch the sides of the containing layout. - */ - public static final String SPLITPANEL_REDUCED = "rounded"; - - /** - * Reduces the visual size of the split handle to one pixel (the active drag - * size is still larger). - */ - public static final String SPLITPANEL_SMALL = "small"; - - /*************************************************************************** - * - * Label styles - * - **************************************************************************/ - - /** - * Largest title/header size. Use for main sections in your application. - */ - public static final String LABEL_H1 = "h1"; - - /** - * Similar style as in panel captions. Useful for sub-sections within a - * view. - */ - public static final String LABEL_H2 = "h2"; - - /** - * Small font size. Useful for contextual help texts and similar less - * frequently needed information. Use with modesty, since this style will be - * more harder to read due to its smaller size and contrast. - */ - public static final String LABEL_SMALL = "small"; - - /*************************************************************************** - * - * Layout styles - * - **************************************************************************/ - - /** - * An alternative background color for layouts. Use on top of white - * background (e.g. inside Panels, TabSheets and sub-windows). - */ - public static final String LAYOUT_DARKER = "darker"; - - /** - * Add a drop shadow around the layout and its contained components. - * Produces a rectangular shadow, even if the contained component would have - * a different shape. - * <p> - * Note: does not work in Internet Explorer 6 - */ - public static final String CSSLAYOUT_SHADOW = "box-shadow"; - - /** - * Adds necessary styles to the layout to make it look selectable (i.e. - * clickable). Add a click listener for the layout, and toggle the - * {@link #CSSLAYOUT_SELECTABLE_SELECTED} style for the same layout to make - * it look selected or not. - */ - public static final String CSSLAYOUT_SELECTABLE = "selectable"; - public static final String CSSLAYOUT_SELECTABLE_SELECTED = "selectable-selected"; - - /*************************************************************************** - * - * TextField styles - * - **************************************************************************/ - - /** - * Small sized text field with small font - */ - public static final String TEXTFIELD_SMALL = "small"; - - /*************************************************************************** - * - * Table styles - * - **************************************************************************/ - - /** - * Smaller header and item fonts. - */ - public static final String TABLE_SMALL = "small"; - - /** - * Removes the border and background color from the table. Removes - * alternating row background colors as well. - */ - public static final String TABLE_BORDERLESS = "borderless"; - - /*************************************************************************** - * - * Accordion styles - * - **************************************************************************/ - - /** - * A detached looking accordion, providing space around its captions and - * content. Doesn't necessarily need a Panel or other container to wrap it - * in order to make it look right. - */ - public static final String ACCORDION_LIGHT = "light"; - - /*************************************************************************** - * - * Window styles - * - **************************************************************************/ - - /** - * Smaller header and a darker background color for the window. Useful for - * smaller dialog-like windows. - */ - public static final String WINDOW_DIALOG = "dialog"; -} diff --git a/src/com/vaadin/util/SerializerHelper.java b/src/com/vaadin/util/SerializerHelper.java deleted file mode 100644 index 5b7b388dd6..0000000000 --- a/src/com/vaadin/util/SerializerHelper.java +++ /dev/null @@ -1,145 +0,0 @@ -/* -@VaadinApache2LicenseForJavaFiles@ - */ -package com.vaadin.util; - -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -/** - * Helper class for performing serialization. Most of the methods are here are - * workarounds for problems in Google App Engine. Used internally by Vaadin and - * should not be used by application developers. Subject to change at any time. - * - * @since 6.0 - */ -public class SerializerHelper { - - /** - * Serializes the class reference so {@link #readClass(ObjectInputStream)} - * can deserialize it. Supports null class references. - * - * @param out - * The {@link ObjectOutputStream} to serialize to. - * @param cls - * A class or null. - * @throws IOException - * Rethrows any IOExceptions from the ObjectOutputStream - */ - public static void writeClass(ObjectOutputStream out, Class<?> cls) - throws IOException { - if (cls == null) { - out.writeObject(null); - } else { - out.writeObject(cls.getName()); - } - - } - - /** - * Serializes the class references so - * {@link #readClassArray(ObjectInputStream)} can deserialize it. Supports - * null class arrays. - * - * @param out - * The {@link ObjectOutputStream} to serialize to. - * @param classes - * An array containing class references or null. - * @throws IOException - * Rethrows any IOExceptions from the ObjectOutputStream - */ - public static void writeClassArray(ObjectOutputStream out, - Class<?>[] classes) throws IOException { - if (classes == null) { - out.writeObject(null); - } else { - String[] classNames = new String[classes.length]; - for (int i = 0; i < classes.length; i++) { - classNames[i] = classes[i].getName(); - } - out.writeObject(classNames); - } - } - - /** - * Deserializes a class references serialized by - * {@link #writeClassArray(ObjectOutputStream, Class[])}. Supports null - * class arrays. - * - * @param in - * {@link ObjectInputStream} to read from. - * @return Class array with the class references or null. - * @throws ClassNotFoundException - * If one of the classes could not be resolved. - * @throws IOException - * Rethrows IOExceptions from the ObjectInputStream - */ - public static Class<?>[] readClassArray(ObjectInputStream in) - throws ClassNotFoundException, IOException { - String[] classNames = (String[]) in.readObject(); - if (classNames == null) { - return null; - } - Class<?>[] classes = new Class<?>[classNames.length]; - for (int i = 0; i < classNames.length; i++) { - classes[i] = resolveClass(classNames[i]); - } - - return classes; - } - - /** - * List of primitive classes. Google App Engine has problems - * serializing/deserializing these (#3064). - */ - private static Class<?>[] primitiveClasses = new Class<?>[] { byte.class, - short.class, int.class, long.class, float.class, double.class, - boolean.class, char.class }; - - /** - * Resolves the class given by {@code className}. - * - * @param className - * The fully qualified class name. - * @return A {@code Class} reference. - * @throws ClassNotFoundException - * If the class could not be resolved. - */ - public static Class<?> resolveClass(String className) - throws ClassNotFoundException { - for (Class<?> c : primitiveClasses) { - if (className.equals(c.getName())) { - return c; - } - } - - return Class.forName(className); - } - - /** - * Deserializes a class reference serialized by - * {@link #writeClass(ObjectOutputStream, Class)}. Supports null class - * references. - * - * @param in - * {@code ObjectInputStream} to read from. - * @return Class reference to the resolved class - * @throws ClassNotFoundException - * If the class could not be resolved. - * @throws IOException - * Rethrows IOExceptions from the ObjectInputStream - */ - public static Class<?> readClass(ObjectInputStream in) throws IOException, - ClassNotFoundException { - String className = (String) in.readObject(); - if (className == null) { - return null; - } else { - return resolveClass(className); - - } - - } - -} diff --git a/src/org/jsoup/Connection.java b/src/org/jsoup/Connection.java deleted file mode 100644 index 564eeb89b7..0000000000 --- a/src/org/jsoup/Connection.java +++ /dev/null @@ -1,481 +0,0 @@ -package org.jsoup; - -import org.jsoup.nodes.Document; -import org.jsoup.parser.Parser; - -import java.net.URL; -import java.util.Map; -import java.util.Collection; -import java.io.IOException; - -/** - * A Connection provides a convenient interface to fetch content from the web, and parse them into Documents. - * <p> - * To get a new Connection, use {@link org.jsoup.Jsoup#connect(String)}. Connections contain {@link Connection.Request} - * and {@link Connection.Response} objects. The request objects are reusable as prototype requests. - * <p> - * Request configuration can be made using either the shortcut methods in Connection (e.g. {@link #userAgent(String)}), - * or by methods in the Connection.Request object directly. All request configuration must be made before the request - * is executed. - * <p> - * The Connection interface is <b>currently in beta</b> and subject to change. Comments, suggestions, and bug reports are welcome. - */ -public interface Connection { - - /** - * GET and POST http methods. - */ - public enum Method { - GET, POST - } - - /** - * Set the request URL to fetch. The protocol must be HTTP or HTTPS. - * @param url URL to connect to - * @return this Connection, for chaining - */ - public Connection url(URL url); - - /** - * Set the request URL to fetch. The protocol must be HTTP or HTTPS. - * @param url URL to connect to - * @return this Connection, for chaining - */ - public Connection url(String url); - - /** - * Set the request user-agent header. - * @param userAgent user-agent to use - * @return this Connection, for chaining - */ - public Connection userAgent(String userAgent); - - /** - * Set the request timeouts (connect and read). If a timeout occurs, an IOException will be thrown. The default - * timeout is 3 seconds (3000 millis). A timeout of zero is treated as an infinite timeout. - * @param millis number of milliseconds (thousandths of a second) before timing out connects or reads. - * @return this Connection, for chaining - */ - public Connection timeout(int millis); - - /** - * Set the request referrer (aka "referer") header. - * @param referrer referrer to use - * @return this Connection, for chaining - */ - public Connection referrer(String referrer); - - /** - * Configures the connection to (not) follow server redirects. By default this is <b>true</b>. - * @param followRedirects true if server redirects should be followed. - * @return this Connection, for chaining - */ - public Connection followRedirects(boolean followRedirects); - - /** - * Set the request method to use, GET or POST. Default is GET. - * @param method HTTP request method - * @return this Connection, for chaining - */ - public Connection method(Method method); - - /** - * Configures the connection to not throw exceptions when a HTTP error occurs. (4xx - 5xx, e.g. 404 or 500). By - * default this is <b>false</b>; an IOException is thrown if an error is encountered. If set to <b>true</b>, the - * response is populated with the error body, and the status message will reflect the error. - * @param ignoreHttpErrors - false (default) if HTTP errors should be ignored. - * @return this Connection, for chaining - */ - public Connection ignoreHttpErrors(boolean ignoreHttpErrors); - - /** - * Ignore the document's Content-Type when parsing the response. By default this is <b>false</b>, an unrecognised - * content-type will cause an IOException to be thrown. (This is to prevent producing garbage by attempting to parse - * a JPEG binary image, for example.) Set to true to force a parse attempt regardless of content type. - * @param ignoreContentType set to true if you would like the content type ignored on parsing the response into a - * Document. - * @return this Connection, for chaining - */ - public Connection ignoreContentType(boolean ignoreContentType); - - /** - * Add a request data parameter. Request parameters are sent in the request query string for GETs, and in the request - * body for POSTs. A request may have multiple values of the same name. - * @param key data key - * @param value data value - * @return this Connection, for chaining - */ - public Connection data(String key, String value); - - /** - * Adds all of the supplied data to the request data parameters - * @param data map of data parameters - * @return this Connection, for chaining - */ - public Connection data(Map<String, String> data); - - /** - * Add a number of request data parameters. Multiple parameters may be set at once, e.g.: - * <code>.data("name", "jsoup", "language", "Java", "language", "English");</code> creates a query string like: - * <code>?name=jsoup&language=Java&language=English</code> - * @param keyvals a set of key value pairs. - * @return this Connection, for chaining - */ - public Connection data(String... keyvals); - - /** - * Set a request header. - * @param name header name - * @param value header value - * @return this Connection, for chaining - * @see org.jsoup.Connection.Request#headers() - */ - public Connection header(String name, String value); - - /** - * Set a cookie to be sent in the request. - * @param name name of cookie - * @param value value of cookie - * @return this Connection, for chaining - */ - public Connection cookie(String name, String value); - - /** - * Adds each of the supplied cookies to the request. - * @param cookies map of cookie name -> value pairs - * @return this Connection, for chaining - */ - public Connection cookies(Map<String, String> cookies); - - /** - * Provide an alternate parser to use when parsing the response to a Document. - * @param parser alternate parser - * @return this Connection, for chaining - */ - public Connection parser(Parser parser); - - /** - * Execute the request as a GET, and parse the result. - * @return parsed Document - * @throws IOException on error - */ - public Document get() throws IOException; - - /** - * Execute the request as a POST, and parse the result. - * @return parsed Document - * @throws IOException on error - */ - public Document post() throws IOException; - - /** - * Execute the request. - * @return a response object - * @throws IOException on error - */ - public Response execute() throws IOException; - - /** - * Get the request object associated with this connection - * @return request - */ - public Request request(); - - /** - * Set the connection's request - * @param request new request object - * @return this Connection, for chaining - */ - public Connection request(Request request); - - /** - * Get the response, once the request has been executed - * @return response - */ - public Response response(); - - /** - * Set the connection's response - * @param response new response - * @return this Connection, for chaining - */ - public Connection response(Response response); - - - /** - * Common methods for Requests and Responses - * @param <T> Type of Base, either Request or Response - */ - interface Base<T extends Base> { - - /** - * Get the URL - * @return URL - */ - public URL url(); - - /** - * Set the URL - * @param url new URL - * @return this, for chaining - */ - public T url(URL url); - - /** - * Get the request method - * @return method - */ - public Method method(); - - /** - * Set the request method - * @param method new method - * @return this, for chaining - */ - public T method(Method method); - - /** - * Get the value of a header. This is a simplified header model, where a header may only have one value. - * <p> - * Header names are case insensitive. - * @param name name of header (case insensitive) - * @return value of header, or null if not set. - * @see #hasHeader(String) - * @see #cookie(String) - */ - public String header(String name); - - /** - * Set a header. This method will overwrite any existing header with the same case insensitive name. - * @param name Name of header - * @param value Value of header - * @return this, for chaining - */ - public T header(String name, String value); - - /** - * Check if a header is present - * @param name name of header (case insensitive) - * @return if the header is present in this request/response - */ - public boolean hasHeader(String name); - - /** - * Remove a header by name - * @param name name of header to remove (case insensitive) - * @return this, for chaining - */ - public T removeHeader(String name); - - /** - * Retrieve all of the request/response headers as a map - * @return headers - */ - public Map<String, String> headers(); - - /** - * Get a cookie value by name from this request/response. - * <p> - * Response objects have a simplified cookie model. Each cookie set in the response is added to the response - * object's cookie key=value map. The cookie's path, domain, and expiry date are ignored. - * @param name name of cookie to retrieve. - * @return value of cookie, or null if not set - */ - public String cookie(String name); - - /** - * Set a cookie in this request/response. - * @param name name of cookie - * @param value value of cookie - * @return this, for chaining - */ - public T cookie(String name, String value); - - /** - * Check if a cookie is present - * @param name name of cookie - * @return if the cookie is present in this request/response - */ - public boolean hasCookie(String name); - - /** - * Remove a cookie by name - * @param name name of cookie to remove - * @return this, for chaining - */ - public T removeCookie(String name); - - /** - * Retrieve all of the request/response cookies as a map - * @return cookies - */ - public Map<String, String> cookies(); - - } - - /** - * Represents a HTTP request. - */ - public interface Request extends Base<Request> { - /** - * Get the request timeout, in milliseconds. - * @return the timeout in milliseconds. - */ - public int timeout(); - - /** - * Update the request timeout. - * @param millis timeout, in milliseconds - * @return this Request, for chaining - */ - public Request timeout(int millis); - - /** - * Get the current followRedirects configuration. - * @return true if followRedirects is enabled. - */ - public boolean followRedirects(); - - /** - * Configures the request to (not) follow server redirects. By default this is <b>true</b>. - * - * @param followRedirects true if server redirects should be followed. - * @return this Request, for chaining - */ - public Request followRedirects(boolean followRedirects); - - /** - * Get the current ignoreHttpErrors configuration. - * @return true if errors will be ignored; false (default) if HTTP errors will cause an IOException to be thrown. - */ - public boolean ignoreHttpErrors(); - - /** - * Configures the request to ignore HTTP errors in the response. - * @param ignoreHttpErrors set to true to ignore HTTP errors. - * @return this Request, for chaining - */ - public Request ignoreHttpErrors(boolean ignoreHttpErrors); - - /** - * Get the current ignoreContentType configuration. - * @return true if invalid content-types will be ignored; false (default) if they will cause an IOException to be thrown. - */ - public boolean ignoreContentType(); - - /** - * Configures the request to ignore the Content-Type of the response. - * @param ignoreContentType set to true to ignore the content type. - * @return this Request, for chaining - */ - public Request ignoreContentType(boolean ignoreContentType); - - /** - * Add a data parameter to the request - * @param keyval data to add. - * @return this Request, for chaining - */ - public Request data(KeyVal keyval); - - /** - * Get all of the request's data parameters - * @return collection of keyvals - */ - public Collection<KeyVal> data(); - - /** - * Specify the parser to use when parsing the document. - * @param parser parser to use. - * @return this Request, for chaining - */ - public Request parser(Parser parser); - - /** - * Get the current parser to use when parsing the document. - * @return current Parser - */ - public Parser parser(); - } - - /** - * Represents a HTTP response. - */ - public interface Response extends Base<Response> { - - /** - * Get the status code of the response. - * @return status code - */ - public int statusCode(); - - /** - * Get the status message of the response. - * @return status message - */ - public String statusMessage(); - - /** - * Get the character set name of the response. - * @return character set name - */ - public String charset(); - - /** - * Get the response content type (e.g. "text/html"); - * @return the response content type - */ - public String contentType(); - - /** - * Parse the body of the response as a Document. - * @return a parsed Document - * @throws IOException on error - */ - public Document parse() throws IOException; - - /** - * Get the body of the response as a plain string. - * @return body - */ - public String body(); - - /** - * Get the body of the response as an array of bytes. - * @return body bytes - */ - public byte[] bodyAsBytes(); - } - - /** - * A Key Value tuple. - */ - public interface KeyVal { - - /** - * Update the key of a keyval - * @param key new key - * @return this KeyVal, for chaining - */ - public KeyVal key(String key); - - /** - * Get the key of a keyval - * @return the key - */ - public String key(); - - /** - * Update the value of a keyval - * @param value the new value - * @return this KeyVal, for chaining - */ - public KeyVal value(String value); - - /** - * Get the value of a keyval - * @return the value - */ - public String value(); - } -} - diff --git a/src/org/jsoup/Jsoup.java b/src/org/jsoup/Jsoup.java deleted file mode 100644 index 8c6afcee36..0000000000 --- a/src/org/jsoup/Jsoup.java +++ /dev/null @@ -1,229 +0,0 @@ -package org.jsoup; - -import org.jsoup.nodes.Document; -import org.jsoup.parser.Parser; -import org.jsoup.safety.Cleaner; -import org.jsoup.safety.Whitelist; -import org.jsoup.helper.DataUtil; -import org.jsoup.helper.HttpConnection; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; - -/** - The core public access point to the jsoup functionality. - - @author Jonathan Hedley */ -public class Jsoup { - private Jsoup() {} - - /** - Parse HTML into a Document. The parser will make a sensible, balanced document tree out of any HTML. - - @param html HTML to parse - @param baseUri The URL where the HTML was retrieved from. Used to resolve relative URLs to absolute URLs, that occur - before the HTML declares a {@code <base href>} tag. - @return sane HTML - */ - public static Document parse(String html, String baseUri) { - return Parser.parse(html, baseUri); - } - - /** - Parse HTML into a Document, using the provided Parser. You can provide an alternate parser, such as a simple XML - (non-HTML) parser. - - @param html HTML to parse - @param baseUri The URL where the HTML was retrieved from. Used to resolve relative URLs to absolute URLs, that occur - before the HTML declares a {@code <base href>} tag. - @param parser alternate {@link Parser#xmlParser() parser} to use. - @return sane HTML - */ - public static Document parse(String html, String baseUri, Parser parser) { - return parser.parseInput(html, baseUri); - } - - /** - Parse HTML into a Document. As no base URI is specified, absolute URL detection relies on the HTML including a - {@code <base href>} tag. - - @param html HTML to parse - @return sane HTML - - @see #parse(String, String) - */ - public static Document parse(String html) { - return Parser.parse(html, ""); - } - - /** - * Creates a new {@link Connection} to a URL. Use to fetch and parse a HTML page. - * <p> - * Use examples: - * <ul> - * <li><code>Document doc = Jsoup.connect("http://example.com").userAgent("Mozilla").data("name", "jsoup").get();</code></li> - * <li><code>Document doc = Jsoup.connect("http://example.com").cookie("auth", "token").post(); - * </ul> - * @param url URL to connect to. The protocol must be {@code http} or {@code https}. - * @return the connection. You can add data, cookies, and headers; set the user-agent, referrer, method; and then execute. - */ - public static Connection connect(String url) { - return HttpConnection.connect(url); - } - - /** - Parse the contents of a file as HTML. - - @param in file to load HTML from - @param charsetName (optional) character set of file contents. Set to {@code null} to determine from {@code http-equiv} meta tag, if - present, or fall back to {@code UTF-8} (which is often safe to do). - @param baseUri The URL where the HTML was retrieved from, to resolve relative links against. - @return sane HTML - - @throws IOException if the file could not be found, or read, or if the charsetName is invalid. - */ - public static Document parse(File in, String charsetName, String baseUri) throws IOException { - return DataUtil.load(in, charsetName, baseUri); - } - - /** - Parse the contents of a file as HTML. The location of the file is used as the base URI to qualify relative URLs. - - @param in file to load HTML from - @param charsetName (optional) character set of file contents. Set to {@code null} to determine from {@code http-equiv} meta tag, if - present, or fall back to {@code UTF-8} (which is often safe to do). - @return sane HTML - - @throws IOException if the file could not be found, or read, or if the charsetName is invalid. - @see #parse(File, String, String) - */ - public static Document parse(File in, String charsetName) throws IOException { - return DataUtil.load(in, charsetName, in.getAbsolutePath()); - } - - /** - Read an input stream, and parse it to a Document. - - @param in input stream to read. Make sure to close it after parsing. - @param charsetName (optional) character set of file contents. Set to {@code null} to determine from {@code http-equiv} meta tag, if - present, or fall back to {@code UTF-8} (which is often safe to do). - @param baseUri The URL where the HTML was retrieved from, to resolve relative links against. - @return sane HTML - - @throws IOException if the file could not be found, or read, or if the charsetName is invalid. - */ - public static Document parse(InputStream in, String charsetName, String baseUri) throws IOException { - return DataUtil.load(in, charsetName, baseUri); - } - - /** - Read an input stream, and parse it to a Document. You can provide an alternate parser, such as a simple XML - (non-HTML) parser. - - @param in input stream to read. Make sure to close it after parsing. - @param charsetName (optional) character set of file contents. Set to {@code null} to determine from {@code http-equiv} meta tag, if - present, or fall back to {@code UTF-8} (which is often safe to do). - @param baseUri The URL where the HTML was retrieved from, to resolve relative links against. - @param parser alternate {@link Parser#xmlParser() parser} to use. - @return sane HTML - - @throws IOException if the file could not be found, or read, or if the charsetName is invalid. - */ - public static Document parse(InputStream in, String charsetName, String baseUri, Parser parser) throws IOException { - return DataUtil.load(in, charsetName, baseUri, parser); - } - - /** - Parse a fragment of HTML, with the assumption that it forms the {@code body} of the HTML. - - @param bodyHtml body HTML fragment - @param baseUri URL to resolve relative URLs against. - @return sane HTML document - - @see Document#body() - */ - public static Document parseBodyFragment(String bodyHtml, String baseUri) { - return Parser.parseBodyFragment(bodyHtml, baseUri); - } - - /** - Parse a fragment of HTML, with the assumption that it forms the {@code body} of the HTML. - - @param bodyHtml body HTML fragment - @return sane HTML document - - @see Document#body() - */ - public static Document parseBodyFragment(String bodyHtml) { - return Parser.parseBodyFragment(bodyHtml, ""); - } - - /** - Fetch a URL, and parse it as HTML. Provided for compatibility; in most cases use {@link #connect(String)} instead. - <p> - The encoding character set is determined by the content-type header or http-equiv meta tag, or falls back to {@code UTF-8}. - - @param url URL to fetch (with a GET). The protocol must be {@code http} or {@code https}. - @param timeoutMillis Connection and read timeout, in milliseconds. If exceeded, IOException is thrown. - @return The parsed HTML. - - @throws IOException If the final server response != 200 OK (redirects are followed), or if there's an error reading - the response stream. - - @see #connect(String) - */ - public static Document parse(URL url, int timeoutMillis) throws IOException { - Connection con = HttpConnection.connect(url); - con.timeout(timeoutMillis); - return con.get(); - } - - /** - Get safe HTML from untrusted input HTML, by parsing input HTML and filtering it through a white-list of permitted - tags and attributes. - - @param bodyHtml input untrusted HTML - @param baseUri URL to resolve relative URLs against - @param whitelist white-list of permitted HTML elements - @return safe HTML - - @see Cleaner#clean(Document) - */ - public static String clean(String bodyHtml, String baseUri, Whitelist whitelist) { - Document dirty = parseBodyFragment(bodyHtml, baseUri); - Cleaner cleaner = new Cleaner(whitelist); - Document clean = cleaner.clean(dirty); - return clean.body().html(); - } - - /** - Get safe HTML from untrusted input HTML, by parsing input HTML and filtering it through a white-list of permitted - tags and attributes. - - @param bodyHtml input untrusted HTML - @param whitelist white-list of permitted HTML elements - @return safe HTML - - @see Cleaner#clean(Document) - */ - public static String clean(String bodyHtml, Whitelist whitelist) { - return clean(bodyHtml, "", whitelist); - } - - /** - Test if the input HTML has only tags and attributes allowed by the Whitelist. Useful for form validation. The input HTML should - still be run through the cleaner to set up enforced attributes, and to tidy the output. - @param bodyHtml HTML to test - @param whitelist whitelist to test against - @return true if no tags or attributes were removed; false otherwise - @see #clean(String, org.jsoup.safety.Whitelist) - */ - public static boolean isValid(String bodyHtml, Whitelist whitelist) { - Document dirty = parseBodyFragment(bodyHtml, ""); - Cleaner cleaner = new Cleaner(whitelist); - return cleaner.isValid(dirty); - } - -} diff --git a/src/org/jsoup/examples/HtmlToPlainText.java b/src/org/jsoup/examples/HtmlToPlainText.java deleted file mode 100644 index 8f563e9608..0000000000 --- a/src/org/jsoup/examples/HtmlToPlainText.java +++ /dev/null @@ -1,109 +0,0 @@ -package org.jsoup.examples; - -import org.jsoup.Jsoup; -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; -import org.jsoup.nodes.TextNode; -import org.jsoup.select.NodeTraversor; -import org.jsoup.select.NodeVisitor; - -import java.io.IOException; - -/** - * HTML to plain-text. This example program demonstrates the use of jsoup to convert HTML input to lightly-formatted - * plain-text. That is divergent from the general goal of jsoup's .text() methods, which is to get clean data from a - * scrape. - * <p/> - * Note that this is a fairly simplistic formatter -- for real world use you'll want to embrace and extend. - * - * @author Jonathan Hedley, jonathan@hedley.net - */ -public class HtmlToPlainText { - public static void main(String... args) throws IOException { - Validate.isTrue(args.length == 1, "usage: supply url to fetch"); - String url = args[0]; - - // fetch the specified URL and parse to a HTML DOM - Document doc = Jsoup.connect(url).get(); - - HtmlToPlainText formatter = new HtmlToPlainText(); - String plainText = formatter.getPlainText(doc); - System.out.println(plainText); - } - - /** - * Format an Element to plain-text - * @param element the root element to format - * @return formatted text - */ - public String getPlainText(Element element) { - FormattingVisitor formatter = new FormattingVisitor(); - NodeTraversor traversor = new NodeTraversor(formatter); - traversor.traverse(element); // walk the DOM, and call .head() and .tail() for each node - - return formatter.toString(); - } - - // the formatting rules, implemented in a breadth-first DOM traverse - private class FormattingVisitor implements NodeVisitor { - private static final int maxWidth = 80; - private int width = 0; - private StringBuilder accum = new StringBuilder(); // holds the accumulated text - - // hit when the node is first seen - public void head(Node node, int depth) { - String name = node.nodeName(); - if (node instanceof TextNode) - append(((TextNode) node).text()); // TextNodes carry all user-readable text in the DOM. - else if (name.equals("li")) - append("\n * "); - } - - // hit when all of the node's children (if any) have been visited - public void tail(Node node, int depth) { - String name = node.nodeName(); - if (name.equals("br")) - append("\n"); - else if (StringUtil.in(name, "p", "h1", "h2", "h3", "h4", "h5")) - append("\n\n"); - else if (name.equals("a")) - append(String.format(" <%s>", node.absUrl("href"))); - } - - // appends text to the string builder with a simple word wrap method - private void append(String text) { - if (text.startsWith("\n")) - width = 0; // reset counter if starts with a newline. only from formats above, not in natural text - if (text.equals(" ") && - (accum.length() == 0 || StringUtil.in(accum.substring(accum.length() - 1), " ", "\n"))) - return; // don't accumulate long runs of empty spaces - - if (text.length() + width > maxWidth) { // won't fit, needs to wrap - String words[] = text.split("\\s+"); - for (int i = 0; i < words.length; i++) { - String word = words[i]; - boolean last = i == words.length - 1; - if (!last) // insert a space if not the last word - word = word + " "; - if (word.length() + width > maxWidth) { // wrap and reset counter - accum.append("\n").append(word); - width = word.length(); - } else { - accum.append(word); - width += word.length(); - } - } - } else { // fits as is, without need to wrap text - accum.append(text); - width += text.length(); - } - } - - public String toString() { - return accum.toString(); - } - } -} diff --git a/src/org/jsoup/examples/ListLinks.java b/src/org/jsoup/examples/ListLinks.java deleted file mode 100644 index 64b29ba107..0000000000 --- a/src/org/jsoup/examples/ListLinks.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.jsoup.examples; - -import org.jsoup.Jsoup; -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.select.Elements; - -import java.io.IOException; - -/** - * Example program to list links from a URL. - */ -public class ListLinks { - public static void main(String[] args) throws IOException { - Validate.isTrue(args.length == 1, "usage: supply url to fetch"); - String url = args[0]; - print("Fetching %s...", url); - - Document doc = Jsoup.connect(url).get(); - Elements links = doc.select("a[href]"); - Elements media = doc.select("[src]"); - Elements imports = doc.select("link[href]"); - - print("\nMedia: (%d)", media.size()); - for (Element src : media) { - if (src.tagName().equals("img")) - print(" * %s: <%s> %sx%s (%s)", - src.tagName(), src.attr("abs:src"), src.attr("width"), src.attr("height"), - trim(src.attr("alt"), 20)); - else - print(" * %s: <%s>", src.tagName(), src.attr("abs:src")); - } - - print("\nImports: (%d)", imports.size()); - for (Element link : imports) { - print(" * %s <%s> (%s)", link.tagName(),link.attr("abs:href"), link.attr("rel")); - } - - print("\nLinks: (%d)", links.size()); - for (Element link : links) { - print(" * a: <%s> (%s)", link.attr("abs:href"), trim(link.text(), 35)); - } - } - - private static void print(String msg, Object... args) { - System.out.println(String.format(msg, args)); - } - - private static String trim(String s, int width) { - if (s.length() > width) - return s.substring(0, width-1) + "."; - else - return s; - } -} diff --git a/src/org/jsoup/examples/package-info.java b/src/org/jsoup/examples/package-info.java deleted file mode 100644 index c312f430d4..0000000000 --- a/src/org/jsoup/examples/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - Contains example programs and use of jsoup. See the <a href="http://jsoup.org/cookbook/">jsoup cookbook</a>. - */ -package org.jsoup.examples;
\ No newline at end of file diff --git a/src/org/jsoup/helper/DataUtil.java b/src/org/jsoup/helper/DataUtil.java deleted file mode 100644 index 9adfe42153..0000000000 --- a/src/org/jsoup/helper/DataUtil.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.jsoup.helper; - -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.parser.Parser; - -import java.io.*; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Internal static utilities for handling data. - * - */ -public class DataUtil { - private static final Pattern charsetPattern = Pattern.compile("(?i)\\bcharset=\\s*\"?([^\\s;\"]*)"); - static final String defaultCharset = "UTF-8"; // used if not found in header or meta charset - private static final int bufferSize = 0x20000; // ~130K. - - private DataUtil() {} - - /** - * Loads a file to a Document. - * @param in file to load - * @param charsetName character set of input - * @param baseUri base URI of document, to resolve relative links against - * @return Document - * @throws IOException on IO error - */ - public static Document load(File in, String charsetName, String baseUri) throws IOException { - FileInputStream inStream = null; - try { - inStream = new FileInputStream(in); - ByteBuffer byteData = readToByteBuffer(inStream); - return parseByteData(byteData, charsetName, baseUri, Parser.htmlParser()); - } finally { - if (inStream != null) - inStream.close(); - } - } - - /** - * Parses a Document from an input steam. - * @param in input stream to parse. You will need to close it. - * @param charsetName character set of input - * @param baseUri base URI of document, to resolve relative links against - * @return Document - * @throws IOException on IO error - */ - public static Document load(InputStream in, String charsetName, String baseUri) throws IOException { - ByteBuffer byteData = readToByteBuffer(in); - return parseByteData(byteData, charsetName, baseUri, Parser.htmlParser()); - } - - /** - * Parses a Document from an input steam, using the provided Parser. - * @param in input stream to parse. You will need to close it. - * @param charsetName character set of input - * @param baseUri base URI of document, to resolve relative links against - * @param parser alternate {@link Parser#xmlParser() parser} to use. - * @return Document - * @throws IOException on IO error - */ - public static Document load(InputStream in, String charsetName, String baseUri, Parser parser) throws IOException { - ByteBuffer byteData = readToByteBuffer(in); - return parseByteData(byteData, charsetName, baseUri, parser); - } - - // reads bytes first into a buffer, then decodes with the appropriate charset. done this way to support - // switching the chartset midstream when a meta http-equiv tag defines the charset. - static Document parseByteData(ByteBuffer byteData, String charsetName, String baseUri, Parser parser) { - String docData; - Document doc = null; - if (charsetName == null) { // determine from meta. safe parse as UTF-8 - // look for <meta http-equiv="Content-Type" content="text/html;charset=gb2312"> or HTML5 <meta charset="gb2312"> - docData = Charset.forName(defaultCharset).decode(byteData).toString(); - doc = parser.parseInput(docData, baseUri); - Element meta = doc.select("meta[http-equiv=content-type], meta[charset]").first(); - if (meta != null) { // if not found, will keep utf-8 as best attempt - String foundCharset = meta.hasAttr("http-equiv") ? getCharsetFromContentType(meta.attr("content")) : meta.attr("charset"); - if (foundCharset != null && foundCharset.length() != 0 && !foundCharset.equals(defaultCharset)) { // need to re-decode - charsetName = foundCharset; - byteData.rewind(); - docData = Charset.forName(foundCharset).decode(byteData).toString(); - doc = null; - } - } - } else { // specified by content type header (or by user on file load) - Validate.notEmpty(charsetName, "Must set charset arg to character set of file to parse. Set to null to attempt to detect from HTML"); - docData = Charset.forName(charsetName).decode(byteData).toString(); - } - if (doc == null) { - // there are times where there is a spurious byte-order-mark at the start of the text. Shouldn't be present - // in utf-8. If after decoding, there is a BOM, strip it; otherwise will cause the parser to go straight - // into head mode - if (docData.charAt(0) == 65279) - docData = docData.substring(1); - - doc = parser.parseInput(docData, baseUri); - doc.outputSettings().charset(charsetName); - } - return doc; - } - - static ByteBuffer readToByteBuffer(InputStream inStream) throws IOException { - byte[] buffer = new byte[bufferSize]; - ByteArrayOutputStream outStream = new ByteArrayOutputStream(bufferSize); - int read; - while(true) { - read = inStream.read(buffer); - if (read == -1) break; - outStream.write(buffer, 0, read); - } - ByteBuffer byteData = ByteBuffer.wrap(outStream.toByteArray()); - return byteData; - } - - /** - * Parse out a charset from a content type header. - * @param contentType e.g. "text/html; charset=EUC-JP" - * @return "EUC-JP", or null if not found. Charset is trimmed and uppercased. - */ - static String getCharsetFromContentType(String contentType) { - if (contentType == null) return null; - Matcher m = charsetPattern.matcher(contentType); - if (m.find()) { - return m.group(1).trim().toUpperCase(); - } - return null; - } - - -} diff --git a/src/org/jsoup/helper/DescendableLinkedList.java b/src/org/jsoup/helper/DescendableLinkedList.java deleted file mode 100644 index 28ca1971eb..0000000000 --- a/src/org/jsoup/helper/DescendableLinkedList.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.jsoup.helper; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.ListIterator; - -/** - * Provides a descending iterator and other 1.6 methods to allow support on the 1.5 JRE. - */ -public class DescendableLinkedList<E> extends LinkedList<E> { - - /** - * Create a new DescendableLinkedList. - */ - public DescendableLinkedList() { - super(); - } - - /** - * Add a new element to the start of the list. - * @param e element to add - */ - public void push(E e) { - addFirst(e); - } - - /** - * Look at the last element, if there is one. - * @return the last element, or null - */ - public E peekLast() { - return size() == 0 ? null : getLast(); - } - - /** - * Remove and return the last element, if there is one - * @return the last element, or null - */ - public E pollLast() { - return size() == 0 ? null : removeLast(); - } - - /** - * Get an iterator that starts and the end of the list and works towards the start. - * @return an iterator that starts and the end of the list and works towards the start. - */ - public Iterator<E> descendingIterator() { - return new DescendingIterator<E>(size()); - } - - private class DescendingIterator<E> implements Iterator<E> { - private final ListIterator<E> iter; - - @SuppressWarnings("unchecked") - private DescendingIterator(int index) { - iter = (ListIterator<E>) listIterator(index); - } - - /** - * Check if there is another element on the list. - * @return if another element - */ - public boolean hasNext() { - return iter.hasPrevious(); - } - - /** - * Get the next element. - * @return the next element. - */ - public E next() { - return iter.previous(); - } - - /** - * Remove the current element. - */ - public void remove() { - iter.remove(); - } - } -} diff --git a/src/org/jsoup/helper/HttpConnection.java b/src/org/jsoup/helper/HttpConnection.java deleted file mode 100644 index 06200a2547..0000000000 --- a/src/org/jsoup/helper/HttpConnection.java +++ /dev/null @@ -1,658 +0,0 @@ -package org.jsoup.helper; - -import org.jsoup.Connection; -import org.jsoup.nodes.Document; -import org.jsoup.parser.Parser; -import org.jsoup.parser.TokenQueue; - -import java.io.*; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLEncoder; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.*; -import java.util.zip.GZIPInputStream; - -/** - * Implementation of {@link Connection}. - * @see org.jsoup.Jsoup#connect(String) - */ -public class HttpConnection implements Connection { - public static Connection connect(String url) { - Connection con = new HttpConnection(); - con.url(url); - return con; - } - - public static Connection connect(URL url) { - Connection con = new HttpConnection(); - con.url(url); - return con; - } - - private Connection.Request req; - private Connection.Response res; - - private HttpConnection() { - req = new Request(); - res = new Response(); - } - - public Connection url(URL url) { - req.url(url); - return this; - } - - public Connection url(String url) { - Validate.notEmpty(url, "Must supply a valid URL"); - try { - req.url(new URL(url)); - } catch (MalformedURLException e) { - throw new IllegalArgumentException("Malformed URL: " + url, e); - } - return this; - } - - public Connection userAgent(String userAgent) { - Validate.notNull(userAgent, "User agent must not be null"); - req.header("User-Agent", userAgent); - return this; - } - - public Connection timeout(int millis) { - req.timeout(millis); - return this; - } - - public Connection followRedirects(boolean followRedirects) { - req.followRedirects(followRedirects); - return this; - } - - public Connection referrer(String referrer) { - Validate.notNull(referrer, "Referrer must not be null"); - req.header("Referer", referrer); - return this; - } - - public Connection method(Method method) { - req.method(method); - return this; - } - - public Connection ignoreHttpErrors(boolean ignoreHttpErrors) { - req.ignoreHttpErrors(ignoreHttpErrors); - return this; - } - - public Connection ignoreContentType(boolean ignoreContentType) { - req.ignoreContentType(ignoreContentType); - return this; - } - - public Connection data(String key, String value) { - req.data(KeyVal.create(key, value)); - return this; - } - - public Connection data(Map<String, String> data) { - Validate.notNull(data, "Data map must not be null"); - for (Map.Entry<String, String> entry : data.entrySet()) { - req.data(KeyVal.create(entry.getKey(), entry.getValue())); - } - return this; - } - - public Connection data(String... keyvals) { - Validate.notNull(keyvals, "Data key value pairs must not be null"); - Validate.isTrue(keyvals.length %2 == 0, "Must supply an even number of key value pairs"); - for (int i = 0; i < keyvals.length; i += 2) { - String key = keyvals[i]; - String value = keyvals[i+1]; - Validate.notEmpty(key, "Data key must not be empty"); - Validate.notNull(value, "Data value must not be null"); - req.data(KeyVal.create(key, value)); - } - return this; - } - - public Connection header(String name, String value) { - req.header(name, value); - return this; - } - - public Connection cookie(String name, String value) { - req.cookie(name, value); - return this; - } - - public Connection cookies(Map<String, String> cookies) { - Validate.notNull(cookies, "Cookie map must not be null"); - for (Map.Entry<String, String> entry : cookies.entrySet()) { - req.cookie(entry.getKey(), entry.getValue()); - } - return this; - } - - public Connection parser(Parser parser) { - req.parser(parser); - return this; - } - - public Document get() throws IOException { - req.method(Method.GET); - execute(); - return res.parse(); - } - - public Document post() throws IOException { - req.method(Method.POST); - execute(); - return res.parse(); - } - - public Connection.Response execute() throws IOException { - res = Response.execute(req); - return res; - } - - public Connection.Request request() { - return req; - } - - public Connection request(Connection.Request request) { - req = request; - return this; - } - - public Connection.Response response() { - return res; - } - - public Connection response(Connection.Response response) { - res = response; - return this; - } - - @SuppressWarnings({"unchecked"}) - private static abstract class Base<T extends Connection.Base> implements Connection.Base<T> { - URL url; - Method method; - Map<String, String> headers; - Map<String, String> cookies; - - private Base() { - headers = new LinkedHashMap<String, String>(); - cookies = new LinkedHashMap<String, String>(); - } - - public URL url() { - return url; - } - - public T url(URL url) { - Validate.notNull(url, "URL must not be null"); - this.url = url; - return (T) this; - } - - public Method method() { - return method; - } - - public T method(Method method) { - Validate.notNull(method, "Method must not be null"); - this.method = method; - return (T) this; - } - - public String header(String name) { - Validate.notNull(name, "Header name must not be null"); - return getHeaderCaseInsensitive(name); - } - - public T header(String name, String value) { - Validate.notEmpty(name, "Header name must not be empty"); - Validate.notNull(value, "Header value must not be null"); - removeHeader(name); // ensures we don't get an "accept-encoding" and a "Accept-Encoding" - headers.put(name, value); - return (T) this; - } - - public boolean hasHeader(String name) { - Validate.notEmpty(name, "Header name must not be empty"); - return getHeaderCaseInsensitive(name) != null; - } - - public T removeHeader(String name) { - Validate.notEmpty(name, "Header name must not be empty"); - Map.Entry<String, String> entry = scanHeaders(name); // remove is case insensitive too - if (entry != null) - headers.remove(entry.getKey()); // ensures correct case - return (T) this; - } - - public Map<String, String> headers() { - return headers; - } - - private String getHeaderCaseInsensitive(String name) { - Validate.notNull(name, "Header name must not be null"); - // quick evals for common case of title case, lower case, then scan for mixed - String value = headers.get(name); - if (value == null) - value = headers.get(name.toLowerCase()); - if (value == null) { - Map.Entry<String, String> entry = scanHeaders(name); - if (entry != null) - value = entry.getValue(); - } - return value; - } - - private Map.Entry<String, String> scanHeaders(String name) { - String lc = name.toLowerCase(); - for (Map.Entry<String, String> entry : headers.entrySet()) { - if (entry.getKey().toLowerCase().equals(lc)) - return entry; - } - return null; - } - - public String cookie(String name) { - Validate.notNull(name, "Cookie name must not be null"); - return cookies.get(name); - } - - public T cookie(String name, String value) { - Validate.notEmpty(name, "Cookie name must not be empty"); - Validate.notNull(value, "Cookie value must not be null"); - cookies.put(name, value); - return (T) this; - } - - public boolean hasCookie(String name) { - Validate.notEmpty("Cookie name must not be empty"); - return cookies.containsKey(name); - } - - public T removeCookie(String name) { - Validate.notEmpty("Cookie name must not be empty"); - cookies.remove(name); - return (T) this; - } - - public Map<String, String> cookies() { - return cookies; - } - } - - public static class Request extends Base<Connection.Request> implements Connection.Request { - private int timeoutMilliseconds; - private boolean followRedirects; - private Collection<Connection.KeyVal> data; - private boolean ignoreHttpErrors = false; - private boolean ignoreContentType = false; - private Parser parser; - - private Request() { - timeoutMilliseconds = 3000; - followRedirects = true; - data = new ArrayList<Connection.KeyVal>(); - method = Connection.Method.GET; - headers.put("Accept-Encoding", "gzip"); - parser = Parser.htmlParser(); - } - - public int timeout() { - return timeoutMilliseconds; - } - - public Request timeout(int millis) { - Validate.isTrue(millis >= 0, "Timeout milliseconds must be 0 (infinite) or greater"); - timeoutMilliseconds = millis; - return this; - } - - public boolean followRedirects() { - return followRedirects; - } - - public Connection.Request followRedirects(boolean followRedirects) { - this.followRedirects = followRedirects; - return this; - } - - public boolean ignoreHttpErrors() { - return ignoreHttpErrors; - } - - public Connection.Request ignoreHttpErrors(boolean ignoreHttpErrors) { - this.ignoreHttpErrors = ignoreHttpErrors; - return this; - } - - public boolean ignoreContentType() { - return ignoreContentType; - } - - public Connection.Request ignoreContentType(boolean ignoreContentType) { - this.ignoreContentType = ignoreContentType; - return this; - } - - public Request data(Connection.KeyVal keyval) { - Validate.notNull(keyval, "Key val must not be null"); - data.add(keyval); - return this; - } - - public Collection<Connection.KeyVal> data() { - return data; - } - - public Request parser(Parser parser) { - this.parser = parser; - return this; - } - - public Parser parser() { - return parser; - } - } - - public static class Response extends Base<Connection.Response> implements Connection.Response { - private static final int MAX_REDIRECTS = 20; - private int statusCode; - private String statusMessage; - private ByteBuffer byteData; - private String charset; - private String contentType; - private boolean executed = false; - private int numRedirects = 0; - private Connection.Request req; - - Response() { - super(); - } - - private Response(Response previousResponse) throws IOException { - super(); - if (previousResponse != null) { - numRedirects = previousResponse.numRedirects + 1; - if (numRedirects >= MAX_REDIRECTS) - throw new IOException(String.format("Too many redirects occurred trying to load URL %s", previousResponse.url())); - } - } - - static Response execute(Connection.Request req) throws IOException { - return execute(req, null); - } - - static Response execute(Connection.Request req, Response previousResponse) throws IOException { - Validate.notNull(req, "Request must not be null"); - String protocol = req.url().getProtocol(); - Validate - .isTrue(protocol.equals("http") || protocol.equals("https"), "Only http & https protocols supported"); - - // set up the request for execution - if (req.method() == Connection.Method.GET && req.data().size() > 0) - serialiseRequestUrl(req); // appends query string - HttpURLConnection conn = createConnection(req); - conn.connect(); - if (req.method() == Connection.Method.POST) - writePost(req.data(), conn.getOutputStream()); - - int status = conn.getResponseCode(); - boolean needsRedirect = false; - if (status != HttpURLConnection.HTTP_OK) { - if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM || status == HttpURLConnection.HTTP_SEE_OTHER) - needsRedirect = true; - else if (!req.ignoreHttpErrors()) - throw new IOException(status + " error loading URL " + req.url().toString()); - } - Response res = new Response(previousResponse); - res.setupFromConnection(conn, previousResponse); - if (needsRedirect && req.followRedirects()) { - req.method(Method.GET); // always redirect with a get. any data param from original req are dropped. - req.data().clear(); - req.url(new URL(req.url(), res.header("Location"))); - for (Map.Entry<String, String> cookie : res.cookies.entrySet()) { // add response cookies to request (for e.g. login posts) - req.cookie(cookie.getKey(), cookie.getValue()); - } - return execute(req, res); - } - res.req = req; - - InputStream bodyStream = null; - InputStream dataStream = null; - try { - dataStream = conn.getErrorStream() != null ? conn.getErrorStream() : conn.getInputStream(); - bodyStream = res.hasHeader("Content-Encoding") && res.header("Content-Encoding").equalsIgnoreCase("gzip") ? - new BufferedInputStream(new GZIPInputStream(dataStream)) : - new BufferedInputStream(dataStream); - - res.byteData = DataUtil.readToByteBuffer(bodyStream); - res.charset = DataUtil.getCharsetFromContentType(res.contentType); // may be null, readInputStream deals with it - } finally { - if (bodyStream != null) bodyStream.close(); - if (dataStream != null) dataStream.close(); - } - - res.executed = true; - return res; - } - - public int statusCode() { - return statusCode; - } - - public String statusMessage() { - return statusMessage; - } - - public String charset() { - return charset; - } - - public String contentType() { - return contentType; - } - - public Document parse() throws IOException { - Validate.isTrue(executed, "Request must be executed (with .execute(), .get(), or .post() before parsing response"); - if (!req.ignoreContentType() && (contentType == null || !(contentType.startsWith("text/") || contentType.startsWith("application/xml") || contentType.startsWith("application/xhtml+xml")))) - throw new IOException(String.format("Unhandled content type \"%s\" on URL %s. Must be text/*, application/xml, or application/xhtml+xml", - contentType, url.toString())); - Document doc = DataUtil.parseByteData(byteData, charset, url.toExternalForm(), req.parser()); - byteData.rewind(); - charset = doc.outputSettings().charset().name(); // update charset from meta-equiv, possibly - return doc; - } - - public String body() { - Validate.isTrue(executed, "Request must be executed (with .execute(), .get(), or .post() before getting response body"); - // charset gets set from header on execute, and from meta-equiv on parse. parse may not have happened yet - String body; - if (charset == null) - body = Charset.forName(DataUtil.defaultCharset).decode(byteData).toString(); - else - body = Charset.forName(charset).decode(byteData).toString(); - byteData.rewind(); - return body; - } - - public byte[] bodyAsBytes() { - Validate.isTrue(executed, "Request must be executed (with .execute(), .get(), or .post() before getting response body"); - return byteData.array(); - } - - // set up connection defaults, and details from request - private static HttpURLConnection createConnection(Connection.Request req) throws IOException { - HttpURLConnection conn = (HttpURLConnection) req.url().openConnection(); - conn.setRequestMethod(req.method().name()); - conn.setInstanceFollowRedirects(false); // don't rely on native redirection support - conn.setConnectTimeout(req.timeout()); - conn.setReadTimeout(req.timeout()); - if (req.method() == Method.POST) - conn.setDoOutput(true); - if (req.cookies().size() > 0) - conn.addRequestProperty("Cookie", getRequestCookieString(req)); - for (Map.Entry<String, String> header : req.headers().entrySet()) { - conn.addRequestProperty(header.getKey(), header.getValue()); - } - return conn; - } - - // set up url, method, header, cookies - private void setupFromConnection(HttpURLConnection conn, Connection.Response previousResponse) throws IOException { - method = Connection.Method.valueOf(conn.getRequestMethod()); - url = conn.getURL(); - statusCode = conn.getResponseCode(); - statusMessage = conn.getResponseMessage(); - contentType = conn.getContentType(); - - Map<String, List<String>> resHeaders = conn.getHeaderFields(); - processResponseHeaders(resHeaders); - - // if from a redirect, map previous response cookies into this response - if (previousResponse != null) { - for (Map.Entry<String, String> prevCookie : previousResponse.cookies().entrySet()) { - if (!hasCookie(prevCookie.getKey())) - cookie(prevCookie.getKey(), prevCookie.getValue()); - } - } - } - - void processResponseHeaders(Map<String, List<String>> resHeaders) { - for (Map.Entry<String, List<String>> entry : resHeaders.entrySet()) { - String name = entry.getKey(); - if (name == null) - continue; // http/1.1 line - - List<String> values = entry.getValue(); - if (name.equalsIgnoreCase("Set-Cookie")) { - for (String value : values) { - if (value == null) - continue; - TokenQueue cd = new TokenQueue(value); - String cookieName = cd.chompTo("=").trim(); - String cookieVal = cd.consumeTo(";").trim(); - if (cookieVal == null) - cookieVal = ""; - // ignores path, date, domain, secure et al. req'd? - // name not blank, value not null - if (cookieName != null && cookieName.length() > 0) - cookie(cookieName, cookieVal); - } - } else { // only take the first instance of each header - if (!values.isEmpty()) - header(name, values.get(0)); - } - } - } - - private static void writePost(Collection<Connection.KeyVal> data, OutputStream outputStream) throws IOException { - OutputStreamWriter w = new OutputStreamWriter(outputStream, DataUtil.defaultCharset); - boolean first = true; - for (Connection.KeyVal keyVal : data) { - if (!first) - w.append('&'); - else - first = false; - - w.write(URLEncoder.encode(keyVal.key(), DataUtil.defaultCharset)); - w.write('='); - w.write(URLEncoder.encode(keyVal.value(), DataUtil.defaultCharset)); - } - w.close(); - } - - private static String getRequestCookieString(Connection.Request req) { - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (Map.Entry<String, String> cookie : req.cookies().entrySet()) { - if (!first) - sb.append("; "); - else - first = false; - sb.append(cookie.getKey()).append('=').append(cookie.getValue()); - // todo: spec says only ascii, no escaping / encoding defined. validate on set? or escape somehow here? - } - return sb.toString(); - } - - // for get url reqs, serialise the data map into the url - private static void serialiseRequestUrl(Connection.Request req) throws IOException { - URL in = req.url(); - StringBuilder url = new StringBuilder(); - boolean first = true; - // reconstitute the query, ready for appends - url - .append(in.getProtocol()) - .append("://") - .append(in.getAuthority()) // includes host, port - .append(in.getPath()) - .append("?"); - if (in.getQuery() != null) { - url.append(in.getQuery()); - first = false; - } - for (Connection.KeyVal keyVal : req.data()) { - if (!first) - url.append('&'); - else - first = false; - url - .append(URLEncoder.encode(keyVal.key(), DataUtil.defaultCharset)) - .append('=') - .append(URLEncoder.encode(keyVal.value(), DataUtil.defaultCharset)); - } - req.url(new URL(url.toString())); - req.data().clear(); // moved into url as get params - } - } - - public static class KeyVal implements Connection.KeyVal { - private String key; - private String value; - - public static KeyVal create(String key, String value) { - Validate.notEmpty(key, "Data key must not be empty"); - Validate.notNull(value, "Data value must not be null"); - return new KeyVal(key, value); - } - - private KeyVal(String key, String value) { - this.key = key; - this.value = value; - } - - public KeyVal key(String key) { - Validate.notEmpty(key, "Data key must not be empty"); - this.key = key; - return this; - } - - public String key() { - return key; - } - - public KeyVal value(String value) { - Validate.notNull(value, "Data value must not be null"); - this.value = value; - return this; - } - - public String value() { - return value; - } - - @Override - public String toString() { - return key + "=" + value; - } - } -} diff --git a/src/org/jsoup/helper/StringUtil.java b/src/org/jsoup/helper/StringUtil.java deleted file mode 100644 index 071a92c7a5..0000000000 --- a/src/org/jsoup/helper/StringUtil.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.jsoup.helper; - -import java.util.Collection; -import java.util.Iterator; - -/** - * A minimal String utility class. Designed for internal jsoup use only. - */ -public final class StringUtil { - // memoised padding up to 10 - private static final String[] padding = {"", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "}; - - /** - * Join a collection of strings by a seperator - * @param strings collection of string objects - * @param sep string to place between strings - * @return joined string - */ - public static String join(Collection strings, String sep) { - return join(strings.iterator(), sep); - } - - /** - * Join a collection of strings by a seperator - * @param strings iterator of string objects - * @param sep string to place between strings - * @return joined string - */ - public static String join(Iterator strings, String sep) { - if (!strings.hasNext()) - return ""; - - String start = strings.next().toString(); - if (!strings.hasNext()) // only one, avoid builder - return start; - - StringBuilder sb = new StringBuilder(64).append(start); - while (strings.hasNext()) { - sb.append(sep); - sb.append(strings.next()); - } - return sb.toString(); - } - - /** - * Returns space padding - * @param width amount of padding desired - * @return string of spaces * width - */ - public static String padding(int width) { - if (width < 0) - throw new IllegalArgumentException("width must be > 0"); - - if (width < padding.length) - return padding[width]; - - char[] out = new char[width]; - for (int i = 0; i < width; i++) - out[i] = ' '; - return String.valueOf(out); - } - - /** - * Tests if a string is blank: null, emtpy, or only whitespace (" ", \r\n, \t, etc) - * @param string string to test - * @return if string is blank - */ - public static boolean isBlank(String string) { - if (string == null || string.length() == 0) - return true; - - int l = string.length(); - for (int i = 0; i < l; i++) { - if (!StringUtil.isWhitespace(string.codePointAt(i))) - return false; - } - return true; - } - - /** - * Tests if a string is numeric, i.e. contains only digit characters - * @param string string to test - * @return true if only digit chars, false if empty or null or contains non-digit chrs - */ - public static boolean isNumeric(String string) { - if (string == null || string.length() == 0) - return false; - - int l = string.length(); - for (int i = 0; i < l; i++) { - if (!Character.isDigit(string.codePointAt(i))) - return false; - } - return true; - } - - /** - * Tests if a code point is "whitespace" as defined in the HTML spec. - * @param c code point to test - * @return true if code point is whitespace, false otherwise - */ - public static boolean isWhitespace(int c){ - return c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r'; - } - - public static String normaliseWhitespace(String string) { - StringBuilder sb = new StringBuilder(string.length()); - - boolean lastWasWhite = false; - boolean modified = false; - - int l = string.length(); - for (int i = 0; i < l; i++) { - int c = string.codePointAt(i); - if (isWhitespace(c)) { - if (lastWasWhite) { - modified = true; - continue; - } - if (c != ' ') - modified = true; - sb.append(' '); - lastWasWhite = true; - } - else { - sb.appendCodePoint(c); - lastWasWhite = false; - } - } - return modified ? sb.toString() : string; - } - - public static boolean in(String needle, String... haystack) { - for (String hay : haystack) { - if (hay.equals(needle)) - return true; - } - return false; - } -} diff --git a/src/org/jsoup/helper/Validate.java b/src/org/jsoup/helper/Validate.java deleted file mode 100644 index 814bcc3a40..0000000000 --- a/src/org/jsoup/helper/Validate.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.jsoup.helper; - -/** - * Simple validation methods. Designed for jsoup internal use - */ -public final class Validate { - - private Validate() {} - - /** - * Validates that the object is not null - * @param obj object to test - */ - public static void notNull(Object obj) { - if (obj == null) - throw new IllegalArgumentException("Object must not be null"); - } - - /** - * Validates that the object is not null - * @param obj object to test - * @param msg message to output if validation fails - */ - public static void notNull(Object obj, String msg) { - if (obj == null) - throw new IllegalArgumentException(msg); - } - - /** - * Validates that the value is true - * @param val object to test - */ - public static void isTrue(boolean val) { - if (!val) - throw new IllegalArgumentException("Must be true"); - } - - /** - * Validates that the value is true - * @param val object to test - * @param msg message to output if validation fails - */ - public static void isTrue(boolean val, String msg) { - if (!val) - throw new IllegalArgumentException(msg); - } - - /** - * Validates that the value is false - * @param val object to test - */ - public static void isFalse(boolean val) { - if (val) - throw new IllegalArgumentException("Must be false"); - } - - /** - * Validates that the value is false - * @param val object to test - * @param msg message to output if validation fails - */ - public static void isFalse(boolean val, String msg) { - if (val) - throw new IllegalArgumentException(msg); - } - - /** - * Validates that the array contains no null elements - * @param objects the array to test - */ - public static void noNullElements(Object[] objects) { - noNullElements(objects, "Array must not contain any null objects"); - } - - /** - * Validates that the array contains no null elements - * @param objects the array to test - * @param msg message to output if validation fails - */ - public static void noNullElements(Object[] objects, String msg) { - for (Object obj : objects) - if (obj == null) - throw new IllegalArgumentException(msg); - } - - /** - * Validates that the string is not empty - * @param string the string to test - */ - public static void notEmpty(String string) { - if (string == null || string.length() == 0) - throw new IllegalArgumentException("String must not be empty"); - } - - /** - * Validates that the string is not empty - * @param string the string to test - * @param msg message to output if validation fails - */ - public static void notEmpty(String string, String msg) { - if (string == null || string.length() == 0) - throw new IllegalArgumentException(msg); - } - - /** - Cause a failure. - @param msg message to output. - */ - public static void fail(String msg) { - throw new IllegalArgumentException(msg); - } -} diff --git a/src/org/jsoup/nodes/Attribute.java b/src/org/jsoup/nodes/Attribute.java deleted file mode 100644 index 02eb29db83..0000000000 --- a/src/org/jsoup/nodes/Attribute.java +++ /dev/null @@ -1,131 +0,0 @@ -package org.jsoup.nodes; - -import org.jsoup.helper.Validate; - -import java.util.Map; - -/** - A single key + value attribute. Keys are trimmed and normalised to lower-case. - - @author Jonathan Hedley, jonathan@hedley.net */ -public class Attribute implements Map.Entry<String, String>, Cloneable { - private String key; - private String value; - - /** - * Create a new attribute from unencoded (raw) key and value. - * @param key attribute key - * @param value attribute value - * @see #createFromEncoded - */ - public Attribute(String key, String value) { - Validate.notEmpty(key); - Validate.notNull(value); - this.key = key.trim().toLowerCase(); - this.value = value; - } - - /** - Get the attribute key. - @return the attribute key - */ - public String getKey() { - return key; - } - - /** - Set the attribute key. Gets normalised as per the constructor method. - @param key the new key; must not be null - */ - public void setKey(String key) { - Validate.notEmpty(key); - this.key = key.trim().toLowerCase(); - } - - /** - Get the attribute value. - @return the attribute value - */ - public String getValue() { - return value; - } - - /** - Set the attribute value. - @param value the new attribute value; must not be null - */ - public String setValue(String value) { - Validate.notNull(value); - String old = this.value; - this.value = value; - return old; - } - - /** - Get the HTML representation of this attribute; e.g. {@code href="index.html"}. - @return HTML - */ - public String html() { - return key + "=\"" + Entities.escape(value, (new Document("")).outputSettings()) + "\""; - } - - protected void html(StringBuilder accum, Document.OutputSettings out) { - accum - .append(key) - .append("=\"") - .append(Entities.escape(value, out)) - .append("\""); - } - - /** - Get the string representation of this attribute, implemented as {@link #html()}. - @return string - */ - public String toString() { - return html(); - } - - /** - * Create a new Attribute from an unencoded key and a HTML attribute encoded value. - * @param unencodedKey assumes the key is not encoded, as can be only run of simple \w chars. - * @param encodedValue HTML attribute encoded value - * @return attribute - */ - public static Attribute createFromEncoded(String unencodedKey, String encodedValue) { - String value = Entities.unescape(encodedValue, true); - return new Attribute(unencodedKey, value); - } - - protected boolean isDataAttribute() { - return key.startsWith(Attributes.dataPrefix) && key.length() > Attributes.dataPrefix.length(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Attribute)) return false; - - Attribute attribute = (Attribute) o; - - if (key != null ? !key.equals(attribute.key) : attribute.key != null) return false; - if (value != null ? !value.equals(attribute.value) : attribute.value != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = key != null ? key.hashCode() : 0; - result = 31 * result + (value != null ? value.hashCode() : 0); - return result; - } - - @Override - public Attribute clone() { - try { - return (Attribute) super.clone(); // only fields are immutable strings key and value, so no more deep copy required - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/src/org/jsoup/nodes/Attributes.java b/src/org/jsoup/nodes/Attributes.java deleted file mode 100644 index 9436750fc9..0000000000 --- a/src/org/jsoup/nodes/Attributes.java +++ /dev/null @@ -1,249 +0,0 @@ -package org.jsoup.nodes; - -import org.jsoup.helper.Validate; - -import java.util.*; - -/** - * The attributes of an Element. - * <p/> - * Attributes are treated as a map: there can be only one value associated with an attribute key. - * <p/> - * Attribute key and value comparisons are done case insensitively, and keys are normalised to - * lower-case. - * - * @author Jonathan Hedley, jonathan@hedley.net - */ -public class Attributes implements Iterable<Attribute>, Cloneable { - protected static final String dataPrefix = "data-"; - - private LinkedHashMap<String, Attribute> attributes = null; - // linked hash map to preserve insertion order. - // null be default as so many elements have no attributes -- saves a good chunk of memory - - /** - Get an attribute value by key. - @param key the attribute key - @return the attribute value if set; or empty string if not set. - @see #hasKey(String) - */ - public String get(String key) { - Validate.notEmpty(key); - - if (attributes == null) - return ""; - - Attribute attr = attributes.get(key.toLowerCase()); - return attr != null ? attr.getValue() : ""; - } - - /** - Set a new attribute, or replace an existing one by key. - @param key attribute key - @param value attribute value - */ - public void put(String key, String value) { - Attribute attr = new Attribute(key, value); - put(attr); - } - - /** - Set a new attribute, or replace an existing one by key. - @param attribute attribute - */ - public void put(Attribute attribute) { - Validate.notNull(attribute); - if (attributes == null) - attributes = new LinkedHashMap<String, Attribute>(2); - attributes.put(attribute.getKey(), attribute); - } - - /** - Remove an attribute by key. - @param key attribute key to remove - */ - public void remove(String key) { - Validate.notEmpty(key); - if (attributes == null) - return; - attributes.remove(key.toLowerCase()); - } - - /** - Tests if these attributes contain an attribute with this key. - @param key key to check for - @return true if key exists, false otherwise - */ - public boolean hasKey(String key) { - return attributes != null && attributes.containsKey(key.toLowerCase()); - } - - /** - Get the number of attributes in this set. - @return size - */ - public int size() { - if (attributes == null) - return 0; - return attributes.size(); - } - - /** - Add all the attributes from the incoming set to this set. - @param incoming attributes to add to these attributes. - */ - public void addAll(Attributes incoming) { - if (incoming.size() == 0) - return; - if (attributes == null) - attributes = new LinkedHashMap<String, Attribute>(incoming.size()); - attributes.putAll(incoming.attributes); - } - - public Iterator<Attribute> iterator() { - return asList().iterator(); - } - - /** - Get the attributes as a List, for iteration. Do not modify the keys of the attributes via this view, as changes - to keys will not be recognised in the containing set. - @return an view of the attributes as a List. - */ - public List<Attribute> asList() { - if (attributes == null) - return Collections.emptyList(); - - List<Attribute> list = new ArrayList<Attribute>(attributes.size()); - for (Map.Entry<String, Attribute> entry : attributes.entrySet()) { - list.add(entry.getValue()); - } - return Collections.unmodifiableList(list); - } - - /** - * Retrieves a filtered view of attributes that are HTML5 custom data attributes; that is, attributes with keys - * starting with {@code data-}. - * @return map of custom data attributes. - */ - public Map<String, String> dataset() { - return new Dataset(); - } - - /** - Get the HTML representation of these attributes. - @return HTML - */ - public String html() { - StringBuilder accum = new StringBuilder(); - html(accum, (new Document("")).outputSettings()); // output settings a bit funky, but this html() seldom used - return accum.toString(); - } - - void html(StringBuilder accum, Document.OutputSettings out) { - if (attributes == null) - return; - - for (Map.Entry<String, Attribute> entry : attributes.entrySet()) { - Attribute attribute = entry.getValue(); - accum.append(" "); - attribute.html(accum, out); - } - } - - public String toString() { - return html(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Attributes)) return false; - - Attributes that = (Attributes) o; - - if (attributes != null ? !attributes.equals(that.attributes) : that.attributes != null) return false; - - return true; - } - - @Override - public int hashCode() { - return attributes != null ? attributes.hashCode() : 0; - } - - @Override - public Attributes clone() { - if (attributes == null) - return new Attributes(); - - Attributes clone; - try { - clone = (Attributes) super.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - clone.attributes = new LinkedHashMap<String, Attribute>(attributes.size()); - for (Attribute attribute: this) - clone.attributes.put(attribute.getKey(), attribute.clone()); - return clone; - } - - private class Dataset extends AbstractMap<String, String> { - - private Dataset() { - if (attributes == null) - attributes = new LinkedHashMap<String, Attribute>(2); - } - - public Set<Entry<String, String>> entrySet() { - return new EntrySet(); - } - - @Override - public String put(String key, String value) { - String dataKey = dataKey(key); - String oldValue = hasKey(dataKey) ? attributes.get(dataKey).getValue() : null; - Attribute attr = new Attribute(dataKey, value); - attributes.put(dataKey, attr); - return oldValue; - } - - private class EntrySet extends AbstractSet<Map.Entry<String, String>> { - public Iterator<Map.Entry<String, String>> iterator() { - return new DatasetIterator(); - } - - public int size() { - int count = 0; - Iterator iter = new DatasetIterator(); - while (iter.hasNext()) - count++; - return count; - } - } - - private class DatasetIterator implements Iterator<Map.Entry<String, String>> { - private Iterator<Attribute> attrIter = attributes.values().iterator(); - private Attribute attr; - public boolean hasNext() { - while (attrIter.hasNext()) { - attr = attrIter.next(); - if (attr.isDataAttribute()) return true; - } - return false; - } - - public Entry<String, String> next() { - return new Attribute(attr.getKey().substring(dataPrefix.length()), attr.getValue()); - } - - public void remove() { - attributes.remove(attr.getKey()); - } - } - } - - private static String dataKey(String key) { - return dataPrefix + key; - } -} diff --git a/src/org/jsoup/nodes/Comment.java b/src/org/jsoup/nodes/Comment.java deleted file mode 100644 index 37fd4368fa..0000000000 --- a/src/org/jsoup/nodes/Comment.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.jsoup.nodes; - -/** - A comment node. - - @author Jonathan Hedley, jonathan@hedley.net */ -public class Comment extends Node { - private static final String COMMENT_KEY = "comment"; - - /** - Create a new comment node. - @param data The contents of the comment - @param baseUri base URI - */ - public Comment(String data, String baseUri) { - super(baseUri); - attributes.put(COMMENT_KEY, data); - } - - public String nodeName() { - return "#comment"; - } - - /** - Get the contents of the comment. - @return comment content - */ - public String getData() { - return attributes.get(COMMENT_KEY); - } - - void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out) { - if (out.prettyPrint()) - indent(accum, depth, out); - accum - .append("<!--") - .append(getData()) - .append("-->"); - } - - void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out) {} - - public String toString() { - return outerHtml(); - } -} diff --git a/src/org/jsoup/nodes/DataNode.java b/src/org/jsoup/nodes/DataNode.java deleted file mode 100644 index a64f56f0a4..0000000000 --- a/src/org/jsoup/nodes/DataNode.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.jsoup.nodes; - -/** - A data node, for contents of style, script tags etc, where contents should not show in text(). - - @author Jonathan Hedley, jonathan@hedley.net */ -public class DataNode extends Node{ - private static final String DATA_KEY = "data"; - - /** - Create a new DataNode. - @param data data contents - @param baseUri base URI - */ - public DataNode(String data, String baseUri) { - super(baseUri); - attributes.put(DATA_KEY, data); - } - - public String nodeName() { - return "#data"; - } - - /** - Get the data contents of this node. Will be unescaped and with original new lines, space etc. - @return data - */ - public String getWholeData() { - return attributes.get(DATA_KEY); - } - - /** - * Set the data contents of this node. - * @param data unencoded data - * @return this node, for chaining - */ - public DataNode setWholeData(String data) { - attributes.put(DATA_KEY, data); - return this; - } - - void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out) { - accum.append(getWholeData()); // data is not escaped in return from data nodes, so " in script, style is plain - } - - void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out) {} - - public String toString() { - return outerHtml(); - } - - /** - Create a new DataNode from HTML encoded data. - @param encodedData encoded data - @param baseUri bass URI - @return new DataNode - */ - public static DataNode createFromEncoded(String encodedData, String baseUri) { - String data = Entities.unescape(encodedData); - return new DataNode(data, baseUri); - } -} diff --git a/src/org/jsoup/nodes/Document.java b/src/org/jsoup/nodes/Document.java deleted file mode 100644 index adb371ce14..0000000000 --- a/src/org/jsoup/nodes/Document.java +++ /dev/null @@ -1,350 +0,0 @@ -package org.jsoup.nodes; - -import org.jsoup.helper.Validate; -import org.jsoup.parser.Tag; -import org.jsoup.select.Elements; - -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.util.ArrayList; -import java.util.List; - -/** - A HTML Document. - - @author Jonathan Hedley, jonathan@hedley.net */ -public class Document extends Element { - private OutputSettings outputSettings = new OutputSettings(); - private QuirksMode quirksMode = QuirksMode.noQuirks; - - /** - Create a new, empty Document. - @param baseUri base URI of document - @see org.jsoup.Jsoup#parse - @see #createShell - */ - public Document(String baseUri) { - super(Tag.valueOf("#root"), baseUri); - } - - /** - Create a valid, empty shell of a document, suitable for adding more elements to. - @param baseUri baseUri of document - @return document with html, head, and body elements. - */ - static public Document createShell(String baseUri) { - Validate.notNull(baseUri); - - Document doc = new Document(baseUri); - Element html = doc.appendElement("html"); - html.appendElement("head"); - html.appendElement("body"); - - return doc; - } - - /** - Accessor to the document's {@code head} element. - @return {@code head} - */ - public Element head() { - return findFirstElementByTagName("head", this); - } - - /** - Accessor to the document's {@code body} element. - @return {@code body} - */ - public Element body() { - return findFirstElementByTagName("body", this); - } - - /** - Get the string contents of the document's {@code title} element. - @return Trimmed title, or empty string if none set. - */ - public String title() { - Element titleEl = getElementsByTag("title").first(); - return titleEl != null ? titleEl.text().trim() : ""; - } - - /** - Set the document's {@code title} element. Updates the existing element, or adds {@code title} to {@code head} if - not present - @param title string to set as title - */ - public void title(String title) { - Validate.notNull(title); - Element titleEl = getElementsByTag("title").first(); - if (titleEl == null) { // add to head - head().appendElement("title").text(title); - } else { - titleEl.text(title); - } - } - - /** - Create a new Element, with this document's base uri. Does not make the new element a child of this document. - @param tagName element tag name (e.g. {@code a}) - @return new element - */ - public Element createElement(String tagName) { - return new Element(Tag.valueOf(tagName), this.baseUri()); - } - - /** - Normalise the document. This happens after the parse phase so generally does not need to be called. - Moves any text content that is not in the body element into the body. - @return this document after normalisation - */ - public Document normalise() { - Element htmlEl = findFirstElementByTagName("html", this); - if (htmlEl == null) - htmlEl = appendElement("html"); - if (head() == null) - htmlEl.prependElement("head"); - if (body() == null) - htmlEl.appendElement("body"); - - // pull text nodes out of root, html, and head els, and push into body. non-text nodes are already taken care - // of. do in inverse order to maintain text order. - normaliseTextNodes(head()); - normaliseTextNodes(htmlEl); - normaliseTextNodes(this); - - normaliseStructure("head", htmlEl); - normaliseStructure("body", htmlEl); - - return this; - } - - // does not recurse. - private void normaliseTextNodes(Element element) { - List<Node> toMove = new ArrayList<Node>(); - for (Node node: element.childNodes) { - if (node instanceof TextNode) { - TextNode tn = (TextNode) node; - if (!tn.isBlank()) - toMove.add(tn); - } - } - - for (int i = toMove.size()-1; i >= 0; i--) { - Node node = toMove.get(i); - element.removeChild(node); - body().prependChild(new TextNode(" ", "")); - body().prependChild(node); - } - } - - // merge multiple <head> or <body> contents into one, delete the remainder, and ensure they are owned by <html> - private void normaliseStructure(String tag, Element htmlEl) { - Elements elements = this.getElementsByTag(tag); - Element master = elements.first(); // will always be available as created above if not existent - if (elements.size() > 1) { // dupes, move contents to master - List<Node> toMove = new ArrayList<Node>(); - for (int i = 1; i < elements.size(); i++) { - Node dupe = elements.get(i); - for (Node node : dupe.childNodes) - toMove.add(node); - dupe.remove(); - } - - for (Node dupe : toMove) - master.appendChild(dupe); - } - // ensure parented by <html> - if (!master.parent().equals(htmlEl)) { - htmlEl.appendChild(master); // includes remove() - } - } - - // fast method to get first by tag name, used for html, head, body finders - private Element findFirstElementByTagName(String tag, Node node) { - if (node.nodeName().equals(tag)) - return (Element) node; - else { - for (Node child: node.childNodes) { - Element found = findFirstElementByTagName(tag, child); - if (found != null) - return found; - } - } - return null; - } - - @Override - public String outerHtml() { - return super.html(); // no outer wrapper tag - } - - /** - Set the text of the {@code body} of this document. Any existing nodes within the body will be cleared. - @param text unencoded text - @return this document - */ - @Override - public Element text(String text) { - body().text(text); // overridden to not nuke doc structure - return this; - } - - @Override - public String nodeName() { - return "#document"; - } - - @Override - public Document clone() { - Document clone = (Document) super.clone(); - clone.outputSettings = this.outputSettings.clone(); - return clone; - } - - /** - * A Document's output settings control the form of the text() and html() methods. - */ - public static class OutputSettings implements Cloneable { - private Entities.EscapeMode escapeMode = Entities.EscapeMode.base; - private Charset charset = Charset.forName("UTF-8"); - private CharsetEncoder charsetEncoder = charset.newEncoder(); - private boolean prettyPrint = true; - private int indentAmount = 1; - - public OutputSettings() {} - - /** - * Get the document's current HTML escape mode: <code>base</code>, which provides a limited set of named HTML - * entities and escapes other characters as numbered entities for maximum compatibility; or <code>extended</code>, - * which uses the complete set of HTML named entities. - * <p> - * The default escape mode is <code>base</code>. - * @return the document's current escape mode - */ - public Entities.EscapeMode escapeMode() { - return escapeMode; - } - - /** - * Set the document's escape mode - * @param escapeMode the new escape mode to use - * @return the document's output settings, for chaining - */ - public OutputSettings escapeMode(Entities.EscapeMode escapeMode) { - this.escapeMode = escapeMode; - return this; - } - - /** - * Get the document's current output charset, which is used to control which characters are escaped when - * generating HTML (via the <code>html()</code> methods), and which are kept intact. - * <p> - * Where possible (when parsing from a URL or File), the document's output charset is automatically set to the - * input charset. Otherwise, it defaults to UTF-8. - * @return the document's current charset. - */ - public Charset charset() { - return charset; - } - - /** - * Update the document's output charset. - * @param charset the new charset to use. - * @return the document's output settings, for chaining - */ - public OutputSettings charset(Charset charset) { - // todo: this should probably update the doc's meta charset - this.charset = charset; - charsetEncoder = charset.newEncoder(); - return this; - } - - /** - * Update the document's output charset. - * @param charset the new charset (by name) to use. - * @return the document's output settings, for chaining - */ - public OutputSettings charset(String charset) { - charset(Charset.forName(charset)); - return this; - } - - CharsetEncoder encoder() { - return charsetEncoder; - } - - /** - * Get if pretty printing is enabled. Default is true. If disabled, the HTML output methods will not re-format - * the output, and the output will generally look like the input. - * @return if pretty printing is enabled. - */ - public boolean prettyPrint() { - return prettyPrint; - } - - /** - * Enable or disable pretty printing. - * @param pretty new pretty print setting - * @return this, for chaining - */ - public OutputSettings prettyPrint(boolean pretty) { - prettyPrint = pretty; - return this; - } - - /** - * Get the current tag indent amount, used when pretty printing. - * @return the current indent amount - */ - public int indentAmount() { - return indentAmount; - } - - /** - * Set the indent amount for pretty printing - * @param indentAmount number of spaces to use for indenting each level. Must be >= 0. - * @return this, for chaining - */ - public OutputSettings indentAmount(int indentAmount) { - Validate.isTrue(indentAmount >= 0); - this.indentAmount = indentAmount; - return this; - } - - @Override - public OutputSettings clone() { - OutputSettings clone; - try { - clone = (OutputSettings) super.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - clone.charset(charset.name()); // new charset and charset encoder - clone.escapeMode = Entities.EscapeMode.valueOf(escapeMode.name()); - // indentAmount, prettyPrint are primitives so object.clone() will handle - return clone; - } - } - - /** - * Get the document's current output settings. - * @return the document's current output settings. - */ - public OutputSettings outputSettings() { - return outputSettings; - } - - public enum QuirksMode { - noQuirks, quirks, limitedQuirks; - } - - public QuirksMode quirksMode() { - return quirksMode; - } - - public Document quirksMode(QuirksMode quirksMode) { - this.quirksMode = quirksMode; - return this; - } -} - diff --git a/src/org/jsoup/nodes/DocumentType.java b/src/org/jsoup/nodes/DocumentType.java deleted file mode 100644 index f8c79f0d18..0000000000 --- a/src/org/jsoup/nodes/DocumentType.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.jsoup.nodes; - -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; - -/** - * A {@code <!DOCTPYE>} node. - */ -public class DocumentType extends Node { - // todo: quirk mode from publicId and systemId - - /** - * Create a new doctype element. - * @param name the doctype's name - * @param publicId the doctype's public ID - * @param systemId the doctype's system ID - * @param baseUri the doctype's base URI - */ - public DocumentType(String name, String publicId, String systemId, String baseUri) { - super(baseUri); - - Validate.notEmpty(name); - attr("name", name); - attr("publicId", publicId); - attr("systemId", systemId); - } - - @Override - public String nodeName() { - return "#doctype"; - } - - @Override - void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out) { - accum.append("<!DOCTYPE ").append(attr("name")); - if (!StringUtil.isBlank(attr("publicId"))) - accum.append(" PUBLIC \"").append(attr("publicId")).append("\""); - if (!StringUtil.isBlank(attr("systemId"))) - accum.append(" \"").append(attr("systemId")).append("\""); - accum.append('>'); - } - - @Override - void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out) { - } -} diff --git a/src/org/jsoup/nodes/Element.java b/src/org/jsoup/nodes/Element.java deleted file mode 100644 index 5c1894c934..0000000000 --- a/src/org/jsoup/nodes/Element.java +++ /dev/null @@ -1,1119 +0,0 @@ -package org.jsoup.nodes; - -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; -import org.jsoup.parser.Parser; -import org.jsoup.parser.Tag; -import org.jsoup.select.Collector; -import org.jsoup.select.Elements; -import org.jsoup.select.Evaluator; -import org.jsoup.select.Selector; - -import java.util.*; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - * A HTML element consists of a tag name, attributes, and child nodes (including text nodes and - * other elements). - * - * From an Element, you can extract data, traverse the node graph, and manipulate the HTML. - * - * @author Jonathan Hedley, jonathan@hedley.net - */ -public class Element extends Node { - private Tag tag; - private Set<String> classNames; - - /** - * Create a new, standalone Element. (Standalone in that is has no parent.) - * - * @param tag tag of this element - * @param baseUri the base URI - * @param attributes initial attributes - * @see #appendChild(Node) - * @see #appendElement(String) - */ - public Element(Tag tag, String baseUri, Attributes attributes) { - super(baseUri, attributes); - - Validate.notNull(tag); - this.tag = tag; - } - - /** - * Create a new Element from a tag and a base URI. - * - * @param tag element tag - * @param baseUri the base URI of this element. It is acceptable for the base URI to be an empty - * string, but not null. - * @see Tag#valueOf(String) - */ - public Element(Tag tag, String baseUri) { - this(tag, baseUri, new Attributes()); - } - - @Override - public String nodeName() { - return tag.getName(); - } - - /** - * Get the name of the tag for this element. E.g. {@code div} - * - * @return the tag name - */ - public String tagName() { - return tag.getName(); - } - - /** - * Change the tag of this element. For example, convert a {@code <span>} to a {@code <div>} with - * {@code el.tagName("div");}. - * - * @param tagName new tag name for this element - * @return this element, for chaining - */ - public Element tagName(String tagName) { - Validate.notEmpty(tagName, "Tag name must not be empty."); - tag = Tag.valueOf(tagName); - return this; - } - - /** - * Get the Tag for this element. - * - * @return the tag object - */ - public Tag tag() { - return tag; - } - - /** - * Test if this element is a block-level element. (E.g. {@code <div> == true} or an inline element - * {@code <p> == false}). - * - * @return true if block, false if not (and thus inline) - */ - public boolean isBlock() { - return tag.isBlock(); - } - - /** - * Get the {@code id} attribute of this element. - * - * @return The id attribute, if present, or an empty string if not. - */ - public String id() { - String id = attr("id"); - return id == null ? "" : id; - } - - /** - * Set an attribute value on this element. If this element already has an attribute with the - * key, its value is updated; otherwise, a new attribute is added. - * - * @return this element - */ - public Element attr(String attributeKey, String attributeValue) { - super.attr(attributeKey, attributeValue); - return this; - } - - /** - * Get this element's HTML5 custom data attributes. Each attribute in the element that has a key - * starting with "data-" is included the dataset. - * <p> - * E.g., the element {@code <div data-package="jsoup" data-language="Java" class="group">...} has the dataset - * {@code package=jsoup, language=java}. - * <p> - * This map is a filtered view of the element's attribute map. Changes to one map (add, remove, update) are reflected - * in the other map. - * <p> - * You can find elements that have data attributes using the {@code [^data-]} attribute key prefix selector. - * @return a map of {@code key=value} custom data attributes. - */ - public Map<String, String> dataset() { - return attributes.dataset(); - } - - @Override - public final Element parent() { - return (Element) parentNode; - } - - /** - * Get this element's parent and ancestors, up to the document root. - * @return this element's stack of parents, closest first. - */ - public Elements parents() { - Elements parents = new Elements(); - accumulateParents(this, parents); - return parents; - } - - private static void accumulateParents(Element el, Elements parents) { - Element parent = el.parent(); - if (parent != null && !parent.tagName().equals("#root")) { - parents.add(parent); - accumulateParents(parent, parents); - } - } - - /** - * Get a child element of this element, by its 0-based index number. - * <p/> - * Note that an element can have both mixed Nodes and Elements as children. This method inspects - * a filtered list of children that are elements, and the index is based on that filtered list. - * - * @param index the index number of the element to retrieve - * @return the child element, if it exists, or {@code null} if absent. - * @see #childNode(int) - */ - public Element child(int index) { - return children().get(index); - } - - /** - * Get this element's child elements. - * <p/> - * This is effectively a filter on {@link #childNodes()} to get Element nodes. - * @return child elements. If this element has no children, returns an - * empty list. - * @see #childNodes() - */ - public Elements children() { - // create on the fly rather than maintaining two lists. if gets slow, memoize, and mark dirty on change - List<Element> elements = new ArrayList<Element>(); - for (Node node : childNodes) { - if (node instanceof Element) - elements.add((Element) node); - } - return new Elements(elements); - } - - /** - * Get this element's child text nodes. The list is unmodifiable but the text nodes may be manipulated. - * <p/> - * This is effectively a filter on {@link #childNodes()} to get Text nodes. - * @return child text nodes. If this element has no text nodes, returns an - * empty list. - * <p/> - * For example, with the input HTML: {@code <p>One <span>Two</span> Three <br> Four</p>} with the {@code p} element selected: - * <ul> - * <li>{@code p.text()} = {@code "One Two Three Four"}</li> - * <li>{@code p.ownText()} = {@code "One Three Four"}</li> - * <li>{@code p.children()} = {@code Elements[<span>, <br>]}</li> - * <li>{@code p.childNodes()} = {@code List<Node>["One ", <span>, " Three ", <br>, " Four"]}</li> - * <li>{@code p.textNodes()} = {@code List<TextNode>["One ", " Three ", " Four"]}</li> - * </ul> - */ - public List<TextNode> textNodes() { - List<TextNode> textNodes = new ArrayList<TextNode>(); - for (Node node : childNodes) { - if (node instanceof TextNode) - textNodes.add((TextNode) node); - } - return Collections.unmodifiableList(textNodes); - } - - /** - * Get this element's child data nodes. The list is unmodifiable but the data nodes may be manipulated. - * <p/> - * This is effectively a filter on {@link #childNodes()} to get Data nodes. - * @return child data nodes. If this element has no data nodes, returns an - * empty list. - * @see #data() - */ - public List<DataNode> dataNodes() { - List<DataNode> dataNodes = new ArrayList<DataNode>(); - for (Node node : childNodes) { - if (node instanceof DataNode) - dataNodes.add((DataNode) node); - } - return Collections.unmodifiableList(dataNodes); - } - - /** - * Find elements that match the {@link Selector} CSS query, with this element as the starting context. Matched elements - * may include this element, or any of its children. - * <p/> - * This method is generally more powerful to use than the DOM-type {@code getElementBy*} methods, because - * multiple filters can be combined, e.g.: - * <ul> - * <li>{@code el.select("a[href]")} - finds links ({@code a} tags with {@code href} attributes) - * <li>{@code el.select("a[href*=example.com]")} - finds links pointing to example.com (loosely) - * </ul> - * <p/> - * See the query syntax documentation in {@link org.jsoup.select.Selector}. - * - * @param cssQuery a {@link Selector} CSS-like query - * @return elements that match the query (empty if none match) - * @see org.jsoup.select.Selector - */ - public Elements select(String cssQuery) { - return Selector.select(cssQuery, this); - } - - /** - * Add a node child node to this element. - * - * @param child node to add. Must not already have a parent. - * @return this element, so that you can add more child nodes or elements. - */ - public Element appendChild(Node child) { - Validate.notNull(child); - - addChildren(child); - return this; - } - - /** - * Add a node to the start of this element's children. - * - * @param child node to add. Must not already have a parent. - * @return this element, so that you can add more child nodes or elements. - */ - public Element prependChild(Node child) { - Validate.notNull(child); - - addChildren(0, child); - return this; - } - - /** - * Create a new element by tag name, and add it as the last child. - * - * @param tagName the name of the tag (e.g. {@code div}). - * @return the new element, to allow you to add content to it, e.g.: - * {@code parent.appendElement("h1").attr("id", "header").text("Welcome");} - */ - public Element appendElement(String tagName) { - Element child = new Element(Tag.valueOf(tagName), baseUri()); - appendChild(child); - return child; - } - - /** - * Create a new element by tag name, and add it as the first child. - * - * @param tagName the name of the tag (e.g. {@code div}). - * @return the new element, to allow you to add content to it, e.g.: - * {@code parent.prependElement("h1").attr("id", "header").text("Welcome");} - */ - public Element prependElement(String tagName) { - Element child = new Element(Tag.valueOf(tagName), baseUri()); - prependChild(child); - return child; - } - - /** - * Create and append a new TextNode to this element. - * - * @param text the unencoded text to add - * @return this element - */ - public Element appendText(String text) { - TextNode node = new TextNode(text, baseUri()); - appendChild(node); - return this; - } - - /** - * Create and prepend a new TextNode to this element. - * - * @param text the unencoded text to add - * @return this element - */ - public Element prependText(String text) { - TextNode node = new TextNode(text, baseUri()); - prependChild(node); - return this; - } - - /** - * Add inner HTML to this element. The supplied HTML will be parsed, and each node appended to the end of the children. - * @param html HTML to add inside this element, after the existing HTML - * @return this element - * @see #html(String) - */ - public Element append(String html) { - Validate.notNull(html); - - List<Node> nodes = Parser.parseFragment(html, this, baseUri()); - addChildren(nodes.toArray(new Node[nodes.size()])); - return this; - } - - /** - * Add inner HTML into this element. The supplied HTML will be parsed, and each node prepended to the start of the element's children. - * @param html HTML to add inside this element, before the existing HTML - * @return this element - * @see #html(String) - */ - public Element prepend(String html) { - Validate.notNull(html); - - List<Node> nodes = Parser.parseFragment(html, this, baseUri()); - addChildren(0, nodes.toArray(new Node[nodes.size()])); - return this; - } - - /** - * Insert the specified HTML into the DOM before this element (i.e. as a preceding sibling). - * - * @param html HTML to add before this element - * @return this element, for chaining - * @see #after(String) - */ - @Override - public Element before(String html) { - return (Element) super.before(html); - } - - /** - * Insert the specified node into the DOM before this node (i.e. as a preceding sibling). - * @param node to add before this element - * @return this Element, for chaining - * @see #after(Node) - */ - @Override - public Element before(Node node) { - return (Element) super.before(node); - } - - /** - * Insert the specified HTML into the DOM after this element (i.e. as a following sibling). - * - * @param html HTML to add after this element - * @return this element, for chaining - * @see #before(String) - */ - @Override - public Element after(String html) { - return (Element) super.after(html); - } - - /** - * Insert the specified node into the DOM after this node (i.e. as a following sibling). - * @param node to add after this element - * @return this element, for chaining - * @see #before(Node) - */ - @Override - public Element after(Node node) { - return (Element) super.after(node); - } - - /** - * Remove all of the element's child nodes. Any attributes are left as-is. - * @return this element - */ - public Element empty() { - childNodes.clear(); - return this; - } - - /** - * Wrap the supplied HTML around this element. - * - * @param html HTML to wrap around this element, e.g. {@code <div class="head"></div>}. Can be arbitrarily deep. - * @return this element, for chaining. - */ - @Override - public Element wrap(String html) { - return (Element) super.wrap(html); - } - - /** - * Get sibling elements. If the element has no sibling elements, returns an empty list. An element is not a sibling - * of itself, so will not be included in the returned list. - * @return sibling elements - */ - public Elements siblingElements() { - if (parentNode == null) - return new Elements(0); - - List<Element> elements = parent().children(); - Elements siblings = new Elements(elements.size() - 1); - for (Element el: elements) - if (el != this) - siblings.add(el); - return siblings; - } - - /** - * Gets the next sibling element of this element. E.g., if a {@code div} contains two {@code p}s, - * the {@code nextElementSibling} of the first {@code p} is the second {@code p}. - * <p/> - * This is similar to {@link #nextSibling()}, but specifically finds only Elements - * @return the next element, or null if there is no next element - * @see #previousElementSibling() - */ - public Element nextElementSibling() { - if (parentNode == null) return null; - List<Element> siblings = parent().children(); - Integer index = indexInList(this, siblings); - Validate.notNull(index); - if (siblings.size() > index+1) - return siblings.get(index+1); - else - return null; - } - - /** - * Gets the previous element sibling of this element. - * @return the previous element, or null if there is no previous element - * @see #nextElementSibling() - */ - public Element previousElementSibling() { - if (parentNode == null) return null; - List<Element> siblings = parent().children(); - Integer index = indexInList(this, siblings); - Validate.notNull(index); - if (index > 0) - return siblings.get(index-1); - else - return null; - } - - /** - * Gets the first element sibling of this element. - * @return the first sibling that is an element (aka the parent's first element child) - */ - public Element firstElementSibling() { - // todo: should firstSibling() exclude this? - List<Element> siblings = parent().children(); - return siblings.size() > 1 ? siblings.get(0) : null; - } - - /** - * Get the list index of this element in its element sibling list. I.e. if this is the first element - * sibling, returns 0. - * @return position in element sibling list - */ - public Integer elementSiblingIndex() { - if (parent() == null) return 0; - return indexInList(this, parent().children()); - } - - /** - * Gets the last element sibling of this element - * @return the last sibling that is an element (aka the parent's last element child) - */ - public Element lastElementSibling() { - List<Element> siblings = parent().children(); - return siblings.size() > 1 ? siblings.get(siblings.size() - 1) : null; - } - - private static <E extends Element> Integer indexInList(Element search, List<E> elements) { - Validate.notNull(search); - Validate.notNull(elements); - - for (int i = 0; i < elements.size(); i++) { - E element = elements.get(i); - if (element.equals(search)) - return i; - } - return null; - } - - // DOM type methods - - /** - * Finds elements, including and recursively under this element, with the specified tag name. - * @param tagName The tag name to search for (case insensitively). - * @return a matching unmodifiable list of elements. Will be empty if this element and none of its children match. - */ - public Elements getElementsByTag(String tagName) { - Validate.notEmpty(tagName); - tagName = tagName.toLowerCase().trim(); - - return Collector.collect(new Evaluator.Tag(tagName), this); - } - - /** - * Find an element by ID, including or under this element. - * <p> - * Note that this finds the first matching ID, starting with this element. If you search down from a different - * starting point, it is possible to find a different element by ID. For unique element by ID within a Document, - * use {@link Document#getElementById(String)} - * @param id The ID to search for. - * @return The first matching element by ID, starting with this element, or null if none found. - */ - public Element getElementById(String id) { - Validate.notEmpty(id); - - Elements elements = Collector.collect(new Evaluator.Id(id), this); - if (elements.size() > 0) - return elements.get(0); - else - return null; - } - - /** - * Find elements that have this class, including or under this element. Case insensitive. - * <p> - * Elements can have multiple classes (e.g. {@code <div class="header round first">}. This method - * checks each class, so you can find the above with {@code el.getElementsByClass("header");}. - * - * @param className the name of the class to search for. - * @return elements with the supplied class name, empty if none - * @see #hasClass(String) - * @see #classNames() - */ - public Elements getElementsByClass(String className) { - Validate.notEmpty(className); - - return Collector.collect(new Evaluator.Class(className), this); - } - - /** - * Find elements that have a named attribute set. Case insensitive. - * - * @param key name of the attribute, e.g. {@code href} - * @return elements that have this attribute, empty if none - */ - public Elements getElementsByAttribute(String key) { - Validate.notEmpty(key); - key = key.trim().toLowerCase(); - - return Collector.collect(new Evaluator.Attribute(key), this); - } - - /** - * Find elements that have an attribute name starting with the supplied prefix. Use {@code data-} to find elements - * that have HTML5 datasets. - * @param keyPrefix name prefix of the attribute e.g. {@code data-} - * @return elements that have attribute names that start with with the prefix, empty if none. - */ - public Elements getElementsByAttributeStarting(String keyPrefix) { - Validate.notEmpty(keyPrefix); - keyPrefix = keyPrefix.trim().toLowerCase(); - - return Collector.collect(new Evaluator.AttributeStarting(keyPrefix), this); - } - - /** - * Find elements that have an attribute with the specific value. Case insensitive. - * - * @param key name of the attribute - * @param value value of the attribute - * @return elements that have this attribute with this value, empty if none - */ - public Elements getElementsByAttributeValue(String key, String value) { - return Collector.collect(new Evaluator.AttributeWithValue(key, value), this); - } - - /** - * Find elements that either do not have this attribute, or have it with a different value. Case insensitive. - * - * @param key name of the attribute - * @param value value of the attribute - * @return elements that do not have a matching attribute - */ - public Elements getElementsByAttributeValueNot(String key, String value) { - return Collector.collect(new Evaluator.AttributeWithValueNot(key, value), this); - } - - /** - * Find elements that have attributes that start with the value prefix. Case insensitive. - * - * @param key name of the attribute - * @param valuePrefix start of attribute value - * @return elements that have attributes that start with the value prefix - */ - public Elements getElementsByAttributeValueStarting(String key, String valuePrefix) { - return Collector.collect(new Evaluator.AttributeWithValueStarting(key, valuePrefix), this); - } - - /** - * Find elements that have attributes that end with the value suffix. Case insensitive. - * - * @param key name of the attribute - * @param valueSuffix end of the attribute value - * @return elements that have attributes that end with the value suffix - */ - public Elements getElementsByAttributeValueEnding(String key, String valueSuffix) { - return Collector.collect(new Evaluator.AttributeWithValueEnding(key, valueSuffix), this); - } - - /** - * Find elements that have attributes whose value contains the match string. Case insensitive. - * - * @param key name of the attribute - * @param match substring of value to search for - * @return elements that have attributes containing this text - */ - public Elements getElementsByAttributeValueContaining(String key, String match) { - return Collector.collect(new Evaluator.AttributeWithValueContaining(key, match), this); - } - - /** - * Find elements that have attributes whose values match the supplied regular expression. - * @param key name of the attribute - * @param pattern compiled regular expression to match against attribute values - * @return elements that have attributes matching this regular expression - */ - public Elements getElementsByAttributeValueMatching(String key, Pattern pattern) { - return Collector.collect(new Evaluator.AttributeWithValueMatching(key, pattern), this); - - } - - /** - * Find elements that have attributes whose values match the supplied regular expression. - * @param key name of the attribute - * @param regex regular expression to match against attribute values. You can use <a href="http://java.sun.com/docs/books/tutorial/essential/regex/pattern.html#embedded">embedded flags</a> (such as (?i) and (?m) to control regex options. - * @return elements that have attributes matching this regular expression - */ - public Elements getElementsByAttributeValueMatching(String key, String regex) { - Pattern pattern; - try { - pattern = Pattern.compile(regex); - } catch (PatternSyntaxException e) { - throw new IllegalArgumentException("Pattern syntax error: " + regex, e); - } - return getElementsByAttributeValueMatching(key, pattern); - } - - /** - * Find elements whose sibling index is less than the supplied index. - * @param index 0-based index - * @return elements less than index - */ - public Elements getElementsByIndexLessThan(int index) { - return Collector.collect(new Evaluator.IndexLessThan(index), this); - } - - /** - * Find elements whose sibling index is greater than the supplied index. - * @param index 0-based index - * @return elements greater than index - */ - public Elements getElementsByIndexGreaterThan(int index) { - return Collector.collect(new Evaluator.IndexGreaterThan(index), this); - } - - /** - * Find elements whose sibling index is equal to the supplied index. - * @param index 0-based index - * @return elements equal to index - */ - public Elements getElementsByIndexEquals(int index) { - return Collector.collect(new Evaluator.IndexEquals(index), this); - } - - /** - * Find elements that contain the specified string. The search is case insensitive. The text may appear directly - * in the element, or in any of its descendants. - * @param searchText to look for in the element's text - * @return elements that contain the string, case insensitive. - * @see Element#text() - */ - public Elements getElementsContainingText(String searchText) { - return Collector.collect(new Evaluator.ContainsText(searchText), this); - } - - /** - * Find elements that directly contain the specified string. The search is case insensitive. The text must appear directly - * in the element, not in any of its descendants. - * @param searchText to look for in the element's own text - * @return elements that contain the string, case insensitive. - * @see Element#ownText() - */ - public Elements getElementsContainingOwnText(String searchText) { - return Collector.collect(new Evaluator.ContainsOwnText(searchText), this); - } - - /** - * Find elements whose text matches the supplied regular expression. - * @param pattern regular expression to match text against - * @return elements matching the supplied regular expression. - * @see Element#text() - */ - public Elements getElementsMatchingText(Pattern pattern) { - return Collector.collect(new Evaluator.Matches(pattern), this); - } - - /** - * Find elements whose text matches the supplied regular expression. - * @param regex regular expression to match text against. You can use <a href="http://java.sun.com/docs/books/tutorial/essential/regex/pattern.html#embedded">embedded flags</a> (such as (?i) and (?m) to control regex options. - * @return elements matching the supplied regular expression. - * @see Element#text() - */ - public Elements getElementsMatchingText(String regex) { - Pattern pattern; - try { - pattern = Pattern.compile(regex); - } catch (PatternSyntaxException e) { - throw new IllegalArgumentException("Pattern syntax error: " + regex, e); - } - return getElementsMatchingText(pattern); - } - - /** - * Find elements whose own text matches the supplied regular expression. - * @param pattern regular expression to match text against - * @return elements matching the supplied regular expression. - * @see Element#ownText() - */ - public Elements getElementsMatchingOwnText(Pattern pattern) { - return Collector.collect(new Evaluator.MatchesOwn(pattern), this); - } - - /** - * Find elements whose text matches the supplied regular expression. - * @param regex regular expression to match text against. You can use <a href="http://java.sun.com/docs/books/tutorial/essential/regex/pattern.html#embedded">embedded flags</a> (such as (?i) and (?m) to control regex options. - * @return elements matching the supplied regular expression. - * @see Element#ownText() - */ - public Elements getElementsMatchingOwnText(String regex) { - Pattern pattern; - try { - pattern = Pattern.compile(regex); - } catch (PatternSyntaxException e) { - throw new IllegalArgumentException("Pattern syntax error: " + regex, e); - } - return getElementsMatchingOwnText(pattern); - } - - /** - * Find all elements under this element (including self, and children of children). - * - * @return all elements - */ - public Elements getAllElements() { - return Collector.collect(new Evaluator.AllElements(), this); - } - - /** - * Gets the combined text of this element and all its children. - * <p> - * For example, given HTML {@code <p>Hello <b>there</b> now!</p>}, {@code p.text()} returns {@code "Hello there now!"} - * - * @return unencoded text, or empty string if none. - * @see #ownText() - * @see #textNodes() - */ - public String text() { - StringBuilder sb = new StringBuilder(); - text(sb); - return sb.toString().trim(); - } - - private void text(StringBuilder accum) { - appendWhitespaceIfBr(this, accum); - - for (Node child : childNodes) { - if (child instanceof TextNode) { - TextNode textNode = (TextNode) child; - appendNormalisedText(accum, textNode); - } else if (child instanceof Element) { - Element element = (Element) child; - if (accum.length() > 0 && element.isBlock() && !TextNode.lastCharIsWhitespace(accum)) - accum.append(" "); - element.text(accum); - } - } - } - - /** - * Gets the text owned by this element only; does not get the combined text of all children. - * <p> - * For example, given HTML {@code <p>Hello <b>there</b> now!</p>}, {@code p.ownText()} returns {@code "Hello now!"}, - * whereas {@code p.text()} returns {@code "Hello there now!"}. - * Note that the text within the {@code b} element is not returned, as it is not a direct child of the {@code p} element. - * - * @return unencoded text, or empty string if none. - * @see #text() - * @see #textNodes() - */ - public String ownText() { - StringBuilder sb = new StringBuilder(); - ownText(sb); - return sb.toString().trim(); - } - - private void ownText(StringBuilder accum) { - for (Node child : childNodes) { - if (child instanceof TextNode) { - TextNode textNode = (TextNode) child; - appendNormalisedText(accum, textNode); - } else if (child instanceof Element) { - appendWhitespaceIfBr((Element) child, accum); - } - } - } - - private void appendNormalisedText(StringBuilder accum, TextNode textNode) { - String text = textNode.getWholeText(); - - if (!preserveWhitespace()) { - text = TextNode.normaliseWhitespace(text); - if (TextNode.lastCharIsWhitespace(accum)) - text = TextNode.stripLeadingWhitespace(text); - } - accum.append(text); - } - - private static void appendWhitespaceIfBr(Element element, StringBuilder accum) { - if (element.tag.getName().equals("br") && !TextNode.lastCharIsWhitespace(accum)) - accum.append(" "); - } - - boolean preserveWhitespace() { - return tag.preserveWhitespace() || parent() != null && parent().preserveWhitespace(); - } - - /** - * Set the text of this element. Any existing contents (text or elements) will be cleared - * @param text unencoded text - * @return this element - */ - public Element text(String text) { - Validate.notNull(text); - - empty(); - TextNode textNode = new TextNode(text, baseUri); - appendChild(textNode); - - return this; - } - - /** - Test if this element has any text content (that is not just whitespace). - @return true if element has non-blank text content. - */ - public boolean hasText() { - for (Node child: childNodes) { - if (child instanceof TextNode) { - TextNode textNode = (TextNode) child; - if (!textNode.isBlank()) - return true; - } else if (child instanceof Element) { - Element el = (Element) child; - if (el.hasText()) - return true; - } - } - return false; - } - - /** - * Get the combined data of this element. Data is e.g. the inside of a {@code script} tag. - * @return the data, or empty string if none - * - * @see #dataNodes() - */ - public String data() { - StringBuilder sb = new StringBuilder(); - - for (Node childNode : childNodes) { - if (childNode instanceof DataNode) { - DataNode data = (DataNode) childNode; - sb.append(data.getWholeData()); - } else if (childNode instanceof Element) { - Element element = (Element) childNode; - String elementData = element.data(); - sb.append(elementData); - } - } - return sb.toString(); - } - - /** - * Gets the literal value of this element's "class" attribute, which may include multiple class names, space - * separated. (E.g. on <code><div class="header gray"></code> returns, "<code>header gray</code>") - * @return The literal class attribute, or <b>empty string</b> if no class attribute set. - */ - public String className() { - return attr("class"); - } - - /** - * Get all of the element's class names. E.g. on element {@code <div class="header gray"}>}, - * returns a set of two elements {@code "header", "gray"}. Note that modifications to this set are not pushed to - * the backing {@code class} attribute; use the {@link #classNames(java.util.Set)} method to persist them. - * @return set of classnames, empty if no class attribute - */ - public Set<String> classNames() { - if (classNames == null) { - String[] names = className().split("\\s+"); - classNames = new LinkedHashSet<String>(Arrays.asList(names)); - } - return classNames; - } - - /** - Set the element's {@code class} attribute to the supplied class names. - @param classNames set of classes - @return this element, for chaining - */ - public Element classNames(Set<String> classNames) { - Validate.notNull(classNames); - attributes.put("class", StringUtil.join(classNames, " ")); - return this; - } - - /** - * Tests if this element has a class. Case insensitive. - * @param className name of class to check for - * @return true if it does, false if not - */ - public boolean hasClass(String className) { - Set<String> classNames = classNames(); - for (String name : classNames) { - if (className.equalsIgnoreCase(name)) - return true; - } - return false; - } - - /** - Add a class name to this element's {@code class} attribute. - @param className class name to add - @return this element - */ - public Element addClass(String className) { - Validate.notNull(className); - - Set<String> classes = classNames(); - classes.add(className); - classNames(classes); - - return this; - } - - /** - Remove a class name from this element's {@code class} attribute. - @param className class name to remove - @return this element - */ - public Element removeClass(String className) { - Validate.notNull(className); - - Set<String> classes = classNames(); - classes.remove(className); - classNames(classes); - - return this; - } - - /** - Toggle a class name on this element's {@code class} attribute: if present, remove it; otherwise add it. - @param className class name to toggle - @return this element - */ - public Element toggleClass(String className) { - Validate.notNull(className); - - Set<String> classes = classNames(); - if (classes.contains(className)) - classes.remove(className); - else - classes.add(className); - classNames(classes); - - return this; - } - - /** - * Get the value of a form element (input, textarea, etc). - * @return the value of the form element, or empty string if not set. - */ - public String val() { - if (tagName().equals("textarea")) - return text(); - else - return attr("value"); - } - - /** - * Set the value of a form element (input, textarea, etc). - * @param value value to set - * @return this element (for chaining) - */ - public Element val(String value) { - if (tagName().equals("textarea")) - text(value); - else - attr("value", value); - return this; - } - - void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out) { - if (accum.length() > 0 && out.prettyPrint() && (tag.formatAsBlock() || (parent() != null && parent().tag().formatAsBlock()))) - indent(accum, depth, out); - accum - .append("<") - .append(tagName()); - attributes.html(accum, out); - - if (childNodes.isEmpty() && tag.isSelfClosing()) - accum.append(" />"); - else - accum.append(">"); - } - - void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out) { - if (!(childNodes.isEmpty() && tag.isSelfClosing())) { - if (out.prettyPrint() && !childNodes.isEmpty() && tag.formatAsBlock()) - indent(accum, depth, out); - accum.append("</").append(tagName()).append(">"); - } - } - - /** - * Retrieves the element's inner HTML. E.g. on a {@code <div>} with one empty {@code <p>}, would return - * {@code <p></p>}. (Whereas {@link #outerHtml()} would return {@code <div><p></p></div>}.) - * - * @return String of HTML. - * @see #outerHtml() - */ - public String html() { - StringBuilder accum = new StringBuilder(); - html(accum); - return accum.toString().trim(); - } - - private void html(StringBuilder accum) { - for (Node node : childNodes) - node.outerHtml(accum); - } - - /** - * Set this element's inner HTML. Clears the existing HTML first. - * @param html HTML to parse and set into this element - * @return this element - * @see #append(String) - */ - public Element html(String html) { - empty(); - append(html); - return this; - } - - public String toString() { - return outerHtml(); - } - - @Override - public boolean equals(Object o) { - return this == o; - } - - @Override - public int hashCode() { - // todo: fixup, not very useful - int result = super.hashCode(); - result = 31 * result + (tag != null ? tag.hashCode() : 0); - return result; - } - - @Override - public Element clone() { - Element clone = (Element) super.clone(); - clone.classNames(); // creates linked set of class names from class attribute - return clone; - } -} diff --git a/src/org/jsoup/nodes/Entities.java b/src/org/jsoup/nodes/Entities.java deleted file mode 100644 index 0ae83e1fc0..0000000000 --- a/src/org/jsoup/nodes/Entities.java +++ /dev/null @@ -1,184 +0,0 @@ -package org.jsoup.nodes; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.CharsetEncoder; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * HTML entities, and escape routines. - * Source: <a href="http://www.w3.org/TR/html5/named-character-references.html#named-character-references">W3C HTML - * named character references</a>. - */ -public class Entities { - public enum EscapeMode { - /** Restricted entities suitable for XHTML output: lt, gt, amp, apos, and quot only. */ - xhtml(xhtmlByVal), - /** Default HTML output entities. */ - base(baseByVal), - /** Complete HTML entities. */ - extended(fullByVal); - - private Map<Character, String> map; - - EscapeMode(Map<Character, String> map) { - this.map = map; - } - - public Map<Character, String> getMap() { - return map; - } - } - - private static final Map<String, Character> full; - private static final Map<Character, String> xhtmlByVal; - private static final Map<Character, String> baseByVal; - private static final Map<Character, String> fullByVal; - private static final Pattern unescapePattern = Pattern.compile("&(#(x|X)?([0-9a-fA-F]+)|[a-zA-Z]+\\d*);?"); - private static final Pattern strictUnescapePattern = Pattern.compile("&(#(x|X)?([0-9a-fA-F]+)|[a-zA-Z]+\\d*);"); - - private Entities() {} - - /** - * Check if the input is a known named entity - * @param name the possible entity name (e.g. "lt" or "amp" - * @return true if a known named entity - */ - public static boolean isNamedEntity(String name) { - return full.containsKey(name); - } - - /** - * Get the Character value of the named entity - * @param name named entity (e.g. "lt" or "amp") - * @return the Character value of the named entity (e.g. '<' or '&') - */ - public static Character getCharacterByName(String name) { - return full.get(name); - } - - static String escape(String string, Document.OutputSettings out) { - return escape(string, out.encoder(), out.escapeMode()); - } - - static String escape(String string, CharsetEncoder encoder, EscapeMode escapeMode) { - StringBuilder accum = new StringBuilder(string.length() * 2); - Map<Character, String> map = escapeMode.getMap(); - - for (int pos = 0; pos < string.length(); pos++) { - Character c = string.charAt(pos); - if (map.containsKey(c)) - accum.append('&').append(map.get(c)).append(';'); - else if (encoder.canEncode(c)) - accum.append(c.charValue()); - else - accum.append("&#").append((int) c).append(';'); - } - - return accum.toString(); - } - - static String unescape(String string) { - return unescape(string, false); - } - - /** - * Unescape the input string. - * @param string - * @param strict if "strict" (that is, requires trailing ';' char, otherwise that's optional) - * @return - */ - static String unescape(String string, boolean strict) { - // todo: change this method to use Tokeniser.consumeCharacterReference - if (!string.contains("&")) - return string; - - Matcher m = strict? strictUnescapePattern.matcher(string) : unescapePattern.matcher(string); // &(#(x|X)?([0-9a-fA-F]+)|[a-zA-Z]\\d*);? - StringBuffer accum = new StringBuffer(string.length()); // pity matcher can't use stringbuilder, avoid syncs - // todo: replace m.appendReplacement with own impl, so StringBuilder and quoteReplacement not required - - while (m.find()) { - int charval = -1; - String num = m.group(3); - if (num != null) { - try { - int base = m.group(2) != null ? 16 : 10; // 2 is hex indicator - charval = Integer.valueOf(num, base); - } catch (NumberFormatException e) { - } // skip - } else { - String name = m.group(1); - if (full.containsKey(name)) - charval = full.get(name); - } - - if (charval != -1 || charval > 0xFFFF) { // out of range - String c = Character.toString((char) charval); - m.appendReplacement(accum, Matcher.quoteReplacement(c)); - } else { - m.appendReplacement(accum, Matcher.quoteReplacement(m.group(0))); // replace with original string - } - } - m.appendTail(accum); - return accum.toString(); - } - - // xhtml has restricted entities - private static final Object[][] xhtmlArray = { - {"quot", 0x00022}, - {"amp", 0x00026}, - {"apos", 0x00027}, - {"lt", 0x0003C}, - {"gt", 0x0003E} - }; - - static { - xhtmlByVal = new HashMap<Character, String>(); - baseByVal = toCharacterKey(loadEntities("entities-base.properties")); // most common / default - full = loadEntities("entities-full.properties"); // extended and overblown. - fullByVal = toCharacterKey(full); - - for (Object[] entity : xhtmlArray) { - Character c = Character.valueOf((char) ((Integer) entity[1]).intValue()); - xhtmlByVal.put(c, ((String) entity[0])); - } - } - - private static Map<String, Character> loadEntities(String filename) { - Properties properties = new Properties(); - Map<String, Character> entities = new HashMap<String, Character>(); - try { - InputStream in = Entities.class.getResourceAsStream(filename); - properties.load(in); - in.close(); - } catch (IOException e) { - throw new MissingResourceException("Error loading entities resource: " + e.getMessage(), "Entities", filename); - } - - for (Map.Entry entry: properties.entrySet()) { - Character val = Character.valueOf((char) Integer.parseInt((String) entry.getValue(), 16)); - String name = (String) entry.getKey(); - entities.put(name, val); - } - return entities; - } - - private static Map<Character, String> toCharacterKey(Map<String, Character> inMap) { - Map<Character, String> outMap = new HashMap<Character, String>(); - for (Map.Entry<String, Character> entry: inMap.entrySet()) { - Character character = entry.getValue(); - String name = entry.getKey(); - - if (outMap.containsKey(character)) { - // dupe, prefer the lower case version - if (name.toLowerCase().equals(name)) - outMap.put(character, name); - } else { - outMap.put(character, name); - } - } - return outMap; - } -} diff --git a/src/org/jsoup/nodes/Node.java b/src/org/jsoup/nodes/Node.java deleted file mode 100644 index eb2b40ee73..0000000000 --- a/src/org/jsoup/nodes/Node.java +++ /dev/null @@ -1,615 +0,0 @@ -package org.jsoup.nodes; - -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; -import org.jsoup.parser.Parser; -import org.jsoup.select.NodeTraversor; -import org.jsoup.select.NodeVisitor; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -/** - The base, abstract Node model. Elements, Documents, Comments etc are all Node instances. - - @author Jonathan Hedley, jonathan@hedley.net */ -public abstract class Node implements Cloneable { - Node parentNode; - List<Node> childNodes; - Attributes attributes; - String baseUri; - int siblingIndex; - - /** - Create a new Node. - @param baseUri base URI - @param attributes attributes (not null, but may be empty) - */ - protected Node(String baseUri, Attributes attributes) { - Validate.notNull(baseUri); - Validate.notNull(attributes); - - childNodes = new ArrayList<Node>(4); - this.baseUri = baseUri.trim(); - this.attributes = attributes; - } - - protected Node(String baseUri) { - this(baseUri, new Attributes()); - } - - /** - * Default constructor. Doesn't setup base uri, children, or attributes; use with caution. - */ - protected Node() { - childNodes = Collections.emptyList(); - attributes = null; - } - - /** - Get the node name of this node. Use for debugging purposes and not logic switching (for that, use instanceof). - @return node name - */ - public abstract String nodeName(); - - /** - * Get an attribute's value by its key. - * <p/> - * To get an absolute URL from an attribute that may be a relative URL, prefix the key with <code><b>abs</b></code>, - * which is a shortcut to the {@link #absUrl} method. - * E.g.: <blockquote><code>String url = a.attr("abs:href");</code></blockquote> - * @param attributeKey The attribute key. - * @return The attribute, or empty string if not present (to avoid nulls). - * @see #attributes() - * @see #hasAttr(String) - * @see #absUrl(String) - */ - public String attr(String attributeKey) { - Validate.notNull(attributeKey); - - if (attributes.hasKey(attributeKey)) - return attributes.get(attributeKey); - else if (attributeKey.toLowerCase().startsWith("abs:")) - return absUrl(attributeKey.substring("abs:".length())); - else return ""; - } - - /** - * Get all of the element's attributes. - * @return attributes (which implements iterable, in same order as presented in original HTML). - */ - public Attributes attributes() { - return attributes; - } - - /** - * Set an attribute (key=value). If the attribute already exists, it is replaced. - * @param attributeKey The attribute key. - * @param attributeValue The attribute value. - * @return this (for chaining) - */ - public Node attr(String attributeKey, String attributeValue) { - attributes.put(attributeKey, attributeValue); - return this; - } - - /** - * Test if this element has an attribute. - * @param attributeKey The attribute key to check. - * @return true if the attribute exists, false if not. - */ - public boolean hasAttr(String attributeKey) { - Validate.notNull(attributeKey); - - if (attributeKey.toLowerCase().startsWith("abs:")) { - String key = attributeKey.substring("abs:".length()); - if (attributes.hasKey(key) && !absUrl(key).equals("")) - return true; - } - return attributes.hasKey(attributeKey); - } - - /** - * Remove an attribute from this element. - * @param attributeKey The attribute to remove. - * @return this (for chaining) - */ - public Node removeAttr(String attributeKey) { - Validate.notNull(attributeKey); - attributes.remove(attributeKey); - return this; - } - - /** - Get the base URI of this node. - @return base URI - */ - public String baseUri() { - return baseUri; - } - - /** - Update the base URI of this node and all of its descendants. - @param baseUri base URI to set - */ - public void setBaseUri(final String baseUri) { - Validate.notNull(baseUri); - - traverse(new NodeVisitor() { - public void head(Node node, int depth) { - node.baseUri = baseUri; - } - - public void tail(Node node, int depth) { - } - }); - } - - /** - * Get an absolute URL from a URL attribute that may be relative (i.e. an <code><a href></code> or - * <code><img src></code>). - * <p/> - * E.g.: <code>String absUrl = linkEl.absUrl("href");</code> - * <p/> - * If the attribute value is already absolute (i.e. it starts with a protocol, like - * <code>http://</code> or <code>https://</code> etc), and it successfully parses as a URL, the attribute is - * returned directly. Otherwise, it is treated as a URL relative to the element's {@link #baseUri}, and made - * absolute using that. - * <p/> - * As an alternate, you can use the {@link #attr} method with the <code>abs:</code> prefix, e.g.: - * <code>String absUrl = linkEl.attr("abs:href");</code> - * - * @param attributeKey The attribute key - * @return An absolute URL if one could be made, or an empty string (not null) if the attribute was missing or - * could not be made successfully into a URL. - * @see #attr - * @see java.net.URL#URL(java.net.URL, String) - */ - public String absUrl(String attributeKey) { - Validate.notEmpty(attributeKey); - - String relUrl = attr(attributeKey); - if (!hasAttr(attributeKey)) { - return ""; // nothing to make absolute with - } else { - URL base; - try { - try { - base = new URL(baseUri); - } catch (MalformedURLException e) { - // the base is unsuitable, but the attribute may be abs on its own, so try that - URL abs = new URL(relUrl); - return abs.toExternalForm(); - } - // workaround: java resolves '//path/file + ?foo' to '//path/?foo', not '//path/file?foo' as desired - if (relUrl.startsWith("?")) - relUrl = base.getPath() + relUrl; - URL abs = new URL(base, relUrl); - return abs.toExternalForm(); - } catch (MalformedURLException e) { - return ""; - } - } - } - - /** - Get a child node by index - @param index index of child node - @return the child node at this index. - */ - public Node childNode(int index) { - return childNodes.get(index); - } - - /** - Get this node's children. Presented as an unmodifiable list: new children can not be added, but the child nodes - themselves can be manipulated. - @return list of children. If no children, returns an empty list. - */ - public List<Node> childNodes() { - return Collections.unmodifiableList(childNodes); - } - - protected Node[] childNodesAsArray() { - return childNodes.toArray(new Node[childNodes().size()]); - } - - /** - Gets this node's parent node. - @return parent node; or null if no parent. - */ - public Node parent() { - return parentNode; - } - - /** - * Gets the Document associated with this Node. - * @return the Document associated with this Node, or null if there is no such Document. - */ - public Document ownerDocument() { - if (this instanceof Document) - return (Document) this; - else if (parentNode == null) - return null; - else - return parentNode.ownerDocument(); - } - - /** - * Remove (delete) this node from the DOM tree. If this node has children, they are also removed. - */ - public void remove() { - Validate.notNull(parentNode); - parentNode.removeChild(this); - } - - /** - * Insert the specified HTML into the DOM before this node (i.e. as a preceding sibling). - * @param html HTML to add before this node - * @return this node, for chaining - * @see #after(String) - */ - public Node before(String html) { - addSiblingHtml(siblingIndex(), html); - return this; - } - - /** - * Insert the specified node into the DOM before this node (i.e. as a preceding sibling). - * @param node to add before this node - * @return this node, for chaining - * @see #after(Node) - */ - public Node before(Node node) { - Validate.notNull(node); - Validate.notNull(parentNode); - - parentNode.addChildren(siblingIndex(), node); - return this; - } - - /** - * Insert the specified HTML into the DOM after this node (i.e. as a following sibling). - * @param html HTML to add after this node - * @return this node, for chaining - * @see #before(String) - */ - public Node after(String html) { - addSiblingHtml(siblingIndex()+1, html); - return this; - } - - /** - * Insert the specified node into the DOM after this node (i.e. as a following sibling). - * @param node to add after this node - * @return this node, for chaining - * @see #before(Node) - */ - public Node after(Node node) { - Validate.notNull(node); - Validate.notNull(parentNode); - - parentNode.addChildren(siblingIndex()+1, node); - return this; - } - - private void addSiblingHtml(int index, String html) { - Validate.notNull(html); - Validate.notNull(parentNode); - - Element context = parent() instanceof Element ? (Element) parent() : null; - List<Node> nodes = Parser.parseFragment(html, context, baseUri()); - parentNode.addChildren(index, nodes.toArray(new Node[nodes.size()])); - } - - /** - Wrap the supplied HTML around this node. - @param html HTML to wrap around this element, e.g. {@code <div class="head"></div>}. Can be arbitrarily deep. - @return this node, for chaining. - */ - public Node wrap(String html) { - Validate.notEmpty(html); - - Element context = parent() instanceof Element ? (Element) parent() : null; - List<Node> wrapChildren = Parser.parseFragment(html, context, baseUri()); - Node wrapNode = wrapChildren.get(0); - if (wrapNode == null || !(wrapNode instanceof Element)) // nothing to wrap with; noop - return null; - - Element wrap = (Element) wrapNode; - Element deepest = getDeepChild(wrap); - parentNode.replaceChild(this, wrap); - deepest.addChildren(this); - - // remainder (unbalanced wrap, like <div></div><p></p> -- The <p> is remainder - if (wrapChildren.size() > 0) { - for (int i = 0; i < wrapChildren.size(); i++) { - Node remainder = wrapChildren.get(i); - remainder.parentNode.removeChild(remainder); - wrap.appendChild(remainder); - } - } - return this; - } - - /** - * Removes this node from the DOM, and moves its children up into the node's parent. This has the effect of dropping - * the node but keeping its children. - * <p/> - * For example, with the input html:<br/> - * {@code <div>One <span>Two <b>Three</b></span></div>}<br/> - * Calling {@code element.unwrap()} on the {@code span} element will result in the html:<br/> - * {@code <div>One Two <b>Three</b></div>}<br/> - * and the {@code "Two "} {@link TextNode} being returned. - * @return the first child of this node, after the node has been unwrapped. Null if the node had no children. - * @see #remove() - * @see #wrap(String) - */ - public Node unwrap() { - Validate.notNull(parentNode); - - int index = siblingIndex; - Node firstChild = childNodes.size() > 0 ? childNodes.get(0) : null; - parentNode.addChildren(index, this.childNodesAsArray()); - this.remove(); - - return firstChild; - } - - private Element getDeepChild(Element el) { - List<Element> children = el.children(); - if (children.size() > 0) - return getDeepChild(children.get(0)); - else - return el; - } - - /** - * Replace this node in the DOM with the supplied node. - * @param in the node that will will replace the existing node. - */ - public void replaceWith(Node in) { - Validate.notNull(in); - Validate.notNull(parentNode); - parentNode.replaceChild(this, in); - } - - protected void setParentNode(Node parentNode) { - if (this.parentNode != null) - this.parentNode.removeChild(this); - this.parentNode = parentNode; - } - - protected void replaceChild(Node out, Node in) { - Validate.isTrue(out.parentNode == this); - Validate.notNull(in); - if (in.parentNode != null) - in.parentNode.removeChild(in); - - Integer index = out.siblingIndex(); - childNodes.set(index, in); - in.parentNode = this; - in.setSiblingIndex(index); - out.parentNode = null; - } - - protected void removeChild(Node out) { - Validate.isTrue(out.parentNode == this); - int index = out.siblingIndex(); - childNodes.remove(index); - reindexChildren(); - out.parentNode = null; - } - - protected void addChildren(Node... children) { - //most used. short circuit addChildren(int), which hits reindex children and array copy - for (Node child: children) { - reparentChild(child); - childNodes.add(child); - child.setSiblingIndex(childNodes.size()-1); - } - } - - protected void addChildren(int index, Node... children) { - Validate.noNullElements(children); - for (int i = children.length - 1; i >= 0; i--) { - Node in = children[i]; - reparentChild(in); - childNodes.add(index, in); - } - reindexChildren(); - } - - private void reparentChild(Node child) { - if (child.parentNode != null) - child.parentNode.removeChild(child); - child.setParentNode(this); - } - - private void reindexChildren() { - for (int i = 0; i < childNodes.size(); i++) { - childNodes.get(i).setSiblingIndex(i); - } - } - - /** - Retrieves this node's sibling nodes. Similar to {@link #childNodes() node.parent.childNodes()}, but does not - include this node (a node is not a sibling of itself). - @return node siblings. If the node has no parent, returns an empty list. - */ - public List<Node> siblingNodes() { - if (parentNode == null) - return Collections.emptyList(); - - List<Node> nodes = parentNode.childNodes; - List<Node> siblings = new ArrayList<Node>(nodes.size() - 1); - for (Node node: nodes) - if (node != this) - siblings.add(node); - return siblings; - } - - /** - Get this node's next sibling. - @return next sibling, or null if this is the last sibling - */ - public Node nextSibling() { - if (parentNode == null) - return null; // root - - List<Node> siblings = parentNode.childNodes; - Integer index = siblingIndex(); - Validate.notNull(index); - if (siblings.size() > index+1) - return siblings.get(index+1); - else - return null; - } - - /** - Get this node's previous sibling. - @return the previous sibling, or null if this is the first sibling - */ - public Node previousSibling() { - if (parentNode == null) - return null; // root - - List<Node> siblings = parentNode.childNodes; - Integer index = siblingIndex(); - Validate.notNull(index); - if (index > 0) - return siblings.get(index-1); - else - return null; - } - - /** - * Get the list index of this node in its node sibling list. I.e. if this is the first node - * sibling, returns 0. - * @return position in node sibling list - * @see org.jsoup.nodes.Element#elementSiblingIndex() - */ - public int siblingIndex() { - return siblingIndex; - } - - protected void setSiblingIndex(int siblingIndex) { - this.siblingIndex = siblingIndex; - } - - /** - * Perform a depth-first traversal through this node and its descendants. - * @param nodeVisitor the visitor callbacks to perform on each node - * @return this node, for chaining - */ - public Node traverse(NodeVisitor nodeVisitor) { - Validate.notNull(nodeVisitor); - NodeTraversor traversor = new NodeTraversor(nodeVisitor); - traversor.traverse(this); - return this; - } - - /** - Get the outer HTML of this node. - @return HTML - */ - public String outerHtml() { - StringBuilder accum = new StringBuilder(128); - outerHtml(accum); - return accum.toString(); - } - - protected void outerHtml(StringBuilder accum) { - new NodeTraversor(new OuterHtmlVisitor(accum, getOutputSettings())).traverse(this); - } - - // if this node has no document (or parent), retrieve the default output settings - private Document.OutputSettings getOutputSettings() { - return ownerDocument() != null ? ownerDocument().outputSettings() : (new Document("")).outputSettings(); - } - - /** - Get the outer HTML of this node. - @param accum accumulator to place HTML into - */ - abstract void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out); - - abstract void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out); - - public String toString() { - return outerHtml(); - } - - protected void indent(StringBuilder accum, int depth, Document.OutputSettings out) { - accum.append("\n").append(StringUtil.padding(depth * out.indentAmount())); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - // todo: have nodes hold a child index, compare against that and parent (not children) - return false; - } - - @Override - public int hashCode() { - int result = parentNode != null ? parentNode.hashCode() : 0; - // not children, or will block stack as they go back up to parent) - result = 31 * result + (attributes != null ? attributes.hashCode() : 0); - return result; - } - - /** - * Create a stand-alone, deep copy of this node, and all of its children. The cloned node will have no siblings or - * parent node. As a stand-alone object, any changes made to the clone or any of its children will not impact the - * original node. - * <p> - * The cloned node may be adopted into another Document or node structure using {@link Element#appendChild(Node)}. - * @return stand-alone cloned node - */ - @Override - public Node clone() { - return doClone(null); // splits for orphan - } - - protected Node doClone(Node parent) { - Node clone; - try { - clone = (Node) super.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e); - } - - clone.parentNode = parent; // can be null, to create an orphan split - clone.siblingIndex = parent == null ? 0 : siblingIndex; - clone.attributes = attributes != null ? attributes.clone() : null; - clone.baseUri = baseUri; - clone.childNodes = new ArrayList<Node>(childNodes.size()); - for (Node child: childNodes) - clone.childNodes.add(child.doClone(clone)); // clone() creates orphans, doClone() keeps parent - - return clone; - } - - private static class OuterHtmlVisitor implements NodeVisitor { - private StringBuilder accum; - private Document.OutputSettings out; - - OuterHtmlVisitor(StringBuilder accum, Document.OutputSettings out) { - this.accum = accum; - this.out = out; - } - - public void head(Node node, int depth) { - node.outerHtmlHead(accum, depth, out); - } - - public void tail(Node node, int depth) { - if (!node.nodeName().equals("#text")) // saves a void hit. - node.outerHtmlTail(accum, depth, out); - } - } -} diff --git a/src/org/jsoup/nodes/TextNode.java b/src/org/jsoup/nodes/TextNode.java deleted file mode 100644 index 9fd0feac8f..0000000000 --- a/src/org/jsoup/nodes/TextNode.java +++ /dev/null @@ -1,175 +0,0 @@ -package org.jsoup.nodes; - -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; - -/** - A text node. - - @author Jonathan Hedley, jonathan@hedley.net */ -public class TextNode extends Node { - /* - TextNode is a node, and so by default comes with attributes and children. The attributes are seldom used, but use - memory, and the child nodes are never used. So we don't have them, and override accessors to attributes to create - them as needed on the fly. - */ - private static final String TEXT_KEY = "text"; - String text; - - /** - Create a new TextNode representing the supplied (unencoded) text). - - @param text raw text - @param baseUri base uri - @see #createFromEncoded(String, String) - */ - public TextNode(String text, String baseUri) { - this.baseUri = baseUri; - this.text = text; - } - - public String nodeName() { - return "#text"; - } - - /** - * Get the text content of this text node. - * @return Unencoded, normalised text. - * @see TextNode#getWholeText() - */ - public String text() { - return normaliseWhitespace(getWholeText()); - } - - /** - * Set the text content of this text node. - * @param text unencoded text - * @return this, for chaining - */ - public TextNode text(String text) { - this.text = text; - if (attributes != null) - attributes.put(TEXT_KEY, text); - return this; - } - - /** - Get the (unencoded) text of this text node, including any newlines and spaces present in the original. - @return text - */ - public String getWholeText() { - return attributes == null ? text : attributes.get(TEXT_KEY); - } - - /** - Test if this text node is blank -- that is, empty or only whitespace (including newlines). - @return true if this document is empty or only whitespace, false if it contains any text content. - */ - public boolean isBlank() { - return StringUtil.isBlank(getWholeText()); - } - - /** - * Split this text node into two nodes at the specified string offset. After splitting, this node will contain the - * original text up to the offset, and will have a new text node sibling containing the text after the offset. - * @param offset string offset point to split node at. - * @return the newly created text node containing the text after the offset. - */ - public TextNode splitText(int offset) { - Validate.isTrue(offset >= 0, "Split offset must be not be negative"); - Validate.isTrue(offset < text.length(), "Split offset must not be greater than current text length"); - - String head = getWholeText().substring(0, offset); - String tail = getWholeText().substring(offset); - text(head); - TextNode tailNode = new TextNode(tail, this.baseUri()); - if (parent() != null) - parent().addChildren(siblingIndex()+1, tailNode); - - return tailNode; - } - - void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out) { - String html = Entities.escape(getWholeText(), out); - if (out.prettyPrint() && parent() instanceof Element && !((Element) parent()).preserveWhitespace()) { - html = normaliseWhitespace(html); - } - - if (out.prettyPrint() && siblingIndex() == 0 && parentNode instanceof Element && ((Element) parentNode).tag().formatAsBlock() && !isBlank()) - indent(accum, depth, out); - accum.append(html); - } - - void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out) {} - - public String toString() { - return outerHtml(); - } - - /** - * Create a new TextNode from HTML encoded (aka escaped) data. - * @param encodedText Text containing encoded HTML (e.g. &lt;) - * @return TextNode containing unencoded data (e.g. <) - */ - public static TextNode createFromEncoded(String encodedText, String baseUri) { - String text = Entities.unescape(encodedText); - return new TextNode(text, baseUri); - } - - static String normaliseWhitespace(String text) { - text = StringUtil.normaliseWhitespace(text); - return text; - } - - static String stripLeadingWhitespace(String text) { - return text.replaceFirst("^\\s+", ""); - } - - static boolean lastCharIsWhitespace(StringBuilder sb) { - return sb.length() != 0 && sb.charAt(sb.length() - 1) == ' '; - } - - // attribute fiddling. create on first access. - private void ensureAttributes() { - if (attributes == null) { - attributes = new Attributes(); - attributes.put(TEXT_KEY, text); - } - } - - @Override - public String attr(String attributeKey) { - ensureAttributes(); - return super.attr(attributeKey); - } - - @Override - public Attributes attributes() { - ensureAttributes(); - return super.attributes(); - } - - @Override - public Node attr(String attributeKey, String attributeValue) { - ensureAttributes(); - return super.attr(attributeKey, attributeValue); - } - - @Override - public boolean hasAttr(String attributeKey) { - ensureAttributes(); - return super.hasAttr(attributeKey); - } - - @Override - public Node removeAttr(String attributeKey) { - ensureAttributes(); - return super.removeAttr(attributeKey); - } - - @Override - public String absUrl(String attributeKey) { - ensureAttributes(); - return super.absUrl(attributeKey); - } -} diff --git a/src/org/jsoup/nodes/XmlDeclaration.java b/src/org/jsoup/nodes/XmlDeclaration.java deleted file mode 100644 index 80d4a0152f..0000000000 --- a/src/org/jsoup/nodes/XmlDeclaration.java +++ /dev/null @@ -1,48 +0,0 @@ -package org.jsoup.nodes; - -/** - An XML Declaration. - - @author Jonathan Hedley, jonathan@hedley.net */ -public class XmlDeclaration extends Node { - private static final String DECL_KEY = "declaration"; - private final boolean isProcessingInstruction; // <! if true, <? if false, declaration (and last data char should be ?) - - /** - Create a new XML declaration - @param data data - @param baseUri base uri - @param isProcessingInstruction is processing instruction - */ - public XmlDeclaration(String data, String baseUri, boolean isProcessingInstruction) { - super(baseUri); - attributes.put(DECL_KEY, data); - this.isProcessingInstruction = isProcessingInstruction; - } - - public String nodeName() { - return "#declaration"; - } - - /** - Get the unencoded XML declaration. - @return XML declaration - */ - public String getWholeDeclaration() { - return attributes.get(DECL_KEY); - } - - void outerHtmlHead(StringBuilder accum, int depth, Document.OutputSettings out) { - accum - .append("<") - .append(isProcessingInstruction ? "!" : "?") - .append(getWholeDeclaration()) - .append(">"); - } - - void outerHtmlTail(StringBuilder accum, int depth, Document.OutputSettings out) {} - - public String toString() { - return outerHtml(); - } -} diff --git a/src/org/jsoup/nodes/entities-base.properties b/src/org/jsoup/nodes/entities-base.properties deleted file mode 100644 index 3d1d11e6c4..0000000000 --- a/src/org/jsoup/nodes/entities-base.properties +++ /dev/null @@ -1,106 +0,0 @@ -AElig=000C6 -AMP=00026 -Aacute=000C1 -Acirc=000C2 -Agrave=000C0 -Aring=000C5 -Atilde=000C3 -Auml=000C4 -COPY=000A9 -Ccedil=000C7 -ETH=000D0 -Eacute=000C9 -Ecirc=000CA -Egrave=000C8 -Euml=000CB -GT=0003E -Iacute=000CD -Icirc=000CE -Igrave=000CC -Iuml=000CF -LT=0003C -Ntilde=000D1 -Oacute=000D3 -Ocirc=000D4 -Ograve=000D2 -Oslash=000D8 -Otilde=000D5 -Ouml=000D6 -QUOT=00022 -REG=000AE -THORN=000DE -Uacute=000DA -Ucirc=000DB -Ugrave=000D9 -Uuml=000DC -Yacute=000DD -aacute=000E1 -acirc=000E2 -acute=000B4 -aelig=000E6 -agrave=000E0 -amp=00026 -aring=000E5 -atilde=000E3 -auml=000E4 -brvbar=000A6 -ccedil=000E7 -cedil=000B8 -cent=000A2 -copy=000A9 -curren=000A4 -deg=000B0 -divide=000F7 -eacute=000E9 -ecirc=000EA -egrave=000E8 -eth=000F0 -euml=000EB -frac12=000BD -frac14=000BC -frac34=000BE -gt=0003E -iacute=000ED -icirc=000EE -iexcl=000A1 -igrave=000EC -iquest=000BF -iuml=000EF -laquo=000AB -lt=0003C -macr=000AF -micro=000B5 -middot=000B7 -nbsp=000A0 -not=000AC -ntilde=000F1 -oacute=000F3 -ocirc=000F4 -ograve=000F2 -ordf=000AA -ordm=000BA -oslash=000F8 -otilde=000F5 -ouml=000F6 -para=000B6 -plusmn=000B1 -pound=000A3 -quot=00022 -raquo=000BB -reg=000AE -sect=000A7 -shy=000AD -sup1=000B9 -sup2=000B2 -sup3=000B3 -szlig=000DF -thorn=000FE -times=000D7 -uacute=000FA -ucirc=000FB -ugrave=000F9 -uml=000A8 -uuml=000FC -yacute=000FD -yen=000A5 -yuml=000FF diff --git a/src/org/jsoup/nodes/entities-full.properties b/src/org/jsoup/nodes/entities-full.properties deleted file mode 100644 index 92f124f408..0000000000 --- a/src/org/jsoup/nodes/entities-full.properties +++ /dev/null @@ -1,2032 +0,0 @@ -AElig=000C6 -AMP=00026 -Aacute=000C1 -Abreve=00102 -Acirc=000C2 -Acy=00410 -Afr=1D504 -Agrave=000C0 -Alpha=00391 -Amacr=00100 -And=02A53 -Aogon=00104 -Aopf=1D538 -ApplyFunction=02061 -Aring=000C5 -Ascr=1D49C -Assign=02254 -Atilde=000C3 -Auml=000C4 -Backslash=02216 -Barv=02AE7 -Barwed=02306 -Bcy=00411 -Because=02235 -Bernoullis=0212C -Beta=00392 -Bfr=1D505 -Bopf=1D539 -Breve=002D8 -Bscr=0212C -Bumpeq=0224E -CHcy=00427 -COPY=000A9 -Cacute=00106 -Cap=022D2 -CapitalDifferentialD=02145 -Cayleys=0212D -Ccaron=0010C -Ccedil=000C7 -Ccirc=00108 -Cconint=02230 -Cdot=0010A -Cedilla=000B8 -CenterDot=000B7 -Cfr=0212D -Chi=003A7 -CircleDot=02299 -CircleMinus=02296 -CirclePlus=02295 -CircleTimes=02297 -ClockwiseContourIntegral=02232 -CloseCurlyDoubleQuote=0201D -CloseCurlyQuote=02019 -Colon=02237 -Colone=02A74 -Congruent=02261 -Conint=0222F -ContourIntegral=0222E -Copf=02102 -Coproduct=02210 -CounterClockwiseContourIntegral=02233 -Cross=02A2F -Cscr=1D49E -Cup=022D3 -CupCap=0224D -DD=02145 -DDotrahd=02911 -DJcy=00402 -DScy=00405 -DZcy=0040F -Dagger=02021 -Darr=021A1 -Dashv=02AE4 -Dcaron=0010E -Dcy=00414 -Del=02207 -Delta=00394 -Dfr=1D507 -DiacriticalAcute=000B4 -DiacriticalDot=002D9 -DiacriticalDoubleAcute=002DD -DiacriticalGrave=00060 -DiacriticalTilde=002DC -Diamond=022C4 -DifferentialD=02146 -Dopf=1D53B -Dot=000A8 -DotDot=020DC -DotEqual=02250 -DoubleContourIntegral=0222F -DoubleDot=000A8 -DoubleDownArrow=021D3 -DoubleLeftArrow=021D0 -DoubleLeftRightArrow=021D4 -DoubleLeftTee=02AE4 -DoubleLongLeftArrow=027F8 -DoubleLongLeftRightArrow=027FA -DoubleLongRightArrow=027F9 -DoubleRightArrow=021D2 -DoubleRightTee=022A8 -DoubleUpArrow=021D1 -DoubleUpDownArrow=021D5 -DoubleVerticalBar=02225 -DownArrow=02193 -DownArrowBar=02913 -DownArrowUpArrow=021F5 -DownBreve=00311 -DownLeftRightVector=02950 -DownLeftTeeVector=0295E -DownLeftVector=021BD -DownLeftVectorBar=02956 -DownRightTeeVector=0295F -DownRightVector=021C1 -DownRightVectorBar=02957 -DownTee=022A4 -DownTeeArrow=021A7 -Downarrow=021D3 -Dscr=1D49F -Dstrok=00110 -ENG=0014A -ETH=000D0 -Eacute=000C9 -Ecaron=0011A -Ecirc=000CA -Ecy=0042D -Edot=00116 -Efr=1D508 -Egrave=000C8 -Element=02208 -Emacr=00112 -EmptySmallSquare=025FB -EmptyVerySmallSquare=025AB -Eogon=00118 -Eopf=1D53C -Epsilon=00395 -Equal=02A75 -EqualTilde=02242 -Equilibrium=021CC -Escr=02130 -Esim=02A73 -Eta=00397 -Euml=000CB -Exists=02203 -ExponentialE=02147 -Fcy=00424 -Ffr=1D509 -FilledSmallSquare=025FC -FilledVerySmallSquare=025AA -Fopf=1D53D -ForAll=02200 -Fouriertrf=02131 -Fscr=02131 -GJcy=00403 -GT=0003E -Gamma=00393 -Gammad=003DC -Gbreve=0011E -Gcedil=00122 -Gcirc=0011C -Gcy=00413 -Gdot=00120 -Gfr=1D50A -Gg=022D9 -Gopf=1D53E -GreaterEqual=02265 -GreaterEqualLess=022DB -GreaterFullEqual=02267 -GreaterGreater=02AA2 -GreaterLess=02277 -GreaterSlantEqual=02A7E -GreaterTilde=02273 -Gscr=1D4A2 -Gt=0226B -HARDcy=0042A -Hacek=002C7 -Hat=0005E -Hcirc=00124 -Hfr=0210C -HilbertSpace=0210B -Hopf=0210D -HorizontalLine=02500 -Hscr=0210B -Hstrok=00126 -HumpDownHump=0224E -HumpEqual=0224F -IEcy=00415 -IJlig=00132 -IOcy=00401 -Iacute=000CD -Icirc=000CE -Icy=00418 -Idot=00130 -Ifr=02111 -Igrave=000CC -Im=02111 -Imacr=0012A -ImaginaryI=02148 -Implies=021D2 -Int=0222C -Integral=0222B -Intersection=022C2 -InvisibleComma=02063 -InvisibleTimes=02062 -Iogon=0012E -Iopf=1D540 -Iota=00399 -Iscr=02110 -Itilde=00128 -Iukcy=00406 -Iuml=000CF -Jcirc=00134 -Jcy=00419 -Jfr=1D50D -Jopf=1D541 -Jscr=1D4A5 -Jsercy=00408 -Jukcy=00404 -KHcy=00425 -KJcy=0040C -Kappa=0039A -Kcedil=00136 -Kcy=0041A -Kfr=1D50E -Kopf=1D542 -Kscr=1D4A6 -LJcy=00409 -LT=0003C -Lacute=00139 -Lambda=0039B -Lang=027EA -Laplacetrf=02112 -Larr=0219E -Lcaron=0013D -Lcedil=0013B -Lcy=0041B -LeftAngleBracket=027E8 -LeftArrow=02190 -LeftArrowBar=021E4 -LeftArrowRightArrow=021C6 -LeftCeiling=02308 -LeftDoubleBracket=027E6 -LeftDownTeeVector=02961 -LeftDownVector=021C3 -LeftDownVectorBar=02959 -LeftFloor=0230A -LeftRightArrow=02194 -LeftRightVector=0294E -LeftTee=022A3 -LeftTeeArrow=021A4 -LeftTeeVector=0295A -LeftTriangle=022B2 -LeftTriangleBar=029CF -LeftTriangleEqual=022B4 -LeftUpDownVector=02951 -LeftUpTeeVector=02960 -LeftUpVector=021BF -LeftUpVectorBar=02958 -LeftVector=021BC -LeftVectorBar=02952 -Leftarrow=021D0 -Leftrightarrow=021D4 -LessEqualGreater=022DA -LessFullEqual=02266 -LessGreater=02276 -LessLess=02AA1 -LessSlantEqual=02A7D -LessTilde=02272 -Lfr=1D50F -Ll=022D8 -Lleftarrow=021DA -Lmidot=0013F -LongLeftArrow=027F5 -LongLeftRightArrow=027F7 -LongRightArrow=027F6 -Longleftarrow=027F8 -Longleftrightarrow=027FA -Longrightarrow=027F9 -Lopf=1D543 -LowerLeftArrow=02199 -LowerRightArrow=02198 -Lscr=02112 -Lsh=021B0 -Lstrok=00141 -Lt=0226A -Map=02905 -Mcy=0041C -MediumSpace=0205F -Mellintrf=02133 -Mfr=1D510 -MinusPlus=02213 -Mopf=1D544 -Mscr=02133 -Mu=0039C -NJcy=0040A -Nacute=00143 -Ncaron=00147 -Ncedil=00145 -Ncy=0041D -NegativeMediumSpace=0200B -NegativeThickSpace=0200B -NegativeThinSpace=0200B -NegativeVeryThinSpace=0200B -NestedGreaterGreater=0226B -NestedLessLess=0226A -NewLine=0000A -Nfr=1D511 -NoBreak=02060 -NonBreakingSpace=000A0 -Nopf=02115 -Not=02AEC -NotCongruent=02262 -NotCupCap=0226D -NotDoubleVerticalBar=02226 -NotElement=02209 -NotEqual=02260 -NotExists=02204 -NotGreater=0226F -NotGreaterEqual=02271 -NotGreaterLess=02279 -NotGreaterTilde=02275 -NotLeftTriangle=022EA -NotLeftTriangleEqual=022EC -NotLess=0226E -NotLessEqual=02270 -NotLessGreater=02278 -NotLessTilde=02274 -NotPrecedes=02280 -NotPrecedesSlantEqual=022E0 -NotReverseElement=0220C -NotRightTriangle=022EB -NotRightTriangleEqual=022ED -NotSquareSubsetEqual=022E2 -NotSquareSupersetEqual=022E3 -NotSubsetEqual=02288 -NotSucceeds=02281 -NotSucceedsSlantEqual=022E1 -NotSupersetEqual=02289 -NotTilde=02241 -NotTildeEqual=02244 -NotTildeFullEqual=02247 -NotTildeTilde=02249 -NotVerticalBar=02224 -Nscr=1D4A9 -Ntilde=000D1 -Nu=0039D -OElig=00152 -Oacute=000D3 -Ocirc=000D4 -Ocy=0041E -Odblac=00150 -Ofr=1D512 -Ograve=000D2 -Omacr=0014C -Omega=003A9 -Omicron=0039F -Oopf=1D546 -OpenCurlyDoubleQuote=0201C -OpenCurlyQuote=02018 -Or=02A54 -Oscr=1D4AA -Oslash=000D8 -Otilde=000D5 -Otimes=02A37 -Ouml=000D6 -OverBar=0203E -OverBrace=023DE -OverBracket=023B4 -OverParenthesis=023DC -PartialD=02202 -Pcy=0041F -Pfr=1D513 -Phi=003A6 -Pi=003A0 -PlusMinus=000B1 -Poincareplane=0210C -Popf=02119 -Pr=02ABB -Precedes=0227A -PrecedesEqual=02AAF -PrecedesSlantEqual=0227C -PrecedesTilde=0227E -Prime=02033 -Product=0220F -Proportion=02237 -Proportional=0221D -Pscr=1D4AB -Psi=003A8 -QUOT=00022 -Qfr=1D514 -Qopf=0211A -Qscr=1D4AC -RBarr=02910 -REG=000AE -Racute=00154 -Rang=027EB -Rarr=021A0 -Rarrtl=02916 -Rcaron=00158 -Rcedil=00156 -Rcy=00420 -Re=0211C -ReverseElement=0220B -ReverseEquilibrium=021CB -ReverseUpEquilibrium=0296F -Rfr=0211C -Rho=003A1 -RightAngleBracket=027E9 -RightArrow=02192 -RightArrowBar=021E5 -RightArrowLeftArrow=021C4 -RightCeiling=02309 -RightDoubleBracket=027E7 -RightDownTeeVector=0295D -RightDownVector=021C2 -RightDownVectorBar=02955 -RightFloor=0230B -RightTee=022A2 -RightTeeArrow=021A6 -RightTeeVector=0295B -RightTriangle=022B3 -RightTriangleBar=029D0 -RightTriangleEqual=022B5 -RightUpDownVector=0294F -RightUpTeeVector=0295C -RightUpVector=021BE -RightUpVectorBar=02954 -RightVector=021C0 -RightVectorBar=02953 -Rightarrow=021D2 -Ropf=0211D -RoundImplies=02970 -Rrightarrow=021DB -Rscr=0211B -Rsh=021B1 -RuleDelayed=029F4 -SHCHcy=00429 -SHcy=00428 -SOFTcy=0042C -Sacute=0015A -Sc=02ABC -Scaron=00160 -Scedil=0015E -Scirc=0015C -Scy=00421 -Sfr=1D516 -ShortDownArrow=02193 -ShortLeftArrow=02190 -ShortRightArrow=02192 -ShortUpArrow=02191 -Sigma=003A3 -SmallCircle=02218 -Sopf=1D54A -Sqrt=0221A -Square=025A1 -SquareIntersection=02293 -SquareSubset=0228F -SquareSubsetEqual=02291 -SquareSuperset=02290 -SquareSupersetEqual=02292 -SquareUnion=02294 -Sscr=1D4AE -Star=022C6 -Sub=022D0 -Subset=022D0 -SubsetEqual=02286 -Succeeds=0227B -SucceedsEqual=02AB0 -SucceedsSlantEqual=0227D -SucceedsTilde=0227F -SuchThat=0220B -Sum=02211 -Sup=022D1 -Superset=02283 -SupersetEqual=02287 -Supset=022D1 -THORN=000DE -TRADE=02122 -TSHcy=0040B -TScy=00426 -Tab=00009 -Tau=003A4 -Tcaron=00164 -Tcedil=00162 -Tcy=00422 -Tfr=1D517 -Therefore=02234 -Theta=00398 -ThinSpace=02009 -Tilde=0223C -TildeEqual=02243 -TildeFullEqual=02245 -TildeTilde=02248 -Topf=1D54B -TripleDot=020DB -Tscr=1D4AF -Tstrok=00166 -Uacute=000DA -Uarr=0219F -Uarrocir=02949 -Ubrcy=0040E -Ubreve=0016C -Ucirc=000DB -Ucy=00423 -Udblac=00170 -Ufr=1D518 -Ugrave=000D9 -Umacr=0016A -UnderBar=0005F -UnderBrace=023DF -UnderBracket=023B5 -UnderParenthesis=023DD -Union=022C3 -UnionPlus=0228E -Uogon=00172 -Uopf=1D54C -UpArrow=02191 -UpArrowBar=02912 -UpArrowDownArrow=021C5 -UpDownArrow=02195 -UpEquilibrium=0296E -UpTee=022A5 -UpTeeArrow=021A5 -Uparrow=021D1 -Updownarrow=021D5 -UpperLeftArrow=02196 -UpperRightArrow=02197 -Upsi=003D2 -Upsilon=003A5 -Uring=0016E -Uscr=1D4B0 -Utilde=00168 -Uuml=000DC -VDash=022AB -Vbar=02AEB -Vcy=00412 -Vdash=022A9 -Vdashl=02AE6 -Vee=022C1 -Verbar=02016 -Vert=02016 -VerticalBar=02223 -VerticalLine=0007C -VerticalSeparator=02758 -VerticalTilde=02240 -VeryThinSpace=0200A -Vfr=1D519 -Vopf=1D54D -Vscr=1D4B1 -Vvdash=022AA -Wcirc=00174 -Wedge=022C0 -Wfr=1D51A -Wopf=1D54E -Wscr=1D4B2 -Xfr=1D51B -Xi=0039E -Xopf=1D54F -Xscr=1D4B3 -YAcy=0042F -YIcy=00407 -YUcy=0042E -Yacute=000DD -Ycirc=00176 -Ycy=0042B -Yfr=1D51C -Yopf=1D550 -Yscr=1D4B4 -Yuml=00178 -ZHcy=00416 -Zacute=00179 -Zcaron=0017D -Zcy=00417 -Zdot=0017B -ZeroWidthSpace=0200B -Zeta=00396 -Zfr=02128 -Zopf=02124 -Zscr=1D4B5 -aacute=000E1 -abreve=00103 -ac=0223E -acd=0223F -acirc=000E2 -acute=000B4 -acy=00430 -aelig=000E6 -af=02061 -afr=1D51E -agrave=000E0 -alefsym=02135 -aleph=02135 -alpha=003B1 -amacr=00101 -amalg=02A3F -amp=00026 -and=02227 -andand=02A55 -andd=02A5C -andslope=02A58 -andv=02A5A -ang=02220 -ange=029A4 -angle=02220 -angmsd=02221 -angmsdaa=029A8 -angmsdab=029A9 -angmsdac=029AA -angmsdad=029AB -angmsdae=029AC -angmsdaf=029AD -angmsdag=029AE -angmsdah=029AF -angrt=0221F -angrtvb=022BE -angrtvbd=0299D -angsph=02222 -angst=000C5 -angzarr=0237C -aogon=00105 -aopf=1D552 -ap=02248 -apE=02A70 -apacir=02A6F -ape=0224A -apid=0224B -apos=00027 -approx=02248 -approxeq=0224A -aring=000E5 -ascr=1D4B6 -ast=0002A -asymp=02248 -asympeq=0224D -atilde=000E3 -auml=000E4 -awconint=02233 -awint=02A11 -bNot=02AED -backcong=0224C -backepsilon=003F6 -backprime=02035 -backsim=0223D -backsimeq=022CD -barvee=022BD -barwed=02305 -barwedge=02305 -bbrk=023B5 -bbrktbrk=023B6 -bcong=0224C -bcy=00431 -bdquo=0201E -becaus=02235 -because=02235 -bemptyv=029B0 -bepsi=003F6 -bernou=0212C -beta=003B2 -beth=02136 -between=0226C -bfr=1D51F -bigcap=022C2 -bigcirc=025EF -bigcup=022C3 -bigodot=02A00 -bigoplus=02A01 -bigotimes=02A02 -bigsqcup=02A06 -bigstar=02605 -bigtriangledown=025BD -bigtriangleup=025B3 -biguplus=02A04 -bigvee=022C1 -bigwedge=022C0 -bkarow=0290D -blacklozenge=029EB -blacksquare=025AA -blacktriangle=025B4 -blacktriangledown=025BE -blacktriangleleft=025C2 -blacktriangleright=025B8 -blank=02423 -blk12=02592 -blk14=02591 -blk34=02593 -block=02588 -bnot=02310 -bopf=1D553 -bot=022A5 -bottom=022A5 -bowtie=022C8 -boxDL=02557 -boxDR=02554 -boxDl=02556 -boxDr=02553 -boxH=02550 -boxHD=02566 -boxHU=02569 -boxHd=02564 -boxHu=02567 -boxUL=0255D -boxUR=0255A -boxUl=0255C -boxUr=02559 -boxV=02551 -boxVH=0256C -boxVL=02563 -boxVR=02560 -boxVh=0256B -boxVl=02562 -boxVr=0255F -boxbox=029C9 -boxdL=02555 -boxdR=02552 -boxdl=02510 -boxdr=0250C -boxh=02500 -boxhD=02565 -boxhU=02568 -boxhd=0252C -boxhu=02534 -boxminus=0229F -boxplus=0229E -boxtimes=022A0 -boxuL=0255B -boxuR=02558 -boxul=02518 -boxur=02514 -boxv=02502 -boxvH=0256A -boxvL=02561 -boxvR=0255E -boxvh=0253C -boxvl=02524 -boxvr=0251C -bprime=02035 -breve=002D8 -brvbar=000A6 -bscr=1D4B7 -bsemi=0204F -bsim=0223D -bsime=022CD -bsol=0005C -bsolb=029C5 -bsolhsub=027C8 -bull=02022 -bullet=02022 -bump=0224E -bumpE=02AAE -bumpe=0224F -bumpeq=0224F -cacute=00107 -cap=02229 -capand=02A44 -capbrcup=02A49 -capcap=02A4B -capcup=02A47 -capdot=02A40 -caret=02041 -caron=002C7 -ccaps=02A4D -ccaron=0010D -ccedil=000E7 -ccirc=00109 -ccups=02A4C -ccupssm=02A50 -cdot=0010B -cedil=000B8 -cemptyv=029B2 -cent=000A2 -centerdot=000B7 -cfr=1D520 -chcy=00447 -check=02713 -checkmark=02713 -chi=003C7 -cir=025CB -cirE=029C3 -circ=002C6 -circeq=02257 -circlearrowleft=021BA -circlearrowright=021BB -circledR=000AE -circledS=024C8 -circledast=0229B -circledcirc=0229A -circleddash=0229D -cire=02257 -cirfnint=02A10 -cirmid=02AEF -cirscir=029C2 -clubs=02663 -clubsuit=02663 -colon=0003A -colone=02254 -coloneq=02254 -comma=0002C -commat=00040 -comp=02201 -compfn=02218 -complement=02201 -complexes=02102 -cong=02245 -congdot=02A6D -conint=0222E -copf=1D554 -coprod=02210 -copy=000A9 -copysr=02117 -crarr=021B5 -cross=02717 -cscr=1D4B8 -csub=02ACF -csube=02AD1 -csup=02AD0 -csupe=02AD2 -ctdot=022EF -cudarrl=02938 -cudarrr=02935 -cuepr=022DE -cuesc=022DF -cularr=021B6 -cularrp=0293D -cup=0222A -cupbrcap=02A48 -cupcap=02A46 -cupcup=02A4A -cupdot=0228D -cupor=02A45 -curarr=021B7 -curarrm=0293C -curlyeqprec=022DE -curlyeqsucc=022DF -curlyvee=022CE -curlywedge=022CF -curren=000A4 -curvearrowleft=021B6 -curvearrowright=021B7 -cuvee=022CE -cuwed=022CF -cwconint=02232 -cwint=02231 -cylcty=0232D -dArr=021D3 -dHar=02965 -dagger=02020 -daleth=02138 -darr=02193 -dash=02010 -dashv=022A3 -dbkarow=0290F -dblac=002DD -dcaron=0010F -dcy=00434 -dd=02146 -ddagger=02021 -ddarr=021CA -ddotseq=02A77 -deg=000B0 -delta=003B4 -demptyv=029B1 -dfisht=0297F -dfr=1D521 -dharl=021C3 -dharr=021C2 -diam=022C4 -diamond=022C4 -diamondsuit=02666 -diams=02666 -die=000A8 -digamma=003DD -disin=022F2 -div=000F7 -divide=000F7 -divideontimes=022C7 -divonx=022C7 -djcy=00452 -dlcorn=0231E -dlcrop=0230D -dollar=00024 -dopf=1D555 -dot=002D9 -doteq=02250 -doteqdot=02251 -dotminus=02238 -dotplus=02214 -dotsquare=022A1 -doublebarwedge=02306 -downarrow=02193 -downdownarrows=021CA -downharpoonleft=021C3 -downharpoonright=021C2 -drbkarow=02910 -drcorn=0231F -drcrop=0230C -dscr=1D4B9 -dscy=00455 -dsol=029F6 -dstrok=00111 -dtdot=022F1 -dtri=025BF -dtrif=025BE -duarr=021F5 -duhar=0296F -dwangle=029A6 -dzcy=0045F -dzigrarr=027FF -eDDot=02A77 -eDot=02251 -eacute=000E9 -easter=02A6E -ecaron=0011B -ecir=02256 -ecirc=000EA -ecolon=02255 -ecy=0044D -edot=00117 -ee=02147 -efDot=02252 -efr=1D522 -eg=02A9A -egrave=000E8 -egs=02A96 -egsdot=02A98 -el=02A99 -elinters=023E7 -ell=02113 -els=02A95 -elsdot=02A97 -emacr=00113 -empty=02205 -emptyset=02205 -emptyv=02205 -emsp13=02004 -emsp14=02005 -emsp=02003 -eng=0014B -ensp=02002 -eogon=00119 -eopf=1D556 -epar=022D5 -eparsl=029E3 -eplus=02A71 -epsi=003B5 -epsilon=003B5 -epsiv=003F5 -eqcirc=02256 -eqcolon=02255 -eqsim=02242 -eqslantgtr=02A96 -eqslantless=02A95 -equals=0003D -equest=0225F -equiv=02261 -equivDD=02A78 -eqvparsl=029E5 -erDot=02253 -erarr=02971 -escr=0212F -esdot=02250 -esim=02242 -eta=003B7 -eth=000F0 -euml=000EB -euro=020AC -excl=00021 -exist=02203 -expectation=02130 -exponentiale=02147 -fallingdotseq=02252 -fcy=00444 -female=02640 -ffilig=0FB03 -fflig=0FB00 -ffllig=0FB04 -ffr=1D523 -filig=0FB01 -flat=0266D -fllig=0FB02 -fltns=025B1 -fnof=00192 -fopf=1D557 -forall=02200 -fork=022D4 -forkv=02AD9 -fpartint=02A0D -frac12=000BD -frac13=02153 -frac14=000BC -frac15=02155 -frac16=02159 -frac18=0215B -frac23=02154 -frac25=02156 -frac34=000BE -frac35=02157 -frac38=0215C -frac45=02158 -frac56=0215A -frac58=0215D -frac78=0215E -frasl=02044 -frown=02322 -fscr=1D4BB -gE=02267 -gEl=02A8C -gacute=001F5 -gamma=003B3 -gammad=003DD -gap=02A86 -gbreve=0011F -gcirc=0011D -gcy=00433 -gdot=00121 -ge=02265 -gel=022DB -geq=02265 -geqq=02267 -geqslant=02A7E -ges=02A7E -gescc=02AA9 -gesdot=02A80 -gesdoto=02A82 -gesdotol=02A84 -gesles=02A94 -gfr=1D524 -gg=0226B -ggg=022D9 -gimel=02137 -gjcy=00453 -gl=02277 -glE=02A92 -gla=02AA5 -glj=02AA4 -gnE=02269 -gnap=02A8A -gnapprox=02A8A -gne=02A88 -gneq=02A88 -gneqq=02269 -gnsim=022E7 -gopf=1D558 -grave=00060 -gscr=0210A -gsim=02273 -gsime=02A8E -gsiml=02A90 -gt=0003E -gtcc=02AA7 -gtcir=02A7A -gtdot=022D7 -gtlPar=02995 -gtquest=02A7C -gtrapprox=02A86 -gtrarr=02978 -gtrdot=022D7 -gtreqless=022DB -gtreqqless=02A8C -gtrless=02277 -gtrsim=02273 -hArr=021D4 -hairsp=0200A -half=000BD -hamilt=0210B -hardcy=0044A -harr=02194 -harrcir=02948 -harrw=021AD -hbar=0210F -hcirc=00125 -hearts=02665 -heartsuit=02665 -hellip=02026 -hercon=022B9 -hfr=1D525 -hksearow=02925 -hkswarow=02926 -hoarr=021FF -homtht=0223B -hookleftarrow=021A9 -hookrightarrow=021AA -hopf=1D559 -horbar=02015 -hscr=1D4BD -hslash=0210F -hstrok=00127 -hybull=02043 -hyphen=02010 -iacute=000ED -ic=02063 -icirc=000EE -icy=00438 -iecy=00435 -iexcl=000A1 -iff=021D4 -ifr=1D526 -igrave=000EC -ii=02148 -iiiint=02A0C -iiint=0222D -iinfin=029DC -iiota=02129 -ijlig=00133 -imacr=0012B -image=02111 -imagline=02110 -imagpart=02111 -imath=00131 -imof=022B7 -imped=001B5 -in=02208 -incare=02105 -infin=0221E -infintie=029DD -inodot=00131 -int=0222B -intcal=022BA -integers=02124 -intercal=022BA -intlarhk=02A17 -intprod=02A3C -iocy=00451 -iogon=0012F -iopf=1D55A -iota=003B9 -iprod=02A3C -iquest=000BF -iscr=1D4BE -isin=02208 -isinE=022F9 -isindot=022F5 -isins=022F4 -isinsv=022F3 -isinv=02208 -it=02062 -itilde=00129 -iukcy=00456 -iuml=000EF -jcirc=00135 -jcy=00439 -jfr=1D527 -jmath=00237 -jopf=1D55B -jscr=1D4BF -jsercy=00458 -jukcy=00454 -kappa=003BA -kappav=003F0 -kcedil=00137 -kcy=0043A -kfr=1D528 -kgreen=00138 -khcy=00445 -kjcy=0045C -kopf=1D55C -kscr=1D4C0 -lAarr=021DA -lArr=021D0 -lAtail=0291B -lBarr=0290E -lE=02266 -lEg=02A8B -lHar=02962 -lacute=0013A -laemptyv=029B4 -lagran=02112 -lambda=003BB -lang=027E8 -langd=02991 -langle=027E8 -lap=02A85 -laquo=000AB -larr=02190 -larrb=021E4 -larrbfs=0291F -larrfs=0291D -larrhk=021A9 -larrlp=021AB -larrpl=02939 -larrsim=02973 -larrtl=021A2 -lat=02AAB -latail=02919 -late=02AAD -lbarr=0290C -lbbrk=02772 -lbrace=0007B -lbrack=0005B -lbrke=0298B -lbrksld=0298F -lbrkslu=0298D -lcaron=0013E -lcedil=0013C -lceil=02308 -lcub=0007B -lcy=0043B -ldca=02936 -ldquo=0201C -ldquor=0201E -ldrdhar=02967 -ldrushar=0294B -ldsh=021B2 -le=02264 -leftarrow=02190 -leftarrowtail=021A2 -leftharpoondown=021BD -leftharpoonup=021BC -leftleftarrows=021C7 -leftrightarrow=02194 -leftrightarrows=021C6 -leftrightharpoons=021CB -leftrightsquigarrow=021AD -leftthreetimes=022CB -leg=022DA -leq=02264 -leqq=02266 -leqslant=02A7D -les=02A7D -lescc=02AA8 -lesdot=02A7F -lesdoto=02A81 -lesdotor=02A83 -lesges=02A93 -lessapprox=02A85 -lessdot=022D6 -lesseqgtr=022DA -lesseqqgtr=02A8B -lessgtr=02276 -lesssim=02272 -lfisht=0297C -lfloor=0230A -lfr=1D529 -lg=02276 -lgE=02A91 -lhard=021BD -lharu=021BC -lharul=0296A -lhblk=02584 -ljcy=00459 -ll=0226A -llarr=021C7 -llcorner=0231E -llhard=0296B -lltri=025FA -lmidot=00140 -lmoust=023B0 -lmoustache=023B0 -lnE=02268 -lnap=02A89 -lnapprox=02A89 -lne=02A87 -lneq=02A87 -lneqq=02268 -lnsim=022E6 -loang=027EC -loarr=021FD -lobrk=027E6 -longleftarrow=027F5 -longleftrightarrow=027F7 -longmapsto=027FC -longrightarrow=027F6 -looparrowleft=021AB -looparrowright=021AC -lopar=02985 -lopf=1D55D -loplus=02A2D -lotimes=02A34 -lowast=02217 -lowbar=0005F -loz=025CA -lozenge=025CA -lozf=029EB -lpar=00028 -lparlt=02993 -lrarr=021C6 -lrcorner=0231F -lrhar=021CB -lrhard=0296D -lrm=0200E -lrtri=022BF -lsaquo=02039 -lscr=1D4C1 -lsh=021B0 -lsim=02272 -lsime=02A8D -lsimg=02A8F -lsqb=0005B -lsquo=02018 -lsquor=0201A -lstrok=00142 -lt=0003C -ltcc=02AA6 -ltcir=02A79 -ltdot=022D6 -lthree=022CB -ltimes=022C9 -ltlarr=02976 -ltquest=02A7B -ltrPar=02996 -ltri=025C3 -ltrie=022B4 -ltrif=025C2 -lurdshar=0294A -luruhar=02966 -mDDot=0223A -macr=000AF -male=02642 -malt=02720 -maltese=02720 -map=021A6 -mapsto=021A6 -mapstodown=021A7 -mapstoleft=021A4 -mapstoup=021A5 -marker=025AE -mcomma=02A29 -mcy=0043C -mdash=02014 -measuredangle=02221 -mfr=1D52A -mho=02127 -micro=000B5 -mid=02223 -midast=0002A -midcir=02AF0 -middot=000B7 -minus=02212 -minusb=0229F -minusd=02238 -minusdu=02A2A -mlcp=02ADB -mldr=02026 -mnplus=02213 -models=022A7 -mopf=1D55E -mp=02213 -mscr=1D4C2 -mstpos=0223E -mu=003BC -multimap=022B8 -mumap=022B8 -nLeftarrow=021CD -nLeftrightarrow=021CE -nRightarrow=021CF -nVDash=022AF -nVdash=022AE -nabla=02207 -nacute=00144 -nap=02249 -napos=00149 -napprox=02249 -natur=0266E -natural=0266E -naturals=02115 -nbsp=000A0 -ncap=02A43 -ncaron=00148 -ncedil=00146 -ncong=02247 -ncup=02A42 -ncy=0043D -ndash=02013 -ne=02260 -neArr=021D7 -nearhk=02924 -nearr=02197 -nearrow=02197 -nequiv=02262 -nesear=02928 -nexist=02204 -nexists=02204 -nfr=1D52B -nge=02271 -ngeq=02271 -ngsim=02275 -ngt=0226F -ngtr=0226F -nhArr=021CE -nharr=021AE -nhpar=02AF2 -ni=0220B -nis=022FC -nisd=022FA -niv=0220B -njcy=0045A -nlArr=021CD -nlarr=0219A -nldr=02025 -nle=02270 -nleftarrow=0219A -nleftrightarrow=021AE -nleq=02270 -nless=0226E -nlsim=02274 -nlt=0226E -nltri=022EA -nltrie=022EC -nmid=02224 -nopf=1D55F -not=000AC -notin=02209 -notinva=02209 -notinvb=022F7 -notinvc=022F6 -notni=0220C -notniva=0220C -notnivb=022FE -notnivc=022FD -npar=02226 -nparallel=02226 -npolint=02A14 -npr=02280 -nprcue=022E0 -nprec=02280 -nrArr=021CF -nrarr=0219B -nrightarrow=0219B -nrtri=022EB -nrtrie=022ED -nsc=02281 -nsccue=022E1 -nscr=1D4C3 -nshortmid=02224 -nshortparallel=02226 -nsim=02241 -nsime=02244 -nsimeq=02244 -nsmid=02224 -nspar=02226 -nsqsube=022E2 -nsqsupe=022E3 -nsub=02284 -nsube=02288 -nsubseteq=02288 -nsucc=02281 -nsup=02285 -nsupe=02289 -nsupseteq=02289 -ntgl=02279 -ntilde=000F1 -ntlg=02278 -ntriangleleft=022EA -ntrianglelefteq=022EC -ntriangleright=022EB -ntrianglerighteq=022ED -nu=003BD -num=00023 -numero=02116 -numsp=02007 -nvDash=022AD -nvHarr=02904 -nvdash=022AC -nvinfin=029DE -nvlArr=02902 -nvrArr=02903 -nwArr=021D6 -nwarhk=02923 -nwarr=02196 -nwarrow=02196 -nwnear=02927 -oS=024C8 -oacute=000F3 -oast=0229B -ocir=0229A -ocirc=000F4 -ocy=0043E -odash=0229D -odblac=00151 -odiv=02A38 -odot=02299 -odsold=029BC -oelig=00153 -ofcir=029BF -ofr=1D52C -ogon=002DB -ograve=000F2 -ogt=029C1 -ohbar=029B5 -ohm=003A9 -oint=0222E -olarr=021BA -olcir=029BE -olcross=029BB -oline=0203E -olt=029C0 -omacr=0014D -omega=003C9 -omicron=003BF -omid=029B6 -ominus=02296 -oopf=1D560 -opar=029B7 -operp=029B9 -oplus=02295 -or=02228 -orarr=021BB -ord=02A5D -order=02134 -orderof=02134 -ordf=000AA -ordm=000BA -origof=022B6 -oror=02A56 -orslope=02A57 -orv=02A5B -oscr=02134 -oslash=000F8 -osol=02298 -otilde=000F5 -otimes=02297 -otimesas=02A36 -ouml=000F6 -ovbar=0233D -par=02225 -para=000B6 -parallel=02225 -parsim=02AF3 -parsl=02AFD -part=02202 -pcy=0043F -percnt=00025 -period=0002E -permil=02030 -perp=022A5 -pertenk=02031 -pfr=1D52D -phi=003C6 -phiv=003D5 -phmmat=02133 -phone=0260E -pi=003C0 -pitchfork=022D4 -piv=003D6 -planck=0210F -planckh=0210E -plankv=0210F -plus=0002B -plusacir=02A23 -plusb=0229E -pluscir=02A22 -plusdo=02214 -plusdu=02A25 -pluse=02A72 -plusmn=000B1 -plussim=02A26 -plustwo=02A27 -pm=000B1 -pointint=02A15 -popf=1D561 -pound=000A3 -pr=0227A -prE=02AB3 -prap=02AB7 -prcue=0227C -pre=02AAF -prec=0227A -precapprox=02AB7 -preccurlyeq=0227C -preceq=02AAF -precnapprox=02AB9 -precneqq=02AB5 -precnsim=022E8 -precsim=0227E -prime=02032 -primes=02119 -prnE=02AB5 -prnap=02AB9 -prnsim=022E8 -prod=0220F -profalar=0232E -profline=02312 -profsurf=02313 -prop=0221D -propto=0221D -prsim=0227E -prurel=022B0 -pscr=1D4C5 -psi=003C8 -puncsp=02008 -qfr=1D52E -qint=02A0C -qopf=1D562 -qprime=02057 -qscr=1D4C6 -quaternions=0210D -quatint=02A16 -quest=0003F -questeq=0225F -quot=00022 -rAarr=021DB -rArr=021D2 -rAtail=0291C -rBarr=0290F -rHar=02964 -racute=00155 -radic=0221A -raemptyv=029B3 -rang=027E9 -rangd=02992 -range=029A5 -rangle=027E9 -raquo=000BB -rarr=02192 -rarrap=02975 -rarrb=021E5 -rarrbfs=02920 -rarrc=02933 -rarrfs=0291E -rarrhk=021AA -rarrlp=021AC -rarrpl=02945 -rarrsim=02974 -rarrtl=021A3 -rarrw=0219D -ratail=0291A -ratio=02236 -rationals=0211A -rbarr=0290D -rbbrk=02773 -rbrace=0007D -rbrack=0005D -rbrke=0298C -rbrksld=0298E -rbrkslu=02990 -rcaron=00159 -rcedil=00157 -rceil=02309 -rcub=0007D -rcy=00440 -rdca=02937 -rdldhar=02969 -rdquo=0201D -rdquor=0201D -rdsh=021B3 -real=0211C -realine=0211B -realpart=0211C -reals=0211D -rect=025AD -reg=000AE -rfisht=0297D -rfloor=0230B -rfr=1D52F -rhard=021C1 -rharu=021C0 -rharul=0296C -rho=003C1 -rhov=003F1 -rightarrow=02192 -rightarrowtail=021A3 -rightharpoondown=021C1 -rightharpoonup=021C0 -rightleftarrows=021C4 -rightleftharpoons=021CC -rightrightarrows=021C9 -rightsquigarrow=0219D -rightthreetimes=022CC -ring=002DA -risingdotseq=02253 -rlarr=021C4 -rlhar=021CC -rlm=0200F -rmoust=023B1 -rmoustache=023B1 -rnmid=02AEE -roang=027ED -roarr=021FE -robrk=027E7 -ropar=02986 -ropf=1D563 -roplus=02A2E -rotimes=02A35 -rpar=00029 -rpargt=02994 -rppolint=02A12 -rrarr=021C9 -rsaquo=0203A -rscr=1D4C7 -rsh=021B1 -rsqb=0005D -rsquo=02019 -rsquor=02019 -rthree=022CC -rtimes=022CA -rtri=025B9 -rtrie=022B5 -rtrif=025B8 -rtriltri=029CE -ruluhar=02968 -rx=0211E -sacute=0015B -sbquo=0201A -sc=0227B -scE=02AB4 -scap=02AB8 -scaron=00161 -sccue=0227D -sce=02AB0 -scedil=0015F -scirc=0015D -scnE=02AB6 -scnap=02ABA -scnsim=022E9 -scpolint=02A13 -scsim=0227F -scy=00441 -sdot=022C5 -sdotb=022A1 -sdote=02A66 -seArr=021D8 -searhk=02925 -searr=02198 -searrow=02198 -sect=000A7 -semi=0003B -seswar=02929 -setminus=02216 -setmn=02216 -sext=02736 -sfr=1D530 -sfrown=02322 -sharp=0266F -shchcy=00449 -shcy=00448 -shortmid=02223 -shortparallel=02225 -shy=000AD -sigma=003C3 -sigmaf=003C2 -sigmav=003C2 -sim=0223C -simdot=02A6A -sime=02243 -simeq=02243 -simg=02A9E -simgE=02AA0 -siml=02A9D -simlE=02A9F -simne=02246 -simplus=02A24 -simrarr=02972 -slarr=02190 -smallsetminus=02216 -smashp=02A33 -smeparsl=029E4 -smid=02223 -smile=02323 -smt=02AAA -smte=02AAC -softcy=0044C -sol=0002F -solb=029C4 -solbar=0233F -sopf=1D564 -spades=02660 -spadesuit=02660 -spar=02225 -sqcap=02293 -sqcup=02294 -sqsub=0228F -sqsube=02291 -sqsubset=0228F -sqsubseteq=02291 -sqsup=02290 -sqsupe=02292 -sqsupset=02290 -sqsupseteq=02292 -squ=025A1 -square=025A1 -squarf=025AA -squf=025AA -srarr=02192 -sscr=1D4C8 -ssetmn=02216 -ssmile=02323 -sstarf=022C6 -star=02606 -starf=02605 -straightepsilon=003F5 -straightphi=003D5 -strns=000AF -sub=02282 -subE=02AC5 -subdot=02ABD -sube=02286 -subedot=02AC3 -submult=02AC1 -subnE=02ACB -subne=0228A -subplus=02ABF -subrarr=02979 -subset=02282 -subseteq=02286 -subseteqq=02AC5 -subsetneq=0228A -subsetneqq=02ACB -subsim=02AC7 -subsub=02AD5 -subsup=02AD3 -succ=0227B -succapprox=02AB8 -succcurlyeq=0227D -succeq=02AB0 -succnapprox=02ABA -succneqq=02AB6 -succnsim=022E9 -succsim=0227F -sum=02211 -sung=0266A -sup1=000B9 -sup2=000B2 -sup3=000B3 -sup=02283 -supE=02AC6 -supdot=02ABE -supdsub=02AD8 -supe=02287 -supedot=02AC4 -suphsol=027C9 -suphsub=02AD7 -suplarr=0297B -supmult=02AC2 -supnE=02ACC -supne=0228B -supplus=02AC0 -supset=02283 -supseteq=02287 -supseteqq=02AC6 -supsetneq=0228B -supsetneqq=02ACC -supsim=02AC8 -supsub=02AD4 -supsup=02AD6 -swArr=021D9 -swarhk=02926 -swarr=02199 -swarrow=02199 -swnwar=0292A -szlig=000DF -target=02316 -tau=003C4 -tbrk=023B4 -tcaron=00165 -tcedil=00163 -tcy=00442 -tdot=020DB -telrec=02315 -tfr=1D531 -there4=02234 -therefore=02234 -theta=003B8 -thetasym=003D1 -thetav=003D1 -thickapprox=02248 -thicksim=0223C -thinsp=02009 -thkap=02248 -thksim=0223C -thorn=000FE -tilde=002DC -times=000D7 -timesb=022A0 -timesbar=02A31 -timesd=02A30 -tint=0222D -toea=02928 -top=022A4 -topbot=02336 -topcir=02AF1 -topf=1D565 -topfork=02ADA -tosa=02929 -tprime=02034 -trade=02122 -triangle=025B5 -triangledown=025BF -triangleleft=025C3 -trianglelefteq=022B4 -triangleq=0225C -triangleright=025B9 -trianglerighteq=022B5 -tridot=025EC -trie=0225C -triminus=02A3A -triplus=02A39 -trisb=029CD -tritime=02A3B -trpezium=023E2 -tscr=1D4C9 -tscy=00446 -tshcy=0045B -tstrok=00167 -twixt=0226C -twoheadleftarrow=0219E -twoheadrightarrow=021A0 -uArr=021D1 -uHar=02963 -uacute=000FA -uarr=02191 -ubrcy=0045E -ubreve=0016D -ucirc=000FB -ucy=00443 -udarr=021C5 -udblac=00171 -udhar=0296E -ufisht=0297E -ufr=1D532 -ugrave=000F9 -uharl=021BF -uharr=021BE -uhblk=02580 -ulcorn=0231C -ulcorner=0231C -ulcrop=0230F -ultri=025F8 -umacr=0016B -uml=000A8 -uogon=00173 -uopf=1D566 -uparrow=02191 -updownarrow=02195 -upharpoonleft=021BF -upharpoonright=021BE -uplus=0228E -upsi=003C5 -upsih=003D2 -upsilon=003C5 -upuparrows=021C8 -urcorn=0231D -urcorner=0231D -urcrop=0230E -uring=0016F -urtri=025F9 -uscr=1D4CA -utdot=022F0 -utilde=00169 -utri=025B5 -utrif=025B4 -uuarr=021C8 -uuml=000FC -uwangle=029A7 -vArr=021D5 -vBar=02AE8 -vBarv=02AE9 -vDash=022A8 -vangrt=0299C -varepsilon=003F5 -varkappa=003F0 -varnothing=02205 -varphi=003D5 -varpi=003D6 -varpropto=0221D -varr=02195 -varrho=003F1 -varsigma=003C2 -vartheta=003D1 -vartriangleleft=022B2 -vartriangleright=022B3 -vcy=00432 -vdash=022A2 -vee=02228 -veebar=022BB -veeeq=0225A -vellip=022EE -verbar=0007C -vert=0007C -vfr=1D533 -vltri=022B2 -vopf=1D567 -vprop=0221D -vrtri=022B3 -vscr=1D4CB -vzigzag=0299A -wcirc=00175 -wedbar=02A5F -wedge=02227 -wedgeq=02259 -weierp=02118 -wfr=1D534 -wopf=1D568 -wp=02118 -wr=02240 -wreath=02240 -wscr=1D4CC -xcap=022C2 -xcirc=025EF -xcup=022C3 -xdtri=025BD -xfr=1D535 -xhArr=027FA -xharr=027F7 -xi=003BE -xlArr=027F8 -xlarr=027F5 -xmap=027FC -xnis=022FB -xodot=02A00 -xopf=1D569 -xoplus=02A01 -xotime=02A02 -xrArr=027F9 -xrarr=027F6 -xscr=1D4CD -xsqcup=02A06 -xuplus=02A04 -xutri=025B3 -xvee=022C1 -xwedge=022C0 -yacute=000FD -yacy=0044F -ycirc=00177 -ycy=0044B -yen=000A5 -yfr=1D536 -yicy=00457 -yopf=1D56A -yscr=1D4CE -yucy=0044E -yuml=000FF -zacute=0017A -zcaron=0017E -zcy=00437 -zdot=0017C -zeetrf=02128 -zeta=003B6 -zfr=1D537 -zhcy=00436 -zigrarr=021DD -zopf=1D56B -zscr=1D4CF -zwj=0200D -zwnj=0200C diff --git a/src/org/jsoup/nodes/package-info.java b/src/org/jsoup/nodes/package-info.java deleted file mode 100644 index 24b12803ff..0000000000 --- a/src/org/jsoup/nodes/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - HTML document structure nodes. - */ -package org.jsoup.nodes;
\ No newline at end of file diff --git a/src/org/jsoup/package-info.java b/src/org/jsoup/package-info.java deleted file mode 100644 index 49526116b4..0000000000 --- a/src/org/jsoup/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - Contains the main {@link org.jsoup.Jsoup} class, which provides convenient static access to the jsoup functionality. - */ -package org.jsoup;
\ No newline at end of file diff --git a/src/org/jsoup/parser/CharacterReader.java b/src/org/jsoup/parser/CharacterReader.java deleted file mode 100644 index b549a571a0..0000000000 --- a/src/org/jsoup/parser/CharacterReader.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.Validate; - -/** - CharacterReader consumes tokens off a string. To replace the old TokenQueue. - */ -class CharacterReader { - static final char EOF = (char) -1; - - private final String input; - private final int length; - private int pos = 0; - private int mark = 0; - - CharacterReader(String input) { - Validate.notNull(input); - input = input.replaceAll("\r\n?", "\n"); // normalise carriage returns to newlines - - this.input = input; - this.length = input.length(); - } - - int pos() { - return pos; - } - - boolean isEmpty() { - return pos >= length; - } - - char current() { - return isEmpty() ? EOF : input.charAt(pos); - } - - char consume() { - char val = isEmpty() ? EOF : input.charAt(pos); - pos++; - return val; - } - - void unconsume() { - pos--; - } - - void advance() { - pos++; - } - - void mark() { - mark = pos; - } - - void rewindToMark() { - pos = mark; - } - - String consumeAsString() { - return input.substring(pos, pos++); - } - - String consumeTo(char c) { - int offset = input.indexOf(c, pos); - if (offset != -1) { - String consumed = input.substring(pos, offset); - pos += consumed.length(); - return consumed; - } else { - return consumeToEnd(); - } - } - - String consumeTo(String seq) { - int offset = input.indexOf(seq, pos); - if (offset != -1) { - String consumed = input.substring(pos, offset); - pos += consumed.length(); - return consumed; - } else { - return consumeToEnd(); - } - } - - String consumeToAny(char... seq) { - int start = pos; - - OUTER: while (!isEmpty()) { - char c = input.charAt(pos); - for (char seek : seq) { - if (seek == c) - break OUTER; - } - pos++; - } - - return pos > start ? input.substring(start, pos) : ""; - } - - String consumeToEnd() { - String data = input.substring(pos, input.length()); - pos = input.length(); - return data; - } - - String consumeLetterSequence() { - int start = pos; - while (!isEmpty()) { - char c = input.charAt(pos); - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) - pos++; - else - break; - } - - return input.substring(start, pos); - } - - String consumeLetterThenDigitSequence() { - int start = pos; - while (!isEmpty()) { - char c = input.charAt(pos); - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) - pos++; - else - break; - } - while (!isEmpty()) { - char c = input.charAt(pos); - if (c >= '0' && c <= '9') - pos++; - else - break; - } - - return input.substring(start, pos); - } - - String consumeHexSequence() { - int start = pos; - while (!isEmpty()) { - char c = input.charAt(pos); - if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f')) - pos++; - else - break; - } - return input.substring(start, pos); - } - - String consumeDigitSequence() { - int start = pos; - while (!isEmpty()) { - char c = input.charAt(pos); - if (c >= '0' && c <= '9') - pos++; - else - break; - } - return input.substring(start, pos); - } - - boolean matches(char c) { - return !isEmpty() && input.charAt(pos) == c; - - } - - boolean matches(String seq) { - return input.startsWith(seq, pos); - } - - boolean matchesIgnoreCase(String seq) { - return input.regionMatches(true, pos, seq, 0, seq.length()); - } - - boolean matchesAny(char... seq) { - if (isEmpty()) - return false; - - char c = input.charAt(pos); - for (char seek : seq) { - if (seek == c) - return true; - } - return false; - } - - boolean matchesLetter() { - if (isEmpty()) - return false; - char c = input.charAt(pos); - return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); - } - - boolean matchesDigit() { - if (isEmpty()) - return false; - char c = input.charAt(pos); - return (c >= '0' && c <= '9'); - } - - boolean matchConsume(String seq) { - if (matches(seq)) { - pos += seq.length(); - return true; - } else { - return false; - } - } - - boolean matchConsumeIgnoreCase(String seq) { - if (matchesIgnoreCase(seq)) { - pos += seq.length(); - return true; - } else { - return false; - } - } - - boolean containsIgnoreCase(String seq) { - // used to check presence of </title>, </style>. only finds consistent case. - String loScan = seq.toLowerCase(); - String hiScan = seq.toUpperCase(); - return (input.indexOf(loScan, pos) > -1) || (input.indexOf(hiScan, pos) > -1); - } - - @Override - public String toString() { - return input.substring(pos); - } -} diff --git a/src/org/jsoup/parser/HtmlTreeBuilder.java b/src/org/jsoup/parser/HtmlTreeBuilder.java deleted file mode 100644 index 457a4c3249..0000000000 --- a/src/org/jsoup/parser/HtmlTreeBuilder.java +++ /dev/null @@ -1,672 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.DescendableLinkedList; -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; -import org.jsoup.nodes.*; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; - -/** - * HTML Tree Builder; creates a DOM from Tokens. - */ -class HtmlTreeBuilder extends TreeBuilder { - - private HtmlTreeBuilderState state; // the current state - private HtmlTreeBuilderState originalState; // original / marked state - - private boolean baseUriSetFromDoc = false; - private Element headElement; // the current head element - private Element formElement; // the current form element - private Element contextElement; // fragment parse context -- could be null even if fragment parsing - private DescendableLinkedList<Element> formattingElements = new DescendableLinkedList<Element>(); // active (open) formatting elements - private List<Token.Character> pendingTableCharacters = new ArrayList<Token.Character>(); // chars in table to be shifted out - - private boolean framesetOk = true; // if ok to go into frameset - private boolean fosterInserts = false; // if next inserts should be fostered - private boolean fragmentParsing = false; // if parsing a fragment of html - - HtmlTreeBuilder() {} - - @Override - Document parse(String input, String baseUri, ParseErrorList errors) { - state = HtmlTreeBuilderState.Initial; - return super.parse(input, baseUri, errors); - } - - List<Node> parseFragment(String inputFragment, Element context, String baseUri, ParseErrorList errors) { - // context may be null - state = HtmlTreeBuilderState.Initial; - initialiseParse(inputFragment, baseUri, errors); - contextElement = context; - fragmentParsing = true; - Element root = null; - - if (context != null) { - if (context.ownerDocument() != null) // quirks setup: - doc.quirksMode(context.ownerDocument().quirksMode()); - - // initialise the tokeniser state: - String contextTag = context.tagName(); - if (StringUtil.in(contextTag, "title", "textarea")) - tokeniser.transition(TokeniserState.Rcdata); - else if (StringUtil.in(contextTag, "iframe", "noembed", "noframes", "style", "xmp")) - tokeniser.transition(TokeniserState.Rawtext); - else if (contextTag.equals("script")) - tokeniser.transition(TokeniserState.ScriptData); - else if (contextTag.equals(("noscript"))) - tokeniser.transition(TokeniserState.Data); // if scripting enabled, rawtext - else if (contextTag.equals("plaintext")) - tokeniser.transition(TokeniserState.Data); - else - tokeniser.transition(TokeniserState.Data); // default - - root = new Element(Tag.valueOf("html"), baseUri); - doc.appendChild(root); - stack.push(root); - resetInsertionMode(); - // todo: setup form element to nearest form on context (up ancestor chain) - } - - runParser(); - if (context != null) - return root.childNodes(); - else - return doc.childNodes(); - } - - @Override - protected boolean process(Token token) { - currentToken = token; - return this.state.process(token, this); - } - - boolean process(Token token, HtmlTreeBuilderState state) { - currentToken = token; - return state.process(token, this); - } - - void transition(HtmlTreeBuilderState state) { - this.state = state; - } - - HtmlTreeBuilderState state() { - return state; - } - - void markInsertionMode() { - originalState = state; - } - - HtmlTreeBuilderState originalState() { - return originalState; - } - - void framesetOk(boolean framesetOk) { - this.framesetOk = framesetOk; - } - - boolean framesetOk() { - return framesetOk; - } - - Document getDocument() { - return doc; - } - - String getBaseUri() { - return baseUri; - } - - void maybeSetBaseUri(Element base) { - if (baseUriSetFromDoc) // only listen to the first <base href> in parse - return; - - String href = base.absUrl("href"); - if (href.length() != 0) { // ignore <base target> etc - baseUri = href; - baseUriSetFromDoc = true; - doc.setBaseUri(href); // set on the doc so doc.createElement(Tag) will get updated base, and to update all descendants - } - } - - boolean isFragmentParsing() { - return fragmentParsing; - } - - void error(HtmlTreeBuilderState state) { - if (errors.canAddError()) - errors.add(new ParseError(reader.pos(), "Unexpected token [%s] when in state [%s]", currentToken.tokenType(), state)); - } - - Element insert(Token.StartTag startTag) { - // handle empty unknown tags - // when the spec expects an empty tag, will directly hit insertEmpty, so won't generate fake end tag. - if (startTag.isSelfClosing() && !Tag.isKnownTag(startTag.name())) { - Element el = insertEmpty(startTag); - process(new Token.EndTag(el.tagName())); // ensure we get out of whatever state we are in - return el; - } - - Element el = new Element(Tag.valueOf(startTag.name()), baseUri, startTag.attributes); - insert(el); - return el; - } - - Element insert(String startTagName) { - Element el = new Element(Tag.valueOf(startTagName), baseUri); - insert(el); - return el; - } - - void insert(Element el) { - insertNode(el); - stack.add(el); - } - - Element insertEmpty(Token.StartTag startTag) { - Tag tag = Tag.valueOf(startTag.name()); - Element el = new Element(tag, baseUri, startTag.attributes); - insertNode(el); - if (startTag.isSelfClosing()) { - tokeniser.acknowledgeSelfClosingFlag(); - if (!tag.isKnownTag()) // unknown tag, remember this is self closing for output - tag.setSelfClosing(); - } - return el; - } - - void insert(Token.Comment commentToken) { - Comment comment = new Comment(commentToken.getData(), baseUri); - insertNode(comment); - } - - void insert(Token.Character characterToken) { - Node node; - // characters in script and style go in as datanodes, not text nodes - if (StringUtil.in(currentElement().tagName(), "script", "style")) - node = new DataNode(characterToken.getData(), baseUri); - else - node = new TextNode(characterToken.getData(), baseUri); - currentElement().appendChild(node); // doesn't use insertNode, because we don't foster these; and will always have a stack. - } - - private void insertNode(Node node) { - // if the stack hasn't been set up yet, elements (doctype, comments) go into the doc - if (stack.size() == 0) - doc.appendChild(node); - else if (isFosterInserts()) - insertInFosterParent(node); - else - currentElement().appendChild(node); - } - - Element pop() { - // todo - dev, remove validation check - if (stack.peekLast().nodeName().equals("td") && !state.name().equals("InCell")) - Validate.isFalse(true, "pop td not in cell"); - if (stack.peekLast().nodeName().equals("html")) - Validate.isFalse(true, "popping html!"); - return stack.pollLast(); - } - - void push(Element element) { - stack.add(element); - } - - DescendableLinkedList<Element> getStack() { - return stack; - } - - boolean onStack(Element el) { - return isElementInQueue(stack, el); - } - - private boolean isElementInQueue(DescendableLinkedList<Element> queue, Element element) { - Iterator<Element> it = queue.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next == element) { - return true; - } - } - return false; - } - - Element getFromStack(String elName) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next.nodeName().equals(elName)) { - return next; - } - } - return null; - } - - boolean removeFromStack(Element el) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next == el) { - it.remove(); - return true; - } - } - return false; - } - - void popStackToClose(String elName) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next.nodeName().equals(elName)) { - it.remove(); - break; - } else { - it.remove(); - } - } - } - - void popStackToClose(String... elNames) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (StringUtil.in(next.nodeName(), elNames)) { - it.remove(); - break; - } else { - it.remove(); - } - } - } - - void popStackToBefore(String elName) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next.nodeName().equals(elName)) { - break; - } else { - it.remove(); - } - } - } - - void clearStackToTableContext() { - clearStackToContext("table"); - } - - void clearStackToTableBodyContext() { - clearStackToContext("tbody", "tfoot", "thead"); - } - - void clearStackToTableRowContext() { - clearStackToContext("tr"); - } - - private void clearStackToContext(String... nodeNames) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (StringUtil.in(next.nodeName(), nodeNames) || next.nodeName().equals("html")) - break; - else - it.remove(); - } - } - - Element aboveOnStack(Element el) { - assert onStack(el); - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next == el) { - return it.next(); - } - } - return null; - } - - void insertOnStackAfter(Element after, Element in) { - int i = stack.lastIndexOf(after); - Validate.isTrue(i != -1); - stack.add(i+1, in); - } - - void replaceOnStack(Element out, Element in) { - replaceInQueue(stack, out, in); - } - - private void replaceInQueue(LinkedList<Element> queue, Element out, Element in) { - int i = queue.lastIndexOf(out); - Validate.isTrue(i != -1); - queue.remove(i); - queue.add(i, in); - } - - void resetInsertionMode() { - boolean last = false; - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element node = it.next(); - if (!it.hasNext()) { - last = true; - node = contextElement; - } - String name = node.nodeName(); - if ("select".equals(name)) { - transition(HtmlTreeBuilderState.InSelect); - break; // frag - } else if (("td".equals(name) || "td".equals(name) && !last)) { - transition(HtmlTreeBuilderState.InCell); - break; - } else if ("tr".equals(name)) { - transition(HtmlTreeBuilderState.InRow); - break; - } else if ("tbody".equals(name) || "thead".equals(name) || "tfoot".equals(name)) { - transition(HtmlTreeBuilderState.InTableBody); - break; - } else if ("caption".equals(name)) { - transition(HtmlTreeBuilderState.InCaption); - break; - } else if ("colgroup".equals(name)) { - transition(HtmlTreeBuilderState.InColumnGroup); - break; // frag - } else if ("table".equals(name)) { - transition(HtmlTreeBuilderState.InTable); - break; - } else if ("head".equals(name)) { - transition(HtmlTreeBuilderState.InBody); - break; // frag - } else if ("body".equals(name)) { - transition(HtmlTreeBuilderState.InBody); - break; - } else if ("frameset".equals(name)) { - transition(HtmlTreeBuilderState.InFrameset); - break; // frag - } else if ("html".equals(name)) { - transition(HtmlTreeBuilderState.BeforeHead); - break; // frag - } else if (last) { - transition(HtmlTreeBuilderState.InBody); - break; // frag - } - } - } - - // todo: tidy up in specific scope methods - private boolean inSpecificScope(String targetName, String[] baseTypes, String[] extraTypes) { - return inSpecificScope(new String[]{targetName}, baseTypes, extraTypes); - } - - private boolean inSpecificScope(String[] targetNames, String[] baseTypes, String[] extraTypes) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element el = it.next(); - String elName = el.nodeName(); - if (StringUtil.in(elName, targetNames)) - return true; - if (StringUtil.in(elName, baseTypes)) - return false; - if (extraTypes != null && StringUtil.in(elName, extraTypes)) - return false; - } - Validate.fail("Should not be reachable"); - return false; - } - - boolean inScope(String[] targetNames) { - return inSpecificScope(targetNames, new String[]{"applet", "caption", "html", "table", "td", "th", "marquee", "object"}, null); - } - - boolean inScope(String targetName) { - return inScope(targetName, null); - } - - boolean inScope(String targetName, String[] extras) { - return inSpecificScope(targetName, new String[]{"applet", "caption", "html", "table", "td", "th", "marquee", "object"}, extras); - // todo: in mathml namespace: mi, mo, mn, ms, mtext annotation-xml - // todo: in svg namespace: forignOjbect, desc, title - } - - boolean inListItemScope(String targetName) { - return inScope(targetName, new String[]{"ol", "ul"}); - } - - boolean inButtonScope(String targetName) { - return inScope(targetName, new String[]{"button"}); - } - - boolean inTableScope(String targetName) { - return inSpecificScope(targetName, new String[]{"html", "table"}, null); - } - - boolean inSelectScope(String targetName) { - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element el = it.next(); - String elName = el.nodeName(); - if (elName.equals(targetName)) - return true; - if (!StringUtil.in(elName, "optgroup", "option")) // all elements except - return false; - } - Validate.fail("Should not be reachable"); - return false; - } - - void setHeadElement(Element headElement) { - this.headElement = headElement; - } - - Element getHeadElement() { - return headElement; - } - - boolean isFosterInserts() { - return fosterInserts; - } - - void setFosterInserts(boolean fosterInserts) { - this.fosterInserts = fosterInserts; - } - - Element getFormElement() { - return formElement; - } - - void setFormElement(Element formElement) { - this.formElement = formElement; - } - - void newPendingTableCharacters() { - pendingTableCharacters = new ArrayList<Token.Character>(); - } - - List<Token.Character> getPendingTableCharacters() { - return pendingTableCharacters; - } - - void setPendingTableCharacters(List<Token.Character> pendingTableCharacters) { - this.pendingTableCharacters = pendingTableCharacters; - } - - /** - 11.2.5.2 Closing elements that have implied end tags<p/> - When the steps below require the UA to generate implied end tags, then, while the current node is a dd element, a - dt element, an li element, an option element, an optgroup element, a p element, an rp element, or an rt element, - the UA must pop the current node off the stack of open elements. - - @param excludeTag If a step requires the UA to generate implied end tags but lists an element to exclude from the - process, then the UA must perform the above steps as if that element was not in the above list. - */ - void generateImpliedEndTags(String excludeTag) { - while ((excludeTag != null && !currentElement().nodeName().equals(excludeTag)) && - StringUtil.in(currentElement().nodeName(), "dd", "dt", "li", "option", "optgroup", "p", "rp", "rt")) - pop(); - } - - void generateImpliedEndTags() { - generateImpliedEndTags(null); - } - - boolean isSpecial(Element el) { - // todo: mathml's mi, mo, mn - // todo: svg's foreigObject, desc, title - String name = el.nodeName(); - return StringUtil.in(name, "address", "applet", "area", "article", "aside", "base", "basefont", "bgsound", - "blockquote", "body", "br", "button", "caption", "center", "col", "colgroup", "command", "dd", - "details", "dir", "div", "dl", "dt", "embed", "fieldset", "figcaption", "figure", "footer", "form", - "frame", "frameset", "h1", "h2", "h3", "h4", "h5", "h6", "head", "header", "hgroup", "hr", "html", - "iframe", "img", "input", "isindex", "li", "link", "listing", "marquee", "menu", "meta", "nav", - "noembed", "noframes", "noscript", "object", "ol", "p", "param", "plaintext", "pre", "script", - "section", "select", "style", "summary", "table", "tbody", "td", "textarea", "tfoot", "th", "thead", - "title", "tr", "ul", "wbr", "xmp"); - } - - // active formatting elements - void pushActiveFormattingElements(Element in) { - int numSeen = 0; - Iterator<Element> iter = formattingElements.descendingIterator(); - while (iter.hasNext()) { - Element el = iter.next(); - if (el == null) // marker - break; - - if (isSameFormattingElement(in, el)) - numSeen++; - - if (numSeen == 3) { - iter.remove(); - break; - } - } - formattingElements.add(in); - } - - private boolean isSameFormattingElement(Element a, Element b) { - // same if: same namespace, tag, and attributes. Element.equals only checks tag, might in future check children - return a.nodeName().equals(b.nodeName()) && - // a.namespace().equals(b.namespace()) && - a.attributes().equals(b.attributes()); - // todo: namespaces - } - - void reconstructFormattingElements() { - int size = formattingElements.size(); - if (size == 0 || formattingElements.getLast() == null || onStack(formattingElements.getLast())) - return; - - Element entry = formattingElements.getLast(); - int pos = size - 1; - boolean skip = false; - while (true) { - if (pos == 0) { // step 4. if none before, skip to 8 - skip = true; - break; - } - entry = formattingElements.get(--pos); // step 5. one earlier than entry - if (entry == null || onStack(entry)) // step 6 - neither marker nor on stack - break; // jump to 8, else continue back to 4 - } - while(true) { - if (!skip) // step 7: on later than entry - entry = formattingElements.get(++pos); - Validate.notNull(entry); // should not occur, as we break at last element - - // 8. create new element from element, 9 insert into current node, onto stack - skip = false; // can only skip increment from 4. - Element newEl = insert(entry.nodeName()); // todo: avoid fostering here? - // newEl.namespace(entry.namespace()); // todo: namespaces - newEl.attributes().addAll(entry.attributes()); - - // 10. replace entry with new entry - formattingElements.add(pos, newEl); - formattingElements.remove(pos + 1); - - // 11 - if (pos == size-1) // if not last entry in list, jump to 7 - break; - } - } - - void clearFormattingElementsToLastMarker() { - while (!formattingElements.isEmpty()) { - Element el = formattingElements.peekLast(); - formattingElements.removeLast(); - if (el == null) - break; - } - } - - void removeFromActiveFormattingElements(Element el) { - Iterator<Element> it = formattingElements.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next == el) { - it.remove(); - break; - } - } - } - - boolean isInActiveFormattingElements(Element el) { - return isElementInQueue(formattingElements, el); - } - - Element getActiveFormattingElement(String nodeName) { - Iterator<Element> it = formattingElements.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next == null) // scope marker - break; - else if (next.nodeName().equals(nodeName)) - return next; - } - return null; - } - - void replaceActiveFormattingElement(Element out, Element in) { - replaceInQueue(formattingElements, out, in); - } - - void insertMarkerToFormattingElements() { - formattingElements.add(null); - } - - void insertInFosterParent(Node in) { - Element fosterParent = null; - Element lastTable = getFromStack("table"); - boolean isLastTableParent = false; - if (lastTable != null) { - if (lastTable.parent() != null) { - fosterParent = lastTable.parent(); - isLastTableParent = true; - } else - fosterParent = aboveOnStack(lastTable); - } else { // no table == frag - fosterParent = stack.get(0); - } - - if (isLastTableParent) { - Validate.notNull(lastTable); // last table cannot be null by this point. - lastTable.before(in); - } - else - fosterParent.appendChild(in); - } - - @Override - public String toString() { - return "TreeBuilder{" + - "currentToken=" + currentToken + - ", state=" + state + - ", currentElement=" + currentElement() + - '}'; - } -} diff --git a/src/org/jsoup/parser/HtmlTreeBuilderState.java b/src/org/jsoup/parser/HtmlTreeBuilderState.java deleted file mode 100644 index ceab9faa5a..0000000000 --- a/src/org/jsoup/parser/HtmlTreeBuilderState.java +++ /dev/null @@ -1,1482 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.DescendableLinkedList; -import org.jsoup.helper.StringUtil; -import org.jsoup.nodes.*; - -import java.util.Iterator; -import java.util.LinkedList; - -/** - * The Tree Builder's current state. Each state embodies the processing for the state, and transitions to other states. - */ -enum HtmlTreeBuilderState { - Initial { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - return true; // ignore whitespace - } else if (t.isComment()) { - tb.insert(t.asComment()); - } else if (t.isDoctype()) { - // todo: parse error check on expected doctypes - // todo: quirk state check on doctype ids - Token.Doctype d = t.asDoctype(); - DocumentType doctype = new DocumentType(d.getName(), d.getPublicIdentifier(), d.getSystemIdentifier(), tb.getBaseUri()); - tb.getDocument().appendChild(doctype); - if (d.isForceQuirks()) - tb.getDocument().quirksMode(Document.QuirksMode.quirks); - tb.transition(BeforeHtml); - } else { - // todo: check not iframe srcdoc - tb.transition(BeforeHtml); - return tb.process(t); // re-process token - } - return true; - } - }, - BeforeHtml { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isDoctype()) { - tb.error(this); - return false; - } else if (t.isComment()) { - tb.insert(t.asComment()); - } else if (isWhitespace(t)) { - return true; // ignore whitespace - } else if (t.isStartTag() && t.asStartTag().name().equals("html")) { - tb.insert(t.asStartTag()); - tb.transition(BeforeHead); - } else if (t.isEndTag() && (StringUtil.in(t.asEndTag().name(), "head", "body", "html", "br"))) { - return anythingElse(t, tb); - } else if (t.isEndTag()) { - tb.error(this); - return false; - } else { - return anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, HtmlTreeBuilder tb) { - tb.insert("html"); - tb.transition(BeforeHead); - return tb.process(t); - } - }, - BeforeHead { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - return true; - } else if (t.isComment()) { - tb.insert(t.asComment()); - } else if (t.isDoctype()) { - tb.error(this); - return false; - } else if (t.isStartTag() && t.asStartTag().name().equals("html")) { - return InBody.process(t, tb); // does not transition - } else if (t.isStartTag() && t.asStartTag().name().equals("head")) { - Element head = tb.insert(t.asStartTag()); - tb.setHeadElement(head); - tb.transition(InHead); - } else if (t.isEndTag() && (StringUtil.in(t.asEndTag().name(), "head", "body", "html", "br"))) { - tb.process(new Token.StartTag("head")); - return tb.process(t); - } else if (t.isEndTag()) { - tb.error(this); - return false; - } else { - tb.process(new Token.StartTag("head")); - return tb.process(t); - } - return true; - } - }, - InHead { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - tb.insert(t.asCharacter()); - return true; - } - switch (t.type) { - case Comment: - tb.insert(t.asComment()); - break; - case Doctype: - tb.error(this); - return false; - case StartTag: - Token.StartTag start = t.asStartTag(); - String name = start.name(); - if (name.equals("html")) { - return InBody.process(t, tb); - } else if (StringUtil.in(name, "base", "basefont", "bgsound", "command", "link")) { - Element el = tb.insertEmpty(start); - // jsoup special: update base the frist time it is seen - if (name.equals("base") && el.hasAttr("href")) - tb.maybeSetBaseUri(el); - } else if (name.equals("meta")) { - Element meta = tb.insertEmpty(start); - // todo: charset switches - } else if (name.equals("title")) { - handleRcData(start, tb); - } else if (StringUtil.in(name, "noframes", "style")) { - handleRawtext(start, tb); - } else if (name.equals("noscript")) { - // else if noscript && scripting flag = true: rawtext (jsoup doesn't run script, to handle as noscript) - tb.insert(start); - tb.transition(InHeadNoscript); - } else if (name.equals("script")) { - // skips some script rules as won't execute them - tb.insert(start); - tb.tokeniser.transition(TokeniserState.ScriptData); - tb.markInsertionMode(); - tb.transition(Text); - } else if (name.equals("head")) { - tb.error(this); - return false; - } else { - return anythingElse(t, tb); - } - break; - case EndTag: - Token.EndTag end = t.asEndTag(); - name = end.name(); - if (name.equals("head")) { - tb.pop(); - tb.transition(AfterHead); - } else if (StringUtil.in(name, "body", "html", "br")) { - return anythingElse(t, tb); - } else { - tb.error(this); - return false; - } - break; - default: - return anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, TreeBuilder tb) { - tb.process(new Token.EndTag("head")); - return tb.process(t); - } - }, - InHeadNoscript { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isDoctype()) { - tb.error(this); - } else if (t.isStartTag() && t.asStartTag().name().equals("html")) { - return tb.process(t, InBody); - } else if (t.isEndTag() && t.asEndTag().name().equals("noscript")) { - tb.pop(); - tb.transition(InHead); - } else if (isWhitespace(t) || t.isComment() || (t.isStartTag() && StringUtil.in(t.asStartTag().name(), - "basefont", "bgsound", "link", "meta", "noframes", "style"))) { - return tb.process(t, InHead); - } else if (t.isEndTag() && t.asEndTag().name().equals("br")) { - return anythingElse(t, tb); - } else if ((t.isStartTag() && StringUtil.in(t.asStartTag().name(), "head", "noscript")) || t.isEndTag()) { - tb.error(this); - return false; - } else { - return anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, HtmlTreeBuilder tb) { - tb.error(this); - tb.process(new Token.EndTag("noscript")); - return tb.process(t); - } - }, - AfterHead { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - tb.insert(t.asCharacter()); - } else if (t.isComment()) { - tb.insert(t.asComment()); - } else if (t.isDoctype()) { - tb.error(this); - } else if (t.isStartTag()) { - Token.StartTag startTag = t.asStartTag(); - String name = startTag.name(); - if (name.equals("html")) { - return tb.process(t, InBody); - } else if (name.equals("body")) { - tb.insert(startTag); - tb.framesetOk(false); - tb.transition(InBody); - } else if (name.equals("frameset")) { - tb.insert(startTag); - tb.transition(InFrameset); - } else if (StringUtil.in(name, "base", "basefont", "bgsound", "link", "meta", "noframes", "script", "style", "title")) { - tb.error(this); - Element head = tb.getHeadElement(); - tb.push(head); - tb.process(t, InHead); - tb.removeFromStack(head); - } else if (name.equals("head")) { - tb.error(this); - return false; - } else { - anythingElse(t, tb); - } - } else if (t.isEndTag()) { - if (StringUtil.in(t.asEndTag().name(), "body", "html")) { - anythingElse(t, tb); - } else { - tb.error(this); - return false; - } - } else { - anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, HtmlTreeBuilder tb) { - tb.process(new Token.StartTag("body")); - tb.framesetOk(true); - return tb.process(t); - } - }, - InBody { - boolean process(Token t, HtmlTreeBuilder tb) { - switch (t.type) { - case Character: { - Token.Character c = t.asCharacter(); - if (c.getData().equals(nullString)) { - // todo confirm that check - tb.error(this); - return false; - } else if (isWhitespace(c)) { - tb.reconstructFormattingElements(); - tb.insert(c); - } else { - tb.reconstructFormattingElements(); - tb.insert(c); - tb.framesetOk(false); - } - break; - } - case Comment: { - tb.insert(t.asComment()); - break; - } - case Doctype: { - tb.error(this); - return false; - } - case StartTag: - Token.StartTag startTag = t.asStartTag(); - String name = startTag.name(); - if (name.equals("html")) { - tb.error(this); - // merge attributes onto real html - Element html = tb.getStack().getFirst(); - for (Attribute attribute : startTag.getAttributes()) { - if (!html.hasAttr(attribute.getKey())) - html.attributes().put(attribute); - } - } else if (StringUtil.in(name, "base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title")) { - return tb.process(t, InHead); - } else if (name.equals("body")) { - tb.error(this); - LinkedList<Element> stack = tb.getStack(); - if (stack.size() == 1 || (stack.size() > 2 && !stack.get(1).nodeName().equals("body"))) { - // only in fragment case - return false; // ignore - } else { - tb.framesetOk(false); - Element body = stack.get(1); - for (Attribute attribute : startTag.getAttributes()) { - if (!body.hasAttr(attribute.getKey())) - body.attributes().put(attribute); - } - } - } else if (name.equals("frameset")) { - tb.error(this); - LinkedList<Element> stack = tb.getStack(); - if (stack.size() == 1 || (stack.size() > 2 && !stack.get(1).nodeName().equals("body"))) { - // only in fragment case - return false; // ignore - } else if (!tb.framesetOk()) { - return false; // ignore frameset - } else { - Element second = stack.get(1); - if (second.parent() != null) - second.remove(); - // pop up to html element - while (stack.size() > 1) - stack.removeLast(); - tb.insert(startTag); - tb.transition(InFrameset); - } - } else if (StringUtil.in(name, - "address", "article", "aside", "blockquote", "center", "details", "dir", "div", "dl", - "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "menu", "nav", "ol", - "p", "section", "summary", "ul")) { - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.insert(startTag); - } else if (StringUtil.in(name, "h1", "h2", "h3", "h4", "h5", "h6")) { - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - if (StringUtil.in(tb.currentElement().nodeName(), "h1", "h2", "h3", "h4", "h5", "h6")) { - tb.error(this); - tb.pop(); - } - tb.insert(startTag); - } else if (StringUtil.in(name, "pre", "listing")) { - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.insert(startTag); - // todo: ignore LF if next token - tb.framesetOk(false); - } else if (name.equals("form")) { - if (tb.getFormElement() != null) { - tb.error(this); - return false; - } - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - Element form = tb.insert(startTag); - tb.setFormElement(form); - } else if (name.equals("li")) { - tb.framesetOk(false); - LinkedList<Element> stack = tb.getStack(); - for (int i = stack.size() - 1; i > 0; i--) { - Element el = stack.get(i); - if (el.nodeName().equals("li")) { - tb.process(new Token.EndTag("li")); - break; - } - if (tb.isSpecial(el) && !StringUtil.in(el.nodeName(), "address", "div", "p")) - break; - } - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.insert(startTag); - } else if (StringUtil.in(name, "dd", "dt")) { - tb.framesetOk(false); - LinkedList<Element> stack = tb.getStack(); - for (int i = stack.size() - 1; i > 0; i--) { - Element el = stack.get(i); - if (StringUtil.in(el.nodeName(), "dd", "dt")) { - tb.process(new Token.EndTag(el.nodeName())); - break; - } - if (tb.isSpecial(el) && !StringUtil.in(el.nodeName(), "address", "div", "p")) - break; - } - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.insert(startTag); - } else if (name.equals("plaintext")) { - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.insert(startTag); - tb.tokeniser.transition(TokeniserState.PLAINTEXT); // once in, never gets out - } else if (name.equals("button")) { - if (tb.inButtonScope("button")) { - // close and reprocess - tb.error(this); - tb.process(new Token.EndTag("button")); - tb.process(startTag); - } else { - tb.reconstructFormattingElements(); - tb.insert(startTag); - tb.framesetOk(false); - } - } else if (name.equals("a")) { - if (tb.getActiveFormattingElement("a") != null) { - tb.error(this); - tb.process(new Token.EndTag("a")); - - // still on stack? - Element remainingA = tb.getFromStack("a"); - if (remainingA != null) { - tb.removeFromActiveFormattingElements(remainingA); - tb.removeFromStack(remainingA); - } - } - tb.reconstructFormattingElements(); - Element a = tb.insert(startTag); - tb.pushActiveFormattingElements(a); - } else if (StringUtil.in(name, - "b", "big", "code", "em", "font", "i", "s", "small", "strike", "strong", "tt", "u")) { - tb.reconstructFormattingElements(); - Element el = tb.insert(startTag); - tb.pushActiveFormattingElements(el); - } else if (name.equals("nobr")) { - tb.reconstructFormattingElements(); - if (tb.inScope("nobr")) { - tb.error(this); - tb.process(new Token.EndTag("nobr")); - tb.reconstructFormattingElements(); - } - Element el = tb.insert(startTag); - tb.pushActiveFormattingElements(el); - } else if (StringUtil.in(name, "applet", "marquee", "object")) { - tb.reconstructFormattingElements(); - tb.insert(startTag); - tb.insertMarkerToFormattingElements(); - tb.framesetOk(false); - } else if (name.equals("table")) { - if (tb.getDocument().quirksMode() != Document.QuirksMode.quirks && tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.insert(startTag); - tb.framesetOk(false); - tb.transition(InTable); - } else if (StringUtil.in(name, "area", "br", "embed", "img", "keygen", "wbr")) { - tb.reconstructFormattingElements(); - tb.insertEmpty(startTag); - tb.framesetOk(false); - } else if (name.equals("input")) { - tb.reconstructFormattingElements(); - Element el = tb.insertEmpty(startTag); - if (!el.attr("type").equalsIgnoreCase("hidden")) - tb.framesetOk(false); - } else if (StringUtil.in(name, "param", "source", "track")) { - tb.insertEmpty(startTag); - } else if (name.equals("hr")) { - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.insertEmpty(startTag); - tb.framesetOk(false); - } else if (name.equals("image")) { - // we're not supposed to ask. - startTag.name("img"); - return tb.process(startTag); - } else if (name.equals("isindex")) { - // how much do we care about the early 90s? - tb.error(this); - if (tb.getFormElement() != null) - return false; - - tb.tokeniser.acknowledgeSelfClosingFlag(); - tb.process(new Token.StartTag("form")); - if (startTag.attributes.hasKey("action")) { - Element form = tb.getFormElement(); - form.attr("action", startTag.attributes.get("action")); - } - tb.process(new Token.StartTag("hr")); - tb.process(new Token.StartTag("label")); - // hope you like english. - String prompt = startTag.attributes.hasKey("prompt") ? - startTag.attributes.get("prompt") : - "This is a searchable index. Enter search keywords: "; - - tb.process(new Token.Character(prompt)); - - // input - Attributes inputAttribs = new Attributes(); - for (Attribute attr : startTag.attributes) { - if (!StringUtil.in(attr.getKey(), "name", "action", "prompt")) - inputAttribs.put(attr); - } - inputAttribs.put("name", "isindex"); - tb.process(new Token.StartTag("input", inputAttribs)); - tb.process(new Token.EndTag("label")); - tb.process(new Token.StartTag("hr")); - tb.process(new Token.EndTag("form")); - } else if (name.equals("textarea")) { - tb.insert(startTag); - // todo: If the next token is a U+000A LINE FEED (LF) character token, then ignore that token and move on to the next one. (Newlines at the start of textarea elements are ignored as an authoring convenience.) - tb.tokeniser.transition(TokeniserState.Rcdata); - tb.markInsertionMode(); - tb.framesetOk(false); - tb.transition(Text); - } else if (name.equals("xmp")) { - if (tb.inButtonScope("p")) { - tb.process(new Token.EndTag("p")); - } - tb.reconstructFormattingElements(); - tb.framesetOk(false); - handleRawtext(startTag, tb); - } else if (name.equals("iframe")) { - tb.framesetOk(false); - handleRawtext(startTag, tb); - } else if (name.equals("noembed")) { - // also handle noscript if script enabled - handleRawtext(startTag, tb); - } else if (name.equals("select")) { - tb.reconstructFormattingElements(); - tb.insert(startTag); - tb.framesetOk(false); - - HtmlTreeBuilderState state = tb.state(); - if (state.equals(InTable) || state.equals(InCaption) || state.equals(InTableBody) || state.equals(InRow) || state.equals(InCell)) - tb.transition(InSelectInTable); - else - tb.transition(InSelect); - } else if (StringUtil.in("optgroup", "option")) { - if (tb.currentElement().nodeName().equals("option")) - tb.process(new Token.EndTag("option")); - tb.reconstructFormattingElements(); - tb.insert(startTag); - } else if (StringUtil.in("rp", "rt")) { - if (tb.inScope("ruby")) { - tb.generateImpliedEndTags(); - if (!tb.currentElement().nodeName().equals("ruby")) { - tb.error(this); - tb.popStackToBefore("ruby"); // i.e. close up to but not include name - } - tb.insert(startTag); - } - } else if (name.equals("math")) { - tb.reconstructFormattingElements(); - // todo: handle A start tag whose tag name is "math" (i.e. foreign, mathml) - tb.insert(startTag); - tb.tokeniser.acknowledgeSelfClosingFlag(); - } else if (name.equals("svg")) { - tb.reconstructFormattingElements(); - // todo: handle A start tag whose tag name is "svg" (xlink, svg) - tb.insert(startTag); - tb.tokeniser.acknowledgeSelfClosingFlag(); - } else if (StringUtil.in(name, - "caption", "col", "colgroup", "frame", "head", "tbody", "td", "tfoot", "th", "thead", "tr")) { - tb.error(this); - return false; - } else { - tb.reconstructFormattingElements(); - tb.insert(startTag); - } - break; - - case EndTag: - Token.EndTag endTag = t.asEndTag(); - name = endTag.name(); - if (name.equals("body")) { - if (!tb.inScope("body")) { - tb.error(this); - return false; - } else { - // todo: error if stack contains something not dd, dt, li, optgroup, option, p, rp, rt, tbody, td, tfoot, th, thead, tr, body, html - tb.transition(AfterBody); - } - } else if (name.equals("html")) { - boolean notIgnored = tb.process(new Token.EndTag("body")); - if (notIgnored) - return tb.process(endTag); - } else if (StringUtil.in(name, - "address", "article", "aside", "blockquote", "button", "center", "details", "dir", "div", - "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "listing", "menu", - "nav", "ol", "pre", "section", "summary", "ul")) { - // todo: refactor these lookups - if (!tb.inScope(name)) { - // nothing to close - tb.error(this); - return false; - } else { - tb.generateImpliedEndTags(); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - tb.popStackToClose(name); - } - } else if (name.equals("form")) { - Element currentForm = tb.getFormElement(); - tb.setFormElement(null); - if (currentForm == null || !tb.inScope(name)) { - tb.error(this); - return false; - } else { - tb.generateImpliedEndTags(); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - // remove currentForm from stack. will shift anything under up. - tb.removeFromStack(currentForm); - } - } else if (name.equals("p")) { - if (!tb.inButtonScope(name)) { - tb.error(this); - tb.process(new Token.StartTag(name)); // if no p to close, creates an empty <p></p> - return tb.process(endTag); - } else { - tb.generateImpliedEndTags(name); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - tb.popStackToClose(name); - } - } else if (name.equals("li")) { - if (!tb.inListItemScope(name)) { - tb.error(this); - return false; - } else { - tb.generateImpliedEndTags(name); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - tb.popStackToClose(name); - } - } else if (StringUtil.in(name, "dd", "dt")) { - if (!tb.inScope(name)) { - tb.error(this); - return false; - } else { - tb.generateImpliedEndTags(name); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - tb.popStackToClose(name); - } - } else if (StringUtil.in(name, "h1", "h2", "h3", "h4", "h5", "h6")) { - if (!tb.inScope(new String[]{"h1", "h2", "h3", "h4", "h5", "h6"})) { - tb.error(this); - return false; - } else { - tb.generateImpliedEndTags(name); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - tb.popStackToClose("h1", "h2", "h3", "h4", "h5", "h6"); - } - } else if (name.equals("sarcasm")) { - // *sigh* - return anyOtherEndTag(t, tb); - } else if (StringUtil.in(name, - "a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small", "strike", "strong", "tt", "u")) { - // Adoption Agency Algorithm. - OUTER: - for (int i = 0; i < 8; i++) { - Element formatEl = tb.getActiveFormattingElement(name); - if (formatEl == null) - return anyOtherEndTag(t, tb); - else if (!tb.onStack(formatEl)) { - tb.error(this); - tb.removeFromActiveFormattingElements(formatEl); - return true; - } else if (!tb.inScope(formatEl.nodeName())) { - tb.error(this); - return false; - } else if (tb.currentElement() != formatEl) - tb.error(this); - - Element furthestBlock = null; - Element commonAncestor = null; - boolean seenFormattingElement = false; - LinkedList<Element> stack = tb.getStack(); - for (int si = 0; si < stack.size(); si++) { - Element el = stack.get(si); - if (el == formatEl) { - commonAncestor = stack.get(si - 1); - seenFormattingElement = true; - } else if (seenFormattingElement && tb.isSpecial(el)) { - furthestBlock = el; - break; - } - } - if (furthestBlock == null) { - tb.popStackToClose(formatEl.nodeName()); - tb.removeFromActiveFormattingElements(formatEl); - return true; - } - - // todo: Let a bookmark note the position of the formatting element in the list of active formatting elements relative to the elements on either side of it in the list. - // does that mean: int pos of format el in list? - Element node = furthestBlock; - Element lastNode = furthestBlock; - INNER: - for (int j = 0; j < 3; j++) { - if (tb.onStack(node)) - node = tb.aboveOnStack(node); - if (!tb.isInActiveFormattingElements(node)) { // note no bookmark check - tb.removeFromStack(node); - continue INNER; - } else if (node == formatEl) - break INNER; - - Element replacement = new Element(Tag.valueOf(node.nodeName()), tb.getBaseUri()); - tb.replaceActiveFormattingElement(node, replacement); - tb.replaceOnStack(node, replacement); - node = replacement; - - if (lastNode == furthestBlock) { - // todo: move the aforementioned bookmark to be immediately after the new node in the list of active formatting elements. - // not getting how this bookmark both straddles the element above, but is inbetween here... - } - if (lastNode.parent() != null) - lastNode.remove(); - node.appendChild(lastNode); - - lastNode = node; - } - - if (StringUtil.in(commonAncestor.nodeName(), "table", "tbody", "tfoot", "thead", "tr")) { - if (lastNode.parent() != null) - lastNode.remove(); - tb.insertInFosterParent(lastNode); - } else { - if (lastNode.parent() != null) - lastNode.remove(); - commonAncestor.appendChild(lastNode); - } - - Element adopter = new Element(Tag.valueOf(name), tb.getBaseUri()); - Node[] childNodes = furthestBlock.childNodes().toArray(new Node[furthestBlock.childNodes().size()]); - for (Node childNode : childNodes) { - adopter.appendChild(childNode); // append will reparent. thus the clone to avoid concurrent mod. - } - furthestBlock.appendChild(adopter); - tb.removeFromActiveFormattingElements(formatEl); - // todo: insert the new element into the list of active formatting elements at the position of the aforementioned bookmark. - tb.removeFromStack(formatEl); - tb.insertOnStackAfter(furthestBlock, adopter); - } - } else if (StringUtil.in(name, "applet", "marquee", "object")) { - if (!tb.inScope("name")) { - if (!tb.inScope(name)) { - tb.error(this); - return false; - } - tb.generateImpliedEndTags(); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - tb.popStackToClose(name); - tb.clearFormattingElementsToLastMarker(); - } - } else if (name.equals("br")) { - tb.error(this); - tb.process(new Token.StartTag("br")); - return false; - } else { - return anyOtherEndTag(t, tb); - } - - break; - case EOF: - // todo: error if stack contains something not dd, dt, li, p, tbody, td, tfoot, th, thead, tr, body, html - // stop parsing - break; - } - return true; - } - - boolean anyOtherEndTag(Token t, HtmlTreeBuilder tb) { - String name = t.asEndTag().name(); - DescendableLinkedList<Element> stack = tb.getStack(); - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element node = it.next(); - if (node.nodeName().equals(name)) { - tb.generateImpliedEndTags(name); - if (!name.equals(tb.currentElement().nodeName())) - tb.error(this); - tb.popStackToClose(name); - break; - } else { - if (tb.isSpecial(node)) { - tb.error(this); - return false; - } - } - } - return true; - } - }, - Text { - // in script, style etc. normally treated as data tags - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isCharacter()) { - tb.insert(t.asCharacter()); - } else if (t.isEOF()) { - tb.error(this); - // if current node is script: already started - tb.pop(); - tb.transition(tb.originalState()); - return tb.process(t); - } else if (t.isEndTag()) { - // if: An end tag whose tag name is "script" -- scripting nesting level, if evaluating scripts - tb.pop(); - tb.transition(tb.originalState()); - } - return true; - } - }, - InTable { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isCharacter()) { - tb.newPendingTableCharacters(); - tb.markInsertionMode(); - tb.transition(InTableText); - return tb.process(t); - } else if (t.isComment()) { - tb.insert(t.asComment()); - return true; - } else if (t.isDoctype()) { - tb.error(this); - return false; - } else if (t.isStartTag()) { - Token.StartTag startTag = t.asStartTag(); - String name = startTag.name(); - if (name.equals("caption")) { - tb.clearStackToTableContext(); - tb.insertMarkerToFormattingElements(); - tb.insert(startTag); - tb.transition(InCaption); - } else if (name.equals("colgroup")) { - tb.clearStackToTableContext(); - tb.insert(startTag); - tb.transition(InColumnGroup); - } else if (name.equals("col")) { - tb.process(new Token.StartTag("colgroup")); - return tb.process(t); - } else if (StringUtil.in(name, "tbody", "tfoot", "thead")) { - tb.clearStackToTableContext(); - tb.insert(startTag); - tb.transition(InTableBody); - } else if (StringUtil.in(name, "td", "th", "tr")) { - tb.process(new Token.StartTag("tbody")); - return tb.process(t); - } else if (name.equals("table")) { - tb.error(this); - boolean processed = tb.process(new Token.EndTag("table")); - if (processed) // only ignored if in fragment - return tb.process(t); - } else if (StringUtil.in(name, "style", "script")) { - return tb.process(t, InHead); - } else if (name.equals("input")) { - if (!startTag.attributes.get("type").equalsIgnoreCase("hidden")) { - return anythingElse(t, tb); - } else { - tb.insertEmpty(startTag); - } - } else if (name.equals("form")) { - tb.error(this); - if (tb.getFormElement() != null) - return false; - else { - Element form = tb.insertEmpty(startTag); - tb.setFormElement(form); - } - } else { - return anythingElse(t, tb); - } - } else if (t.isEndTag()) { - Token.EndTag endTag = t.asEndTag(); - String name = endTag.name(); - - if (name.equals("table")) { - if (!tb.inTableScope(name)) { - tb.error(this); - return false; - } else { - tb.popStackToClose("table"); - } - tb.resetInsertionMode(); - } else if (StringUtil.in(name, - "body", "caption", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr")) { - tb.error(this); - return false; - } else { - return anythingElse(t, tb); - } - } else if (t.isEOF()) { - if (tb.currentElement().nodeName().equals("html")) - tb.error(this); - return true; // stops parsing - } - return anythingElse(t, tb); - } - - boolean anythingElse(Token t, HtmlTreeBuilder tb) { - tb.error(this); - boolean processed = true; - if (StringUtil.in(tb.currentElement().nodeName(), "table", "tbody", "tfoot", "thead", "tr")) { - tb.setFosterInserts(true); - processed = tb.process(t, InBody); - tb.setFosterInserts(false); - } else { - processed = tb.process(t, InBody); - } - return processed; - } - }, - InTableText { - boolean process(Token t, HtmlTreeBuilder tb) { - switch (t.type) { - case Character: - Token.Character c = t.asCharacter(); - if (c.getData().equals(nullString)) { - tb.error(this); - return false; - } else { - tb.getPendingTableCharacters().add(c); - } - break; - default: - if (tb.getPendingTableCharacters().size() > 0) { - for (Token.Character character : tb.getPendingTableCharacters()) { - if (!isWhitespace(character)) { - // InTable anything else section: - tb.error(this); - if (StringUtil.in(tb.currentElement().nodeName(), "table", "tbody", "tfoot", "thead", "tr")) { - tb.setFosterInserts(true); - tb.process(character, InBody); - tb.setFosterInserts(false); - } else { - tb.process(character, InBody); - } - } else - tb.insert(character); - } - tb.newPendingTableCharacters(); - } - tb.transition(tb.originalState()); - return tb.process(t); - } - return true; - } - }, - InCaption { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isEndTag() && t.asEndTag().name().equals("caption")) { - Token.EndTag endTag = t.asEndTag(); - String name = endTag.name(); - if (!tb.inTableScope(name)) { - tb.error(this); - return false; - } else { - tb.generateImpliedEndTags(); - if (!tb.currentElement().nodeName().equals("caption")) - tb.error(this); - tb.popStackToClose("caption"); - tb.clearFormattingElementsToLastMarker(); - tb.transition(InTable); - } - } else if (( - t.isStartTag() && StringUtil.in(t.asStartTag().name(), - "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr") || - t.isEndTag() && t.asEndTag().name().equals("table")) - ) { - tb.error(this); - boolean processed = tb.process(new Token.EndTag("caption")); - if (processed) - return tb.process(t); - } else if (t.isEndTag() && StringUtil.in(t.asEndTag().name(), - "body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th", "thead", "tr")) { - tb.error(this); - return false; - } else { - return tb.process(t, InBody); - } - return true; - } - }, - InColumnGroup { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - tb.insert(t.asCharacter()); - return true; - } - switch (t.type) { - case Comment: - tb.insert(t.asComment()); - break; - case Doctype: - tb.error(this); - break; - case StartTag: - Token.StartTag startTag = t.asStartTag(); - String name = startTag.name(); - if (name.equals("html")) - return tb.process(t, InBody); - else if (name.equals("col")) - tb.insertEmpty(startTag); - else - return anythingElse(t, tb); - break; - case EndTag: - Token.EndTag endTag = t.asEndTag(); - name = endTag.name(); - if (name.equals("colgroup")) { - if (tb.currentElement().nodeName().equals("html")) { // frag case - tb.error(this); - return false; - } else { - tb.pop(); - tb.transition(InTable); - } - } else - return anythingElse(t, tb); - break; - case EOF: - if (tb.currentElement().nodeName().equals("html")) - return true; // stop parsing; frag case - else - return anythingElse(t, tb); - default: - return anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, TreeBuilder tb) { - boolean processed = tb.process(new Token.EndTag("colgroup")); - if (processed) // only ignored in frag case - return tb.process(t); - return true; - } - }, - InTableBody { - boolean process(Token t, HtmlTreeBuilder tb) { - switch (t.type) { - case StartTag: - Token.StartTag startTag = t.asStartTag(); - String name = startTag.name(); - if (name.equals("tr")) { - tb.clearStackToTableBodyContext(); - tb.insert(startTag); - tb.transition(InRow); - } else if (StringUtil.in(name, "th", "td")) { - tb.error(this); - tb.process(new Token.StartTag("tr")); - return tb.process(startTag); - } else if (StringUtil.in(name, "caption", "col", "colgroup", "tbody", "tfoot", "thead")) { - return exitTableBody(t, tb); - } else - return anythingElse(t, tb); - break; - case EndTag: - Token.EndTag endTag = t.asEndTag(); - name = endTag.name(); - if (StringUtil.in(name, "tbody", "tfoot", "thead")) { - if (!tb.inTableScope(name)) { - tb.error(this); - return false; - } else { - tb.clearStackToTableBodyContext(); - tb.pop(); - tb.transition(InTable); - } - } else if (name.equals("table")) { - return exitTableBody(t, tb); - } else if (StringUtil.in(name, "body", "caption", "col", "colgroup", "html", "td", "th", "tr")) { - tb.error(this); - return false; - } else - return anythingElse(t, tb); - break; - default: - return anythingElse(t, tb); - } - return true; - } - - private boolean exitTableBody(Token t, HtmlTreeBuilder tb) { - if (!(tb.inTableScope("tbody") || tb.inTableScope("thead") || tb.inScope("tfoot"))) { - // frag case - tb.error(this); - return false; - } - tb.clearStackToTableBodyContext(); - tb.process(new Token.EndTag(tb.currentElement().nodeName())); // tbody, tfoot, thead - return tb.process(t); - } - - private boolean anythingElse(Token t, HtmlTreeBuilder tb) { - return tb.process(t, InTable); - } - }, - InRow { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isStartTag()) { - Token.StartTag startTag = t.asStartTag(); - String name = startTag.name(); - - if (StringUtil.in(name, "th", "td")) { - tb.clearStackToTableRowContext(); - tb.insert(startTag); - tb.transition(InCell); - tb.insertMarkerToFormattingElements(); - } else if (StringUtil.in(name, "caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr")) { - return handleMissingTr(t, tb); - } else { - return anythingElse(t, tb); - } - } else if (t.isEndTag()) { - Token.EndTag endTag = t.asEndTag(); - String name = endTag.name(); - - if (name.equals("tr")) { - if (!tb.inTableScope(name)) { - tb.error(this); // frag - return false; - } - tb.clearStackToTableRowContext(); - tb.pop(); // tr - tb.transition(InTableBody); - } else if (name.equals("table")) { - return handleMissingTr(t, tb); - } else if (StringUtil.in(name, "tbody", "tfoot", "thead")) { - if (!tb.inTableScope(name)) { - tb.error(this); - return false; - } - tb.process(new Token.EndTag("tr")); - return tb.process(t); - } else if (StringUtil.in(name, "body", "caption", "col", "colgroup", "html", "td", "th")) { - tb.error(this); - return false; - } else { - return anythingElse(t, tb); - } - } else { - return anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, HtmlTreeBuilder tb) { - return tb.process(t, InTable); - } - - private boolean handleMissingTr(Token t, TreeBuilder tb) { - boolean processed = tb.process(new Token.EndTag("tr")); - if (processed) - return tb.process(t); - else - return false; - } - }, - InCell { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isEndTag()) { - Token.EndTag endTag = t.asEndTag(); - String name = endTag.name(); - - if (StringUtil.in(name, "td", "th")) { - if (!tb.inTableScope(name)) { - tb.error(this); - tb.transition(InRow); // might not be in scope if empty: <td /> and processing fake end tag - return false; - } - tb.generateImpliedEndTags(); - if (!tb.currentElement().nodeName().equals(name)) - tb.error(this); - tb.popStackToClose(name); - tb.clearFormattingElementsToLastMarker(); - tb.transition(InRow); - } else if (StringUtil.in(name, "body", "caption", "col", "colgroup", "html")) { - tb.error(this); - return false; - } else if (StringUtil.in(name, "table", "tbody", "tfoot", "thead", "tr")) { - if (!tb.inTableScope(name)) { - tb.error(this); - return false; - } - closeCell(tb); - return tb.process(t); - } else { - return anythingElse(t, tb); - } - } else if (t.isStartTag() && - StringUtil.in(t.asStartTag().name(), - "caption", "col", "colgroup", "tbody", "td", "tfoot", "th", "thead", "tr")) { - if (!(tb.inTableScope("td") || tb.inTableScope("th"))) { - tb.error(this); - return false; - } - closeCell(tb); - return tb.process(t); - } else { - return anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, HtmlTreeBuilder tb) { - return tb.process(t, InBody); - } - - private void closeCell(HtmlTreeBuilder tb) { - if (tb.inTableScope("td")) - tb.process(new Token.EndTag("td")); - else - tb.process(new Token.EndTag("th")); // only here if th or td in scope - } - }, - InSelect { - boolean process(Token t, HtmlTreeBuilder tb) { - switch (t.type) { - case Character: - Token.Character c = t.asCharacter(); - if (c.getData().equals(nullString)) { - tb.error(this); - return false; - } else { - tb.insert(c); - } - break; - case Comment: - tb.insert(t.asComment()); - break; - case Doctype: - tb.error(this); - return false; - case StartTag: - Token.StartTag start = t.asStartTag(); - String name = start.name(); - if (name.equals("html")) - return tb.process(start, InBody); - else if (name.equals("option")) { - tb.process(new Token.EndTag("option")); - tb.insert(start); - } else if (name.equals("optgroup")) { - if (tb.currentElement().nodeName().equals("option")) - tb.process(new Token.EndTag("option")); - else if (tb.currentElement().nodeName().equals("optgroup")) - tb.process(new Token.EndTag("optgroup")); - tb.insert(start); - } else if (name.equals("select")) { - tb.error(this); - return tb.process(new Token.EndTag("select")); - } else if (StringUtil.in(name, "input", "keygen", "textarea")) { - tb.error(this); - if (!tb.inSelectScope("select")) - return false; // frag - tb.process(new Token.EndTag("select")); - return tb.process(start); - } else if (name.equals("script")) { - return tb.process(t, InHead); - } else { - return anythingElse(t, tb); - } - break; - case EndTag: - Token.EndTag end = t.asEndTag(); - name = end.name(); - if (name.equals("optgroup")) { - if (tb.currentElement().nodeName().equals("option") && tb.aboveOnStack(tb.currentElement()) != null && tb.aboveOnStack(tb.currentElement()).nodeName().equals("optgroup")) - tb.process(new Token.EndTag("option")); - if (tb.currentElement().nodeName().equals("optgroup")) - tb.pop(); - else - tb.error(this); - } else if (name.equals("option")) { - if (tb.currentElement().nodeName().equals("option")) - tb.pop(); - else - tb.error(this); - } else if (name.equals("select")) { - if (!tb.inSelectScope(name)) { - tb.error(this); - return false; - } else { - tb.popStackToClose(name); - tb.resetInsertionMode(); - } - } else - return anythingElse(t, tb); - break; - case EOF: - if (!tb.currentElement().nodeName().equals("html")) - tb.error(this); - break; - default: - return anythingElse(t, tb); - } - return true; - } - - private boolean anythingElse(Token t, HtmlTreeBuilder tb) { - tb.error(this); - return false; - } - }, - InSelectInTable { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isStartTag() && StringUtil.in(t.asStartTag().name(), "caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th")) { - tb.error(this); - tb.process(new Token.EndTag("select")); - return tb.process(t); - } else if (t.isEndTag() && StringUtil.in(t.asEndTag().name(), "caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th")) { - tb.error(this); - if (tb.inTableScope(t.asEndTag().name())) { - tb.process(new Token.EndTag("select")); - return (tb.process(t)); - } else - return false; - } else { - return tb.process(t, InSelect); - } - } - }, - AfterBody { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - return tb.process(t, InBody); - } else if (t.isComment()) { - tb.insert(t.asComment()); // into html node - } else if (t.isDoctype()) { - tb.error(this); - return false; - } else if (t.isStartTag() && t.asStartTag().name().equals("html")) { - return tb.process(t, InBody); - } else if (t.isEndTag() && t.asEndTag().name().equals("html")) { - if (tb.isFragmentParsing()) { - tb.error(this); - return false; - } else { - tb.transition(AfterAfterBody); - } - } else if (t.isEOF()) { - // chillax! we're done - } else { - tb.error(this); - tb.transition(InBody); - return tb.process(t); - } - return true; - } - }, - InFrameset { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - tb.insert(t.asCharacter()); - } else if (t.isComment()) { - tb.insert(t.asComment()); - } else if (t.isDoctype()) { - tb.error(this); - return false; - } else if (t.isStartTag()) { - Token.StartTag start = t.asStartTag(); - String name = start.name(); - if (name.equals("html")) { - return tb.process(start, InBody); - } else if (name.equals("frameset")) { - tb.insert(start); - } else if (name.equals("frame")) { - tb.insertEmpty(start); - } else if (name.equals("noframes")) { - return tb.process(start, InHead); - } else { - tb.error(this); - return false; - } - } else if (t.isEndTag() && t.asEndTag().name().equals("frameset")) { - if (tb.currentElement().nodeName().equals("html")) { // frag - tb.error(this); - return false; - } else { - tb.pop(); - if (!tb.isFragmentParsing() && !tb.currentElement().nodeName().equals("frameset")) { - tb.transition(AfterFrameset); - } - } - } else if (t.isEOF()) { - if (!tb.currentElement().nodeName().equals("html")) { - tb.error(this); - return true; - } - } else { - tb.error(this); - return false; - } - return true; - } - }, - AfterFrameset { - boolean process(Token t, HtmlTreeBuilder tb) { - if (isWhitespace(t)) { - tb.insert(t.asCharacter()); - } else if (t.isComment()) { - tb.insert(t.asComment()); - } else if (t.isDoctype()) { - tb.error(this); - return false; - } else if (t.isStartTag() && t.asStartTag().name().equals("html")) { - return tb.process(t, InBody); - } else if (t.isEndTag() && t.asEndTag().name().equals("html")) { - tb.transition(AfterAfterFrameset); - } else if (t.isStartTag() && t.asStartTag().name().equals("noframes")) { - return tb.process(t, InHead); - } else if (t.isEOF()) { - // cool your heels, we're complete - } else { - tb.error(this); - return false; - } - return true; - } - }, - AfterAfterBody { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isComment()) { - tb.insert(t.asComment()); - } else if (t.isDoctype() || isWhitespace(t) || (t.isStartTag() && t.asStartTag().name().equals("html"))) { - return tb.process(t, InBody); - } else if (t.isEOF()) { - // nice work chuck - } else { - tb.error(this); - tb.transition(InBody); - return tb.process(t); - } - return true; - } - }, - AfterAfterFrameset { - boolean process(Token t, HtmlTreeBuilder tb) { - if (t.isComment()) { - tb.insert(t.asComment()); - } else if (t.isDoctype() || isWhitespace(t) || (t.isStartTag() && t.asStartTag().name().equals("html"))) { - return tb.process(t, InBody); - } else if (t.isEOF()) { - // nice work chuck - } else if (t.isStartTag() && t.asStartTag().name().equals("noframes")) { - return tb.process(t, InHead); - } else { - tb.error(this); - return false; - } - return true; - } - }, - ForeignContent { - boolean process(Token t, HtmlTreeBuilder tb) { - return true; - // todo: implement. Also; how do we get here? - } - }; - - private static String nullString = String.valueOf('\u0000'); - - abstract boolean process(Token t, HtmlTreeBuilder tb); - - private static boolean isWhitespace(Token t) { - if (t.isCharacter()) { - String data = t.asCharacter().getData(); - // todo: this checks more than spec - "\t", "\n", "\f", "\r", " " - for (int i = 0; i < data.length(); i++) { - char c = data.charAt(i); - if (!StringUtil.isWhitespace(c)) - return false; - } - return true; - } - return false; - } - - private static void handleRcData(Token.StartTag startTag, HtmlTreeBuilder tb) { - tb.insert(startTag); - tb.tokeniser.transition(TokeniserState.Rcdata); - tb.markInsertionMode(); - tb.transition(Text); - } - - private static void handleRawtext(Token.StartTag startTag, HtmlTreeBuilder tb) { - tb.insert(startTag); - tb.tokeniser.transition(TokeniserState.Rawtext); - tb.markInsertionMode(); - tb.transition(Text); - } -} diff --git a/src/org/jsoup/parser/ParseError.java b/src/org/jsoup/parser/ParseError.java deleted file mode 100644 index dfa090051b..0000000000 --- a/src/org/jsoup/parser/ParseError.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.jsoup.parser; - -/** - * A Parse Error records an error in the input HTML that occurs in either the tokenisation or the tree building phase. - */ -public class ParseError { - private int pos; - private String errorMsg; - - ParseError(int pos, String errorMsg) { - this.pos = pos; - this.errorMsg = errorMsg; - } - - ParseError(int pos, String errorFormat, Object... args) { - this.errorMsg = String.format(errorFormat, args); - this.pos = pos; - } - - /** - * Retrieve the error message. - * @return the error message. - */ - public String getErrorMessage() { - return errorMsg; - } - - /** - * Retrieves the offset of the error. - * @return error offset within input - */ - public int getPosition() { - return pos; - } - - @Override - public String toString() { - return pos + ": " + errorMsg; - } -} diff --git a/src/org/jsoup/parser/ParseErrorList.java b/src/org/jsoup/parser/ParseErrorList.java deleted file mode 100644 index 3824ffbc4e..0000000000 --- a/src/org/jsoup/parser/ParseErrorList.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.jsoup.parser; - -import java.util.ArrayList; - -/** - * A container for ParseErrors. - * - * @author Jonathan Hedley - */ -class ParseErrorList extends ArrayList<ParseError>{ - private static final int INITIAL_CAPACITY = 16; - private final int maxSize; - - ParseErrorList(int initialCapacity, int maxSize) { - super(initialCapacity); - this.maxSize = maxSize; - } - - boolean canAddError() { - return size() < maxSize; - } - - int getMaxSize() { - return maxSize; - } - - static ParseErrorList noTracking() { - return new ParseErrorList(0, 0); - } - - static ParseErrorList tracking(int maxSize) { - return new ParseErrorList(INITIAL_CAPACITY, maxSize); - } -} diff --git a/src/org/jsoup/parser/Parser.java b/src/org/jsoup/parser/Parser.java deleted file mode 100644 index 2236219c06..0000000000 --- a/src/org/jsoup/parser/Parser.java +++ /dev/null @@ -1,157 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; - -import java.util.List; - -/** - * Parses HTML into a {@link org.jsoup.nodes.Document}. Generally best to use one of the more convenient parse methods - * in {@link org.jsoup.Jsoup}. - */ -public class Parser { - private static final int DEFAULT_MAX_ERRORS = 0; // by default, error tracking is disabled. - - private TreeBuilder treeBuilder; - private int maxErrors = DEFAULT_MAX_ERRORS; - private ParseErrorList errors; - - /** - * Create a new Parser, using the specified TreeBuilder - * @param treeBuilder TreeBuilder to use to parse input into Documents. - */ - public Parser(TreeBuilder treeBuilder) { - this.treeBuilder = treeBuilder; - } - - public Document parseInput(String html, String baseUri) { - errors = isTrackErrors() ? ParseErrorList.tracking(maxErrors) : ParseErrorList.noTracking(); - Document doc = treeBuilder.parse(html, baseUri, errors); - return doc; - } - - // gets & sets - /** - * Get the TreeBuilder currently in use. - * @return current TreeBuilder. - */ - public TreeBuilder getTreeBuilder() { - return treeBuilder; - } - - /** - * Update the TreeBuilder used when parsing content. - * @param treeBuilder current TreeBuilder - * @return this, for chaining - */ - public Parser setTreeBuilder(TreeBuilder treeBuilder) { - this.treeBuilder = treeBuilder; - return this; - } - - /** - * Check if parse error tracking is enabled. - * @return current track error state. - */ - public boolean isTrackErrors() { - return maxErrors > 0; - } - - /** - * Enable or disable parse error tracking for the next parse. - * @param maxErrors the maximum number of errors to track. Set to 0 to disable. - * @return this, for chaining - */ - public Parser setTrackErrors(int maxErrors) { - this.maxErrors = maxErrors; - return this; - } - - /** - * Retrieve the parse errors, if any, from the last parse. - * @return list of parse errors, up to the size of the maximum errors tracked. - */ - public List<ParseError> getErrors() { - return errors; - } - - // static parse functions below - /** - * Parse HTML into a Document. - * - * @param html HTML to parse - * @param baseUri base URI of document (i.e. original fetch location), for resolving relative URLs. - * - * @return parsed Document - */ - public static Document parse(String html, String baseUri) { - TreeBuilder treeBuilder = new HtmlTreeBuilder(); - return treeBuilder.parse(html, baseUri, ParseErrorList.noTracking()); - } - - /** - * Parse a fragment of HTML into a list of nodes. The context element, if supplied, supplies parsing context. - * - * @param fragmentHtml the fragment of HTML to parse - * @param context (optional) the element that this HTML fragment is being parsed for (i.e. for inner HTML). This - * provides stack context (for implicit element creation). - * @param baseUri base URI of document (i.e. original fetch location), for resolving relative URLs. - * - * @return list of nodes parsed from the input HTML. Note that the context element, if supplied, is not modified. - */ - public static List<Node> parseFragment(String fragmentHtml, Element context, String baseUri) { - HtmlTreeBuilder treeBuilder = new HtmlTreeBuilder(); - return treeBuilder.parseFragment(fragmentHtml, context, baseUri, ParseErrorList.noTracking()); - } - - /** - * Parse a fragment of HTML into the {@code body} of a Document. - * - * @param bodyHtml fragment of HTML - * @param baseUri base URI of document (i.e. original fetch location), for resolving relative URLs. - * - * @return Document, with empty head, and HTML parsed into body - */ - public static Document parseBodyFragment(String bodyHtml, String baseUri) { - Document doc = Document.createShell(baseUri); - Element body = doc.body(); - List<Node> nodeList = parseFragment(bodyHtml, body, baseUri); - Node[] nodes = nodeList.toArray(new Node[nodeList.size()]); // the node list gets modified when re-parented - for (Node node : nodes) { - body.appendChild(node); - } - return doc; - } - - /** - * @param bodyHtml HTML to parse - * @param baseUri baseUri base URI of document (i.e. original fetch location), for resolving relative URLs. - * - * @return parsed Document - * @deprecated Use {@link #parseBodyFragment} or {@link #parseFragment} instead. - */ - public static Document parseBodyFragmentRelaxed(String bodyHtml, String baseUri) { - return parse(bodyHtml, baseUri); - } - - // builders - - /** - * Create a new HTML parser. This parser treats input as HTML5, and enforces the creation of a normalised document, - * based on a knowledge of the semantics of the incoming tags. - * @return a new HTML parser. - */ - public static Parser htmlParser() { - return new Parser(new HtmlTreeBuilder()); - } - - /** - * Create a new XML parser. This parser assumes no knowledge of the incoming tags and does not treat it as HTML, - * rather creates a simple tree directly from the input. - * @return a new simple XML parser. - */ - public static Parser xmlParser() { - return new Parser(new XmlTreeBuilder()); - } -} diff --git a/src/org/jsoup/parser/Tag.java b/src/org/jsoup/parser/Tag.java deleted file mode 100644 index 40b7557b39..0000000000 --- a/src/org/jsoup/parser/Tag.java +++ /dev/null @@ -1,262 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.Validate; - -import java.util.HashMap; -import java.util.Map; - -/** - * HTML Tag capabilities. - * - * @author Jonathan Hedley, jonathan@hedley.net - */ -public class Tag { - private static final Map<String, Tag> tags = new HashMap<String, Tag>(); // map of known tags - - private String tagName; - private boolean isBlock = true; // block or inline - private boolean formatAsBlock = true; // should be formatted as a block - private boolean canContainBlock = true; // Can this tag hold block level tags? - private boolean canContainInline = true; // only pcdata if not - private boolean empty = false; // can hold nothing; e.g. img - private boolean selfClosing = false; // can self close (<foo />). used for unknown tags that self close, without forcing them as empty. - private boolean preserveWhitespace = false; // for pre, textarea, script etc - - private Tag(String tagName) { - this.tagName = tagName.toLowerCase(); - } - - /** - * Get this tag's name. - * - * @return the tag's name - */ - public String getName() { - return tagName; - } - - /** - * Get a Tag by name. If not previously defined (unknown), returns a new generic tag, that can do anything. - * <p/> - * Pre-defined tags (P, DIV etc) will be ==, but unknown tags are not registered and will only .equals(). - * - * @param tagName Name of tag, e.g. "p". Case insensitive. - * @return The tag, either defined or new generic. - */ - public static Tag valueOf(String tagName) { - Validate.notNull(tagName); - tagName = tagName.trim().toLowerCase(); - Validate.notEmpty(tagName); - - synchronized (tags) { - Tag tag = tags.get(tagName); - if (tag == null) { - // not defined: create default; go anywhere, do anything! (incl be inside a <p>) - tag = new Tag(tagName); - tag.isBlock = false; - tag.canContainBlock = true; - } - return tag; - } - } - - /** - * Gets if this is a block tag. - * - * @return if block tag - */ - public boolean isBlock() { - return isBlock; - } - - /** - * Gets if this tag should be formatted as a block (or as inline) - * - * @return if should be formatted as block or inline - */ - public boolean formatAsBlock() { - return formatAsBlock; - } - - /** - * Gets if this tag can contain block tags. - * - * @return if tag can contain block tags - */ - public boolean canContainBlock() { - return canContainBlock; - } - - /** - * Gets if this tag is an inline tag. - * - * @return if this tag is an inline tag. - */ - public boolean isInline() { - return !isBlock; - } - - /** - * Gets if this tag is a data only tag. - * - * @return if this tag is a data only tag - */ - public boolean isData() { - return !canContainInline && !isEmpty(); - } - - /** - * Get if this is an empty tag - * - * @return if this is an empty tag - */ - public boolean isEmpty() { - return empty; - } - - /** - * Get if this tag is self closing. - * - * @return if this tag should be output as self closing. - */ - public boolean isSelfClosing() { - return empty || selfClosing; - } - - /** - * Get if this is a pre-defined tag, or was auto created on parsing. - * - * @return if a known tag - */ - public boolean isKnownTag() { - return tags.containsKey(tagName); - } - - /** - * Check if this tagname is a known tag. - * - * @param tagName name of tag - * @return if known HTML tag - */ - public static boolean isKnownTag(String tagName) { - return tags.containsKey(tagName); - } - - /** - * Get if this tag should preserve whitespace within child text nodes. - * - * @return if preserve whitepace - */ - public boolean preserveWhitespace() { - return preserveWhitespace; - } - - Tag setSelfClosing() { - selfClosing = true; - return this; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof Tag)) return false; - - Tag tag = (Tag) o; - - if (canContainBlock != tag.canContainBlock) return false; - if (canContainInline != tag.canContainInline) return false; - if (empty != tag.empty) return false; - if (formatAsBlock != tag.formatAsBlock) return false; - if (isBlock != tag.isBlock) return false; - if (preserveWhitespace != tag.preserveWhitespace) return false; - if (selfClosing != tag.selfClosing) return false; - if (!tagName.equals(tag.tagName)) return false; - - return true; - } - - @Override - public int hashCode() { - int result = tagName.hashCode(); - result = 31 * result + (isBlock ? 1 : 0); - result = 31 * result + (formatAsBlock ? 1 : 0); - result = 31 * result + (canContainBlock ? 1 : 0); - result = 31 * result + (canContainInline ? 1 : 0); - result = 31 * result + (empty ? 1 : 0); - result = 31 * result + (selfClosing ? 1 : 0); - result = 31 * result + (preserveWhitespace ? 1 : 0); - return result; - } - - public String toString() { - return tagName; - } - - // internal static initialisers: - // prepped from http://www.w3.org/TR/REC-html40/sgml/dtd.html and other sources - private static final String[] blockTags = { - "html", "head", "body", "frameset", "script", "noscript", "style", "meta", "link", "title", "frame", - "noframes", "section", "nav", "aside", "hgroup", "header", "footer", "p", "h1", "h2", "h3", "h4", "h5", "h6", - "ul", "ol", "pre", "div", "blockquote", "hr", "address", "figure", "figcaption", "form", "fieldset", "ins", - "del", "dl", "dt", "dd", "li", "table", "caption", "thead", "tfoot", "tbody", "colgroup", "col", "tr", "th", - "td", "video", "audio", "canvas", "details", "menu", "plaintext" - }; - private static final String[] inlineTags = { - "object", "base", "font", "tt", "i", "b", "u", "big", "small", "em", "strong", "dfn", "code", "samp", "kbd", - "var", "cite", "abbr", "time", "acronym", "mark", "ruby", "rt", "rp", "a", "img", "br", "wbr", "map", "q", - "sub", "sup", "bdo", "iframe", "embed", "span", "input", "select", "textarea", "label", "button", "optgroup", - "option", "legend", "datalist", "keygen", "output", "progress", "meter", "area", "param", "source", "track", - "summary", "command", "device" - }; - private static final String[] emptyTags = { - "meta", "link", "base", "frame", "img", "br", "wbr", "embed", "hr", "input", "keygen", "col", "command", - "device" - }; - private static final String[] formatAsInlineTags = { - "title", "a", "p", "h1", "h2", "h3", "h4", "h5", "h6", "pre", "address", "li", "th", "td", "script", "style" - }; - private static final String[] preserveWhitespaceTags = {"pre", "plaintext", "title"}; - - static { - // creates - for (String tagName : blockTags) { - Tag tag = new Tag(tagName); - register(tag); - } - for (String tagName : inlineTags) { - Tag tag = new Tag(tagName); - tag.isBlock = false; - tag.canContainBlock = false; - tag.formatAsBlock = false; - register(tag); - } - - // mods: - for (String tagName : emptyTags) { - Tag tag = tags.get(tagName); - Validate.notNull(tag); - tag.canContainBlock = false; - tag.canContainInline = false; - tag.empty = true; - } - - for (String tagName : formatAsInlineTags) { - Tag tag = tags.get(tagName); - Validate.notNull(tag); - tag.formatAsBlock = false; - } - - for (String tagName : preserveWhitespaceTags) { - Tag tag = tags.get(tagName); - Validate.notNull(tag); - tag.preserveWhitespace = true; - } - } - - private static Tag register(Tag tag) { - synchronized (tags) { - tags.put(tag.tagName, tag); - } - return tag; - } -} diff --git a/src/org/jsoup/parser/Token.java b/src/org/jsoup/parser/Token.java deleted file mode 100644 index 9f4f9e250d..0000000000 --- a/src/org/jsoup/parser/Token.java +++ /dev/null @@ -1,252 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Attribute; -import org.jsoup.nodes.Attributes; - -/** - * Parse tokens for the Tokeniser. - */ -abstract class Token { - TokenType type; - - private Token() { - } - - String tokenType() { - return this.getClass().getSimpleName(); - } - - static class Doctype extends Token { - final StringBuilder name = new StringBuilder(); - final StringBuilder publicIdentifier = new StringBuilder(); - final StringBuilder systemIdentifier = new StringBuilder(); - boolean forceQuirks = false; - - Doctype() { - type = TokenType.Doctype; - } - - String getName() { - return name.toString(); - } - - String getPublicIdentifier() { - return publicIdentifier.toString(); - } - - public String getSystemIdentifier() { - return systemIdentifier.toString(); - } - - public boolean isForceQuirks() { - return forceQuirks; - } - } - - static abstract class Tag extends Token { - protected String tagName; - private String pendingAttributeName; - private String pendingAttributeValue; - - boolean selfClosing = false; - Attributes attributes = new Attributes(); // todo: allow nodes to not have attributes - - void newAttribute() { - if (pendingAttributeName != null) { - if (pendingAttributeValue == null) - pendingAttributeValue = ""; - Attribute attribute = new Attribute(pendingAttributeName, pendingAttributeValue); - attributes.put(attribute); - } - pendingAttributeName = null; - pendingAttributeValue = null; - } - - void finaliseTag() { - // finalises for emit - if (pendingAttributeName != null) { - // todo: check if attribute name exists; if so, drop and error - newAttribute(); - } - } - - String name() { - Validate.isFalse(tagName.length() == 0); - return tagName; - } - - Tag name(String name) { - tagName = name; - return this; - } - - boolean isSelfClosing() { - return selfClosing; - } - - @SuppressWarnings({"TypeMayBeWeakened"}) - Attributes getAttributes() { - return attributes; - } - - // these appenders are rarely hit in not null state-- caused by null chars. - void appendTagName(String append) { - tagName = tagName == null ? append : tagName.concat(append); - } - - void appendTagName(char append) { - appendTagName(String.valueOf(append)); - } - - void appendAttributeName(String append) { - pendingAttributeName = pendingAttributeName == null ? append : pendingAttributeName.concat(append); - } - - void appendAttributeName(char append) { - appendAttributeName(String.valueOf(append)); - } - - void appendAttributeValue(String append) { - pendingAttributeValue = pendingAttributeValue == null ? append : pendingAttributeValue.concat(append); - } - - void appendAttributeValue(char append) { - appendAttributeValue(String.valueOf(append)); - } - } - - static class StartTag extends Tag { - StartTag() { - super(); - type = TokenType.StartTag; - } - - StartTag(String name) { - this(); - this.tagName = name; - } - - StartTag(String name, Attributes attributes) { - this(); - this.tagName = name; - this.attributes = attributes; - } - - @Override - public String toString() { - return "<" + name() + " " + attributes.toString() + ">"; - } - } - - static class EndTag extends Tag{ - EndTag() { - super(); - type = TokenType.EndTag; - } - - EndTag(String name) { - this(); - this.tagName = name; - } - - @Override - public String toString() { - return "</" + name() + " " + attributes.toString() + ">"; - } - } - - static class Comment extends Token { - final StringBuilder data = new StringBuilder(); - - Comment() { - type = TokenType.Comment; - } - - String getData() { - return data.toString(); - } - - @Override - public String toString() { - return "<!--" + getData() + "-->"; - } - } - - static class Character extends Token { - private final String data; - - Character(String data) { - type = TokenType.Character; - this.data = data; - } - - String getData() { - return data; - } - - @Override - public String toString() { - return getData(); - } - } - - static class EOF extends Token { - EOF() { - type = Token.TokenType.EOF; - } - } - - boolean isDoctype() { - return type == TokenType.Doctype; - } - - Doctype asDoctype() { - return (Doctype) this; - } - - boolean isStartTag() { - return type == TokenType.StartTag; - } - - StartTag asStartTag() { - return (StartTag) this; - } - - boolean isEndTag() { - return type == TokenType.EndTag; - } - - EndTag asEndTag() { - return (EndTag) this; - } - - boolean isComment() { - return type == TokenType.Comment; - } - - Comment asComment() { - return (Comment) this; - } - - boolean isCharacter() { - return type == TokenType.Character; - } - - Character asCharacter() { - return (Character) this; - } - - boolean isEOF() { - return type == TokenType.EOF; - } - - enum TokenType { - Doctype, - StartTag, - EndTag, - Comment, - Character, - EOF - } -} diff --git a/src/org/jsoup/parser/TokenQueue.java b/src/org/jsoup/parser/TokenQueue.java deleted file mode 100644 index a2fdfe621a..0000000000 --- a/src/org/jsoup/parser/TokenQueue.java +++ /dev/null @@ -1,393 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; - -/** - * A character queue with parsing helpers. - * - * @author Jonathan Hedley - */ -public class TokenQueue { - private String queue; - private int pos = 0; - - private static final char ESC = '\\'; // escape char for chomp balanced. - - /** - Create a new TokenQueue. - @param data string of data to back queue. - */ - public TokenQueue(String data) { - Validate.notNull(data); - queue = data; - } - - /** - * Is the queue empty? - * @return true if no data left in queue. - */ - public boolean isEmpty() { - return remainingLength() == 0; - } - - private int remainingLength() { - return queue.length() - pos; - } - - /** - * Retrieves but does not remove the first character from the queue. - * @return First character, or 0 if empty. - */ - public char peek() { - return isEmpty() ? 0 : queue.charAt(pos); - } - - /** - Add a character to the start of the queue (will be the next character retrieved). - @param c character to add - */ - public void addFirst(Character c) { - addFirst(c.toString()); - } - - /** - Add a string to the start of the queue. - @param seq string to add. - */ - public void addFirst(String seq) { - // not very performant, but an edge case - queue = seq + queue.substring(pos); - pos = 0; - } - - /** - * Tests if the next characters on the queue match the sequence. Case insensitive. - * @param seq String to check queue for. - * @return true if the next characters match. - */ - public boolean matches(String seq) { - return queue.regionMatches(true, pos, seq, 0, seq.length()); - } - - /** - * Case sensitive match test. - * @param seq string to case sensitively check for - * @return true if matched, false if not - */ - public boolean matchesCS(String seq) { - return queue.startsWith(seq, pos); - } - - - /** - Tests if the next characters match any of the sequences. Case insensitive. - @param seq list of strings to case insensitively check for - @return true of any matched, false if none did - */ - public boolean matchesAny(String... seq) { - for (String s : seq) { - if (matches(s)) - return true; - } - return false; - } - - public boolean matchesAny(char... seq) { - if (isEmpty()) - return false; - - for (char c: seq) { - if (queue.charAt(pos) == c) - return true; - } - return false; - } - - public boolean matchesStartTag() { - // micro opt for matching "<x" - return (remainingLength() >= 2 && queue.charAt(pos) == '<' && Character.isLetter(queue.charAt(pos+1))); - } - - /** - * Tests if the queue matches the sequence (as with match), and if they do, removes the matched string from the - * queue. - * @param seq String to search for, and if found, remove from queue. - * @return true if found and removed, false if not found. - */ - public boolean matchChomp(String seq) { - if (matches(seq)) { - pos += seq.length(); - return true; - } else { - return false; - } - } - - /** - Tests if queue starts with a whitespace character. - @return if starts with whitespace - */ - public boolean matchesWhitespace() { - return !isEmpty() && StringUtil.isWhitespace(queue.charAt(pos)); - } - - /** - Test if the queue matches a word character (letter or digit). - @return if matches a word character - */ - public boolean matchesWord() { - return !isEmpty() && Character.isLetterOrDigit(queue.charAt(pos)); - } - - /** - * Drops the next character off the queue. - */ - public void advance() { - if (!isEmpty()) pos++; - } - - /** - * Consume one character off queue. - * @return first character on queue. - */ - public char consume() { - return queue.charAt(pos++); - } - - /** - * Consumes the supplied sequence of the queue. If the queue does not start with the supplied sequence, will - * throw an illegal state exception -- but you should be running match() against that condition. - <p> - Case insensitive. - * @param seq sequence to remove from head of queue. - */ - public void consume(String seq) { - if (!matches(seq)) - throw new IllegalStateException("Queue did not match expected sequence"); - int len = seq.length(); - if (len > remainingLength()) - throw new IllegalStateException("Queue not long enough to consume sequence"); - - pos += len; - } - - /** - * Pulls a string off the queue, up to but exclusive of the match sequence, or to the queue running out. - * @param seq String to end on (and not include in return, but leave on queue). <b>Case sensitive.</b> - * @return The matched data consumed from queue. - */ - public String consumeTo(String seq) { - int offset = queue.indexOf(seq, pos); - if (offset != -1) { - String consumed = queue.substring(pos, offset); - pos += consumed.length(); - return consumed; - } else { - return remainder(); - } - } - - public String consumeToIgnoreCase(String seq) { - int start = pos; - String first = seq.substring(0, 1); - boolean canScan = first.toLowerCase().equals(first.toUpperCase()); // if first is not cased, use index of - while (!isEmpty()) { - if (matches(seq)) - break; - - if (canScan) { - int skip = queue.indexOf(first, pos) - pos; - if (skip == 0) // this char is the skip char, but not match, so force advance of pos - pos++; - else if (skip < 0) // no chance of finding, grab to end - pos = queue.length(); - else - pos += skip; - } - else - pos++; - } - - String data = queue.substring(start, pos); - return data; - } - - /** - Consumes to the first sequence provided, or to the end of the queue. Leaves the terminator on the queue. - @param seq any number of terminators to consume to. <b>Case insensitive.</b> - @return consumed string - */ - // todo: method name. not good that consumeTo cares for case, and consume to any doesn't. And the only use for this - // is is a case sensitive time... - public String consumeToAny(String... seq) { - int start = pos; - while (!isEmpty() && !matchesAny(seq)) { - pos++; - } - - String data = queue.substring(start, pos); - return data; - } - - /** - * Pulls a string off the queue (like consumeTo), and then pulls off the matched string (but does not return it). - * <p> - * If the queue runs out of characters before finding the seq, will return as much as it can (and queue will go - * isEmpty() == true). - * @param seq String to match up to, and not include in return, and to pull off queue. <b>Case sensitive.</b> - * @return Data matched from queue. - */ - public String chompTo(String seq) { - String data = consumeTo(seq); - matchChomp(seq); - return data; - } - - public String chompToIgnoreCase(String seq) { - String data = consumeToIgnoreCase(seq); // case insensitive scan - matchChomp(seq); - return data; - } - - /** - * Pulls a balanced string off the queue. E.g. if queue is "(one (two) three) four", (,) will return "one (two) three", - * and leave " four" on the queue. Unbalanced openers and closers can be escaped (with \). Those escapes will be left - * in the returned string, which is suitable for regexes (where we need to preserve the escape), but unsuitable for - * contains text strings; use unescape for that. - * @param open opener - * @param close closer - * @return data matched from the queue - */ - public String chompBalanced(char open, char close) { - StringBuilder accum = new StringBuilder(); - int depth = 0; - char last = 0; - - do { - if (isEmpty()) break; - Character c = consume(); - if (last == 0 || last != ESC) { - if (c.equals(open)) - depth++; - else if (c.equals(close)) - depth--; - } - - if (depth > 0 && last != 0) - accum.append(c); // don't include the outer match pair in the return - last = c; - } while (depth > 0); - return accum.toString(); - } - - /** - * Unescaped a \ escaped string. - * @param in backslash escaped string - * @return unescaped string - */ - public static String unescape(String in) { - StringBuilder out = new StringBuilder(); - char last = 0; - for (char c : in.toCharArray()) { - if (c == ESC) { - if (last != 0 && last == ESC) - out.append(c); - } - else - out.append(c); - last = c; - } - return out.toString(); - } - - /** - * Pulls the next run of whitespace characters of the queue. - */ - public boolean consumeWhitespace() { - boolean seen = false; - while (matchesWhitespace()) { - pos++; - seen = true; - } - return seen; - } - - /** - * Retrieves the next run of word type (letter or digit) off the queue. - * @return String of word characters from queue, or empty string if none. - */ - public String consumeWord() { - int start = pos; - while (matchesWord()) - pos++; - return queue.substring(start, pos); - } - - /** - * Consume an tag name off the queue (word or :, _, -) - * - * @return tag name - */ - public String consumeTagName() { - int start = pos; - while (!isEmpty() && (matchesWord() || matchesAny(':', '_', '-'))) - pos++; - - return queue.substring(start, pos); - } - - /** - * Consume a CSS element selector (tag name, but | instead of : for namespaces, to not conflict with :pseudo selects). - * - * @return tag name - */ - public String consumeElementSelector() { - int start = pos; - while (!isEmpty() && (matchesWord() || matchesAny('|', '_', '-'))) - pos++; - - return queue.substring(start, pos); - } - - /** - Consume a CSS identifier (ID or class) off the queue (letter, digit, -, _) - http://www.w3.org/TR/CSS2/syndata.html#value-def-identifier - @return identifier - */ - public String consumeCssIdentifier() { - int start = pos; - while (!isEmpty() && (matchesWord() || matchesAny('-', '_'))) - pos++; - - return queue.substring(start, pos); - } - - /** - Consume an attribute key off the queue (letter, digit, -, _, :") - @return attribute key - */ - public String consumeAttributeKey() { - int start = pos; - while (!isEmpty() && (matchesWord() || matchesAny('-', '_', ':'))) - pos++; - - return queue.substring(start, pos); - } - - /** - Consume and return whatever is left on the queue. - @return remained of queue. - */ - public String remainder() { - StringBuilder accum = new StringBuilder(); - while (!isEmpty()) { - accum.append(consume()); - } - return accum.toString(); - } - - public String toString() { - return queue.substring(pos); - } -} diff --git a/src/org/jsoup/parser/Tokeniser.java b/src/org/jsoup/parser/Tokeniser.java deleted file mode 100644 index ce6ee690d6..0000000000 --- a/src/org/jsoup/parser/Tokeniser.java +++ /dev/null @@ -1,230 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Entities; - -import java.util.ArrayList; -import java.util.List; - -/** - * Readers the input stream into tokens. - */ -class Tokeniser { - static final char replacementChar = '\uFFFD'; // replaces null character - - private CharacterReader reader; // html input - private ParseErrorList errors; // errors found while tokenising - - private TokeniserState state = TokeniserState.Data; // current tokenisation state - private Token emitPending; // the token we are about to emit on next read - private boolean isEmitPending = false; - private StringBuilder charBuffer = new StringBuilder(); // buffers characters to output as one token - StringBuilder dataBuffer; // buffers data looking for </script> - - Token.Tag tagPending; // tag we are building up - Token.Doctype doctypePending; // doctype building up - Token.Comment commentPending; // comment building up - private Token.StartTag lastStartTag; // the last start tag emitted, to test appropriate end tag - private boolean selfClosingFlagAcknowledged = true; - - Tokeniser(CharacterReader reader, ParseErrorList errors) { - this.reader = reader; - this.errors = errors; - } - - Token read() { - if (!selfClosingFlagAcknowledged) { - error("Self closing flag not acknowledged"); - selfClosingFlagAcknowledged = true; - } - - while (!isEmitPending) - state.read(this, reader); - - // if emit is pending, a non-character token was found: return any chars in buffer, and leave token for next read: - if (charBuffer.length() > 0) { - String str = charBuffer.toString(); - charBuffer.delete(0, charBuffer.length()); - return new Token.Character(str); - } else { - isEmitPending = false; - return emitPending; - } - } - - void emit(Token token) { - Validate.isFalse(isEmitPending, "There is an unread token pending!"); - - emitPending = token; - isEmitPending = true; - - if (token.type == Token.TokenType.StartTag) { - Token.StartTag startTag = (Token.StartTag) token; - lastStartTag = startTag; - if (startTag.selfClosing) - selfClosingFlagAcknowledged = false; - } else if (token.type == Token.TokenType.EndTag) { - Token.EndTag endTag = (Token.EndTag) token; - if (endTag.attributes.size() > 0) - error("Attributes incorrectly present on end tag"); - } - } - - void emit(String str) { - // buffer strings up until last string token found, to emit only one token for a run of character refs etc. - // does not set isEmitPending; read checks that - charBuffer.append(str); - } - - void emit(char c) { - charBuffer.append(c); - } - - TokeniserState getState() { - return state; - } - - void transition(TokeniserState state) { - this.state = state; - } - - void advanceTransition(TokeniserState state) { - reader.advance(); - this.state = state; - } - - void acknowledgeSelfClosingFlag() { - selfClosingFlagAcknowledged = true; - } - - Character consumeCharacterReference(Character additionalAllowedCharacter, boolean inAttribute) { - if (reader.isEmpty()) - return null; - if (additionalAllowedCharacter != null && additionalAllowedCharacter == reader.current()) - return null; - if (reader.matchesAny('\t', '\n', '\f', ' ', '<', '&')) - return null; - - reader.mark(); - if (reader.matchConsume("#")) { // numbered - boolean isHexMode = reader.matchConsumeIgnoreCase("X"); - String numRef = isHexMode ? reader.consumeHexSequence() : reader.consumeDigitSequence(); - if (numRef.length() == 0) { // didn't match anything - characterReferenceError("numeric reference with no numerals"); - reader.rewindToMark(); - return null; - } - if (!reader.matchConsume(";")) - characterReferenceError("missing semicolon"); // missing semi - int charval = -1; - try { - int base = isHexMode ? 16 : 10; - charval = Integer.valueOf(numRef, base); - } catch (NumberFormatException e) { - } // skip - if (charval == -1 || (charval >= 0xD800 && charval <= 0xDFFF) || charval > 0x10FFFF) { - characterReferenceError("character outside of valid range"); - return replacementChar; - } else { - // todo: implement number replacement table - // todo: check for extra illegal unicode points as parse errors - return (char) charval; - } - } else { // named - // get as many letters as possible, and look for matching entities. unconsume backwards till a match is found - String nameRef = reader.consumeLetterThenDigitSequence(); - String origNameRef = new String(nameRef); // for error reporting. nameRef gets chomped looking for matches - boolean looksLegit = reader.matches(';'); - boolean found = false; - while (nameRef.length() > 0 && !found) { - if (Entities.isNamedEntity(nameRef)) - found = true; - else { - nameRef = nameRef.substring(0, nameRef.length()-1); - reader.unconsume(); - } - } - if (!found) { - if (looksLegit) // named with semicolon - characterReferenceError(String.format("invalid named referenece '%s'", origNameRef)); - reader.rewindToMark(); - return null; - } - if (inAttribute && (reader.matchesLetter() || reader.matchesDigit() || reader.matchesAny('=', '-', '_'))) { - // don't want that to match - reader.rewindToMark(); - return null; - } - if (!reader.matchConsume(";")) - characterReferenceError("missing semicolon"); // missing semi - return Entities.getCharacterByName(nameRef); - } - } - - Token.Tag createTagPending(boolean start) { - tagPending = start ? new Token.StartTag() : new Token.EndTag(); - return tagPending; - } - - void emitTagPending() { - tagPending.finaliseTag(); - emit(tagPending); - } - - void createCommentPending() { - commentPending = new Token.Comment(); - } - - void emitCommentPending() { - emit(commentPending); - } - - void createDoctypePending() { - doctypePending = new Token.Doctype(); - } - - void emitDoctypePending() { - emit(doctypePending); - } - - void createTempBuffer() { - dataBuffer = new StringBuilder(); - } - - boolean isAppropriateEndTagToken() { - if (lastStartTag == null) - return false; - return tagPending.tagName.equals(lastStartTag.tagName); - } - - String appropriateEndTagName() { - return lastStartTag.tagName; - } - - void error(TokeniserState state) { - if (errors.canAddError()) - errors.add(new ParseError(reader.pos(), "Unexpected character '%s' in input state [%s]", reader.current(), state)); - } - - void eofError(TokeniserState state) { - if (errors.canAddError()) - errors.add(new ParseError(reader.pos(), "Unexpectedly reached end of file (EOF) in input state [%s]", state)); - } - - private void characterReferenceError(String message) { - if (errors.canAddError()) - errors.add(new ParseError(reader.pos(), "Invalid character reference: %s", message)); - } - - private void error(String errorMsg) { - if (errors.canAddError()) - errors.add(new ParseError(reader.pos(), errorMsg)); - } - - boolean currentNodeInHtmlNS() { - // todo: implement namespaces correctly - return true; - // Element currentNode = currentNode(); - // return currentNode != null && currentNode.namespace().equals("HTML"); - } -} diff --git a/src/org/jsoup/parser/TokeniserState.java b/src/org/jsoup/parser/TokeniserState.java deleted file mode 100644 index e3013c73e9..0000000000 --- a/src/org/jsoup/parser/TokeniserState.java +++ /dev/null @@ -1,1778 +0,0 @@ -package org.jsoup.parser; - -/** - * States and transition activations for the Tokeniser. - */ -enum TokeniserState { - Data { - // in data state, gather characters until a character reference or tag is found - void read(Tokeniser t, CharacterReader r) { - switch (r.current()) { - case '&': - t.advanceTransition(CharacterReferenceInData); - break; - case '<': - t.advanceTransition(TagOpen); - break; - case nullChar: - t.error(this); // NOT replacement character (oddly?) - t.emit(r.consume()); - break; - case eof: - t.emit(new Token.EOF()); - break; - default: - String data = r.consumeToAny('&', '<', nullChar); - t.emit(data); - break; - } - } - }, - CharacterReferenceInData { - // from & in data - void read(Tokeniser t, CharacterReader r) { - Character c = t.consumeCharacterReference(null, false); - if (c == null) - t.emit('&'); - else - t.emit(c); - t.transition(Data); - } - }, - Rcdata { - /// handles data in title, textarea etc - void read(Tokeniser t, CharacterReader r) { - switch (r.current()) { - case '&': - t.advanceTransition(CharacterReferenceInRcdata); - break; - case '<': - t.advanceTransition(RcdataLessthanSign); - break; - case nullChar: - t.error(this); - r.advance(); - t.emit(replacementChar); - break; - case eof: - t.emit(new Token.EOF()); - break; - default: - String data = r.consumeToAny('&', '<', nullChar); - t.emit(data); - break; - } - } - }, - CharacterReferenceInRcdata { - void read(Tokeniser t, CharacterReader r) { - Character c = t.consumeCharacterReference(null, false); - if (c == null) - t.emit('&'); - else - t.emit(c); - t.transition(Rcdata); - } - }, - Rawtext { - void read(Tokeniser t, CharacterReader r) { - switch (r.current()) { - case '<': - t.advanceTransition(RawtextLessthanSign); - break; - case nullChar: - t.error(this); - r.advance(); - t.emit(replacementChar); - break; - case eof: - t.emit(new Token.EOF()); - break; - default: - String data = r.consumeToAny('<', nullChar); - t.emit(data); - break; - } - } - }, - ScriptData { - void read(Tokeniser t, CharacterReader r) { - switch (r.current()) { - case '<': - t.advanceTransition(ScriptDataLessthanSign); - break; - case nullChar: - t.error(this); - r.advance(); - t.emit(replacementChar); - break; - case eof: - t.emit(new Token.EOF()); - break; - default: - String data = r.consumeToAny('<', nullChar); - t.emit(data); - break; - } - } - }, - PLAINTEXT { - void read(Tokeniser t, CharacterReader r) { - switch (r.current()) { - case nullChar: - t.error(this); - r.advance(); - t.emit(replacementChar); - break; - case eof: - t.emit(new Token.EOF()); - break; - default: - String data = r.consumeTo(nullChar); - t.emit(data); - break; - } - } - }, - TagOpen { - // from < in data - void read(Tokeniser t, CharacterReader r) { - switch (r.current()) { - case '!': - t.advanceTransition(MarkupDeclarationOpen); - break; - case '/': - t.advanceTransition(EndTagOpen); - break; - case '?': - t.advanceTransition(BogusComment); - break; - default: - if (r.matchesLetter()) { - t.createTagPending(true); - t.transition(TagName); - } else { - t.error(this); - t.emit('<'); // char that got us here - t.transition(Data); - } - break; - } - } - }, - EndTagOpen { - void read(Tokeniser t, CharacterReader r) { - if (r.isEmpty()) { - t.eofError(this); - t.emit("</"); - t.transition(Data); - } else if (r.matchesLetter()) { - t.createTagPending(false); - t.transition(TagName); - } else if (r.matches('>')) { - t.error(this); - t.advanceTransition(Data); - } else { - t.error(this); - t.advanceTransition(BogusComment); - } - } - }, - TagName { - // from < or </ in data, will have start or end tag pending - void read(Tokeniser t, CharacterReader r) { - // previous TagOpen state did NOT consume, will have a letter char in current - String tagName = r.consumeToAny('\t', '\n', '\f', ' ', '/', '>', nullChar).toLowerCase(); - t.tagPending.appendTagName(tagName); - - switch (r.consume()) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeAttributeName); - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - case nullChar: // replacement - t.tagPending.appendTagName(replacementStr); - break; - case eof: // should emit pending tag? - t.eofError(this); - t.transition(Data); - // no default, as covered with above consumeToAny - } - } - }, - RcdataLessthanSign { - // from < in rcdata - void read(Tokeniser t, CharacterReader r) { - if (r.matches('/')) { - t.createTempBuffer(); - t.advanceTransition(RCDATAEndTagOpen); - } else if (r.matchesLetter() && !r.containsIgnoreCase("</" + t.appropriateEndTagName())) { - // diverge from spec: got a start tag, but there's no appropriate end tag (</title>), so rather than - // consuming to EOF; break out here - t.tagPending = new Token.EndTag(t.appropriateEndTagName()); - t.emitTagPending(); - r.unconsume(); // undo "<" - t.transition(Data); - } else { - t.emit("<"); - t.transition(Rcdata); - } - } - }, - RCDATAEndTagOpen { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - t.createTagPending(false); - t.tagPending.appendTagName(Character.toLowerCase(r.current())); - t.dataBuffer.append(Character.toLowerCase(r.current())); - t.advanceTransition(RCDATAEndTagName); - } else { - t.emit("</"); - t.transition(Rcdata); - } - } - }, - RCDATAEndTagName { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.tagPending.appendTagName(name.toLowerCase()); - t.dataBuffer.append(name); - return; - } - - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - if (t.isAppropriateEndTagToken()) - t.transition(BeforeAttributeName); - else - anythingElse(t, r); - break; - case '/': - if (t.isAppropriateEndTagToken()) - t.transition(SelfClosingStartTag); - else - anythingElse(t, r); - break; - case '>': - if (t.isAppropriateEndTagToken()) { - t.emitTagPending(); - t.transition(Data); - } - else - anythingElse(t, r); - break; - default: - anythingElse(t, r); - } - } - - private void anythingElse(Tokeniser t, CharacterReader r) { - t.emit("</" + t.dataBuffer.toString()); - t.transition(Rcdata); - } - }, - RawtextLessthanSign { - void read(Tokeniser t, CharacterReader r) { - if (r.matches('/')) { - t.createTempBuffer(); - t.advanceTransition(RawtextEndTagOpen); - } else { - t.emit('<'); - t.transition(Rawtext); - } - } - }, - RawtextEndTagOpen { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - t.createTagPending(false); - t.transition(RawtextEndTagName); - } else { - t.emit("</"); - t.transition(Rawtext); - } - } - }, - RawtextEndTagName { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.tagPending.appendTagName(name.toLowerCase()); - t.dataBuffer.append(name); - return; - } - - if (t.isAppropriateEndTagToken() && !r.isEmpty()) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeAttributeName); - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - default: - t.dataBuffer.append(c); - anythingElse(t, r); - } - } else - anythingElse(t, r); - } - - private void anythingElse(Tokeniser t, CharacterReader r) { - t.emit("</" + t.dataBuffer.toString()); - t.transition(Rawtext); - } - }, - ScriptDataLessthanSign { - void read(Tokeniser t, CharacterReader r) { - switch (r.consume()) { - case '/': - t.createTempBuffer(); - t.transition(ScriptDataEndTagOpen); - break; - case '!': - t.emit("<!"); - t.transition(ScriptDataEscapeStart); - break; - default: - t.emit("<"); - r.unconsume(); - t.transition(ScriptData); - } - } - }, - ScriptDataEndTagOpen { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - t.createTagPending(false); - t.transition(ScriptDataEndTagName); - } else { - t.emit("</"); - t.transition(ScriptData); - } - - } - }, - ScriptDataEndTagName { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.tagPending.appendTagName(name.toLowerCase()); - t.dataBuffer.append(name); - return; - } - - if (t.isAppropriateEndTagToken() && !r.isEmpty()) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeAttributeName); - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - default: - t.dataBuffer.append(c); - anythingElse(t, r); - } - } else { - anythingElse(t, r); - } - } - - private void anythingElse(Tokeniser t, CharacterReader r) { - t.emit("</" + t.dataBuffer.toString()); - t.transition(ScriptData); - } - }, - ScriptDataEscapeStart { - void read(Tokeniser t, CharacterReader r) { - if (r.matches('-')) { - t.emit('-'); - t.advanceTransition(ScriptDataEscapeStartDash); - } else { - t.transition(ScriptData); - } - } - }, - ScriptDataEscapeStartDash { - void read(Tokeniser t, CharacterReader r) { - if (r.matches('-')) { - t.emit('-'); - t.advanceTransition(ScriptDataEscapedDashDash); - } else { - t.transition(ScriptData); - } - } - }, - ScriptDataEscaped { - void read(Tokeniser t, CharacterReader r) { - if (r.isEmpty()) { - t.eofError(this); - t.transition(Data); - return; - } - - switch (r.current()) { - case '-': - t.emit('-'); - t.advanceTransition(ScriptDataEscapedDash); - break; - case '<': - t.advanceTransition(ScriptDataEscapedLessthanSign); - break; - case nullChar: - t.error(this); - r.advance(); - t.emit(replacementChar); - break; - default: - String data = r.consumeToAny('-', '<', nullChar); - t.emit(data); - } - } - }, - ScriptDataEscapedDash { - void read(Tokeniser t, CharacterReader r) { - if (r.isEmpty()) { - t.eofError(this); - t.transition(Data); - return; - } - - char c = r.consume(); - switch (c) { - case '-': - t.emit(c); - t.transition(ScriptDataEscapedDashDash); - break; - case '<': - t.transition(ScriptDataEscapedLessthanSign); - break; - case nullChar: - t.error(this); - t.emit(replacementChar); - t.transition(ScriptDataEscaped); - break; - default: - t.emit(c); - t.transition(ScriptDataEscaped); - } - } - }, - ScriptDataEscapedDashDash { - void read(Tokeniser t, CharacterReader r) { - if (r.isEmpty()) { - t.eofError(this); - t.transition(Data); - return; - } - - char c = r.consume(); - switch (c) { - case '-': - t.emit(c); - break; - case '<': - t.transition(ScriptDataEscapedLessthanSign); - break; - case '>': - t.emit(c); - t.transition(ScriptData); - break; - case nullChar: - t.error(this); - t.emit(replacementChar); - t.transition(ScriptDataEscaped); - break; - default: - t.emit(c); - t.transition(ScriptDataEscaped); - } - } - }, - ScriptDataEscapedLessthanSign { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - t.createTempBuffer(); - t.dataBuffer.append(Character.toLowerCase(r.current())); - t.emit("<" + r.current()); - t.advanceTransition(ScriptDataDoubleEscapeStart); - } else if (r.matches('/')) { - t.createTempBuffer(); - t.advanceTransition(ScriptDataEscapedEndTagOpen); - } else { - t.emit('<'); - t.transition(ScriptDataEscaped); - } - } - }, - ScriptDataEscapedEndTagOpen { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - t.createTagPending(false); - t.tagPending.appendTagName(Character.toLowerCase(r.current())); - t.dataBuffer.append(r.current()); - t.advanceTransition(ScriptDataEscapedEndTagName); - } else { - t.emit("</"); - t.transition(ScriptDataEscaped); - } - } - }, - ScriptDataEscapedEndTagName { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.tagPending.appendTagName(name.toLowerCase()); - t.dataBuffer.append(name); - return; - } - - if (t.isAppropriateEndTagToken() && !r.isEmpty()) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeAttributeName); - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - default: - t.dataBuffer.append(c); - anythingElse(t, r); - break; - } - } else { - anythingElse(t, r); - } - } - - private void anythingElse(Tokeniser t, CharacterReader r) { - t.emit("</" + t.dataBuffer.toString()); - t.transition(ScriptDataEscaped); - } - }, - ScriptDataDoubleEscapeStart { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.dataBuffer.append(name.toLowerCase()); - t.emit(name); - return; - } - - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - case '/': - case '>': - if (t.dataBuffer.toString().equals("script")) - t.transition(ScriptDataDoubleEscaped); - else - t.transition(ScriptDataEscaped); - t.emit(c); - break; - default: - r.unconsume(); - t.transition(ScriptDataEscaped); - } - } - }, - ScriptDataDoubleEscaped { - void read(Tokeniser t, CharacterReader r) { - char c = r.current(); - switch (c) { - case '-': - t.emit(c); - t.advanceTransition(ScriptDataDoubleEscapedDash); - break; - case '<': - t.emit(c); - t.advanceTransition(ScriptDataDoubleEscapedLessthanSign); - break; - case nullChar: - t.error(this); - r.advance(); - t.emit(replacementChar); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - default: - String data = r.consumeToAny('-', '<', nullChar); - t.emit(data); - } - } - }, - ScriptDataDoubleEscapedDash { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '-': - t.emit(c); - t.transition(ScriptDataDoubleEscapedDashDash); - break; - case '<': - t.emit(c); - t.transition(ScriptDataDoubleEscapedLessthanSign); - break; - case nullChar: - t.error(this); - t.emit(replacementChar); - t.transition(ScriptDataDoubleEscaped); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - default: - t.emit(c); - t.transition(ScriptDataDoubleEscaped); - } - } - }, - ScriptDataDoubleEscapedDashDash { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '-': - t.emit(c); - break; - case '<': - t.emit(c); - t.transition(ScriptDataDoubleEscapedLessthanSign); - break; - case '>': - t.emit(c); - t.transition(ScriptData); - break; - case nullChar: - t.error(this); - t.emit(replacementChar); - t.transition(ScriptDataDoubleEscaped); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - default: - t.emit(c); - t.transition(ScriptDataDoubleEscaped); - } - } - }, - ScriptDataDoubleEscapedLessthanSign { - void read(Tokeniser t, CharacterReader r) { - if (r.matches('/')) { - t.emit('/'); - t.createTempBuffer(); - t.advanceTransition(ScriptDataDoubleEscapeEnd); - } else { - t.transition(ScriptDataDoubleEscaped); - } - } - }, - ScriptDataDoubleEscapeEnd { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.dataBuffer.append(name.toLowerCase()); - t.emit(name); - return; - } - - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - case '/': - case '>': - if (t.dataBuffer.toString().equals("script")) - t.transition(ScriptDataEscaped); - else - t.transition(ScriptDataDoubleEscaped); - t.emit(c); - break; - default: - r.unconsume(); - t.transition(ScriptDataDoubleEscaped); - } - } - }, - BeforeAttributeName { - // from tagname <xxx - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - break; // ignore whitespace - case '/': - t.transition(SelfClosingStartTag); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - case nullChar: - t.error(this); - t.tagPending.newAttribute(); - r.unconsume(); - t.transition(AttributeName); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - case '"': - case '\'': - case '<': - case '=': - t.error(this); - t.tagPending.newAttribute(); - t.tagPending.appendAttributeName(c); - t.transition(AttributeName); - break; - default: // A-Z, anything else - t.tagPending.newAttribute(); - r.unconsume(); - t.transition(AttributeName); - } - } - }, - AttributeName { - // from before attribute name - void read(Tokeniser t, CharacterReader r) { - String name = r.consumeToAny('\t', '\n', '\f', ' ', '/', '=', '>', nullChar, '"', '\'', '<'); - t.tagPending.appendAttributeName(name.toLowerCase()); - - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(AfterAttributeName); - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '=': - t.transition(BeforeAttributeValue); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - case nullChar: - t.error(this); - t.tagPending.appendAttributeName(replacementChar); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - case '"': - case '\'': - case '<': - t.error(this); - t.tagPending.appendAttributeName(c); - // no default, as covered in consumeToAny - } - } - }, - AfterAttributeName { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - // ignore - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '=': - t.transition(BeforeAttributeValue); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - case nullChar: - t.error(this); - t.tagPending.appendAttributeName(replacementChar); - t.transition(AttributeName); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - case '"': - case '\'': - case '<': - t.error(this); - t.tagPending.newAttribute(); - t.tagPending.appendAttributeName(c); - t.transition(AttributeName); - break; - default: // A-Z, anything else - t.tagPending.newAttribute(); - r.unconsume(); - t.transition(AttributeName); - } - } - }, - BeforeAttributeValue { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - // ignore - break; - case '"': - t.transition(AttributeValue_doubleQuoted); - break; - case '&': - r.unconsume(); - t.transition(AttributeValue_unquoted); - break; - case '\'': - t.transition(AttributeValue_singleQuoted); - break; - case nullChar: - t.error(this); - t.tagPending.appendAttributeValue(replacementChar); - t.transition(AttributeValue_unquoted); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - case '>': - t.error(this); - t.emitTagPending(); - t.transition(Data); - break; - case '<': - case '=': - case '`': - t.error(this); - t.tagPending.appendAttributeValue(c); - t.transition(AttributeValue_unquoted); - break; - default: - r.unconsume(); - t.transition(AttributeValue_unquoted); - } - } - }, - AttributeValue_doubleQuoted { - void read(Tokeniser t, CharacterReader r) { - String value = r.consumeToAny('"', '&', nullChar); - if (value.length() > 0) - t.tagPending.appendAttributeValue(value); - - char c = r.consume(); - switch (c) { - case '"': - t.transition(AfterAttributeValue_quoted); - break; - case '&': - Character ref = t.consumeCharacterReference('"', true); - if (ref != null) - t.tagPending.appendAttributeValue(ref); - else - t.tagPending.appendAttributeValue('&'); - break; - case nullChar: - t.error(this); - t.tagPending.appendAttributeValue(replacementChar); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - // no default, handled in consume to any above - } - } - }, - AttributeValue_singleQuoted { - void read(Tokeniser t, CharacterReader r) { - String value = r.consumeToAny('\'', '&', nullChar); - if (value.length() > 0) - t.tagPending.appendAttributeValue(value); - - char c = r.consume(); - switch (c) { - case '\'': - t.transition(AfterAttributeValue_quoted); - break; - case '&': - Character ref = t.consumeCharacterReference('\'', true); - if (ref != null) - t.tagPending.appendAttributeValue(ref); - else - t.tagPending.appendAttributeValue('&'); - break; - case nullChar: - t.error(this); - t.tagPending.appendAttributeValue(replacementChar); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - // no default, handled in consume to any above - } - } - }, - AttributeValue_unquoted { - void read(Tokeniser t, CharacterReader r) { - String value = r.consumeToAny('\t', '\n', '\f', ' ', '&', '>', nullChar, '"', '\'', '<', '=', '`'); - if (value.length() > 0) - t.tagPending.appendAttributeValue(value); - - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeAttributeName); - break; - case '&': - Character ref = t.consumeCharacterReference('>', true); - if (ref != null) - t.tagPending.appendAttributeValue(ref); - else - t.tagPending.appendAttributeValue('&'); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - case nullChar: - t.error(this); - t.tagPending.appendAttributeValue(replacementChar); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - case '"': - case '\'': - case '<': - case '=': - case '`': - t.error(this); - t.tagPending.appendAttributeValue(c); - break; - // no default, handled in consume to any above - } - - } - }, - // CharacterReferenceInAttributeValue state handled inline - AfterAttributeValue_quoted { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeAttributeName); - break; - case '/': - t.transition(SelfClosingStartTag); - break; - case '>': - t.emitTagPending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - default: - t.error(this); - r.unconsume(); - t.transition(BeforeAttributeName); - } - - } - }, - SelfClosingStartTag { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '>': - t.tagPending.selfClosing = true; - t.emitTagPending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.transition(Data); - break; - default: - t.error(this); - t.transition(BeforeAttributeName); - } - } - }, - BogusComment { - void read(Tokeniser t, CharacterReader r) { - // todo: handle bogus comment starting from eof. when does that trigger? - // rewind to capture character that lead us here - r.unconsume(); - Token.Comment comment = new Token.Comment(); - comment.data.append(r.consumeTo('>')); - // todo: replace nullChar with replaceChar - t.emit(comment); - t.advanceTransition(Data); - } - }, - MarkupDeclarationOpen { - void read(Tokeniser t, CharacterReader r) { - if (r.matchConsume("--")) { - t.createCommentPending(); - t.transition(CommentStart); - } else if (r.matchConsumeIgnoreCase("DOCTYPE")) { - t.transition(Doctype); - } else if (r.matchConsume("[CDATA[")) { - // todo: should actually check current namepspace, and only non-html allows cdata. until namespace - // is implemented properly, keep handling as cdata - //} else if (!t.currentNodeInHtmlNS() && r.matchConsume("[CDATA[")) { - t.transition(CdataSection); - } else { - t.error(this); - t.advanceTransition(BogusComment); // advance so this character gets in bogus comment data's rewind - } - } - }, - CommentStart { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '-': - t.transition(CommentStartDash); - break; - case nullChar: - t.error(this); - t.commentPending.data.append(replacementChar); - t.transition(Comment); - break; - case '>': - t.error(this); - t.emitCommentPending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.emitCommentPending(); - t.transition(Data); - break; - default: - t.commentPending.data.append(c); - t.transition(Comment); - } - } - }, - CommentStartDash { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '-': - t.transition(CommentStartDash); - break; - case nullChar: - t.error(this); - t.commentPending.data.append(replacementChar); - t.transition(Comment); - break; - case '>': - t.error(this); - t.emitCommentPending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.emitCommentPending(); - t.transition(Data); - break; - default: - t.commentPending.data.append(c); - t.transition(Comment); - } - } - }, - Comment { - void read(Tokeniser t, CharacterReader r) { - char c = r.current(); - switch (c) { - case '-': - t.advanceTransition(CommentEndDash); - break; - case nullChar: - t.error(this); - r.advance(); - t.commentPending.data.append(replacementChar); - break; - case eof: - t.eofError(this); - t.emitCommentPending(); - t.transition(Data); - break; - default: - t.commentPending.data.append(r.consumeToAny('-', nullChar)); - } - } - }, - CommentEndDash { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '-': - t.transition(CommentEnd); - break; - case nullChar: - t.error(this); - t.commentPending.data.append('-').append(replacementChar); - t.transition(Comment); - break; - case eof: - t.eofError(this); - t.emitCommentPending(); - t.transition(Data); - break; - default: - t.commentPending.data.append('-').append(c); - t.transition(Comment); - } - } - }, - CommentEnd { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '>': - t.emitCommentPending(); - t.transition(Data); - break; - case nullChar: - t.error(this); - t.commentPending.data.append("--").append(replacementChar); - t.transition(Comment); - break; - case '!': - t.error(this); - t.transition(CommentEndBang); - break; - case '-': - t.error(this); - t.commentPending.data.append('-'); - break; - case eof: - t.eofError(this); - t.emitCommentPending(); - t.transition(Data); - break; - default: - t.error(this); - t.commentPending.data.append("--").append(c); - t.transition(Comment); - } - } - }, - CommentEndBang { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '-': - t.commentPending.data.append("--!"); - t.transition(CommentEndDash); - break; - case '>': - t.emitCommentPending(); - t.transition(Data); - break; - case nullChar: - t.error(this); - t.commentPending.data.append("--!").append(replacementChar); - t.transition(Comment); - break; - case eof: - t.eofError(this); - t.emitCommentPending(); - t.transition(Data); - break; - default: - t.commentPending.data.append("--!").append(c); - t.transition(Comment); - } - } - }, - Doctype { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeDoctypeName); - break; - case eof: - t.eofError(this); - t.createDoctypePending(); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.transition(BeforeDoctypeName); - } - } - }, - BeforeDoctypeName { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - t.createDoctypePending(); - t.transition(DoctypeName); - return; - } - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - break; // ignore whitespace - case nullChar: - t.error(this); - t.doctypePending.name.append(replacementChar); - t.transition(DoctypeName); - break; - case eof: - t.eofError(this); - t.createDoctypePending(); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.createDoctypePending(); - t.doctypePending.name.append(c); - t.transition(DoctypeName); - } - } - }, - DoctypeName { - void read(Tokeniser t, CharacterReader r) { - if (r.matchesLetter()) { - String name = r.consumeLetterSequence(); - t.doctypePending.name.append(name.toLowerCase()); - return; - } - char c = r.consume(); - switch (c) { - case '>': - t.emitDoctypePending(); - t.transition(Data); - break; - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(AfterDoctypeName); - break; - case nullChar: - t.error(this); - t.doctypePending.name.append(replacementChar); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.doctypePending.name.append(c); - } - } - }, - AfterDoctypeName { - void read(Tokeniser t, CharacterReader r) { - if (r.isEmpty()) { - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - return; - } - if (r.matchesAny('\t', '\n', '\f', ' ')) - r.advance(); // ignore whitespace - else if (r.matches('>')) { - t.emitDoctypePending(); - t.advanceTransition(Data); - } else if (r.matchConsumeIgnoreCase("PUBLIC")) { - t.transition(AfterDoctypePublicKeyword); - } else if (r.matchConsumeIgnoreCase("SYSTEM")) { - t.transition(AfterDoctypeSystemKeyword); - } else { - t.error(this); - t.doctypePending.forceQuirks = true; - t.advanceTransition(BogusDoctype); - } - - } - }, - AfterDoctypePublicKeyword { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeDoctypePublicIdentifier); - break; - case '"': - t.error(this); - // set public id to empty string - t.transition(DoctypePublicIdentifier_doubleQuoted); - break; - case '\'': - t.error(this); - // set public id to empty string - t.transition(DoctypePublicIdentifier_singleQuoted); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.doctypePending.forceQuirks = true; - t.transition(BogusDoctype); - } - } - }, - BeforeDoctypePublicIdentifier { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - break; - case '"': - // set public id to empty string - t.transition(DoctypePublicIdentifier_doubleQuoted); - break; - case '\'': - // set public id to empty string - t.transition(DoctypePublicIdentifier_singleQuoted); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.doctypePending.forceQuirks = true; - t.transition(BogusDoctype); - } - } - }, - DoctypePublicIdentifier_doubleQuoted { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '"': - t.transition(AfterDoctypePublicIdentifier); - break; - case nullChar: - t.error(this); - t.doctypePending.publicIdentifier.append(replacementChar); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.doctypePending.publicIdentifier.append(c); - } - } - }, - DoctypePublicIdentifier_singleQuoted { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\'': - t.transition(AfterDoctypePublicIdentifier); - break; - case nullChar: - t.error(this); - t.doctypePending.publicIdentifier.append(replacementChar); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.doctypePending.publicIdentifier.append(c); - } - } - }, - AfterDoctypePublicIdentifier { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BetweenDoctypePublicAndSystemIdentifiers); - break; - case '>': - t.emitDoctypePending(); - t.transition(Data); - break; - case '"': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_doubleQuoted); - break; - case '\'': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_singleQuoted); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.doctypePending.forceQuirks = true; - t.transition(BogusDoctype); - } - } - }, - BetweenDoctypePublicAndSystemIdentifiers { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - break; - case '>': - t.emitDoctypePending(); - t.transition(Data); - break; - case '"': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_doubleQuoted); - break; - case '\'': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_singleQuoted); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.doctypePending.forceQuirks = true; - t.transition(BogusDoctype); - } - } - }, - AfterDoctypeSystemKeyword { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - t.transition(BeforeDoctypeSystemIdentifier); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case '"': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_doubleQuoted); - break; - case '\'': - t.error(this); - // system id empty - t.transition(DoctypeSystemIdentifier_singleQuoted); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - } - } - }, - BeforeDoctypeSystemIdentifier { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - break; - case '"': - // set system id to empty string - t.transition(DoctypeSystemIdentifier_doubleQuoted); - break; - case '\'': - // set public id to empty string - t.transition(DoctypeSystemIdentifier_singleQuoted); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.doctypePending.forceQuirks = true; - t.transition(BogusDoctype); - } - } - }, - DoctypeSystemIdentifier_doubleQuoted { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '"': - t.transition(AfterDoctypeSystemIdentifier); - break; - case nullChar: - t.error(this); - t.doctypePending.systemIdentifier.append(replacementChar); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.doctypePending.systemIdentifier.append(c); - } - } - }, - DoctypeSystemIdentifier_singleQuoted { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\'': - t.transition(AfterDoctypeSystemIdentifier); - break; - case nullChar: - t.error(this); - t.doctypePending.systemIdentifier.append(replacementChar); - break; - case '>': - t.error(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.doctypePending.systemIdentifier.append(c); - } - } - }, - AfterDoctypeSystemIdentifier { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '\t': - case '\n': - case '\f': - case ' ': - break; - case '>': - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.eofError(this); - t.doctypePending.forceQuirks = true; - t.emitDoctypePending(); - t.transition(Data); - break; - default: - t.error(this); - t.transition(BogusDoctype); - // NOT force quirks - } - } - }, - BogusDoctype { - void read(Tokeniser t, CharacterReader r) { - char c = r.consume(); - switch (c) { - case '>': - t.emitDoctypePending(); - t.transition(Data); - break; - case eof: - t.emitDoctypePending(); - t.transition(Data); - break; - default: - // ignore char - break; - } - } - }, - CdataSection { - void read(Tokeniser t, CharacterReader r) { - String data = r.consumeTo("]]>"); - t.emit(data); - r.matchConsume("]]>"); - t.transition(Data); - } - }; - - - abstract void read(Tokeniser t, CharacterReader r); - - private static final char nullChar = '\u0000'; - private static final char replacementChar = Tokeniser.replacementChar; - private static final String replacementStr = String.valueOf(Tokeniser.replacementChar); - private static final char eof = CharacterReader.EOF; -} diff --git a/src/org/jsoup/parser/TreeBuilder.java b/src/org/jsoup/parser/TreeBuilder.java deleted file mode 100644 index e06caad501..0000000000 --- a/src/org/jsoup/parser/TreeBuilder.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.DescendableLinkedList; -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Document; -import org.jsoup.nodes.Element; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author Jonathan Hedley - */ -abstract class TreeBuilder { - CharacterReader reader; - Tokeniser tokeniser; - protected Document doc; // current doc we are building into - protected DescendableLinkedList<Element> stack; // the stack of open elements - protected String baseUri; // current base uri, for creating new elements - protected Token currentToken; // currentToken is used only for error tracking. - protected ParseErrorList errors; // null when not tracking errors - - protected void initialiseParse(String input, String baseUri, ParseErrorList errors) { - Validate.notNull(input, "String input must not be null"); - Validate.notNull(baseUri, "BaseURI must not be null"); - - doc = new Document(baseUri); - reader = new CharacterReader(input); - this.errors = errors; - tokeniser = new Tokeniser(reader, errors); - stack = new DescendableLinkedList<Element>(); - this.baseUri = baseUri; - } - - Document parse(String input, String baseUri) { - return parse(input, baseUri, ParseErrorList.noTracking()); - } - - Document parse(String input, String baseUri, ParseErrorList errors) { - initialiseParse(input, baseUri, errors); - runParser(); - return doc; - } - - protected void runParser() { - while (true) { - Token token = tokeniser.read(); - process(token); - - if (token.type == Token.TokenType.EOF) - break; - } - } - - protected abstract boolean process(Token token); - - protected Element currentElement() { - return stack.getLast(); - } -} diff --git a/src/org/jsoup/parser/XmlTreeBuilder.java b/src/org/jsoup/parser/XmlTreeBuilder.java deleted file mode 100644 index 3f03ad26ac..0000000000 --- a/src/org/jsoup/parser/XmlTreeBuilder.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.jsoup.parser; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.*; - -import java.util.Iterator; - -/** - * @author Jonathan Hedley - */ -public class XmlTreeBuilder extends TreeBuilder { - @Override - protected void initialiseParse(String input, String baseUri, ParseErrorList errors) { - super.initialiseParse(input, baseUri, errors); - stack.add(doc); // place the document onto the stack. differs from HtmlTreeBuilder (not on stack) - } - - @Override - protected boolean process(Token token) { - // start tag, end tag, doctype, comment, character, eof - switch (token.type) { - case StartTag: - insert(token.asStartTag()); - break; - case EndTag: - popStackToClose(token.asEndTag()); - break; - case Comment: - insert(token.asComment()); - break; - case Character: - insert(token.asCharacter()); - break; - case Doctype: - insert(token.asDoctype()); - break; - case EOF: // could put some normalisation here if desired - break; - default: - Validate.fail("Unexpected token type: " + token.type); - } - return true; - } - - private void insertNode(Node node) { - currentElement().appendChild(node); - } - - Element insert(Token.StartTag startTag) { - Tag tag = Tag.valueOf(startTag.name()); - // todo: wonder if for xml parsing, should treat all tags as unknown? because it's not html. - Element el = new Element(tag, baseUri, startTag.attributes); - insertNode(el); - if (startTag.isSelfClosing()) { - tokeniser.acknowledgeSelfClosingFlag(); - if (!tag.isKnownTag()) // unknown tag, remember this is self closing for output. see above. - tag.setSelfClosing(); - } else { - stack.add(el); - } - return el; - } - - void insert(Token.Comment commentToken) { - Comment comment = new Comment(commentToken.getData(), baseUri); - insertNode(comment); - } - - void insert(Token.Character characterToken) { - Node node = new TextNode(characterToken.getData(), baseUri); - insertNode(node); - } - - void insert(Token.Doctype d) { - DocumentType doctypeNode = new DocumentType(d.getName(), d.getPublicIdentifier(), d.getSystemIdentifier(), baseUri); - insertNode(doctypeNode); - } - - /** - * If the stack contains an element with this tag's name, pop up the stack to remove the first occurrence. If not - * found, skips. - * - * @param endTag - */ - private void popStackToClose(Token.EndTag endTag) { - String elName = endTag.name(); - Element firstFound = null; - - Iterator<Element> it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next.nodeName().equals(elName)) { - firstFound = next; - break; - } - } - if (firstFound == null) - return; // not found, skip - - it = stack.descendingIterator(); - while (it.hasNext()) { - Element next = it.next(); - if (next == firstFound) { - it.remove(); - break; - } else { - it.remove(); - } - } - } -} diff --git a/src/org/jsoup/parser/package-info.java b/src/org/jsoup/parser/package-info.java deleted file mode 100644 index 168fdf4086..0000000000 --- a/src/org/jsoup/parser/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - Contains the HTML parser, tag specifications, and HTML tokeniser. - */ -package org.jsoup.parser; diff --git a/src/org/jsoup/safety/Cleaner.java b/src/org/jsoup/safety/Cleaner.java deleted file mode 100644 index eda67df86b..0000000000 --- a/src/org/jsoup/safety/Cleaner.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.jsoup.safety; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.*; -import org.jsoup.parser.Tag; - -import java.util.List; - -/** - The whitelist based HTML cleaner. Use to ensure that end-user provided HTML contains only the elements and attributes - that you are expecting; no junk, and no cross-site scripting attacks! - <p/> - The HTML cleaner parses the input as HTML and then runs it through a white-list, so the output HTML can only contain - HTML that is allowed by the whitelist. - <p/> - It is assumed that the input HTML is a body fragment; the clean methods only pull from the source's body, and the - canned white-lists only allow body contained tags. - <p/> - Rather than interacting directly with a Cleaner object, generally see the {@code clean} methods in {@link org.jsoup.Jsoup}. - */ -public class Cleaner { - private Whitelist whitelist; - - /** - Create a new cleaner, that sanitizes documents using the supplied whitelist. - @param whitelist white-list to clean with - */ - public Cleaner(Whitelist whitelist) { - Validate.notNull(whitelist); - this.whitelist = whitelist; - } - - /** - Creates a new, clean document, from the original dirty document, containing only elements allowed by the whitelist. - The original document is not modified. Only elements from the dirt document's <code>body</code> are used. - @param dirtyDocument Untrusted base document to clean. - @return cleaned document. - */ - public Document clean(Document dirtyDocument) { - Validate.notNull(dirtyDocument); - - Document clean = Document.createShell(dirtyDocument.baseUri()); - copySafeNodes(dirtyDocument.body(), clean.body()); - - return clean; - } - - /** - Determines if the input document is valid, against the whitelist. It is considered valid if all the tags and attributes - in the input HTML are allowed by the whitelist. - <p/> - This method can be used as a validator for user input forms. An invalid document will still be cleaned successfully - using the {@link #clean(Document)} document. If using as a validator, it is recommended to still clean the document - to ensure enforced attributes are set correctly, and that the output is tidied. - @param dirtyDocument document to test - @return true if no tags or attributes need to be removed; false if they do - */ - public boolean isValid(Document dirtyDocument) { - Validate.notNull(dirtyDocument); - - Document clean = Document.createShell(dirtyDocument.baseUri()); - int numDiscarded = copySafeNodes(dirtyDocument.body(), clean.body()); - return numDiscarded == 0; - } - - /** - Iterates the input and copies trusted nodes (tags, attributes, text) into the destination. - @param source source of HTML - @param dest destination element to copy into - @return number of discarded elements (that were considered unsafe) - */ - private int copySafeNodes(Element source, Element dest) { - List<Node> sourceChildren = source.childNodes(); - int numDiscarded = 0; - - for (Node sourceChild : sourceChildren) { - if (sourceChild instanceof Element) { - Element sourceEl = (Element) sourceChild; - - if (whitelist.isSafeTag(sourceEl.tagName())) { // safe, clone and copy safe attrs - ElementMeta meta = createSafeElement(sourceEl); - Element destChild = meta.el; - dest.appendChild(destChild); - - numDiscarded += meta.numAttribsDiscarded; - numDiscarded += copySafeNodes(sourceEl, destChild); // recurs - } else { // not a safe tag, but it may have children (els or text) that are, so recurse - numDiscarded++; - numDiscarded += copySafeNodes(sourceEl, dest); - } - } else if (sourceChild instanceof TextNode) { - TextNode sourceText = (TextNode) sourceChild; - TextNode destText = new TextNode(sourceText.getWholeText(), sourceChild.baseUri()); - dest.appendChild(destText); - } // else, we don't care about comments, xml proc instructions, etc - } - return numDiscarded; - } - - private ElementMeta createSafeElement(Element sourceEl) { - String sourceTag = sourceEl.tagName(); - Attributes destAttrs = new Attributes(); - Element dest = new Element(Tag.valueOf(sourceTag), sourceEl.baseUri(), destAttrs); - int numDiscarded = 0; - - Attributes sourceAttrs = sourceEl.attributes(); - for (Attribute sourceAttr : sourceAttrs) { - if (whitelist.isSafeAttribute(sourceTag, sourceEl, sourceAttr)) - destAttrs.put(sourceAttr); - else - numDiscarded++; - } - Attributes enforcedAttrs = whitelist.getEnforcedAttributes(sourceTag); - destAttrs.addAll(enforcedAttrs); - - return new ElementMeta(dest, numDiscarded); - } - - private static class ElementMeta { - Element el; - int numAttribsDiscarded; - - ElementMeta(Element el, int numAttribsDiscarded) { - this.el = el; - this.numAttribsDiscarded = numAttribsDiscarded; - } - } - -} diff --git a/src/org/jsoup/safety/Whitelist.java b/src/org/jsoup/safety/Whitelist.java deleted file mode 100644 index 2c1150ce9e..0000000000 --- a/src/org/jsoup/safety/Whitelist.java +++ /dev/null @@ -1,451 +0,0 @@ -package org.jsoup.safety; - -/* - Thank you to Ryan Grove (wonko.com) for the Ruby HTML cleaner http://github.com/rgrove/sanitize/, which inspired - this whitelist configuration, and the initial defaults. - */ - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Attribute; -import org.jsoup.nodes.Attributes; -import org.jsoup.nodes.Element; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - - -/** - Whitelists define what HTML (elements and attributes) to allow through the cleaner. Everything else is removed. - <p/> - Start with one of the defaults: - <ul> - <li>{@link #none} - <li>{@link #simpleText} - <li>{@link #basic} - <li>{@link #basicWithImages} - <li>{@link #relaxed} - </ul> - <p/> - If you need to allow more through (please be careful!), tweak a base whitelist with: - <ul> - <li>{@link #addTags} - <li>{@link #addAttributes} - <li>{@link #addEnforcedAttribute} - <li>{@link #addProtocols} - </ul> - <p/> - The cleaner and these whitelists assume that you want to clean a <code>body</code> fragment of HTML (to add user - supplied HTML into a templated page), and not to clean a full HTML document. If the latter is the case, either wrap the - document HTML around the cleaned body HTML, or create a whitelist that allows <code>html</code> and <code>head</code> - elements as appropriate. - <p/> - If you are going to extend a whitelist, please be very careful. Make sure you understand what attributes may lead to - XSS attack vectors. URL attributes are particularly vulnerable and require careful validation. See - http://ha.ckers.org/xss.html for some XSS attack examples. - - @author Jonathan Hedley - */ -public class Whitelist { - private Set<TagName> tagNames; // tags allowed, lower case. e.g. [p, br, span] - private Map<TagName, Set<AttributeKey>> attributes; // tag -> attribute[]. allowed attributes [href] for a tag. - private Map<TagName, Map<AttributeKey, AttributeValue>> enforcedAttributes; // always set these attribute values - private Map<TagName, Map<AttributeKey, Set<Protocol>>> protocols; // allowed URL protocols for attributes - private boolean preserveRelativeLinks; // option to preserve relative links - - /** - This whitelist allows only text nodes: all HTML will be stripped. - - @return whitelist - */ - public static Whitelist none() { - return new Whitelist(); - } - - /** - This whitelist allows only simple text formatting: <code>b, em, i, strong, u</code>. All other HTML (tags and - attributes) will be removed. - - @return whitelist - */ - public static Whitelist simpleText() { - return new Whitelist() - .addTags("b", "em", "i", "strong", "u") - ; - } - - /** - This whitelist allows a fuller range of text nodes: <code>a, b, blockquote, br, cite, code, dd, dl, dt, em, i, li, - ol, p, pre, q, small, strike, strong, sub, sup, u, ul</code>, and appropriate attributes. - <p/> - Links (<code>a</code> elements) can point to <code>http, https, ftp, mailto</code>, and have an enforced - <code>rel=nofollow</code> attribute. - <p/> - Does not allow images. - - @return whitelist - */ - public static Whitelist basic() { - return new Whitelist() - .addTags( - "a", "b", "blockquote", "br", "cite", "code", "dd", "dl", "dt", "em", - "i", "li", "ol", "p", "pre", "q", "small", "strike", "strong", "sub", - "sup", "u", "ul") - - .addAttributes("a", "href") - .addAttributes("blockquote", "cite") - .addAttributes("q", "cite") - - .addProtocols("a", "href", "ftp", "http", "https", "mailto") - .addProtocols("blockquote", "cite", "http", "https") - .addProtocols("cite", "cite", "http", "https") - - .addEnforcedAttribute("a", "rel", "nofollow") - ; - - } - - /** - This whitelist allows the same text tags as {@link #basic}, and also allows <code>img</code> tags, with appropriate - attributes, with <code>src</code> pointing to <code>http</code> or <code>https</code>. - - @return whitelist - */ - public static Whitelist basicWithImages() { - return basic() - .addTags("img") - .addAttributes("img", "align", "alt", "height", "src", "title", "width") - .addProtocols("img", "src", "http", "https") - ; - } - - /** - This whitelist allows a full range of text and structural body HTML: <code>a, b, blockquote, br, caption, cite, - code, col, colgroup, dd, dl, dt, em, h1, h2, h3, h4, h5, h6, i, img, li, ol, p, pre, q, small, strike, strong, sub, - sup, table, tbody, td, tfoot, th, thead, tr, u, ul</code> - <p/> - Links do not have an enforced <code>rel=nofollow</code> attribute, but you can add that if desired. - - @return whitelist - */ - public static Whitelist relaxed() { - return new Whitelist() - .addTags( - "a", "b", "blockquote", "br", "caption", "cite", "code", "col", - "colgroup", "dd", "div", "dl", "dt", "em", "h1", "h2", "h3", "h4", "h5", "h6", - "i", "img", "li", "ol", "p", "pre", "q", "small", "strike", "strong", - "sub", "sup", "table", "tbody", "td", "tfoot", "th", "thead", "tr", "u", - "ul") - - .addAttributes("a", "href", "title") - .addAttributes("blockquote", "cite") - .addAttributes("col", "span", "width") - .addAttributes("colgroup", "span", "width") - .addAttributes("img", "align", "alt", "height", "src", "title", "width") - .addAttributes("ol", "start", "type") - .addAttributes("q", "cite") - .addAttributes("table", "summary", "width") - .addAttributes("td", "abbr", "axis", "colspan", "rowspan", "width") - .addAttributes( - "th", "abbr", "axis", "colspan", "rowspan", "scope", - "width") - .addAttributes("ul", "type") - - .addProtocols("a", "href", "ftp", "http", "https", "mailto") - .addProtocols("blockquote", "cite", "http", "https") - .addProtocols("img", "src", "http", "https") - .addProtocols("q", "cite", "http", "https") - ; - } - - /** - Create a new, empty whitelist. Generally it will be better to start with a default prepared whitelist instead. - - @see #basic() - @see #basicWithImages() - @see #simpleText() - @see #relaxed() - */ - public Whitelist() { - tagNames = new HashSet<TagName>(); - attributes = new HashMap<TagName, Set<AttributeKey>>(); - enforcedAttributes = new HashMap<TagName, Map<AttributeKey, AttributeValue>>(); - protocols = new HashMap<TagName, Map<AttributeKey, Set<Protocol>>>(); - preserveRelativeLinks = false; - } - - /** - Add a list of allowed elements to a whitelist. (If a tag is not allowed, it will be removed from the HTML.) - - @param tags tag names to allow - @return this (for chaining) - */ - public Whitelist addTags(String... tags) { - Validate.notNull(tags); - - for (String tagName : tags) { - Validate.notEmpty(tagName); - tagNames.add(TagName.valueOf(tagName)); - } - return this; - } - - /** - Add a list of allowed attributes to a tag. (If an attribute is not allowed on an element, it will be removed.) - <p/> - E.g.: <code>addAttributes("a", "href", "class")</code> allows <code>href</code> and <code>class</code> attributes - on <code>a</code> tags. - <p/> - To make an attribute valid for <b>all tags</b>, use the pseudo tag <code>:all</code>, e.g. - <code>addAttributes(":all", "class")</code>. - - @param tag The tag the attributes are for. The tag will be added to the allowed tag list if necessary. - @param keys List of valid attributes for the tag - @return this (for chaining) - */ - public Whitelist addAttributes(String tag, String... keys) { - Validate.notEmpty(tag); - Validate.notNull(keys); - Validate.isTrue(keys.length > 0, "No attributes supplied."); - - TagName tagName = TagName.valueOf(tag); - if (!tagNames.contains(tagName)) - tagNames.add(tagName); - Set<AttributeKey> attributeSet = new HashSet<AttributeKey>(); - for (String key : keys) { - Validate.notEmpty(key); - attributeSet.add(AttributeKey.valueOf(key)); - } - if (attributes.containsKey(tagName)) { - Set<AttributeKey> currentSet = attributes.get(tagName); - currentSet.addAll(attributeSet); - } else { - attributes.put(tagName, attributeSet); - } - return this; - } - - /** - Add an enforced attribute to a tag. An enforced attribute will always be added to the element. If the element - already has the attribute set, it will be overridden. - <p/> - E.g.: <code>addEnforcedAttribute("a", "rel", "nofollow")</code> will make all <code>a</code> tags output as - <code><a href="..." rel="nofollow"></code> - - @param tag The tag the enforced attribute is for. The tag will be added to the allowed tag list if necessary. - @param key The attribute key - @param value The enforced attribute value - @return this (for chaining) - */ - public Whitelist addEnforcedAttribute(String tag, String key, String value) { - Validate.notEmpty(tag); - Validate.notEmpty(key); - Validate.notEmpty(value); - - TagName tagName = TagName.valueOf(tag); - if (!tagNames.contains(tagName)) - tagNames.add(tagName); - AttributeKey attrKey = AttributeKey.valueOf(key); - AttributeValue attrVal = AttributeValue.valueOf(value); - - if (enforcedAttributes.containsKey(tagName)) { - enforcedAttributes.get(tagName).put(attrKey, attrVal); - } else { - Map<AttributeKey, AttributeValue> attrMap = new HashMap<AttributeKey, AttributeValue>(); - attrMap.put(attrKey, attrVal); - enforcedAttributes.put(tagName, attrMap); - } - return this; - } - - /** - * Configure this Whitelist to preserve relative links in an element's URL attribute, or convert them to absolute - * links. By default, this is <b>false</b>: URLs will be made absolute (e.g. start with an allowed protocol, like - * e.g. {@code http://}. - * <p /> - * Note that when handling relative links, the input document must have an appropriate {@code base URI} set when - * parsing, so that the link's protocol can be confirmed. Regardless of the setting of the {@code preserve relative - * links} option, the link must be resolvable against the base URI to an allowed protocol; otherwise the attribute - * will be removed. - * - * @param preserve {@code true} to allow relative links, {@code false} (default) to deny - * @return this Whitelist, for chaining. - * @see #addProtocols - */ - public Whitelist preserveRelativeLinks(boolean preserve) { - preserveRelativeLinks = preserve; - return this; - } - - /** - Add allowed URL protocols for an element's URL attribute. This restricts the possible values of the attribute to - URLs with the defined protocol. - <p/> - E.g.: <code>addProtocols("a", "href", "ftp", "http", "https")</code> - - @param tag Tag the URL protocol is for - @param key Attribute key - @param protocols List of valid protocols - @return this, for chaining - */ - public Whitelist addProtocols(String tag, String key, String... protocols) { - Validate.notEmpty(tag); - Validate.notEmpty(key); - Validate.notNull(protocols); - - TagName tagName = TagName.valueOf(tag); - AttributeKey attrKey = AttributeKey.valueOf(key); - Map<AttributeKey, Set<Protocol>> attrMap; - Set<Protocol> protSet; - - if (this.protocols.containsKey(tagName)) { - attrMap = this.protocols.get(tagName); - } else { - attrMap = new HashMap<AttributeKey, Set<Protocol>>(); - this.protocols.put(tagName, attrMap); - } - if (attrMap.containsKey(attrKey)) { - protSet = attrMap.get(attrKey); - } else { - protSet = new HashSet<Protocol>(); - attrMap.put(attrKey, protSet); - } - for (String protocol : protocols) { - Validate.notEmpty(protocol); - Protocol prot = Protocol.valueOf(protocol); - protSet.add(prot); - } - return this; - } - - boolean isSafeTag(String tag) { - return tagNames.contains(TagName.valueOf(tag)); - } - - boolean isSafeAttribute(String tagName, Element el, Attribute attr) { - TagName tag = TagName.valueOf(tagName); - AttributeKey key = AttributeKey.valueOf(attr.getKey()); - - if (attributes.containsKey(tag)) { - if (attributes.get(tag).contains(key)) { - if (protocols.containsKey(tag)) { - Map<AttributeKey, Set<Protocol>> attrProts = protocols.get(tag); - // ok if not defined protocol; otherwise test - return !attrProts.containsKey(key) || testValidProtocol(el, attr, attrProts.get(key)); - } else { // attribute found, no protocols defined, so OK - return true; - } - } - } - // no attributes defined for tag, try :all tag - return !tagName.equals(":all") && isSafeAttribute(":all", el, attr); - } - - private boolean testValidProtocol(Element el, Attribute attr, Set<Protocol> protocols) { - // try to resolve relative urls to abs, and optionally update the attribute so output html has abs. - // rels without a baseuri get removed - String value = el.absUrl(attr.getKey()); - if (value.length() == 0) - value = attr.getValue(); // if it could not be made abs, run as-is to allow custom unknown protocols - if (!preserveRelativeLinks) - attr.setValue(value); - - for (Protocol protocol : protocols) { - String prot = protocol.toString() + ":"; - if (value.toLowerCase().startsWith(prot)) { - return true; - } - } - return false; - } - - Attributes getEnforcedAttributes(String tagName) { - Attributes attrs = new Attributes(); - TagName tag = TagName.valueOf(tagName); - if (enforcedAttributes.containsKey(tag)) { - Map<AttributeKey, AttributeValue> keyVals = enforcedAttributes.get(tag); - for (Map.Entry<AttributeKey, AttributeValue> entry : keyVals.entrySet()) { - attrs.put(entry.getKey().toString(), entry.getValue().toString()); - } - } - return attrs; - } - - // named types for config. All just hold strings, but here for my sanity. - - static class TagName extends TypedValue { - TagName(String value) { - super(value); - } - - static TagName valueOf(String value) { - return new TagName(value); - } - } - - static class AttributeKey extends TypedValue { - AttributeKey(String value) { - super(value); - } - - static AttributeKey valueOf(String value) { - return new AttributeKey(value); - } - } - - static class AttributeValue extends TypedValue { - AttributeValue(String value) { - super(value); - } - - static AttributeValue valueOf(String value) { - return new AttributeValue(value); - } - } - - static class Protocol extends TypedValue { - Protocol(String value) { - super(value); - } - - static Protocol valueOf(String value) { - return new Protocol(value); - } - } - - abstract static class TypedValue { - private String value; - - TypedValue(String value) { - Validate.notNull(value); - this.value = value; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) return true; - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - TypedValue other = (TypedValue) obj; - if (value == null) { - if (other.value != null) return false; - } else if (!value.equals(other.value)) return false; - return true; - } - - @Override - public String toString() { - return value; - } - } -} - diff --git a/src/org/jsoup/safety/package-info.java b/src/org/jsoup/safety/package-info.java deleted file mode 100644 index ac890f0607..0000000000 --- a/src/org/jsoup/safety/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - Contains the jsoup HTML cleaner, and whitelist definitions. - */ -package org.jsoup.safety; diff --git a/src/org/jsoup/select/Collector.java b/src/org/jsoup/select/Collector.java deleted file mode 100644 index 8f01045768..0000000000 --- a/src/org/jsoup/select/Collector.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; - -/** - * Collects a list of elements that match the supplied criteria. - * - * @author Jonathan Hedley - */ -public class Collector { - - private Collector() { - } - - /** - Build a list of elements, by visiting root and every descendant of root, and testing it against the evaluator. - @param eval Evaluator to test elements against - @param root root of tree to descend - @return list of matches; empty if none - */ - public static Elements collect (Evaluator eval, Element root) { - Elements elements = new Elements(); - new NodeTraversor(new Accumulator(root, elements, eval)).traverse(root); - return elements; - } - - private static class Accumulator implements NodeVisitor { - private final Element root; - private final Elements elements; - private final Evaluator eval; - - Accumulator(Element root, Elements elements, Evaluator eval) { - this.root = root; - this.elements = elements; - this.eval = eval; - } - - public void head(Node node, int depth) { - if (node instanceof Element) { - Element el = (Element) node; - if (eval.matches(root, el)) - elements.add(el); - } - } - - public void tail(Node node, int depth) { - // void - } - } -} diff --git a/src/org/jsoup/select/CombiningEvaluator.java b/src/org/jsoup/select/CombiningEvaluator.java deleted file mode 100644 index a31ed2636f..0000000000 --- a/src/org/jsoup/select/CombiningEvaluator.java +++ /dev/null @@ -1,94 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.helper.StringUtil; -import org.jsoup.nodes.Element; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -/** - * Base combining (and, or) evaluator. - */ -abstract class CombiningEvaluator extends Evaluator { - final List<Evaluator> evaluators; - - CombiningEvaluator() { - super(); - evaluators = new ArrayList<Evaluator>(); - } - - CombiningEvaluator(Collection<Evaluator> evaluators) { - this(); - this.evaluators.addAll(evaluators); - } - - Evaluator rightMostEvaluator() { - return evaluators.size() > 0 ? evaluators.get(evaluators.size() - 1) : null; - } - - void replaceRightMostEvaluator(Evaluator replacement) { - evaluators.set(evaluators.size() - 1, replacement); - } - - static final class And extends CombiningEvaluator { - And(Collection<Evaluator> evaluators) { - super(evaluators); - } - - And(Evaluator... evaluators) { - this(Arrays.asList(evaluators)); - } - - @Override - public boolean matches(Element root, Element node) { - for (Evaluator s : evaluators) { - if (!s.matches(root, node)) - return false; - } - return true; - } - - @Override - public String toString() { - return StringUtil.join(evaluators, " "); - } - } - - static final class Or extends CombiningEvaluator { - /** - * Create a new Or evaluator. The initial evaluators are ANDed together and used as the first clause of the OR. - * @param evaluators initial OR clause (these are wrapped into an AND evaluator). - */ - Or(Collection<Evaluator> evaluators) { - super(); - if (evaluators.size() > 1) - this.evaluators.add(new And(evaluators)); - else // 0 or 1 - this.evaluators.addAll(evaluators); - } - - Or() { - super(); - } - - public void add(Evaluator e) { - evaluators.add(e); - } - - @Override - public boolean matches(Element root, Element node) { - for (Evaluator s : evaluators) { - if (s.matches(root, node)) - return true; - } - return false; - } - - @Override - public String toString() { - return String.format(":or%s", evaluators); - } - } -} diff --git a/src/org/jsoup/select/Elements.java b/src/org/jsoup/select/Elements.java deleted file mode 100644 index 8302da1e53..0000000000 --- a/src/org/jsoup/select/Elements.java +++ /dev/null @@ -1,536 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Element; -import org.jsoup.nodes.Node; - -import java.util.*; - -/** - A list of {@link Element Elements}, with methods that act on every element in the list. - <p/> - To get an Elements object, use the {@link Element#select(String)} method. - - @author Jonathan Hedley, jonathan@hedley.net */ -public class Elements implements List<Element>, Cloneable { - private List<Element> contents; - - public Elements() { - contents = new ArrayList<Element>(); - } - - public Elements(int initialCapacity) { - contents = new ArrayList<Element>(initialCapacity); - } - - public Elements(Collection<Element> elements) { - contents = new ArrayList<Element>(elements); - } - - public Elements(List<Element> elements) { - contents = elements; - } - - public Elements(Element... elements) { - this(Arrays.asList(elements)); - } - - @Override - public Elements clone() { - List<Element> elements = new ArrayList<Element>(); - - for(Element e : contents) - elements.add(e.clone()); - - - return new Elements(elements); - } - - // attribute methods - /** - Get an attribute value from the first matched element that has the attribute. - @param attributeKey The attribute key. - @return The attribute value from the first matched element that has the attribute.. If no elements were matched (isEmpty() == true), - or if the no elements have the attribute, returns empty string. - @see #hasAttr(String) - */ - public String attr(String attributeKey) { - for (Element element : contents) { - if (element.hasAttr(attributeKey)) - return element.attr(attributeKey); - } - return ""; - } - - /** - Checks if any of the matched elements have this attribute set. - @param attributeKey attribute key - @return true if any of the elements have the attribute; false if none do. - */ - public boolean hasAttr(String attributeKey) { - for (Element element : contents) { - if (element.hasAttr(attributeKey)) - return true; - } - return false; - } - - /** - * Set an attribute on all matched elements. - * @param attributeKey attribute key - * @param attributeValue attribute value - * @return this - */ - public Elements attr(String attributeKey, String attributeValue) { - for (Element element : contents) { - element.attr(attributeKey, attributeValue); - } - return this; - } - - /** - * Remove an attribute from every matched element. - * @param attributeKey The attribute to remove. - * @return this (for chaining) - */ - public Elements removeAttr(String attributeKey) { - for (Element element : contents) { - element.removeAttr(attributeKey); - } - return this; - } - - /** - Add the class name to every matched element's {@code class} attribute. - @param className class name to add - @return this - */ - public Elements addClass(String className) { - for (Element element : contents) { - element.addClass(className); - } - return this; - } - - /** - Remove the class name from every matched element's {@code class} attribute, if present. - @param className class name to remove - @return this - */ - public Elements removeClass(String className) { - for (Element element : contents) { - element.removeClass(className); - } - return this; - } - - /** - Toggle the class name on every matched element's {@code class} attribute. - @param className class name to add if missing, or remove if present, from every element. - @return this - */ - public Elements toggleClass(String className) { - for (Element element : contents) { - element.toggleClass(className); - } - return this; - } - - /** - Determine if any of the matched elements have this class name set in their {@code class} attribute. - @param className class name to check for - @return true if any do, false if none do - */ - public boolean hasClass(String className) { - for (Element element : contents) { - if (element.hasClass(className)) - return true; - } - return false; - } - - /** - * Get the form element's value of the first matched element. - * @return The form element's value, or empty if not set. - * @see Element#val() - */ - public String val() { - if (size() > 0) - return first().val(); - else - return ""; - } - - /** - * Set the form element's value in each of the matched elements. - * @param value The value to set into each matched element - * @return this (for chaining) - */ - public Elements val(String value) { - for (Element element : contents) - element.val(value); - return this; - } - - /** - * Get the combined text of all the matched elements. - * <p> - * Note that it is possible to get repeats if the matched elements contain both parent elements and their own - * children, as the Element.text() method returns the combined text of a parent and all its children. - * @return string of all text: unescaped and no HTML. - * @see Element#text() - */ - public String text() { - StringBuilder sb = new StringBuilder(); - for (Element element : contents) { - if (sb.length() != 0) - sb.append(" "); - sb.append(element.text()); - } - return sb.toString(); - } - - public boolean hasText() { - for (Element element: contents) { - if (element.hasText()) - return true; - } - return false; - } - - /** - * Get the combined inner HTML of all matched elements. - * @return string of all element's inner HTML. - * @see #text() - * @see #outerHtml() - */ - public String html() { - StringBuilder sb = new StringBuilder(); - for (Element element : contents) { - if (sb.length() != 0) - sb.append("\n"); - sb.append(element.html()); - } - return sb.toString(); - } - - /** - * Get the combined outer HTML of all matched elements. - * @return string of all element's outer HTML. - * @see #text() - * @see #html() - */ - public String outerHtml() { - StringBuilder sb = new StringBuilder(); - for (Element element : contents) { - if (sb.length() != 0) - sb.append("\n"); - sb.append(element.outerHtml()); - } - return sb.toString(); - } - - /** - * Get the combined outer HTML of all matched elements. Alias of {@link #outerHtml()}. - * @return string of all element's outer HTML. - * @see #text() - * @see #html() - */ - public String toString() { - return outerHtml(); - } - - /** - * Update the tag name of each matched element. For example, to change each {@code <i>} to a {@code <em>}, do - * {@code doc.select("i").tagName("em");} - * @param tagName the new tag name - * @return this, for chaining - * @see Element#tagName(String) - */ - public Elements tagName(String tagName) { - for (Element element : contents) { - element.tagName(tagName); - } - return this; - } - - /** - * Set the inner HTML of each matched element. - * @param html HTML to parse and set into each matched element. - * @return this, for chaining - * @see Element#html(String) - */ - public Elements html(String html) { - for (Element element : contents) { - element.html(html); - } - return this; - } - - /** - * Add the supplied HTML to the start of each matched element's inner HTML. - * @param html HTML to add inside each element, before the existing HTML - * @return this, for chaining - * @see Element#prepend(String) - */ - public Elements prepend(String html) { - for (Element element : contents) { - element.prepend(html); - } - return this; - } - - /** - * Add the supplied HTML to the end of each matched element's inner HTML. - * @param html HTML to add inside each element, after the existing HTML - * @return this, for chaining - * @see Element#append(String) - */ - public Elements append(String html) { - for (Element element : contents) { - element.append(html); - } - return this; - } - - /** - * Insert the supplied HTML before each matched element's outer HTML. - * @param html HTML to insert before each element - * @return this, for chaining - * @see Element#before(String) - */ - public Elements before(String html) { - for (Element element : contents) { - element.before(html); - } - return this; - } - - /** - * Insert the supplied HTML after each matched element's outer HTML. - * @param html HTML to insert after each element - * @return this, for chaining - * @see Element#after(String) - */ - public Elements after(String html) { - for (Element element : contents) { - element.after(html); - } - return this; - } - - /** - Wrap the supplied HTML around each matched elements. For example, with HTML - {@code <p><b>This</b> is <b>Jsoup</b></p>}, - <code>doc.select("b").wrap("<i></i>");</code> - becomes {@code <p><i><b>This</b></i> is <i><b>jsoup</b></i></p>} - @param html HTML to wrap around each element, e.g. {@code <div class="head"></div>}. Can be arbitrarily deep. - @return this (for chaining) - @see Element#wrap - */ - public Elements wrap(String html) { - Validate.notEmpty(html); - for (Element element : contents) { - element.wrap(html); - } - return this; - } - - /** - * Removes the matched elements from the DOM, and moves their children up into their parents. This has the effect of - * dropping the elements but keeping their children. - * <p/> - * This is useful for e.g removing unwanted formatting elements but keeping their contents. - * <p/> - * E.g. with HTML: {@code <div><font>One</font> <font><a href="/">Two</a></font></div>}<br/> - * {@code doc.select("font").unwrap();}<br/> - * HTML = {@code <div>One <a href="/">Two</a></div>} - * - * @return this (for chaining) - * @see Node#unwrap - */ - public Elements unwrap() { - for (Element element : contents) { - element.unwrap(); - } - return this; - } - - /** - * Empty (remove all child nodes from) each matched element. This is similar to setting the inner HTML of each - * element to nothing. - * <p> - * E.g. HTML: {@code <div><p>Hello <b>there</b></p> <p>now</p></div>}<br> - * <code>doc.select("p").empty();</code><br> - * HTML = {@code <div><p></p> <p></p></div>} - * @return this, for chaining - * @see Element#empty() - * @see #remove() - */ - public Elements empty() { - for (Element element : contents) { - element.empty(); - } - return this; - } - - /** - * Remove each matched element from the DOM. This is similar to setting the outer HTML of each element to nothing. - * <p> - * E.g. HTML: {@code <div><p>Hello</p> <p>there</p> <img /></div>}<br> - * <code>doc.select("p").remove();</code><br> - * HTML = {@code <div> <img /></div>} - * <p> - * Note that this method should not be used to clean user-submitted HTML; rather, use {@link org.jsoup.safety.Cleaner} to clean HTML. - * @return this, for chaining - * @see Element#empty() - * @see #empty() - */ - public Elements remove() { - for (Element element : contents) { - element.remove(); - } - return this; - } - - // filters - - /** - * Find matching elements within this element list. - * @param query A {@link Selector} query - * @return the filtered list of elements, or an empty list if none match. - */ - public Elements select(String query) { - return Selector.select(query, this); - } - - /** - * Remove elements from this list that match the {@link Selector} query. - * <p> - * E.g. HTML: {@code <div class=logo>One</div> <div>Two</div>}<br> - * <code>Elements divs = doc.select("div").not("#logo");</code><br> - * Result: {@code divs: [<div>Two</div>]} - * <p> - * @param query the selector query whose results should be removed from these elements - * @return a new elements list that contains only the filtered results - */ - public Elements not(String query) { - Elements out = Selector.select(query, this); - return Selector.filterOut(this, out); - } - - /** - * Get the <i>nth</i> matched element as an Elements object. - * <p> - * See also {@link #get(int)} to retrieve an Element. - * @param index the (zero-based) index of the element in the list to retain - * @return Elements containing only the specified element, or, if that element did not exist, an empty list. - */ - public Elements eq(int index) { - return contents.size() > index ? new Elements(get(index)) : new Elements(); - } - - /** - * Test if any of the matched elements match the supplied query. - * @param query A selector - * @return true if at least one element in the list matches the query. - */ - public boolean is(String query) { - Elements children = select(query); - return !children.isEmpty(); - } - - /** - * Get all of the parents and ancestor elements of the matched elements. - * @return all of the parents and ancestor elements of the matched elements - */ - public Elements parents() { - HashSet<Element> combo = new LinkedHashSet<Element>(); - for (Element e: contents) { - combo.addAll(e.parents()); - } - return new Elements(combo); - } - - // list-like methods - /** - Get the first matched element. - @return The first matched element, or <code>null</code> if contents is empty; - */ - public Element first() { - return contents.isEmpty() ? null : contents.get(0); - } - - /** - Get the last matched element. - @return The last matched element, or <code>null</code> if contents is empty. - */ - public Element last() { - return contents.isEmpty() ? null : contents.get(contents.size() - 1); - } - - /** - * Perform a depth-first traversal on each of the selected elements. - * @param nodeVisitor the visitor callbacks to perform on each node - * @return this, for chaining - */ - public Elements traverse(NodeVisitor nodeVisitor) { - Validate.notNull(nodeVisitor); - NodeTraversor traversor = new NodeTraversor(nodeVisitor); - for (Element el: contents) { - traversor.traverse(el); - } - return this; - } - - // implements List<Element> delegates: - public int size() {return contents.size();} - - public boolean isEmpty() {return contents.isEmpty();} - - public boolean contains(Object o) {return contents.contains(o);} - - public Iterator<Element> iterator() {return contents.iterator();} - - public Object[] toArray() {return contents.toArray();} - - public <T> T[] toArray(T[] a) {return contents.toArray(a);} - - public boolean add(Element element) {return contents.add(element);} - - public boolean remove(Object o) {return contents.remove(o);} - - public boolean containsAll(Collection<?> c) {return contents.containsAll(c);} - - public boolean addAll(Collection<? extends Element> c) {return contents.addAll(c);} - - public boolean addAll(int index, Collection<? extends Element> c) {return contents.addAll(index, c);} - - public boolean removeAll(Collection<?> c) {return contents.removeAll(c);} - - public boolean retainAll(Collection<?> c) {return contents.retainAll(c);} - - public void clear() {contents.clear();} - - public boolean equals(Object o) {return contents.equals(o);} - - public int hashCode() {return contents.hashCode();} - - public Element get(int index) {return contents.get(index);} - - public Element set(int index, Element element) {return contents.set(index, element);} - - public void add(int index, Element element) {contents.add(index, element);} - - public Element remove(int index) {return contents.remove(index);} - - public int indexOf(Object o) {return contents.indexOf(o);} - - public int lastIndexOf(Object o) {return contents.lastIndexOf(o);} - - public ListIterator<Element> listIterator() {return contents.listIterator();} - - public ListIterator<Element> listIterator(int index) {return contents.listIterator(index);} - - public List<Element> subList(int fromIndex, int toIndex) {return contents.subList(fromIndex, toIndex);} -} diff --git a/src/org/jsoup/select/Evaluator.java b/src/org/jsoup/select/Evaluator.java deleted file mode 100644 index 16a083bd77..0000000000 --- a/src/org/jsoup/select/Evaluator.java +++ /dev/null @@ -1,454 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Element; - -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -/** - * Evaluates that an element matches the selector. - */ -public abstract class Evaluator { - protected Evaluator() { - } - - /** - * Test if the element meets the evaluator's requirements. - * - * @param root Root of the matching subtree - * @param element tested element - */ - public abstract boolean matches(Element root, Element element); - - /** - * Evaluator for tag name - */ - public static final class Tag extends Evaluator { - private String tagName; - - public Tag(String tagName) { - this.tagName = tagName; - } - - @Override - public boolean matches(Element root, Element element) { - return (element.tagName().equals(tagName)); - } - - @Override - public String toString() { - return String.format("%s", tagName); - } - } - - /** - * Evaluator for element id - */ - public static final class Id extends Evaluator { - private String id; - - public Id(String id) { - this.id = id; - } - - @Override - public boolean matches(Element root, Element element) { - return (id.equals(element.id())); - } - - @Override - public String toString() { - return String.format("#%s", id); - } - - } - - /** - * Evaluator for element class - */ - public static final class Class extends Evaluator { - private String className; - - public Class(String className) { - this.className = className; - } - - @Override - public boolean matches(Element root, Element element) { - return (element.hasClass(className)); - } - - @Override - public String toString() { - return String.format(".%s", className); - } - - } - - /** - * Evaluator for attribute name matching - */ - public static final class Attribute extends Evaluator { - private String key; - - public Attribute(String key) { - this.key = key; - } - - @Override - public boolean matches(Element root, Element element) { - return element.hasAttr(key); - } - - @Override - public String toString() { - return String.format("[%s]", key); - } - - } - - /** - * Evaluator for attribute name prefix matching - */ - public static final class AttributeStarting extends Evaluator { - private String keyPrefix; - - public AttributeStarting(String keyPrefix) { - this.keyPrefix = keyPrefix; - } - - @Override - public boolean matches(Element root, Element element) { - List<org.jsoup.nodes.Attribute> values = element.attributes().asList(); - for (org.jsoup.nodes.Attribute attribute : values) { - if (attribute.getKey().startsWith(keyPrefix)) - return true; - } - return false; - } - - @Override - public String toString() { - return String.format("[^%s]", keyPrefix); - } - - } - - /** - * Evaluator for attribute name/value matching - */ - public static final class AttributeWithValue extends AttributeKeyPair { - public AttributeWithValue(String key, String value) { - super(key, value); - } - - @Override - public boolean matches(Element root, Element element) { - return element.hasAttr(key) && value.equalsIgnoreCase(element.attr(key)); - } - - @Override - public String toString() { - return String.format("[%s=%s]", key, value); - } - - } - - /** - * Evaluator for attribute name != value matching - */ - public static final class AttributeWithValueNot extends AttributeKeyPair { - public AttributeWithValueNot(String key, String value) { - super(key, value); - } - - @Override - public boolean matches(Element root, Element element) { - return !value.equalsIgnoreCase(element.attr(key)); - } - - @Override - public String toString() { - return String.format("[%s!=%s]", key, value); - } - - } - - /** - * Evaluator for attribute name/value matching (value prefix) - */ - public static final class AttributeWithValueStarting extends AttributeKeyPair { - public AttributeWithValueStarting(String key, String value) { - super(key, value); - } - - @Override - public boolean matches(Element root, Element element) { - return element.hasAttr(key) && element.attr(key).toLowerCase().startsWith(value); // value is lower case already - } - - @Override - public String toString() { - return String.format("[%s^=%s]", key, value); - } - - } - - /** - * Evaluator for attribute name/value matching (value ending) - */ - public static final class AttributeWithValueEnding extends AttributeKeyPair { - public AttributeWithValueEnding(String key, String value) { - super(key, value); - } - - @Override - public boolean matches(Element root, Element element) { - return element.hasAttr(key) && element.attr(key).toLowerCase().endsWith(value); // value is lower case - } - - @Override - public String toString() { - return String.format("[%s$=%s]", key, value); - } - - } - - /** - * Evaluator for attribute name/value matching (value containing) - */ - public static final class AttributeWithValueContaining extends AttributeKeyPair { - public AttributeWithValueContaining(String key, String value) { - super(key, value); - } - - @Override - public boolean matches(Element root, Element element) { - return element.hasAttr(key) && element.attr(key).toLowerCase().contains(value); // value is lower case - } - - @Override - public String toString() { - return String.format("[%s*=%s]", key, value); - } - - } - - /** - * Evaluator for attribute name/value matching (value regex matching) - */ - public static final class AttributeWithValueMatching extends Evaluator { - String key; - Pattern pattern; - - public AttributeWithValueMatching(String key, Pattern pattern) { - this.key = key.trim().toLowerCase(); - this.pattern = pattern; - } - - @Override - public boolean matches(Element root, Element element) { - return element.hasAttr(key) && pattern.matcher(element.attr(key)).find(); - } - - @Override - public String toString() { - return String.format("[%s~=%s]", key, pattern.toString()); - } - - } - - /** - * Abstract evaluator for attribute name/value matching - */ - public abstract static class AttributeKeyPair extends Evaluator { - String key; - String value; - - public AttributeKeyPair(String key, String value) { - Validate.notEmpty(key); - Validate.notEmpty(value); - - this.key = key.trim().toLowerCase(); - this.value = value.trim().toLowerCase(); - } - } - - /** - * Evaluator for any / all element matching - */ - public static final class AllElements extends Evaluator { - - @Override - public boolean matches(Element root, Element element) { - return true; - } - - @Override - public String toString() { - return "*"; - } - } - - /** - * Evaluator for matching by sibling index number (e < idx) - */ - public static final class IndexLessThan extends IndexEvaluator { - public IndexLessThan(int index) { - super(index); - } - - @Override - public boolean matches(Element root, Element element) { - return element.elementSiblingIndex() < index; - } - - @Override - public String toString() { - return String.format(":lt(%d)", index); - } - - } - - /** - * Evaluator for matching by sibling index number (e > idx) - */ - public static final class IndexGreaterThan extends IndexEvaluator { - public IndexGreaterThan(int index) { - super(index); - } - - @Override - public boolean matches(Element root, Element element) { - return element.elementSiblingIndex() > index; - } - - @Override - public String toString() { - return String.format(":gt(%d)", index); - } - - } - - /** - * Evaluator for matching by sibling index number (e = idx) - */ - public static final class IndexEquals extends IndexEvaluator { - public IndexEquals(int index) { - super(index); - } - - @Override - public boolean matches(Element root, Element element) { - return element.elementSiblingIndex() == index; - } - - @Override - public String toString() { - return String.format(":eq(%d)", index); - } - - } - - /** - * Abstract evaluator for sibling index matching - * - * @author ant - */ - public abstract static class IndexEvaluator extends Evaluator { - int index; - - public IndexEvaluator(int index) { - this.index = index; - } - } - - /** - * Evaluator for matching Element (and its descendants) text - */ - public static final class ContainsText extends Evaluator { - private String searchText; - - public ContainsText(String searchText) { - this.searchText = searchText.toLowerCase(); - } - - @Override - public boolean matches(Element root, Element element) { - return (element.text().toLowerCase().contains(searchText)); - } - - @Override - public String toString() { - return String.format(":contains(%s", searchText); - } - } - - /** - * Evaluator for matching Element's own text - */ - public static final class ContainsOwnText extends Evaluator { - private String searchText; - - public ContainsOwnText(String searchText) { - this.searchText = searchText.toLowerCase(); - } - - @Override - public boolean matches(Element root, Element element) { - return (element.ownText().toLowerCase().contains(searchText)); - } - - @Override - public String toString() { - return String.format(":containsOwn(%s", searchText); - } - } - - /** - * Evaluator for matching Element (and its descendants) text with regex - */ - public static final class Matches extends Evaluator { - private Pattern pattern; - - public Matches(Pattern pattern) { - this.pattern = pattern; - } - - @Override - public boolean matches(Element root, Element element) { - Matcher m = pattern.matcher(element.text()); - return m.find(); - } - - @Override - public String toString() { - return String.format(":matches(%s", pattern); - } - } - - /** - * Evaluator for matching Element's own text with regex - */ - public static final class MatchesOwn extends Evaluator { - private Pattern pattern; - - public MatchesOwn(Pattern pattern) { - this.pattern = pattern; - } - - @Override - public boolean matches(Element root, Element element) { - Matcher m = pattern.matcher(element.ownText()); - return m.find(); - } - - @Override - public String toString() { - return String.format(":matchesOwn(%s", pattern); - } - } -} diff --git a/src/org/jsoup/select/NodeTraversor.java b/src/org/jsoup/select/NodeTraversor.java deleted file mode 100644 index 9bb081e56c..0000000000 --- a/src/org/jsoup/select/NodeTraversor.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Node; - -/** - * Depth-first node traversor. Use to iterate through all nodes under and including the specified root node. - * <p/> - * This implementation does not use recursion, so a deep DOM does not risk blowing the stack. - */ -public class NodeTraversor { - private NodeVisitor visitor; - - /** - * Create a new traversor. - * @param visitor a class implementing the {@link NodeVisitor} interface, to be called when visiting each node. - */ - public NodeTraversor(NodeVisitor visitor) { - this.visitor = visitor; - } - - /** - * Start a depth-first traverse of the root and all of its descendants. - * @param root the root node point to traverse. - */ - public void traverse(Node root) { - Node node = root; - int depth = 0; - - while (node != null) { - visitor.head(node, depth); - if (node.childNodes().size() > 0) { - node = node.childNode(0); - depth++; - } else { - while (node.nextSibling() == null && depth > 0) { - visitor.tail(node, depth); - node = node.parent(); - depth--; - } - visitor.tail(node, depth); - if (node == root) - break; - node = node.nextSibling(); - } - } - } -} diff --git a/src/org/jsoup/select/NodeVisitor.java b/src/org/jsoup/select/NodeVisitor.java deleted file mode 100644 index 20112e8d29..0000000000 --- a/src/org/jsoup/select/NodeVisitor.java +++ /dev/null @@ -1,30 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Node; - -/** - * Node visitor interface. Provide an implementing class to {@link NodeTraversor} to iterate through nodes. - * <p/> - * This interface provides two methods, {@code head} and {@code tail}. The head method is called when the node is first - * seen, and the tail method when all of the node's children have been visited. As an example, head can be used to - * create a start tag for a node, and tail to create the end tag. - */ -public interface NodeVisitor { - /** - * Callback for when a node is first visited. - * - * @param node the node being visited. - * @param depth the depth of the node, relative to the root node. E.g., the root node has depth 0, and a child node - * of that will have depth 1. - */ - public void head(Node node, int depth); - - /** - * Callback for when a node is last visited, after all of its descendants have been visited. - * - * @param node the node being visited. - * @param depth the depth of the node, relative to the root node. E.g., the root node has depth 0, and a child node - * of that will have depth 1. - */ - public void tail(Node node, int depth); -} diff --git a/src/org/jsoup/select/QueryParser.java b/src/org/jsoup/select/QueryParser.java deleted file mode 100644 index d3cc36f91c..0000000000 --- a/src/org/jsoup/select/QueryParser.java +++ /dev/null @@ -1,293 +0,0 @@ -package org.jsoup.select; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import org.jsoup.helper.StringUtil; -import org.jsoup.helper.Validate; -import org.jsoup.parser.TokenQueue; - -/** - * Parses a CSS selector into an Evaluator tree. - */ -class QueryParser { - private final static String[] combinators = {",", ">", "+", "~", " "}; - - private TokenQueue tq; - private String query; - private List<Evaluator> evals = new ArrayList<Evaluator>(); - - /** - * Create a new QueryParser. - * @param query CSS query - */ - private QueryParser(String query) { - this.query = query; - this.tq = new TokenQueue(query); - } - - /** - * Parse a CSS query into an Evaluator. - * @param query CSS query - * @return Evaluator - */ - public static Evaluator parse(String query) { - QueryParser p = new QueryParser(query); - return p.parse(); - } - - /** - * Parse the query - * @return Evaluator - */ - Evaluator parse() { - tq.consumeWhitespace(); - - if (tq.matchesAny(combinators)) { // if starts with a combinator, use root as elements - evals.add(new StructuralEvaluator.Root()); - combinator(tq.consume()); - } else { - findElements(); - } - - while (!tq.isEmpty()) { - // hierarchy and extras - boolean seenWhite = tq.consumeWhitespace(); - - if (tq.matchesAny(combinators)) { - combinator(tq.consume()); - } else if (seenWhite) { - combinator(' '); - } else { // E.class, E#id, E[attr] etc. AND - findElements(); // take next el, #. etc off queue - } - } - - if (evals.size() == 1) - return evals.get(0); - - return new CombiningEvaluator.And(evals); - } - - private void combinator(char combinator) { - tq.consumeWhitespace(); - String subQuery = consumeSubQuery(); // support multi > childs - - Evaluator rootEval; // the new topmost evaluator - Evaluator currentEval; // the evaluator the new eval will be combined to. could be root, or rightmost or. - Evaluator newEval = parse(subQuery); // the evaluator to add into target evaluator - boolean replaceRightMost = false; - - if (evals.size() == 1) { - rootEval = currentEval = evals.get(0); - // make sure OR (,) has precedence: - if (rootEval instanceof CombiningEvaluator.Or && combinator != ',') { - currentEval = ((CombiningEvaluator.Or) currentEval).rightMostEvaluator(); - replaceRightMost = true; - } - } - else { - rootEval = currentEval = new CombiningEvaluator.And(evals); - } - evals.clear(); - - // for most combinators: change the current eval into an AND of the current eval and the new eval - if (combinator == '>') - currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.ImmediateParent(currentEval)); - else if (combinator == ' ') - currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.Parent(currentEval)); - else if (combinator == '+') - currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.ImmediatePreviousSibling(currentEval)); - else if (combinator == '~') - currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.PreviousSibling(currentEval)); - else if (combinator == ',') { // group or. - CombiningEvaluator.Or or; - if (currentEval instanceof CombiningEvaluator.Or) { - or = (CombiningEvaluator.Or) currentEval; - or.add(newEval); - } else { - or = new CombiningEvaluator.Or(); - or.add(currentEval); - or.add(newEval); - } - currentEval = or; - } - else - throw new Selector.SelectorParseException("Unknown combinator: " + combinator); - - if (replaceRightMost) - ((CombiningEvaluator.Or) rootEval).replaceRightMostEvaluator(currentEval); - else rootEval = currentEval; - evals.add(rootEval); - } - - private String consumeSubQuery() { - StringBuilder sq = new StringBuilder(); - while (!tq.isEmpty()) { - if (tq.matches("(")) - sq.append("(").append(tq.chompBalanced('(', ')')).append(")"); - else if (tq.matches("[")) - sq.append("[").append(tq.chompBalanced('[', ']')).append("]"); - else if (tq.matchesAny(combinators)) - break; - else - sq.append(tq.consume()); - } - return sq.toString(); - } - - private void findElements() { - if (tq.matchChomp("#")) - byId(); - else if (tq.matchChomp(".")) - byClass(); - else if (tq.matchesWord()) - byTag(); - else if (tq.matches("[")) - byAttribute(); - else if (tq.matchChomp("*")) - allElements(); - else if (tq.matchChomp(":lt(")) - indexLessThan(); - else if (tq.matchChomp(":gt(")) - indexGreaterThan(); - else if (tq.matchChomp(":eq(")) - indexEquals(); - else if (tq.matches(":has(")) - has(); - else if (tq.matches(":contains(")) - contains(false); - else if (tq.matches(":containsOwn(")) - contains(true); - else if (tq.matches(":matches(")) - matches(false); - else if (tq.matches(":matchesOwn(")) - matches(true); - else if (tq.matches(":not(")) - not(); - else // unhandled - throw new Selector.SelectorParseException("Could not parse query '%s': unexpected token at '%s'", query, tq.remainder()); - - } - - private void byId() { - String id = tq.consumeCssIdentifier(); - Validate.notEmpty(id); - evals.add(new Evaluator.Id(id)); - } - - private void byClass() { - String className = tq.consumeCssIdentifier(); - Validate.notEmpty(className); - evals.add(new Evaluator.Class(className.trim().toLowerCase())); - } - - private void byTag() { - String tagName = tq.consumeElementSelector(); - Validate.notEmpty(tagName); - - // namespaces: if element name is "abc:def", selector must be "abc|def", so flip: - if (tagName.contains("|")) - tagName = tagName.replace("|", ":"); - - evals.add(new Evaluator.Tag(tagName.trim().toLowerCase())); - } - - private void byAttribute() { - TokenQueue cq = new TokenQueue(tq.chompBalanced('[', ']')); // content queue - String key = cq.consumeToAny("=", "!=", "^=", "$=", "*=", "~="); // eq, not, start, end, contain, match, (no val) - Validate.notEmpty(key); - cq.consumeWhitespace(); - - if (cq.isEmpty()) { - if (key.startsWith("^")) - evals.add(new Evaluator.AttributeStarting(key.substring(1))); - else - evals.add(new Evaluator.Attribute(key)); - } else { - if (cq.matchChomp("=")) - evals.add(new Evaluator.AttributeWithValue(key, cq.remainder())); - - else if (cq.matchChomp("!=")) - evals.add(new Evaluator.AttributeWithValueNot(key, cq.remainder())); - - else if (cq.matchChomp("^=")) - evals.add(new Evaluator.AttributeWithValueStarting(key, cq.remainder())); - - else if (cq.matchChomp("$=")) - evals.add(new Evaluator.AttributeWithValueEnding(key, cq.remainder())); - - else if (cq.matchChomp("*=")) - evals.add(new Evaluator.AttributeWithValueContaining(key, cq.remainder())); - - else if (cq.matchChomp("~=")) - evals.add(new Evaluator.AttributeWithValueMatching(key, Pattern.compile(cq.remainder()))); - else - throw new Selector.SelectorParseException("Could not parse attribute query '%s': unexpected token at '%s'", query, cq.remainder()); - } - } - - private void allElements() { - evals.add(new Evaluator.AllElements()); - } - - // pseudo selectors :lt, :gt, :eq - private void indexLessThan() { - evals.add(new Evaluator.IndexLessThan(consumeIndex())); - } - - private void indexGreaterThan() { - evals.add(new Evaluator.IndexGreaterThan(consumeIndex())); - } - - private void indexEquals() { - evals.add(new Evaluator.IndexEquals(consumeIndex())); - } - - private int consumeIndex() { - String indexS = tq.chompTo(")").trim(); - Validate.isTrue(StringUtil.isNumeric(indexS), "Index must be numeric"); - return Integer.parseInt(indexS); - } - - // pseudo selector :has(el) - private void has() { - tq.consume(":has"); - String subQuery = tq.chompBalanced('(', ')'); - Validate.notEmpty(subQuery, ":has(el) subselect must not be empty"); - evals.add(new StructuralEvaluator.Has(parse(subQuery))); - } - - // pseudo selector :contains(text), containsOwn(text) - private void contains(boolean own) { - tq.consume(own ? ":containsOwn" : ":contains"); - String searchText = TokenQueue.unescape(tq.chompBalanced('(', ')')); - Validate.notEmpty(searchText, ":contains(text) query must not be empty"); - if (own) - evals.add(new Evaluator.ContainsOwnText(searchText)); - else - evals.add(new Evaluator.ContainsText(searchText)); - } - - // :matches(regex), matchesOwn(regex) - private void matches(boolean own) { - tq.consume(own ? ":matchesOwn" : ":matches"); - String regex = tq.chompBalanced('(', ')'); // don't unescape, as regex bits will be escaped - Validate.notEmpty(regex, ":matches(regex) query must not be empty"); - - if (own) - evals.add(new Evaluator.MatchesOwn(Pattern.compile(regex))); - else - evals.add(new Evaluator.Matches(Pattern.compile(regex))); - } - - // :not(selector) - private void not() { - tq.consume(":not"); - String subQuery = tq.chompBalanced('(', ')'); - Validate.notEmpty(subQuery, ":not(selector) subselect must not be empty"); - - evals.add(new StructuralEvaluator.Not(parse(subQuery))); - } -} diff --git a/src/org/jsoup/select/Selector.java b/src/org/jsoup/select/Selector.java deleted file mode 100644 index 8fc6286798..0000000000 --- a/src/org/jsoup/select/Selector.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.helper.Validate; -import org.jsoup.nodes.Element; - -import java.util.Collection; -import java.util.LinkedHashSet; - -/** - * CSS-like element selector, that finds elements matching a query. - * <p/> - * <h2>Selector syntax</h2> - * A selector is a chain of simple selectors, separated by combinators. Selectors are case insensitive (including against - * elements, attributes, and attribute values). - * <p/> - * The universal selector (*) is implicit when no element selector is supplied (i.e. {@code *.header} and {@code .header} - * is equivalent). - * <p/> - * <table> - * <tr><th>Pattern</th><th>Matches</th><th>Example</th></tr> - * <tr><td><code>*</code></td><td>any element</td><td><code>*</code></td></tr> - * <tr><td><code>tag</code></td><td>elements with the given tag name</td><td><code>div</code></td></tr> - * <tr><td><code>ns|E</code></td><td>elements of type E in the namespace <i>ns</i></td><td><code>fb|name</code> finds <code><fb:name></code> elements</td></tr> - * <tr><td><code>#id</code></td><td>elements with attribute ID of "id"</td><td><code>div#wrap</code>, <code>#logo</code></td></tr> - * <tr><td><code>.class</code></td><td>elements with a class name of "class"</td><td><code>div.left</code>, <code>.result</code></td></tr> - * <tr><td><code>[attr]</code></td><td>elements with an attribute named "attr" (with any value)</td><td><code>a[href]</code>, <code>[title]</code></td></tr> - * <tr><td><code>[^attrPrefix]</code></td><td>elements with an attribute name starting with "attrPrefix". Use to find elements with HTML5 datasets</td><td><code>[^data-]</code>, <code>div[^data-]</code></td></tr> - * <tr><td><code>[attr=val]</code></td><td>elements with an attribute named "attr", and value equal to "val"</td><td><code>img[width=500]</code>, <code>a[rel=nofollow]</code></td></tr> - * <tr><td><code>[attr^=valPrefix]</code></td><td>elements with an attribute named "attr", and value starting with "valPrefix"</td><td><code>a[href^=http:]</code></code></td></tr> - * <tr><td><code>[attr$=valSuffix]</code></td><td>elements with an attribute named "attr", and value ending with "valSuffix"</td><td><code>img[src$=.png]</code></td></tr> - * <tr><td><code>[attr*=valContaining]</code></td><td>elements with an attribute named "attr", and value containing "valContaining"</td><td><code>a[href*=/search/]</code></td></tr> - * <tr><td><code>[attr~=<em>regex</em>]</code></td><td>elements with an attribute named "attr", and value matching the regular expression</td><td><code>img[src~=(?i)\\.(png|jpe?g)]</code></td></tr> - * <tr><td></td><td>The above may be combined in any order</td><td><code>div.header[title]</code></td></tr> - * <tr><td><td colspan="3"><h3>Combinators</h3></td></tr> - * <tr><td><code>E F</code></td><td>an F element descended from an E element</td><td><code>div a</code>, <code>.logo h1</code></td></tr> - * <tr><td><code>E > F</code></td><td>an F direct child of E</td><td><code>ol > li</code></td></tr> - * <tr><td><code>E + F</code></td><td>an F element immediately preceded by sibling E</td><td><code>li + li</code>, <code>div.head + div</code></td></tr> - * <tr><td><code>E ~ F</code></td><td>an F element preceded by sibling E</td><td><code>h1 ~ p</code></td></tr> - * <tr><td><code>E, F, G</code></td><td>all matching elements E, F, or G</td><td><code>a[href], div, h3</code></td></tr> - * <tr><td><td colspan="3"><h3>Pseudo selectors</h3></td></tr> - * <tr><td><code>:lt(<em>n</em>)</code></td><td>elements whose sibling index is less than <em>n</em></td><td><code>td:lt(3)</code> finds the first 2 cells of each row</td></tr> - * <tr><td><code>:gt(<em>n</em>)</code></td><td>elements whose sibling index is greater than <em>n</em></td><td><code>td:gt(1)</code> finds cells after skipping the first two</td></tr> - * <tr><td><code>:eq(<em>n</em>)</code></td><td>elements whose sibling index is equal to <em>n</em></td><td><code>td:eq(0)</code> finds the first cell of each row</td></tr> - * <tr><td><code>:has(<em>selector</em>)</code></td><td>elements that contains at least one element matching the <em>selector</em></td><td><code>div:has(p)</code> finds divs that contain p elements </td></tr> - * <tr><td><code>:not(<em>selector</em>)</code></td><td>elements that do not match the <em>selector</em>. See also {@link Elements#not(String)}</td><td><code>div:not(.logo)</code> finds all divs that do not have the "logo" class.<br /><code>div:not(:has(div))</code> finds divs that do not contain divs.</code></td></tr> - * <tr><td><code>:contains(<em>text</em>)</code></td><td>elements that contains the specified text. The search is case insensitive. The text may appear in the found element, or any of its descendants.</td><td><code>p:contains(jsoup)</code> finds p elements containing the text "jsoup".</td></tr> - * <tr><td><code>:matches(<em>regex</em>)</code></td><td>elements whose text matches the specified regular expression. The text may appear in the found element, or any of its descendants.</td><td><code>td:matches(\\d+)</code> finds table cells containing digits. <code>div:matches((?i)login)</code> finds divs containing the text, case insensitively.</td></tr> - * <tr><td><code>:containsOwn(<em>text</em>)</code></td><td>elements that directly contains the specified text. The search is case insensitive. The text must appear in the found element, not any of its descendants.</td><td><code>p:containsOwn(jsoup)</code> finds p elements with own text "jsoup".</td></tr> - * <tr><td><code>:matchesOwn(<em>regex</em>)</code></td><td>elements whose own text matches the specified regular expression. The text must appear in the found element, not any of its descendants.</td><td><code>td:matchesOwn(\\d+)</code> finds table cells directly containing digits. <code>div:matchesOwn((?i)login)</code> finds divs containing the text, case insensitively.</td></tr> - * <tr><td></td><td>The above may be combined in any order and with other selectors</td><td><code>.light:contains(name):eq(0)</code></td></tr> - * </table> - * - * @author Jonathan Hedley, jonathan@hedley.net - * @see Element#select(String) - */ -public class Selector { - private final Evaluator evaluator; - private final Element root; - - private Selector(String query, Element root) { - Validate.notNull(query); - query = query.trim(); - Validate.notEmpty(query); - Validate.notNull(root); - - this.evaluator = QueryParser.parse(query); - - this.root = root; - } - - /** - * Find elements matching selector. - * - * @param query CSS selector - * @param root root element to descend into - * @return matching elements, empty if not - */ - public static Elements select(String query, Element root) { - return new Selector(query, root).select(); - } - - /** - * Find elements matching selector. - * - * @param query CSS selector - * @param roots root elements to descend into - * @return matching elements, empty if not - */ - public static Elements select(String query, Iterable<Element> roots) { - Validate.notEmpty(query); - Validate.notNull(roots); - LinkedHashSet<Element> elements = new LinkedHashSet<Element>(); - - for (Element root : roots) { - elements.addAll(select(query, root)); - } - return new Elements(elements); - } - - private Elements select() { - return Collector.collect(evaluator, root); - } - - // exclude set. package open so that Elements can implement .not() selector. - static Elements filterOut(Collection<Element> elements, Collection<Element> outs) { - Elements output = new Elements(); - for (Element el : elements) { - boolean found = false; - for (Element out : outs) { - if (el.equals(out)) { - found = true; - break; - } - } - if (!found) - output.add(el); - } - return output; - } - - public static class SelectorParseException extends IllegalStateException { - public SelectorParseException(String msg, Object... params) { - super(String.format(msg, params)); - } - } -} diff --git a/src/org/jsoup/select/StructuralEvaluator.java b/src/org/jsoup/select/StructuralEvaluator.java deleted file mode 100644 index 69e8a62e58..0000000000 --- a/src/org/jsoup/select/StructuralEvaluator.java +++ /dev/null @@ -1,132 +0,0 @@ -package org.jsoup.select; - -import org.jsoup.nodes.Element; - -/** - * Base structural evaluator. - */ -abstract class StructuralEvaluator extends Evaluator { - Evaluator evaluator; - - static class Root extends Evaluator { - public boolean matches(Element root, Element element) { - return root == element; - } - } - - static class Has extends StructuralEvaluator { - public Has(Evaluator evaluator) { - this.evaluator = evaluator; - } - - public boolean matches(Element root, Element element) { - for (Element e : element.getAllElements()) { - if (e != element && evaluator.matches(root, e)) - return true; - } - return false; - } - - public String toString() { - return String.format(":has(%s)", evaluator); - } - } - - static class Not extends StructuralEvaluator { - public Not(Evaluator evaluator) { - this.evaluator = evaluator; - } - - public boolean matches(Element root, Element node) { - return !evaluator.matches(root, node); - } - - public String toString() { - return String.format(":not%s", evaluator); - } - } - - static class Parent extends StructuralEvaluator { - public Parent(Evaluator evaluator) { - this.evaluator = evaluator; - } - - public boolean matches(Element root, Element element) { - if (root == element) - return false; - - Element parent = element.parent(); - while (parent != root) { - if (evaluator.matches(root, parent)) - return true; - parent = parent.parent(); - } - return false; - } - - public String toString() { - return String.format(":parent%s", evaluator); - } - } - - static class ImmediateParent extends StructuralEvaluator { - public ImmediateParent(Evaluator evaluator) { - this.evaluator = evaluator; - } - - public boolean matches(Element root, Element element) { - if (root == element) - return false; - - Element parent = element.parent(); - return parent != null && evaluator.matches(root, parent); - } - - public String toString() { - return String.format(":ImmediateParent%s", evaluator); - } - } - - static class PreviousSibling extends StructuralEvaluator { - public PreviousSibling(Evaluator evaluator) { - this.evaluator = evaluator; - } - - public boolean matches(Element root, Element element) { - if (root == element) - return false; - - Element prev = element.previousElementSibling(); - - while (prev != null) { - if (evaluator.matches(root, prev)) - return true; - - prev = prev.previousElementSibling(); - } - return false; - } - - public String toString() { - return String.format(":prev*%s", evaluator); - } - } - - static class ImmediatePreviousSibling extends StructuralEvaluator { - public ImmediatePreviousSibling(Evaluator evaluator) { - this.evaluator = evaluator; - } - - public boolean matches(Element root, Element element) { - if (root == element) - return false; - - Element prev = element.previousElementSibling(); - return prev != null && evaluator.matches(root, prev); - } - - public String toString() { - return String.format(":prev%s", evaluator); - } - } -} diff --git a/src/org/jsoup/select/package-info.java b/src/org/jsoup/select/package-info.java deleted file mode 100644 index a6e6a2fa0f..0000000000 --- a/src/org/jsoup/select/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - Packages to support the CSS-style element selector. - */ -package org.jsoup.select;
\ No newline at end of file |