All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.miginfocom.swt.MigLayout Maven / Gradle / Ivy

There is a newer version: 3.7.4
Show newest version
package net.miginfocom.swt;
/*
 * License (BSD):
 * ==============
 *
 * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this list
 * of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or other
 * materials provided with the distribution.
 * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
 * used to endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * @version 1.0
 * @author Mikael Grev, MiG InfoCom AB
 *         Date: 2006-sep-08
 */

import net.miginfocom.layout.*;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Layout;

import java.io.*;
import java.lang.ref.WeakReference;
import java.util.*;

/** A very flexbile layout manager.
 * 

* Read the documentation that came with this layout manager for information on usage. */ public final class MigLayout extends Layout implements Externalizable { // ******** Instance part ******** /** The component to string constraints mappings. */ private final Map scrConstrMap = new IdentityHashMap(8); /** Hold the serializable text representation of the constraints. */ private Object layoutConstraints = "", colConstraints = "", rowConstraints = ""; // Should never be null! // ******** Transient part ******** private transient ContainerWrapper cacheParentW = null; private transient final Map ccMap = new HashMap(8); private transient LC lc = null; private transient AC colSpecs = null, rowSpecs = null; private transient Grid grid = null; private transient java.util.Timer debugTimer = null; private transient long curDelay = -1; private transient int lastModCount = PlatformDefaults.getModCount(); private transient int lastHash = -1; private transient ArrayList callbackList = null; /** Constructor with no constraints. */ public MigLayout() { this("", "", ""); } /** Constructor. * @param layoutConstraints The constraints that concern the whole layout. null will be treated as "". */ public MigLayout(String layoutConstraints) { this(layoutConstraints, "", ""); } /** Constructor. * @param layoutConstraints The constraints that concern the whole layout. null will be treated as "". * @param colConstraints The constraints for the columns in the grid. null will be treated as "". */ public MigLayout(String layoutConstraints, String colConstraints) { this(layoutConstraints, colConstraints, ""); } /** Constructor. * @param layoutConstraints The constraints that concern the whole layout. null will be treated as "". * @param colConstraints The constraints for the columns in the grid. null will be treated as "". * @param rowConstraints The constraints for the rows in the grid. null will be treated as "". */ public MigLayout(String layoutConstraints, String colConstraints, String rowConstraints) { setLayoutConstraints(layoutConstraints); setColumnConstraints(colConstraints); setRowConstraints(rowConstraints); } /** Constructor. * @param layoutConstraints The constraints that concern the whole layout. null will be treated as an empty cosntraint. */ public MigLayout(LC layoutConstraints) { this(layoutConstraints, null, null); } /** Constructor. * @param layoutConstraints The constraints that concern the whole layout. null will be treated as an empty cosntraint. * @param colConstraints The constraints for the columns in the grid. null will be treated as an empty constraint. */ public MigLayout(LC layoutConstraints, AC colConstraints) { this(layoutConstraints, colConstraints, null); } /** Constructor. * @param layoutConstraints The constraints that concern the whole layout. null will be treated as an empty cosntraint. * @param colConstraints The constraints for the columns in the grid. null will be treated as an empty constraint. * @param rowConstraints The constraints for the rows in the grid. null will be treated as an empty constraint. */ public MigLayout(LC layoutConstraints, AC colConstraints, AC rowConstraints) { setLayoutConstraints(layoutConstraints); setColumnConstraints(colConstraints); setRowConstraints(rowConstraints); } /** Returns layout constraints eighter as a String or {@link net.miginfocom.layout.LC} depending what was sent in * to the constructor or set with {@link #setLayoutConstraints(Object)}. * @return The layout constraints eighter as a String or {@link net.miginfocom.layout.LC} depending what was sent in * to the constructor or set with {@link #setLayoutConstraints(Object)}. Never null. */ public Object getLayoutConstraints() { return layoutConstraints; } /** Sets the layout constraints for the layout manager instance as a String. *

* See the class JavaDocs for information on how this string is formatted. * @param s The layout constraints as a String representation. null is converted to "" for storage. * @throws RuntimeException if the constaint was not valid. */ public void setLayoutConstraints(Object s) { if (s == null || s instanceof String) { s = ConstraintParser.prepare((String) s); lc = ConstraintParser.parseLayoutConstraint((String) s); } else if (s instanceof LC) { lc = (LC) s; } else { throw new IllegalArgumentException("Illegal constraint type: " + s.getClass().toString()); } layoutConstraints = s; grid = null; } /** Returns the column layout constraints either as a String or {@link net.miginfocom.layout.AC}. * @return The column constraints eighter as a String or {@link net.miginfocom.layout.LC} depending what was sent in * to the constructor or set with {@link #setLayoutConstraints(Object)}. Never null. */ public Object getColumnConstraints() { return colConstraints; } /** Sets the column layout constraints for the layout manager instance as a String. *

* See the class JavaDocs for information on how this string is formatted. * @param constr The column layout constraints as a String representation. null is converted to "" for storage. * @throws RuntimeException if the constaint was not valid. */ public void setColumnConstraints(Object constr) { if (constr == null || constr instanceof String) { constr = ConstraintParser.prepare((String) constr); colSpecs = ConstraintParser.parseColumnConstraints((String) constr); } else if (constr instanceof AC) { colSpecs = (AC) constr; } else { throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString()); } colConstraints = constr; grid = null; } /** Returns the row layout constraints as a String representation. This string is the exact string as set with {@link #setRowConstraints(Object)} * or sent into the constructor. *

* See the class JavaDocs for information on how this string is formatted. * @return The row layout constraints as a String representation. Never null. */ public Object getRowConstraints() { return rowConstraints; } /** Sets the row layout constraints for the layout manager instance as a String. *

* See the class JavaDocs for information on how this string is formatted. * @param constr The row layout constraints as a String representation. null is converted to "" for storage. * @throws RuntimeException if the constaint was not valid. */ public void setRowConstraints(Object constr) { if (constr == null || constr instanceof String) { constr = ConstraintParser.prepare((String) constr); rowSpecs = ConstraintParser.parseRowConstraints((String) constr); } else if (constr instanceof AC) { rowSpecs = (AC) constr; } else { throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString()); } rowConstraints = constr; grid = null; } /** Returns a shallow copy of the constraints map. * @return A shallow copy of the constraints map. Never null. */ public Map getConstraintMap() { return new IdentityHashMap(scrConstrMap); } /** Sets the constraints map. * @param map The map. Will be copied. */ public void setConstraintMap(Map map) { scrConstrMap.clear(); ccMap.clear(); for (Map.Entry e : map.entrySet()) setComponentConstraintsImpl(e.getKey(), e.getValue(), true); } /** Sets the component constraint for the component that already must be handleded by this layout manager. *

* See the class JavaDocs for information on how this string is formatted. * @param constr The component constraints as a String or {@link net.miginfocom.layout.CC}. null is ok. * @param comp The component to set the constraints for. * @param noCheck Doesn't check if control already is managed. * @throws RuntimeException if the constaint was not valid. * @throws IllegalArgumentException If the component is not handling the component. */ private void setComponentConstraintsImpl(Control comp, Object constr, boolean noCheck) { if (noCheck == false && scrConstrMap.containsKey(comp) == false) throw new IllegalArgumentException("Component must already be added to parent!"); ComponentWrapper cw = new SwtComponentWrapper(comp); if (constr == null || constr instanceof String) { String cStr = ConstraintParser.prepare((String) constr); scrConstrMap.put(comp, constr); ccMap.put(cw, ConstraintParser.parseComponentConstraint(cStr)); } else if (constr instanceof CC) { scrConstrMap.put(comp, constr); ccMap.put(cw, (CC) constr); } else { throw new IllegalArgumentException("Constraint must be String or ComponentConstraint: " + constr.getClass().toString()); } grid = null; } /** Returns if this layout manager is currently managing this component. * @param c The component to check. If null then false will be returned. * @return If this layout manager is currently managing this component. */ public boolean isManagingComponent(Control c) { return scrConstrMap.containsKey(c); } /** Adds the callback function that will be called at different stages of the layout cylce. * @param callback The callback. Not null. */ public void addLayoutCallback(LayoutCallback callback) { if (callback == null) throw new NullPointerException(); if (callbackList == null) callbackList = new ArrayList(1); callbackList.add(callback); } /** Removes the callback if it exists. * @param callback The callback. May be null. */ public void removeLayoutCallback(LayoutCallback callback) { if (callbackList != null) callbackList.remove(callback); } /** Sets the debugging state for this layout manager instance. If debug is turned on a timer will repaint the last laid out parent * with debug information on top. *

* Red fill and dashed darked red outline is used to indicate occupied cells in the grid. Blue dashed outline indicate indicate * component bounds set. *

* Note that debug can also be set on the layout constraints. There it will be persisted. The calue set here will not. See the class * JavaDocs for information. * @param parentW The parent. Never null. * @param b true means debug is turned on. */ private synchronized void setDebug(final ComponentWrapper parentW, boolean b) { if (b && (debugTimer == null || curDelay != getDebugMillis())) { if (debugTimer != null) debugTimer.cancel(); debugTimer = new Timer(true); curDelay = getDebugMillis(); debugTimer.schedule(new MyDebugRepaintTask(this), curDelay, curDelay); ContainerWrapper pCW = parentW.getParent(); Composite parent = pCW != null ? (Composite) pCW.getComponent() : null; if (parent != null) parent.layout(); } else if (!b && debugTimer != null) { debugTimer.cancel(); debugTimer = null; } } /** Returns the current debugging state. * @return The current debugging state. */ private boolean getDebug() { return debugTimer != null; } /** Returns the debug millis. Combines the value from {@link net.miginfocom.layout.LC#getDebugMillis()} and {@link net.miginfocom.layout.LayoutUtil#getGlobalDebugMillis()} * @return The combined value. */ private int getDebugMillis() { int globalDebugMillis = LayoutUtil.getGlobalDebugMillis(); return globalDebugMillis > 0 ? globalDebugMillis : lc.getDebugMillis(); } /** Check if something has changed and if so recrete it to the cached objects. * @param parent The parent that is the target for this layout manager. */ private final void checkCache(Composite parent) { if (parent == null) return; checkConstrMap(parent); ContainerWrapper par = checkParent(parent); // Check if the grid is valid int mc = PlatformDefaults.getModCount(); if (lastModCount != mc) { grid = null; lastModCount = mc; } int hash = parent.getSize().hashCode(); for (Iterator it = ccMap.keySet().iterator(); it.hasNext();) hash += it.next().getLayoutHashCode(); if (hash != lastHash) { grid = null; lastHash = hash; } setDebug(par, getDebugMillis() > 0); if (grid == null) grid = new Grid(par, lc, rowSpecs, colSpecs, ccMap, callbackList); } private boolean checkConstrMap(Composite parent) { Control[] comps = parent.getChildren(); boolean changed = comps.length != scrConstrMap.size(); if (changed == false) { for (int i = 0; i < comps.length; i++) { Control c = comps[i]; if (scrConstrMap.get(c) != c.getLayoutData()) { changed = true; break; } } } if (changed) { scrConstrMap.clear(); for (int i = 0; i < comps.length; i++) { Control c = comps[i]; setComponentConstraintsImpl(c, c.getLayoutData(), true); } } return changed; } private final ContainerWrapper checkParent(Composite parent) { if (parent == null) return null; if (cacheParentW == null || cacheParentW.getComponent() != parent) cacheParentW = new SwtContainerWrapper(parent); return cacheParentW; } public float getLayoutAlignmentX(Composite parent) { return lc != null && lc.getAlignX() != null ? lc.getAlignX().getPixels(1, checkParent(parent), null) : 0; } public float getLayoutAlignmentY(Composite parent) { return lc != null && lc.getAlignY() != null ? lc.getAlignY().getPixels(1, checkParent(parent), null) : 0; } protected Point computeSize(Composite parent, int wHint, int hHint, boolean flushCache) { checkCache(parent); int w = LayoutUtil.getSizeSafe(grid != null ? grid.getWidth() : null, LayoutUtil.PREF); int h = LayoutUtil.getSizeSafe(grid != null ? grid.getHeight() : null, LayoutUtil.PREF); return new Point(w, h); } protected void layout(Composite parent, boolean flushCache) { checkCache(parent); Rectangle r = parent.getClientArea(); int[] b = new int[] {r.x, r.y, r.width, r.height}; final boolean layoutAgain = grid.layout(b, lc.getAlignX(), lc.getAlignY(), getDebug(), true); if (layoutAgain) { grid = null; checkCache(parent); grid.layout(b, lc.getAlignX(), lc.getAlignY(), getDebug(), false); } } protected boolean flushCache(Control control) { // if (lc.isNoCache()) // Commented for 3.5 since there was too often that the "nocache" was needed and the user did not know. grid = null; return true; } // ************************************************ // Persistence Delegate and Serializable combined. // ************************************************ private Object readResolve() throws ObjectStreamException { return LayoutUtil.getSerializedObject(this); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in)); } public void writeExternal(ObjectOutput out) throws IOException { if (getClass() == MigLayout.class) LayoutUtil.writeAsXML(out, this); } private static class MyDebugRepaintTask extends TimerTask { private final WeakReference layoutRef; private MyDebugRepaintTask(MigLayout layout) { this.layoutRef = new WeakReference(layout); } public void run() { final MigLayout layout = layoutRef.get(); if (layout != null && layout.grid != null) { Display.getDefault ().asyncExec(new Runnable () { public void run () { if (layout.grid != null) layout.grid.paintDebug(); } }); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy