package org.jtheque.ui.utils.windows; import org.jtheque.core.Core; import org.jtheque.core.utils.OSGiUtils; import org.jtheque.errors.Error; import org.jtheque.errors.ErrorService; import org.jtheque.i18n.Internationalizable; import org.jtheque.i18n.LanguageService; import org.jtheque.images.ImageService; import org.jtheque.ui.Controller; import org.jtheque.ui.constraints.Constraint; import org.jtheque.utils.StringUtils; import org.jtheque.utils.collections.ArrayUtils; import org.jtheque.utils.collections.CollectionUtils; import org.jtheque.utils.ui.SwingUtils; import org.jdesktop.jxlayer.JXLayer; import org.jdesktop.jxlayer.plaf.ext.LockableUI; import org.osgi.framework.BundleContext; import org.springframework.context.ApplicationContext; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.SwingUtilities; import java.awt.Component; import java.awt.Cursor; import java.awt.Image; import java.awt.Window; import java.util.Collection; import java.util.Map; /* * Copyright JTheque (Baptiste Wicht) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * A Window state implementation. This state manage the state of Dialogs and Frames. * * @author Baptiste Wicht */ public final class WindowState implements org.jtheque.ui.WindowState { private String titleKey; private Object[] titleReplaces; private final Collection<Internationalizable> internationalizables = CollectionUtils.newList(); private final Map<Object, Constraint> constraintCache = CollectionUtils.newHashMap(5); private final Window window; private JXLayer<JComponent> content; private Controller<?> controller; private LockableUI waitUI; private BundleContext bundleContext; private ApplicationContext applicationContext; private boolean builded; /** * Construct a new WindowState. * * @param window The window to manage. */ public WindowState(Window window) { super(); this.window = window; } /** * Build the state. */ public void build() { content = new JXLayer<JComponent>(); window.setIconImage(getDefaultWindowIcon()); builded = true; } /** * Return the default icon for the window icon. * * @return The default icon. */ protected Image getDefaultWindowIcon() { return getService(ImageService.class).getImage(Core.WINDOW_ICON); } /** * Return the service of the given class. * * @param classz The class to get the service. * @param <T> The type of service. * * @return The service of the given class if it's exists otherwise null. */ protected <T> T getService(Class<T> classz) { return OSGiUtils.getService(bundleContext, classz); } @Override public void startWait() { installWaitUIIfNecessary(); content.setUI(waitUI); waitUI.setLocked(true); window.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); } @Override public void stopWait() { if (waitUI != null) { waitUI.setLocked(false); window.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); content.setUI(null); } } /** * Create the wait UI only if this has not been done before. */ private void installWaitUIIfNecessary() { if (waitUI == null) { waitUI = new BusyPainterUI(window); } } /** * Return the content pane of the view. * * @return The content pane of the view. */ public JXLayer<JComponent> getContent() { return content; } /** * Set a glass pane over the view. * * @param glassPane The glass pane to set over the view. */ public void setGlassPane(Component glassPane) { SwingUtils.inEdt(new GlassPaneSetter(glassPane)); } /** * Display the view. */ public void display() { if (!builded) { SwingUtils.inEdt(new Runnable() { @Override public void run() { ((ManagedWindow) window).build(); } }); } SwingUtils.inEdt(new Runnable() { @Override public void run() { window.setVisible(true); } }); } /** * Return the controller of the view. * * @return The controller of the view. */ public Controller<?> getController() { return controller; } /** * Set the controller of the view. * * @param controller The controller of the view. */ public void setController(Controller<?> controller) { this.controller = controller; } /** * Return the bundle context. * * @return The bundle context of the view. */ public BundleContext getBundleContext() { return bundleContext; } /** * Return the bundle context. * * @param bundleContext The bundle context. */ public void setBundleContext(BundleContext bundleContext) { this.bundleContext = bundleContext; } /** * Return the application context. * * @return The application context. */ public ApplicationContext getApplicationContext() { return applicationContext; } /** * Return the application context. * * @param applicationContext The application context. */ public void setApplicationContext(ApplicationContext applicationContext) { this.applicationContext = applicationContext; } /** * Add an internationalizable to the container. * * @param internationalizable The internationalizable to add. */ public void addInternationalizable(Internationalizable internationalizable) { internationalizables.add(internationalizable); } /** * Refresh the title of the window. * * @param languageService The language service to use for i18n. */ public void refreshText(LanguageService languageService) { if (StringUtils.isNotEmpty(titleKey)) { setTitleKey(titleKey, titleReplaces); } for (Internationalizable internationalizable : internationalizables) { internationalizable.refreshText(languageService); } } /** * Set the title key of the window. * * @param key The key of the title. * @param replaces The replaces of the title. */ public void setTitleKey(String key, Object... replaces) { titleKey = key; if (!ArrayUtils.isEmpty(replaces)) { titleReplaces = ArrayUtils.copyOf(replaces); } ((ManagedWindow) window).setTitle(getMessage(key, replaces)); } /** * Return the internationalized message. * * @param key The internationalization key. * * @return The internationalized message. */ protected String getMessage(String key) { return getService(LanguageService.class).getMessage(key); } /** * Return the internationalized message. * * @param key The internationalization key. * @param replaces The replacement objects to use. * * @return the internationalized message. */ protected String getMessage(String key, Object... replaces) { return getService(LanguageService.class).getMessage(key, replaces); } /** * Add a constraint to the view. * * @param field The field to validate. * @param constraint The constraint to add to the view. */ public void addConstraint(Object field, Constraint constraint) { constraintCache.put(field, constraint); constraint.configure(field); } /** * Validate the content of the view. * * @return true if the view content is valid else false. */ public boolean validateContent() { Collection<Error> errors = CollectionUtils.newList(5); ((ManagedWindow) window).validate(errors); ErrorService errorService = getService(ErrorService.class); for (Error error : errors) { errorService.addError(error); } return errors.isEmpty(); } /** * Validate the view using the setted constraints. * * @param errors The errors collection to fill. */ public void validate(Collection<Error> errors) { for (Map.Entry<Object, Constraint> constraint : constraintCache.entrySet()) { constraint.getValue().validate(constraint.getKey(), errors); } } /** * A simple runnable to apply a glass pane to the view associated with this state. * * @author Baptiste Wicht */ private final class GlassPaneSetter implements Runnable { private final Component glassPane; /** * Construct a new GlassPaneSetter for the given glass pane. * * @param glassPane The glass pane to set on the view. */ private GlassPaneSetter(Component glassPane) { this.glassPane = glassPane; } @Override public void run() { if (glassPane == null) { JPanel glasspane = content.createGlassPane(); glasspane.setVisible(false); glasspane.setOpaque(false); content.setGlassPane(glasspane); } else { content.setGlassPane((JPanel) glassPane); glassPane.setVisible(true); glassPane.repaint(); SwingUtilities.updateComponentTreeUI(glassPane); } SwingUtilities.updateComponentTreeUI(content); } } }