summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--prototypes/miglayout/gfx_tokenlibrary.pas180
-rw-r--r--prototypes/miglayout/gui_mig_boundsize.pas90
-rw-r--r--prototypes/miglayout/gui_mig_constraintparser.pas78
-rw-r--r--prototypes/miglayout/gui_mig_exceptions.pas18
-rw-r--r--prototypes/miglayout/gui_mig_lc.pas80
-rw-r--r--prototypes/miglayout/gui_mig_unitvalue.pas22
-rw-r--r--prototypes/miglayout/gui_miglayout.pas48
-rw-r--r--prototypes/miglayout/net/miginfocom/demo/CallbackDemo.java145
-rw-r--r--prototypes/miglayout/net/miginfocom/demo/HiDPISimulator.java495
-rw-r--r--prototypes/miglayout/net/miginfocom/demo/SwingDemo.java3668
-rw-r--r--prototypes/miglayout/net/miginfocom/demo/SwtDemo.java2100
-rw-r--r--prototypes/miglayout/net/miginfocom/examples/Example01.java43
-rw-r--r--prototypes/miglayout/net/miginfocom/examples/Example02.java53
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/AC.java493
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/BoundSize.java246
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/CC.java1543
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java258
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java1409
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java69
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/DimConstraint.java466
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/Grid.java2245
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/IDEUtil.java704
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java31
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LC.java717
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java48
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java532
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/LinkHandler.java182
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java675
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java92
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/UnitConverter.java59
-rw-r--r--prototypes/miglayout/net/miginfocom/layout/UnitValue.java626
-rw-r--r--prototypes/miglayout/net/miginfocom/swing/MigLayout.java549
-rw-r--r--prototypes/miglayout/net/miginfocom/swing/SwingComponentWrapper.java426
-rw-r--r--prototypes/miglayout/net/miginfocom/swing/SwingContainerWrapper.java108
-rw-r--r--prototypes/miglayout/net/miginfocom/swt/MigLayout.java506
-rw-r--r--prototypes/miglayout/net/miginfocom/swt/SwtComponentWrapper.java359
-rw-r--r--prototypes/miglayout/net/miginfocom/swt/SwtContainerWrapper.java112
-rw-r--r--prototypes/miglayout/readme.txt15
-rw-r--r--prototypes/miglayout/test.lpi82
-rw-r--r--prototypes/miglayout/test.lpr62
-rw-r--r--prototypes/miglayout/unittests/constraintparser_tests.pas142
-rw-r--r--prototypes/miglayout/unittests/fpcunit_miglayout.lpi69
-rw-r--r--prototypes/miglayout/unittests/fpcunit_miglayout.lpr25
43 files changed, 19870 insertions, 0 deletions
diff --git a/prototypes/miglayout/gfx_tokenlibrary.pas b/prototypes/miglayout/gfx_tokenlibrary.pas
new file mode 100644
index 00000000..8365b8b4
--- /dev/null
+++ b/prototypes/miglayout/gfx_tokenlibrary.pas
@@ -0,0 +1,180 @@
+{
+ Tokens Library.
+
+ Copyright (C) 1996, Earl F. Glynn. All Rights Reserved.
+ Converted from C++ Tokens unit, December 1996
+ Customized for the tiOPF2 by G.Geldenhuys, March 2007
+
+ Note:
+ The diagram explaining the Finite State Machine used for this parser
+ can be found at: Docs/diagrams/tiTokenLibrary_Diagram.png
+
+
+ Sample Usage:
+
+ FieldSpec := TTokens.Create(FieldSpecLine, ', ', '"', '"', '\', tsMultipleSeparatorsBetweenTokens);
+ try
+ FieldType := UpperCase(FieldSpec.Token(2));
+ finally
+ FieldSpec.Free;
+ end;
+}
+
+unit gfx_tokenlibrary;
+
+{$mode objfpc}{$H+}
+
+interface
+
+type
+ TTokenSeparator = (tsSingleSeparatorBetweenTokens,
+ tsMultipleSeparatorsBetweenTokens);
+
+ TTokens = class(TObject)
+ private
+ FOriginalString: string;
+ FCount: integer;
+ FTokenString: string; // Separator-stripped string with tokens separated by NULLs
+ public
+ constructor Create(const OriginalString: string; const Separators: string;
+ const LeftMark: char; const RightMark: char; const Escape: char;
+ const SeparatorBetweenTokens: TTokenSeparator = tsMultipleSeparatorsBetweenTokens); overload;
+ destructor Destroy; override;
+ function Token(const index: integer): string;
+ function TokenCount: integer;
+ end;
+
+
+implementation
+
+const
+ NULL = #$00;
+
+type
+ TFiniteStates = (fsSkipSeparatorsState,
+ fsAcceptSingleWordTokenState,
+ fsAcceptMultiWordTokenState,
+ fsEscapeState);
+
+constructor TTokens.Create(const OriginalString: string; const Separators: string;
+ const LeftMark: char; const RightMark: char; const Escape: char;
+ const SeparatorBetweenTokens: TTokenSeparator);
+var
+ c: char;
+ i: integer;
+ IgnoreNextSeparator: boolean;
+ state: TFiniteStates;
+begin
+ inherited Create;
+
+ FOriginalString := OriginalString;
+ FTokenString := '';
+ FCount := 0;
+
+ // The following "flag" is somewhat of a kludge to allow a single
+ // separator to follow the closing RightMark of a Multiword Token
+ // when SeparatorBetweenTokens = tsSingleSeparatorBetweenTokens
+ IgnoreNextSeparator := False;
+
+ // Initial state of finite state machine that recognizes tokens
+ state := fsSkipSeparatorsState;
+
+ for i := 1 to Length(FOriginalString) do
+ begin
+ c := FOriginalString[i];
+ case state of
+ fsSkipSeparatorsState:
+ // Do nothing if character is separator
+ if Pos(c, Separators) > 0 then
+ begin
+ // For cases like multiple comma-delimited fields, treat each
+ // separator as end of a token, e.g, "x,,,y" would be 4 tokens
+ if SeparatorBetweenTokens = tsSingleSeparatorBetweenTokens then
+ begin
+ if IgnoreNextSeparator then
+ IgnoreNextSeparator := False
+ else
+ begin
+ Inc(FCount);
+ FTokenString := FTokenString + NULL;
+ end;
+ end;
+ end
+ else if c = LeftMark then
+ begin
+ state := fsAcceptMultiWordTokenState;
+ Inc(FCount);
+ end
+ else
+ begin
+ state := fsAcceptSingleWordTokenState;
+ Inc(FCount);
+ FTokenString := FTokenString + c;
+ end;
+
+ fsAcceptSingleWordTokenState:
+ if Pos(c, Separators) = 0 then
+ FTokenString := FTokenString + c // not a separator
+ else
+ begin // separator
+ FTokenString := FTokenString + NULL;
+ state := fsSkipSeparatorsState;
+ end;
+
+ fsAcceptMultiWordTokenState:
+ if c = RightMark then
+ begin
+ FTokenString := FTokenString + NULL;
+ state := fsSkipSeparatorsState;
+ IgnoreNextSeparator := True;
+ end
+ else if c = Escape then
+ state := fsEscapeState
+ else
+ FTokenString := FTokenString + c;
+
+ fsEscapeState:
+ begin
+ FTokenString := FTokenString + c;
+ state := fsAcceptMultiWordTokenState;
+ end
+ end; { case }
+ end; { for }
+end;
+
+destructor TTokens.Destroy;
+begin
+ inherited Destroy;
+end;
+
+function TTokens.Token(const index: integer): string;
+var
+ c: char;
+ found: integer;
+ i: integer;
+begin
+ Result := '';
+ found := 1;
+ i := 1;
+
+ while (i <= length(FTokenString)) and (found <= index) do
+ begin
+ c := FTokenString[i];
+
+ if c = NULL then
+ Inc(found)
+ else if (found = index) then
+ Result := Result + c;
+
+ Inc(i);
+ end;
+end;
+
+function TTokens.TokenCount: integer;
+begin
+ Result := FCount;
+end;
+
+
+end.
+
diff --git a/prototypes/miglayout/gui_mig_boundsize.pas b/prototypes/miglayout/gui_mig_boundsize.pas
new file mode 100644
index 00000000..a77b6b80
--- /dev/null
+++ b/prototypes/miglayout/gui_mig_boundsize.pas
@@ -0,0 +1,90 @@
+unit gui_mig_boundsize;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, gui_mig_unitvalue;
+
+type
+
+ { TBoundSize }
+
+ TBoundSize = class(TObject)
+ private
+ FMin: TUnitValue;
+ FPref: TUnitValue;
+ FMax: TUnitValue;
+ FGapPush: Boolean;
+ public
+ constructor Create(AMinMaxPref: TUnitValue; ACreateString: string); // overloaded;
+ constructor Create(AMin: TUnitValue; APreferred: TUnitValue; AMax: TUnitValue; ACreateString: string); // overloaded;
+ constructor Create(AMin: TUnitValue; APreferred: TUnitValue; AMax: TUnitValue; AGapPush: Boolean; ACreateString: string); // overloaded;
+ function GetSize(const ASizeType: integer): TUnitValue;
+ function IsUnset: Boolean;
+ function GetConstraintString: string;
+ property Min: TUnitValue read FMin;
+ property Preferred: TUnitValue read FPref;
+ property Max: TUnitValue read FMax;
+ property GapPush: Boolean read FGapPush;
+ end;
+
+implementation
+
+uses
+ gui_mig_exceptions;
+
+
+{ TBoundSize }
+
+function TBoundSize.IsUnset: Boolean;
+begin
+ Result := (FMin = nil) and (FPref = nil) and (FMax = nil);
+end;
+
+function TBoundSize.GetConstraintString: string;
+begin
+ Result := 'null';
+ {$Note TBoundSize.GetConstraintString still needs to be implemented. }
+end;
+
+constructor TBoundSize.Create(AMinMaxPref: TUnitValue; ACreateString: string);
+begin
+ Create(AMinMaxPref, AMinMaxPref, AMinMaxPref, ACreateString);
+end;
+
+constructor TBoundSize.Create(AMin: TUnitValue; APreferred: TUnitValue;
+ AMax: TUnitValue; ACreateString: string);
+begin
+ Create(AMin, APreferred, AMax, False, ACreateString);
+end;
+
+constructor TBoundSize.Create(AMin: TUnitValue; APreferred: TUnitValue;
+ AMax: TUnitValue; AGapPush: Boolean; ACreateString: string);
+begin
+ inherited Create;
+ FMin := AMin;
+ FPref := APreferred;
+ FMax := AMax;
+ FGapPush := AGapPush;
+
+ {$Note TBoundSize.Create is incompleted, we still need to handle ACreateString. }
+end;
+
+function TBoundSize.GetSize(const ASizeType: integer): TUnitValue;
+begin
+ case ASizetype of
+ 0{MIN}:
+ result := FMin;
+ 1{PREF}:
+ result := FPref;
+ 2{MAX}:
+ result := FMax;
+ else
+ raise EIllegalArgument.CreateFmt('Unknown size: %d', [ASizeType]);
+ end;
+end;
+
+end.
+
diff --git a/prototypes/miglayout/gui_mig_constraintparser.pas b/prototypes/miglayout/gui_mig_constraintparser.pas
new file mode 100644
index 00000000..5f91c135
--- /dev/null
+++ b/prototypes/miglayout/gui_mig_constraintparser.pas
@@ -0,0 +1,78 @@
+unit gui_mig_constraintparser;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, gui_mig_lc;
+
+type
+ TConstraintParser = class(TObject)
+ public
+ function ParseLayoutConstraint(const s: string): TLC;
+ end;
+
+implementation
+
+uses
+ gfx_tokenlibrary;
+
+{ TConstraintParser }
+
+function TConstraintParser.ParseLayoutConstraint(const s: string): TLC;
+var
+ tokenizer: TTokens;
+ parts: TStringList;
+ part: string;
+ i: integer;
+ len: integer;
+begin
+ result := TLC.Create;
+
+ if s = '' then
+ Exit;
+
+ tokenizer := TTokens.Create(s, ',', '"', '"', '\', tsSingleSeparatorBetweenTokens);
+ parts := TStringList.Create;
+ for i := 1 to tokenizer.TokenCount do
+ parts.Add(trim(tokenizer.Token(i)));
+ tokenizer.Free;
+
+ // First check for "ltr" or "rtl" since that will affect the interpretation
+ // of the other constraints.
+ for i := 0 to parts.Count-1 do
+ begin
+ part := parts[i];
+ if part = '' then
+ continue;
+
+ len := Length(part);
+ if (len = 3) or (len = 11) then // optimization
+ begin
+ if (part = 'ltr') or (part = 'rtl') or (part = 'lefttoright') or (part = 'righttoleft') then
+ begin
+ result.LeftToRight := part[1] = 'l';
+ parts[i] := ''; // so we don't process it again
+ end;
+ if (part = 'ttb') or (part = 'btt') or (part = 'toptobottom') or (part = 'bottomtotop') then
+ begin
+ result.TopToBottom := part[1] = 't';
+ parts[i] := ''; // so we don't process it again
+ end;
+ end;
+ end;
+
+ for i := 0 to parts.Count-1 do
+ begin
+ part := parts[i];
+ if part = '' then
+ continue;
+
+ end;
+
+ parts.Free;
+end;
+
+end.
+
diff --git a/prototypes/miglayout/gui_mig_exceptions.pas b/prototypes/miglayout/gui_mig_exceptions.pas
new file mode 100644
index 00000000..259a8492
--- /dev/null
+++ b/prototypes/miglayout/gui_mig_exceptions.pas
@@ -0,0 +1,18 @@
+unit gui_mig_exceptions;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils;
+
+type
+
+ EIllegalArgument = class(Exception);
+
+
+implementation
+
+end.
+
diff --git a/prototypes/miglayout/gui_mig_lc.pas b/prototypes/miglayout/gui_mig_lc.pas
new file mode 100644
index 00000000..49316592
--- /dev/null
+++ b/prototypes/miglayout/gui_mig_lc.pas
@@ -0,0 +1,80 @@
+{
+ Layout Manager Constraint.
+}
+
+unit gui_mig_lc;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, gui_mig_unitvalue, gui_mig_boundsize, gui_mig_exceptions;
+
+type
+
+ { TLC }
+
+ TLC = class(TObject)
+ private
+ FDebugMillis: integer;
+ FFillX: Boolean;
+ FFillY: Boolean;
+ FFlowX: Boolean;
+ FGridGapX: TBoundSize;
+ FGridGapY: TBoundSize;
+ FHideMode: integer;
+ FNoCache: Boolean;
+ FAlignX: TUnitValue;
+ FAlignY: TUnitValue;
+ FLeftToRight: Boolean;
+ FTopToBottom: Boolean;
+ procedure SetHideMode(const AValue: integer);
+ public
+ constructor Create;
+ property NoCache: Boolean read FNoCache write FNoCache default False;
+ property AlignX: TUnitValue read FAlignX write FAlignX;
+ property AlignY: TUnitValue read FAlignY write FAlignY;
+ property DebugMillis: integer read FDebugMillis write FDebugMillis default 0;
+ property FillX: Boolean read FFillX write FFillX default False;
+ property FillY: Boolean read FFillY write FFillY default False;
+ property FlowX: Boolean read FFlowX write FFlowX default True;
+ property GridGapX: TBoundSize read FGridGapX write FGridGapX;
+ property GridGapY: TBoundSize read FGridGapY write FGridGapY;
+ property HideMode: integer read FHideMode write SetHideMode;
+ property LeftToRight: Boolean read FLeftToRight write FLeftToRight;
+ property TopToBottom: Boolean read FTopToBottom write FTopToBottom;
+ end;
+
+
+implementation
+
+{ TLC }
+
+procedure TLC.SetHideMode(const AValue: integer);
+begin
+ if FHideMode=AValue then exit;
+
+ if (AValue < 0) or (AValue > 3) then
+ raise EIllegalArgument.CreateFmt('Wrong HideMode: %d', [AValue]);
+
+ FHideMode:=AValue;
+end;
+
+constructor TLC.Create;
+begin
+ FNoCache := False;
+ FAlignX := nil;
+ FAlignY := nil;
+ FDebugMillis := 0;
+ FFillX := False;
+ FFillY := False;
+ FFlowX := True;
+ FGridGapX := nil;
+ FGridGapY := nil;
+ FLeftToRight := True;
+ FTopToBottom := True;
+end;
+
+end.
+
diff --git a/prototypes/miglayout/gui_mig_unitvalue.pas b/prototypes/miglayout/gui_mig_unitvalue.pas
new file mode 100644
index 00000000..44925357
--- /dev/null
+++ b/prototypes/miglayout/gui_mig_unitvalue.pas
@@ -0,0 +1,22 @@
+unit gui_mig_unitvalue;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils;
+
+type
+
+ TUnitValue = class(TObject)
+ private
+ FPixels: integer;
+ public
+ property Pixels: integer read FPixels;
+ end;
+
+implementation
+
+end.
+
diff --git a/prototypes/miglayout/gui_miglayout.pas b/prototypes/miglayout/gui_miglayout.pas
new file mode 100644
index 00000000..ee626769
--- /dev/null
+++ b/prototypes/miglayout/gui_miglayout.pas
@@ -0,0 +1,48 @@
+unit gui_miglayout;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, gui_bevel, gfxbase;
+
+type
+
+ { TfpgLayoutPanel }
+
+ TfpgLayoutPanel = class(TfpgBevel)
+ protected
+ procedure HandleResize(awidth, aheight: TfpgCoord); override;
+ public
+ constructor Create(AOwner: TComponent); override;
+ procedure Add(AComponent: TComponent; AConstraint: string);
+ end;
+
+implementation
+
+uses
+ fpgfx;
+
+{ TfpgLayoutPanel }
+
+procedure TfpgLayoutPanel.HandleResize(awidth, aheight: TfpgCoord);
+begin
+ writeln('HandleResize');
+ inherited HandleResize(awidth, aheight);
+end;
+
+constructor TfpgLayoutPanel.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ Align := alClient;
+ Shape := bsSpacer;
+end;
+
+procedure TfpgLayoutPanel.Add(AComponent: TComponent; AConstraint: string);
+begin
+ //
+end;
+
+end.
+
diff --git a/prototypes/miglayout/net/miginfocom/demo/CallbackDemo.java b/prototypes/miglayout/net/miginfocom/demo/CallbackDemo.java
new file mode 100644
index 00000000..693271e4
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/demo/CallbackDemo.java
@@ -0,0 +1,145 @@
+package net.miginfocom.demo;
+
+import net.miginfocom.swing.MigLayout;
+import net.miginfocom.layout.*;
+import javax.swing.*;
+import java.awt.event.*;
+import java.awt.*;
+import java.util.IdentityHashMap;
+
+public class CallbackDemo extends JFrame implements ActionListener, MouseMotionListener, MouseListener
+{
+ private final Timer repaintTimer = new Timer(20, new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ ((JPanel) getContentPane()).revalidate();
+ }
+ });
+ private final IdentityHashMap<Object, Long> pressMap = new IdentityHashMap<Object, Long>();
+ private Point mousePos = null;
+
+ public CallbackDemo()
+ {
+ super("MiG Layout Callback Demo");
+
+ MigLayout migLayout = new MigLayout("align center bottom, insets 30");
+ final JPanel panel = new JPanel(migLayout) {
+ protected void paintComponent(Graphics g)
+ {
+ ((Graphics2D) g).setPaint(new GradientPaint(0, getHeight() / 2, Color.WHITE, 0, getHeight(), new Color(240, 238, 235)));
+ g.fillRect(0, 0, getWidth(), getHeight());
+ }
+ };
+ setContentPane(panel);
+
+ // This callback methods will be called for every layout cycle and let you make correction before and after the calculations.
+ migLayout.addLayoutCallback(new LayoutCallback() {
+
+ // This is the size change part
+ public BoundSize[] getSize(ComponentWrapper comp)
+ {
+ if (comp.getComponent() instanceof JButton) {
+ Component c = (Component) comp.getComponent();
+ Point p = mousePos != null ? SwingUtilities.convertPoint(panel, mousePos, c) : new Point(-1000, -1000);
+
+ float fact = (float) Math.sqrt(Math.pow(Math.abs(p.x - c.getWidth() / 2f), 2) + Math.pow(Math.abs(p.y - c.getHeight() / 2f), 2));
+ fact = Math.max(2 - (fact / 200), 1);
+
+ return new BoundSize[] {new BoundSize(new UnitValue(60 * fact), ""), new BoundSize(new UnitValue(60 * fact), "")};
+ }
+ return null;
+ }
+
+ // This is the jumping part
+ public void correctBounds(ComponentWrapper c)
+ {
+ Long pressedNanos = pressMap.get(c.getComponent());
+ if (pressedNanos != null) {
+ long duration = System.nanoTime() - pressedNanos;
+ double maxHeight = 100.0 - (duration / 100000000.0);
+ int deltaY = (int) Math.round(Math.abs(Math.sin((duration) / 300000000.0) * maxHeight));
+ c.setBounds(c.getX(), c.getY() - deltaY, c.getWidth(), c.getHeight());
+
+ if (maxHeight < 0.5) {
+ pressMap.remove(c.getComponent());
+ if (pressMap.size() == 0)
+ repaintTimer.stop();
+ }
+ }
+ }
+ });
+
+ for (int j = 0; j < 10; j++)
+ panel.add(createButton(j), "aligny 0.8al");
+
+ JLabel label = new JLabel("Can't you just feel the urge to press one of those Swing JButtons?");
+ label.setFont(new Font("verdana", Font.PLAIN, 24));
+ label.setForeground(new Color(150, 150, 150));
+ panel.add(label, "pos 0.5al 0.2al");
+
+ panel.addMouseMotionListener(this);
+ panel.addMouseListener(this);
+ }
+
+ private static Font[] FONTS = new Font[120];
+ private JButton createButton(int i)
+ {
+ JButton button = new JButton(String.valueOf("MIG LAYOUT".charAt(i))) {
+ public Font getFont()
+ {
+ if (FONTS[0] == null) {
+ for (int i = 0; i < FONTS.length; i++)
+ FONTS[i] = new Font("tahoma", Font.PLAIN, i);
+ }
+
+ return FONTS[getWidth() >> 1];
+ }
+ };
+
+ button.setForeground(new Color(100, 100, 100));
+ button.setFocusPainted(false);
+ button.addMouseMotionListener(this);
+ button.addActionListener(this);
+ button.setMargin(new Insets(0, 0, 0, 0));
+ return button;
+ }
+
+ public void mouseDragged(MouseEvent e) {}
+ public void mouseMoved(MouseEvent e)
+ {
+ if (e.getSource() instanceof JButton) {
+ mousePos = SwingUtilities.convertPoint((Component) e.getSource(), e.getPoint(), getContentPane());
+ } else {
+ mousePos = e.getPoint();
+ }
+ ((JPanel) getContentPane()).revalidate();
+ }
+
+ public void mousePressed(MouseEvent e) {}
+ public void mouseReleased(MouseEvent e) {}
+ public void mouseClicked(MouseEvent e) {}
+ public void mouseEntered(MouseEvent e) {}
+ public void mouseExited(MouseEvent e)
+ {
+ mousePos = null;
+ ((JPanel) getContentPane()).revalidate();
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ pressMap.put(e.getSource(), System.nanoTime());
+ repaintTimer.start();
+ }
+
+ public static void main(String args[])
+ {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception ex) {}
+
+ CallbackDemo demoFrame = new CallbackDemo();
+ demoFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ demoFrame.setSize(970, 500);
+ demoFrame.setLocationRelativeTo(null);
+ demoFrame.setVisible(true);
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/demo/HiDPISimulator.java b/prototypes/miglayout/net/miginfocom/demo/HiDPISimulator.java
new file mode 100644
index 00000000..5c7840d2
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/demo/HiDPISimulator.java
@@ -0,0 +1,495 @@
+package net.miginfocom.demo;
+
+import net.miginfocom.layout.PlatformDefaults;
+import net.miginfocom.layout.UnitValue;
+import net.miginfocom.swing.MigLayout;
+import org.jvnet.substance.SubstanceLookAndFeel;
+import org.jvnet.substance.fonts.SubstanceFontUtilities;
+import org.jvnet.substance.skin.SubstanceBusinessBlackSteelLookAndFeel;
+
+import javax.swing.*;
+import javax.swing.border.LineBorder;
+import javax.swing.plaf.FontUIResource;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.util.*;
+
+/** A demo application that shows some components in a GUI and how they will look on a HiDPI screen.
+ */
+public class HiDPISimulator
+{
+ static final String SYSTEM_LAF_NAME = "System";
+ static final String SUBSTANCE_LAF_NAME = "Substance";
+ static final String OCEAN_LAF_NAME = "Ocean";
+ static final String NUMBUS_LAF_NAME = "Nimbus (Soon..)";
+
+ static JFrame APP_GUI_FRAME;
+ static HiDPIDemoPanel HiDPIDEMO_PANEL;
+ static JPanel SIM_PANEL;
+ static JPanel MIRROR_PANEL;
+ static JScrollPane MAIN_SCROLL;
+ static JTextArea TEXT_AREA;
+
+ static boolean SCALE_LAF = false;
+ static boolean SCALE_FONTS = true;
+ static boolean SCALE_LAYOUT = true;
+
+ static boolean PAINT_GHOSTED = false;
+
+ static BufferedImage GUI_BUF = null;
+ static BufferedImage ORIG_GUI_BUF = null;
+
+ static int CUR_DPI = PlatformDefaults.getDefaultDPI();
+ static HashMap<String, Font> ORIG_DEFAULTS;
+
+ private static JPanel createScaleMirror()
+ {
+ return new JPanel(new MigLayout()) {
+ protected void paintComponent(Graphics g)
+ {
+ super.paintComponent(g);
+
+ if (GUI_BUF != null) {
+ Graphics2D g2 = (Graphics2D) g.create();
+
+ double dpi = getToolkit().getScreenResolution();
+
+ AffineTransform oldTrans = g2.getTransform();
+ g2.scale(dpi / CUR_DPI, dpi / CUR_DPI);
+
+ g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+
+ g2.drawImage(GUI_BUF, 0, 0, null);
+
+ g2.setTransform(oldTrans);
+
+ if (ORIG_GUI_BUF != null && PAINT_GHOSTED) {
+ g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f));
+ g2.drawImage(ORIG_GUI_BUF, 0, 0, null);
+ }
+
+ g2.dispose();
+ }
+ }
+
+ public Dimension getPreferredSize()
+ {
+ return ORIG_GUI_BUF != null ? new Dimension(ORIG_GUI_BUF.getWidth(), ORIG_GUI_BUF.getHeight()) : new Dimension(100, 100);
+ }
+
+ public Dimension getMinimumSize()
+ {
+ return getPreferredSize();
+ }
+ };
+ }
+
+ private static JPanel createSimulator()
+ {
+ final JRadioButton scaleCompsFonts = new JRadioButton("UIManager Font Substitution", true);
+ final JRadioButton scaleCompsLaf = new JRadioButton("Native Look&Feel Scaling", false);
+ final JRadioButton scaleCompsNone = new JRadioButton("No Scaling", false);
+ final JRadioButton scaleLayoutMig = new JRadioButton("Native MigLayout Gap Scaling", true);
+ final JRadioButton scaleLayoutNone = new JRadioButton("No Gap Scaling", false);
+ final JComboBox lafCombo = new JComboBox(new String[] {SYSTEM_LAF_NAME, SUBSTANCE_LAF_NAME, OCEAN_LAF_NAME, NUMBUS_LAF_NAME});
+
+ final ButtonGroup bg1 = new ButtonGroup();
+ final ButtonGroup bg2 = new ButtonGroup();
+ final JCheckBox ghostCheck = new JCheckBox("Overlay \"Optimal\" HiDPI Result");
+
+ scaleCompsLaf.setEnabled(false);
+
+ bg1.add(scaleCompsFonts);
+ bg1.add(scaleCompsLaf);
+ bg1.add(scaleCompsNone);
+
+ bg2.add(scaleLayoutMig);
+ bg2.add(scaleLayoutNone);
+
+ Vector<String> dpiStrings = new Vector<String>();
+
+ for (float f = 0.5f; f < 2.01f; f += 0.1f)
+ dpiStrings.add(Math.round(PlatformDefaults.getDefaultDPI() * f) + " DPI (" + Math.round(f * 100f + 0.499f) + "%)");
+
+ final JComboBox dpiCombo = new JComboBox(dpiStrings);
+ dpiCombo.setSelectedIndex(5);
+
+ JPanel panel = new JPanel(new MigLayout("alignx center, insets 10px 20px 10px 20px, flowy", "[]50px[]", "[]3px[]0px[]"));
+
+ JLabel lafLabel = new JLabel("Look & Feel:");
+ JLabel sliderLabel = new JLabel("Simulated DPI:");
+ JLabel scaleLabel = new JLabel("Component/Text Scaling:");
+ JLabel layoutLabel = new JLabel("LayoutManager Scaling:");
+ JLabel visualsLabel = new JLabel("Visual Aids:");
+
+ panel.add(lafLabel, "");
+ panel.add(lafCombo, "wrap");
+
+ panel.add(sliderLabel, "");
+ panel.add(dpiCombo, "wrap");
+
+ panel.add(scaleLabel, "");
+ panel.add(scaleCompsFonts, "");
+ panel.add(scaleCompsLaf, "");
+ panel.add(scaleCompsNone, "wrap");
+
+ panel.add(layoutLabel, "");
+ panel.add(scaleLayoutMig, "");
+ panel.add(scaleLayoutNone, "wrap");
+
+ panel.add(visualsLabel, "");
+ panel.add(ghostCheck, "");
+
+ lockFont(dpiCombo, scaleCompsFonts, scaleCompsLaf, scaleLayoutMig, scaleCompsNone, lafCombo, ghostCheck, panel, lafLabel, sliderLabel, scaleLayoutNone, scaleLabel, layoutLabel, visualsLabel);
+
+ lafCombo.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ GUI_BUF = null;
+ try {
+ Object s = lafCombo.getSelectedItem();
+
+ dpiCombo.setSelectedIndex(5);
+
+ if (s.equals(SYSTEM_LAF_NAME)) {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } else if (s.equals(SUBSTANCE_LAF_NAME)) {
+ UIManager.setLookAndFeel(new SubstanceBusinessBlackSteelLookAndFeel());
+ } else if (s.equals(OCEAN_LAF_NAME)) {
+ UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
+ } else {
+ JOptionPane.showMessageDialog(APP_GUI_FRAME, "Nimbus will be included as soon as it is ready!");
+ }
+
+ if (ORIG_DEFAULTS != null) {
+ for (String key : ORIG_DEFAULTS.keySet())
+ UIManager.put(key, null);
+ }
+ ORIG_DEFAULTS = null;
+
+ if (UIManager.getLookAndFeel().getName().toLowerCase().contains("windows")) {
+ UIManager.put("TextArea.font", UIManager.getFont("TextField.font"));
+ } else {
+ UIManager.put("TextArea.font", null);
+ }
+
+ SwingUtilities.updateComponentTreeUI(APP_GUI_FRAME);
+ MAIN_SCROLL.setBorder(null);
+
+ if (s.equals(SYSTEM_LAF_NAME)) {
+ if (scaleCompsLaf.isSelected())
+ scaleCompsFonts.setSelected(true);
+
+ scaleCompsLaf.setEnabled(false);
+
+ } else if (s.equals(SUBSTANCE_LAF_NAME)) {
+ scaleCompsLaf.setEnabled(true);
+
+ } else if (s.equals(OCEAN_LAF_NAME)) {
+ if (scaleCompsLaf.isSelected())
+ scaleCompsFonts.setSelected(true);
+ scaleCompsLaf.setEnabled(false);
+ }
+
+ setDPI(CUR_DPI);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+ });
+
+ ghostCheck.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent actionEvent)
+ {
+ GUI_BUF = null;
+ PAINT_GHOSTED = ghostCheck.isSelected();
+ APP_GUI_FRAME.repaint();
+ }
+ });
+
+ scaleLayoutMig.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e)
+ {
+ GUI_BUF = null;
+ SCALE_LAYOUT = scaleLayoutMig.isSelected();
+ setDPI(CUR_DPI);
+ }
+ });
+
+ ItemListener il = new ItemListener() {
+ public void itemStateChanged(ItemEvent e)
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ GUI_BUF = null;
+ SCALE_LAF = scaleCompsLaf.isSelected();
+ SCALE_FONTS = scaleCompsFonts.isSelected();
+ setDPI(CUR_DPI);
+ }
+ }
+ };
+
+ scaleCompsLaf.addItemListener(il);
+ scaleCompsFonts.addItemListener(il);
+ scaleCompsNone.addItemListener(il);
+
+ dpiCombo.addItemListener(new ItemListener() {
+ public void itemStateChanged(ItemEvent e)
+ {
+ if (e.getStateChange() == ItemEvent.SELECTED) {
+ GUI_BUF = null;
+ CUR_DPI = Integer.parseInt(dpiCombo.getSelectedItem().toString().substring(0, 3).trim());
+ setDPI(CUR_DPI);
+ }
+ }
+ });
+
+ return panel;
+ }
+
+ private static void lockFont(Component ... comps)
+ {
+ for (Component c : comps) {
+ Font f = c.getFont();
+ c.setFont(f.deriveFont((float) f.getSize()));
+ }
+ }
+
+ private static void revalidateGUI()
+ {
+ APP_GUI_FRAME.getContentPane().invalidate();
+ APP_GUI_FRAME.repaint();
+ }
+
+ private synchronized static void setDPI(int dpi)
+ {
+ float scaleFactor = dpi / (float) Toolkit.getDefaultToolkit().getScreenResolution();
+ TEXT_AREA.setSize(0, 0); // To reset for Swing TextArea horizontal size bug...
+ PlatformDefaults.setHorizontalScaleFactor(.1f);// Only so that the cache will be invalidated for sure
+ PlatformDefaults.setHorizontalScaleFactor(SCALE_LAYOUT ? scaleFactor : null);
+ PlatformDefaults.setVerticalScaleFactor(SCALE_LAYOUT ? scaleFactor : null);
+
+ float fontScale = SCALE_FONTS ? dpi / (float) Toolkit.getDefaultToolkit().getScreenResolution() : 1f;
+
+ if (ORIG_DEFAULTS == null) {
+ ORIG_DEFAULTS = new HashMap<String, Font>();
+
+ Set entries = new HashSet(UIManager.getLookAndFeelDefaults().keySet());
+ for (Iterator it = entries.iterator(); it.hasNext();) {
+ String key = it.next().toString();
+ Object value = UIManager.get(key);
+
+ if (value instanceof Font)
+ ORIG_DEFAULTS.put(key, (Font) value);
+ }
+ }
+
+ Set entries = ORIG_DEFAULTS.entrySet();
+ for (Iterator<Map.Entry<String, Font>> it = entries.iterator(); it.hasNext();) {
+ Map.Entry<String, Font> e = it.next();
+ Font origFont = e.getValue();
+
+ if (SCALE_LAF == false) {
+ UIManager.put(e.getKey(), new FontUIResource(origFont.deriveFont(origFont.getSize() * fontScale)));
+ } else {
+ UIManager.put(e.getKey(), null);
+ }
+ }
+
+ if (SCALE_LAF) {
+ scaleSubstanceLAF(scaleFactor);
+ } else if (UIManager.getLookAndFeel().getName().toLowerCase().contains("substance")) {
+ scaleSubstanceLAF(1);
+ }
+
+ SwingUtilities.updateComponentTreeUI(HiDPIDEMO_PANEL);
+ revalidateGUI();
+ }
+
+ private static void scaleSubstanceLAF(float factor)
+ {
+ SubstanceLookAndFeel.setFontPolicy(SubstanceFontUtilities.getScaledFontPolicy(factor));
+
+ try {
+ UIManager.setLookAndFeel(new SubstanceBusinessBlackSteelLookAndFeel());
+ } catch (Exception exc) {
+ }
+
+ SwingUtilities.updateComponentTreeUI(APP_GUI_FRAME);
+ MAIN_SCROLL.setBorder(null);
+ }
+
+ public static void main(String[] args)
+ {
+ try {
+ System.setProperty("apple.laf.useScreenMenuBar", "true");
+ System.setProperty("com.apple.mrj.application.apple.menu.about.name", "HiDPI Simulator");
+ } catch(Exception ex) {}
+
+ PlatformDefaults.setDefaultHorizontalUnit(UnitValue.LPX);
+ PlatformDefaults.setDefaultVerticalUnit(UnitValue.LPY);
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ if (UIManager.getLookAndFeel().getName().toLowerCase().contains("windows"))
+ UIManager.put("TextArea.font", UIManager.getFont("TextField.font"));
+
+ APP_GUI_FRAME = new JFrame("Resolution Independence Simulator");
+
+// RepaintManager.currentManager(APP_GUI_FRAME).setDoubleBufferingEnabled(false);
+
+ JPanel uberPanel = new JPanel(new MigLayout("fill, insets 0px, nocache"));
+
+ JPanel mainPanel = new JPanel(new MigLayout("fill, insets 0px, nocache")) {
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g.create();
+
+ g2.setPaint(new GradientPaint(0, 0, new Color(20, 20, 30), 0, getHeight(), new Color(90, 90, 110), false));
+ g2.fillRect(0, 0, getWidth(), getHeight());
+
+ g2.setFont(g2.getFont().deriveFont(Font.BOLD, 13));
+ g2.setPaint(Color.WHITE);
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+ g2.drawString("Left panel shows the scaled version. Right side shows how this would look on a HiDPI screen. It should look the same as the original panel!", 10, 19);
+
+ g2.dispose();
+ }
+ };
+
+ HiDPIDEMO_PANEL = new HiDPIDemoPanel();
+ SIM_PANEL = createSimulator();
+ MIRROR_PANEL = createScaleMirror();
+
+ MAIN_SCROLL = new JScrollPane(mainPanel);
+ MAIN_SCROLL.setBorder(null);
+
+ mainPanel.add(HiDPIDEMO_PANEL, "align center center, split, span, width pref!");
+ mainPanel.add(MIRROR_PANEL, "id mirror, gap 20px!, width pref!");
+
+ uberPanel.add(SIM_PANEL, "dock south");
+ uberPanel.add(MAIN_SCROLL, "dock center");
+
+ Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
+ APP_GUI_FRAME.setContentPane(uberPanel);
+ APP_GUI_FRAME.setSize(Math.min(1240, screenSize.width), Math.min(950, screenSize.height - 30));
+ APP_GUI_FRAME.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ APP_GUI_FRAME.setLocationRelativeTo(null);
+ APP_GUI_FRAME.setVisible(true);
+ }
+ });
+ }
+}
+
+class HiDPIDemoPanel extends JPanel {
+ public HiDPIDemoPanel()
+ {
+ super(new MigLayout());
+
+ JLabel jLabel1 = new JLabel("A Small Label:");
+ JTextField jTextField1 = new JTextField(10);
+ JButton jButton1 = new JButton("Cancel");
+ JButton jButton2 = new JButton("OK");
+ JButton jButton4 = new JButton("Help");
+ JList jList1 = new JList();
+ JLabel jLabel2 = new JLabel("Label:");
+ JTextField jTextField2 = new JTextField(10);
+ JLabel jLabel3 = new JLabel("This is another section");
+ JSeparator jSeparator1 = new JSeparator();
+ JTextArea jTextArea1 = new JTextArea("Some general text that takes place, doesn't offend anyone and fills some pixels.", 3, 30); // colums set always!
+ JLabel jLabel4 = new JLabel("Some Text Area");
+ JLabel jLabel6 = new JLabel("Some List:");
+ JComboBox jComboBox1 = new JComboBox();
+ JCheckBox jCheckBox1 = new JCheckBox("Orange");
+
+ JScrollBar scroll1 = new JScrollBar(JScrollBar.VERTICAL);
+ JScrollBar scroll2 = new JScrollBar(JScrollBar.HORIZONTAL, 30, 40, 0, 100);
+ JRadioButton radio = new JRadioButton("Apple");
+ JProgressBar prog = new JProgressBar();
+ prog.setValue(50);
+ JSpinner spinner = new JSpinner(new SpinnerNumberModel(50, 0, 100, 1));
+ JTree tree = new JTree();
+ tree.setOpaque(false);
+ tree.setEnabled(false);
+
+ jList1.setModel(new AbstractListModel() {
+ String[] strings = { "Donald Duck", "Mickey Mouse", "Pluto", "Cartman" };
+ public int getSize() { return strings.length; }
+ public Object getElementAt(int i) { return strings[i]; }
+ });
+
+ jList1.setVisibleRowCount(4);
+ jList1.setBorder(new LineBorder(Color.GRAY));
+ jTextArea1.setLineWrap(true);
+ jTextArea1.setWrapStyleWord(true);
+ jTextArea1.setBorder(new LineBorder(Color.GRAY));
+ jComboBox1.setModel(new DefaultComboBoxModel(new String[] {"Text in ComboBox"}));
+ jCheckBox1.setMargin(new java.awt.Insets(0, 0, 0, 0));
+
+ add(jLabel1, "split, span");
+ add(jTextField1, "");
+ add(jLabel2, "gap unrelated");
+ add(jTextField2, "wrap");
+ add(jLabel3, "split, span");
+ add(jSeparator1, "growx, span, gap 2, wrap unrelated");
+ add(jLabel4, "wrap 2");
+ add(jTextArea1, "span, wmin 150, wrap unrelated");
+ add(jLabel6, "wrap 2");
+ add(jList1, "split, span");
+ add(scroll1, "growy");
+ add(prog, "width 80!");
+ add(tree, "wrap unrelated");
+
+ add(scroll2, "split, span, growx");
+ add(spinner, "wrap unrelated");
+ add(jComboBox1, "span, split");
+ add(radio, "");
+ add(jCheckBox1, "wrap unrelated");
+ add(jButton4, "split, span, tag help2");
+ add(jButton2, "tag ok");
+ add(jButton1, "tag cancel");
+
+ HiDPISimulator.TEXT_AREA = jTextArea1;
+ }
+
+ public void paint(Graphics g)
+ {
+ if (HiDPISimulator.GUI_BUF == null) {
+ BufferedImage bi = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
+
+ Graphics2D g2 = bi.createGraphics();
+
+ super.paint(g2);
+
+ g2.dispose();
+
+ g.drawImage(bi, 0, 0, null);
+
+ HiDPISimulator.GUI_BUF = bi;
+
+ if (HiDPISimulator.CUR_DPI == PlatformDefaults.getDefaultDPI())
+ HiDPISimulator.ORIG_GUI_BUF = bi;
+
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ HiDPISimulator.MIRROR_PANEL.revalidate();
+ HiDPISimulator.MIRROR_PANEL.repaint();
+ }
+ });
+ } else {
+ super.paint(g);
+ }
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/demo/SwingDemo.java b/prototypes/miglayout/net/miginfocom/demo/SwingDemo.java
new file mode 100644
index 00000000..42f9b13c
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/demo/SwingDemo.java
@@ -0,0 +1,3668 @@
+package net.miginfocom.demo;
+
+import net.miginfocom.layout.*;
+import net.miginfocom.swing.MigLayout;
+
+import javax.swing.*;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.LineBorder;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Random;
+
+/*
+ * 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
+ */
+public class SwingDemo extends JFrame
+{
+ public static final int INITIAL_INDEX = 0;
+ private static final boolean DEBUG = false;
+ private static final boolean OPAQUE = false;
+
+ private static final String[][] panels = new String[][] {
+// {"Test", "Test, disregard"},
+ {"Welcome", "\n\n \"MigLayout makes complex layouts easy and normal layouts one-liners.\""},
+ {"Quick Start", "This is an example of how to build a common dialog type. Note that there are no special components, nested panels or absolute references to cell positions. If you look at the source code you will see that the layout code is very simple to understand."},
+ {"Plain", "A simple example on how simple it is to create normal forms. No builders needed since the whole layout manager works like a builder."},
+ {"Alignments", "Shows how the alignment of components are specified. At the top/left is the alignment for the column/row. The components have no alignments specified.\n\nNote that baseline alignment will be interpreted as 'center' before JDK 6."},
+ {"Cell Alignments", "Shows how components are aligned when both column/row alignments and component constraints are specified. At the top/left are the alignment for the column/row and the text on the buttons is the component constraint that will override the column/row alignment if it is an alignment.\n\nNote that baseline alignment will be interpreted as 'center' before JDK 6."},
+ {"Basic Sizes", "A simple example that shows how to use the column or row min/preferred/max size to set the sizes of the contained components and also an example that shows how to do this directly in the component constraints."},
+ {"Growing", "A simple example that shows how to use the growx and growy constraint to set the sizes and how they should grow to fit the available size. Both the column/row and the component grow/shrink constraints can be set, but the components will always be confined to the space given by its column/row."},
+ {"Grow Shrink", "Demonstrates the very flexible grow and shrink constraints that can be set on a component.\nComponents can be divided into grow/shrink groups and also have grow/shrink weight within each of those groups.\n\nBy default " +
+ "components shrink to their inherent (or specified) minimum size, but they don't grow."},
+ {"Span", "This example shows the powerful spanning and splitting that can be specified in the component constraints. With spanning any number of cells can be merged with the additional option to split that space for more than one component. This makes layouts very flexible and reduces the number of times you will need nested panels to very few."},
+ {"Flow Direction", "Shows the different flow directions. Flow direction for the layout specifies if the next cell will be in the x or y dimension. Note that it can be a different flow direction in the slit cell (the middle cell is slit in two). Wrap is set to 3 for all panels."},
+ {"Grouping", "Sizes for both components and columns/rows can be grouped so they get the same size. For instance buttons in a button bar can be given a size-group so that they will all get " +
+ "the same minimum and preferred size (the largest within the group). Size-groups can be set for the width, height or both."},
+ {"Units", "Demonstrates the basic units that are understood by MigLayout. These units can be extended by the user by adding one or more UnitConverter(s)."},
+ {"Component Sizes", "Minimum, preferred and maximum component sizes can be overridden in the component constraints using any unit type. The format to do this is short and simple to understand. You simply specify the " +
+ "min, preferred and max sizes with a colon between.\n\nAbove are some examples of this. An exclamation mark means that the value will be used for all sizes."},
+ {"Bound Sizes", "Shows how to create columns that are stable between tabs using minimum sizes."},
+ {"Cell Position", "Even though MigLayout has automatic grid flow you can still specify the cell position explicitly. You can even combine absolute (x, y) and flow (skip, wrap and newline) constraints to build your layout."},
+ {"Orientation", "MigLayout supports not only right-to-left orientation, but also bottom-to-top. You can even set the flow direction so that the flow is vertical instead of horizontal. It will automatically " +
+ "pick up if right-to-left is to be used depending on the ComponentWrapper, but it can also be manually set for every layout."},
+ {"Absolute Position", "Demonstrates the option to place any number of components using absolute coordinates. This can be just the position (if min/preferred size) using \"x y p p\" format or" +
+ "the bounds using the \"x1 y1 x2 y2\" format. Any unit can be used and percent is relative to the parent.\nAbsolute components will not disturb the flow or occupy cells in the grid. " +
+ "Absolute positioned components will be taken into account when calculating the container's preferred size."},
+ {"Component Links", "Components can be linked to any side of any other component. It can be a forward, backward or cyclic link references, as long as it is stable and won't continue to change value over many iterations." +
+ "Links are referencing the ID of another component. The ID can be overridden by the component's constrains or is provided by the ComponentWrapper. For instance it will use the component's 'name' on Swing.\n" +
+ "Since the links can be combined with any expression (such as 'butt1.x+10' or 'max(button.x, 200)' the links are very customizable."},
+ {"Docking", "Docking components can be added around the grid. The docked component will get the whole width/height on the docked side by default, however this can be overridden. When all docked components are laid out, whatever space " +
+ "is left will be available for the normal grid laid out components. Docked components does not in any way affect the flow in the grid.\n\nSince the docking runs in the same code path " +
+ "as the normal layout code the same properties can be specified for the docking components. You can for instance set the sizes and alignment or link other components to their docked component's bounds."},
+ {"Button Bars", "Button order is very customizable and are by default different on the supported platforms. E.g. Gaps, button order and minimum button size are properties that are 'per platform'. MigLayout picks up the current platform automatically and adjusts the button order and minimum button size accordingly, all without using a button builder or any other special code construct."},
+ {"Visual Bounds", "Human perceptible bounds may not be the same as the mathematical bounds for the component. This is for instance the case if there is a drop shadow painted by the component's border. MigLayout can compensate " +
+ "for this in a simple way. Note the top middle tab-component, it is not aligned visually correct on Windows XP. For the second tab the bounds are corrected automatically on Windows XP."},
+ {"Debug", "Demonstrates the non-intrusive way to get visual debugging aid. There is no need to use a special DebugPanel or anything that will need code changes. The user can simply turn on debug on the layout manager by using the \"debug\" constraint and it will " +
+ "continuously repaint the panel with debug information on top. This means you don't have to change your code to debug!"},
+ {"Layout Showdown", "This is an implementation of the Layout Showdown posted on java.net by John O'Conner. The first tab is a pure implemenetation of the showdown that follows all the rules. The second tab is a slightly fixed version that follows some improved layout guidelines." +
+ "The source code is for bothe the first and for the fixed version. Note the simplification of the code for the fixed version. Writing better layouts with MiG Layout is reasier that writing bad.\n\nReference: http://weblogs.java.net/blog/joconner/archive/2006/10/more_informatio.html"},
+ {"API Constraints1", "This dialog shows the constraint API added to v2.0. It works the same way as the string constraints but with chained method calls. See the source code for details."},
+ {"API Constraints2", "This dialog shows the constraint API added to v2.0. It works the same way as the string constraints but with chained method calls. See the source code for details."}
+ };
+
+ private int lastIndex = -10;
+
+ private JPanel contentPanel = DEBUG ? new JPanel(new BorderLayout()) : new JPanel(new MigLayout("wrap", "[]unrel[grow]", "[grow][pref]"));
+
+ private JTabbedPane layoutPickerTabPane = new JTabbedPane();
+ private JList pickerList = new JList(new DefaultListModel());
+
+ private JTabbedPane southTabPane = new JTabbedPane();
+ private JScrollPane descrTextAreaScroll = createTextAreaScroll("", 5, 80, true);
+ private JTextArea descrTextArea = (JTextArea) descrTextAreaScroll.getViewport().getView();
+
+ private JScrollPane sourceTextAreaScroll = null;
+ private JTextArea sourceTextArea = null;
+
+ private JPanel layoutDisplayPanel = new JPanel(new BorderLayout(0, 0));
+ private static boolean buttonOpaque = true;
+ private JFrame sourceFrame = null;
+ private JTextArea sourceFrameTextArea = null;
+
+ private static int benchRuns = 0;
+ private static long startupMillis = 0;
+ private static long timeToShowMillis = 0;
+ private static long benchRunTime = 0;
+ private static String benchOutFileName = null;
+ private static boolean append = false;
+ private static long lastRunTimeStart = 0;
+ private static StringBuffer runTimeSB = null;
+
+ public static void main(String args[])
+ {
+ try {
+ System.setProperty("apple.laf.useScreenMenuBar", "true");
+ System.setProperty("com.apple.mrj.application.apple.menu.about.name", "MiGLayout Swing Demo");
+ } catch(Throwable ex) {
+ // Beacuse we did not have permissions.
+ }
+
+ startupMillis = System.currentTimeMillis();
+
+ String laf = UIManager.getSystemLookAndFeelClassName();
+
+ if (args.length > 0) {
+ for (int i = 0; i <args.length; i++) {
+ String arg = args[i].trim();
+ if (arg.startsWith("-laf")) {
+ laf = arg.substring(4);
+ } else if (arg.startsWith("-bench")) {
+ benchRuns = 10;
+ try {
+ benchRuns = Integer.parseInt(arg.substring(6));
+ } catch(Exception ex) {}
+ } else if (arg.startsWith("-bout")) {
+ benchOutFileName = arg.substring(5);
+ } else if (arg.startsWith("-append")) {
+ append = true;
+ } else if (arg.startsWith("-verbose")) {
+ runTimeSB = new StringBuffer(256);
+ } else if (arg.equals("-steel")) {
+ laf = "javax.swing.plaf.metal.MetalLookAndFeel";
+ System.setProperty("swing.metalTheme", "steel");
+ } else if (arg.equals("-ocean")) {
+ laf = "javax.swing.plaf.metal.MetalLookAndFeel";
+ } else {
+ System.out.println("Usage: [-laf[look_&_feel_class_name]] [-bench[#_of_runs]] [-bout[benchmark_results_filename]] [-append] [-steel] [-ocean]\n" +
+ " -laf Set the Application Look&Feel. (Look and feel must be in Classpath)\n" +
+ " -bench Run demo as benchmark. Run count can be appended. 10 is default.\n" +
+ " -bout Benchmark results output filename.\n" +
+ " -append Appends the result to the -bout file.\n" +
+ " -verbose Print the times of every run.\n" +
+ " -steel Sets the old Steel theme for Sun's Metal look&feel.\n" +
+ " -ocean Sets the Ocean theme for Sun's Metal look&feel.\n" +
+ "\nExamples:\n" +
+ " java -jar swingdemoapp.jar -bench -boutC:/bench.txt -append\n" +
+ " java -jar swingdemoapp.jar -ocean -bench20\n" +
+ " java -cp c:\\looks-2.0.4.jar;.\\swingdemoapp.jar net.miginfocom.demo.SwingDemo -lafcom.jgoodies.looks.plastic.PlasticLookAndFeel -bench20 -boutC:/bench.txt");
+ System.exit(0);
+ }
+ }
+ }
+
+ if (benchRuns > 0)
+ LayoutUtil.setDesignTime(null, true); // So that the string constraints to create the UnitValues is saved and can be recreated exactly.
+
+// laf = "net.sourceforge.napkinlaf.NapkinLookAndFeel";
+// laf = "javax.swing.plaf.metal.MetalLookAndFeel";
+// System.setProperty("swing.metalTheme", "steel");
+// laf = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
+// laf = "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel";
+// laf = "com.jgoodies.looks.plastic.PlasticLookAndFeel";
+// laf = "com.jgoodies.looks.plastic.Plastic3DLookAndFeel";
+// laf = "com.jgoodies.looks.plastic.PlasticXPLookAndFeel";
+// laf = "com.jgoodies.looks.windows.WindowsLookAndFeel";
+
+ if (laf.endsWith("WindowsLookAndFeel"))
+ buttonOpaque = false;
+
+ final String laff = laf;
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ UIManager.setLookAndFeel(laff);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ SwingDemo demo = new SwingDemo();
+ }
+ });
+ }
+
+ public SwingDemo()
+ {
+ super("MigLayout Swing Demo v2.4 - Mig Layout v" + LayoutUtil.getVersion());
+
+// if (benchRuns > 0)
+// RepaintManager.currentManager(this).setDoubleBufferingEnabled(false);
+
+ if (benchRuns == 0) {
+ sourceTextAreaScroll = createTextAreaScroll("", 5, 80, true);
+ sourceTextArea = (JTextArea) sourceTextAreaScroll.getViewport().getView();
+ }
+
+ if (DEBUG) {
+ contentPanel.add(layoutDisplayPanel, BorderLayout.CENTER);
+// contentPanel.add(layoutPickerTabPane, BorderLayout.WEST);
+// contentPanel.add(descriptionTabPane, BorderLayout.SOUTH);
+ } else {
+ contentPanel.add(layoutPickerTabPane, "spany,grow");
+ contentPanel.add(layoutDisplayPanel, "grow");
+ contentPanel.add(southTabPane, "growx");
+ }
+
+ setContentPane(contentPanel);
+
+ pickerList.setOpaque(OPAQUE);
+ ((DefaultListCellRenderer) pickerList.getCellRenderer()).setOpaque(OPAQUE);
+ pickerList.setSelectionForeground(new Color(0, 0, 220));
+ pickerList.setBackground(null);
+ pickerList.setBorder(new EmptyBorder(2, 5, 0, 4));
+ pickerList.setFont(pickerList.getFont().deriveFont(Font.BOLD));
+ layoutPickerTabPane.addTab("Example Browser", pickerList);
+
+ descrTextAreaScroll.setBorder(null);
+ descrTextAreaScroll.setOpaque(OPAQUE);
+ descrTextAreaScroll.getViewport().setOpaque(OPAQUE);
+ descrTextArea.setOpaque(OPAQUE);
+ descrTextArea.setEditable(false);
+ descrTextArea.setBorder(new EmptyBorder(0, 4, 0, 4));
+ southTabPane.addTab("Description", descrTextAreaScroll);
+
+
+ if (sourceTextArea != null) {
+ sourceTextAreaScroll.setBorder(null);
+ sourceTextAreaScroll.setOpaque(OPAQUE);
+ sourceTextAreaScroll.getViewport().setOpaque(OPAQUE);
+ sourceTextAreaScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ sourceTextArea.setOpaque(OPAQUE);
+ sourceTextArea.setLineWrap(false);
+ sourceTextArea.setWrapStyleWord(false);
+ sourceTextArea.setEditable(false);
+ sourceTextArea.setBorder(new EmptyBorder(0, 4, 0, 4));
+ sourceTextArea.setFont(new Font("monospaced", Font.PLAIN, 11));
+ southTabPane.addTab("Source Code", sourceTextAreaScroll);
+
+ southTabPane.addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e)
+ {
+ if (e.getClickCount() == 2)
+ showSourceInFrame();
+ }
+ });
+ }
+
+ for (int i = 0; i < panels.length; i++)
+ ((DefaultListModel) pickerList.getModel()).addElement(panels[i][0]);
+
+ try {
+ setSize(900, 650);
+ setLocationRelativeTo(null);
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ setVisible(true);
+ } catch(Throwable t) {
+ t.printStackTrace();
+ System.exit(1);
+ }
+
+ pickerList.addListSelectionListener(new ListSelectionListener() {
+ public void valueChanged(ListSelectionEvent e)
+ {
+ int ix = pickerList.getSelectedIndex();
+ if (ix == -1 || lastIndex == ix)
+ return;
+
+ lastIndex = ix;
+
+ String methodName = "create" + panels[ix][0].replace(' ', '_');
+ layoutDisplayPanel.removeAll();
+ try {
+ pickerList.requestFocusInWindow();
+ final JComponent panel = (JComponent) SwingDemo.class.getMethod(methodName, new Class[0]).invoke(SwingDemo.this, new Object[0]);
+ layoutDisplayPanel.add(panel);
+ descrTextArea.setText(panels[ix][1]);
+ descrTextArea.setCaretPosition(0);
+ contentPanel.revalidate();
+
+ } catch (Exception e1) {
+ e1.printStackTrace(); // Should never happpen...
+ }
+ southTabPane.setSelectedIndex(0);
+ }
+ });
+
+ pickerList.requestFocusInWindow();
+ Toolkit.getDefaultToolkit().setDynamicLayout(true);
+
+ if (benchRuns > 0) {
+ doBenchmark();
+ } else {
+ pickerList.setSelectedIndex(INITIAL_INDEX);
+
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
+ public boolean dispatchKeyEvent(KeyEvent e)
+ {
+ if (e.getID() == KeyEvent.KEY_PRESSED && e.getKeyCode() == KeyEvent.VK_B && (e.getModifiersEx() & KeyEvent.CTRL_DOWN_MASK) > 0) {
+ startupMillis = System.currentTimeMillis();
+ timeToShowMillis = System.currentTimeMillis() - startupMillis;
+ benchRuns = 1;
+ doBenchmark();
+ return true;
+ }
+ return false;
+ }
+ });
+ }
+ }
+
+ private void doBenchmark()
+ {
+ Thread benchThread = new Thread() {
+ public void run()
+ {
+ for (int j = 0; j < benchRuns; j++) {
+ lastRunTimeStart = System.currentTimeMillis();
+ for (int i = 0, iCnt = pickerList.getModel().getSize(); i < iCnt; i++) {
+
+ if (benchRuns > 0 && panels[i][0].equals("Visual Bounds"))
+ continue; // the SWT version does not have Visual bounds...
+
+ final int ii = i;
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ pickerList.setSelectedIndex(ii);
+ Toolkit.getDefaultToolkit().sync();
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ Component[] comps = layoutDisplayPanel.getComponents();
+ for (int cIx = 0; cIx < comps.length; cIx++) {
+ if (comps[cIx] instanceof JTabbedPane) {
+ final JTabbedPane tp = (JTabbedPane) comps[cIx];
+
+ for (int k = 0, kCnt = tp.getTabCount(); k < kCnt; k++) {
+ final int kk = k;
+ try {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ tp.setSelectedIndex(kk);
+ Toolkit.getDefaultToolkit().sync();
+
+ if (timeToShowMillis == 0)
+ timeToShowMillis = System.currentTimeMillis() - startupMillis;
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ if (runTimeSB != null) {
+ runTimeSB.append("Run ").append(j).append(": ");
+ runTimeSB.append(System.currentTimeMillis() - lastRunTimeStart).append(" millis.\n");
+ }
+ }
+
+ benchRunTime = System.currentTimeMillis() - startupMillis - timeToShowMillis;
+
+ final String message = "Java Version: " + System.getProperty("java.version") + "\n" +
+ "Look & Feel: " + UIManager.getLookAndFeel().getDescription() + "\n" +
+ "Time to Show: " + timeToShowMillis + " millis.\n" +
+ (runTimeSB != null ? runTimeSB.toString() : "") +
+ "Benchmark Run Time: " + benchRunTime + " millis.\n" +
+ "Average Run Time: " + (benchRunTime / benchRuns) + " millis (" + benchRuns + " runs).\n\n";
+
+ if (benchOutFileName == null) {
+ JOptionPane.showMessageDialog(SwingDemo.this, message, "Results", JOptionPane.INFORMATION_MESSAGE);
+ } else {
+ FileWriter fw = null;
+ try {
+ fw = new FileWriter(benchOutFileName, append);
+ fw.write(message);
+ } catch(IOException ex) {
+ ex.printStackTrace();
+ } finally {
+ if (fw != null)
+ try {fw.close();} catch(IOException ex) {}
+ }
+ }
+ System.out.println(message);
+ }
+ };
+ benchThread.start();
+ }
+
+ private void setSource(String source)
+ {
+ if (benchRuns > 0 || sourceTextArea == null)
+ return;
+
+ if (source.length() > 0) {
+ source = source.replaceAll("\t\t", "");
+ source = "DOUBLE CLICK TAB TO SHOW SOURCE IN SEPARATE WINDOW!\n===================================================\n\n" + source;
+ }
+ sourceTextArea.setText(source);
+ sourceTextArea.setCaretPosition(0);
+
+ if (sourceFrame != null && sourceFrame.isVisible()) {
+ sourceFrameTextArea.setText(source.length() > 105 ? source.substring(105) : "No Source Code Available!");
+ sourceFrameTextArea.setCaretPosition(0);
+ }
+ }
+
+ private void showSourceInFrame()
+ {
+ if (sourceTextArea == null)
+ return;
+
+ JScrollPane sourceFrameTextAreaScroll = createTextAreaScroll("", 5, 80, true);
+ sourceFrameTextArea = (JTextArea) sourceFrameTextAreaScroll.getViewport().getView();
+
+ sourceFrameTextAreaScroll.setBorder(null);
+ sourceFrameTextAreaScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ sourceFrameTextArea.setLineWrap(false);
+ sourceFrameTextArea.setWrapStyleWord(false);
+ sourceFrameTextArea.setEditable(false);
+ sourceFrameTextArea.setBorder(new EmptyBorder(10, 10, 10, 10));
+ sourceFrameTextArea.setFont(new Font("monospaced", Font.PLAIN, 12));
+
+ String source = this.sourceTextArea.getText();
+ sourceFrameTextArea.setText(source.length() > 105 ? source.substring(105) : "No Source Code Available!");
+ sourceFrameTextArea.setCaretPosition(0);
+
+ sourceFrame = new JFrame("Source Code");
+ sourceFrame.getContentPane().add(sourceFrameTextAreaScroll, BorderLayout.CENTER);
+ sourceFrame.setSize(700, 800);
+ sourceFrame.setLocationRelativeTo(this);
+ sourceFrame.setVisible(true);
+ }
+
+ public JComponent createTest()
+ {
+ JComponent pane = new JPanel();
+
+ pane.setLayout(new MigLayout("debug"));
+
+ pane.add(new JLabel("Separator"), "gapbottom 1, ax r, spanx, split");
+ pane.add(new JSeparator(), "gap rel, growx");
+
+ JLabel label = new JLabel("<html><font color=red><b>some text in label</b></font></html>");
+
+
+ pane.add(label, "wrap");
+ pane.add(new JButton("Button1"));
+ pane.add(new JButton("Button2"));
+ pane.add(new JButton("Button3"));
+
+ return pane;
+ }
+
+ public JComponent createAPI_Constraints1()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ LC layC = new LC().fill().wrap();
+ AC colC = new AC().align("right", 1).fill(2, 4).grow(100, 2, 4).align("right", 3).gap("15", 2);
+ AC rowC = new AC().align("top", 7).gap("15!", 6).grow(100, 8);
+
+ JPanel panel = createTabPanel(new MigLayout(layC, colC, rowC)); // Makes the background gradient
+
+ // References to text fields not stored to reduce code clutter.
+
+ JScrollPane list2 = new JScrollPane(new JList(new String[] {"Mouse, Mickey"}));
+ panel.add(list2, new CC().spanY().growY().minWidth("150").gapX(null, "10"));
+
+ panel.add(new JLabel("Last Name"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("First Name"));
+ panel.add(new JTextField(), new CC().wrap().alignX("right"));
+ panel.add(new JLabel("Phone"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("Email"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("Address 1"));
+ panel.add(new JTextField(), new CC().spanX().growX());
+ panel.add(new JLabel("Address 2"));
+ panel.add(new JTextField(), new CC().spanX().growX());
+ panel.add(new JLabel("City"));
+ panel.add(new JTextField(), new CC().wrap());
+ panel.add(new JLabel("State"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("Postal Code"));
+ panel.add(new JTextField(10), new CC().spanX(2).growX(0));
+ panel.add(new JLabel("Country"));
+ panel.add(new JTextField(), new CC().wrap());
+
+ panel.add(new JButton("New"), new CC().spanX(5).split(5).tag("other"));
+ panel.add(new JButton("Delete"), new CC().tag("other"));
+ panel.add(new JButton("Edit"), new CC().tag("other"));
+ panel.add(new JButton("Save"), new CC().tag("other"));
+ panel.add(new JButton("Cancel"), new CC().tag("cancel"));
+
+ tabbedPane.addTab("Layout Showdown (improved)", panel);
+
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "LC layC = new LC().fill().wrap();\n" +
+ "AC colC = new AC().align(\"right\", 1).fill(2, 4).grow(100, 2, 4).align(\"right\", 3).gap(\"15\", 2);\n" +
+ "AC rowC = new AC().align(\"top\", 7).gap(\"15!\", 6).grow(100, 8);\n" +
+ "\n" +
+ "JPanel panel = createTabPanel(new MigLayout(layC, colC, rowC)); // Makes the background gradient\n" +
+ "\n" +
+ "// References to text fields not stored to reduce code clutter.\n" +
+ "\n" +
+ "JScrollPane list2 = new JScrollPane(new JList(new String[] {\"Mouse, Mickey\"}));\n" +
+ "panel.add(list2, new CC().spanY().growY().minWidth(\"150\").gapX(null, \"10\"));\n" +
+ "\n" +
+ "panel.add(new JLabel(\"Last Name\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"First Name\"));\n" +
+ "panel.add(new JTextField(), new CC().wrap().alignX(\"right\"));\n" +
+ "panel.add(new JLabel(\"Phone\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"Email\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"Address 1\"));\n" +
+ "panel.add(new JTextField(), new CC().spanX().growX());\n" +
+ "panel.add(new JLabel(\"Address 2\"));\n" +
+ "panel.add(new JTextField(), new CC().spanX().growX());\n" +
+ "panel.add(new JLabel(\"City\"));\n" +
+ "panel.add(new JTextField(), new CC().wrap());\n" +
+ "panel.add(new JLabel(\"State\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"Postal Code\"));\n" +
+ "panel.add(new JTextField(10), new CC().spanX(2).growX(0));\n" +
+ "panel.add(new JLabel(\"Country\"));\n" +
+ "panel.add(new JTextField(), new CC().wrap());\n" +
+ "\n" +
+ "panel.add(new JButton(\"New\"), new CC().spanX(5).split(5).tag(\"other\"));\n" +
+ "panel.add(new JButton(\"Delete\"), new CC().tag(\"other\"));\n" +
+ "panel.add(new JButton(\"Edit\"), new CC().tag(\"other\"));\n" +
+ "panel.add(new JButton(\"Save\"), new CC().tag(\"other\"));\n" +
+ "panel.add(new JButton(\"Cancel\"), new CC().tag(\"cancel\"));\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Layout Showdown (improved)\", panel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createAPI_Constraints2()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ LC layC = new LC().fill().wrap();
+ AC colC = new AC().align("right", 0).fill(1, 3).grow(100, 1, 3).align("right", 2).gap("15", 1);
+ AC rowC = new AC().index(6).gap("15!").align("top").grow(100, 8);
+
+ JPanel panel = createTabPanel(new MigLayout(layC, colC, rowC)); // Makes the background gradient
+
+ // References to text fields not stored to reduce code clutter.
+
+ panel.add(new JLabel("Last Name"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("First Name"));
+ panel.add(new JTextField(), new CC().wrap());
+ panel.add(new JLabel("Phone"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("Email"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("Address 1"));
+ panel.add(new JTextField(), new CC().spanX().growX());
+ panel.add(new JLabel("Address 2"));
+ panel.add(new JTextField(), new CC().spanX().growX());
+ panel.add(new JLabel("City"));
+ panel.add(new JTextField(), new CC().wrap());
+ panel.add(new JLabel("State"));
+ panel.add(new JTextField());
+ panel.add(new JLabel("Postal Code"));
+ panel.add(new JTextField(10), new CC().spanX(2).growX(0));
+ panel.add(new JLabel("Country"));
+ panel.add(new JTextField(), new CC().wrap());
+
+ panel.add(createButton("New"), new CC().spanX(5).split(5).tag("other"));
+ panel.add(createButton("Delete"), new CC().tag("other"));
+ panel.add(createButton("Edit"), new CC().tag("other"));
+ panel.add(createButton("Save"), new CC().tag("other"));
+ panel.add(createButton("Cancel"), new CC().tag("cancel"));
+
+ tabbedPane.addTab("Layout Showdown (improved)", panel);
+
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "LC layC = new LC().fill().wrap();\n" +
+ "AC colC = new AC().align(\"right\", 0).fill(1, 3).grow(100, 1, 3).align(\"right\", 2).gap(\"15\", 1);\n" +
+ "AC rowC = new AC().index(6).gap(\"15!\").align(\"top\").grow(100, 8);\n" +
+ "\n" +
+ "JPanel panel = createTabPanel(new MigLayout(layC, colC, rowC)); // Makes the background gradient\n" +
+ "\n" +
+ "// References to text fields not stored to reduce code clutter.\n" +
+ "\n" +
+ "panel.add(new JLabel(\"Last Name\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"First Name\"));\n" +
+ "panel.add(new JTextField(), new CC().wrap());\n" +
+ "panel.add(new JLabel(\"Phone\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"Email\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"Address 1\"));\n" +
+ "panel.add(new JTextField(), new CC().spanX().growX());\n" +
+ "panel.add(new JLabel(\"Address 2\"));\n" +
+ "panel.add(new JTextField(), new CC().spanX().growX());\n" +
+ "panel.add(new JLabel(\"City\"));\n" +
+ "panel.add(new JTextField(), new CC().wrap());\n" +
+ "panel.add(new JLabel(\"State\"));\n" +
+ "panel.add(new JTextField());\n" +
+ "panel.add(new JLabel(\"Postal Code\"));\n" +
+ "panel.add(new JTextField(10), new CC().spanX(2).growX(0));\n" +
+ "panel.add(new JLabel(\"Country\"));\n" +
+ "panel.add(new JTextField(), new CC().wrap());\n" +
+ "\n" +
+ "panel.add(createButton(\"New\"), new CC().spanX(5).split(5).tag(\"other\"));\n" +
+ "panel.add(createButton(\"Delete\"), new CC().tag(\"other\"));\n" +
+ "panel.add(createButton(\"Edit\"), new CC().tag(\"other\"));\n" +
+ "panel.add(createButton(\"Save\"), new CC().tag(\"other\"));\n" +
+ "panel.add(createButton(\"Cancel\"), new CC().tag(\"cancel\"));\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Layout Showdown (improved)\", panel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createLayout_Showdown()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ JPanel p = createTabPanel(new MigLayout("", "[]15[][grow,fill]15[grow]"));
+
+ JScrollPane list1 = new JScrollPane(new JList(new String[] {"Mouse, Mickey"}));
+
+ p.add(list1, "spany, growy, wmin 150");
+ p.add(new JLabel("Last Name"));
+ p.add(new JTextField());
+ p.add(new JLabel("First Name"), "split"); // split divides the cell
+ p.add(new JTextField(), "growx, wrap");
+ p.add(new JLabel("Phone"));
+ p.add(new JTextField());
+ p.add(new JLabel("Email"), "split");
+ p.add(new JTextField(), "growx, wrap");
+ p.add(new JLabel("Address 1"));
+ p.add(new JTextField(), "span, growx"); // span merges cells
+ p.add(new JLabel("Address 2"));
+ p.add(new JTextField(), "span, growx");
+ p.add(new JLabel("City"));
+ p.add(new JTextField(), "wrap"); // wrap continues on next line
+ p.add(new JLabel("State"));
+ p.add(new JTextField());
+ p.add(new JLabel("Postal Code"), "split");
+ p.add(new JTextField(), "growx, wrap");
+ p.add(new JLabel("Country"));
+ p.add(new JTextField(), "wrap 15");
+
+ p.add(createButton("New"), "span, split, align left");
+ p.add(createButton("Delete"), "");
+ p.add(createButton("Edit"), "");
+ p.add(createButton("Save"), "");
+ p.add(createButton("Cancel"), "wrap push");
+
+ tabbedPane.addTab("Layout Showdown (pure)", p);
+
+
+ // Fixed version *******************************************
+
+ JPanel p2 = createTabPanel(new MigLayout("", "[]15[][grow,fill]15[][grow,fill]")); // Makes the background gradient
+
+ // References to text fields not stored to reduce code clutter.
+
+ JScrollPane list2 = new JScrollPane(new JList(new String[] {"Mouse, Mickey"}));
+ p2.add(list2, "spany, growy, wmin 150");
+ p2.add(new JLabel("Last Name"));
+ p2.add(new JTextField());
+ p2.add(new JLabel("First Name"));
+ p2.add(new JTextField(), "wrap");
+ p2.add(new JLabel("Phone"));
+ p2.add(new JTextField());
+ p2.add(new JLabel("Email"));
+ p2.add(new JTextField(), "wrap");
+ p2.add(new JLabel("Address 1"));
+ p2.add(new JTextField(), "span");
+ p2.add(new JLabel("Address 2"));
+ p2.add(new JTextField(), "span");
+ p2.add(new JLabel("City"));
+ p2.add(new JTextField(), "wrap");
+ p2.add(new JLabel("State"));
+ p2.add(new JTextField());
+ p2.add(new JLabel("Postal Code"));
+ p2.add(new JTextField(10), "growx 0, wrap");
+ p2.add(new JLabel("Country"));
+ p2.add(new JTextField(), "wrap 15");
+
+ p2.add(createButton("New"), "tag other, span, split");
+ p2.add(createButton("Delete"), "tag other");
+ p2.add(createButton("Edit"), "tag other");
+ p2.add(createButton("Save"), "tag other");
+ p2.add(createButton("Cancel"), "tag cancel, wrap push");
+
+ tabbedPane.addTab("Layout Showdown (improved)", p2);
+
+
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "JPanel p = createTabPanel(new MigLayout(\"\", \"[]15[][grow,fill]15[grow]\"));\n" +
+ "\n" +
+ "JScrollPane list1 = new JScrollPane(new JList(new String[] {\"Mouse, Mickey\"}));\n" +
+ "\n" +
+ "p.add(list1, \"spany, growy, wmin 150\");\n" +
+ "p.add(new JLabel(\"Last Name\"));\n" +
+ "p.add(new JTextField());\n" +
+ "p.add(new JLabel(\"First Name\"), \"split\"); // split divides the cell\n" +
+ "p.add(new JTextField(), \"growx, wrap\");\n" +
+ "p.add(new JLabel(\"Phone\"));\n" +
+ "p.add(new JTextField());\n" +
+ "p.add(new JLabel(\"Email\"), \"split\");\n" +
+ "p.add(new JTextField(), \"growx, wrap\");\n" +
+ "p.add(new JLabel(\"Address 1\"));\n" +
+ "p.add(new JTextField(), \"span, growx\"); // span merges cells\n" +
+ "p.add(new JLabel(\"Address 2\"));\n" +
+ "p.add(new JTextField(), \"span, growx\");\n" +
+ "p.add(new JLabel(\"City\"));\n" +
+ "p.add(new JTextField(), \"wrap\"); // wrap continues on next line\n" +
+ "p.add(new JLabel(\"State\"));\n" +
+ "p.add(new JTextField());\n" +
+ "p.add(new JLabel(\"Postal Code\"), \"split\");\n" +
+ "p.add(new JTextField(), \"growx, wrap\");\n" +
+ "p.add(new JLabel(\"Country\"));\n" +
+ "p.add(new JTextField(), \"wrap 15\");\n" +
+ "\n" +
+ "p.add(createButton(\"New\"), \"span, split, align left\");\n" +
+ "p.add(createButton(\"Delete\"), \"\");\n" +
+ "p.add(createButton(\"Edit\"), \"\");\n" +
+ "p.add(createButton(\"Save\"), \"\");\n" +
+ "p.add(createButton(\"Cancel\"), \"wrap push\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Layout Showdown (pure)\", p);" +
+ "\n" +
+ "\t\t// Fixed version *******************************************\n" +
+ "JPanel p2 = createTabPanel(new MigLayout(\"\", \"[]15[][grow,fill]15[][grow,fill]\")); // Makes the background gradient\n" +
+ "\n" +
+ "// References to text fields not stored to reduce code clutter.\n" +
+ "\n" +
+ "JScrollPane list2 = new JScrollPane(new JList(new String[] {\"Mouse, Mickey\"}));\n" +
+ "p2.add(list2, \"spany, growy, wmin 150\");\n" +
+ "p2.add(new JLabel(\"Last Name\"));\n" +
+ "p2.add(new JTextField());\n" +
+ "p2.add(new JLabel(\"First Name\"));\n" +
+ "p2.add(new JTextField(), \"wrap\");\n" +
+ "p2.add(new JLabel(\"Phone\"));\n" +
+ "p2.add(new JTextField());\n" +
+ "p2.add(new JLabel(\"Email\"));\n" +
+ "p2.add(new JTextField(), \"wrap\");\n" +
+ "p2.add(new JLabel(\"Address 1\"));\n" +
+ "p2.add(new JTextField(), \"span\");\n" +
+ "p2.add(new JLabel(\"Address 2\"));\n" +
+ "p2.add(new JTextField(), \"span\");\n" +
+ "p2.add(new JLabel(\"City\"));\n" +
+ "p2.add(new JTextField(), \"wrap\");\n" +
+ "p2.add(new JLabel(\"State\"));\n" +
+ "p2.add(new JTextField());\n" +
+ "p2.add(new JLabel(\"Postal Code\"));\n" +
+ "p2.add(new JTextField(10), \"growx 0, wrap\");\n" +
+ "p2.add(new JLabel(\"Country\"));\n" +
+ "p2.add(new JTextField(), \"wrap 15\");\n" +
+ "\n" +
+ "p2.add(createButton(\"New\"), \"tag other, span, split\");\n" +
+ "p2.add(createButton(\"Delete\"), \"tag other\");\n" +
+ "p2.add(createButton(\"Edit\"), \"tag other\");\n" +
+ "p2.add(createButton(\"Save\"), \"tag other\");\n" +
+ "p2.add(createButton(\"Cancel\"), \"tag cancel, wrap push\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Layout Showdown (improved)\", p2);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createWelcome()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ MigLayout lm = new MigLayout("ins 20, fill", "", "[grow]unrel[]");
+
+ JPanel mainPanel = createTabPanel(lm);
+
+ String s = "MigLayout's main purpose is to make layouts for SWT and Swing, and possibly other frameworks, much more powerful and a lot easier to create, especially for manual coding.\n\n" +
+ "The motto is: \"MigLayout makes complex layouts easy and normal layouts one-liners.\"\n\n" +
+ "The layout engine is very flexible and advanced, something that is needed to make it simple to use yet handle almost all layout use-cases.\n\n" +
+ "MigLayout can handle all layouts that the commonly used Swing Layout Managers can handle and this with a lot of extra features. " +
+ "It also incorporates most, if not all, of the open source alternatives FormLayout's and TableLayout's functionality." +
+ "\n\n\nThanks to Karsten Lentzsch of JGoodies.com for allowing the reuse of the main demo application layout and for his inspiring talks that led to this layout Manager." +
+ "\n\n\nMikael Grev\n" +
+ "MiG InfoCom AB\n" +
+ "miglayout@miginfocom.com";
+
+ JTextArea textArea = new JTextArea(s);
+ textArea.setEditable(false);
+ textArea.setSize(400, 400);
+
+ if (PlatformDefaults.getCurrentPlatform() == PlatformDefaults.WINDOWS_XP)
+ textArea.setFont(new Font("tahoma", Font.BOLD, 11));
+
+ textArea.setOpaque(OPAQUE);
+ textArea.setWrapStyleWord(true);
+ textArea.setLineWrap(true);
+
+ JLabel label = new JLabel("You can Right Click any Component or Container to change the constraints for it!");
+ label.setForeground(new Color(200, 0, 0));
+
+ mainPanel.add(textArea, "w 500:pref,ay top,grow,wrap");
+ mainPanel.add(label, "growx");
+ label.setFont(label.getFont().deriveFont(Font.BOLD));
+
+ tabbedPane.addTab("Welcome", mainPanel);
+
+ setSource("");
+
+ return tabbedPane;
+ }
+
+ public JComponent createVisual_Bounds()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // "NON"-corrected bounds
+ JPanel p1 = createTabPanel(new MigLayout("fill, ins 3, novisualpadding"));
+ p1.setBorder(new LineBorder(Color.BLACK));
+
+ JTabbedPane demoPane2 = new JTabbedPane();
+ JPanel demoPanel2 = new JPanel();
+ demoPanel2.setBackground(Color.WHITE);
+ demoPane2.addTab("Demo Tab", demoPanel2);
+
+ p1.add(createTextArea("A JTextArea", 1, 100), "grow, aligny bottom, wmin 100");
+ p1.add(demoPane2, "grow, aligny bottom");
+ p1.add(createTextField("A JTextField", 100), "grow, aligny bottom, wmin 100");
+ p1.add(createTextArea("A JTextArea", 1, 100), "newline,grow, aligny bottom, wmin 100");
+ p1.add(createTextArea("A JTextArea", 1, 100), "grow, aligny bottom, wmin 100");
+ p1.add(createTextArea("A JTextArea", 1, 100), "grow, aligny bottom, wmin 100");
+
+ JPanel p2 = createTabPanel(new MigLayout("center,center,fill,ins 3"));
+ p2.setBorder(new LineBorder(Color.BLACK));
+
+ JTabbedPane demoPane = new JTabbedPane();
+ JPanel demoPanel = new JPanel();
+ demoPanel.setBackground(Color.WHITE);
+ demoPane.addTab("Demo Tab", demoPanel);
+
+ p2.add(createTextArea("A JTextArea", 1, 100), "grow, aligny bottom, wmin 100");
+ p2.add(demoPane, "grow, aligny bottom");
+ p2.add(createTextField("A JTextField", 100), "grow, aligny bottom, wmin 100");
+ p2.add(createTextArea("A JTextArea", 1, 100), "newline,grow, aligny bottom, wmin 100");
+ p2.add(createTextArea("A JTextArea", 1, 100), "grow, aligny bottom, wmin 100");
+ p2.add(createTextArea("A JTextArea", 1, 100), "grow, aligny bottom, wmin 100");
+
+ tabbedPane.addTab("Visual Bounds (Not Corrected)", p1);
+ tabbedPane.addTab("Visual Bounds (Corrected on XP)", p2);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// \"NON\"-corrected bounds\n" +
+ "JPanel p1 = createTabPanel(new MigLayout(\"fill, ins 3, novisualpadding\"));\n" +
+ "p1.setBorder(new LineBorder(Color.BLACK));\n" +
+ "\n" +
+ "JTabbedPane demoPane2 = new JTabbedPane();\n" +
+ "JPanel demoPanel2 = new JPanel();\n" +
+ "demoPanel2.setBackground(Color.WHITE);\n" +
+ "demoPane2.addTab(\"Demo Tab\", demoPanel2);\n" +
+ "\n" +
+ "p1.add(createTextArea(\"A JTextArea\", 1, 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "p1.add(demoPane2, \"grow, aligny bottom\");\n" +
+ "p1.add(createTextField(\"A JTextField\", 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "p1.add(createTextArea(\"A JTextArea\", 1, 100), \"newline,grow, aligny bottom, wmin 100\");\n" +
+ "p1.add(createTextArea(\"A JTextArea\", 1, 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "p1.add(createTextArea(\"A JTextArea\", 1, 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "\n" +
+ "JPanel p2 = createTabPanel(new MigLayout(\"center,center,fill,ins 3\"));\n" +
+ "p2.setBorder(new LineBorder(Color.BLACK));\n" +
+ "\n" +
+ "JTabbedPane demoPane = new JTabbedPane();\n" +
+ "JPanel demoPanel = new JPanel();\n" +
+ "demoPanel.setBackground(Color.WHITE);\n" +
+ "demoPane.addTab(\"Demo Tab\", demoPanel);\n" +
+ "\n" +
+ "p2.add(createTextArea(\"A JTextArea\", 1, 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "p2.add(demoPane, \"grow, aligny bottom\");\n" +
+ "p2.add(createTextField(\"A JTextField\", 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "p2.add(createTextArea(\"A JTextArea\", 1, 100), \"newline,grow, aligny bottom, wmin 100\");\n" +
+ "p2.add(createTextArea(\"A JTextArea\", 1, 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "p2.add(createTextArea(\"A JTextArea\", 1, 100), \"grow, aligny bottom, wmin 100\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Visual Bounds (Not Corrected)\", p1);\n" +
+ "tabbedPane.addTab(\"Visual Bounds (Corrected on XP)\", p2);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createDocking()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ JPanel p1 = createTabPanel(new MigLayout("fill"));
+
+ p1.add(createPanel("1. North"), "north");
+ p1.add(createPanel("2. West"), "west");
+ p1.add(createPanel("3. East"), "east");
+ p1.add(createPanel("4. South"), "south");
+
+ String[][] data = new String[20][6];
+ for (int r = 0; r < data.length; r++) {
+ data[r] = new String[6];
+ for (int c = 0; c < data[r].length; c++)
+ data[r][c] = "Cell " + (r + 1) + ", " + (c + 1);
+ }
+ JTable table = new JTable(data, new String[] {"Column 1", "Column 2", "Column 3", "Column 4", "Column 5", "Column 6"});
+ p1.add(new JScrollPane(table), "grow");
+
+ JPanel p2 = createTabPanel(new MigLayout("fill", "[c]", ""));
+
+ p2.add(createPanel("1. North"), "north");
+ p2.add(createPanel("2. North"), "north");
+ p2.add(createPanel("3. West"), "west");
+ p2.add(createPanel("4. West"), "west");
+ p2.add(createPanel("5. South"), "south");
+ p2.add(createPanel("6. East"), "east");
+ p2.add(createButton("7. Normal"));
+ p2.add(createButton("8. Normal"));
+ p2.add(createButton("9. Normal"));
+
+ JPanel p3 = createTabPanel(new MigLayout());
+
+ p3.add(createPanel("1. North"), "north");
+ p3.add(createPanel("2. South"), "south");
+ p3.add(createPanel("3. West"), "west");
+ p3.add(createPanel("4. East"), "east");
+ p3.add(createButton("5. Normal"));
+
+ JPanel p4 = createTabPanel(new MigLayout());
+
+ p4.add(createPanel("1. North"), "north");
+ p4.add(createPanel("2. North"), "north");
+ p4.add(createPanel("3. West"), "west");
+ p4.add(createPanel("4. West"), "west");
+ p4.add(createPanel("5. South"), "south");
+ p4.add(createPanel("6. East"), "east");
+ p4.add(createButton("7. Normal"));
+ p4.add(createButton("8. Normal"));
+ p4.add(createButton("9. Normal"));
+
+ JPanel p5 = createTabPanel(new MigLayout("fillx", "[c]", ""));
+
+ p5.add(createPanel("1. North"), "north");
+ p5.add(createPanel("2. North"), "north");
+ p5.add(createPanel("3. West"), "west");
+ p5.add(createPanel("4. West"), "west");
+ p5.add(createPanel("5. South"), "south");
+ p5.add(createPanel("6. East"), "east");
+ p5.add(createButton("7. Normal"));
+ p5.add(createButton("8. Normal"));
+ p5.add(createButton("9. Normal"));
+
+ JPanel p6 = createTabPanel(new MigLayout("fill", "", ""));
+
+ Random rand = new Random();
+ String[] sides = {"north", "east", "south", "west"};
+ for (int i = 0; i < 20; i++) {
+ int side = rand.nextInt(4);
+ p6.add(createPanel((i + 1) + " " + sides[side]), sides[side]);
+ }
+ p6.add(createPanel("I'm in the Center!"), "dock center");
+
+ tabbedPane.addTab("Docking 1 (fill)", p1);
+ tabbedPane.addTab("Docking 2 (fill)", p2);
+ tabbedPane.addTab("Docking 3", p3);
+ tabbedPane.addTab("Docking 4", p4);
+ tabbedPane.addTab("Docking 5 (fillx)", p5);
+ tabbedPane.addTab("Random Docking", new JScrollPane(p6));
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "JPanel p1 = createTabPanel(new MigLayout(\"fill\"));\n" +
+ "\n" +
+ "p1.add(createPanel(\"1. North\"), \"north\");\n" +
+ "p1.add(createPanel(\"2. West\"), \"west\");\n" +
+ "p1.add(createPanel(\"3. East\"), \"east\");\n" +
+ "p1.add(createPanel(\"4. South\"), \"south\");\n" +
+ "\n" +
+ "String[][] data = new String[20][6];\n" +
+ "for (int r = 0; r < data.length; r++) {\n" +
+ "\tdata[r] = new String[6];\n" +
+ "\tfor (int c = 0; c < data[r].length; c++)\n" +
+ "\t\tdata[r][c] = \"Cell \" + (r + 1) + \", \" + (c + 1);\n" +
+ "}\n" +
+ "JTable table = new JTable(data, new String[] {\"Column 1\", \"Column 2\", \"Column 3\", \"Column 4\", \"Column 5\", \"Column 6\"});\n" +
+ "p1.add(new JScrollPane(table), \"grow\");\n" +
+ "\n" +
+ "JPanel p2 = createTabPanel(new MigLayout(\"fill\", \"[c]\", \"\"));\n" +
+ "\n" +
+ "p2.add(createPanel(\"1. North\"), \"north\");\n" +
+ "p2.add(createPanel(\"2. North\"), \"north\");\n" +
+ "p2.add(createPanel(\"3. West\"), \"west\");\n" +
+ "p2.add(createPanel(\"4. West\"), \"west\");\n" +
+ "p2.add(createPanel(\"5. South\"), \"south\");\n" +
+ "p2.add(createPanel(\"6. East\"), \"east\");\n" +
+ "p2.add(createButton(\"7. Normal\"));\n" +
+ "p2.add(createButton(\"8. Normal\"));\n" +
+ "p2.add(createButton(\"9. Normal\"));\n" +
+ "\n" +
+ "JPanel p3 = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "p3.add(createPanel(\"1. North\"), \"north\");\n" +
+ "p3.add(createPanel(\"2. South\"), \"south\");\n" +
+ "p3.add(createPanel(\"3. West\"), \"west\");\n" +
+ "p3.add(createPanel(\"4. East\"), \"east\");\n" +
+ "p3.add(createButton(\"5. Normal\"));\n" +
+ "\n" +
+ "JPanel p4 = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "p4.add(createPanel(\"1. North\"), \"north\");\n" +
+ "p4.add(createPanel(\"2. North\"), \"north\");\n" +
+ "p4.add(createPanel(\"3. West\"), \"west\");\n" +
+ "p4.add(createPanel(\"4. West\"), \"west\");\n" +
+ "p4.add(createPanel(\"5. South\"), \"south\");\n" +
+ "p4.add(createPanel(\"6. East\"), \"east\");\n" +
+ "p4.add(createButton(\"7. Normal\"));\n" +
+ "p4.add(createButton(\"8. Normal\"));\n" +
+ "p4.add(createButton(\"9. Normal\"));\n" +
+ "\n" +
+ "JPanel p5 = createTabPanel(new MigLayout(\"fillx\", \"[c]\", \"\"));\n" +
+ "\n" +
+ "p5.add(createPanel(\"1. North\"), \"north\");\n" +
+ "p5.add(createPanel(\"2. North\"), \"north\");\n" +
+ "p5.add(createPanel(\"3. West\"), \"west\");\n" +
+ "p5.add(createPanel(\"4. West\"), \"west\");\n" +
+ "p5.add(createPanel(\"5. South\"), \"south\");\n" +
+ "p5.add(createPanel(\"6. East\"), \"east\");\n" +
+ "p5.add(createButton(\"7. Normal\"));\n" +
+ "p5.add(createButton(\"8. Normal\"));\n" +
+ "p5.add(createButton(\"9. Normal\"));\n" +
+ "\n" +
+ "JPanel p6 = createTabPanel(new MigLayout(\"fill\", \"\", \"\"));\n" +
+ "\n" +
+ "Random rand = new Random();\n" +
+ "String[] sides = {\"north\", \"east\", \"south\", \"west\"};\n" +
+ "for (int i = 0; i < 20; i++) {\n" +
+ "\tint side = rand.nextInt(4);\n" +
+ "\tp6.add(createPanel((i + 1) + \" \" + sides[side]), sides[side]);\n" +
+ "}\n" +
+ "p6.add(createButton(\"I'm in the middle!\"), \"grow\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Docking 1 (fill)\", p1);\n" +
+ "tabbedPane.addTab(\"Docking 2 (fill)\", p2);\n" +
+ "tabbedPane.addTab(\"Docking 3\", p3);\n" +
+ "tabbedPane.addTab(\"Docking 4\", p4);\n" +
+ "tabbedPane.addTab(\"Docking 5 (fillx)\", p5);\n" +
+ "tabbedPane.addTab(\"Docking Spiral\", new JScrollPane(p6));");
+
+ return tabbedPane;
+ }
+
+ public JComponent createAbsolute_Position()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Pos tab
+ final JPanel posPanel = createTabPanel(new MigLayout());
+
+ posPanel.add(createButton(), "pos 0.5al 0al");
+ posPanel.add(createButton(), "pos 1al 0al");
+ posPanel.add(createButton(), "pos 0.5al 0.5al");
+ posPanel.add(createButton(), "pos 5in 45lp");
+ posPanel.add(createButton(), "pos 0.5al 0.5al");
+ posPanel.add(createButton(), "pos 0.5al 1.0al");
+ posPanel.add(createButton(), "pos 1al .25al");
+ posPanel.add(createButton(), "pos visual.x2-pref visual.y2-pref");
+ posPanel.add(createButton(), "pos 1al -1in");
+ posPanel.add(createButton(), "pos 100 100");
+ posPanel.add(createButton(), "pos (10+(20*3lp)) 200");
+ posPanel.add(createButton("Drag Window! (pos 500-container.xpos 500-container.ypos)"),
+ "pos 500-container.xpos 500-container.ypos");
+
+ // Bounds tab
+ JPanel boundsPanel = createTabPanel(new MigLayout());
+
+ String constr = "pos (visual.x+visual.w*0.1) visual.y2-40 (visual.x2-visual.w*0.1) visual.y2";
+ JLabel southLabel = createLabel(constr, SwingConstants.CENTER);
+ southLabel.setBorder(new LineBorder(Color.LIGHT_GRAY, 1));
+ southLabel.setBackground(new Color(200, 200, 255, benchRuns == 0 ? 70 : 255));
+ southLabel.setOpaque(true);
+ southLabel.setFont(southLabel.getFont().deriveFont(Font.BOLD));
+ boundsPanel.add(southLabel, constr);
+
+ boundsPanel.add(createButton(), "pos 0 0 container.x2 n");
+ boundsPanel.add(createButton(), "pos visual.x 40 visual.x2 70");
+ boundsPanel.add(createButton(), "pos visual.x 100 visual.x2 p");
+ boundsPanel.add(createButton(), "pos 0.1al 0.4al n (visual.y2 - 10)");
+ boundsPanel.add(createButton(), "pos 0.9al 0.4al n visual.y2-10");
+ boundsPanel.add(createButton(), "pos 0.5al 0.5al, pad 3 0 -3 0");
+ boundsPanel.add(createButton(), "pos n n 50% 50%");
+ boundsPanel.add(createButton(), "pos 50% 50% n n");
+ boundsPanel.add(createButton(), "pos 50% n n 50%");
+ boundsPanel.add(createButton(), "pos n 50% 50% n");
+
+ tabbedPane.addTab("X Y Positions", posPanel);
+ tabbedPane.addTab("X1 Y1 X2 Y2 Bounds", boundsPanel);
+
+ // Glass pane tab
+ if (benchRuns == 0) {
+ final JPanel glassPanel = createTabPanel(new MigLayout("align c c, ins 0"));
+ final JButton butt = createButton("Press me!!");
+ glassPanel.add(butt);
+
+ butt.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ butt.setEnabled(false);
+ final JPanel bg = new JPanel(new MigLayout("align c c,fill")) {
+ public void paint(Graphics g)
+ {
+ g.setColor(getBackground());
+ g.fillRect(0, 0, getWidth(), getHeight());
+ super.paint(g);
+ }
+ };
+ bg.setOpaque(OPAQUE);
+ configureActiveComponet(bg);
+
+ final JLabel label = createLabel("You don't need a GlassPane to be cool!");
+ label.setFont(label.getFont().deriveFont(30f));
+ label.setForeground(new Color(255, 255, 255, 0));
+ bg.add(label, "align 50% 30%");
+
+ glassPanel.add(bg, "pos visual.x visual.y visual.x2 visual.y2", 0);
+ final long startTime = System.nanoTime();
+ final long endTime = startTime + 500000000L;
+
+ glassPanel.revalidate();
+
+ final javax.swing.Timer timer = new Timer(25, null);
+
+ timer.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ long now = System.nanoTime();
+ int alpha = (int) (((now - startTime) / (double) (endTime - startTime)) * 300);
+ if (alpha < 150)
+ bg.setBackground(new Color(100, 100, 100, alpha));
+
+ if (alpha > 150 && alpha < 405) {
+ label.setForeground(new Color(255, 255, 255, (alpha - 150)));
+ bg.repaint();
+ }
+ if (alpha > 405)
+ timer.stop();
+ }
+ });
+ timer.start();
+ }
+ });
+ tabbedPane.addTab("GlassPane Substitute", glassPanel);
+ addComponentListener(new ComponentAdapter() {
+ public void componentMoved(ComponentEvent e) {
+ if (posPanel.isDisplayable()) {
+ posPanel.revalidate();
+ } else {
+ removeComponentListener(this);
+ }
+ }
+ });
+ }
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// Pos tab\n" +
+ "final JPanel posPanel = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "posPanel.add(createButton(), \"pos 0.5al 0al\");\n" +
+ "posPanel.add(createButton(), \"pos 1al 0al\");\n" +
+ "posPanel.add(createButton(), \"pos 0.5al 0.5al\");\n" +
+ "posPanel.add(createButton(), \"pos 5in 45lp\");\n" +
+ "posPanel.add(createButton(), \"pos 0.5al 0.5al\");\n" +
+ "posPanel.add(createButton(), \"pos 0.5al 1.0al\");\n" +
+ "posPanel.add(createButton(), \"pos 1al .25al\");\n" +
+ "posPanel.add(createButton(), \"pos visual.x2-pref visual.y2-pref\");\n" +
+ "posPanel.add(createButton(), \"pos 1al -1in\");\n" +
+ "posPanel.add(createButton(), \"pos 100 100\");\n" +
+ "posPanel.add(createButton(), \"pos (10+(20*3lp)) 200\");\n" +
+ "posPanel.add(createButton(\"Drag Window! (pos 500-container.xpos 500-container.ypos)\"),\n" +
+ " \"pos 500-container.xpos 500-container.ypos\");\n" +
+ "\n" +
+ "// Bounds tab\n" +
+ "JPanel boundsPanel = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "String constr = \"pos (visual.x+visual.w*0.1) visual.y2-40 (visual.x2-visual.w*0.1) visual.y2\";\n" +
+ "JLabel southLabel = createLabel(constr, SwingConstants.CENTER);\n" +
+ "southLabel.setBorder(new LineBorder(Color.LIGHT_GRAY, 1));\n" +
+ "southLabel.setBackground(new Color(200, 200, 255, 70));\n" +
+ "southLabel.setOpaque(true);\n" +
+ "southLabel.setFont(southLabel.getFont().deriveFont(Font.BOLD));\n" +
+ "boundsPanel.add(southLabel, constr);\n" +
+ "\n" +
+ "boundsPanel.add(createButton(), \"pos 0 0 container.x2 n\");\n" +
+ "boundsPanel.add(createButton(), \"pos visual.x 40 visual.x2 70\");\n" +
+ "boundsPanel.add(createButton(), \"pos visual.x 100 visual.x2 p\");\n" +
+ "boundsPanel.add(createButton(), \"pos 0.1al 0.4al n visual.y2-10\");\n" +
+ "boundsPanel.add(createButton(), \"pos 0.9al 0.4al n visual.y2-10\");\n" +
+ "boundsPanel.add(createButton(), \"pos 0.5al 0.5al, pad 3 0 -3 0\");\n" +
+ "boundsPanel.add(createButton(), \"pos n n 50% 50%\");\n" +
+ "boundsPanel.add(createButton(), \"pos 50% 50% n n\");\n" +
+ "boundsPanel.add(createButton(), \"pos 50% n n 50%\");\n" +
+ "boundsPanel.add(createButton(), \"pos n 50% 50% n\");\n" +
+ "\n" +
+ "// Glass pane tab\n" +
+ "final JPanel glassPanel = createTabPanel(new MigLayout(\"align c c, ins 0\"));\n" +
+ "final JButton butt = createButton(\"Press me!!\");\n" +
+ "glassPanel.add(butt);\n" +
+ "\n" +
+ "butt.addActionListener(new ActionListener()\t\t{\n" +
+ "\tpublic void actionPerformed(ActionEvent e)\n" +
+ "\t{\n" +
+ "\t\tbutt.setEnabled(false);\n" +
+ "\t\tfinal JPanel bg = new JPanel(new MigLayout(\"align c c,fill\")) {\n" +
+ "\t\t\tpublic void paint(Graphics g)\n" +
+ "\t\t\t{\n" +
+ "\t\t\t\tg.setColor(getBackground());\n" +
+ "\t\t\t\tg.fillRect(0, 0, getWidth(), getHeight());\n" +
+ "\t\t\t\tsuper.paint(g);\n" +
+ "\t\t\t}\n" +
+ "\t\t};\n" +
+ "\t\tbg.setOpaque(OPAQUE);\n" +
+ "\t\tconfigureActiveComponet(bg);\n" +
+ "\n" +
+ "\t\tfinal JLabel label = createLabel(\"You don't need a GlassPane to be cool!\");\n" +
+ "\t\tlabel.setFont(label.getFont().deriveFont(30f));\n" +
+ "\t\tlabel.setForeground(new Color(255, 255, 255, 0));\n" +
+ "\t\tbg.add(label, \"align 50% 30%\");\n" +
+ "\n" +
+ "\t\tglassPanel.add(bg, \"pos visual.x visual.y visual.x2 visual.y2\", 0);\n" +
+ "\t\tfinal long startTime = System.nanoTime();\n" +
+ "\t\tfinal long endTime = startTime + 500000000L;\n" +
+ "\n" +
+ "\t\tglassPanel.revalidate();\n" +
+ "\n" +
+ "\t\tfinal javax.swing.Timer timer = new Timer(25, null);\n" +
+ "\n" +
+ "\t\ttimer.addActionListener(new ActionListener() {\n" +
+ "\t\t\tpublic void actionPerformed(ActionEvent e)\n" +
+ "\t\t\t{\n" +
+ "\t\t\t\tlong now = System.nanoTime();\n" +
+ "\t\t\t\tint alpha = (int) (((now - startTime) / (double) (endTime - startTime)) * 300);\n" +
+ "\t\t\t\tif (alpha < 150)\n" +
+ "\t\t\t\t\tbg.setBackground(new Color(100, 100, 100, alpha));\n" +
+ "\n" +
+ "\t\t\t\tif (alpha > 150 && alpha < 405) {\n" +
+ "\t\t\t\t\tlabel.setForeground(new Color(255, 255, 255, (alpha - 150)));\n" +
+ "\t\t\t\t\tbg.repaint();\n" +
+ "\t\t\t\t}\n" +
+ "\t\t\t\tif (alpha > 405)\n" +
+ "\t\t\t\t\ttimer.stop();\n" +
+ "\t\t\t}\n" +
+ "\t\t});\n" +
+ "\t\ttimer.start();\n" +
+ "\t}\n" +
+ "});\n" +
+ "\n" +
+ "tabbedPane.addTab(\"X Y Positions\", posPanel);\n" +
+ "tabbedPane.addTab(\"X1 Y1 X2 Y2 Bounds\", boundsPanel);\n" +
+ "tabbedPane.addTab(\"GlassPane Substitute\", glassPanel);\n" +
+ "\n" +
+ "addComponentListener(new ComponentAdapter() {\n" +
+ "\tpublic void componentMoved(ComponentEvent e) {\n" +
+ "\t\tif (posPanel.isDisplayable()) {\n" +
+ "\t\t\tposPanel.revalidate();\n" +
+ "\t\t} else {\n" +
+ "\t\t\tremoveComponentListener(this);\n" +
+ "\t\t}\n" +
+ "\t}\n" +
+ "});");
+
+ return tabbedPane;
+ }
+
+ public JComponent createComponent_Links()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ JPanel linksPanel = createTabPanel(new MigLayout());
+
+ // Links tab
+ JButton mini = createButton("Mini");
+ mini.setMargin(new Insets(0, 1, 0, 1));
+ linksPanel.add(mini, "pos null ta.y ta.x2 null");
+ linksPanel.add(createTextArea("Components, Please Link to Me!\nMy ID is: 'ta'", 3, 30), "id ta, pos 0.5al 0.5al");
+ linksPanel.add(createButton(), "id b1,pos ta.x2 ta.y2");
+ linksPanel.add(createButton(), "pos b1.x2+rel b1.y visual.x2 null");
+ linksPanel.add(createButton(), "pos ta.x2+rel ta.y visual.x2 null");
+ linksPanel.add(createButton(), "pos null ta.y+(ta.h-pref)/2 ta.x-rel null");
+ linksPanel.add(createButton(), "pos ta.x ta.y2+100 ta.x2 null");
+ linksPanel.add(createCheck("pos (ta.x+indent) (ta.y2+rel)"),
+ "pos (ta.x+indent) (ta.y2+rel)");
+
+ // External tab
+ JPanel externalPanel = createTabPanel(new MigLayout());
+
+ JButton extButt = createButton("Bounds Externally Set!");
+ extButt.setBounds(250, 130, 200, 40);
+ externalPanel.add(extButt, "id ext, external");
+ externalPanel.add(createButton(), "pos ext.x2 ext.y2");
+ externalPanel.add(createButton(), "pos null null ext.x ext.y");
+
+ // Start/End Group tab
+ JPanel egPanel = createTabPanel(new MigLayout());
+
+ egPanel.add(createButton(), "id b1, endgroupx g1, pos 200 200");
+ egPanel.add(createButton(), "id b2, endgroupx g1, pos (b1.x+2ind) (b1.y2+rel)");
+ egPanel.add(createButton(), "id b3, endgroupx g1, pos (b1.x+4ind) (b2.y2+rel)");
+ egPanel.add(createButton(), "id b4, endgroupx g1, pos (b1.x+6ind) (b3.y2+rel)");
+
+ // Group Bounds tab
+ JPanel gpPanel = createTabPanel(new MigLayout());
+
+ gpPanel.add(createButton(), "id grp1.b1, pos n 0.5al 50% n");
+ gpPanel.add(createButton(), "id grp1.b2, pos 50% 0.5al n n");
+ gpPanel.add(createButton(), "id grp1.b3, pos 0.5al n n b1.y");
+ gpPanel.add(createButton(), "id grp1.b4, pos 0.5al b1.y2 n n");
+
+ gpPanel.add(createButton(), "pos n grp1.y2 grp1.x n");
+ gpPanel.add(createButton(), "pos n n grp1.x grp1.y");
+ gpPanel.add(createButton(), "pos grp1.x2 n n grp1.y");
+ gpPanel.add(createButton(), "pos grp1.x2 grp1.y2");
+
+ JPanel boundsPanel = new JPanel(null);
+ boundsPanel.setBackground(new Color(200, 200, 255));
+ gpPanel.add(boundsPanel, "pos grp1.x grp1.y grp1.x2 grp1.y2");
+
+
+ tabbedPane.addTab("Component Links", linksPanel);
+ tabbedPane.addTab("External Components", externalPanel);
+ tabbedPane.addTab("End Grouping", egPanel);
+ tabbedPane.addTab("Group Bounds", gpPanel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "JPanel linksPanel = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "// Links tab\n" +
+ "JButton mini = createButton(\"Mini\");\n" +
+ "mini.setMargin(new Insets(0, 1, 0, 1));\n" +
+ "linksPanel.add(mini, \"pos null ta.y ta.x2 null\");\n" +
+ "linksPanel.add(createTextArea(\"Components, Please Link to Me!\\nMy ID is: 'ta'\", 3, 30), \"id ta, pos 0.5al 0.5al\");\n" +
+ "linksPanel.add(createButton(), \"id b1,pos ta.x2 ta.y2\");\n" +
+ "linksPanel.add(createButton(), \"pos b1.x2+rel b1.y visual.x2 null\");\n" +
+ "linksPanel.add(createButton(), \"pos ta.x2+rel ta.y visual.x2 null\");\n" +
+ "linksPanel.add(createButton(), \"pos null ta.y+(ta.h-pref)/2 ta.x-rel null\");\n" +
+ "linksPanel.add(createButton(), \"pos ta.x ta.y2+100 ta.x2 null\");\n" +
+ "linksPanel.add(createCheck(\"pos (ta.x+indent) (ta.y2+rel)\"),\n" +
+ " \"pos (ta.x+indent) (ta.y2+rel)\");\n" +
+ "\n" +
+ "// External tab\n" +
+ "JPanel externalPanel = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "JButton extButt = createButton(\"Bounds Externally Set!\");\n" +
+ "extButt.setBounds(250, 130, 200, 40);\n" +
+ "externalPanel.add(extButt, \"id ext, external\");\n" +
+ "externalPanel.add(createButton(), \"pos ext.x2 ext.y2\");\n" +
+ "externalPanel.add(createButton(), \"pos null null ext.x ext.y\");\n" +
+ "\n" +
+ "// Start/End Group tab\n" +
+ "JPanel egPanel = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "egPanel.add(createButton(), \"id b1, endgroupx g1, pos 200 200\");\n" +
+ "egPanel.add(createButton(), \"id b2, endgroupx g1, pos (b1.x+2ind) (b1.y2+rel)\");\n" +
+ "egPanel.add(createButton(), \"id b3, endgroupx g1, pos (b1.x+4ind) (b2.y2+rel)\");\n" +
+ "egPanel.add(createButton(), \"id b4, endgroupx g1, pos (b1.x+6ind) (b3.y2+rel)\");\n" +
+ "\n" +
+ "// Group Bounds tab\n" +
+ "JPanel gpPanel = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "gpPanel.add(createButton(), \"id grp1.b1, pos n 0.5al 50% n\");\n" +
+ "gpPanel.add(createButton(), \"id grp1.b2, pos 50% 0.5al n n\");\n" +
+ "gpPanel.add(createButton(), \"id grp1.b3, pos 0.5al n n b1.y\");\n" +
+ "gpPanel.add(createButton(), \"id grp1.b4, pos 0.5al b1.y2 n n\");\n" +
+ "\n" +
+ "gpPanel.add(createButton(), \"pos n grp1.y2 grp1.x n\");\n" +
+ "gpPanel.add(createButton(), \"pos n n grp1.x grp1.y\");\n" +
+ "gpPanel.add(createButton(), \"pos grp1.x2 n n grp1.y\");\n" +
+ "gpPanel.add(createButton(), \"pos grp1.x2 grp1.y2\");\n" +
+ "\n" +
+ "JPanel boundsPanel = new JPanel(null);\n" +
+ "boundsPanel.setBackground(new Color(200, 200, 255));\n" +
+ "gpPanel.add(boundsPanel, \"pos grp1.x grp1.y grp1.x2 grp1.y2\");\n" +
+ "\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Component Links\", linksPanel);\n" +
+ "tabbedPane.addTab(\"External Components\", externalPanel);\n" +
+ "tabbedPane.addTab(\"End Grouping\", egPanel);\n" +
+ "tabbedPane.addTab(\"Group Bounds\", gpPanel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createFlow_Direction()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ tabbedPane.addTab("Layout: flowx, Cell: flowx", createFlowPanel("", "flowx"));
+ tabbedPane.addTab("Layout: flowx, Cell: flowy", createFlowPanel("", "flowy"));
+ tabbedPane.addTab("Layout: flowy, Cell: flowx", createFlowPanel("flowy", "flowx"));
+ tabbedPane.addTab("Layout: flowy, Cell: flowy", createFlowPanel("flowy", "flowy"));
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Layout: flowx, Cell: flowx\", createFlowPanel(\"\", \"flowx\"));\n" +
+ "tabbedPane.addTab(\"Layout: flowx, Cell: flowy\", createFlowPanel(\"\", \"flowy\"));\n" +
+ "tabbedPane.addTab(\"Layout: flowy, Cell: flowx\", createFlowPanel(\"flowy\", \"flowx\"));\n" +
+ "tabbedPane.addTab(\"Layout: flowy, Cell: flowy\", createFlowPanel(\"flowy\", \"flowy\"));" +
+ "\n\tpublic JPanel createFlowPanel(String gridFlow, String cellFlow)\n" +
+ "\t{\n" +
+ "MigLayout lm = new MigLayout(\"center, wrap 3,\" + gridFlow,\n" +
+ " \"[110,fill]\",\n" +
+ " \"[110,fill]\");\n" +
+ "JPanel panel = createTabPanel(lm);\n" +
+ "\n" +
+ "for (int i = 0; i < 9; i++) {\n" +
+ "\tJButton b = createButton(\"\" + (i + 1));\n" +
+ "\tb.setFont(b.getFont().deriveFont(20f));\n" +
+ "\tpanel.add(b, cellFlow);\n" +
+ "}\n" +
+ "\n" +
+ "JButton b = createButton(\"5:2\");\n" +
+ "b.setFont(b.getFont().deriveFont(20f));\n" +
+ "panel.add(b, cellFlow + \",cell 1 1\");\n" +
+ "\n" +
+ "return panel;\n" +
+ "\t}");
+
+ return tabbedPane;
+ }
+
+ public JPanel createFlowPanel(String gridFlow, String cellFlow)
+ {
+ MigLayout lm = new MigLayout("center, wrap 3," + gridFlow,
+ "[110,fill]",
+ "[110,fill]");
+ JPanel panel = createTabPanel(lm);
+
+ Font f = panel.getFont().deriveFont(20f);
+ for (int i = 0; i < 9; i++) {
+ JComponent b = createPanel("" + (i + 1));
+ b.setFont(f);
+ panel.add(b, cellFlow);
+ }
+
+ JComponent b = createPanel("5:2");
+ b.setFont(f);
+ panel.add(b, cellFlow + ",cell 1 1");
+
+ return panel;
+ }
+
+ public JComponent createDebug()
+ {
+ return createPlainImpl(true);
+ }
+
+ public JComponent createButton_Bars()
+ {
+ MigLayout lm = new MigLayout("ins 0 0 15lp 0",
+ "[grow]",
+ "[grow][baseline,nogrid]");
+
+ final JPanel mainPanel = new JPanel(lm);
+ final JLabel formatLabel = createLabel("");
+ formatLabel.setFont(formatLabel.getFont().deriveFont(Font.BOLD));
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ JToggleButton winButt = createToggleButton("Windows");
+ JToggleButton macButt = createToggleButton("Mac OS X");
+ JButton helpButt = createButton("Help");
+
+ if (benchRuns == 0) {
+ winButt.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ PlatformDefaults.setPlatform(PlatformDefaults.WINDOWS_XP);
+ formatLabel.setText("'" + PlatformDefaults.getButtonOrder() + "'");
+ ((JPanel) ((JFrame) Frame.getFrames()[0]).getContentPane()).revalidate();
+ }
+ });
+
+ macButt.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ PlatformDefaults.setPlatform(PlatformDefaults.MAC_OSX);
+ formatLabel.setText(PlatformDefaults.getButtonOrder());
+ ((JPanel) ((JFrame) Frame.getFrames()[0]).getContentPane()).revalidate();
+ }
+ });
+
+ helpButt.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ JOptionPane.showMessageDialog(mainPanel, "See JavaDoc for PlatformConverter.getButtonBarOrder(..) for details on the format string.");
+ }
+ });
+ }
+
+ ButtonGroup bg = new ButtonGroup();
+ bg.add(winButt);
+ bg.add(macButt);
+ if (benchRuns == 0) {
+ if (PlatformDefaults.getCurrentPlatform() == PlatformDefaults.MAC_OSX) {
+ macButt.doClick();
+ } else {
+ winButt.doClick();
+ }
+ }
+
+ tabbedPane.addTab("Buttons", createButtonBarsPanel("help", false));
+ tabbedPane.addTab("Buttons with Help2", createButtonBarsPanel("help2", false));
+ tabbedPane.addTab("Buttons (Same width)", createButtonBarsPanel("help", true));
+
+ mainPanel.add(tabbedPane, "grow,wrap");
+
+ mainPanel.add(createLabel("Button Order:"));
+ mainPanel.add(formatLabel, "growx");
+ mainPanel.add(winButt);
+ mainPanel.add(macButt);
+ mainPanel.add(helpButt, "gapbefore unrel");
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("MigLayout lm = new MigLayout(\"ins 0 0 15lp 0\",\n" +
+ " \"[grow]\",\n" +
+ " \"[grow][baseline,nogrid,gap unrelated]\");\n" +
+ "\n" +
+ "final JPanel mainPanel = new JPanel(lm);\n" +
+ "final JLabel formatLabel = createLabel(\"\");\n" +
+ "formatLabel.setFont(formatLabel.getFont().deriveFont(Font.BOLD));\n" +
+ "JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "JToggleButton winButt = createToggleButton(\"Windows\");\n" +
+ "\n" +
+ "winButt.addActionListener(new ActionListener() {\n" +
+ "\tpublic void actionPerformed(ActionEvent e) {\n" +
+ "\t\tPlatformDefaults.setPlatform(PlatformDefaults.WINDOWS_XP);\n" +
+ "\t\tformatLabel.setText(\"'\" + PlatformDefaults.getButtonOrder() + \"'\");\n" +
+ "\t\tSwingUtilities.updateComponentTreeUI(mainPanel);\n" +
+ "\t}\n" +
+ "});\n" +
+ "\n" +
+ "JToggleButton macButt = createToggleButton(\"Mac OS X\");\n" +
+ "macButt.addActionListener(new ActionListener() {\n" +
+ "\tpublic void actionPerformed(ActionEvent e) {\n" +
+ "\t\tPlatformDefaults.setPlatform(PlatformDefaults.MAC_OSX);\n" +
+ "\t\tformatLabel.setText(PlatformDefaults.getButtonOrder());\n" +
+ "\t\tSwingUtilities.updateComponentTreeUI(mainPanel);\n" +
+ "\t}\n" +
+ "});\n" +
+ "\n" +
+ "JButton helpButt = createButton(\"Help\");\n" +
+ "helpButt.addActionListener(new ActionListener() {\n" +
+ "\tpublic void actionPerformed(ActionEvent e) {\n" +
+ "\t\tJOptionPane.showMessageDialog(mainPanel, \"See JavaDoc for PlatformConverter.getButtonBarOrder(..) for details on the format string.\");\n" +
+ "\t}\n" +
+ "});\n" +
+ "\n" +
+ "ButtonGroup bg = new ButtonGroup();\n" +
+ "bg.add(winButt);\n" +
+ "bg.add(macButt);\n" +
+ "winButt.doClick();\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Buttons\", createButtonBarsPanel(\"help\", false));\n" +
+ "tabbedPane.addTab(\"Buttons with Help2\", createButtonBarsPanel(\"help2\", false));\n" +
+ "tabbedPane.addTab(\"Buttons (Same width)\", createButtonBarsPanel(\"help\", true));\n" +
+ "\n" +
+ "mainPanel.add(tabbedPane, \"grow,wrap\");\n" +
+ "\n" +
+ "mainPanel.add(createLabel(\"Button Order:\"));\n" +
+ "mainPanel.add(formatLabel, \"growx\");\n" +
+ "mainPanel.add(winButt);\n" +
+ "mainPanel.add(macButt);\n" +
+ "mainPanel.add(helpButt, \"gapbefore unrel\");");
+
+ return mainPanel;
+ }
+
+ private JComponent createButtonBarsPanel(String helpTag, boolean sizeLocked)
+ {
+ MigLayout lm = new MigLayout("nogrid, fillx, aligny 100%, gapy unrel");
+ JPanel panel = createTabPanel(lm);
+
+ // Notice that the order in the rows below does not matter...
+ String[][] buttons = new String[][] {
+ {"OK"},
+ {"No", "Yes"},
+ {"Help", "Close"},
+ {"OK", "Help"},
+ {"OK", "Cancel", "Help"},
+ {"OK", "Cancel", "Apply", "Help"},
+ {"No", "Yes", "Cancel"},
+ {"Help", "< Back", "Forward >", "Cancel"},
+ {"Print...", "Cancel", "Help"}
+ };
+
+ for (int r = 0; r < buttons.length; r++) {
+ for (int i = 0; i < buttons[r].length; i++) {
+ String txt = buttons[r][i];
+ String tag = txt;
+
+ if (txt.equals("Help")) {
+ tag = helpTag;
+ } else if (txt.equals("< Back")) {
+ tag = "back";
+ } else if (txt.equals("Close")) {
+ tag = "cancel";
+ } else if (txt.equals("Forward >")) {
+ tag = "next";
+ } else if (txt.equals("Print...")) {
+ tag = "other";
+ }
+ String wrap = (i == buttons[r].length - 1) ? ",wrap" : "";
+ String sizeGroup = sizeLocked ? ("sgx " + r + ",") : "";
+ panel.add(createButton(txt), sizeGroup + "tag " + tag + wrap);
+ }
+ }
+ return panel;
+ }
+
+ public JComponent createOrientation()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ MigLayout lm = new MigLayout("flowy", "[grow,fill]", "[]20[]20[]20[]");
+ JPanel mainPanel = createTabPanel(lm);
+
+ // Default orientation
+ MigLayout defLM = new MigLayout("", "[trailing][grow,fill]", "");
+
+ JPanel defPanel = createTabPanel(defLM);
+ addSeparator(defPanel, "Default Orientation");
+ defPanel.add(createLabel("Level of Trust"));
+ defPanel.add(createTextField(""), "span,growx");
+ defPanel.add(createLabel("Radar Presentation"));
+ defPanel.add(createTextField(""));
+ defPanel.add(createTextField(""));
+
+ // Right-to-left, Top-to-bottom
+ MigLayout rtlLM = new MigLayout("rtl,ttb",
+ "[trailing][grow,fill]",
+ "");
+ JPanel rtlPanel = createTabPanel(rtlLM);
+ addSeparator(rtlPanel, "Right to Left");
+ rtlPanel.add(createLabel("Level of Trust"));
+ rtlPanel.add(createTextField(""), "span,growx");
+ rtlPanel.add(createLabel("Radar Presentation"));
+ rtlPanel.add(createTextField(""));
+ rtlPanel.add(createTextField(""));
+
+ // Right-to-left, Bottom-to-top
+ MigLayout rtlbLM = new MigLayout("rtl,btt",
+ "[trailing][grow,fill]",
+ "");
+ JPanel rtlbPanel = createTabPanel(rtlbLM);
+ addSeparator(rtlbPanel, "Right to Left, Bottom to Top");
+ rtlbPanel.add(createLabel("Level of Trust"));
+ rtlbPanel.add(createTextField(""), "span,growx");
+ rtlbPanel.add(createLabel("Radar Presentation"));
+ rtlbPanel.add(createTextField(""));
+ rtlbPanel.add(createTextField(""));
+
+ // Left-to-right, Bottom-to-top
+ MigLayout ltrbLM = new MigLayout("ltr,btt",
+ "[trailing][grow,fill]",
+ "");
+ JPanel ltrbPanel = createTabPanel(ltrbLM);
+ addSeparator(ltrbPanel, "Left to Right, Bottom to Top");
+ ltrbPanel.add(createLabel("Level of Trust"));
+ ltrbPanel.add(createTextField(""), "span,growx");
+ ltrbPanel.add(createLabel("Radar Presentation"));
+ ltrbPanel.add(createTextField(""));
+ ltrbPanel.add(createTextField(""));
+
+ mainPanel.add(defPanel);
+ mainPanel.add(rtlPanel);
+ mainPanel.add(rtlbPanel);
+ mainPanel.add(ltrbPanel);
+
+ tabbedPane.addTab("Orientation", mainPanel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "MigLayout lm = new MigLayout(\"flowy\", \"[grow,fill]\", \"[]0[]15lp[]0[]\");\n" +
+ "JPanel mainPanel = createTabPanel(lm);\n" +
+ "\n" +
+ "// Default orientation\n" +
+ "MigLayout defLM = new MigLayout(\"\", \"[][grow,fill]\", \"\");\n" +
+ "\n" +
+ "JPanel defPanel = createTabPanel(defLM);\n" +
+ "addSeparator(defPanel, \"Default Orientation\");\n" +
+ "defPanel.add(createLabel(\"Level\"));\n" +
+ "defPanel.add(createTextField(\"\"), \"span,growx\");\n" +
+ "defPanel.add(createLabel(\"Radar\"));\n" +
+ "defPanel.add(createTextField(\"\"));\n" +
+ "defPanel.add(createTextField(\"\"));\n" +
+ "\n" +
+ "// Right-to-left, Top-to-bottom\n" +
+ "MigLayout rtlLM = new MigLayout(\"rtl,ttb\",\n" +
+ " \"[][grow,fill]\",\n" +
+ " \"\");\n" +
+ "JPanel rtlPanel = createTabPanel(rtlLM);\n" +
+ "addSeparator(rtlPanel, \"Right to Left\");\n" +
+ "rtlPanel.add(createLabel(\"Level\"));\n" +
+ "rtlPanel.add(createTextField(\"\"), \"span,growx\");\n" +
+ "rtlPanel.add(createLabel(\"Radar\"));\n" +
+ "rtlPanel.add(createTextField(\"\"));\n" +
+ "rtlPanel.add(createTextField(\"\"));\n" +
+ "\n" +
+ "// Right-to-left, Bottom-to-top\n" +
+ "MigLayout rtlbLM = new MigLayout(\"rtl,btt\",\n" +
+ " \"[][grow,fill]\",\n" +
+ " \"\");\n" +
+ "JPanel rtlbPanel = createTabPanel(rtlbLM);\n" +
+ "addSeparator(rtlbPanel, \"Right to Left, Bottom to Top\");\n" +
+ "rtlbPanel.add(createLabel(\"Level\"));\n" +
+ "rtlbPanel.add(createTextField(\"\"), \"span,growx\");\n" +
+ "rtlbPanel.add(createLabel(\"Radar\"));\n" +
+ "rtlbPanel.add(createTextField(\"\"));\n" +
+ "rtlbPanel.add(createTextField(\"\"));\n" +
+ "\n" +
+ "// Left-to-right, Bottom-to-top\n" +
+ "MigLayout ltrbLM = new MigLayout(\"ltr,btt\",\n" +
+ " \"[][grow,fill]\",\n" +
+ " \"\");\n" +
+ "JPanel ltrbPanel = createTabPanel(ltrbLM);\n" +
+ "addSeparator(ltrbPanel, \"Left to Right, Bottom to Top\");\n" +
+ "ltrbPanel.add(createLabel(\"Level\"));\n" +
+ "ltrbPanel.add(createTextField(\"\"), \"span,growx\");\n" +
+ "ltrbPanel.add(createLabel(\"Radar\"));\n" +
+ "ltrbPanel.add(createTextField(\"\"));\n" +
+ "ltrbPanel.add(createTextField(\"\"));\n" +
+ "\n" +
+ "mainPanel.add(defPanel);\n" +
+ "mainPanel.add(rtlPanel);\n" +
+ "mainPanel.add(rtlbPanel);\n" +
+ "mainPanel.add(ltrbPanel);\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Orientation\", mainPanel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createCell_Position()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Absolute grid position
+ MigLayout absLM = new MigLayout("",
+ "[100:pref,fill]",
+ "[100:pref,fill]");
+ JPanel absPanel = createTabPanel(absLM);
+ absPanel.add(createButton(), "cell 0 0");
+ absPanel.add(createButton(), "cell 2 0");
+ absPanel.add(createButton(), "cell 3 0");
+ absPanel.add(createButton(), "cell 1 1");
+ absPanel.add(createButton(), "cell 0 2");
+ absPanel.add(createButton(), "cell 2 2");
+ absPanel.add(createButton(), "cell 2 2");
+
+
+ // Relative grid position with wrap
+ MigLayout relAwLM = new MigLayout("wrap",
+ "[100:pref,fill][100:pref,fill][100:pref,fill][100:pref,fill]",
+ "[100:pref,fill]");
+ JPanel relAwPanel = createTabPanel(relAwLM);
+ relAwPanel.add(createButton());
+ relAwPanel.add(createButton(), "skip");
+ relAwPanel.add(createButton());
+ relAwPanel.add(createButton(), "skip,wrap");
+ relAwPanel.add(createButton());
+ relAwPanel.add(createButton(), "skip,split");
+ relAwPanel.add(createButton());
+
+
+ // Relative grid position with manual wrap
+ MigLayout relWLM = new MigLayout("",
+ "[100:pref,fill]",
+ "[100:pref,fill]");
+ JPanel relWPanel = createTabPanel(relWLM);
+ relWPanel.add(createButton());
+ relWPanel.add(createButton(), "skip");
+ relWPanel.add(createButton(), "wrap");
+ relWPanel.add(createButton(), "skip,wrap");
+ relWPanel.add(createButton());
+ relWPanel.add(createButton(), "skip,split");
+
+ relWPanel.add(createButton());
+
+
+ // Mixed relative and absolute grid position
+ MigLayout mixLM = new MigLayout("",
+ "[100:pref,fill]",
+ "[100:pref,fill]");
+ JPanel mixPanel = createTabPanel(mixLM);
+ mixPanel.add(createButton());
+ mixPanel.add(createButton(), "cell 2 0");
+ mixPanel.add(createButton());
+ mixPanel.add(createButton(), "cell 1 1,wrap");
+ mixPanel.add(createButton());
+ mixPanel.add(createButton(), "cell 2 2,split");
+ mixPanel.add(createButton());
+
+ tabbedPane.addTab("Absolute", absPanel);
+ tabbedPane.addTab("Relative + Wrap", relAwPanel);
+ tabbedPane.addTab("Relative", relWPanel);
+ tabbedPane.addTab("Mixed", mixPanel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("\t\tJTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "\t\t// Absolute grid position\n" +
+ "\t\tMigLayout absLM = new MigLayout(\"\",\n" +
+ "\t\t \"[100:pref,fill]\",\n" +
+ "\t\t \"[100:pref,fill]\");\n" +
+ "\t\tJPanel absPanel = createTabPanel(absLM);\n" +
+ "\t\tabsPanel.add(createPanel(), \"cell 0 0\");\n" +
+ "\t\tabsPanel.add(createPanel(), \"cell 2 0\");\n" +
+ "\t\tabsPanel.add(createPanel(), \"cell 3 0\");\n" +
+ "\t\tabsPanel.add(createPanel(), \"cell 1 1\");\n" +
+ "\t\tabsPanel.add(createPanel(), \"cell 0 2\");\n" +
+ "\t\tabsPanel.add(createPanel(), \"cell 2 2\");\n" +
+ "\t\tabsPanel.add(createPanel(), \"cell 2 2\");\n" +
+ "\n" +
+ "\n" +
+ "\t\t// Relative grid position with wrap\n" +
+ "\t\tMigLayout relAwLM = new MigLayout(\"wrap\",\n" +
+ "\t\t \"[100:pref,fill][100:pref,fill][100:pref,fill][100:pref,fill]\",\n" +
+ "\t\t \"[100:pref,fill]\");\n" +
+ "\t\tJPanel relAwPanel = createTabPanel(relAwLM);\n" +
+ "\t\trelAwPanel.add(createPanel());\n" +
+ "\t\trelAwPanel.add(createPanel(), \"skip\");\n" +
+ "\t\trelAwPanel.add(createPanel());\n" +
+ "\t\trelAwPanel.add(createPanel(), \"skip,wrap\");\n" +
+ "\t\trelAwPanel.add(createPanel());\n" +
+ "\t\trelAwPanel.add(createPanel(), \"skip,split\");\n" +
+ "\t\trelAwPanel.add(createPanel());\n" +
+ "\n" +
+ "\n" +
+ "\t\t// Relative grid position with manual wrap\n" +
+ "\t\tMigLayout relWLM = new MigLayout(\"\",\n" +
+ "\t\t \"[100:pref,fill]\",\n" +
+ "\t\t \"[100:pref,fill]\");\n" +
+ "\t\tJPanel relWPanel = createTabPanel(relWLM);\n" +
+ "\t\trelWPanel.add(createPanel());\n" +
+ "\t\trelWPanel.add(createPanel(), \"skip\");\n" +
+ "\t\trelWPanel.add(createPanel(), \"wrap\");\n" +
+ "\t\trelWPanel.add(createPanel(), \"skip,wrap\");\n" +
+ "\t\trelWPanel.add(createPanel());\n" +
+ "\t\trelWPanel.add(createPanel(), \"skip,split\");\n" +
+ "\n" +
+ "\t\trelWPanel.add(createPanel());\n" +
+ "\n" +
+ "\n" +
+ "\t\t// Mixed relative and absolute grid position\n" +
+ "\t\tMigLayout mixLM = new MigLayout(\"\",\n" +
+ "\t\t \"[100:pref,fill]\",\n" +
+ "\t\t \"[100:pref,fill]\");\n" +
+ "\t\tJPanel mixPanel = createTabPanel(mixLM);\n" +
+ "\t\tmixPanel.add(createPanel());\n" +
+ "\t\tmixPanel.add(createPanel(), \"cell 2 0\");\n" +
+ "\t\tmixPanel.add(createPanel());\n" +
+ "\t\tmixPanel.add(createPanel(), \"cell 1 1,wrap\");\n" +
+ "\t\tmixPanel.add(createPanel());\n" +
+ "\t\tmixPanel.add(createPanel(), \"cell 2 2,split\");\n" +
+ "\t\tmixPanel.add(createPanel());\n" +
+ "\n" +
+ "\t\ttabbedPane.addTab(\"Absolute\", absPanel);\n" +
+ "\t\ttabbedPane.addTab(\"Relative + Wrap\", relAwPanel);\n" +
+ "\t\ttabbedPane.addTab(\"Relative\", relWPanel);\n" +
+ "\t\ttabbedPane.addTab(\"Mixed\", mixPanel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createPlain()
+ {
+ return createPlainImpl(false);
+ }
+
+ private JComponent createPlainImpl(boolean debug)
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ MigLayout lm = new MigLayout((debug && benchRuns == 0 ? "debug, inset 20" : "ins 20"), "[para]0[][100lp, fill][60lp][95lp, fill]", "");
+ JPanel panel = createTabPanel(lm);
+
+ addSeparator(panel, "Manufacturer");
+
+ panel.add(createLabel("Company"), "skip");
+ panel.add(createTextField(""), "span, growx");
+ panel.add(createLabel("Contact"), "skip");
+ panel.add(createTextField(""), "span, growx");
+ panel.add(createLabel("Order No"), "skip");
+ panel.add(createTextField(15), "wrap para");
+
+ addSeparator(panel, "Inspector");
+
+ panel.add(createLabel("Name"), "skip");
+ panel.add(createTextField(""), "span, growx");
+ panel.add(createLabel("Reference No"), "skip");
+ panel.add(createTextField(""), "wrap");
+ panel.add(createLabel("Status"), "skip");
+ panel.add(createCombo(new String[] {"In Progress", "Finnished", "Released"}), "wrap para");
+
+ addSeparator(panel, "Ship");
+
+ panel.add(createLabel("Shipyard"), "skip");
+ panel.add(createTextField(""), "span, growx");
+ panel.add(createLabel("Register No"), "skip");
+ panel.add(createTextField(""));
+ panel.add(createLabel("Hull No"), "right");
+ panel.add(createTextField(15), "wrap");
+ panel.add(createLabel("Project Type"), "skip");
+ panel.add(createCombo(new String[] {"New Building", "Convention", "Repair"}));
+
+ if (debug)
+ panel.add(createLabel("Red is cell bounds. Blue is component bounds."), "newline,ax left,span,gaptop 40,");
+
+ tabbedPane.addTab("Plain", panel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "MigLayout lm = new MigLayout((debug && benchRuns == 0 ? \"debug, inset 20\" : \"ins 20\"), \"[para]0[][100lp, fill][60lp][95lp, fill]\", \"\");\n" +
+ "JPanel panel = createTabPanel(lm);\n" +
+ "\n" +
+ "addSeparator(panel, \"Manufacturer\");\n" +
+ "\n" +
+ "panel.add(createLabel(\"Company\"), \"skip\");\n" +
+ "panel.add(createTextField(\"\"), \"span, growx\");\n" +
+ "panel.add(createLabel(\"Contact\"), \"skip\");\n" +
+ "panel.add(createTextField(\"\"), \"span, growx\");\n" +
+ "panel.add(createLabel(\"Order No\"), \"skip\");\n" +
+ "panel.add(createTextField(15), \"wrap para\");\n" +
+ "\n" +
+ "addSeparator(panel, \"Inspector\");\n" +
+ "\n" +
+ "panel.add(createLabel(\"Name\"), \"skip\");\n" +
+ "panel.add(createTextField(\"\"), \"span, growx\");\n" +
+ "panel.add(createLabel(\"Reference No\"), \"skip\");\n" +
+ "panel.add(createTextField(\"\"), \"wrap\");\n" +
+ "panel.add(createLabel(\"Status\"), \"skip\");\n" +
+ "panel.add(createCombo(new String[] {\"In Progress\", \"Finnished\", \"Released\"}), \"wrap para\");\n" +
+ "\n" +
+ "addSeparator(panel, \"Ship\");\n" +
+ "\n" +
+ "panel.add(createLabel(\"Shipyard\"), \"skip\");\n" +
+ "panel.add(createTextField(\"\"), \"span, growx\");\n" +
+ "panel.add(createLabel(\"Register No\"), \"skip\");\n" +
+ "panel.add(createTextField(\"\"));\n" +
+ "panel.add(createLabel(\"Hull No\"), \"right\");\n" +
+ "panel.add(createTextField(15), \"wrap\");\n" +
+ "panel.add(createLabel(\"Project Type\"), \"skip\");\n" +
+ "panel.add(createCombo(new String[] {\"New Building\", \"Convention\", \"Repair\"}));\n" +
+ "\n" +
+ "if (debug)\n" +
+ "\tpanel.add(createLabel(\"Red is cell bounds. Blue is component bounds.\"), \"newline,ax left,span,gaptop 40,\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Plain\", panel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createBound_Sizes()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ for (int i = 0; i < 2; i++) { // Jumping for 0 and Stable for 1
+ String colConstr = i == 0 ? "[right][200]" : "[right, 75lp:pref][200]";
+
+ MigLayout LM1 = new MigLayout("wrap", colConstr, "");
+ JPanel panel1 = createTabPanel(LM1);
+ panel1.add(createLabel("File Number:"));
+ panel1.add(createTextField(""), "growx");
+ panel1.add(createLabel("RFQ Number:"));
+ panel1.add(createTextField(""), "growx");
+ panel1.add(createLabel("Entry Date:"));
+ panel1.add(createTextField(6));
+ panel1.add(createLabel("Sales Person:"));
+ panel1.add(createTextField(""), "growx");
+
+ MigLayout LM2 = new MigLayout("wrap", colConstr, "");
+ JPanel panel2 = createTabPanel(LM2);
+ panel2.add(createLabel("Shipper:"));
+ panel2.add(createTextField(6), "split 2");
+ panel2.add(createTextField(""), "growx");
+ panel2.add(createLabel("Consignee:"));
+ panel2.add(createTextField(6), "split 2");
+ panel2.add(createTextField(""), "growx");
+ panel2.add(createLabel("Departure:"));
+ panel2.add(createTextField(6), "split 2");
+ panel2.add(createTextField(""), "growx");
+ panel2.add(createLabel("Destination:"));
+ panel2.add(createTextField(6), "split 2");
+ panel2.add(createTextField(""), "growx");
+
+ tabbedPane.addTab(i == 0 ? "Jumping 1" : "Stable 1", panel1);
+ tabbedPane.addTab(i == 0 ? "Jumping 2" : "Stable 2", panel2);
+ }
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "for (int i = 0; i < 2; i++) { // Jumping for 0 and Stable for 1\n" +
+ "\tString colConstr = i == 0 ? \"[right][200]\" : \"[right, 75lp:pref][200]\";\n" +
+ "\n" +
+ "\tMigLayout LM1 = new MigLayout(\"wrap\", colConstr, \"\");\n" +
+ "\tJPanel panel1 = createTabPanel(LM1);\n" +
+ "\tpanel1.add(createLabel(\"File Number:\"));\n" +
+ "\tpanel1.add(createTextField(\"\"), \"growx\");\n" +
+ "\tpanel1.add(createLabel(\"RFQ Number:\"));\n" +
+ "\tpanel1.add(createTextField(\"\"), \"growx\");\n" +
+ "\tpanel1.add(createLabel(\"Entry Date:\"));\n" +
+ "\tpanel1.add(createTextField(6));\n" +
+ "\tpanel1.add(createLabel(\"Sales Person:\"));\n" +
+ "\tpanel1.add(createTextField(\"\"), \"growx\");\n" +
+ "\n" +
+ "\tMigLayout LM2 = new MigLayout(\"wrap\", colConstr, \"\");\n" +
+ "\tJPanel panel2 = createTabPanel(LM2);\n" +
+ "\tpanel2.add(createLabel(\"Shipper:\"));\n" +
+ "\tpanel2.add(createTextField(6), \"split 2\");\n" +
+ "\tpanel2.add(createTextField(\"\"), \"growx\");\n" +
+ "\tpanel2.add(createLabel(\"Consignee:\"));\n" +
+ "\tpanel2.add(createTextField(6), \"split 2\");\n" +
+ "\tpanel2.add(createTextField(\"\"), \"growx\");\n" +
+ "\tpanel2.add(createLabel(\"Departure:\"));\n" +
+ "\tpanel2.add(createTextField(6), \"split 2\");\n" +
+ "\tpanel2.add(createTextField(\"\"), \"growx\");\n" +
+ "\tpanel2.add(createLabel(\"Destination:\"));\n" +
+ "\tpanel2.add(createTextField(6), \"split 2\");\n" +
+ "\tpanel2.add(createTextField(\"\"), \"growx\");\n" +
+ "\n" +
+ "\ttabbedPane.addTab(i == 0 ? \"Jumping 1\" : \"Stable 2\", panel1);\n" +
+ "\ttabbedPane.addTab(i == 0 ? \"Jumping 2\" : \"Stable 2\", panel2);\n" +
+ "}");
+
+ return tabbedPane;
+ }
+
+ public JComponent createComponent_Sizes()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ MigLayout LM = new MigLayout("wrap", "[right][0:pref,grow]", "");
+
+ JPanel panel = createTabPanel(LM);
+ JScrollPane descrText = createTextAreaScroll("Use slider to see how the components grow and shrink depending on the constraints set on them.", 0, 0, false);
+
+ descrText.setOpaque(OPAQUE);
+ descrText.setBorder(new EmptyBorder(10, 10, 10, 10));
+ ((JTextArea) descrText.getViewport().getView()).setOpaque(OPAQUE);
+ descrText.getViewport().setOpaque(OPAQUE);
+
+ JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, panel, descrText);
+ splitPane.setOpaque(OPAQUE);
+ splitPane.setBorder(null);
+
+ panel.add(createLabel("\"\""));
+ panel.add(createTextField("8"));
+ panel.add(createLabel("\"min!\""));
+ panel.add(createTextField("3", 3), "width min!");
+ panel.add(createLabel("\"pref!\""));
+ panel.add(createTextField("3", 3), "width pref!");
+ panel.add(createLabel("\"min:pref\""));
+ panel.add(createTextField("8", 8), "width min:pref");
+ panel.add(createLabel("\"min:100:150\""));
+ panel.add(createTextField("8", 8), "width min:100:150");
+ panel.add(createLabel("\"min:100:150, growx\""));
+ panel.add(createTextField("8", 8), "width min:100:150, growx");
+ panel.add(createLabel("\"min:100, growx\""));
+ panel.add(createTextField("8", 8), "width min:100, growx");
+ panel.add(createLabel("\"40!\""));
+ panel.add(createTextField("8", 8), "width 40!");
+ panel.add(createLabel("\"40:40:40\""));
+ panel.add(createTextField("8", 8), "width 40:40:40");
+
+ tabbedPane.addTab("Component Sizes", splitPane);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "MigLayout LM = new MigLayout(\"wrap\", \"[right][0:pref,grow]\", \"\");\n" +
+ "\n" +
+ "JPanel panel = createTabPanel(LM);\n" +
+ "JScrollPane descrText = createTextAreaScroll(\"Use slider to see how the components grow and shrink depending on the constraints set on them.\", 0, 0, false);\n" +
+ "\n" +
+ "descrText.setOpaque(OPAQUE);\n" +
+ "descrText.setBorder(new EmptyBorder(10, 10, 10, 10));\n" +
+ "((JTextArea) descrText.getViewport().getView()).setOpaque(OPAQUE);\n" +
+ "descrText.getViewport().setOpaque(OPAQUE);\n" +
+ "\n" +
+ "JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, panel, descrText);\n" +
+ "splitPane.setOpaque(OPAQUE);\n" +
+ "splitPane.setBorder(null);\n" +
+ "\n" +
+ "panel.add(createLabel(\"\\\"\\\"\"));\n" +
+ "panel.add(createTextField(\"8\", 8));\n" +
+ "panel.add(createLabel(\"\\\"min!\\\"\"));\n" +
+ "panel.add(createTextField(\"3\", 3), \"width min!\");\n" +
+ "panel.add(createLabel(\"\\\"pref!\\\"\"));\n" +
+ "panel.add(createTextField(\"3\", 3), \"width pref!\");\n" +
+ "panel.add(createLabel(\"\\\"min:pref\\\"\"));\n" +
+ "panel.add(createTextField(\"8\", 8), \"width min:pref\");\n" +
+ "panel.add(createLabel(\"\\\"min:100:150\\\"\"));\n" +
+ "panel.add(createTextField(\"8\", 8), \"width min:100:150\");\n" +
+ "panel.add(createLabel(\"\\\"min:100:150, growx\\\"\"));\n" +
+ "panel.add(createTextField(\"8\", 8), \"width min:100:150, growx\");\n" +
+ "panel.add(createLabel(\"\\\"min:100, growx\\\"\"));\n" +
+ "panel.add(createTextField(\"8\", 8), \"width min:100, growx\");\n" +
+ "panel.add(createLabel(\"\\\"40!\\\"\"));\n" +
+ "panel.add(createTextField(\"8\", 8), \"width 40!\");\n" +
+ "panel.add(createLabel(\"\\\"40:40:40\\\"\"));\n" +
+ "panel.add(createTextField(\"8\", 8), \"width 40:40:40\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Component Sizes\", splitPane);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createCell_Alignments()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Horizontal
+ MigLayout hLM = new MigLayout("wrap",
+ "[grow,left][grow,center][grow,right][grow,fill,center]",
+ "[]unrel[][]");
+ JPanel hPanel = createTabPanel(hLM);
+ String[] sizes = new String[] {"", "growx", "growx 0", "left", "center", "right", "leading", "trailing"};
+ hPanel.add(createLabel("[left]"), "c");
+ hPanel.add(createLabel("[center]"), "c");
+ hPanel.add(createLabel("[right]"), "c");
+ hPanel.add(createLabel("[fill,center]"), "c, growx 0");
+
+ for (int r = 0; r < sizes.length; r++) {
+ for (int c = 0; c < 4; c++) {
+ String text = sizes[r].length() > 0 ? sizes[r] : "default";
+ hPanel.add(createButton(text), sizes[r]);
+ }
+ }
+
+ // Vertical
+ MigLayout vLM = new MigLayout("wrap,flowy",
+ "[right][]",
+ "[grow,top][grow,center][grow,bottom][grow,fill,bottom][grow,fill,baseline]");
+ JPanel vPanel = createTabPanel(vLM);
+ String[] vSizes = new String[] {"", "growy", "growy 0", "top", "center", "bottom"};
+ vPanel.add(createLabel("[top]"), "center");
+ vPanel.add(createLabel("[center]"), "center");
+ vPanel.add(createLabel("[bottom]"), "center");
+ vPanel.add(createLabel("[fill, bottom]"), "center, growy 0");
+ vPanel.add(createLabel("[fill, baseline]"), "center");
+
+ for (int c = 0; c < vSizes.length; c++) {
+ for (int r = 0; r < 5; r++) {
+ String text = vSizes[c].length() > 0 ? vSizes[c] : "default";
+ JButton b = createButton(text);
+ if (r == 4 && c <= 1)
+ b.setFont(new Font("sansserif", Font.PLAIN, 16 + c * 5));
+ vPanel.add(b, vSizes[c]);
+ }
+ }
+
+ tabbedPane.addTab("Horizontal", hPanel);
+ tabbedPane.addTab("Vertical", vPanel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// Horizontal\n" +
+ "MigLayout hLM = new MigLayout(\"wrap\",\n" +
+ " \"[grow,left][grow,center][grow,right][grow,fill,center]\",\n" +
+ " \"[]unrel[][]\");\n" +
+ "JPanel hPanel = createTabPanel(hLM);\n" +
+ "String[] sizes = new String[] {\"\", \"growx\", \"growx 0\", \"left\", \"center\", \"right\", \"leading\", \"trailing\"};\n" +
+ "hPanel.add(createLabel(\"[left]\"), \"c\");\n" +
+ "hPanel.add(createLabel(\"[center]\"), \"c\");\n" +
+ "hPanel.add(createLabel(\"[right]\"), \"c\");\n" +
+ "hPanel.add(createLabel(\"[fill,center]\"), \"c, growx 0\");\n" +
+ "\n" +
+ "for (int r = 0; r < sizes.length; r++) {\n" +
+ "\tfor (int c = 0; c < 4; c++) {\n" +
+ "\t\tString text = sizes[r].length() > 0 ? sizes[r] : \"default\";\n" +
+ "\t\thPanel.add(createButton(text), sizes[r]);\n" +
+ "\t}\n" +
+ "}\n" +
+ "\n" +
+ "// Vertical\n" +
+ "MigLayout vLM = new MigLayout(\"wrap,flowy\",\n" +
+ " \"[right][]\",\n" +
+ " \"[grow,top][grow,center][grow,bottom][grow,fill,bottom][grow,fill,baseline]\");\n" +
+ "JPanel vPanel = createTabPanel(vLM);\n" +
+ "String[] vSizes = new String[] {\"\", \"growy\", \"growy 0\", \"top\", \"center\", \"bottom\"};\n" +
+ "vPanel.add(createLabel(\"[top]\"), \"center\");\n" +
+ "vPanel.add(createLabel(\"[center]\"), \"center\");\n" +
+ "vPanel.add(createLabel(\"[bottom]\"), \"center\");\n" +
+ "vPanel.add(createLabel(\"[fill, bottom]\"), \"center, growy 0\");\n" +
+ "vPanel.add(createLabel(\"[fill, baseline]\"), \"center\");\n" +
+ "\n" +
+ "for (int c = 0; c < vSizes.length; c++) {\n" +
+ "\tfor (int r = 0; r < 5; r++) {\n" +
+ "\t\tString text = vSizes[c].length() > 0 ? vSizes[c] : \"default\";\n" +
+ "\t\tJButton b = createButton(text);\n" +
+ "\t\tif (r == 4 && c <= 1)\n" +
+ "\t\t\tb.setFont(new Font(\"sansserif\", Font.PLAIN, 16 + c * 5));\n" +
+ "\t\tvPanel.add(b, vSizes[c]);\n" +
+ "\t}\n" +
+ "}\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Horizontal\", hPanel);\n" +
+ "tabbedPane.addTab(\"Vertical\", vPanel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createUnits()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Horizontal
+ MigLayout hLM = new MigLayout("wrap,nocache",
+ "[right][]",
+ "");
+ JPanel hPanel = createTabPanel(hLM);
+ String[] sizes = new String[] {"72pt", "25.4mm", "2.54cm", "1in", "72px", "96px", "120px", "25%", "20sp"};
+ for (int i = 0; i < sizes.length; i++) {
+ hPanel.add(createLabel(sizes[i]));
+ hPanel.add(createTextField(""), "width " + sizes[i] + "!");
+ }
+
+ // Horizontal lp
+ MigLayout hlpLM = new MigLayout("nocache", "[right][][]", "");
+ JPanel hlpPanel = createTabPanel(hlpLM);
+ hlpPanel.add(createLabel("9 cols"));
+ hlpPanel.add(createTextField(9));
+ String[] lpSizes = new String[] {"75lp", "75px", "88px", "100px"};
+ hlpPanel.add(createLabel("Width of createTextField(9)"), "wrap");
+ for (int i = 0; i < lpSizes.length; i++) {
+ hlpPanel.add(createLabel(lpSizes[i]));
+ hlpPanel.add(createTextField(""), "width " + lpSizes[i] + "!, wrap");
+ }
+
+ // Vertical
+ MigLayout vLM = new MigLayout("wrap,flowy,nocache",
+ "[c]",
+ "[top][top]");
+ JPanel vPanel = createTabPanel(vLM);
+ String[] vSizes = new String[] {"72pt", "25.4mm", "2.54cm", "1in", "72px", "96px", "120px", "25%", "20sp"};
+ for (int i = 0; i < sizes.length; i++) {
+ vPanel.add(createLabel(vSizes[i]));
+ vPanel.add(createTextArea("", 0, 5), "width 50!, height " + vSizes[i] + "!");
+ }
+
+ // Vertical lp
+ MigLayout vlpLM = new MigLayout("wrap,flowy,nocache",
+ "[c]",
+ "[top][top]40px[top][top]");
+ JPanel vlpPanel = createTabPanel(vlpLM);
+ vlpPanel.add(createLabel("4 rows"));
+ vlpPanel.add(createTextArea("", 4, 5), "width 50!");
+ vlpPanel.add(createLabel("field"));
+ vlpPanel.add(createTextField(5));
+
+ String[] vlpSizes1 = new String[] {"63lp", "57px", "63px", "68px", "25%"};
+ String[] vlpSizes2 = new String[] {"21lp", "21px", "23px", "24px", "10%"};
+ for (int i = 0; i < vlpSizes1.length; i++) {
+ vlpPanel.add(createLabel(vlpSizes1[i]));
+ vlpPanel.add(createTextArea("", 1, 5), "width 50!, height " + vlpSizes1[i] + "!");
+ vlpPanel.add(createLabel(vlpSizes2[i]));
+ vlpPanel.add(createTextField(5), "height " + vlpSizes2[i] + "!");
+ }
+
+ vlpPanel.add(createLabel("button"), "skip 2");
+ vlpPanel.add(createButton("..."));
+
+ tabbedPane.addTab("Horizontal", hPanel);
+ tabbedPane.addTab("Horizontal LP", hlpPanel);
+ tabbedPane.addTab("Vertical", vPanel);
+ tabbedPane.addTab("Vertical LP", vlpPanel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// Horizontal\n" +
+ "MigLayout hLM = new MigLayout(\"wrap,nocache\",\n" +
+ "\t\t\t\t\t\t\t \"[right][]\",\n" +
+ "\t\t\t\t\t\t\t \"\");\n" +
+ "JPanel hPanel = createTabPanel(hLM);\n" +
+ "String[] sizes = new String[] {\"72pt\", \"25.4mm\", \"2.54cm\", \"1in\", \"72px\", \"96px\", \"120px\", \"25%\", \"20sp\"};\n" +
+ "for (int i = 0; i < sizes.length; i++) {\n" +
+ "\thPanel.add(createLabel(sizes[i]));\n" +
+ "\thPanel.add(createTextField(\"\"), \"width \" + sizes[i] + \"!\");\n" +
+ "}\n" +
+ "\n" +
+ "// Horizontal lp\n" +
+ "MigLayout hlpLM = new MigLayout(\"nocache\", \"[right][][]\", \"\");\n" +
+ "JPanel hlpPanel = createTabPanel(hlpLM);\n" +
+ "hlpPanel.add(createLabel(\"9 cols\"));\n" +
+ "hlpPanel.add(createTextField(9));\n" +
+ "String[] lpSizes = new String[] {\"75lp\", \"75px\", \"88px\", \"100px\"};\n" +
+ "hlpPanel.add(createLabel(\"Width of createTextField(9)\"), \"wrap\");\n" +
+ "for (int i = 0; i < lpSizes.length; i++) {\n" +
+ "\thlpPanel.add(createLabel(lpSizes[i]));\n" +
+ "\thlpPanel.add(createTextField(\"\"), \"width \" + lpSizes[i] + \"!, wrap\");\n" +
+ "}\n" +
+ "\n" +
+ "// Vertical\n" +
+ "MigLayout vLM = new MigLayout(\"wrap,flowy,nocache\",\n" +
+ "\t\t\t\t\t\t\t \"[c]\",\n" +
+ "\t\t\t\t\t\t\t \"[top][top]\");\n" +
+ "JPanel vPanel = createTabPanel(vLM);\n" +
+ "String[] vSizes = new String[] {\"72pt\", \"25.4mm\", \"2.54cm\", \"1in\", \"72px\", \"96px\", \"120px\", \"25%\", \"20sp\"};\n" +
+ "for (int i = 0; i < sizes.length; i++) {\n" +
+ "\tvPanel.add(createLabel(vSizes[i]));\n" +
+ "\tvPanel.add(createTextArea(\"\", 0, 5), \"width 50!, height \" + vSizes[i] + \"!\");\n" +
+ "}\n" +
+ "\n" +
+ "// Vertical lp\n" +
+ "MigLayout vlpLM = new MigLayout(\"wrap,flowy,nocache\",\n" +
+ "\t\t\t\t\t\t\t\t\"[c]\",\n" +
+ "\t\t\t\t\t\t\t\t\"[top][top]40px[top][top]\");\n" +
+ "JPanel vlpPanel = createTabPanel(vlpLM);\n" +
+ "vlpPanel.add(createLabel(\"4 rows\"));\n" +
+ "vlpPanel.add(createTextArea(\"\", 4, 5), \"width 50!\");\n" +
+ "vlpPanel.add(createLabel(\"field\"));\n" +
+ "vlpPanel.add(createTextField(5));\n" +
+ "\n" +
+ "String[] vlpSizes1 = new String[] {\"63lp\", \"57px\", \"63px\", \"68px\", \"25%\"};\n" +
+ "String[] vlpSizes2 = new String[] {\"21lp\", \"21px\", \"23px\", \"24px\", \"10%\"};\n" +
+ "for (int i = 0; i < vlpSizes1.length; i++) {\n" +
+ "\tvlpPanel.add(createLabel(vlpSizes1[i]));\n" +
+ "\tvlpPanel.add(createTextArea(\"\", 1, 5), \"width 50!, height \" + vlpSizes1[i] + \"!\");\n" +
+ "\tvlpPanel.add(createLabel(vlpSizes2[i]));\n" +
+ "\tvlpPanel.add(createTextField(5), \"height \" + vlpSizes2[i] + \"!\");\n" +
+ "}\n" +
+ "\n" +
+ "vlpPanel.add(createLabel(\"button\"), \"skip 2\");\n" +
+ "vlpPanel.add(createButton(\"...\"));\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Horizontal\", hPanel);\n" +
+ "tabbedPane.addTab(\"Horizontal LP\", hlpPanel);\n" +
+ "tabbedPane.addTab(\"Vertical\", vPanel);\n" +
+ "tabbedPane.addTab(\"Vertical LP\", vlpPanel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createGrouping()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Ungrouped
+ MigLayout ugM = new MigLayout("", "[]push[][][]", "");
+ JPanel ugPanel = createTabPanel(ugM);
+ ugPanel.add(createButton("Help"));
+ ugPanel.add(createButton("< Back"), "");
+ ugPanel.add(createButton("Forward >"), "gap push");
+ ugPanel.add(createButton("Apply"), "gap unrel");
+ ugPanel.add(createButton("Cancel"), "gap unrel");
+
+ // Grouped Components
+ MigLayout gM = new MigLayout("nogrid, fillx");
+ JPanel gPanel = createTabPanel(gM);
+ gPanel.add(createButton("Help"), "sg");
+ gPanel.add(createButton("< Back"), "sg,gap push");
+ gPanel.add(createButton("Forward >"), "sg");
+ gPanel.add(createButton("Apply"), "sg,gap unrel");
+ gPanel.add(createButton("Cancel"), "sg,gap unrel");
+
+ // Grouped Columns
+ MigLayout gcM = new MigLayout("", "[sg,fill]push[sg,fill][sg,fill]unrel[sg,fill]unrel[sg,fill]", "");
+ JPanel gcPanel = createTabPanel(gcM);
+ gcPanel.add(createButton("Help"));
+ gcPanel.add(createButton("< Back"));
+ gcPanel.add(createButton("Forward >"));
+ gcPanel.add(createButton("Apply"));
+ gcPanel.add(createButton("Cancel"));
+
+ // Ungrouped Rows
+ MigLayout ugrM = new MigLayout(); // no "sg" is the only difference to next panel
+ JPanel ugrPanel = createTabPanel(ugrM);
+ ugrPanel.add(createLabel("File Number:"));
+ ugrPanel.add(createTextField(30), "wrap");
+ ugrPanel.add(createLabel("BL/MBL number:"));
+ ugrPanel.add(createTextField(7), "split 2");
+ ugrPanel.add(createTextField(7), "wrap");
+ ugrPanel.add(createLabel("Entry Date:"));
+ ugrPanel.add(createTextField(7), "wrap");
+ ugrPanel.add(createLabel("RFQ Number:"));
+ ugrPanel.add(createTextField(30), "wrap");
+ ugrPanel.add(createLabel("Goods:"));
+ ugrPanel.add(createCheck("Dangerous"), "wrap");
+ ugrPanel.add(createLabel("Shipper:"));
+ ugrPanel.add(createTextField(30), "wrap");
+ ugrPanel.add(createLabel("Customer:"));
+ ugrPanel.add(createTextField(""), "split 2,growx");
+ ugrPanel.add(createButton("..."), "width 60px:pref,wrap");
+ ugrPanel.add(createLabel("Port of Loading:"));
+ ugrPanel.add(createTextField(30), "wrap");
+ ugrPanel.add(createLabel("Destination:"));
+ ugrPanel.add(createTextField(30), "wrap");
+
+ // Grouped Rows
+ MigLayout grM = new MigLayout("", "[]", "[sg]"); // "sg" is the only difference to previous panel
+ JPanel grPanel = createTabPanel(grM);
+ grPanel.add(createLabel("File Number:"));
+ grPanel.add(createTextField(30),"wrap");
+ grPanel.add(createLabel("BL/MBL number:"));
+ grPanel.add(createTextField(7),"split 2");
+ grPanel.add(createTextField(7), "wrap");
+ grPanel.add(createLabel("Entry Date:"));
+ grPanel.add(createTextField(7), "wrap");
+ grPanel.add(createLabel("RFQ Number:"));
+ grPanel.add(createTextField(30), "wrap");
+ grPanel.add(createLabel("Goods:"));
+ grPanel.add(createCheck("Dangerous"), "wrap");
+ grPanel.add(createLabel("Shipper:"));
+ grPanel.add(createTextField(30), "wrap");
+ grPanel.add(createLabel("Customer:"));
+ grPanel.add(createTextField(""), "split 2,growx");
+ grPanel.add(createButton("..."), "width 50px:pref,wrap");
+ grPanel.add(createLabel("Port of Loading:"));
+ grPanel.add(createTextField(30), "wrap");
+ grPanel.add(createLabel("Destination:"));
+ grPanel.add(createTextField(30), "wrap");
+
+ tabbedPane.addTab("Ungrouped", ugPanel);
+ tabbedPane.addTab("Grouped (Components)", gPanel);
+ tabbedPane.addTab("Grouped (Columns)", gcPanel);
+ tabbedPane.addTab("Ungrouped Rows", ugrPanel);
+ tabbedPane.addTab("Grouped Rows", grPanel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// Ungrouped\n" +
+ "MigLayout ugM = new MigLayout(\"\", \"[]push[][][]\", \"\");\n" +
+ "JPanel ugPanel = createTabPanel(ugM);\n" +
+ "ugPanel.add(createButton(\"Help\"));\n" +
+ "ugPanel.add(createButton(\"< Back\"), \"\");\n" +
+ "ugPanel.add(createButton(\"Forward >\"), \"gap push\");\n" +
+ "ugPanel.add(createButton(\"Apply\"), \"gap unrel\");\n" +
+ "ugPanel.add(createButton(\"Cancel\"), \"gap unrel\");\n" +
+ "\n" +
+ "// Grouped Components\n" +
+ "MigLayout gM = new MigLayout(\"nogrid, fillx\");\n" +
+ "JPanel gPanel = createTabPanel(gM);\n" +
+ "gPanel.add(createButton(\"Help\"), \"sg\");\n" +
+ "gPanel.add(createButton(\"< Back\"), \"sg,gap push\");\n" +
+ "gPanel.add(createButton(\"Forward >\"), \"sg\");\n" +
+ "gPanel.add(createButton(\"Apply\"), \"sg,gap unrel\");\n" +
+ "gPanel.add(createButton(\"Cancel\"), \"sg,gap unrel\");\n" +
+ "\n" +
+ "// Grouped Columns\n" +
+ "MigLayout gcM = new MigLayout(\"\", \"[sg,fill]push[sg,fill][sg,fill]unrel[sg,fill]unrel[sg,fill]\", \"\");\n" +
+ "JPanel gcPanel = createTabPanel(gcM);\n" +
+ "gcPanel.add(createButton(\"Help\"));\n" +
+ "gcPanel.add(createButton(\"< Back\"));\n" +
+ "gcPanel.add(createButton(\"Forward >\"));\n" +
+ "gcPanel.add(createButton(\"Apply\"));\n" +
+ "gcPanel.add(createButton(\"Cancel\"));\n" +
+ "\n" +
+ "// Ungrouped Rows\n" +
+ "MigLayout ugrM = new MigLayout(); // no \"sg\" is the only difference to next panel\n" +
+ "JPanel ugrPanel = createTabPanel(ugrM);\n" +
+ "ugrPanel.add(createLabel(\"File Number:\"));\n" +
+ "ugrPanel.add(createTextField(30), \"wrap\");\n" +
+ "ugrPanel.add(createLabel(\"BL/MBL number:\"));\n" +
+ "ugrPanel.add(createTextField(7), \"split 2\");\n" +
+ "ugrPanel.add(createTextField(7), \"wrap\");\n" +
+ "ugrPanel.add(createLabel(\"Entry Date:\"));\n" +
+ "ugrPanel.add(createTextField(7), \"wrap\");\n" +
+ "ugrPanel.add(createLabel(\"RFQ Number:\"));\n" +
+ "ugrPanel.add(createTextField(30), \"wrap\");\n" +
+ "ugrPanel.add(createLabel(\"Goods:\"));\n" +
+ "ugrPanel.add(createCheck(\"Dangerous\"), \"wrap\");\n" +
+ "ugrPanel.add(createLabel(\"Shipper:\"));\n" +
+ "ugrPanel.add(createTextField(30), \"wrap\");\n" +
+ "ugrPanel.add(createLabel(\"Customer:\"));\n" +
+ "ugrPanel.add(createTextField(\"\"), \"split 2,growx\");\n" +
+ "ugrPanel.add(createButton(\"...\"), \"width 60px:pref,wrap\");\n" +
+ "ugrPanel.add(createLabel(\"Port of Loading:\"));\n" +
+ "ugrPanel.add(createTextField(30), \"wrap\");\n" +
+ "ugrPanel.add(createLabel(\"Destination:\"));\n" +
+ "ugrPanel.add(createTextField(30), \"wrap\");\n" +
+ "\n" +
+ "// Grouped Rows\n" +
+ "MigLayout grM = new MigLayout(\"\", \"[]\", \"[sg]\"); // \"sg\" is the only difference to previous panel\n" +
+ "JPanel grPanel = createTabPanel(grM);\n" +
+ "grPanel.add(createLabel(\"File Number:\"));\n" +
+ "grPanel.add(createTextField(30),\"wrap\");\n" +
+ "grPanel.add(createLabel(\"BL/MBL number:\"));\n" +
+ "grPanel.add(createTextField(7),\"split 2\");\n" +
+ "grPanel.add(createTextField(7), \"wrap\");\n" +
+ "grPanel.add(createLabel(\"Entry Date:\"));\n" +
+ "grPanel.add(createTextField(7), \"wrap\");\n" +
+ "grPanel.add(createLabel(\"RFQ Number:\"));\n" +
+ "grPanel.add(createTextField(30), \"wrap\");\n" +
+ "grPanel.add(createLabel(\"Goods:\"));\n" +
+ "grPanel.add(createCheck(\"Dangerous\"), \"wrap\");\n" +
+ "grPanel.add(createLabel(\"Shipper:\"));\n" +
+ "grPanel.add(createTextField(30), \"wrap\");\n" +
+ "grPanel.add(createLabel(\"Customer:\"));\n" +
+ "grPanel.add(createTextField(\"\"), \"split 2,growx\");\n" +
+ "grPanel.add(createButton(\"...\"), \"width 50px:pref,wrap\");\n" +
+ "grPanel.add(createLabel(\"Port of Loading:\"));\n" +
+ "grPanel.add(createTextField(30), \"wrap\");\n" +
+ "grPanel.add(createLabel(\"Destination:\"));\n" +
+ "grPanel.add(createTextField(30), \"wrap\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Ungrouped\", ugPanel);\n" +
+ "tabbedPane.addTab(\"Grouped (Components)\", gPanel);\n" +
+ "tabbedPane.addTab(\"Grouped (Columns)\", gcPanel);\n" +
+ "tabbedPane.addTab(\"Ungrouped Rows\", ugrPanel);\n" +
+ "tabbedPane.addTab(\"Grouped Rows\", grPanel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createSpan()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Horizontal span
+ MigLayout colLM = new MigLayout("nocache",
+ "[fill][25%!,fill][105lp!,fill][100px!,fill]",
+ "[]15[][]");
+ JPanel colPanel = createTabPanel(colLM);
+ colPanel.add(createTextField("Col1 [ ]"));
+ colPanel.add(createTextField("Col2 [25%!]"));
+ colPanel.add(createTextField("Col3 [105lp!]"));
+ colPanel.add(createTextField("Col4 [100px!]"), "wrap");
+
+ colPanel.add(createLabel("Full Name:"));
+ colPanel.add(createTextField("span, growx", 40), "span,growx");
+
+ colPanel.add(createLabel("Phone:"));
+ colPanel.add(createTextField(5), "span 3, split 5");
+ colPanel.add(createTextField(7));
+ colPanel.add(createTextField(7));
+ colPanel.add(createTextField(9));
+ colPanel.add(createLabel("(span 3, split 4)"), "wrap");
+
+ colPanel.add(createLabel("Zip/City:"));
+ colPanel.add(createTextField(5));
+ colPanel.add(createTextField("span 2, growx", 5), "span 2,growx");
+
+ // Vertical span
+ MigLayout rowLM = new MigLayout("wrap",
+ "[225lp]para[225lp]",
+ "[]3[]unrel[]3[]unrel[]3[]");
+ JPanel rowPanel = createTabPanel(rowLM);
+ rowPanel.add(createLabel("Name"));
+ rowPanel.add(createLabel("Notes"));
+ rowPanel.add(createTextField("growx"), "growx");
+ rowPanel.add(createTextArea("spany,grow", 5, 20), "spany,grow");
+ rowPanel.add(createLabel("Phone"));
+ rowPanel.add(createTextField("growx"), "growx");
+ rowPanel.add(createLabel("Fax"));
+ rowPanel.add(createTextField("growx"), "growx");
+
+ tabbedPane.addTab("Column Span/Split", colPanel);
+ tabbedPane.addTab("Row Span", rowPanel);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("\t\tJTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "\t\t// Horizontal span\n" +
+ "\t\tMigLayout colLM = new MigLayout(\"\",\n" +
+ "\t\t \"[fill][25%!,fill][105lp!,fill][100px!,fill]\",\n" +
+ "\t\t \"[]15[][]\");\n" +
+ "\t\tJPanel colPanel = createTabPanel(colLM);\n" +
+ "\t\tcolPanel.add(createTextField(\"Col1 [ ]\"));\n" +
+ "\t\tcolPanel.add(createTextField(\"Col2 [25%!]\"));\n" +
+ "\t\tcolPanel.add(createTextField(\"Col3 [105lp!]\"));\n" +
+ "\t\tcolPanel.add(createTextField(\"Col4 [100px!]\"), \"wrap\");\n" +
+ "\n" +
+ "\t\tcolPanel.add(createLabel(\"Full Name:\"));\n" +
+ "\t\tcolPanel.add(createTextField(\"span, growx\", 40), \"span,growx\");\n" +
+ "\n" +
+ "\t\tcolPanel.add(createLabel(\"Phone:\"));\n" +
+ "\t\tcolPanel.add(createTextField(5), \"span 3, split 5\");\n" +
+ "\t\tcolPanel.add(createTextField(7));\n" +
+ "\t\tcolPanel.add(createTextField(7));\n" +
+ "\t\tcolPanel.add(createTextField(9));\n" +
+ "\t\tcolPanel.add(createLabel(\"(span 3, split 4)\"), \"wrap\");\n" +
+ "\n" +
+ "\t\tcolPanel.add(createLabel(\"Zip/City:\"));\n" +
+ "\t\tcolPanel.add(createTextField(5));\n" +
+ "\t\tcolPanel.add(createTextField(\"span 2, growx\", 5), \"span 2,growx\");\n" +
+ "\n" +
+ "\t\t// Vertical span\n" +
+ "\t\tMigLayout rowLM = new MigLayout(\"wrap\",\n" +
+ "\t\t \"[225lp]para[225lp]\",\n" +
+ "\t\t \"[]3[]unrel[]3[]unrel[]3[]\");\n" +
+ "\t\tJPanel rowPanel = createTabPanel(rowLM);\n" +
+ "\t\trowPanel.add(createLabel(\"Name\"));\n" +
+ "\t\trowPanel.add(createLabel(\"Notes\"));\n" +
+ "\t\trowPanel.add(createTextField(\"growx\"), \"growx\");\n" +
+ "\t\trowPanel.add(createTextArea(\"spany,grow\", 5, 20), \"spany,grow\");\n" +
+ "\t\trowPanel.add(createLabel(\"Phone\"));\n" +
+ "\t\trowPanel.add(createTextField(\"growx\"), \"growx\");\n" +
+ "\t\trowPanel.add(createLabel(\"Fax\"));\n" +
+ "\t\trowPanel.add(createTextField(\"growx\"), \"growx\");\n" +
+ "\n" +
+ "\t\ttabbedPane.addTab(\"Column Span/Split\", colPanel);\n" +
+ "\t\ttabbedPane.addTab(\"Row Span\", rowPanel);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createGrowing()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // All tab
+ MigLayout allLM = new MigLayout("",
+ "[pref!][grow,fill]",
+ "[]15[]");
+ JPanel allTab = createTabPanel(allLM);
+ allTab.add(createLabel("Fixed"));
+ allTab.add(createLabel("Gets all extra space"), "wrap");
+ allTab.add(createTextField(5));
+ allTab.add(createTextField(5));
+
+ // Half tab
+ MigLayout halfLM = new MigLayout("",
+ "[pref!][grow,fill]",
+ "[]15[]");
+ JPanel halfTab = createTabPanel(halfLM);
+ halfTab.add(createLabel("Fixed"));
+ halfTab.add(createLabel("Gets half of extra space"));
+ halfTab.add(createLabel("Gets half of extra space"), "wrap");
+ halfTab.add(createTextField(5));
+ halfTab.add(createTextField(5));
+ halfTab.add(createTextField(5));
+
+ // Percent 1 tab
+ MigLayout p1LM = new MigLayout("",
+ "[pref!][0:0,grow 25,fill][0:0,grow 75,fill]",
+ "[]15[]");
+ JPanel p1Tab = createTabPanel(p1LM);
+ p1Tab.add(createLabel("Fixed"));
+ p1Tab.add(createLabel("Gets 25% of extra space"), "");
+ p1Tab.add(createLabel("Gets 75% of extra space"), "wrap");
+ p1Tab.add(createTextField(5));
+ p1Tab.add(createTextField(5));
+ p1Tab.add(createTextField(5));
+
+ // Percent 2 tab
+ MigLayout p2LM = new MigLayout("",
+ "[0:0,grow 33,fill][0:0,grow 67,fill]",
+ "[]15[]");
+ JPanel p2Tab = createTabPanel(p2LM);
+ p2Tab.add(createLabel("Gets 33% of extra space"), "");
+ p2Tab.add(createLabel("Gets 67% of extra space"), "wrap");
+ p2Tab.add(createTextField(5));
+ p2Tab.add(createTextField(5));
+
+ // Vertical 1 tab
+ MigLayout v1LM = new MigLayout("flowy",
+ "[]15[]",
+ "[][c,pref!][c,grow 25,fill][c,grow 75,fill]");
+ JPanel v1Tab = createTabPanel(v1LM);
+ v1Tab.add(createLabel("Fixed"), "skip");
+ v1Tab.add(createLabel("Gets 25% of extra space"));
+ v1Tab.add(createLabel("Gets 75% of extra space"), "wrap");
+ v1Tab.add(createLabel("new JTextArea(4, 30)"));
+ v1Tab.add(createTextAreaScroll("", 4, 30, false));
+ v1Tab.add(createTextAreaScroll("", 4, 30, false));
+ v1Tab.add(createTextAreaScroll("", 4, 30, false));
+
+ // Vertical 2 tab
+ MigLayout v2LM = new MigLayout("flowy",
+ "[]15[]",
+ "[][c,grow 33,fill][c,grow 67,fill]");
+ JPanel v2Tab = createTabPanel(v2LM);
+ v2Tab.add(createLabel("Gets 33% of extra space"), "skip");
+ v2Tab.add(createLabel("Gets 67% of extra space"), "wrap");
+ v2Tab.add(createLabel("new JTextArea(4, 30)"));
+ v2Tab.add(createTextAreaScroll("", 4, 30, false));
+ v2Tab.add(createTextAreaScroll("", 4, 30, false));
+
+ tabbedPane.addTab("All", allTab);
+ tabbedPane.addTab("Half", halfTab);
+ tabbedPane.addTab("Percent 1", p1Tab);
+ tabbedPane.addTab("Percent 2", p2Tab);
+ tabbedPane.addTab("Vertical 1", v1Tab);
+ tabbedPane.addTab("Vertical 2", v2Tab);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// All tab\n" +
+ "MigLayout allLM = new MigLayout(\"\",\n" +
+ " \"[pref!][grow,fill]\",\n" +
+ " \"[]15[]\");\n" +
+ "JPanel allTab = createTabPanel(allLM);\n" +
+ "allTab.add(createLabel(\"Fixed\"));\n" +
+ "allTab.add(createLabel(\"Gets all extra space\"), \"wrap\");\n" +
+ "allTab.add(createTextField(5));\n" +
+ "allTab.add(createTextField(5));\n" +
+ "\n" +
+ "// Half tab\n" +
+ "MigLayout halfLM = new MigLayout(\"\",\n" +
+ " \"[pref!][grow,fill]\",\n" +
+ " \"[]15[]\");\n" +
+ "JPanel halfTab = createTabPanel(halfLM);\n" +
+ "halfTab.add(createLabel(\"Fixed\"));\n" +
+ "halfTab.add(createLabel(\"Gets half of extra space\"));\n" +
+ "halfTab.add(createLabel(\"Gets half of extra space\"), \"wrap\");\n" +
+ "halfTab.add(createTextField(5));\n" +
+ "halfTab.add(createTextField(5));\n" +
+ "halfTab.add(createTextField(5));\n" +
+ "\n" +
+ "// Percent 1 tab\n" +
+ "MigLayout p1LM = new MigLayout(\"\",\n" +
+ " \"[pref!][0:0,grow 25,fill][0:0,grow 75,fill]\",\n" +
+ " \"[]15[]\");\n" +
+ "JPanel p1Tab = createTabPanel(p1LM);\n" +
+ "p1Tab.add(createLabel(\"Fixed\"));\n" +
+ "p1Tab.add(createLabel(\"Gets 25% of extra space\"), \"\");\n" +
+ "p1Tab.add(createLabel(\"Gets 75% of extra space\"), \"wrap\");\n" +
+ "p1Tab.add(createTextField(5));\n" +
+ "p1Tab.add(createTextField(5));\n" +
+ "p1Tab.add(createTextField(5));\n" +
+ "\n" +
+ "// Percent 2 tab\n" +
+ "MigLayout p2LM = new MigLayout(\"\",\n" +
+ " \"[0:0,grow 33,fill][0:0,grow 67,fill]\",\n" +
+ " \"[]15[]\");\n" +
+ "JPanel p2Tab = createTabPanel(p2LM);\n" +
+ "p2Tab.add(createLabel(\"Gets 33% of extra space\"), \"\");\n" +
+ "p2Tab.add(createLabel(\"Gets 67% of extra space\"), \"wrap\");\n" +
+ "p2Tab.add(createTextField(5));\n" +
+ "p2Tab.add(createTextField(5));\n" +
+ "\n" +
+ "// Vertical 1 tab\n" +
+ "MigLayout v1LM = new MigLayout(\"flowy\",\n" +
+ " \"[]15[]\",\n" +
+ " \"[][c,pref!][c,grow 25,fill][c,grow 75,fill]\");\n" +
+ "JPanel v1Tab = createTabPanel(v1LM);\n" +
+ "v1Tab.add(createLabel(\"Fixed\"), \"skip\");\n" +
+ "v1Tab.add(createLabel(\"Gets 25% of extra space\"));\n" +
+ "v1Tab.add(createLabel(\"Gets 75% of extra space\"), \"wrap\");\n" +
+ "v1Tab.add(createLabel(\"new JTextArea(4, 30)\"));\n" +
+ "v1Tab.add(createTextAreaScroll(\"\", 4, 30, false));\n" +
+ "v1Tab.add(createTextAreaScroll(\"\", 4, 30, false));\n" +
+ "v1Tab.add(createTextAreaScroll(\"\", 4, 30, false));\n" +
+ "\n" +
+ "// Vertical 2 tab\n" +
+ "MigLayout v2LM = new MigLayout(\"flowy\",\n" +
+ " \"[]15[]\",\n" +
+ " \"[][c,grow 33,fill][c,grow 67,fill]\");\n" +
+ "JPanel v2Tab = createTabPanel(v2LM);\n" +
+ "v2Tab.add(createLabel(\"Gets 33% of extra space\"), \"skip\");\n" +
+ "v2Tab.add(createLabel(\"Gets 67% of extra space\"), \"wrap\");\n" +
+ "v2Tab.add(createLabel(\"new JTextArea(4, 30)\"));\n" +
+ "v2Tab.add(createTextAreaScroll(\"\", 4, 30, false));\n" +
+ "v2Tab.add(createTextAreaScroll(\"\", 4, 30, false));\n" +
+ "\n" +
+ "tabbedPane.addTab(\"All\", allTab);\n" +
+ "tabbedPane.addTab(\"Half\", halfTab);\n" +
+ "tabbedPane.addTab(\"Percent 1\", p1Tab);\n" +
+ "tabbedPane.addTab(\"Percent 2\", p2Tab);\n" +
+ "tabbedPane.addTab(\"Vertical 1\", v1Tab);\n" +
+ "tabbedPane.addTab(\"Vertical 2\", v2Tab);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createBasic_Sizes()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Horizontal tab
+ MigLayout horLM = new MigLayout("",
+ "[]15[75px]25[min]25[]",
+ "[]15");
+ JPanel horTab = createTabPanel(horLM);
+ horTab.add(createLabel("75px"), "skip");
+ horTab.add(createLabel("Min"));
+ horTab.add(createLabel("Pref"), "wrap");
+
+ horTab.add(createLabel("new TextField(15)"));
+ horTab.add(createTextField(15));
+ horTab.add(createTextField(15));
+ horTab.add(createTextField(15));
+
+ // Vertical tab 1
+ MigLayout verLM = new MigLayout("flowy,wrap",
+ "[]15[]",
+ "[]15[c,45px]15[c,min]15[c,pref]");
+ JPanel verTab = createTabPanel(verLM);
+ verTab.add(createLabel("45px"), "skip");
+ verTab.add(createLabel("Min"));
+ verTab.add(createLabel("Pref"));
+
+ verTab.add(createLabel("new JTextArea(10, 40)"));
+ verTab.add(createTextArea("", 10, 40));
+ verTab.add(createTextArea("", 10, 40));
+ verTab.add(createTextArea("", 10, 40));
+
+ // Componentsized/Baseline 2
+ MigLayout verLM2 = new MigLayout("flowy,wrap",
+ "[]15[]",
+ "[]15[baseline]15[baseline]15[baseline]");
+ JPanel verTab2 = createTabPanel(verLM2);
+ verTab2.add(createLabel("45px"), "skip");
+ verTab2.add(createLabel("Min"));
+ verTab2.add(createLabel("Pref"));
+
+ verTab2.add(createLabel("new JTextArea(10, 40)"));
+ verTab2.add(createTextArea("", 10, 40), "height 45");
+ verTab2.add(createTextArea("", 10, 40), "height min");
+ verTab2.add(createTextArea("", 10, 40), "height pref");
+
+ tabbedPane.addTab("Horizontal - Column size set", horTab);
+ tabbedPane.addTab("Vertical - Row sized", verTab);
+ tabbedPane.addTab("Vertical - Component sized + Baseline", verTab2);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// Horizontal tab\n" +
+ "MigLayout horLM = new MigLayout(\"\",\n" +
+ " \"[]15[75px]25[min]25[]\",\n" +
+ " \"[]15\");\n" +
+ "JPanel horTab = createTabPanel(horLM);\n" +
+ "horTab.add(createLabel(\"75px\"), \"skip\");\n" +
+ "horTab.add(createLabel(\"Min\"));\n" +
+ "horTab.add(createLabel(\"Pref\"), \"wrap\");\n" +
+ "\n" +
+ "horTab.add(createLabel(\"new TextField(15)\"));\n" +
+ "horTab.add(createTextField(15));\n" +
+ "horTab.add(createTextField(15));\n" +
+ "horTab.add(createTextField(15));\n" +
+ "\n" +
+ "// Vertical tab 1\n" +
+ "MigLayout verLM = new MigLayout(\"flowy,wrap\",\n" +
+ " \"[]15[]\",\n" +
+ " \"[]15[c,45px]15[c,min]15[c,pref]\");\n" +
+ "JPanel verTab = createTabPanel(verLM);\n" +
+ "verTab.add(createLabel(\"45px\"), \"skip\");\n" +
+ "verTab.add(createLabel(\"Min\"));\n" +
+ "verTab.add(createLabel(\"Pref\"));\n" +
+ "\n" +
+ "verTab.add(createLabel(\"new JTextArea(10, 40)\"));\n" +
+ "verTab.add(createTextArea(\"\", 10, 40));\n" +
+ "verTab.add(createTextArea(\"\", 10, 40));\n" +
+ "verTab.add(createTextArea(\"\", 10, 40));\n" +
+ "\n" +
+ "// Componentsized/Baseline 2\n" +
+ "MigLayout verLM2 = new MigLayout(\"flowy,wrap\",\n" +
+ " \"[]15[]\",\n" +
+ " \"[]15[baseline]15[baseline]15[baseline]\");\n" +
+ "JPanel verTab2 = createTabPanel(verLM2);\n" +
+ "verTab2.add(createLabel(\"45px\"), \"skip\");\n" +
+ "verTab2.add(createLabel(\"Min\"));\n" +
+ "verTab2.add(createLabel(\"Pref\"));\n" +
+ "\n" +
+ "verTab2.add(createLabel(\"new JTextArea(10, 40)\"));\n" +
+ "verTab2.add(createTextArea(\"\", 10, 40), \"height 45\");\n" +
+ "verTab2.add(createTextArea(\"\", 10, 40), \"height min\");\n" +
+ "verTab2.add(createTextArea(\"\", 10, 40), \"height pref\");\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Horizontal - Column size set\", horTab);\n" +
+ "tabbedPane.addTab(\"Vertical - Row sized\", verTab);\n" +
+ "tabbedPane.addTab(\"Vertical - Component sized + Baseline\", verTab2);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createAlignments()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // Horizontal tab
+ MigLayout horLM = new MigLayout("wrap",
+ "[label]15[left]15[center]15[right]15[fill]15[]",
+ "[]15[]");
+
+ String[] horLabels = new String[] {"[label]", "[left]", "[center]", "[right]", "[fill]", "[] (Default)"};
+ JPanel horTab = createTabPanel(horLM);
+ String[] horNames = new String[] {"First Name", "Phone Number", "Facsmile", "Email", "Address", "Other"};
+ for (int c = 0; c < horLabels.length; c++)
+ horTab.add(createLabel(horLabels[c]));
+
+ for (int r = 0; r < horLabels.length; r++) {
+ for (int c = 0; c < horNames.length; c++)
+ horTab.add(c == 0 ? createLabel(horNames[r] + ":") : createButton(horNames[r]));
+ }
+
+ // Vertical tab
+ MigLayout verLM = new MigLayout("wrap,flowy",
+ "[]unrel[]rel[]",
+ "[top]15[center]15[bottom]15[fill]15[fill,baseline]15[baseline]15[]");
+
+ String[] verLabels = new String[] {"[top]", "[center]", "[bottom]", "[fill]", "[fill,baseline]", "[baseline]", "[] (Default)"};
+ JPanel verTab = createTabPanel(verLM);
+
+ String[] verNames = benchRuns == 0 ? new String[] {"<html>One</html>", "<html>One<br>Two</html>"} : new String[] {"One", "One/Two"};
+ for (int c = 0; c < verLabels.length; c++)
+ verTab.add(createLabel(verLabels[c]));
+
+ for (int r = 0; r < verNames.length; r++) {
+ for (int c = 0; c < verLabels.length; c++)
+ verTab.add(createButton(verNames[r]));
+ }
+
+ for (int c = 0; c < verLabels.length; c++)
+ verTab.add(createTextField("JTextFied"));
+
+ for (int c = 0; c < verLabels.length; c++)
+ verTab.add(createTextArea("JTextArea", 1, 8));
+
+ for (int c = 0; c < verLabels.length; c++)
+ verTab.add(createTextArea("JTextArea\nwith two lines", 1, 10));
+
+ for (int c = 0; c < verLabels.length; c++)
+ verTab.add(createTextAreaScroll("Scrolling JTextArea\nwith two lines", 1, 15, true));
+
+ tabbedPane.addTab("Horizontal", horTab);
+ tabbedPane.addTab("Vertical", verTab);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// Horizontal tab\n" +
+ "MigLayout horLM = new MigLayout(\"wrap\",\n" +
+ " \"[left]15[center]15[right]15[fill]15[]\",\n" +
+ " \"rel[]rel\");\n" +
+ "\n" +
+ "String[] horLabels = new String[] {\"[left]\", \"[center]\", \"[right]\", \"[fill]\", \"[] (Default)\"};\n" +
+ "JPanel horTab = createTabPanel(horLM);\n" +
+ "String[] horNames = new String[] {\"First Name\", \"Phone Number\", \"Facsmile\", \"Email\", \"Address\"};\n" +
+ "for (int c = 0; c < horLabels.length; c++)\n" +
+ "\thorTab.add(createLabel(horLabels[c]));\n" +
+ "\n" +
+ "for (int r = 0; r < horLabels.length; r++) {\n" +
+ "\tfor (int c = 0; c < horNames.length; c++)\n" +
+ "\t\thorTab.add(createButton(horNames[r]));\n" +
+ "}\n" +
+ "\n" +
+ "// Vertical tab\n" +
+ "MigLayout verLM = new MigLayout(\"wrap,flowy\",\n" +
+ " \"[]unrel[]rel[]\",\n" +
+ " \"[top]15[center]15[bottom]15[fill]15[fill,baseline]15[baseline]15[]\");\n" +
+ "\n" +
+ "String[] verLabels = new String[] {\"[top]\", \"[center]\", \"[bottom]\", \"[fill]\", \"[fill,baseline]\", \"[baseline]\", \"[] (Default)\"};\n" +
+ "JPanel verTab = createTabPanel(verLM);\n" +
+ "\n" +
+ "String[] verNames = new String[] {\"<html>One</html>\", \"<html>One<br>Two</html>\"};\n" +
+ "for (int c = 0; c < verLabels.length; c++)\n" +
+ "\tverTab.add(createLabel(verLabels[c]));\n" +
+ "\n" +
+ "for (int r = 0; r < verNames.length; r++) {\n" +
+ "\tfor (int c = 0; c < verLabels.length; c++)\n" +
+ "\t\tverTab.add(createButton(verNames[r]));\n" +
+ "}\n" +
+ "\n" +
+ "for (int c = 0; c < verLabels.length; c++)\n" +
+ "\tverTab.add(createTextField(\"JTextFied\"));\n" +
+ "\n" +
+ "for (int c = 0; c < verLabels.length; c++)\n" +
+ "\tverTab.add(createTextArea(\"JTextArea\", 1, 8));\n" +
+ "\n" +
+ "for (int c = 0; c < verLabels.length; c++)\n" +
+ "\tverTab.add(createTextArea(\"JTextArea\\nwith two lines\", 1, 10));\n" +
+ "\n" +
+ "for (int c = 0; c < verLabels.length; c++)\n" +
+ "\tverTab.add(createTextAreaScroll(\"Scrolling JTextArea\\nwith two lines\", 1, 15, true));\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Horizontal\", horTab);\n" +
+ "tabbedPane.addTab(\"Vertical\", verTab);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createQuick_Start()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ JPanel p = createTabPanel(new MigLayout("inset 20"));
+
+ addSeparator(p, "General");
+
+ p.add(createLabel("Company"), "gap para");
+ p.add(createTextField(""), "span, growx");
+ p.add(createLabel("Contact"), "gap para");
+ p.add(createTextField(""), "span, growx, wrap para");
+
+ addSeparator(p, "Propeller");
+
+ p.add(createLabel("PTI/kW"), "gap para");
+ p.add(createTextField(10));
+ p.add(createLabel("Power/kW"),"gap para");
+ p.add(createTextField(10), "wrap");
+ p.add(createLabel("R/mm"), "gap para");
+ p.add(createTextField(10));
+ p.add(createLabel("D/mm"), "gap para");
+ p.add(createTextField(10));
+
+ tabbedPane.addTab("Quick Start", p);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "JPanel p = createTabPanel(new MigLayout());\n" +
+ "\n" +
+ "addSeparator(p, \"General\");\n" +
+ "\n" +
+ "p.add(createLabel(\"Company\"), \"gap para\");\n" +
+ "p.add(createTextField(\"\"), \"span, growx, wrap\");\n" +
+ "p.add(createLabel(\"Contact\"), \"gap para\");\n" +
+ "p.add(createTextField(\"\"), \"span, growx, wrap para\");\n" +
+ "\n" +
+ "addSeparator(p, \"Propeller\");\n" +
+ "\n" +
+ "p.add(createLabel(\"PTI/kW\"), \"gap para\");\n" +
+ "p.add(createTextField(10));\n" +
+ "p.add(createLabel(\"Power/kW\"),\"gap para\");\n" +
+ "p.add(createTextField(10), \"wrap\");\n" +
+ "p.add(createLabel(\"R/mm\"), \"gap para\");\n" +
+ "p.add(createTextField(10));\n" +
+ "p.add(createLabel(\"D/mm\"), \"gap para\");\n" +
+ "p.add(createTextField(10));\n" +
+ "\n" +
+ "tabbedPane.addTab(\"Quick Start\", p);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createGrow_Shrink()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ // shrink tab
+ MigLayout slm = new MigLayout("nogrid");
+ JPanel sPanel = createTabPanel(slm);
+
+ JScrollPane sDescrText = createTextAreaScroll("Use the slider to see how the components shrink depending on the constraints set on them.\n\n'shp' means Shrink Priority. " +
+ "Lower values will be shrunk before higer ones and the default value is 100.\n\n'shrink' means Shrink Weight. " +
+ "Lower values relative to other's means they will shrink less when space is scarse. " +
+ "Shrink Weight is only relative to components with the same Shrink Priority. Default Shrink Weight is 100.\n\n" +
+ "The component's minimum size will always be honored.", 0, 0, true);
+
+ sDescrText.setOpaque(OPAQUE);
+ sDescrText.setBorder(new EmptyBorder(10, 10, 10, 10));
+ ((JTextArea) sDescrText.getViewport().getView()).setOpaque(OPAQUE);
+ sDescrText.getViewport().setOpaque(OPAQUE);
+
+ JSplitPane sSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sPanel, sDescrText);
+ sSplitPane.setOpaque(OPAQUE);
+ sSplitPane.setBorder(null);
+
+ sPanel.add(createTextField("shp 110", 12), "shp 110");
+ sPanel.add(createTextField("Default (100)", 12), "");
+ sPanel.add(createTextField("shp 90", 12), "shp 90");
+
+ sPanel.add(createTextField("shrink 25", 20), "newline,shrink 25");
+ sPanel.add(createTextField("shrink 75", 20), "shrink 75");
+
+ sPanel.add(createTextField("Default", 20), "newline");
+ sPanel.add(createTextField("Default", 20), "");
+
+ sPanel.add(createTextField("shrink 0", 40), "newline,shrink 0");
+
+ sPanel.add(createTextField("shp 110", 12), "newline,shp 110");
+ sPanel.add(createTextField("shp 100,shrink 25", 12), "shp 100,shrink 25");
+ sPanel.add(createTextField("shp 100,shrink 75", 12), "shp 100,shrink 75");
+ tabbedPane.addTab("Shrink", sSplitPane);
+
+ // Grow tab
+ MigLayout glm = new MigLayout("nogrid", "[grow]", "");
+ JPanel gPanel = createTabPanel(glm);
+
+ JScrollPane gDescrText = createTextAreaScroll("'gp' means Grow Priority. " +
+ "Higher values will be grown before lower ones and the default value is 100.\n\n'grow' means Grow Weight. " +
+ "Higher values relative to other's means they will grow more when space is up for takes. " +
+ "Grow Weight is only relative to components with the same Grow Priority. Default Grow Weight is 0 which means " +
+ "components will normally not grow. \n\nNote that the buttons in the first and last row have max width set to 170 to " +
+ "emphasize Grow Priority.\n\nThe component's maximum size will always be honored.", 0, 0, true);
+
+ gDescrText.setOpaque(OPAQUE);
+ gDescrText.setBorder(new EmptyBorder(10, 10, 10, 10));
+ ((JTextArea) gDescrText.getViewport().getView()).setOpaque(OPAQUE);
+ gDescrText.getViewport().setOpaque(OPAQUE);
+
+ JSplitPane gSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, gPanel, gDescrText);
+ gSplitPane.setOpaque(OPAQUE);
+ gSplitPane.setBorder(null);
+
+ gPanel.add(createButton("gp 110,grow"), "gp 110,grow,wmax 170");
+ gPanel.add(createButton("Default (100),grow"), "grow,wmax 170");
+ gPanel.add(createButton("gp 90,grow"), "gp 90,grow,wmax 170");
+
+ gPanel.add(createButton("Default Button"), "newline");
+
+ gPanel.add(createButton("growx"), "newline,growx,wrap");
+
+ gPanel.add(createButton("gp 110,grow"), "gp 110,grow,wmax 170");
+ gPanel.add(createButton("gp 100,grow 25"), "gp 100,grow 25,wmax 170");
+ gPanel.add(createButton("gp 100,grow 75"), "gp 100,grow 75,wmax 170");
+ tabbedPane.addTab("Grow", gSplitPane);
+
+ // Disregard. Just forgetting the source code text close to the source code.
+ setSource("JTabbedPane tabbedPane = new JTabbedPane();\n" +
+ "\n" +
+ "// shrink tab\n" +
+ "MigLayout slm = new MigLayout(\"nogrid\");\n" +
+ "JPanel sPanel = createTabPanel(slm);\n" +
+ "\n" +
+ "JScrollPane sDescrText = createTextAreaScroll(\"Use the slider to see how the components shrink depending on the constraints set on them.\\n\\n'shp' means Shrink Priority. \" +\n" +
+ " \"Lower values will be shrunk before higer ones and the default value is 100.\\n\\n'shrink' means Shrink Weight. \" +\n" +
+ " \"Lower values relative to other's means they will shrink less when space is scarse. \" +\n" +
+ " \"Shrink Weight is only relative to components with the same Shrink Priority. Default Shrink Weight is 100.\\n\\n\" +\n" +
+ " \"The component's minimum size will always be honored.\", 0, 0, true);\n" +
+ "\n" +
+ "sDescrText.setOpaque(OPAQUE);\n" +
+ "sDescrText.setBorder(new EmptyBorder(10, 10, 10, 10));\n" +
+ "((JTextArea) sDescrText.getViewport().getView()).setOpaque(OPAQUE);\n" +
+ "sDescrText.getViewport().setOpaque(OPAQUE);\n" +
+ "\n" +
+ "JSplitPane sSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, sPanel, sDescrText);\n" +
+ "sSplitPane.setOpaque(OPAQUE);\n" +
+ "sSplitPane.setBorder(null);\n" +
+ "\n" +
+ "sPanel.add(createTextField(\"shp 110\", 12), \"shp 110\");\n" +
+ "sPanel.add(createTextField(\"Default (100)\", 12), \"\");\n" +
+ "sPanel.add(createTextField(\"shp 90\", 12), \"shp 90\");\n" +
+ "\n" +
+ "sPanel.add(createTextField(\"shrink 25\", 20), \"newline,shrink 25\");\n" +
+ "sPanel.add(createTextField(\"shrink 75\", 20), \"shrink 75\");\n" +
+ "\n" +
+ "sPanel.add(createTextField(\"Default\", 20), \"newline\");\n" +
+ "sPanel.add(createTextField(\"Default\", 20), \"\");\n" +
+ "\n" +
+ "sPanel.add(createTextField(\"shrink 0\", 40), \"newline,shrink 0\");\n" +
+ "\n" +
+ "sPanel.add(createTextField(\"shp 110\", 12), \"newline,shp 110\");\n" +
+ "sPanel.add(createTextField(\"shp 100,shrink 25\", 12), \"shp 100,shrink 25\");\n" +
+ "sPanel.add(createTextField(\"shp 100,shrink 75\", 12), \"shp 100,shrink 75\");\n" +
+ "tabbedPane.addTab(\"Shrink\", sSplitPane);\n" +
+ "\n" +
+ "// Grow tab\n" +
+ "MigLayout glm = new MigLayout(\"nogrid\", \"[grow]\", \"\");\n" +
+ "JPanel gPanel = createTabPanel(glm);\n" +
+ "\n" +
+ "JScrollPane gDescrText = createTextAreaScroll(\"'gp' means Grow Priority. \" +\n" +
+ " \"Higher values will be grown before lower ones and the default value is 100.\\n\\n'grow' means Grow Weight. \" +\n" +
+ " \"Higher values relative to other's means they will grow more when space is up for takes. \" +\n" +
+ " \"Grow Weight is only relative to components with the same Grow Priority. Default Grow Weight is 0 which means \" +\n" +
+ " \"components will normally not grow. \\n\\nNote that the buttons in the first and last row have max width set to 170 to \" +\n" +
+ " \"emphasize Grow Priority.\\n\\nThe component's maximum size will always be honored.\", 0, 0, true);\n" +
+ "\n" +
+ "gDescrText.setOpaque(OPAQUE);\n" +
+ "gDescrText.setBorder(new EmptyBorder(10, 10, 10, 10));\n" +
+ "((JTextArea) gDescrText.getViewport().getView()).setOpaque(OPAQUE);\n" +
+ "gDescrText.getViewport().setOpaque(OPAQUE);\n" +
+ "\n" +
+ "JSplitPane gSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, gPanel, gDescrText);\n" +
+ "gSplitPane.setOpaque(OPAQUE);\n" +
+ "gSplitPane.setBorder(null);\n" +
+ "\n" +
+ "gPanel.add(createButton(\"gp 110,grow\"), \"gp 110,grow,wmax 170\");\n" +
+ "gPanel.add(createButton(\"Default (100),grow\"), \"grow,wmax 170\");\n" +
+ "gPanel.add(createButton(\"gp 90,grow\"), \"gp 90,grow,wmax 170\");\n" +
+ "\n" +
+ "gPanel.add(createButton(\"Default Button\"), \"newline\");\n" +
+ "\n" +
+ "gPanel.add(createButton(\"growx\"), \"newline,growx,wrap\");\n" +
+ "\n" +
+ "gPanel.add(createButton(\"gp 110,grow\"), \"gp 110,grow,wmax 170\");\n" +
+ "gPanel.add(createButton(\"gp 100,grow 25\"), \"gp 100,grow 25,wmax 170\");\n" +
+ "gPanel.add(createButton(\"gp 100,grow 75\"), \"gp 100,grow 75,wmax 170\");\n" +
+ "tabbedPane.addTab(\"Grow\", gSplitPane);");
+
+ return tabbedPane;
+ }
+
+ public JComponent createPlainApi()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ MigLayout lm = new MigLayout(new LC(), null, null);
+ JPanel panel = createTabPanel(lm);
+
+ addSeparator(panel, "Manufacturer");
+ panel.add(createLabel("Company"));
+ panel.add(createTextField(""), "span,growx");
+ panel.add(createLabel("Contact"));
+ panel.add(createTextField(""), "span,growx");
+ panel.add(createLabel("Order No"));
+ panel.add(createTextField(15), "wrap");
+
+ addSeparator(panel, "Inspector");
+ panel.add(createLabel("Name"));
+ panel.add(createTextField(""), "span,growx");
+ panel.add(createLabel("Reference No"));
+ panel.add(createTextField(""), "wrap");
+ panel.add(createLabel("Status"));
+ panel.add(createCombo(new String[] {"In Progress", "Finnished", "Released"}), "wrap");
+
+ addSeparator(panel, "Ship");
+ panel.add(createLabel("Shipyard"));
+ panel.add(createTextField(""), "span,growx");
+ panel.add(createLabel("Register No"));
+ panel.add(createTextField(""));
+ panel.add(createLabel("Hull No"), "right");
+ panel.add(createTextField(15), "wrap");
+ panel.add(createLabel("Project Type"));
+ panel.add(createCombo(new String[] {"New Building", "Convention", "Repair"}));
+
+ tabbedPane.addTab("Plain", panel);
+
+ return tabbedPane;
+ }
+
+ // **********************************************************
+ // * Helper Methods
+ // **********************************************************
+
+ private final ToolTipListener toolTipListener = new ToolTipListener();
+ private final ConstraintListener constraintListener = new ConstraintListener();
+
+ private JLabel createLabel(String text)
+ {
+ return createLabel(text, SwingConstants.LEADING);
+ }
+
+ private JLabel createLabel(String text, int align)
+ {
+ final JLabel b = new JLabel(text, align);
+ configureActiveComponet(b);
+ return b;
+ }
+
+ public JComboBox createCombo(String[] items)
+ {
+ JComboBox combo = new JComboBox(items);
+
+ if (PlatformDefaults.getCurrentPlatform() == PlatformDefaults.MAC_OSX)
+ combo.setOpaque(false);
+
+ return combo;
+ }
+
+ private JTextField createTextField(int cols)
+ {
+ return createTextField("", cols);
+ }
+
+ private JTextField createTextField(String text)
+ {
+ return createTextField(text, 0);
+ }
+
+ private JTextField createTextField(String text, int cols)
+ {
+ final JTextField b = new JTextField(text, cols);
+
+ configureActiveComponet(b);
+
+ return b;
+ }
+
+ private static final Font BUTT_FONT = new Font("monospaced", Font.PLAIN, 12);
+ private JButton createButton()
+ {
+ return createButton("");
+ }
+
+ private JButton createButton(String text)
+ {
+ return createButton(text, false);
+ }
+
+ private JButton createButton(String text, boolean bold)
+ {
+ JButton b = new JButton(text) {
+ public void addNotify()
+ {
+ super.addNotify();
+ if (benchRuns == 0) { // Since this does not exist in the SWT version
+ if (getText().length() == 0) {
+ String lText = (String) ((MigLayout) getParent().getLayout()).getComponentConstraints(this);
+ setText(lText != null && lText.length() > 0 ? lText : "<Empty>");
+ }
+ } else {
+ setText("Benchmark Version");
+ }
+ }
+ };
+
+ if (bold)
+ b.setFont(b.getFont().deriveFont(Font.BOLD));
+
+ configureActiveComponet(b);
+
+ b.setOpaque(buttonOpaque); // Or window's buttons will have strange border
+
+ if (PlatformDefaults.getCurrentPlatform() == PlatformDefaults.MAC_OSX)
+ b.setContentAreaFilled(false);
+
+ return b;
+ }
+
+ private JToggleButton createToggleButton(String text)
+ {
+ JToggleButton b = new JToggleButton(text);
+// configureActiveComponet(b);
+ b.setOpaque(buttonOpaque); // Or window's buttons will have strange border
+ return b;
+ }
+
+ private JCheckBox createCheck(String text)
+ {
+ JCheckBox b = new JCheckBox(text);
+
+ configureActiveComponet(b);
+
+ b.setOpaque(OPAQUE); // Or window's checkboxes will have strange border
+ return b;
+ }
+
+ private JPanel createTabPanel(LayoutManager lm)
+ {
+ JPanel panel = new JPanel(lm);
+ configureActiveComponet(panel);
+ panel.setOpaque(OPAQUE);
+ return panel;
+ }
+
+ private JComponent createPanel()
+ {
+ return createPanel("");
+ }
+
+ private JComponent createPanel(String s)
+ {
+ JLabel panel = new JLabel(s, SwingConstants.CENTER) {
+ public void addNotify()
+ {
+ super.addNotify();
+ if (benchRuns == 0) { // Since this does not exist in the SWT version
+ if (getText().length() == 0) {
+ String lText = (String) ((MigLayout) getParent().getLayout()).getComponentConstraints(this);
+ setText(lText != null && lText.length() > 0 ? lText : "<Empty>");
+ }
+ }
+ }
+ };
+ panel.setBorder(new EtchedBorder());
+ panel.setOpaque(true);
+ configureActiveComponet(panel);
+
+ return panel;
+ }
+
+ private JTextArea createTextArea(String text, int rows, int cols)
+ {
+ JTextArea ta = new JTextArea(text, rows, cols);
+ ta.setBorder(UIManager.getBorder("TextField.border"));
+ ta.setFont(UIManager.getFont("TextField.font"));
+ ta.setWrapStyleWord(true);
+ ta.setLineWrap(true);
+
+ configureActiveComponet(ta);
+
+ return ta;
+ }
+
+ private JScrollPane createTextAreaScroll(String text, int rows, int cols, boolean hasVerScroll)
+ {
+ JTextArea ta = new JTextArea(text, rows, cols);
+ ta.setFont(UIManager.getFont("TextField.font"));
+ ta.setWrapStyleWord(true);
+ ta.setLineWrap(true);
+
+ JScrollPane scroll = new JScrollPane(
+ ta,
+ hasVerScroll ? ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED : ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER,
+ ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
+
+ return scroll;
+ }
+
+ private JComponent configureActiveComponet(JComponent c)
+ {
+ if (benchRuns == 0) {
+ c.addMouseMotionListener(toolTipListener);
+ c.addMouseListener(constraintListener);
+ }
+ return c;
+ }
+
+ static final Color LABEL_COLOR = new Color(0, 70, 213);
+ private void addSeparator(JPanel panel, String text)
+ {
+ JLabel l = createLabel(text);
+ l.setForeground(LABEL_COLOR);
+
+ panel.add(l, "gapbottom 1, span, split 2");
+ panel.add(configureActiveComponet(new JSeparator()), "gapleft rel, growx");
+ }
+
+ private class ConstraintListener extends MouseAdapter
+ {
+ public void mousePressed(MouseEvent e)
+ {
+ if (e.isPopupTrigger())
+ react(e);
+ }
+
+ public void mouseReleased(MouseEvent e)
+ {
+ if (e.isPopupTrigger())
+ react(e);
+ }
+
+ public void react(MouseEvent e)
+ {
+ JComponent c = (JComponent) e.getSource();
+ LayoutManager lm = c.getParent().getLayout();
+ if (lm instanceof MigLayout == false)
+ lm = c.getLayout();
+
+ if (lm instanceof MigLayout) {
+ MigLayout layout = (MigLayout) lm;
+ boolean isComp = layout.isManagingComponent(c);
+
+ Object compConstr = isComp ? layout.getComponentConstraints(c) : null;
+ if (isComp && compConstr == null)
+ compConstr = "";
+
+ Object rowsConstr = isComp ? null : layout.getRowConstraints();
+ Object colsConstr = isComp ? null : layout.getColumnConstraints();
+ Object layoutConstr = isComp ? null : layout.getLayoutConstraints();
+
+ ConstraintsDialog cDlg = new ConstraintsDialog(SwingDemo.this,
+ layoutConstr instanceof LC ? IDEUtil.getConstraintString((LC) layoutConstr, false) : (String) layoutConstr,
+ rowsConstr instanceof AC ? IDEUtil.getConstraintString((AC) rowsConstr, false, false) : (String) rowsConstr,
+ colsConstr instanceof AC ? IDEUtil.getConstraintString((AC) colsConstr, false, false) : (String) colsConstr,
+ compConstr instanceof CC ? IDEUtil.getConstraintString((CC) colsConstr, false) : (String) compConstr);
+
+ cDlg.pack();
+ cDlg.setLocationRelativeTo(c);
+
+ if (cDlg.showDialog()) {
+ try {
+ if (isComp) {
+ String constrStr = cDlg.componentConstrTF.getText().trim();
+ layout.setComponentConstraints(c, constrStr);
+ if (c instanceof JButton) {
+ c.setFont(BUTT_FONT);
+ ((JButton) c).setText(constrStr.length() == 0 ? "<Empty>" : constrStr);
+ }
+ } else {
+ layout.setLayoutConstraints(cDlg.layoutConstrTF.getText());
+ layout.setRowConstraints(cDlg.rowsConstrTF.getText());
+ layout.setColumnConstraints(cDlg.colsConstrTF.getText());
+ }
+ } catch(Exception ex) {
+ StringWriter sw = new StringWriter();
+ ex.printStackTrace(new PrintWriter(sw));
+ JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(c), sw.toString(), "Error parsing Constraint!", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+
+ c.invalidate();
+ c.getParent().validate();
+ }
+ }
+ }
+ }
+
+ private static class ToolTipListener extends MouseMotionAdapter
+ {
+ public void mouseMoved(MouseEvent e)
+ {
+ JComponent c = (JComponent) e.getSource();
+ LayoutManager lm = c.getParent().getLayout();
+ if (lm instanceof MigLayout) {
+ String constr = (String) ((MigLayout) lm).getComponentConstraints(c);
+ c.setToolTipText((constr != null ? ("\"" + constr + "\"") : "null"));
+ }
+ }
+ }
+
+ private static class ConstraintsDialog extends JDialog implements ActionListener, KeyEventDispatcher
+ {
+ private static final Color ERROR_COLOR = new Color(255, 180, 180);
+ private final JPanel mainPanel = new JPanel(new MigLayout("fillx,flowy,ins dialog",
+ "[fill]",
+ "2[]2"));
+ final JTextField layoutConstrTF;
+ final JTextField rowsConstrTF;
+ final JTextField colsConstrTF;
+ final JTextField componentConstrTF;
+
+ private final JButton okButt = new JButton("OK");
+ private final JButton cancelButt = new JButton("Cancel");
+
+ private boolean okPressed = false;
+
+ public ConstraintsDialog(Frame owner, String layoutConstr, String rowsConstr, String colsConstr, String compConstr)
+ {
+ super(owner, (compConstr != null ? "Edit Component Constraints" : "Edit Container Constraints"), true);
+
+ layoutConstrTF = createConstraintField(layoutConstr);
+ rowsConstrTF = createConstraintField(rowsConstr);
+ colsConstrTF = createConstraintField(colsConstr);
+ componentConstrTF = createConstraintField(compConstr);
+
+ if (componentConstrTF != null) {
+ mainPanel.add(new JLabel("Component Constraints"));
+ mainPanel.add(componentConstrTF);
+ }
+
+ if (layoutConstrTF != null) {
+ mainPanel.add(new JLabel("Layout Constraints"));
+ mainPanel.add(layoutConstrTF);
+ }
+
+ if (colsConstrTF != null) {
+ mainPanel.add(new JLabel("Column Constraints"), "gaptop unrel");
+ mainPanel.add(colsConstrTF);
+ }
+
+ if (rowsConstrTF != null) {
+ mainPanel.add(new JLabel("Row Constraints"), "gaptop unrel");
+ mainPanel.add(rowsConstrTF);
+ }
+
+ mainPanel.add(okButt, "tag ok,split,flowx,gaptop 15");
+ mainPanel.add(cancelButt, "tag cancel,gaptop 15");
+
+ setContentPane(mainPanel);
+
+ okButt.addActionListener(this);
+ cancelButt.addActionListener(this);
+ }
+
+ public void addNotify()
+ {
+ super.addNotify();
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
+ }
+
+ public void removeNotify()
+ {
+ KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
+ super.removeNotify();
+ }
+
+ public boolean dispatchKeyEvent(KeyEvent e)
+ {
+ if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
+ dispose();
+ return false;
+ }
+
+ public void actionPerformed(ActionEvent e)
+ {
+ if (e.getSource() == okButt)
+ okPressed = true;
+ dispose();
+ }
+
+ private JTextField createConstraintField(String text)
+ {
+ if (text == null)
+ return null;
+
+ final JTextField tf = new JTextField(text, 50);
+ tf.setFont(new Font("monospaced", Font.PLAIN, 12));
+
+ tf.addKeyListener(new KeyAdapter() {
+ public void keyPressed(KeyEvent e)
+ {
+ if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+ okButt.doClick();
+ return;
+ }
+
+ javax.swing.Timer timer = new Timer(50, new ActionListener() {
+ public void actionPerformed(ActionEvent e)
+ {
+ String constr = tf.getText();
+ try {
+ if (tf == layoutConstrTF) {
+ ConstraintParser.parseLayoutConstraint(constr);
+ } else if (tf == rowsConstrTF) {
+ ConstraintParser.parseRowConstraints(constr);
+ } else if (tf == colsConstrTF) {
+ ConstraintParser.parseColumnConstraints(constr);
+ } else if (tf == componentConstrTF) {
+ ConstraintParser.parseComponentConstraint(constr);
+ }
+
+ tf.setBackground(Color.WHITE);
+ okButt.setEnabled(true);
+ } catch(Exception ex) {
+ tf.setBackground(ERROR_COLOR);
+ okButt.setEnabled(false);
+ }
+ }
+ });
+ timer.setRepeats(false);
+ timer.start();
+ }
+ });
+
+ return tf;
+ }
+
+ private boolean showDialog()
+ {
+ setVisible(true);
+ return okPressed;
+ }
+ }
+
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/demo/SwtDemo.java b/prototypes/miglayout/net/miginfocom/demo/SwtDemo.java
new file mode 100644
index 00000000..43bcf538
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/demo/SwtDemo.java
@@ -0,0 +1,2100 @@
+package net.miginfocom.demo;
+
+import net.miginfocom.layout.*;
+import net.miginfocom.swt.MigLayout;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.widgets.*;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Random;
+
+/*
+ * 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
+ */
+public class SwtDemo
+{
+ public static final int SELECTED_INDEX = 0;
+
+ private static final String[][] panels = new String[][] {
+// {"Test", "Test, Disregard"},
+ {"Welcome", "\n\n \"MigLayout makes complex layouts easy and normal layouts one-liners.\""},
+ {"Quick Start", "This is an example of how to build a common dialog type. Note that there are no special components, nested panels or absolute references to cell positions. If you look at the source code you will see that the layout code is very simple to understand."},
+ {"Plain", "A simple example on how simple it is to create normal forms. No builders needed since the whole layout manager works like a builder."},
+ {"Alignments", "Shows how the alignment of components are specified. At the top/left is the alignment for the column/row. The components have no alignments specified.\n\nNote that baseline alignment will be interpreted as 'center' before JDK 6."},
+ {"Cell Alignments", "Shows how components are aligned when both column/row alignments and component constraints are specified. At the top/left are the alignment for the column/row and the text on the buttons is the component constraint that will override the column/row alignment if it is an alignment.\n\nNote that baseline alignment will be interpreted as 'center' before JDK 6."},
+ {"Basic Sizes", "A simple example that shows how to use the column or row min/preferred/max size to set the sizes of the contained components and also an example that shows how to do this directly in the component constraints."},
+ {"Growing", "A simple example that shows how to use the growx and growy constraint to set the sizes and how they should grow to fit the available size. Both the column/row and the component grow/shrink constraints can be set, but the components will always be confined to the space given by its column/row."},
+ {"Grow Shrink", "Demonstrates the very flexible grow and shrink constraints that can be set on a component.\nComponents can be divided into grow/shrink groups and also have grow/shrink weight within each of those groups.\n\nBy default " +
+ "components shrink to their inherent (or specified) minimum size, but they don't grow."},
+ {"Span", "This example shows the powerful spanning and splitting that can be specified in the component constraints. With spanning any number of cells can be merged with the additional option to split that space for more than one component. This makes layouts very flexible and reduces the number of times you will need nested panels to very few."},
+ {"Flow Direction", "Shows the different flow directions. Flow direction for the layout specifies if the next cell will be in the x or y dimension. Note that it can be a different flow direction in the slit cell (the middle cell is slit in two). Wrap is set to 3 for all panels."},
+ {"Grouping", "Sizes for both components and columns/rows can be grouped so they get the same size. For instance buttons in a button bar can be given a size-group so that they will all get " +
+ "the same minimum and preferred size (the largest within the group). Size-groups can be set for the width, height or both."},
+ {"Units", "Demonstrates the basic units that are understood by MigLayout. These units can be extended by the user by adding one or more UnitConverter(s)."},
+ {"Component Sizes", "Minimum, preferred and maximum component sizes can be overridden in the component constraints using any unit type. The format to do this is short and simple to understand. You simply specify the " +
+ "min, preferred and max sizes with a colon between.\n\nAbove are some examples of this. An exclamation mark means that the value will be used for all sizes."},
+ {"Bound Sizes", "Shows how to create columns that are stable between tabs using minimum sizes."},
+ {"Cell Position", "Even though MigLayout has automatic grid flow you can still specify the cell position explicitly. You can even combine absolute (x, y) and flow (skip, wrap and newline) constraints to build your layout."},
+ {"Orientation", "MigLayout supports not only right-to-left orientation, but also bottom-to-top. You can even set the flow direction so that the flow is vertical instead of horizontal. It will automatically " +
+ "pick up if right-to-left is to be used depending on the ComponentWrapper, but it can also be manually set for every layout."},
+ {"Absolute Position", "Demonstrates the option to place any number of components using absolute coordinates. This can be just the position (if min/preferred size) using \"x y p p\" format or" +
+ "the bounds using the \"x1 y1 x2 y2\" format. Any unit can be used and percent is relative to the parent.\nAbsolute components will not disturb the flow or occupy cells in the grid. " +
+ "Absolute positioned components will be taken into account when calculating the container's preferred size."},
+ {"Component Links", "Components can be linked to any side of any other component. It can be a forward, backward or cyclic link references, as long as it is stable and won't continue to change value over many iterations." +
+ "Links are referencing the ID of another component. The ID can be overridden by the component's constrains or is provided by the ComponentWrapper. For instance it will use the component's 'name' on Swing.\n" +
+ "Since the links can be combined with any expression (such as 'butt1.x+10' or 'max(button.x, 200)' the links are very customizable."},
+ {"Docking", "Docking components can be added around the grid. The docked component will get the whole width/height on the docked side by default, however this can be overridden. When all docked components are laid out, whatever space " +
+ "is left will be available for the normal grid laid out components. Docked components does not in any way affect the flow in the grid.\n\nSince the docking runs in the same code path " +
+ "as the normal layout code the same properties can be specified for the docking components. You can for instance set the sizes and alignment or link other components to their docked component's bounds."},
+ {"Button Bars", "Button order is very customizable and are by default different on the supported platforms. E.g. Gaps, button order and minimum button size are properties that are 'per platform'. MigLayout picks up the current platform automatically and adjusts the button order and minimum button size accordingly, all without using a button builder or any other special code construct."},
+ {"Debug", "Demonstrates the non-intrusive way to get visual debugging aid. There is no need to use a special DebugPanel or anything that will need code changes. The user can simply turn on debug on the layout manager by using the “debug” constraint and it will " +
+ "continuously repaint the panel with debug information on top. This means you don't have to change your code to debug!"},
+ {"Layout Showdown", "This is an implementation of the Layout Showdown posted on java.net by John O'Conner. The first tab is a pure implemenetation of the showdown that follows all the rules. The second tab is a slightly fixed version that follows some improved layout guidelines." +
+ "The source code is for bothe the first and for the fixed version. Note the simplification of the code for the fixed version. Writing better layouts with MiG Layout is reasier that writing bad.\n\nReference: http://weblogs.java.net/blog/joconner/archive/2006/10/more_informatio.html"},
+ {"API Constraints1", "This dialog shows the constraint API added to v2.0. It works the same way as the string constraints but with chained method calls. See the source code for details."},
+ {"API Constraints2", "This dialog shows the constraint API added to v2.0. It works the same way as the string constraints but with chained method calls. See the source code for details."},
+ };
+
+ private static int DOUBLE_BUFFER = 0;//SWT.DOUBLE_BUFFERED;
+
+ private static int benchRuns = 0;
+ private static long startupMillis = 0;
+ private static long timeToShowMillis = 0;
+ private static long benchRunTime = 0;
+ private static String benchOutFileName = null;
+ private static boolean append = false;
+
+ private static long lastRunTimeStart = 0;
+ private static StringBuffer runTimeSB = null;
+
+ private static Display display = null;
+
+ public static void main(String[] args)
+ {
+ startupMillis = System.currentTimeMillis();
+
+ if (args.length > 0) {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i].trim();
+ if (arg.startsWith("-bench")) {
+ benchRuns = 10;
+ try {
+ if (arg.length() > 6)
+ benchRuns = Integer.parseInt(arg.substring(6));
+ } catch (Exception ex) {}
+ } else if (arg.startsWith("-bout")) {
+ benchOutFileName = arg.substring(5);
+ } else if (arg.startsWith("-append")) {
+ append = true;
+ } else if (arg.startsWith("-verbose")) {
+ runTimeSB = new StringBuffer(256);
+ } else {
+ System.out.println("Usage: [-bench[#_of_runs]] [-bout[benchmark_results_filename]] [-append]\n" +
+ " -bench Run demo as benchmark. Run count can be appended. 10 is default.\n" +
+ " -bout Benchmark results output filename.\n" +
+ " -append Appends the result to the \"-bout\" file.\n" +
+ " -verbose Print the times of every run.\n" +
+ "\nExamples:\n" +
+ " java -jar swtdemoapp.jar -bench -boutC:/bench.txt -append\n" +
+ " java -jar swtdemoapp.jar -bench20\n" +
+ "NOTE! swt-win32-3232.dll must be in the current directory!");
+ System.exit(0);
+ }
+ }
+ }
+
+ if (benchRuns > 0)
+ LayoutUtil.setDesignTime(null, true);
+
+ new SwtDemo();
+ }
+
+ final List pickerList;
+ final Composite layoutDisplayPanel;
+ final StyledText descrTextArea;
+
+ public SwtDemo()
+ {
+ display = new Display();
+ final Shell shell = new Shell();
+
+ shell.setLayout(new MigLayout("wrap", "[]u[grow,fill]", "[grow,fill][pref!]"));
+ shell.setText("MigLayout SWT Demo v2.5 - Mig Layout v" + LayoutUtil.getVersion());
+
+ TabFolder layoutPickerTabPane = new TabFolder(shell, DOUBLE_BUFFER);
+ layoutPickerTabPane.setLayoutData("spany,grow");
+ pickerList = new List(layoutPickerTabPane, SWT.SINGLE | DOUBLE_BUFFER);
+ deriveFont(pickerList, SWT.BOLD, -1);
+ TabItem tab = new TabItem(layoutPickerTabPane, DOUBLE_BUFFER);
+ tab.setControl(pickerList);
+ tab.setText("Example Browser");
+ for (int i = 0; i < panels.length; i++)
+ pickerList.add(panels[i][0]);
+
+ layoutDisplayPanel = new Composite(shell, DOUBLE_BUFFER);
+ layoutDisplayPanel.setLayout(new MigLayout("fill, insets 0"));
+
+ TabFolder descriptionTabPane = new TabFolder(shell, DOUBLE_BUFFER);
+ descriptionTabPane.setLayoutData("growx,hmin 120,w 500:500");
+ descrTextArea = createTextArea(descriptionTabPane, "", "", SWT.MULTI | SWT.WRAP);
+ tab = new TabItem(descriptionTabPane, DOUBLE_BUFFER);
+ tab.setControl(descrTextArea);
+ tab.setText("Description");
+
+ pickerList.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ dispatchSelection();
+ }
+ });
+
+ shell.setSize(900, 650);
+ shell.open();
+
+ shell.layout();
+
+
+ if (benchRuns > 0) {
+ doBenchmark();
+ } else {
+ pickerList.select(SELECTED_INDEX);
+ dispatchSelection();
+
+ display.addFilter(SWT.KeyDown, new Listener() {
+
+ public void handleEvent(Event e)
+ {
+ if (e.character == 'b') {
+ startupMillis = System.currentTimeMillis();
+ timeToShowMillis = System.currentTimeMillis() - startupMillis;
+ benchRuns = 1;
+ doBenchmark();
+ }
+ }
+ });
+ }
+
+ while(!shell.isDisposed()){
+ if(!display.readAndDispatch())
+ display.sleep();
+ }
+
+ display.dispose();
+ }
+
+ private static Control[] comps = null; // thread hack...
+ private static Control[] tabs = null; // thread hack...
+
+ private void doBenchmark()
+ {
+ final int pCnt = pickerList.getItemCount();
+ Thread benchThread = new Thread() {
+ public void run()
+ {
+ for (int j = 0; j < benchRuns; j++) {
+ lastRunTimeStart = System.currentTimeMillis();
+ final int jj = j;
+ for (int i = 0; i < pCnt; i++) {
+ final int ii = i;
+ try {
+ display.syncExec(new Runnable() {
+ public void run () {
+ pickerList.setSelection(ii);
+ dispatchSelection();
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ display.syncExec(new Runnable() {
+ public void run() {
+ comps = layoutDisplayPanel.getChildren();
+ }
+ });
+
+ for (int cIx = 0; cIx < comps.length; cIx++) {
+
+ if (comps[cIx] instanceof TabFolder) {
+ final TabFolder tp = (TabFolder) comps[cIx];
+
+ display.syncExec(new Runnable() {
+ public void run() {
+ tabs = tp.getTabList();
+ }
+ });
+
+ for (int k = 0; k < tabs.length; k++) {
+ final int kk = k;
+ try {
+ display.syncExec(new Runnable() {
+ public void run() {
+ tp.setSelection(kk);
+
+ if (timeToShowMillis == 0)
+ timeToShowMillis = System.currentTimeMillis() - startupMillis;
+ }
+ });
+ } catch (Exception e) {
+ e.printStackTrace();
+ };
+ }
+ }
+ }
+ }
+ if (runTimeSB != null) {
+ runTimeSB.append("Run ").append(jj).append(": ");
+ runTimeSB.append(System.currentTimeMillis() - lastRunTimeStart).append(" millis.\n");
+ }
+ }
+
+ benchRunTime = System.currentTimeMillis() - startupMillis - timeToShowMillis;
+
+ final String message = "Java Version: " + System.getProperty("java.version") + "\n" +
+ "Time to Show: " + timeToShowMillis + " millis.\n" +
+ (runTimeSB != null ? runTimeSB.toString() : "") +
+ "Benchmark Run Time: " + benchRunTime + " millis.\n" +
+ "Average Run Time: " + (benchRunTime / benchRuns) + " millis (" + benchRuns + " runs).\n\n";
+
+ display.syncExec(new Runnable() {
+ public void run() {
+ if (benchOutFileName == null) {
+ MessageBox messageBox = new MessageBox(display.getActiveShell(), SWT.OK | SWT.ICON_INFORMATION);
+ messageBox.setText("Results");
+ messageBox.setMessage(message);
+ messageBox.open();
+ } else {
+ FileWriter fw = null;
+ try {
+ fw = new FileWriter(benchOutFileName, append);
+ fw.write(message);
+ } catch(IOException ex) {
+ ex.printStackTrace();
+ } finally {
+ if (fw != null)
+ try {fw.close();} catch(IOException ex) {}
+ }
+ }
+ }
+ });
+
+ System.out.println(message);
+
+ if (benchOutFileName != null)
+ System.exit(0);
+ }
+ };
+ benchThread.start();
+ }
+
+ private void dispatchSelection()
+ {
+ int ix = pickerList.getSelectionIndex();
+ if (ix == -1)
+ return;
+
+ String methodName = "create" + panels[ix][0].replace(' ', '_');
+ Control[] children = layoutDisplayPanel.getChildren();
+ for (int i = 0; i < children.length; i++)
+ children[i].dispose();
+
+ try {
+ Control child = (Control) SwtDemo.class.getMethod(methodName, new Class[] {Composite.class}).invoke(SwtDemo.this, new Object[] {layoutDisplayPanel});
+ child.setLayoutData("grow, wmin 500");
+ descrTextArea.setText(panels[ix][1]);
+ layoutDisplayPanel.layout();
+ } catch (Exception e1) {
+ e1.printStackTrace(); // Should never happpen...
+ }
+ }
+
+ public Control createTest(Composite parent2)
+ {
+// TabFolder tabFolder = new TabFolder(parent2, DOUBLE_BUFFER);
+
+ Composite parent = new Composite(parent2, SWT.NONE);
+
+ MigLayout layout = new MigLayout("wrap 2");
+ layout.setColumnConstraints("[grow, shrink][grow, shrink]");
+ parent.setLayout(layout);
+
+ Label label = new Label(parent, SWT.WRAP);
+ label.setText("This is a long label");
+ label.setLayoutData("width 20:pref:pref");
+
+ label = new Label(parent, SWT.NONE);
+ label.setText("Label 2");
+
+ label = new Label(parent, SWT.NONE);
+ label.setText("Label 3");
+
+ label = new Label(parent, SWT.NONE);
+ label.setText("Label 4");
+
+ return parent;
+ }
+
+ public Control createWelcome(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ TabItem mainItem = createTabPanel(tabbedPane, "Welcome", new FillLayout());
+ MigLayout lm = new MigLayout("ins 30, fill");
+ Composite panel = createPanel(tabbedPane, lm);
+ mainItem.setControl(panel);
+
+ String s = "MigLayout's main purpose is to make layouts for SWT and Swing, and possibly other frameworks, much more powerful and a lot easier to create, especially for manual coding.\n\n" +
+ "The motto is: \"MigLayout makes complex layouts easy and normal layouts one-liners.\"\n\n" +
+ "The layout engine is very flexible and advanced, something that is needed to make it simple to use yet handle almost all layout use-cases.\n\n" +
+ "MigLayout can handle all layouts that the commonly used Swing Layout Managers can handle and this with a lot of extra features. " +
+ "It also incorporates most, if not all, of the open source alternatives FormLayout's and TableLayout's functionality." +
+ "\n\n\nThanks to Karsten Lentzsch of JGoodies.com for allowing the reuse of the main demo application layout and for his inspiring talks that led to this layout Manager." +
+ "\n\n\nMikael Grev\n" +
+ "MiG InfoCom AB\n" +
+ "miglayout@miginfocom.com";
+
+ StyledText textArea = new StyledText(panel, SWT.MULTI | SWT.WRAP | SWT.BORDER);
+ textArea.setText(s);
+ textArea.setSize(400, 400);
+ textArea.setLayoutData("w 500:500,ay top,grow");
+ deriveFont(textArea, SWT.BOLD, -1);
+
+ return tabbedPane;
+ }
+
+ public Composite createAPI_Constraints1(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ LC layC = new LC().fill().wrap();
+ AC colC = new AC().align("right", 0).fill(1, 3).grow(100, 1, 3).align("right", 2).gap("15", 1);
+ AC rowC = new AC().align("top", 7).gap("15!", 6).grow(100, 8);
+
+ TabItem p1 = createTabPanel(tabbedPane, "Layout Showdown (improved)", new MigLayout(layC, colC, rowC));
+
+ // References to text fields not stored to reduce code clutter.
+
+ createList(p1, "Mouse, Mickey", new CC().dockWest().minWidth("150").gapX(null, "10"));
+ createLabel(p1, "Last Name", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "First Name", "");
+ createTextField(p1, "", new CC().wrap());
+ createLabel(p1, "Phone", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Email", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Address 1", "");
+ createTextField(p1, "", new CC().spanX().growX());
+ createLabel(p1, "Address 2", "");
+ createTextField(p1, "", new CC().spanX().growX());
+ createLabel(p1, "City", "");
+ createTextField(p1, "", new CC().wrap());
+ createLabel(p1, "State", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Postal Code", "");
+ createTextField(p1, "", new CC().spanX(2).growX(0));
+ createLabel(p1, "Country", "");
+ createTextField(p1, "", new CC().wrap());
+
+ createButton(p1, "New", new CC().spanX(5).split(5).tag("other"));
+ createButton(p1, "Delete", new CC().tag("other"));
+ createButton(p1, "Edit", new CC().tag("other"));
+ createButton(p1, "Save", new CC().tag("other"));
+ createButton(p1, "Cancel", new CC().tag("cancel"));
+
+ return tabbedPane;
+ }
+
+ public Composite createAPI_Constraints2(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ LC layC = new LC().fill().wrap();
+ AC colC = new AC().align("right", 0).fill(1, 3).grow(100, 1, 3).align("right", 2).gap("15", 1);
+ AC rowC = new AC().index(6).gap("15!").align("top").grow(100, 8);
+
+ TabItem p1 = createTabPanel(tabbedPane, "Layout Showdown (improved)", new MigLayout(layC, colC, rowC));
+
+ // References to text fields not stored to reduce code clutter.
+
+ createLabel(p1, "Last Name", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "First Name", "");
+ createTextField(p1, "", new CC().wrap());
+ createLabel(p1, "Phone", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Email", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Address 1", "");
+ createTextField(p1, "", new CC().spanX().growX());
+ createLabel(p1, "Address 2", "");
+ createTextField(p1, "", new CC().spanX().growX());
+ createLabel(p1, "City", "");
+ createTextField(p1, "", new CC().wrap());
+ createLabel(p1, "State", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Postal Code", "");
+ createTextField(p1, "", new CC().spanX(2).growX(0));
+ createLabel(p1, "Country", "");
+ createTextField(p1, "", new CC().wrap());
+
+ createButton(p1, "New", new CC().spanX(5).split(5).tag("other"));
+ createButton(p1, "Delete", new CC().tag("other"));
+ createButton(p1, "Edit", new CC().tag("other"));
+ createButton(p1, "Save", new CC().tag("other"));
+ createButton(p1, "Cancel", new CC().tag("cancel"));
+
+ return tabbedPane;
+ }
+
+ public Composite createLayout_Showdown(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ TabItem p1 = createTabPanel(tabbedPane, "Layout Showdown (pure)", new MigLayout("", "[]15[][grow,fill]15[grow]"));
+
+ // References to text fields not stored to reduce code clutter.
+
+ createList(p1, "Mouse, Mickey", "spany, growy, wmin 150");
+ createLabel(p1, "Last Name", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "First Name", "split"); // split divides the cell
+ createTextField(p1, "", "growx, wrap");
+ createLabel(p1, "Phone", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Email", "split");
+ createTextField(p1, "", "growx, wrap");
+ createLabel(p1, "Address 1", "");
+ createTextField(p1, "", "span, growx"); // span merges cells
+ createLabel(p1, "Address 2", "");
+ createTextField(p1, "", "span, growx");
+ createLabel(p1, "City", "");
+ createTextField(p1, "", "wrap"); // wrap continues on next line
+ createLabel(p1, "State", "");
+ createTextField(p1, "", "");
+ createLabel(p1, "Postal Code", "split");
+ createTextField(p1, "", "growx, wrap");
+ createLabel(p1, "Country", "");
+ createTextField(p1, "", "wrap 15");
+
+ createButton(p1, "New", "span, split, align right");
+ createButton(p1, "Delete", "");
+ createButton(p1, "Edit", "");
+ createButton(p1, "Save", "");
+ createButton(p1, "Cancel", "wrap push");
+
+
+ // Fixed version *******************************************
+
+
+ TabItem p2 = createTabPanel(tabbedPane, "Layout Showdown (improved)", new MigLayout("", "[]15[][grow,fill]15[][grow,fill]"));
+
+ // References to text fields not stored to reduce code clutter.
+
+ createList(p2, "Mouse, Mickey", "spany, growy, wmin 150");
+ createLabel(p2, "Last Name", "");
+ createTextField(p2, "", "");
+ createLabel(p2, "First Name", "");
+ createTextField(p2, "", "wrap");
+ createLabel(p2, "Phone", "");
+ createTextField(p2, "", "");
+ createLabel(p2, "Email", "");
+ createTextField(p2, "", "wrap");
+ createLabel(p2, "Address 1", "");
+ createTextField(p2, "", "span");
+ createLabel(p2, "Address 2", "");
+ createTextField(p2, "", "span");
+ createLabel(p2, "City", "");
+ createTextField(p2, "", "wrap");
+ createLabel(p2, "State", "");
+ createTextField(p2, "", "");
+ createLabel(p2, "Postal Code", "");
+ createTextField(p2, "", "width 50, grow 0, wrap");
+ createLabel(p2, "Country", "");
+ createTextField(p2, "", "wrap 15");
+
+ createButton(p2, "New", "tag other, span, split");
+ createButton(p2, "Delete", "tag other");
+ createButton(p2, "Edit", "tag other");
+ createButton(p2, "Save", "tag other");
+ createButton(p2, "Cancel", "tag cancel, wrap push");
+
+ return tabbedPane;
+ }
+
+ public Composite createDocking(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+ tabbedPane.setLayoutData("grow");
+
+ TabItem p1 = createTabPanel(tabbedPane, "Docking 1", new MigLayout("fill"));
+
+ createPanel(p1, "1. North", "north");
+ createPanel(p1, "2. West", "west");
+ createPanel(p1, "3. East", "east");
+ createPanel(p1, "4. South", "south");
+
+ Table table = new Table(getComposite(p1), DOUBLE_BUFFER);
+ for (int i = 0; i < 6; i++) {
+ TableColumn tc = new TableColumn(table, SWT.LEFT | SWT.V_SCROLL | SWT.SCROLL_LINE);
+ tc.setText("Column " + (i + 1));
+ tc.setWidth(100);
+ }
+
+ for (int r = 0; r < 20; r++) {
+ TableItem item1 = new TableItem(table,0);
+ String[] data = new String[6];
+ for (int c = 0; c < data.length; c++)
+ data[c] = "Cell " + (r + 1) + ", " + (c + 1);
+ item1.setText(data);
+ }
+ table.setHeaderVisible(true);
+ table.setLinesVisible(true);
+ table.setLayoutData("grow");
+
+
+ TabItem p2 = createTabPanel(tabbedPane, "Docking 2 (fill)", new MigLayout("fill", "[c]", ""));
+
+ createPanel(p2, "1. North", "north");
+ createPanel(p2, "2. North", "north");
+ createPanel(p2, "3. West", "west");
+ createPanel(p2, "4. West", "west");
+ createPanel(p2, "5. South", "south");
+ createPanel(p2, "6. East", "east");
+ createButton(p2, "7. Normal", "");
+ createButton(p2, "8. Normal", "");
+ createButton(p2, "9. Normal", "");
+
+ TabItem p3 = createTabPanel(tabbedPane, "Docking 3", new MigLayout());
+
+ createPanel(p3, "1. North", "north");
+ createPanel(p3, "2. South", "south");
+ createPanel(p3, "3. West", "west");
+ createPanel(p3, "4. East", "east");
+ createButton(p3, "5. Normal", "");
+
+ TabItem p4 = createTabPanel(tabbedPane, "Docking 4", new MigLayout());
+
+ createPanel(p4, "1. North", "north");
+ createPanel(p4, "2. North", "north");
+ createPanel(p4, "3. West", "west");
+ createPanel(p4, "4. West", "west");
+ createPanel(p4, "5. South", "south");
+ createPanel(p4, "6. East", "east");
+ createButton(p4, "7. Normal", "");
+ createButton(p4, "8. Normal", "");
+ createButton(p4, "9. Normal", "");
+
+ TabItem p5 = createTabPanel(tabbedPane, "Docking 5 (fillx)", new MigLayout("fillx", "[c]", ""));
+
+ createPanel(p5, "1. North", "north");
+ createPanel(p5, "2. North", "north");
+ createPanel(p5, "3. West", "west");
+ createPanel(p5, "4. West", "west");
+ createPanel(p5, "5. South", "south");
+ createPanel(p5, "6. East", "east");
+ createButton(p5, "7. Normal", "");
+ createButton(p5, "8. Normal", "");
+ createButton(p5, "9. Normal", "");
+
+ TabItem p6 = createTabPanel(tabbedPane, "Random Docking", new MigLayout("fill"));
+
+ String[] sides = {"north", "east", "south", "west"};
+ Random rand = new Random();
+ for (int i = 0; i < 20; i++) {
+ int side = rand.nextInt(4);
+ createPanel(p6, ((i + 1) + " " + sides[side]), sides[side]);
+ }
+ createPanel(p6, "I'm in the Center!", "grow");
+
+ return tabbedPane;
+ }
+
+ public Control createAbsolute_Position(final Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Pos tab
+ TabItem posTabPanel = createTabPanel(tabbedPane, "X Y Positions", new FillLayout());
+ final Composite posPanel = createPanel(posTabPanel, new MigLayout());
+
+ createButton(posPanel, "pos 0.5al 0al", null);
+ createButton(posPanel, "pos 1al 0al", null);
+ createButton(posPanel, "pos 0.5al 0.5al", null);
+ createButton(posPanel, "pos 5in 45lp", null);
+ createButton(posPanel, "pos 0.5al 0.5al", null);
+ createButton(posPanel, "pos 0.5al 1al", null);
+ createButton(posPanel, "pos 1al .25al", null);
+ createButton(posPanel, "pos visual.x2-pref visual.y2-pref", null);
+ createButton(posPanel, "pos 1al -1in", null);
+ createButton(posPanel, "pos 100 100", null);
+ createButton(posPanel, "pos (10+(20*3lp)) 200", null);
+ createButton(posPanel, "Drag Window! (pos 500-container.xpos 500-container.ypos)",
+ "pos 500-container.xpos 500-container.ypos");
+
+ // Bounds tab
+ TabItem boundsTabPanel = createTabPanel(tabbedPane, "X1 Y1 X2 Y2 Bounds", new FillLayout());
+ Composite boundsPanel = createPanel(boundsTabPanel, new MigLayout());
+
+ Label southLabel = createLabel(boundsPanel, "pos (visual.x+visual.w*0.1) visual.y2-40 (visual.x2-visual.w*0.1) visual.y2", null, SWT.CENTER | SWT.BORDER);
+ southLabel.setBackground(new Color(display, 200, 200, 255));
+ deriveFont(southLabel, SWT.BOLD, 10);
+
+ createButton(boundsPanel, "pos 0 0 container.x2 n", null);
+ createButton(boundsPanel, "pos visual.x 40 visual.x2 70", null);
+ createButton(boundsPanel, "pos visual.x 100 visual.x2 p", null);
+ createButton(boundsPanel, "pos 0.1al 0.4al n visual.y2-10", null);
+ createButton(boundsPanel, "pos 0.9al 0.4al n visual.y2-10", null);
+ createButton(boundsPanel, "pos 0.5al 0.5al, pad 3 0 -3 0", null);
+ createButton(boundsPanel, "pos n n 50% 50%", null);
+ createButton(boundsPanel, "pos 50% 50% n n", null);
+ createButton(boundsPanel, "pos 50% n n 50%", null);
+ createButton(boundsPanel, "pos n 50% 50% n", null);
+
+ // Glass pane tab
+// final TabItem glassPanel = createTabPanel(tabbedPane, "GlassPane Substitute", parent, new SwtMigLayout("align c c"));
+// final Button butt = new Button("Press me!!");
+// glassPanel.add(butt);
+//
+// butt.addActionListener(new ActionListener() {
+// public void actionPerformed(ActionEvent e)
+// {
+// butt.setEnabled(false);
+// final JPanel bg = new JPanel(parent, new SwtMigLayout("align c c,fill")) {
+// public void paint(Graphics g)
+// {
+// g.setColor(getBackground());
+// g.fillRect(0, 0, getWidth(), getHeight());
+// super.paint(g);
+// }
+// };
+// bg.setOpaque(false);
+// configureActiveComponet(bg);
+//
+// final Label label = createLabel("You don't need a GlassPane to be cool!");
+// label.setFont(label.getFont().deriveFont(30f));
+// label.setForeground(new Color(255, 255, 255, 0));
+// bg.add(label, "align 50% 30%");
+//
+// glassPanel.add(bg, "pos 0 0 visual.x2 visual.y2", 0);
+// final long startTime = System.nanoTime();
+// final long endTime = startTime + 500000000L;
+//
+// glassPanel.revalidate();
+//
+// final javax.swing.Timer timer = new Timer(25, null);
+//
+// timer.addActionListener(new ActionListener() {
+// public void actionPerformed(ActionEvent e)
+// {
+// long now = System.nanoTime();
+// int alpha = (int) (((now - startTime) / (double) (endTime - startTime)) * 300);
+// if (alpha < 150)
+// bg.setBackground(new Color(100, 100, 100, alpha));
+//
+// if (alpha > 150 && alpha < 405) {
+// label.setForeground(new Color(255, 255, 255, (alpha - 150)));
+// bg.repaint();
+// }
+// if (alpha > 405)
+// timer.stop();
+// }
+// });
+// timer.start();
+// }
+// });
+//
+
+ parent.getShell().addControlListener(new ControlAdapter() {
+ public void controlMoved(ControlEvent e)
+ {
+ if (!posPanel.isDisposed()) {
+ posPanel.layout();
+ } else {
+ parent.getShell().removeControlListener(this);
+ }
+ }
+ });
+
+ return tabbedPane;
+ }
+
+ public Control createComponent_Links(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ TabItem linksPanel = createTabPanel(tabbedPane, "Component Links", new MigLayout());
+
+ // Links tab
+ createButton(linksPanel, "Mini", "pos null ta.y ta.x2 null, pad 3 0 -3 0");
+ createTextArea(linksPanel, "Components, Please Link to Me!\nMy ID is: 'ta'", "id ta, pos 0.5al 0.5al, w 300");
+ createButton(linksPanel, "id b1,pos ta.x2 ta.y2", null);
+ createButton(linksPanel, "pos b1.x2+rel b1.y visual.x2 null", null);
+ createCheck(linksPanel, "pos (ta.x+indent) (ta.y2+rel)", null);
+ createButton(linksPanel, "pos ta.x2+rel ta.y visual.x2 null", null);
+ createButton(linksPanel, "pos null ta.y+(ta.h-pref)/2 ta.x-rel null", null);
+ createButton(linksPanel, "pos ta.x ta.y2+100 ta.x2 null", null);
+
+ // External tab
+ TabItem externalPanel = createTabPanel(tabbedPane, "External Components", new MigLayout());
+
+ Button extButt = createButton(externalPanel, "Bounds Externally Set!", "id ext, external");
+ extButt.setBounds(250, 130, 200, 40);
+ createButton(externalPanel, "pos ext.x2 ext.y2", "pos ext.x2 ext.y2");
+ createButton(externalPanel, "pos null null ext.x ext.y", "pos null null ext.x ext.y");
+
+ TabItem egTabPanel = createTabPanel(tabbedPane, "End Grouping", new FillLayout());
+ final Composite egPanel = createPanel(egTabPanel, new MigLayout());
+
+ createButton(egPanel, "id b1, endgroupx g1, pos 200 200", null);
+ createButton(egPanel, "id b2, endgroupx g1, pos (b1.x+2ind) (b1.y2+rel)", null);
+ createButton(egPanel, "id b3, endgroupx g1, pos (b1.x+4ind) (b2.y2+rel)", null);
+ createButton(egPanel, "id b4, endgroupx g1, pos (b1.x+6ind) (b3.y2+rel)", null);
+
+ // Group Bounds tab
+ TabItem gpTabPanel = createTabPanel(tabbedPane, "Group Bounds", new FillLayout());
+ final Composite gpPanel = createPanel(gpTabPanel, new MigLayout());
+
+ createButton(gpPanel, "id grp1.b1, pos n 0.5al 50% n", null);
+ createButton(gpPanel, "id grp1.b2, pos 50% 0.5al n n", null);
+ createButton(gpPanel, "id grp1.b3, pos 0.5al n n b1.y", null);
+ createButton(gpPanel, "id grp1.b4, pos 0.5al b1.y2 n n", null);
+
+ createButton(gpPanel, "pos n grp1.y2 grp1.x n", null);
+ createButton(gpPanel, "pos n n grp1.x grp1.y", null);
+ createButton(gpPanel, "pos grp1.x2 n n grp1.y", null);
+ createButton(gpPanel, "pos grp1.x2 grp1.y2", null);
+
+ Composite boundsPanel = createPanel(gpPanel, (Layout) null);
+ boundsPanel.setLayoutData("pos grp1.x grp1.y grp1.x2 grp1.y2");
+ boundsPanel.setBackground(new Color(display, 200, 200, 255));
+
+ return tabbedPane;
+ }
+
+ public Control createFlow_Direction(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ createFlowPanel(tabbedPane, "Layout: flowx, Cell: flowx", "", "flowx");
+ createFlowPanel(tabbedPane, "Layout: flowx, Cell: flowy", "", "flowy");
+ createFlowPanel(tabbedPane, "Layout: flowy, Cell: flowx", "flowy", "flowx");
+ createFlowPanel(tabbedPane, "Layout: flowy, Cell: flowy", "flowy", "flowy");
+
+ return tabbedPane;
+ }
+
+ private TabItem createFlowPanel(TabFolder parent, String text, String gridFlow, String cellFlow)
+ {
+ MigLayout lm = new MigLayout("center, wrap 3," + gridFlow,
+ "[110,fill]",
+ "[110,fill]");
+ TabItem panel = createTabPanel(parent, text, lm);
+
+ for (int i = 0; i < 9; i++) {
+ Composite b = createPanel(panel, "" + (i + 1), cellFlow);
+ Font f = deriveFont(b, SWT.DEFAULT, 20);
+ b.getChildren()[0].setFont(f);
+ }
+
+ Composite b = createPanel(panel, "5:2", cellFlow + ",cell 1 1");
+ Font f = deriveFont(b, SWT.DEFAULT, 20);
+ b.getChildren()[0].setFont(f);
+
+ return panel;
+ }
+
+ public Control createDebug(Composite parent)
+ {
+ return createPlainImpl(parent, true);
+ }
+
+ public Control createButton_Bars(final Composite parent)
+ {
+ MigLayout lm = new MigLayout("ins 0 0 15lp 0",
+ "[grow]",
+ "[grow]u[baseline,nogrid]");
+
+ final Composite mainPanel = new Composite(parent, DOUBLE_BUFFER);
+ mainPanel.setLayout(lm);
+
+ TabFolder tabbedPane = new TabFolder(mainPanel, DOUBLE_BUFFER);
+ tabbedPane.setLayoutData("grow, wrap");
+
+ createButtonBarsPanel(tabbedPane, "Buttons", "help", false);
+ createButtonBarsPanel(tabbedPane, "Buttons with Help2", "help2", false);
+ createButtonBarsPanel(tabbedPane, "Buttons (Same width)", "help", true);
+
+ createLabel(mainPanel, "Button Order:", "");
+ final Label formatLabel = createLabel(mainPanel, "", "growx");
+ deriveFont(formatLabel, SWT.BOLD , -1);
+
+ final Button winButt = createToggleButton(mainPanel, "Windows", "wmin button");
+ final Button macButt = createToggleButton(mainPanel, "Mac OS X", "wmin button");
+
+ winButt.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (winButt.getSelection()) {
+ PlatformDefaults.setPlatform(PlatformDefaults.WINDOWS_XP);
+ formatLabel.setText("'" + PlatformDefaults.getButtonOrder() + "'");
+ macButt.setSelection(false);
+ mainPanel.layout();
+ }
+ }
+ });
+
+ macButt.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e)
+ {
+ if (macButt.getSelection()) {
+ PlatformDefaults.setPlatform(PlatformDefaults.MAC_OSX);
+ formatLabel.setText("'" + PlatformDefaults.getButtonOrder() + "'");
+ winButt.setSelection(false);
+ mainPanel.layout();
+ }
+ }
+ });
+
+ Button helpButt = createButton(mainPanel, "Help", "gap unrel,wmin button");
+ helpButt.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e)
+ {
+ MessageBox msgBox = new MessageBox(parent.getShell());
+ msgBox.setMessage("See JavaDoc for PlatformConverter.getButtonBarOrder(..) for details on the format string.");
+ msgBox.open();
+ }
+ });
+
+ (PlatformDefaults.getPlatform() == PlatformDefaults.WINDOWS_XP ? winButt : macButt).setSelection(true);
+
+ return mainPanel;
+ }
+
+ private TabItem createButtonBarsPanel(TabFolder parent, String text, String helpTag, boolean sizeLocked)
+ {
+ MigLayout lm = new MigLayout("nogrid, fillx, aligny 100%, gapy unrel");
+ TabItem panel = createTabPanel(parent, text, lm);
+
+ // Notice that the order in the rows below does not matter...
+ String[][] buttons = new String[][] {
+ {"No", "Yes"},
+ {"Help", "Close"},
+ {"OK", "Help"},
+ {"OK", "Cancel", "Help"},
+ {"OK", "Cancel", "Apply", "Help"},
+ {"No", "Yes", "Cancel"},
+ {"Help", "< Move Back", "Move Forward >", "Cancel"},
+ {"Print...", "Cancel", "Help"},
+ };
+
+ for (int r = 0; r < buttons.length; r++) {
+ for (int i = 0; i < buttons[r].length; i++) {
+ String txt = buttons[r][i];
+ String tag = txt;
+
+ if (txt.equals("Help")) {
+ tag = helpTag;
+ } else if (txt.equals("< Move Back")) {
+ tag = "back";
+ } else if (txt.equals("Close")) {
+ tag = "cancel";
+ } else if (txt.equals("Move Forward >")) {
+ tag = "next";
+ } else if (txt.equals("Print...")) {
+ tag = "other";
+ }
+ String wrap = (i == buttons[r].length - 1) ? ",wrap" : "";
+ String sizeGroup = sizeLocked ? ("sgx " + r + ",") : "";
+ createButton(panel, txt, sizeGroup + "tag " + tag + wrap);
+ }
+ }
+
+ return panel;
+ }
+
+ public Control createOrientation(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ MigLayout lm = new MigLayout("flowy", "[grow,fill]", "[]0[]15lp[]0[]");
+ TabItem mainPanel = createTabPanel(tabbedPane, "Orientation", lm);
+
+ // Default orientation
+ MigLayout defLM = new MigLayout("", "[][grow,fill]", "");
+
+ Composite defPanel = createPanel(mainPanel, defLM);
+ addSeparator(defPanel, "Default Orientation");
+ createLabel(defPanel, "Level", "");
+ createTextField(defPanel, "", "span,growx");
+ createLabel(defPanel, "Radar", "");
+ createTextField(defPanel, "", "");
+ createTextField(defPanel, "", "");
+
+ // Right-to-left, Top-to-bottom
+ MigLayout rtlLM = new MigLayout("rtl,ttb",
+ "[][grow,fill]",
+ "");
+ Composite rtlPanel = createPanel(mainPanel, rtlLM);
+ addSeparator(rtlPanel, "Right to Left");
+ createLabel(rtlPanel, "Level", "");
+ createTextField(rtlPanel, "", "span,growx");
+ createLabel(rtlPanel, "Radar", "");
+ createTextField(rtlPanel, "", "");
+ createTextField(rtlPanel, "", "");
+
+ // Right-to-left, Bottom-to-top
+ MigLayout rtlbLM = new MigLayout("rtl,btt",
+ "[][grow,fill]",
+ "");
+ Composite rtlbPanel = createPanel(mainPanel, rtlbLM);
+ addSeparator(rtlbPanel, "Right to Left, Bottom to Top");
+ createLabel(rtlbPanel, "Level", "");
+ createTextField(rtlbPanel, "", "span,growx");
+ createLabel(rtlbPanel, "Radar", "");
+ createTextField(rtlbPanel, "", "");
+ createTextField(rtlbPanel, "", "");
+
+ // Left-to-right, Bottom-to-top
+ MigLayout ltrbLM = new MigLayout("ltr,btt",
+ "[][grow,fill]",
+ "");
+
+ Composite ltrbPanel = createPanel(mainPanel, ltrbLM);
+ addSeparator(ltrbPanel, "Left to Right, Bottom to Top");
+ createLabel(ltrbPanel, "Level", "");
+ createTextField(ltrbPanel, "", "span,growx");
+ createLabel(ltrbPanel, "Radar", "");
+ createTextField(ltrbPanel, "", "");
+ createTextField(ltrbPanel, "", "");
+
+ return tabbedPane;
+ }
+
+ public Control createCell_Position(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Absolute grid position
+ MigLayout absLM = new MigLayout("",
+ "[100:pref,fill]",
+ "[100:pref,fill]");
+
+ TabItem absPanel = createTabPanel(tabbedPane, "Absolute", absLM);
+ createPanel(absPanel, "cell 0 0", null);
+ createPanel(absPanel, "cell 2 0", null);
+ createPanel(absPanel, "cell 3 0", null);
+ createPanel(absPanel, "cell 1 1", null);
+ createPanel(absPanel, "cell 0 2", null);
+ createPanel(absPanel, "cell 2 2", null);
+ createPanel(absPanel, "cell 2 2", null);
+
+
+ // Relative grid position with wrap
+ MigLayout relAwLM = new MigLayout("wrap",
+ "[100:pref,fill][100:pref,fill][100:pref,fill][100:pref,fill]",
+ "[100:pref,fill]");
+ TabItem relAwPanel = createTabPanel(tabbedPane, "Relative + Wrap", relAwLM);
+ createPanel(relAwPanel, "", null);
+ createPanel(relAwPanel, "skip", null);
+ createPanel(relAwPanel, "", null);
+ createPanel(relAwPanel, "skip,wrap", null);
+ createPanel(relAwPanel, "", null);
+ createPanel(relAwPanel, "skip,split", null);
+ createPanel(relAwPanel, "", null);
+
+
+ // Relative grid position with manual wrap
+ MigLayout relWLM = new MigLayout("",
+ "[100:pref,fill]",
+ "[100:pref,fill]");
+ TabItem relWPanel = createTabPanel(tabbedPane, "Relative", relWLM);
+ createPanel(relWPanel, "", null);
+ createPanel(relWPanel, "skip", null);
+ createPanel(relWPanel, "wrap", null);
+ createPanel(relWPanel, "skip,wrap", null);
+ createPanel(relWPanel, "", null);
+ createPanel(relWPanel, "skip,split", null);
+ createPanel(relWPanel, "", null);
+
+
+ // Mixed relative and absolute grid position
+ MigLayout mixLM = new MigLayout("",
+ "[100:pref,fill]",
+ "[100:pref,fill]");
+ TabItem mixPanel = createTabPanel(tabbedPane, "Mixed", mixLM);
+ createPanel(mixPanel, "", null);
+ createPanel(mixPanel, "cell 2 0", null);
+ createPanel(mixPanel, "", null);
+ createPanel(mixPanel, "cell 1 1,wrap", null);
+ createPanel(mixPanel, "", null);
+ createPanel(mixPanel, "cell 2 2,split", null);
+ createPanel(mixPanel, "", null);
+
+ return tabbedPane;
+ }
+
+ public Control createPlain(Composite parent)
+ {
+ return createPlainImpl(parent, false);
+ }
+
+ private Control createPlainImpl(Composite parent, boolean debug)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ MigLayout lm = new MigLayout((debug && benchRuns == 0 ? "debug" : ""), "[r][100lp, fill][60lp][95lp, fill]", "");
+ TabItem panel = createTabPanel(tabbedPane, "Plain", lm);
+
+ addSeparator(panel, "Manufacturer");
+ createLabel(panel, "Company", "");
+ createTextField(panel, "", "span,growx");
+ createLabel(panel, "Contact", "");
+ createTextField(panel, "", "span,growx");
+ createLabel(panel, "Order No", "");
+ createTextField(panel, "", "wmin 15*6,wrap");
+
+ addSeparator(panel, "Inspector");
+ createLabel(panel, "Name", "");
+ createTextField(panel, "", "span,growx");
+ createLabel(panel, "Reference No", "");
+ createTextField(panel, "", "wrap");
+ createLabel(panel, "Status", "");
+ createCombo(panel, new String[] {"In Progress", "Finnished", "Released"}, "wrap");
+
+ addSeparator(panel, "Ship");
+ createLabel(panel, "Shipyard", "");
+ createTextField(panel, "", "span,growx");
+ createLabel(panel, "Register No", "");
+ createTextField(panel, "", "");
+ createLabel(panel, "Hull No", "right");
+ createTextField(panel, "", "wmin 15*6,wrap");
+ createLabel(panel, "Project Type", "");
+ createCombo(panel, new String[] {"New Building", "Convention", "Repair"}, "wrap");
+
+ if (debug)
+ createLabel(panel, "Blue is component bounds. Cell bounds (red) can not be shown in SWT", "newline,ax left,span,gaptop 40");
+
+ return tabbedPane;
+ }
+
+ public Control createBound_Sizes(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ for (int i = 0; i < 2; i++) { // Jumping for 0 and Stable for 1
+ String colConstr = i == 0 ? "[right][200]" : "[right, 75lp:pref][200]";
+
+ MigLayout LM1 = new MigLayout("wrap", colConstr, "");
+ TabItem panel1 = createTabPanel(tabbedPane, i == 0 ? "Jumping 1" : "Stable 2", LM1);
+ createLabel(panel1, "File Number:", "");
+ createTextField(panel1, "", "growx");
+ createLabel(panel1, "RFQ Number:", "");
+ createTextField(panel1, "", "growx");
+ createLabel(panel1, "Entry Date:", "");
+ createTextField(panel1, "", "wmin 6*6");
+ createLabel(panel1, "Sales Person:", "");
+ createTextField(panel1, "", "growx");
+
+ MigLayout LM2 = new MigLayout("wrap", colConstr, "");
+ TabItem panel2 = createTabPanel(tabbedPane, i == 0 ? "Jumping 2" : "Stable 2", LM2);
+ createLabel(panel2, "Shipper:", "");
+ createTextField(panel2, "", "wmin 6*6,split 2");
+ createTextField(panel2, "", "growx");
+ createLabel(panel2, "Consignee:", "");
+ createTextField(panel2, "", "wmin 6*6,split 2");
+ createTextField(panel2, "", "growx");
+ createLabel(panel2, "Departure:", "");
+ createTextField(panel2, "", "wmin 6*6,split 2");
+ createTextField(panel2, "", "growx");
+ createLabel(panel2, "Destination:", "");
+ createTextField(panel2, "", "wmin 6*6,split 2");
+ createTextField(panel2, "", "growx");
+ }
+ return tabbedPane;
+ }
+
+ public Control createComponent_Sizes(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ MigLayout lm = new MigLayout("wrap", "[right][0:pref,grow]", "");
+
+ TabItem tabPanel = createTabPanel(tabbedPane, "Component Sizes", new FillLayout());
+
+ SashForm sashForm = new SashForm(getComposite(tabPanel), SWT.HORIZONTAL | SWT.SMOOTH);
+ sashForm.setBackground(new Color(display, 50, 50, 50));
+
+ Composite panel = createPanel(sashForm, lm);
+ createTextArea(sashForm, "Use slider to see how the components grow and shrink depending on the constraints set on them.", "");
+
+ createLabel(panel, "", "");
+ createTextField(panel, "8 ", "");
+ createLabel(panel, "width min!", null);
+ createTextField(panel, "3 ", "width min!");
+ createLabel(panel, "width pref!", "");
+ createTextField(panel, "3 ", "width pref!");
+ createLabel(panel, "width min:pref", null);
+ createTextField(panel, "8 ", "width min:pref");
+ createLabel(panel, "width min:100:150", null);
+ createTextField(panel, "8 ", "width min:100:150");
+ createLabel(panel, "width min:100:150, growx", null);
+ createTextField(panel, "8 ", "width min:100:150, growx");
+ createLabel(panel, "width min:100, growx", null);
+ createTextField(panel, "8 ", "width min:100, growx");
+ createLabel(panel, "width 40!", null);
+ createTextField(panel, "8 ", "width 40!");
+ createLabel(panel, "width 40:40:40", null);
+ createTextField(panel, "8 ", "width 40:40:40");
+
+ return tabbedPane;
+ }
+
+ public Control createCell_Alignments(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Horizontal
+ MigLayout hLM = new MigLayout("wrap",
+ "[grow,left][grow,center][grow,right][grow,fill,center]",
+ "[]unrel[][]");
+ TabItem hPanel = createTabPanel(tabbedPane, "Horizontal", hLM);
+ String[] sizes = new String[] {"", "growx", "growx 0", "left", "center", "right", "leading", "trailing"};
+ createLabel(hPanel, "[left]", "c");
+ createLabel(hPanel, "[center]", "c");
+ createLabel(hPanel, "[right]", "c");
+ createLabel(hPanel, "[fill,center]", "c, growx 0");
+
+ for (int r = 0; r < sizes.length; r++) {
+ for (int c = 0; c < 4; c++) {
+ String text = sizes[r].length() > 0 ? sizes[r] : "default";
+ createButton(hPanel, text, sizes[r]);
+ }
+ }
+
+ // Vertical
+ MigLayout vLM = new MigLayout("wrap,flowy",
+ "[right][]",
+ "[grow,top][grow,center][grow,bottom][grow,fill,bottom][grow,fill,baseline]");
+ TabItem vPanel = createTabPanel(tabbedPane, "Vertical", vLM);
+ String[] vSizes = new String[] {"", "growy", "growy 0", "top", "center", "bottom"};
+ createLabel(vPanel, "[top]", "center");
+ createLabel(vPanel, "[center]", "center");
+ createLabel(vPanel, "[bottom]", "center");
+ createLabel(vPanel, "[fill, bottom]", "center, growy 0");
+ createLabel(vPanel, "[fill, baseline]", "center");
+
+ for (int c = 0; c < vSizes.length; c++) {
+ for (int r = 0; r < 5; r++) {
+ String text = vSizes[c].length() > 0 ? vSizes[c] : "default";
+ createButton(vPanel, text, vSizes[c]);
+ }
+ }
+
+ return tabbedPane;
+ }
+
+ public Control createUnits(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Horizontal
+ MigLayout hLM = new MigLayout("wrap",
+ "[right][]",
+ "");
+ TabItem hPanel = createTabPanel(tabbedPane, "Horizontal", hLM);
+ String[] sizes = new String[] {"72pt", "25.4mm", "2.54cm", "1in", "72px", "96px", "120px", "25%", "30sp"};
+ for (int i = 0; i < sizes.length; i++) {
+ createLabel(hPanel, sizes[i], "");
+ createTextField(hPanel, "", "width " + sizes[i] + "");
+ }
+
+ // Horizontal lp
+ MigLayout hlpLM = new MigLayout("", "[right][][]", "");
+ TabItem hlpPanel = createTabPanel(tabbedPane, "Horizontal LP", hlpLM);
+ createLabel(hlpPanel, "9 cols", "");
+ createTextField(hlpPanel, "", "wmin 9*6");
+ String[] lpSizes = new String[] {"75lp", "75px", "88px", "100px"};
+ createLabel(hlpPanel, "", "wrap");
+ for (int i = 0; i < lpSizes.length; i++) {
+ createLabel(hlpPanel, lpSizes[i], "");
+ createTextField(hlpPanel, "", "width " + lpSizes[i] + ", wrap");
+ }
+
+ // Vertical
+ MigLayout vLM = new MigLayout("wrap,flowy",
+ "[c]",
+ "[top][top]");
+ TabItem vPanel = createTabPanel(tabbedPane, "Vertical", vLM);
+ String[] vSizes = new String[] {"72pt", "25.4mm", "2.54cm", "1in", "72px", "96px", "120px", "25%", "30sp"};
+ for (int i = 0; i < sizes.length; i++) {
+ createLabel(vPanel, vSizes[i], "");
+ createTextArea(vPanel, "", "width 50!, height " + vSizes[i] + "");
+ }
+
+ // Vertical lp
+ MigLayout vlpLM = new MigLayout("wrap,flowy",
+ "[c]",
+ "[top][top]40px[top][top]");
+ TabItem vlpPanel = createTabPanel(tabbedPane, "Vertical LP", vlpLM);
+ createLabel(vlpPanel, "4 rows", "");
+ createTextArea(vlpPanel, "\n\n\n\n", "width 50!");
+ createLabel(vlpPanel, "field", "");
+ createTextField(vlpPanel, "", "wmin 5*9");
+
+ String[] vlpSizes1 = new String[] {"63lp", "57px", "63px", "68px", "25%"};
+ String[] vlpSizes2 = new String[] {"21lp", "21px", "23px", "24px", "10%"};
+ for (int i = 0; i < vlpSizes1.length; i++) {
+ createLabel(vlpPanel, vlpSizes1[i], "");
+ createTextArea(vlpPanel, "", "width 50!, height " + vlpSizes1[i] + "");
+ createLabel(vlpPanel, vlpSizes2[i], "");
+ createTextField(vlpPanel, "", "height " + vlpSizes2[i] + "!,wmin 5*6");
+ }
+
+ createLabel(vlpPanel, "button", "skip 2");
+ createButton(vlpPanel, "...", "");
+
+ return tabbedPane;
+ }
+
+ public Control createGrouping(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Ungrouped
+ MigLayout ugM = new MigLayout("", "[]push[][][]", "");
+ TabItem ugPanel = createTabPanel(tabbedPane, "Ungrouped", ugM);
+ createButton(ugPanel, "Help", "");
+ createButton(ugPanel, "< Back", "gap push");
+ createButton(ugPanel, "Forward >", "");
+ createButton(ugPanel, "Apply", "gap unrel");
+ createButton(ugPanel, "Cancel", "gap unrel");
+
+ // Grouped Components
+ MigLayout gM = new MigLayout("nogrid, fillx");
+ TabItem gPanel = createTabPanel(tabbedPane, "Grouped (Components)", gM);
+ createButton(gPanel, "Help", "sg");
+ createButton(gPanel, "< Back", "sg, gap push");
+ createButton(gPanel, "Forward >", "sg");
+ createButton(gPanel, "Apply", "sg, gap unrel");
+ createButton(gPanel, "Cancel", "sg, gap unrel");
+
+ // Grouped Columns
+ MigLayout gcM = new MigLayout("", "[sg,fill]push[sg,fill][sg,fill]unrel[sg,fill]unrel[sg,fill]", "");
+ TabItem gcPanel = createTabPanel(tabbedPane, "Grouped (Columns)", gcM);
+ createButton(gcPanel, "Help", "");
+ createButton(gcPanel, "< Back", "");
+ createButton(gcPanel, "Forward >", "");
+ createButton(gcPanel, "Apply", "");
+ createButton(gcPanel, "Cancel", "");
+
+ // Ungrouped Rows
+ MigLayout ugrM = new MigLayout(); // no "sg" is the only difference to next panel
+ TabItem ugrPanel = createTabPanel(tabbedPane, "Ungrouped Rows", ugrM);
+ createLabel(ugrPanel, "File Number:", "");
+ createTextField(ugrPanel, "30 ", "wrap");
+ createLabel(ugrPanel, "BL/MBL number:", "");
+ createTextField(ugrPanel, "7 ", "split 2");
+ createTextField(ugrPanel, "7 ", "wrap");
+ createLabel(ugrPanel, "Entry Date:", "");
+ createTextField(ugrPanel, "7 ", "wrap");
+ createLabel(ugrPanel, "RFQ Number:", "");
+ createTextField(ugrPanel, "30 ", "wrap");
+ createLabel(ugrPanel, "Goods:", "");
+ createCheck(ugrPanel, "Dangerous", "wrap");
+ createLabel(ugrPanel, "Shipper:", "");
+ createTextField(ugrPanel, "30 ", "wrap");
+ createLabel(ugrPanel, "Customer:", "");
+ createTextField(ugrPanel, "", "split 2,growx");
+ createButton(ugrPanel, "...", "width 60px:pref,wrap");
+ createLabel(ugrPanel, "Port of Loading:", "");
+ createTextField(ugrPanel, "30 ", "wrap");
+ createLabel(ugrPanel, "Destination:", "");
+ createTextField(ugrPanel, "30 ", "wrap");
+
+ // Grouped Rows
+ MigLayout grM = new MigLayout("", "[]", "[sg]"); // "sg" is the only difference to previous panel
+ TabItem grPanel = createTabPanel(tabbedPane, "Grouped Rows", grM);
+ createLabel(grPanel, "File Number:", "");
+ createTextField(grPanel, "30 ","wrap");
+ createLabel(grPanel, "BL/MBL number:", "");
+ createTextField(grPanel, "7 ","split 2");
+ createTextField(grPanel, "7 ", "wrap");
+ createLabel(grPanel, "Entry Date:", "");
+ createTextField(grPanel, "7 ", "wrap");
+ createLabel(grPanel, "RFQ Number:", "");
+ createTextField(grPanel, "30 ", "wrap");
+ createLabel(grPanel, "Goods:", "");
+ createCheck(grPanel, "Dangerous", "wrap");
+ createLabel(grPanel, "Shipper:", "");
+ createTextField(grPanel, "30 ", "wrap");
+ createLabel(grPanel, "Customer:", "");
+ createTextField(grPanel, "", "split 2,growx");
+ createButton(grPanel, "...", "width 50px:pref,wrap");
+ createLabel(grPanel, "Port of Loading:", "");
+ createTextField(grPanel, "30 ", "wrap");
+ createLabel(grPanel, "Destination:", "");
+ createTextField(grPanel, "30 ", "wrap");
+
+ return tabbedPane;
+ }
+
+ public Control createSpan(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Horizontal span
+ MigLayout colLM = new MigLayout("",
+ "[fill][25%,fill][105lp!,fill][150px!,fill]",
+ "[]15[][]");
+ TabItem colPanel = createTabPanel(tabbedPane, "Column Span/Split", colLM);
+ createTextField(colPanel, "Col1 [ ]", "");
+ createTextField(colPanel, "Col2 [25%]", "");
+ createTextField(colPanel, "Col3 [105lp!]", "");
+ createTextField(colPanel, "Col4 [150px!]", "wrap");
+
+ createLabel(colPanel, "Full Name:", "");
+ createTextField(colPanel, "span, growx ", "span,growx");
+
+ createLabel(colPanel, "Phone:", "");
+ createTextField(colPanel, " ", "span 3, split 5");
+ createTextField(colPanel, " ", null);
+ createTextField(colPanel, " ", null);
+ createTextField(colPanel, " ", null);
+ createLabel(colPanel, "(span 3, split 4)", "wrap");
+
+ createLabel(colPanel, "Zip/City:", "");
+ createTextField(colPanel, " ", "");
+ createTextField(colPanel, "span 2, growx", null);
+
+ // Vertical span
+ MigLayout rowLM = new MigLayout("wrap",
+ "[225lp]para[225lp]",
+ "[]3[]unrel[]3[]unrel[]3[]");
+ TabItem rowPanel = createTabPanel(tabbedPane, "Row Span", rowLM);
+ createLabel(rowPanel, "Name", "");
+ createLabel(rowPanel, "Notes", "");
+ createTextField(rowPanel, "growx", null);
+ createTextArea(rowPanel, "spany,grow ", "spany,grow,hmin 13*5");
+ createLabel(rowPanel, "Phone", "");
+ createTextField(rowPanel, "growx", null);
+ createLabel(rowPanel, "Fax", "");
+ createTextField(rowPanel, "growx", null);
+
+
+ return tabbedPane;
+ }
+
+ public Control createGrowing(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // All tab
+ MigLayout allLM = new MigLayout("",
+ "[pref!][grow,fill]",
+ "[]15[]");
+ TabItem allTab = createTabPanel(tabbedPane, "All", allLM);
+ createLabel(allTab, "Fixed", "");
+ createLabel(allTab, "Gets all extra space", "wrap");
+ createTextField(allTab, " ", "");
+ createTextField(allTab, " ", "");
+
+ // Half tab
+ MigLayout halfLM = new MigLayout("",
+ "[pref!][grow,fill]",
+ "[]15[]");
+ TabItem halfTab = createTabPanel(tabbedPane, "Half", halfLM);
+ createLabel(halfTab, "Fixed", "");
+ createLabel(halfTab, "Gets half of extra space", "");
+ createLabel(halfTab, "Gets half of extra space", "wrap");
+ createTextField(halfTab, " ", "");
+ createTextField(halfTab, " ", "");
+ createTextField(halfTab, " ", "");
+
+ // Percent 1 tab
+ MigLayout p1LM = new MigLayout("",
+ "[pref!][0:0,grow 25,fill][0:0,grow 75,fill]",
+ "[]15[]");
+ TabItem p1Tab = createTabPanel(tabbedPane, "Percent 1", p1LM);
+ createLabel(p1Tab, "Fixed", "");
+ createLabel(p1Tab, "Gets 25% of extra space", "");
+ createLabel(p1Tab, "Gets 75% of extra space", "wrap");
+ createTextField(p1Tab, " ", "");
+ createTextField(p1Tab, " ", "");
+ createTextField(p1Tab, " ", "");
+
+ // Percent 2 tab
+ MigLayout p2LM = new MigLayout("",
+ "[0:0,grow 33,fill][0:0,grow 67,fill]",
+ "[]15[]");
+ TabItem p2Tab = createTabPanel(tabbedPane, "Percent 2", p2LM);
+ createLabel(p2Tab, "Gets 33% of extra space", "");
+ createLabel(p2Tab, "Gets 67% of extra space", "wrap");
+ createTextField(p2Tab, " ", "");
+ createTextField(p2Tab, " ", "");
+
+ // Vertical 1 tab
+ MigLayout v1LM = new MigLayout("flowy",
+ "[]15[]",
+ "[][c,pref!][c,grow 25,fill][c,grow 75,fill]");
+ TabItem v1Tab = createTabPanel(tabbedPane, "Vertical 1", v1LM);
+ createLabel(v1Tab, "Fixed", "skip");
+ createLabel(v1Tab, "Gets 25% of extra space", "");
+ createLabel(v1Tab, "Gets 75% of extra space", "wrap");
+ createLabel(v1Tab, "new Text(SWT.MULTI | SWT.WRAP | SWT.BORDER)", "");
+ createTextArea(v1Tab, "", "hmin 4*13");
+ createTextArea(v1Tab, "", "hmin 4*13");
+ createTextArea(v1Tab, "", "hmin 4*13");
+
+ // Vertical 2 tab
+ MigLayout v2LM = new MigLayout("flowy",
+ "[]15[]",
+ "[][c,grow 33,fill][c,grow 67,fill]");
+ TabItem v2Tab = createTabPanel(tabbedPane, "Vertical 2", v2LM);
+ createLabel(v2Tab, "Gets 33% of extra space", "skip");
+ createLabel(v2Tab, "Gets 67% of extra space", "wrap");
+ createLabel(v2Tab, "new Text(SWT.MULTI | SWT.WRAP | SWT.BORDER)", "");
+ createTextArea(v2Tab, "", "hmin 4*13");
+ createTextArea(v2Tab, "", "hmin 4*13");
+
+ return tabbedPane;
+ }
+
+ public Control createBasic_Sizes(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Horizontal tab
+ MigLayout horLM = new MigLayout("",
+ "[]15[75px]25[min]25[]",
+ "[]15");
+ TabItem horTab = createTabPanel(tabbedPane, "Horizontal - Column size set", horLM);
+ createLabel(horTab, "75px", "skip");
+ createLabel(horTab, "Min", "");
+ createLabel(horTab, "Pref", "wrap");
+
+ createLabel(horTab, "new Text(15)", "");
+ createTextField(horTab, "", "wmin 10");
+ createTextField(horTab, "", "wmin 10");
+ createTextField(horTab, "", "wmin 10");
+
+ // Vertical tab 1
+ MigLayout verLM = new MigLayout("flowy,wrap",
+ "[]15[]",
+ "[]15[c,45:45]15[c,min]15[c,pref]");
+ TabItem verTab = createTabPanel(tabbedPane, "\"Vertical - Row sized\"", verLM);
+ createLabel(verTab, "45px", "skip");
+ createLabel(verTab, "Min", "");
+ createLabel(verTab, "Pref", "");
+
+ createLabel(verTab, "new Text(SWT.MULTI)", "");
+ createTextArea(verTab, "", "");
+ createTextArea(verTab, "", "");
+ createTextArea(verTab, "", "");
+
+ // Componentsized/Baseline 2
+ MigLayout verLM2 = new MigLayout("flowy,wrap",
+ "[]15[]",
+ "[]15[baseline]15[baseline]15[baseline]");
+ TabItem verTab2 = createTabPanel(tabbedPane, "\"Vertical - Component sized + Baseline\"", verLM2);
+ createLabel(verTab2, "45px", "skip");
+ createLabel(verTab2, "Min", "");
+ createLabel(verTab2, "Pref", "");
+
+ createLabel(verTab2, "new Text(SWT.MULTI)", "");
+ createTextArea(verTab2, "", "height 45");
+ createTextArea(verTab2, "", "height min");
+ createTextArea(verTab2, "", "height pref");
+
+ return tabbedPane;
+ }
+
+ public Control createAlignments(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // Horizontal tab
+ MigLayout horLM = new MigLayout("wrap",
+ "[label]15[left]15[center]15[right]15[fill]15[]",
+ "[]15[]");
+
+ String[] horLabels = new String[] {"[label]", "[left]", "[center]", "[right]", "[fill]", "[] (Default)"};
+ TabItem horTab = createTabPanel(tabbedPane, "Horizontal", horLM);
+ String[] horNames = new String[] {"First Name", "Phone Number", "Facsmile", "Email", "Address", "Other"};
+ for (int c = 0; c < horLabels.length; c++)
+ createLabel(horTab, horLabels[c], "");
+
+ for (int r = 0; r < horLabels.length; r++) {
+ for (int c = 0; c < horNames.length; c++) {
+ if (c == 0) {
+ createLabel(horTab, horNames[r] + ":", "");
+ } else {
+ createButton(horTab, horNames[r], "");
+ }
+ }
+ }
+
+ // Vertical tab
+ MigLayout verLM = new MigLayout("wrap,flowy",
+ "[]unrel[]rel[]",
+ "[top]15[center]15[bottom]15[fill]15[fill,baseline]15[baseline]15[]");
+
+ String[] verLabels = new String[] {"[top]", "[center]", "[bottom]", "[fill]", "[fill,baseline]", "[baseline]", "[] (Default)"};
+ TabItem verTab = createTabPanel(tabbedPane, "Vertical", verLM);
+
+ for (int c = 0; c < verLabels.length; c++)
+ createLabel(verTab, verLabels[c], "");
+
+ for (int c = 0; c < verLabels.length; c++)
+ createButton(verTab, "A Button", "");
+
+ for (int c = 0; c < verLabels.length; c++)
+ createTextField(verTab, "JTextFied", "");
+
+ for (int c = 0; c < verLabels.length; c++)
+ createTextArea(verTab, "Text ", "");
+
+ for (int c = 0; c < verLabels.length; c++)
+ createTextArea(verTab, "Text\nwith two lines", "");
+
+ for (int c = 0; c < verLabels.length; c++)
+ createTextArea(verTab, "Scrolling Text\nwith two lines", "");
+
+ return tabbedPane;
+ }
+
+ public Control createQuick_Start(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ MigLayout lm = new MigLayout("wrap",
+ "[right][fill,sizegroup]unrel[right][fill,sizegroup]",
+ "");
+
+ TabItem p = createTabPanel(tabbedPane, "Quick Start", lm);
+
+ addSeparator(p, "General");
+ createLabel(p, "Company", "gap indent");
+ createTextField(p, "", "span,growx");
+ createLabel(p, "Contact", "gap indent");
+ createTextField(p, "", "span,growx");
+
+ addSeparator(p, "Propeller");
+ createLabel(p, "PTI/kW", "gap indent");
+ createTextField(p, "", "wmin 100");
+ createLabel(p, "Power/kW", "gap indent");
+ createTextField(p, "", "wmin 100");
+ createLabel(p, "R/mm", "gap indent");
+ createTextField(p, "", "wmin 100");
+ createLabel(p, "D/mm", "gap indent");
+ createTextField(p, "", "wmin 100");
+
+ return tabbedPane;
+ }
+
+ public Control createGrow_Shrink(Composite parent)
+ {
+ TabFolder tabbedPane = new TabFolder(parent, DOUBLE_BUFFER);
+
+ // shrink tab
+ MigLayout slm = new MigLayout("nogrid");
+ TabItem shrinkTabPanel = createTabPanel(tabbedPane, "Shrink", new FillLayout());
+
+
+ SashForm shrinkSash = new SashForm(getComposite(shrinkTabPanel), SWT.HORIZONTAL | SWT.SMOOTH);
+ shrinkSash.setBackground(new Color(display, 100, 100, 100));
+
+ Composite shrinkPanel = createPanel(shrinkSash, slm);
+ shrinkPanel.setLayoutData("wmin 100");
+
+ createTextField(shrinkPanel, "shp 110", "shp 110,w 10:130");
+ createTextField(shrinkPanel, "Default (100)", "w 10:130");
+ createTextField(shrinkPanel, "shp 90", "shp 90,w 10:130");
+
+ createTextField(shrinkPanel, "shrink 25", "newline,shrink 25,w 10:130");
+ createTextField(shrinkPanel, "shrink 75", "shrink 75,w 10:130");
+
+ createTextField(shrinkPanel, "Default", "newline, w 10:130");
+ createTextField(shrinkPanel, "Default", "w 10:130");
+
+ createTextField(shrinkPanel, "shrink 0", "newline,shrink 0,w 10:130");
+
+ createTextField(shrinkPanel, "shp 110", "newline,shp 110,w 10:130");
+ createTextField(shrinkPanel, "shp 100,shrink 25", "shp 100,shrink 25,w 10:130");
+ createTextField(shrinkPanel, "shp 100,shrink 75", "shp 100,shrink 75,w 10:130");
+
+ createTextArea(shrinkSash, "Use the slider to see how the components shrink depending on the constraints set on them.\n\n'shp' means Shrink Priority. " +
+ "Lower values will be shrunk before higer ones and the default value is 100.\n\n'shrink' means Shrink Weight. " +
+ "Lower values relative to other's means they will shrink less when space is scarse. " +
+ "Shrink Weight is only relative to components with the same Shrink Priority. Default Shrink Weight is 100.\n\n" +
+ "The component's minimum size will always be honored.\n\nFor SWT, which doesn't have a component notion of minimum, " +
+ "preferred or maximum size, those sizes are set explicitly to minimum 10 and preferred 130 pixels.", "");
+
+ // Grow tab
+ TabItem growTabPanel = createTabPanel(tabbedPane, "Grow", new FillLayout());
+
+ SashForm growSash = new SashForm(getComposite(growTabPanel), SWT.HORIZONTAL | SWT.SMOOTH);
+ growSash.setBackground(new Color(display, 100, 100, 100));
+
+ Composite growPanel = createPanel(growSash, new MigLayout("nogrid", "[grow]"));
+ growPanel.setLayoutData("wmin 100");
+
+ createButton(growPanel, "gp 110, grow", "gp 110, grow, wmax 170");
+ createButton(growPanel, "Default (100), grow", "grow, wmax 170");
+ createButton(growPanel, "gp 90, grow", "gp 90, grow, wmax 170");
+
+ createButton(growPanel, "Default Button", "newline");
+
+ createButton(growPanel, "growx", "newline,growx,wrap");
+
+ createButton(growPanel, "gp 110, grow", "gp 110, grow, wmax 170");
+ createButton(growPanel, "gp 100, grow 25", "gp 100, grow 25, wmax 170");
+ createButton(growPanel, "gp 100, grow 75", "gp 100, grow 75, wmax 170");
+
+ createTextArea(growSash, "'gp' means Grow Priority. " +
+ "Lower values will be grown before higher ones and the default value is 100.\n\n'grow' means Grow Weight. " +
+ "Higher values relative to other's means they will grow more when space is up for takes. " +
+ "Grow Weight is only relative to components with the same Grow Priority. Default Grow Weight is 0 which means " +
+ "components will normally not grow. \n\nNote that the buttons in the first and last row have max width set to 170 to " +
+ "emphasize Grow Priority.\n\nThe component's maximum size will always be honored.", "");
+
+ return tabbedPane;
+ }
+
+
+ // **********************************************************
+ // * Helper Methods
+ // **********************************************************
+
+// private final ToolTipListener toolTipListener = new ToolTipListener();
+// private final ConstraintListener constraintListener = new ConstraintListener();
+
+ private Combo createCombo(Object parent, String[] texts, Object layout)
+ {
+ Combo b = new Combo(getComposite(parent), SWT.DROP_DOWN);
+ for (int i = 0; i < texts.length; i++)
+ b.add(texts[i]);
+ b.setLayoutData(layout);
+
+// configureActiveComponet(b);
+
+ return b;
+ }
+
+ private Label createLabel(Object parent, String text, Object layout)
+ {
+ return createLabel(parent, text, layout, SWT.LEFT);
+ }
+
+ private Label createLabel(Object parent, String text, Object layout, int style)
+ {
+ final Label b = new Label(getComposite(parent), style | DOUBLE_BUFFER);
+ b.setText(text);
+ b.setLayoutData(layout != null ? layout : text);
+// b.setAlignment();
+
+// configureActiveComponet(b);
+
+ return b;
+ }
+
+ private Text createTextField(Object parent, String text, Object layout)
+ {
+ final Text b = new Text(getComposite(parent), SWT.SINGLE | SWT.BORDER | DOUBLE_BUFFER);
+ b.setText(text);
+ b.setLayoutData(layout != null ? layout : text);
+
+// configureActiveComponet(b);
+
+ return b;
+ }
+
+ private Button createButton(Object parent, String text, Object layout)
+ {
+ return createButton(getComposite(parent), text, layout, false);
+ }
+
+ private Button createButton(Object parent, String text, Object layout, boolean bold)
+ {
+ Button b = new Button(getComposite(parent), SWT.PUSH | SWT.NO_BACKGROUND | DOUBLE_BUFFER);
+ b.setText(text.length() == 0 ? "\"\"" : text);
+ b.setLayoutData(layout != null ? layout : text);
+
+// configureActiveComponet(b);
+
+ return b;
+ }
+
+ private Composite createPanel(Object parent, String text, Object layout)
+ {
+ Color bg = new Color(display.getActiveShell().getDisplay(), 255, 255, 255);
+ Composite panel = new Composite(getComposite(parent), DOUBLE_BUFFER | SWT.BORDER);
+ panel.setLayout(new MigLayout("fill"));
+ panel.setBackground(bg);
+ panel.setLayoutData(layout != null ? layout : text);
+ text = text.length() == 0 ? "\"\"" : text;
+ Label label = createLabel(panel, text, "grow", SWT.NO_BACKGROUND | SWT.CENTER);
+ label.setBackground(bg);
+
+// configureActiveComponet(panel);
+
+ return panel;
+ }
+
+ private TabItem createTabPanel(TabFolder parent, String text, Layout lm)
+ {
+ Composite panel = new Composite(parent, DOUBLE_BUFFER);
+// panel.setBackground(parent.getDisplay().getSystemColor(SWT.COLOR_WHITE));
+ TabItem tab = new TabItem(parent, DOUBLE_BUFFER);
+ tab.setControl(panel);
+ tab.setText(text);
+ if (lm != null)
+ panel.setLayout(lm);
+
+// configureActiveComponet(panel);
+ return tab;
+ }
+
+ private Composite createPanel(Object parent, Layout lm)
+ {
+ Composite panel = new Composite(getComposite(parent), DOUBLE_BUFFER);
+ panel.setLayout(lm);
+
+// configureActiveComponet(panel);
+
+ return panel;
+ }
+
+ private Button createToggleButton(Object parent, String text, Object layout)
+ {
+ Button b = new Button(getComposite(parent), SWT.TOGGLE | DOUBLE_BUFFER);
+ b.setText(text.length() == 0 ? "\"\"" : text);
+ b.setLayoutData(layout != null ? layout : text);
+
+// configureActiveComponet(b);
+
+ return b;
+ }
+
+ private Button createCheck(Object parent, String text, Object layout)
+ {
+ Button b = new Button(getComposite(parent), SWT.CHECK | DOUBLE_BUFFER);
+ b.setText(text);
+ b.setLayoutData(layout != null ? layout : text);
+// configureActiveComponet(b);
+
+ return b;
+ }
+
+ private List createList(Object parent, String text, Object layout)
+ {
+ List list = new List(getComposite(parent), DOUBLE_BUFFER | SWT.BORDER);
+ list.add(text);
+ list.setLayoutData(layout);
+ return list;
+ }
+
+ private StyledText createTextArea(Object parent, String text, String layout)
+ {
+ return createTextArea(parent, text, layout, SWT.MULTI | SWT.WRAP | SWT.BORDER | DOUBLE_BUFFER);
+ }
+
+ private StyledText createTextArea(Object parent, String text, String layout, int style)
+ {
+ StyledText ta = new StyledText(getComposite(parent), SWT.MULTI | SWT.WRAP | style | DOUBLE_BUFFER);
+ ta.setText(text);
+ ta.setLayoutData(layout != null ? layout : text);
+
+// configureActiveComponet(ta);
+
+ return ta;
+ }
+
+ public Composite getComposite(Object c)
+ {
+ if (c instanceof Control)
+ return (Composite) c;
+
+ return (Composite) ((TabItem) c).getControl();
+ }
+
+ private Font deriveFont(Control cont, int style, int height)
+ {
+ Font f = cont.getFont();
+ FontData fd = f.getFontData()[0];
+ if (style != SWT.DEFAULT)
+ fd.setStyle(style);
+
+ if (height != -1)
+ fd.setHeight(height);
+
+ Font font = new Font(display, fd);
+ cont.setFont(font);
+ return font;
+ }
+
+// private Control configureActiveComponet(Control c)
+// {
+// c.addMouseMotionListener(toolTipListener);
+// c.addMouseListener(constraintListener);
+// return c;
+// }
+
+ private void addSeparator(Object panel, String text)
+ {
+ Label l = createLabel(panel, text, "gaptop para, span, split 2");
+ l.setForeground(new Color(display, 0, 70, 213));
+
+ Label s = new Label(getComposite(panel), SWT.SEPARATOR | SWT.HORIZONTAL | DOUBLE_BUFFER);
+ s.setLayoutData("gapleft rel, gaptop para, growx");
+
+// configureActiveComponet(s);
+ }
+
+// private class ConstraintListener extends MouseAdapter
+// {
+// public void mousePressed(MouseEvent e)
+// {
+// if (e.isPopupTrigger())
+// react(e);
+// }
+//
+// public void mouseReleased(MouseEvent e)
+// {
+// if (e.isPopupTrigger())
+// react(e);
+// }
+//
+// public void react(MouseEvent e)
+// {
+// Control c = (Control) e.getSource();
+// LayoutManager lm = c.getParent().getLayout();
+// if (lm instanceof SwtMigLayout == false)
+// lm = c.getLayout();
+//
+// if (lm instanceof SwtMigLayout) {
+// MigLayout ffl = (MigLayout) lm;
+// boolean isComp = ffl.isManagingComponent(c);
+// String compConstr = isComp ? ffl.getComponentConstraints(c) : null;
+// String rowsConstr = isComp ? null : ffl.getRowConstraints();
+// String colsConstr = isComp ? null : ffl.getColumnConstraints();
+// String layoutConstr = isComp ? null : ffl.getLayoutConstraints();
+//
+// ConstraintsDialog cDlg = new ConstraintsDialog(SwingDemo.this, layoutConstr, rowsConstr, colsConstr, compConstr);
+// cDlg.pack();
+// cDlg.setLocationRelativeTo(c);
+//
+// if (cDlg.showDialog()) {
+// try {
+// if (isComp) {
+// String constrStr = cDlg.componentConstrTF.getText().trim();
+// ffl.setComponentConstraints(c, constrStr);
+// if (c instanceof Button) {
+// c.setFont(BUTT_FONT);
+// ((Button) c).setText(constrStr.length() == 0 ? "<Empty>" : constrStr);
+// }
+// } else {
+// ffl.setLayoutConstraints(cDlg.layoutConstrTF.getText());
+// ffl.setRowConstraints(cDlg.rowsConstrTF.getText());
+// ffl.setColumnConstraints(cDlg.colsConstrTF.getText());
+// }
+// } catch(Exception ex) {
+// StringWriter sw = new StringWriter();
+// ex.printStackTrace(new PrintWriter(sw));
+// JOptionPane.showMessageDialog(SwingUtilities.getWindowAncestor(c), sw.toString(), "Error parsing Constraint!", JOptionPane.ERROR_MESSAGE);
+// return;
+// }
+//
+// c.invalidate();
+// c.getParent().validate();
+// }
+// }
+// }
+// }
+//
+// private static class ToolTipListener extends MouseMotionAdapter
+// {
+// public void mouseMoved(MouseEvent e)
+// {
+// Control c = (Control) e.getSource();
+// LayoutManager lm = c.getParent().getLayout();
+// if (lm instanceof SwtMigLayout) {
+// String constr = ((MigLayout) lm).getComponentConstraints(c);
+// c.setToolTipText((constr != null ? ("\"" + constr + "\"") : "null"));
+// }
+// }
+// }
+//
+// private static class ConstraintsDialog extends JDialog implements ActionListener, KeyEventDispatcher
+// {
+// private static final Color ERROR_COLOR = new Color(255, 180, 180);
+// private final JPanel mainPanel = new JPanel(parent, new SwtMigLayout("fillx,flowy,ins dialog",
+// "[fill]",
+// "2[]2"));
+// final Text layoutConstrTF;
+// final Text rowsConstrTF;
+// final Text colsConstrTF;
+// final Text componentConstrTF;
+//
+// private final Button okButt = new Button("OK");
+// private final Button cancelButt = new Button("Cancel");
+//
+// private boolean okPressed = false;
+//
+// public ConstraintsDialog(Frame owner, String layoutConstr, String rowsConstr, String colsConstr, String compConstr)
+// {
+// super(owner, (compConstr != null ? "Edit Component Constraints" : "Edit Container Constraints"), true);
+//
+// layoutConstrTF = createConstraintField(layoutConstr);
+// rowsConstrTF = createConstraintField(rowsConstr);
+// colsConstrTF = createConstraintField(colsConstr);
+// componentConstrTF = createConstraintField(compConstr);
+//
+// if (componentConstrTF != null) {
+// mainPanel.add(new Label("Component Constraints"));
+// mainPanel.add(componentConstrTF);
+// }
+//
+// if (layoutConstrTF != null) {
+// mainPanel.add(new Label("Container Layout Constraints"));
+// mainPanel.add(layoutConstrTF);
+// }
+//
+// if (rowsConstrTF != null) {
+// mainPanel.add(new Label("Container Row Constraints"), "gaptop unrel");
+// mainPanel.add(rowsConstrTF);
+// }
+//
+// if (colsConstrTF != null) {
+// mainPanel.add(new Label("Container Column Constraints"), "gaptop unrel");
+// mainPanel.add(colsConstrTF);
+// }
+//
+// mainPanel.add(okButt, "tag ok,split,flowx,gaptop 15");
+// mainPanel.add(cancelButt, "tag cancel,gaptop 15");
+//
+// setContentPane(mainPanel);
+//
+// okButt.addActionListener(this);
+// cancelButt.addActionListener(this);
+// }
+//
+// public void addNotify()
+// {
+// super.addNotify();
+// KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(this);
+// }
+//
+// public void removeNotify()
+// {
+// KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(this);
+// super.removeNotify();
+// }
+//
+// public boolean dispatchKeyEvent(KeyEvent e)
+// {
+// if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
+// dispose();
+// return false;
+// }
+//
+// public void actionPerformed(ActionEvent e)
+// {
+// if (e.getSource() == okButt)
+// okPressed = true;
+// dispose();
+// }
+//
+// private Text createConstraintField(String text)
+// {
+// if (text == null)
+// return null;
+//
+// final Text tf = new Text(text, 50);
+// tf.setFont(new Font("monospaced", Font.PLAIN, 12));
+//
+// tf.addKeyListener(new KeyAdapter() {
+// public void keyPressed(KeyEvent e)
+// {
+// if (e.getKeyCode() == KeyEvent.VK_ENTER) {
+// okButt.doClick();
+// return;
+// }
+//
+// javax.swing.Timer timer = new Timer(50, new ActionListener() {
+// public void actionPerformed(ActionEvent e)
+// {
+// String constr = tf.getText();
+// try {
+// if (tf == layoutConstrTF) {
+// MigLayout.validateLayoutConstraint(constr);
+// } else if (tf == rowsConstrTF) {
+// MigLayout.validateRowConstraints(constr);
+// } else if (tf == colsConstrTF) {
+// MigLayout.validateColumnConstraints(constr);
+// } else if (tf == componentConstrTF) {
+// MigLayout.validateComponentConstraint(constr);
+// }
+// tf.setBackground(Color.WHITE);
+// okButt.setEnabled(true);
+// } catch(Exception ex) {
+// tf.setBackground(ERROR_COLOR);
+// okButt.setEnabled(false);
+// }
+// }
+// });
+// timer.setRepeats(false);
+// timer.start();
+// }
+// });
+//
+// return tf;
+// }
+//
+// private boolean showDialog()
+// {
+// setVisible(true);
+// return okPressed;
+// }
+// }
+
+}
+
+
+
+
diff --git a/prototypes/miglayout/net/miginfocom/examples/Example01.java b/prototypes/miglayout/net/miginfocom/examples/Example01.java
new file mode 100644
index 00000000..c67d935c
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/examples/Example01.java
@@ -0,0 +1,43 @@
+package net.miginfocom.examples;
+
+import net.miginfocom.swing.MigLayout;
+
+import javax.swing.*;
+
+/**
+ */
+public class Example01
+{
+ private static JPanel createPanel()
+ {
+ JPanel panel = new JPanel(new MigLayout());
+
+ panel.add(new JLabel("First Name"));
+ panel.add(new JTextField(15));
+ panel.add(new JLabel("Surname"), "gap unrelated"); // Unrelated size is resolved per platform
+ panel.add(new JTextField(15), "wrap"); // Wraps to the next row
+ panel.add(new JLabel("Address"));
+ panel.add(new JTextField(), "span, growx"); // Spans cells in row and grows to fit that
+
+ return panel;
+ }
+
+ public static void main(String[] args)
+ {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ JFrame frame = new JFrame("Example 01");
+ frame.getContentPane().add(createPanel());
+ frame.pack();
+ frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ });
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/examples/Example02.java b/prototypes/miglayout/net/miginfocom/examples/Example02.java
new file mode 100644
index 00000000..31ef9286
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/examples/Example02.java
@@ -0,0 +1,53 @@
+package net.miginfocom.examples;
+
+import net.miginfocom.swing.MigLayout;
+
+import javax.swing.*;
+import javax.swing.border.CompoundBorder;
+import javax.swing.border.EmptyBorder;
+import javax.swing.border.EtchedBorder;
+
+public class Example02
+{
+ private static JPanel createPanel()
+ {
+ JPanel panel = new JPanel(new MigLayout());
+
+ panel.add(createLabel("West Panel"), "dock west");
+ panel.add(createLabel("North 1 Panel"), "dock north");
+ panel.add(createLabel("North 2 Panel"), "dock north");
+ panel.add(createLabel("South Panel"), "dock south");
+ panel.add(createLabel("East Panel"), "dock east");
+ panel.add(createLabel("Center Panel"), "grow, push"); // "dock center" from v3.0
+
+ return panel;
+ }
+
+ private static JLabel createLabel(String text)
+ {
+ JLabel label = new JLabel(text);
+ label.setHorizontalAlignment(JLabel.CENTER);
+ label.setBorder(new CompoundBorder(new EtchedBorder(), new EmptyBorder(5, 10, 5, 10)));
+ return label;
+ }
+
+ public static void main(String[] args)
+ {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+
+ JFrame frame = new JFrame("Example 02");
+ frame.getContentPane().add(createPanel());
+ frame.pack();
+ frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ });
+ }
+
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/AC.java b/prototypes/miglayout/net/miginfocom/layout/AC.java
new file mode 100644
index 00000000..34ade72b
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/AC.java
@@ -0,0 +1,493 @@
+package net.miginfocom.layout;
+
+import java.io.*;
+import java.util.ArrayList;
+
+/*
+ * 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
+ */
+
+/** A constraint that holds the column <b>or</b> row constraints for the grid. It also holds the gaps between the rows and columns.
+ * <p>
+ * This class is a holder and builder for a number of {@link net.miginfocom.layout.DimConstraint}s.
+ * <p>
+ * For a more thorough explanation of what these constraints do, and how to build the constriants, see the White Paper or Cheat Sheet at www.migcomponents.com.
+ * <p>
+ * Note that there are two way to build this constraint. Through String (e.g. <code>"[100]3[200,fill]"</code> or through API (E.g.
+ * <code>new AxisConstraint().size("100").gap("3").size("200").fill()</code>.
+ */
+public final class AC implements Externalizable
+{
+ private final ArrayList<DimConstraint> cList = new ArrayList<DimConstraint>(8);
+
+ private transient int curIx = 0;
+
+ /** Constructor. Creates an instance that can be configured manually. Will be initialized with a default
+ * {@link net.miginfocom.layout.DimConstraint}.
+ */
+ public AC()
+ {
+ cList.add(new DimConstraint());
+ }
+
+ /** Property. The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of.
+ * These <code><DimConstraints/code> contains all information in this class.
+ * @return The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. A new list and
+ * never <code>null</code>.
+ */
+ public final DimConstraint[] getConstaints()
+ {
+ return cList.toArray(new DimConstraint[cList.size()]);
+ }
+
+ /** Sets the different {@link net.miginfocom.layout.DimConstraint}s that this object should consists of.
+ * @param constr The different {@link net.miginfocom.layout.DimConstraint}s that this object consists of. The list
+ * will be copied for storage. <code>null</code> or and emty array will reset the constaints to one <code>DimConstraint</code>
+ * with default values.
+ */
+ public final void setConstaints(DimConstraint[] constr)
+ {
+ if (constr == null || constr.length < 1 )
+ constr = new DimConstraint[] {new DimConstraint()};
+
+ cList.clear();
+ cList.ensureCapacity(constr.length);
+ for (int i = 0; i < constr.length; i++)
+ cList.add(constr[i]);
+ }
+
+ /** Returns the number of rows/columns that this constraints currently have.
+ * @return The number of rows/columns that this constraints currently have. At least 1.
+ */
+ public int getCount()
+ {
+ return cList.size();
+ }
+
+ /** Sets the total number of rows/columns to <code>size</code>. If the number of rows/columns is already more
+ * than <code>size</code> nothing will happen.
+ * @param size The total number of rows/columns
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC count(int size)
+ {
+ makeSize(size);
+ return this;
+ }
+
+ /** Specifies that the current row/column should not be grid-like. The while row/colum will have its components layed out
+ * in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned).
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC noGrid()
+ {
+ return noGrid(curIx);
+ }
+
+ /** Specifies that the indicated rows/columns should not be grid-like. The while row/colum will have its components layed out
+ * in one single cell. It is the same as to say that the cells in this column/row will all be merged (a.k.a spanned).
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC noGrid(int... indexes)
+ {
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setNoGrid(true);
+ }
+ return this;
+ }
+
+ /** Sets the current row/column to <code>i</code>. If the current number of rows/columns is less than <code>i</code> a call
+ * to {@link #count(int)} will set the size accoringly.
+ * <p>
+ * The next call to any of the constriant methods (e.g. {@link net.miginfocom.layout.AC#noGrid}) will be carried
+ * out on this new row/column.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param i The new current row/column.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC index(int i)
+ {
+ makeSize(i);
+ curIx = i;
+ return this;
+ }
+
+ /** Specifies that the current row/column's component should grow by default. It does not affect the size of the row/column.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC fill()
+ {
+ return fill(curIx);
+ }
+
+ /** Specifies that the indicated rows'/columns' component should grow by default. It does not affect the size of the row/column.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC fill(int... indexes)
+ {
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setFill(true);
+ }
+ return this;
+ }
+
+// /** Specifies that the current row/column should be put in the end group <code>s</code> and will thus share the same ending
+// * coordinate within the group.
+// * <p>
+// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+// * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
+// * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+// */
+// public final AxisConstraint endGroup(String s)
+// {
+// return endGroup(s, curIx);
+// }
+//
+// /** Specifies that the indicated rows/columns should be put in the end group <code>s</code> and will thus share the same ending
+// * coordinate within the group.
+// * <p>
+// * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+// * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
+// * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+// * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+// */
+// public final AxisConstraint endGroup(String s, int... indexes)
+// {
+// for (int i = indexes.length - 1; i >= 0; i--) {
+// int ix = indexes[i];
+// makeSize(ix);
+// cList.get(ix).setEndGroup(s);
+// }
+// return this;
+// }
+
+ /** Specifies that the current row/column should be put in the size group <code>s</code> and will thus share the same size
+ * constraints as the other components in the group.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC sizeGroup(String s)
+ {
+ return sizeGroup(s, curIx);
+ }
+
+ /** Specifies that the indicated rows/columns should be put in the size group <code>s</code> and will thus share the same size
+ * constraints as the other components in the group.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC sizeGroup(String s, int... indexes)
+ {
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setSizeGroup(s);
+ }
+ return this;
+ }
+
+ /** Specifies the current row/column's min and/or preferred and/or max size. E.g. <code>"10px"</code> or <code>"50:100:200"</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s The minimum and/or preferred and/or maximum size of this row. The string will be interpreted
+ * as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC size(String s)
+ {
+ return size(s, curIx);
+ }
+
+ /** Specifies the indicated rows'/columns' min and/or preferred and/or max size. E.g. <code>"10px"</code> or <code>"50:100:200"</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The minimum and/or preferred and/or maximum size of this row. The string will be interpreted
+ * as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC size(String size, int... indexes)
+ {
+ BoundSize bs = ConstraintParser.parseBoundSize(size, false, true);
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setSize(bs);
+ }
+ return this;
+ }
+
+ /** Specifies the gap size to be the default one <b>AND</b> moves to the next column/row. The method is called <code>.gap()</code>
+ * rather the more natural <code>.next()</code> to indicate that it is very much related to the other <code>.gap(..)</code> methods.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC gap()
+ {
+ curIx++;
+ return this;
+ }
+
+ /** Specifies the gap size to <code>size</code> <b>AND</b> moves to the next column/row.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column.
+ * The string will be interpreted as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC gap(String size)
+ {
+ return gap(size, curIx++);
+ }
+
+ /** Specifies the indicated rows'/columns' gap size to <code>size</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size minimum and/or preferred and/or maximum size of the gap between this and the next row/column.
+ * The string will be interpreted as a <b>BoundSize</b>. For more info on how <b>BoundSize</b> is formatted see the documentation.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC gap(String size, int... indexes)
+ {
+ BoundSize bsa = size != null ? ConstraintParser.parseBoundSize(size, true, true) : null;
+
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ if (bsa != null)
+ cList.get(ix).setGapAfter(bsa);
+ }
+ return this;
+ }
+
+ /** Specifies the current row/column's columns default alignment <b>for its components</b>. It does not affect the positioning
+ * or size of the columns/row itself. For columns it is the horizonal alignment (e.g. "left") and for rows it is the vertical
+ * alignment (e.g. "top").
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param side The default side to align the components. E.g. "top" or "left", or "leading" or "trailing" or "bottom" or "right".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC align(String side)
+ {
+ return align(side, curIx);
+ }
+
+ /** Specifies the indicated rows'/columns' columns default alignment <b>for its components</b>. It does not affect the positioning
+ * or size of the columns/row itself. For columns it is the horizonal alignment (e.g. "left") and for rows it is the vertical
+ * alignment (e.g. "top").
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param side The default side to align the components. E.g. "top" or "left", or "before" or "after" or "bottom" or "right".
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC align(String side, int... indexes)
+ {
+ UnitValue al = ConstraintParser.parseAlignKeywords(side, true);
+ if (al == null)
+ al = ConstraintParser.parseAlignKeywords(side, false);
+
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setAlign(al);
+ }
+ return this;
+ }
+
+ /** Specifies the current row/column's grow priority.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The new grow priority.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC growPrio(int p)
+ {
+ return growPrio(p, curIx);
+ }
+
+ /** Specifies the indicated rows'/columns' grow priority.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The new grow priority.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC growPrio(int p, int... indexes)
+ {
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setGrowPriority(p);
+ }
+ return this;
+ }
+
+ /** Specifies the current row/column's grow weight within columns/rows with the same <code>grow priority</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param w The new grow weight.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC grow(float w)
+ {
+ return grow(w, curIx);
+ }
+
+ /** Specifies the indicated rows'/columns' grow weight within columns/rows with the same <code>grow priority</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param w The new grow weight.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC grow(float w, int... indexes)
+ {
+ Float gw = new Float(w);
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setGrow(gw);
+ }
+ return this;
+ }
+
+ /** Specifies the current row/column's shrink priority.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The new shrink priority.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC shrinkPrio(int p)
+ {
+ return shrinkPrio(p, curIx);
+ }
+
+ /** Specifies the indicated rows'/columns' shrink priority.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The new shrink priority.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC shrinkPrio(int p, int... indexes)
+ {
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setShrinkPriority(p);
+ }
+ return this;
+ }
+
+ /** Specifies that the current row/column's shrink weight withing the columns/rows with the same <code>shrink priority</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
+ * @param w The shrink weight.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC shrinkWeight(float w)
+ {
+ return shrinkWeight(w, curIx);
+ }
+
+ /** Specifies the indicated rows'/columns' shrink weight withing the columns/rows with the same <code>shrink priority</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the White Paper or Cheat Sheet at www.migcomponents.com.
+ * @param w The shrink weight.
+ * @param indexes The index(es) (0-based) of the columns/rows that should be affected by this constraint.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new AxisConstraint().noGrid().gap().fill()</code>.
+ */
+ public final AC shrinkWeight(float w, int... indexes)
+ {
+ Float sw = new Float(w);
+ for (int i = indexes.length - 1; i >= 0; i--) {
+ int ix = indexes[i];
+ makeSize(ix);
+ cList.get(ix).setShrink(sw);
+ }
+ return this;
+ }
+
+ private void makeSize(int sz)
+ {
+ if (cList.size() <= sz) {
+ cList.ensureCapacity(sz);
+ for (int i = cList.size(); i <= sz; i++)
+ cList.add(new DimConstraint());
+ }
+ }
+
+ // ************************************************
+ // 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() == AC.class)
+ LayoutUtil.writeAsXML(out, this);
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/layout/BoundSize.java b/prototypes/miglayout/net/miginfocom/layout/BoundSize.java
new file mode 100644
index 00000000..a5eeb32f
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/BoundSize.java
@@ -0,0 +1,246 @@
+package net.miginfocom.layout;
+
+import java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+import java.io.*;
+/*
+ * 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
+ */
+
+/** A size that contains minimum, preferred and maximum size of type {@link UnitValue}.
+ * <p>
+ * This class is a simple value container and it is immutable.
+ * <p>
+ * If a size is missing (i.e., <code>null</code>) that boundary should be considered "not in use".
+ * <p>
+ * You can create a BoundSize from a String with the use of {@link ConstraintParser#parseBoundSize(String, boolean, boolean)}
+ */
+public class BoundSize implements Serializable
+{
+ public static final BoundSize ZERO_PIXEL = new BoundSize(UnitValue.ZERO, "0px");
+
+ private final transient UnitValue min;
+ private final transient UnitValue pref;
+ private final transient UnitValue max;
+ private final transient boolean gapPush;
+
+ /** Constructor that use the same value for min/preferred/max size.
+ * @param minMaxPref The value to use for min/preferred/max size.
+ * @param createString The string used to create the BoundsSize.
+ */
+ public BoundSize(UnitValue minMaxPref, String createString)
+ {
+ this(minMaxPref, minMaxPref, minMaxPref, createString);
+ }
+
+ /** Constructor. <b>This method is here for serilization only and should normally not be used. Use
+ * {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead.
+ * @param min The minimum size. May be <code>null</code>.
+ * @param preferred The preferred size. May be <code>null</code>.
+ * @param max The maximum size. May be <code>null</code>.
+ * @param createString The string used to create the BoundsSize.
+ */
+ public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, String createString) // Bound to old delegate!!!!!
+ {
+ this(min, preferred, max, false, createString);
+ }
+
+ /** Constructor. <b>This method is here for serilization only and should normally not be used. Use
+ * {@link ConstraintParser#parseBoundSize(String, boolean, boolean)} instead.
+ * @param min The minimum size. May be <code>null</code>.
+ * @param preferred The preferred size. May be <code>null</code>.
+ * @param max The maximum size. May be <code>null</code>.
+ * @param gapPush If the size should be hinted as "pushing" and thus want to occupy free space if noone else is claiming it.
+ * @param createString The string used to create the BoundsSize.
+ */
+ public BoundSize(UnitValue min, UnitValue preferred, UnitValue max, boolean gapPush, String createString)
+ {
+ this.min = min;
+ this.pref = preferred;
+ this.max = max;
+ this.gapPush = gapPush;
+
+ LayoutUtil.putCCString(this, createString); // this escapes!!
+ }
+
+ /** Returns the minimum size as sent into the constructor.
+ * @return The minimum size as sent into the constructor. May be <code>null</code>.
+ */
+ public final UnitValue getMin()
+ {
+ return min;
+ }
+
+ /** Returns the preferred size as sent into the constructor.
+ * @return The preferred size as sent into the constructor. May be <code>null</code>.
+ */
+ public final UnitValue getPreferred()
+ {
+ return pref;
+ }
+
+ /** Returns the maximum size as sent into the constructor.
+ * @return The maximum size as sent into the constructor. May be <code>null</code>.
+ */
+ public final UnitValue getMax()
+ {
+ return max;
+ }
+
+ /** If the size should be hinted as "pushing" and thus want to occupy free space if noone else is claiming it.
+ * @return The value.
+ */
+ public boolean getGapPush()
+ {
+ return gapPush;
+ }
+
+ /** Returns if this bound size has no min, preferred and maximum size set (they are all <code>null</code>)
+ * @return If unset.
+ */
+ public boolean isUnset()
+ {
+ return pref == null && min == null && max == null;
+ }
+
+ /** Returns the minimum, preferred or maximum size for this bounded size.
+ * @param sizeType The type. <code>LayoutUtil.MIN</code>, <code>LayoutUtil.PREF</code> or <code>LayoutUtil.MAX</code>.
+ * @return
+ */
+ final UnitValue getSize(int sizeType)
+ {
+ switch(sizeType) {
+ case LayoutUtil.MIN:
+ return min;
+ case LayoutUtil.PREF:
+ return pref;
+ case LayoutUtil.MAX:
+ return max;
+ default:
+ throw new IllegalArgumentException("Unknown size: " + sizeType);
+ }
+ }
+
+ /** Convert the bound sizes to pixels.
+ * <p>
+ * <code>null</code> bound sizes will be 0 for min and preferred and {@link net.miginfocom.layout.LayoutUtil#INF} for max.
+ * @param refSize The reference size.
+ * @param parent The parent. Not <code>null</code>.
+ * @param comp The component, if applicable, can be <code>null</code>.
+ * @return An array of lenth three (min,pref,max).
+ */
+ final int[] getPixelSizes(float refSize, ContainerWrapper parent, ComponentWrapper comp)
+ {
+ return new int[] {
+ min != null ? min.getPixels(refSize, parent, comp) : 0,
+ pref != null ? pref.getPixels(refSize, parent, comp) : 0,
+ max != null ? max.getPixels(refSize, parent, comp) : LayoutUtil.INF
+ };
+ }
+
+ /** Returns the a constraint string that can be re-parsed to be the exact same UnitValue.
+ * @return A String. Never <code>null</code>.
+ */
+ String getConstraintString()
+ {
+ String cs = LayoutUtil.getCCString(this);
+ if (cs != null)
+ return cs;
+
+ if (min == pref && pref == max)
+ return min != null ? (min.getConstraintString() + "!") : "null";
+
+ StringBuilder sb = new StringBuilder(16);
+
+ if (min != null)
+ sb.append(min.getConstraintString()).append(':');
+
+ if (pref != null) {
+ sb.append(pref.getConstraintString());
+ } else if (min != null) {
+ sb.append('n');
+ }
+
+ if (max != null)
+ sb.append(sb.length() == 0 ? "::" : ":").append(max.getConstraintString());
+
+ if (gapPush) {
+ if (sb.length() > 0)
+ sb.append(':');
+ sb.append("push");
+ }
+
+ return sb.toString();
+ }
+
+ static {
+ LayoutUtil.setDelegate(BoundSize.class, new PersistenceDelegate() {
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ BoundSize bs = (BoundSize) oldInstance;
+ if (Grid.TEST_GAPS) {
+ return new Expression(oldInstance, BoundSize.class, "new", new Object[] {
+ bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getGapPush(), bs.getConstraintString()
+ });
+ } else {
+ return new Expression(oldInstance, BoundSize.class, "new", new Object[] {
+ bs.getMin(), bs.getPreferred(), bs.getMax(), bs.getConstraintString()
+ });
+ }
+ }
+ });
+ }
+
+ // ************************************************
+ // Persistence Delegate and Serializable combined.
+ // ************************************************
+
+ private static final long serialVersionUID = 1L;
+
+ protected Object readResolve() throws ObjectStreamException
+ {
+ return LayoutUtil.getSerializedObject(this);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException
+ {
+ if (getClass() == BoundSize.class)
+ LayoutUtil.writeAsXML(out, this);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
+ {
+ LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/layout/CC.java b/prototypes/miglayout/net/miginfocom/layout/CC.java
new file mode 100644
index 00000000..1fe75e2c
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/CC.java
@@ -0,0 +1,1543 @@
+package net.miginfocom.layout;
+
+import java.io.*;
+/*
+ * 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
+ */
+
+/** A simple value holder for one component's constraint.
+ */
+public final class CC implements Externalizable
+{
+ private static final BoundSize DEF_GAP = new BoundSize(null, null); // Only used to denote default wrap/newline gap.
+
+ static final String[] DOCK_SIDES = {"north", "west", "south", "east"};
+
+ // See the getters and setters for information about the properties below.
+
+ private int dock = -1;
+
+ private UnitValue[] pos = null; // [x1, y1, x2, y2]
+
+ private UnitValue[] padding = null; // top, left, bottom, right
+
+ private Boolean flowX = null;
+
+ private int skip = 0;
+
+ private int split = 1;
+
+ private int spanX = 1, spanY = 1;
+
+ private int cellX = -1, cellY = 0; // If cellX is -1 then cellY is also considered -1. cellY is never negative.
+
+ private String tag = null;
+
+ private String id = null;
+
+ private int hideMode = -1;
+
+ private DimConstraint hor = new DimConstraint();
+
+ private DimConstraint ver = new DimConstraint();
+
+ private BoundSize newline = null;
+
+ private BoundSize wrap = null;
+
+ private boolean boundsInGrid = true;
+
+ private boolean external = false;
+
+ private Float pushX = null, pushY = null;
+
+
+ /** Empty constructor.
+ */
+ public CC()
+ {
+ }
+
+ // **********************************************************
+ // Chaining constraint setters
+ // **********************************************************
+
+ /** Specifies that the component should be put in the end group <code>s</code> and will thus share the same ending
+ * coordinate as them within the group.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC endGroupX(String s)
+ {
+ hor.setEndGroup(s);
+ return this;
+ }
+
+ /** Specifies that the component should be put in the size group <code>s</code> and will thus share the same size
+ * as them within the group.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s A name to associate on the group that should be the same for other rows/columns in the same group.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC sizeGroupX(String s)
+ {
+ hor.setSizeGroup(s);
+ return this;
+ }
+
+ /** The minimum size for the component. The value will override any value that is set on the component itself.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC minWidth(String size)
+ {
+ hor.setSize(LayoutUtil.derive(hor.getSize(), ConstraintParser.parseUnitValue(size, true), null, null));
+ return this;
+ }
+
+ /** The size for the component as a min and/or preferref and/or maximum size. The value will override any value that is set on
+ * the component itself.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The size expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC width(String size)
+ {
+ hor.setSize(ConstraintParser.parseBoundSize(size, false, true));
+ return this;
+ }
+
+ /** The maximum size for the component. The value will override any value that is set on the component itself.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC maxWidth(String size)
+ {
+ hor.setSize(LayoutUtil.derive(hor.getSize(), null, null, ConstraintParser.parseUnitValue(size, true)));
+ return this;
+ }
+
+
+ /** The horizontal gap before and/or after the component. The gap is towards cell bounds and/or other component bounds.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param before The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
+ * @param after The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC gapX(String before, String after)
+ {
+ if (before != null)
+ hor.setGapBefore(ConstraintParser.parseBoundSize(before, true, true));
+
+ if (after != null)
+ hor.setGapAfter(ConstraintParser.parseBoundSize(after, true, true));
+
+ return this;
+ }
+
+ /** Same functionality as <code>getHorizontal().setAlign(ConstraintParser.parseUnitValue(unitValue, true))</code> only this method
+ * returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param align The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC alignX(String align)
+ {
+ hor.setAlign(ConstraintParser.parseUnitValueOrAlign(align, true, null));
+ return this;
+ }
+
+ /** The grow priority compared to other components in the same cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The grow priority.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC growPrioX(int p)
+ {
+ hor.setGrowPriority(p);
+ return this;
+ }
+
+ /** Grow weight for the component horizontally. It default to weight <code>100</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #growX(float)
+ */
+ public final CC growX()
+ {
+ hor.setGrow(ResizeConstraint.WEIGHT_100);
+ return this;
+ }
+
+ /** Grow weight for the component horizontally.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param w The new grow weight.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC growX(float w)
+ {
+ hor.setGrow(new Float(w));
+ return this;
+ }
+
+ /** The shrink priority compared to other components in the same cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The shrink priority.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC shrinkPrioX(int p)
+ {
+ hor.setShrinkPriority(p);
+ return this;
+ }
+
+ /** Shrink weight for the component horizontally.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param w The new shrink weight.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC shrinkX(float w)
+ {
+ hor.setShrink(new Float(w));
+ return this;
+ }
+
+ /** The end group that this componet should be placed in.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s The name of the group. If <code>null</code> that means no group (default)
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC endGroupY(String s)
+ {
+ ver.setEndGroup(s);
+ return this;
+ }
+
+ /** The size group that this componet should be placed in.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s The name of the group. If <code>null</code> that means no group (default)
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC sizeGroupY(String s)
+ {
+ ver.setSizeGroup(s);
+ return this;
+ }
+
+ /** The minimum size for the component. The value will override any value that is set on the component itself.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC minHeight(String size)
+ {
+ ver.setSize(LayoutUtil.derive(ver.getSize(), ConstraintParser.parseUnitValue(size, false), null, null));
+ return this;
+ }
+
+ /** The size for the component as a min and/or preferref and/or maximum size. The value will override any value that is set on
+ * the component itself.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The size expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC height(String size)
+ {
+ ver.setSize(ConstraintParser.parseBoundSize(size, false, false));
+ return this;
+ }
+
+ /** The maximum size for the component. The value will override any value that is set on the component itself.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The size expressed as a <code>UnitValue</code>. E.g. "100px" or "200mm".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC maxHeight(String size)
+ {
+ ver.setSize(LayoutUtil.derive(ver.getSize(), null, null, ConstraintParser.parseUnitValue(size, false)));
+ return this;
+ }
+
+ /** The vertical gap before (normally above) and/or after (normally below) the component. The gap is towards cell bounds and/or other component bounds.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param before The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
+ * @param after The size of the gap expressed as a <code>BoundSize</code>. E.g. "50:100px:200mm" or "100px!".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC gapY(String before, String after)
+ {
+ if (before != null)
+ ver.setGapBefore(ConstraintParser.parseBoundSize(before, true, false));
+
+ if (after != null)
+ ver.setGapAfter(ConstraintParser.parseBoundSize(after, true, false));
+
+ return this;
+ }
+
+ /** Same functionality as <code>getVertical().setAlign(ConstraintParser.parseUnitValue(unitValue, true))</code> only this method
+ * returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param align The align keyword or for instance "100px". E.g "top" or "bottom".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC alignY(String align)
+ {
+ ver.setAlign(ConstraintParser.parseUnitValueOrAlign(align, false, null));
+ return this;
+ }
+
+ /** The grow priority compared to other components in the same cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The grow priority.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC growPrioY(int p)
+ {
+ ver.setGrowPriority(p);
+ return this;
+ }
+
+ /** Grow weight for the component vertically. Defaults to <code>100</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #growY(Float)
+ */
+ public final CC growY()
+ {
+ ver.setGrow(ResizeConstraint.WEIGHT_100);
+ return this;
+ }
+
+ /** Grow weight for the component vertically.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param w The new grow weight.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC growY(Float w)
+ {
+ ver.setGrow(w);
+ return this;
+ }
+
+ /** The shrink priority compared to other components in the same cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The shrink priority.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC shrinkPrioY(int p)
+ {
+ ver.setShrinkPriority(p);
+ return this;
+ }
+
+ /** Shrink weight for the component horizontally.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param w The new shrink weight.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC shrinkY(float w)
+ {
+ ver.setShrink(new Float(w));
+ return this;
+ }
+
+ /** How this component, if hidden (not visible), should be treated.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param mode The mode. Default to the mode in the {@link net.miginfocom.layout.LC}.
+ * 0 == Normal. Bounds will be calculated as if the component was visible.<br>
+ * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
+ * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
+ * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC hideMode(int mode)
+ {
+ setHideMode(mode);
+ return this;
+ }
+
+ /** The id used to reference this component in some constraints.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
+ * The dot should never be first or last if present.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ */
+ public final CC id(String s)
+ {
+ setId(s);
+ return this;
+ }
+
+ /** Same functionality as {@link #setTag(String tag)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param tag The new tag. May be <code>null</code>.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setTag(String)
+ */
+ public final CC tag(String tag)
+ {
+ setTag(tag);
+ return this;
+ }
+
+ /** Same functionality as {@link #setCellX(int col)} and {@link #setCellY(int row)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param col The column in the grid to place this component.
+ * @param row The rw in the grid to place this component.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setCellX(int)
+ * @see #setCellY(int)
+ */
+ public final CC cell(int col, int row)
+ {
+ setCellX(col);
+ setCellY(row);
+ return this;
+ }
+
+ /** Set the cell(s) that the component should occupy in the grid. Same functionality as {@link #setCellX(int col)} and
+ * {@link #setCellY(int row)} together with {@link #setSpanX(int width)} and {@link #setSpanY(int height)}. This method
+ * returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param col The column in the grid to place this component.
+ * @param row The rw in the grid to place this component.
+ * @param width How many cells the component should span (i.e. merge). <code>LayoutUtil.INF</code> spans to the end of the row.
+ * @param height How many cells the component should span (i.e. merge). <code>LayoutUtil.INF</code> spans to the end of the column.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setCellX(int)
+ * @see #setCellY(int)
+ */
+ public final CC cell(int col, int row, int width, int height)
+ {
+ setCellX(col);
+ setCellY(row);
+ setSpanX(width);
+ setSpanY(height);
+ return this;
+ }
+
+ /** Same functionality as <code>spanX(cellsX).spanY(cellsY)</code> which means this cell will span cells in both x and y.
+ * This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setSpanY(int)
+ * @see #setSpanX(int)
+ * @see #spanY()
+ * @see #spanX()
+ */
+ public final CC span(int cellsX, int cellsY)
+ {
+ return spanX(cellsX).spanY(cellsY);
+ }
+
+ /** Same functionality as {@link #setSpanY(int LayoutUtil.INF)} which means this cell will span the rest of the column.
+ * This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setSpanY(int)
+ * @see #spanY()
+ */
+ public final CC spanY()
+ {
+ return spanY(LayoutUtil.INF);
+ }
+
+ /** Same functionality as {@link #setSpanY(int cells)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param cells The number of cells to span (i.e. merge).
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setSpanY(int)
+ */
+ public final CC spanY(int cells)
+ {
+ setSpanY(cells);
+ return this;
+ }
+
+ /** Same functionality as {@link #setSpanX(int LayoutUtil.INF)} which means this cell will span the rest of the row.
+ * This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setSpanX(int)
+ * @see #spanX()
+ */
+ public final CC spanX()
+ {
+ return spanX(LayoutUtil.INF);
+ }
+
+ /** Same functionality as {@link #setSpanX(int cells)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param cells The number of cells to span (i.e. merge).
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setSpanY(int)
+ */
+ public final CC spanX(int cells)
+ {
+ setSpanX(cells);
+ return this;
+ }
+
+ /** Same functionality as <code>pushX().pushY()</code> which means this cell will push in both x and y dimensions.
+ * This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setPushX(Float)
+ * @see #setPushX(Float)
+ * @see #pushY()
+ * @see #pushX()
+ */
+ public final CC push()
+ {
+ return pushX().pushY();
+ }
+
+ /** Same functionality as <code>pushX(weightX).pushY(weightY)</code> which means this cell will push in both x and y dimensions.
+ * This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param weightX The weight used in the push.
+ * @param weightY The weight used in the push.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setPushY(Float)
+ * @see #setPushX(Float)
+ * @see #pushY()
+ * @see #pushX()
+ */
+ public final CC push(Float weightX, Float weightY)
+ {
+ return pushX(weightX).pushY(weightY);
+ }
+
+ /** Same functionality as {@link #setPushY(Float))} which means this cell will push the rest of the column.
+ * This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setPushY(Float)
+ * @see #pushY()
+ */
+ public final CC pushY()
+ {
+ return pushY(ResizeConstraint.WEIGHT_100);
+ }
+
+ /** Same functionality as {@link #setPushY(Float weight)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param weight The weight used in the push.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setPushY(Float)
+ */
+ public final CC pushY(Float weight)
+ {
+ setPushY(weight);
+ return this;
+ }
+
+ /** Same functionality as {@link #setPushX(Float)} which means this cell will push the rest of the row.
+ * This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setPushX(Float)
+ * @see #pushX()
+ */
+ public final CC pushX()
+ {
+ return pushX(ResizeConstraint.WEIGHT_100);
+ }
+
+ /** Same functionality as {@link #setPushX(Float weight)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param weight The weight used in the push.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setPushY(Float)
+ */
+ public final CC pushX(Float weight)
+ {
+ setPushX(weight);
+ return this;
+ }
+
+ /** Same functionality as {@link #setSplit(int parts)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param parts The number of parts (i.e. component slots) the cell should be divided into.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setSplit(int)
+ */
+ public final CC split(int parts)
+ {
+ setSplit(parts);
+ return this;
+ }
+
+ /** Same functionality as {@link #setSkip(int)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param cells How many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setSkip(int)
+ */
+ public final CC skip(int cells)
+ {
+ setSkip(cells);
+ return this;
+ }
+
+ /** Same functionality as {@link #setExternal(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setExternal(boolean)
+ */
+ public final CC external()
+ {
+ setExternal(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setFlowX(Boolean .TRUE)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setFlowX(Boolean)
+ */
+ public final CC flowX()
+ {
+ setFlowX(Boolean.TRUE);
+ return this;
+ }
+
+ /** Same functionality as {@link #setFlowX(Boolean .FALSE)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setFlowX(Boolean)
+ */
+ public final CC flowY()
+ {
+ setFlowX(Boolean.FALSE);
+ return this;
+ }
+
+
+ /** Same functionality as {@link #growX()} and {@link #growY()}.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #growX()
+ * @see #growY()
+ */
+ public final CC grow()
+ {
+ growX();
+ growY();
+ return this;
+ }
+
+ /** Same functionality as {@link #setNewline(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setNewline(boolean)
+ */
+ public final CC newline()
+ {
+ setNewline(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setNewlineGapSize(BoundString)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param gapSize The gap size that will override the gap size in the row/colum constraints if <code>!= null</code>. E.g. "5px" or "unrel".
+ * If <code>null</code> or <code>""</code> the newline size will be set to the default size and turned on. This is different compared to
+ * {@link #setNewlineGapSize(BoundString)}.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setNewlineGapSize(BoundSize)
+ */
+ public final CC newline(String gapSize)
+ {
+ BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false));
+ if (bs != null) {
+ setNewlineGapSize(bs);
+ } else {
+ setNewline(true);
+ }
+ return this;
+ }
+
+ /** Same functionality as {@link #setWrap(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setWrap(boolean)
+ */
+ public final CC wrap()
+ {
+ setWrap(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setWrapGapSize(BoundString)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param gapSize The gap size that will override the gap size in the row/colum constraints if <code>!= null</code>. E.g. "5px" or "unrel".
+ * If <code>null</code> or <code>""</code> the wrap size will be set to the default size and turned on. This is different compared to
+ * {@link #setWrapGapSize(BoundString)}.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setWrapGapSize(BoundSize)
+ */
+ public final CC wrap(String gapSize)
+ {
+ BoundSize bs = ConstraintParser.parseBoundSize(gapSize, true, (flowX != null && flowX == false));
+ if (bs != null) {
+ setWrapGapSize(bs);
+ } else {
+ setWrap(true);
+ }
+ return this;
+ }
+
+ /** Same functionality as {@link #setDockSide(int 0)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setDockSide(int)
+ */
+ public final CC dockNorth()
+ {
+ setDockSide(0);
+ return this;
+ }
+
+ /** Same functionality as {@link #setDockSide(int 1)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setDockSide(int)
+ */
+ public final CC dockWest()
+ {
+ setDockSide(1);
+ return this;
+ }
+
+ /** Same functionality as {@link #setDockSide(int 2)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setDockSide(int)
+ */
+ public final CC dockSouth()
+ {
+ setDockSide(2);
+ return this;
+ }
+
+ /** Same functionality as {@link #setDockSide(int 3)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setDockSide(int)
+ */
+ public final CC dockEast()
+ {
+ setDockSide(3);
+ return this;
+ }
+
+ /** Sets the x-coordinate for the component. This is used to set the x coordinate position to a specific value. The component
+ * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setPos(UnitValue[])
+ * @see #setBoundsInGrid(boolean)
+ */
+ public final CC x(String x)
+ {
+ return corrPos(x, 0);
+ }
+
+ /** Sets the y-coordinate for the component. This is used to set the y coordinate position to a specific value. The component
+ * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setPos(UnitValue[])
+ * @see #setBoundsInGrid(boolean)
+ */
+ public final CC y(String y)
+ {
+ return corrPos(y, 1);
+ }
+
+ /** Sets the x2-coordinate for the component (right side). This is used to set the x2 coordinate position to a specific value. The component
+ * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the x position.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setPos(UnitValue[])
+ * @see #setBoundsInGrid(boolean)
+ */
+ public final CC x2(String x2)
+ {
+ return corrPos(x2, 2);
+ }
+
+ /** Sets the y2-coordinate for the component (bottom side). This is used to set the y2 coordinate position to a specific value. The component
+ * bounds is still precalculated to the grid cell and this method should be seen as a way to correct the y position.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setPos(UnitValue[])
+ * @see #setBoundsInGrid(boolean)
+ */
+ public final CC y2(String y2)
+ {
+ return corrPos(y2, 3);
+ }
+
+ private final CC corrPos(String uv, int ix)
+ {
+ UnitValue[] b = getPos();
+ if (b == null)
+ b = new UnitValue[4];
+
+ b[ix] = ConstraintParser.parseUnitValue(uv, (ix % 2 == 0));
+ setPos(b);
+
+ setBoundsInGrid(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #x(String x)} and {@link #y(String y)} toghether.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
+ * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setPos(UnitValue[])
+ */
+ public final CC pos(String x, String y)
+ {
+ UnitValue[] b = getPos();
+ if (b == null)
+ b = new UnitValue[4];
+
+ b[0] = ConstraintParser.parseUnitValue(x, true);
+ b[1] = ConstraintParser.parseUnitValue(y, false);
+ setPos(b);
+
+ setBoundsInGrid(false);
+ return this;
+ }
+
+ /** Same functionality as {@link #x(String x)}, {@link #y(String y)}, {@link #y2(String y)} and {@link #y2(String y)} toghether.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param x The x position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
+ * @param y The y position as a UnitValue. E.g. "10" or "40mm" or "container.x+10".
+ * @param x2 The x2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
+ * @param y2 The y2 side's position as a UnitValue. E.g. "10" or "40mm" or "container.x2 - 10".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setPos(UnitValue[])
+ */
+ public final CC pos(String x, String y, String x2, String y2)
+ {
+ setPos(new UnitValue[] {
+ ConstraintParser.parseUnitValue(x, true),
+ ConstraintParser.parseUnitValue(y, false),
+ ConstraintParser.parseUnitValue(x2, true),
+ ConstraintParser.parseUnitValue(y2, false),
+ });
+ setBoundsInGrid(false);
+ return this;
+ }
+
+ /** Same functionality as {@link #setPadding(UnitValue[])} but the unit values as absolute pixels. This method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param top The top padding that will be added to the y coordinate at the last stage in the layout.
+ * @param left The top padding that will be added to the x coordinate at the last stage in the layout.
+ * @param bottom The top padding that will be added to the y2 coordinate at the last stage in the layout.
+ * @param right The top padding that will be added to the x2 coordinate at the last stage in the layout.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setTag(String)
+ */
+ public final CC pad(int top, int left, int bottom, int right)
+ {
+ setPadding(new UnitValue[] {
+ new UnitValue(top), new UnitValue(left), new UnitValue(bottom), new UnitValue(right)
+ });
+ return this;
+ }
+
+ /** Same functionality as <code>setPadding(ConstraintParser.parseInsets(pad, false))}</code> only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param pad The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new ComponentConstraint().noGrid().gap().fill()</code>.
+ * @see #setTag(String)
+ */
+ public final CC pad(String pad)
+ {
+ setPadding(pad != null ? ConstraintParser.parseInsets(pad, false) : null);
+ return this;
+ }
+
+ // **********************************************************
+ // Bean properties
+ // **********************************************************
+
+ /** Returns the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size
+ * and grow/shink priorities and weights.
+ * @return The current dimension constraint. Never <code>null</code>.
+ */
+ public DimConstraint getHorizontal()
+ {
+ return hor;
+ }
+
+ /** Sets the horizontal dimension constraint for this component constraint. It has constraints for the horizontal size
+ * and grow/shink priorities and weights.
+ * @param h The new dimension constraint. If <code>null</code> it will be reset to <code>new DimConstraint();</code>
+ */
+ public void setHorizontal(DimConstraint h)
+ {
+ hor = h != null ? h : new DimConstraint();
+ }
+
+ /** Returns the vertical dimension constraint for this component constraint. It has constraints for the vertical size
+ * and grow/shink priorities and weights.
+ * @return The current dimension constraint. Never <code>null</code>.
+ */
+ public DimConstraint getVertical()
+ {
+ return ver;
+ }
+
+ /** Sets the vertical dimension constraint for this component constraint. It has constraints for the vertical size
+ * and grow/shink priorities and weights.
+ * @param v The new dimension constraint. If <code>null</code> it will be reset to <code>new DimConstraint();</code>
+ */
+ public void setVertical(DimConstraint v)
+ {
+ ver = v != null ? v : new DimConstraint();
+ }
+
+ /** Returns the vertical or horizontal dim constraint.
+ * @param isHor If the horizontal constraint should be returned.
+ * @return The dim constraint. Never <code>null</code>.
+ */
+ public DimConstraint getDimConstraint(boolean isHor)
+ {
+ return isHor ? hor : ver;
+ }
+
+ /** Returns the absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not
+ * affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used
+ * to adjust the edges relative to the old value. May be <code>null</code> and elements may be <code>null</code>.
+ * <code>null</code> value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1
+ * and x2 will just absolutely positions the component.
+ * <p>
+ * Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of thisproperty slightly.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value as a new array, free to modify.
+ */
+ public UnitValue[] getPos()
+ {
+ return pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null;
+ }
+
+ /** Sets absolute positioning of one or more of the edges. This will be applied last in the layout cycle and will not
+ * affect the flow or grid positions. The positioning is relative to the parent and can not (as padding) be used
+ * to adjust the edges relative to the old value. May be <code>null</code> and elements may be <code>null</code>.
+ * <code>null</code> value(s) for the x2 and y2 will be interpreted as to keep the preferred size and thus the x1
+ * and x2 will just absolutely positions the component.
+ * <p>
+ * Note that {@link #setBoundsInGrid(boolean)} changes the interpretation of thisproperty slightly.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param pos <code>UnitValue[] {x, y, x2, y2}</code>. Must be <code>null</code> or of length 4. Elements can be <code>null</code>.
+ */
+ public void setPos(UnitValue[] pos)
+ {
+ this.pos = pos != null ? new UnitValue[] {pos[0], pos[1], pos[2], pos[3]} : null;
+ }
+
+ /** Returns if the absolute <code>pos</code> value should be corrections to the component that is in a normal cell. If <code>false</code>
+ * the value of <code>pos</code> is truly absolute in that it will not affect the grid or have a default bounds in the grid.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ * @see #getPos()
+ */
+ public boolean isBoundsInGrid()
+ {
+ return boundsInGrid;
+ }
+
+ /** Sets if the absolute <code>pos</code> value should be corrections to the component that is in a normal cell. If <code>false</code>
+ * the value of <code>pos</code> is truly absolute in that it will not affect the grid or have a default bounds in the grid.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>true</code> for bounds taken from the grid position. <code>false</code> is default.
+ * @see #setPos(UnitValue[])
+ */
+ void setBoundsInGrid(boolean b)
+ {
+ this.boundsInGrid = b;
+ }
+
+ /** Returns the absolute cell position in the grid or <code>-1</code> if cell positioning is not used.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public int getCellX()
+ {
+ return cellX;
+ }
+
+ /** Set an absolute cell x-position in the grid. If &gt;= 0 this point points to the absolute cell that this constaint's component should occupy.
+ * If there's already a component in that cell they will split the cell. The flow will then continue after this cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param x The x-position or <code>-1</code> to disable cell positioning.
+ */
+ public void setCellX(int x)
+ {
+ cellX = x;
+ }
+
+ /** Returns the absolute cell position in the grid or <code>-1</code> if cell positioning is not used.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public int getCellY()
+ {
+ return cellX < 0 ? -1 : cellY;
+ }
+
+ /** Set an absolute cell x-position in the grid. If &gt;= 0 this point points to the absolute cell that this constaint's component should occupy.
+ * If there's already a component in that cell they will split the cell. The flow will then continue after this cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param y The y-position or <code>-1</code> to disable cell positioning.
+ */
+ public void setCellY(int y)
+ {
+ if (y < 0)
+ cellX = -1;
+ cellY = y < 0 ? 0 : y;
+ }
+
+ /** Sets the docking side. -1 means no docking.<br>
+ * Valid sides are: <code> north = 0, west = 1, south = 2, east = 3</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current side.
+ */
+ public int getDockSide()
+ {
+ return dock;
+ }
+
+ /** Sets the docking side. -1 means no docking.<br>
+ * Valid sides are: <code> north = 0, west = 1, south = 2, east = 3</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param side -1 or 0-3.
+ */
+ public void setDockSide(int side)
+ {
+ if (side < -1 || side > 3)
+ throw new IllegalArgumentException("Illegal dock side: " + side);
+ dock = side;
+ }
+
+ /** Returns if this component should have its bounds handled by an external source and not this layout manager.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public boolean isExternal()
+ {
+ return external;
+ }
+
+ /** If this boolean is true this component is not handled in any way by the layout manager and the component can have its bounds set by an external
+ * handler which is normally by the use of some <code>component.setBounds(x, y, width, height)</code> directly (for Swing).
+ * <p>
+ * The bounds <b>will not</b> affect the minimum and preferred size of the container.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>true</code> means that the bounds are not changed.
+ */
+ public void setExternal(boolean b)
+ {
+ this.external = b;
+ }
+
+ /** Returns if the flow in the <b>cell</b> is in the horizontal dimension. Vertical if <code>false</code>. Only the first
+ * component is a cell can set the flow.
+ * <p>
+ * If <code>null</code> the flow direction is inherited by from the {@link net.miginfocom.layout.LC}.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public Boolean getFlowX()
+ {
+ return flowX;
+ }
+
+ /** Sets if the flow in the <b>cell</b> is in the horizontal dimension. Vertical if <code>false</code>. Only the first
+ * component is a cell can set the flow.
+ * <p>
+ * If <code>null</code> the flow direction is inherited by from the {@link net.miginfocom.layout.LC}.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>Boolean.TRUE</code> means horizontal flow in the cell.
+ */
+ public void setFlowX(Boolean b)
+ {
+ this.flowX = b;
+ }
+
+ /** Sets how a component that is hidden (not visible) should be treated by default.
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The mode:<br>
+ * 0 == Normal. Bounds will be calculated as if the component was visible.<br>
+ * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
+ * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
+ * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
+ */
+ public int getHideMode()
+ {
+ return hideMode;
+ }
+
+ /** Sets how a component that is hidden (not visible) should be treated by default.
+ * @param mode The mode:<br>
+ * 0 == Normal. Bounds will be calculated as if the component was visible.<br>
+ * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
+ * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
+ * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
+ */
+ public void setHideMode(int mode)
+ {
+ if (mode < -1 || mode > 3)
+ throw new IllegalArgumentException("Wrong hideMode: " + mode);
+
+ hideMode = mode;
+ }
+
+ /** Returns the id used to reference this component in some constraints.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
+ * The dot should never be first or last if present.
+ */
+ public String getId()
+ {
+ return id;
+ }
+
+ /** Sets the id used to reference this component in some constraints.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param id The id or <code>null</code>. May consist of a groupID and an componentID which are separated by a dot: ".". E.g. "grp1.id1".
+ * The dot should never be first or last if present.
+ */
+ public void setId(String id)
+ {
+ this.id = id;
+ }
+
+ /** Returns the absolute resizing in the last stage of the layout cycle. May be <code>null</code> and elements may be <code>null</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value. <code>null</code> or of length 4.
+ */
+ public UnitValue[] getPadding()
+ {
+ return padding != null ? new UnitValue[] {padding[0], padding[1], padding[2], padding[3]} : null;
+ }
+
+ /** Sets the absolute resizing in the last stage of the layout cycle. These values are added to the edges and can thus for
+ * instance be used to grow or reduce the size or move the component an absolute number of pixels. May be <code>null</code>
+ * and elements may be <code>null</code>.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param sides top, left, bottom right. Must be <code>null</code> or of length 4.
+ */
+ public void setPadding(UnitValue[] sides)
+ {
+ this.padding = sides != null ? new UnitValue[] {sides[0], sides[1], sides[2], sides[3]} : null;
+ }
+
+ /** Returns how many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to.
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value. 0 if no skip.
+ */
+ public int getSkip()
+ {
+ return skip;
+ }
+
+ /** Sets how many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to.
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param cells How many cells in the grid that should be skipped <b>before</b> the component that this constraint belongs to
+ */
+ public void setSkip(int cells)
+ {
+ this.skip = cells;
+ }
+
+ /** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
+ * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public int getSpanX()
+ {
+ return spanX;
+ }
+
+ /** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
+ * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param cells The number of cells to span (i.e. merge).
+ */
+ public void setSpanX(int cells)
+ {
+ this.spanX = cells;
+ }
+
+ /** Returns the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
+ * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public int getSpanY()
+ {
+ return spanY;
+ }
+
+ /** Sets the number of cells the cell that this constraint's component will span in the indicated dimension. <code>1</code> is default and
+ * means that it only spans the current cell. <code>LayoutUtil.INF</code> is used to indicate a span to the end of the column/row.
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param cells The number of cells to span (i.e. merge).
+ */
+ public void setSpanY(int cells)
+ {
+ this.spanY = cells;
+ }
+
+ /** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing.
+ * If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight
+ * will take precedence. Push is normally used when the grid has not been defined in the layout.
+ * <p>
+ * If multiple components in a column has push weights set the largest one will be used for the column.
+ * @return The current push value. Default is <code>null</code>.
+ */
+ public Float getPushX()
+ {
+ return pushX;
+ }
+
+ /** "pushx" indicates that the column that this component is in (this first if the component spans) should default to growing.
+ * If any other column has been set to grow this push value on the component does nothing as the column's explicit grow weight
+ * will take precedence. Push is normally used when the grid has not been defined in the layout.
+ * <p>
+ * If multiple components in a column has push weights set the largest one will be used for the column.
+ * @param weight The new push value. Default is <code>null</code>.
+ */
+ public void setPushX(Float weight)
+ {
+ this.pushX = weight;
+ }
+
+ /** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing.
+ * If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight
+ * will take precedence. Push is normally used when the grid has not been defined in the layout.
+ * <p>
+ * If multiple components in a row has push weights set the largest one will be used for the row.
+ * @return The current push value. Default is <code>null</code>.
+ */
+ public Float getPushY()
+ {
+ return pushY;
+ }
+
+ /** "pushx" indicates that the row that this component is in (this first if the component spans) should default to growing.
+ * If any other row has been set to grow this push value on the component does nothing as the row's explicit grow weight
+ * will take precedence. Push is normally used when the grid has not been defined in the layout.
+ * <p>
+ * If multiple components in a row has push weights set the largest one will be used for the row.
+ * @param weight The new push value. Default is <code>null</code>.
+ */
+ public void setPushY(Float weight)
+ {
+ this.pushY = weight;
+ }
+
+ /** Returns in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance
+ * it is split in two, the next componet will also share the same cell. Note that the cell can also span a number of
+ * cells, which means that you can for instance span three cells and split that big cell for two components. Split can be
+ * set to a very high value to make all components in the same row/column share the same cell (e.g. <code>LayoutUtil.INF</code>).
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public int getSplit()
+ {
+ return split;
+ }
+
+ /** Sets in how many parts the current cell (that this constraint's component will be in) should be split in. If for instance
+ * it is split in two, the next componet will also share the same cell. Note that the cell can also span a number of
+ * cells, which means that you can for instance span three cells and split that big cell for two components. Split can be
+ * set to a very high value to make all components in the same row/column share the same cell (e.g. <code>LayoutUtil.INF</code>).
+ * <p>
+ * Note that only the first component will be checked for this property.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param parts The number of parts (i.e. component slots) the cell should be divided into.
+ */
+ public void setSplit(int parts)
+ {
+ this.split = parts;
+ }
+
+ /** Tags the component with metadata. Currently only used to tag buttons with for instance "cancel" or "ok" to make them
+ * show up in the correct order depending on platform. See {@link PlatformDefaults#setButtonOrder(String)} for information.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value. May be <code>null</code>.
+ */
+ public String getTag()
+ {
+ return tag;
+ }
+
+ /** Optinal tag that gives more context to this constraint's component. It is for instance used to tag buttons in a
+ * button bar with the button type such as "ok", "help" or "cancel".
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param tag The new tag. May be <code>null</code>.
+ */
+ public void setTag(String tag)
+ {
+ this.tag = tag;
+ }
+
+ /** Returns if the flow should wrap to the next line/column <b>after</b> the component that this constraint belongs to.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public boolean isWrap()
+ {
+ return wrap != null;
+ }
+
+ /** Sets if the flow should wrap to the next line/column <b>after</b> the component that this constraint belongs to.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>true</code> means wrap after.
+ */
+ public void setWrap(boolean b)
+ {
+ wrap = b ? (wrap == null ? DEF_GAP : wrap) : null;
+ }
+
+ /** Returns the wrap size if it is a custom size. If wrap was set to true with {@link #setWrap(boolean)} then this method will
+ * return <code>null</code> since that means that the gap size should be the default one as defined in the rows spec.
+ * @return The custom gap size. NOTE! Will return <code>null</code> for both no wrap <b>and</b> default wrap.
+ * @see #isWrap()
+ * @see #setWrap(boolean)
+ * @since 2.4.2
+ */
+ public BoundSize getWrapGapSize()
+ {
+ return wrap == DEF_GAP ? null : wrap;
+ }
+
+ /** Set the wrap size and turns wrap on if <code>!= null</code>.
+ * @param s The custom gap size. NOTE! <code>null</code> will not turn on or off wrap, it will only set the wrap gap size to "default".
+ * A non-null value will turn on wrap though.
+ * @see #isWrap()
+ * @see #setWrap(boolean)
+ * @since 2.4.2
+ */
+ public void setWrapGapSize(BoundSize s)
+ {
+ wrap = s == null ? (wrap != null ? DEF_GAP : null) : s;
+ }
+
+ /** Returns if the flow should wrap to the next line/column <b>before</b> the component that this constraint belongs to.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current value.
+ */
+ public boolean isNewline()
+ {
+ return newline != null;
+ }
+
+ /** Sets if the flow should wrap to the next line/column <b>before</b> the component that this constraint belongs to.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>true</code> means wrap before.
+ */
+ public void setNewline(boolean b)
+ {
+ newline = b ? (newline == null ? DEF_GAP : newline) : null;
+ }
+
+ /** Returns the newline size if it is a custom size. If newline was set to true with {@link #setNewline(boolean)} then this method will
+ * return <code>null</code> since that means that the gap size should be the default one as defined in the rows spec.
+ * @return The custom gap size. NOTE! Will return <code>null</code> for both no newline <b>and</b> default newline.
+ * @see #isNewline()
+ * @see #setNewline(boolean)
+ * @since 2.4.2
+ */
+ public BoundSize getNewlineGapSize()
+ {
+ return newline == DEF_GAP ? null : newline;
+ }
+
+ /** Set the newline size and turns newline on if <code>!= null</code>.
+ * @param s The custom gap size. NOTE! <code>null</code> will not turn on or off newline, it will only set the newline gap size to "default".
+ * A non-null value will turn on newline though.
+ * @see #isNewline()
+ * @see #setNewline(boolean)
+ * @since 2.4.2
+ */
+ public void setNewlineGapSize(BoundSize s)
+ {
+ newline = s == null ? (newline != null ? DEF_GAP : null) : s;
+ }
+
+ // ************************************************
+ // 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() == CC.class)
+ LayoutUtil.writeAsXML(out, this);
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java b/prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java
new file mode 100644
index 00000000..af96ca6b
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/ComponentWrapper.java
@@ -0,0 +1,258 @@
+package net.miginfocom.layout;
+/*
+ * 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
+ */
+
+/** A class that wraps the important parts of a Component.
+ * <p>
+ * <b>NOTE!</b>.equals() and .hashcode() should be shunted to the wrapped component. E.g.
+ * <pre>
+ * public int hashCode()
+ {
+ return getComponent().hashCode();
+ }
+
+ public final boolean equals(Object o)
+ {
+ if (o == null || o instanceof ComponentWrapper == false)
+ return false;
+
+ return getComponent().equals(((ComponentWrapper) o).getComponent());
+ }
+ * </pre>
+ */
+public interface ComponentWrapper
+{
+ static final int TYPE_UNSET = -1;
+ public static final int TYPE_UNKNOWN = 0;
+ public static final int TYPE_CONTAINER = 1;
+ public static final int TYPE_LABEL = 2;
+ public static final int TYPE_TEXT_FIELD = 3;
+ public static final int TYPE_TEXT_AREA = 4;
+ public static final int TYPE_BUTTON = 5;
+ public static final int TYPE_LIST = 6;
+ public static final int TYPE_TABLE = 7;
+ public static final int TYPE_SCROLL_PANE = 8;
+ public static final int TYPE_IMAGE = 9;
+ public static final int TYPE_PANEL = 10;
+ public static final int TYPE_COMBO_BOX = 11;
+ public static final int TYPE_SLIDER = 12;
+ public static final int TYPE_SPINNER = 13;
+ public static final int TYPE_PROGRESS_BAR = 14;
+ public static final int TYPE_TREE = 15;
+ public static final int TYPE_CHECK_BOX = 16;
+ public static final int TYPE_SCROLL_BAR = 17;
+ public static final int TYPE_SEPARATOR = 18;
+
+ /** Returns the actual object that this wrapper is aggregating. This might be needed for getting
+ * information about the object that the wrapper interface does not provide.
+ * <p>
+ * If this is a container the container should be returned instead.
+ * @return The actual object that this wrapper is aggregating. Not <code>null</code>.
+ */
+ public abstract Object getComponent();
+
+ /** Returns the current x coordinate for this component.
+ * @return The current x coordinate for this component.
+ */
+ public abstract int getX();
+
+ /** Returns the current y coordinate for this component.
+ * @return The current y coordinate for this component.
+ */
+ public abstract int getY();
+
+ /** Returns the current width for this component.
+ * @return The current width for this component.
+ */
+ public abstract int getWidth();
+
+ /** Returns the current height for this component.
+ * @return The current height for this component.
+ */
+ public abstract int getHeight();
+
+ /** Returns the screen x-coordinate for the upper left coordinate of the component layoutable bounds.
+ * @return The screen x-coordinate for the upper left coordinate of the component layoutable bounds.
+ */
+ public abstract int getScreenLocationX();
+
+ /** Returns the screen y-coordinate for the upper left coordinate of the component layoutable bounds.
+ * @return The screen y-coordinate for the upper left coordinate of the component layoutable bounds.
+ */
+ public abstract int getScreenLocationY();
+
+ /** Returns the minimum width of the component.
+ * @return The minimum width of the component.
+ */
+ public abstract int getMinimumWidth();
+
+ /** Returns the minimum height of the component.
+ * @return The minimum height of the component.
+ */
+ public abstract int getMinimumHeight();
+
+ /** Returns the preferred width of the component.
+ * @return The preferred width of the component.
+ */
+ public abstract int getPreferredWidth();
+
+ /** Returns the preferred height of the component.
+ * @return The preferred height of the component.
+ */
+ public abstract int getPreferredHeight();
+
+ /** Returns the maximum width of the component.
+ * @return The maximum width of the component.
+ */
+ public abstract int getMaximumWidth();
+
+ /** Returns the maximum height of the component.
+ * @return The maximum height of the component.
+ */
+ public abstract int getMaximumHeight();
+
+ /** Sets the component's bounds.
+ * @param x The x coordinate.
+ * @param y The y coordinate.
+ * @param width The width.
+ * @param height The height.
+ */
+ public abstract void setBounds(int x, int y, int width, int height);
+
+ /** Returns if the component's visibility is set to <code>true</code>. This should not return if the component is
+ * actually visibile, but if the visibility is set to true or not.
+ * @return <code>true</code> means visible.
+ */
+ public abstract boolean isVisible();
+
+ /** Returns the baseline for the component given the suggested height.
+ * @param width The width to calculate for if other than the current. If <code>-1</code> the current size should be used.
+ * @param height The height to calculate for if other than the current. If <code>-1</code> the current size should be used.
+ * @return The baseline from the top or -1 if not applicable.
+ */
+ public abstract int getBaseline(int width, int height);
+
+ /** Returns if the component has a baseline and if it can be retrieved. Should for instance return
+ * <code>false</code> for Swing before mustang.
+ * @return If the component has a baseline and if it can be retrieved.
+ */
+ public abstract boolean hasBaseline();
+
+ /** Returns the container for this component.
+ * @return The container for this component. Should never be <code>null</code>.
+ */
+ public abstract ContainerWrapper getParent();
+
+ /** Returns the pixel unit factor for the horizontal or vertical dimension.
+ * <p>
+ * The factor is 1 for both dimensions on the normal font in a JPanel on Windows. The factor should increase with a bigger "X".
+ * <p>
+ * This is the Swing version:
+ * <pre>
+ * Rectangle2D r = fm.getStringBounds("X", parent.getGraphics());
+ * wFactor = r.getWidth() / 6;
+ * hFactor = r.getHeight() / 13.27734375f;
+ * </pre>
+ * @param isHor If it is the horizontal factor that should be returned.
+ * @return The factor.
+ */
+ public abstract float getPixelUnitFactor(boolean isHor);
+
+ /** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default
+ * screen if the component is not visible.
+ * @return The DPI.
+ */
+ public abstract int getHorizontalScreenDPI();
+
+ /** Returns the DPI (Dots Per Inch) of the screen the component is currently in or for the default
+ * screen if the component is not visible.
+ * @return The DPI.
+ */
+ public abstract int getVerticalScreenDPI();
+
+ /** Returns the pixel size of the screen that the component is currently in or for the default
+ * screen if the component is not visible or <code>null</code>.
+ * @return The screen size. E.g. <code>1280</code>.
+ */
+ public abstract int getScreenWidth();
+
+ /** Returns the pixel size of the screen that the component is currently in or for the default
+ * screen if the component is not visible or <code>null</code>.
+ * @return The screen size. E.g. <code>1024</code>.
+ */
+ public abstract int getScreenHeight();
+
+ /** Returns a String id that can be used to reference the component in link constraints. This value should
+ * return the default id for the component. The id can be set for a component in the constraints and if
+ * so the value returned by this method will never be used. If there are no sensible id for the component
+ * <code>null</code> should be returned.
+ * <p>
+ * For instance the Swing implementation returns the string returned from <code>Component.getName()</code>.
+ * @return The string link id or <code>null</code>.
+ */
+ public abstract String getLinkId();
+
+ /** Returns a hash code that should be resonably different for anything that might change the layout. This value is used to
+ * know if the component layout needs to clear any caches.
+ * @return A hash code that should be resonably different for anything that might change the layout. Returns -1 if the widget is
+ * disposed.
+ */
+ public abstract int getLayoutHashCode();
+
+ /** Returns the padding on a component by component basis. This method can be overridden to return padding to compensate for example for
+ * borders that have shadows or where the outer most pixel is not the visual "edge" to align to.
+ * <p>
+ * Default implementation returnes <code>null</code> for all components except for Windows XP's JTabbedPane which will return new Insets(0, 0, 2, 2).
+ * <p>
+ * <b>NOTE!</B> To reduce cenerated garbage the returned padding should never be changed so that the same insets can be returned many times.
+ * @return <code>null</code> if no padding. <b>NOTE!</B> To reduce cenerated garbage the returned padding should never be changed so that
+ * the same insets can be returned many times. [top, left, bottom, right]
+ */
+ public int[] getVisualPadding();
+
+ /** Paints component outline to indicate where it is.
+ */
+ public abstract void paintDebugOutline();
+
+ /** Returns the type of component that this wrapper is wrapping.
+ * <p>
+ * This method can be invoked often so the result should be cached.
+ * @param disregardScrollPane Is <code>true</code> any wrapping scroll pane should be disregarded and the type
+ * of the scrolled component should be returned.
+ * @return The type of component that this wrapper is wrapping. E.g. {@link #TYPE_LABEL}.
+ */
+ public abstract int getComponetType(boolean disregardScrollPane);
+
+ ;
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java b/prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java
new file mode 100644
index 00000000..9abeafa7
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/ConstraintParser.java
@@ -0,0 +1,1409 @@
+package net.miginfocom.layout;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+/*
+ * 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
+ */
+
+/** Parses string constraints.
+ */
+public final class ConstraintParser
+{
+ private ConstraintParser()
+ {
+ }
+
+ /** Parses the layout constraints and stores the parsed values in the transient (cache) member varables.
+ * @param s The String to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>.
+ * @throws RuntimeException if the constaint was not valid.
+ * @return The parsed constraint. Never <code>null</code>.
+ */
+ public static LC parseLayoutConstraint(String s)
+ {
+ LC lc = new LC();
+ if (s.length() == 0)
+ return lc;
+
+ String[] parts = toTrimmedTokens(s, ',');
+
+ // First check for "ltr" or "rtl" since that will affect the interpretation of the other constraints.
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ if (part == null)
+ continue;
+
+ int len = part.length();
+ if (len == 3 || len == 11) { // Optimization
+ if (part.equals("ltr") || part.equals("rtl") || part.equals("lefttoright") || part.equals("righttoleft")) {
+ lc.setLeftToRight(part.charAt(0) == 'l' ? Boolean.TRUE : Boolean.FALSE);
+ parts[i] = null; // So we will not try to interpret it again
+ }
+
+ if (part.equals("ttb") || part.equals("btt") || part.equals("toptobottom") || part.equals("bottomtotop")) {
+ lc.setTopToBottom(part.charAt(0) == 't');
+ parts[i] = null; // So we will not try to interpret it again
+ }
+ }
+ }
+
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ if (part == null || part.length() == 0)
+ continue;
+
+ try {
+ int ix = -1;
+ char c = part.charAt(0);
+
+ if (c == 'w') {
+ ix = startsWithLenient(part, "wrap", -1, true);
+ if (ix > -1) {
+ String num = part.substring(ix).trim();
+ lc.setWrapAfter(num.length() != 0 ? Integer.parseInt(num) : 0);
+ continue;
+ }
+ }
+
+ if (c == 'g') {
+ if (part.startsWith("gapx ")) {
+ lc.setGridGapX(parseBoundSize(part.substring(5).trim(), true, true));
+ continue;
+ }
+
+ if (part.startsWith("gapy ")) {
+ lc.setGridGapY(parseBoundSize(part.substring(5).trim(), true, false));
+ continue;
+ }
+
+ if (part.startsWith("gap ")) {
+ String[] gaps = toTrimmedTokens(part.substring(4).trim(), ' ');
+ lc.setGridGapX(parseBoundSize(gaps[0], true, true));
+ lc.setGridGapY(gaps.length > 1 ? parseBoundSize(gaps[1], true, false) : lc.getGridGapX());
+ continue;
+ }
+ }
+
+ if (c == 'd') {
+ ix = startsWithLenient(part, "debug", 5, true);
+ if (ix > -1) {
+ String millis = part.substring(ix).trim();
+ lc.setDebugMillis(millis.length() > 0 ? Integer.parseInt(millis) : 1000);
+ continue;
+ }
+ }
+
+ if (c == 'n') {
+ if (part.equals("nogrid")) {
+ lc.setNoGrid(true);
+ continue;
+ }
+
+ if (part.equals("nocache")) {
+ lc.setNoCache(true);
+ continue;
+ }
+
+ if (part.equals("novisualpadding")) {
+ lc.setVisualPadding(false);
+ continue;
+ }
+ }
+
+ if (c == 'f') {
+ if (part.equals("fill") || part.equals("fillx") || part.equals("filly")) {
+ lc.setFillX(part.length() == 4 || part.charAt(4) == 'x');
+ lc.setFillY(part.length() == 4 || part.charAt(4) == 'y');
+ continue;
+ }
+
+ if (part.equals("flowy")) {
+ lc.setFlowX(false);
+ continue;
+ }
+
+ if (part.equals("flowx")) {
+ lc.setFlowX(true); // This is the default but added for consistency
+ continue;
+ }
+ }
+
+ if (c == 'i') {
+ ix = startsWithLenient(part, "insets", 3, true);
+ if (ix > -1) {
+ String insStr = part.substring(ix).trim();
+ UnitValue[] ins = parseInsets(insStr, true);
+ LayoutUtil.putCCString(ins, insStr);
+ lc.setInsets(ins);
+ continue;
+ }
+ }
+
+ if (c == 'a') {
+ ix = startsWithLenient(part, new String[] {"aligny", "ay"}, new int[] {6, 2}, true);
+ if (ix > -1) {
+ lc.setAlignY(parseUnitValueOrAlign(part.substring(ix).trim(), false, null));
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"alignx", "ax"}, new int[] {6, 2}, true);
+ if (ix > -1) {
+ lc.setAlignX(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "align", 2, true);
+ if (ix > -1) {
+ String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ lc.setAlignX(parseUnitValueOrAlign(gaps[0], true, null));
+ lc.setAlignY(gaps.length > 1 ? parseUnitValueOrAlign(gaps[1], false, null) : lc.getAlignX());
+ continue;
+ }
+ }
+
+ if (c == 'h' && part.startsWith("hidemode ")) {
+ lc.setHideMode(Integer.parseInt(part.substring(9)));
+ continue;
+ }
+
+ if (lc.getAlignX() == null) {
+ UnitValue alignX = parseAlignKeywords(part, true);
+ if (alignX != null) {
+ lc.setAlignX(alignX);
+ continue;
+ }
+ }
+
+ UnitValue alignY = parseAlignKeywords(part, false);
+ if (alignY != null) {
+ lc.setAlignY(alignY);
+ continue;
+ }
+
+ throw new IllegalArgumentException("Unknown Constraint: '" + part + "'\n");
+
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage());
+ }
+ }
+
+// lc = (LC) serializeTest(lc);
+
+ return lc;
+ }
+
+ /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
+ * @param s The string to parse. Not <code>null</code>.
+ * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed.
+ * @throws RuntimeException if the constaint was not valid.
+ */
+ public static AC parseRowConstraints(String s)
+ {
+ return parseAxisConstraint(s, false);
+ }
+
+ /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
+ * @param s The string to parse. Not <code>null</code>.
+ * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed.
+ * @throws RuntimeException if the constaint was not valid.
+ */
+ public static AC parseColumnConstraints(String s)
+ {
+ return parseAxisConstraint(s, true);
+ }
+
+ /** Parses the column or rows constraints. They normally looks something like <code>"[min:pref]rel[10px][]"</code>.
+ * @param s The string to parse. Not <code>null</code>.
+ * @param isCols If this for columns rather than rows.
+ * @return An array of {@link DimConstraint}s that is as manu are there exist "[...]" sections in the string that is parsed.
+ * @throws RuntimeException if the constaint was not valid.
+ */
+ private static AC parseAxisConstraint(String s, boolean isCols)
+ {
+ s = s.trim();
+
+ if (s.length() == 0)
+ return new AC(); // Short circuit for performance.
+
+ s = s.toLowerCase();
+
+ ArrayList<String> parts = getRowColAndGapsTrimmed(s);
+
+ BoundSize[] gaps = new BoundSize[(parts.size() >> 1) + 1];
+ for (int i = 0, iSz = parts.size(), gIx = 0; i < iSz; i += 2, gIx++)
+ gaps[gIx] = parseBoundSize(parts.get(i), true, isCols);
+
+ DimConstraint[] colSpecs = new DimConstraint[parts.size() >> 1];
+ for (int i = 0, gIx = 0; i < colSpecs.length; i++, gIx++) {
+ if (gIx >= gaps.length - 1)
+ gIx = gaps.length - 2;
+
+ colSpecs[i] = parseDimConstraint(parts.get((i << 1) + 1), gaps[gIx], gaps[gIx + 1], isCols);
+ }
+
+ AC ac = new AC();
+ ac.setConstaints(colSpecs);
+
+// ac = (AC) serializeTest(ac);
+
+ return ac;
+ }
+
+ /** Parses a single column or row constriant.
+ * @param s The single constrint to parse. May look something like <code>"min:pref,fill,grow"</code>. Should not be <code>null</code> and <b>must
+ * be lower case and trimmed</b>.
+ * @param gapBefore The default gap "before" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>.
+ * @param gapAfter The default gap "after" the column/row constraint. Can be overridden with a <code>"gap"</code> section within <code>s</code>.
+ * @param isCols If the constraints are column constraints rather than row constraints.
+ * @return A single constraint. Never <code>null</code>.
+ * @throws RuntimeException if the constaint was not valid.
+ */
+ private static DimConstraint parseDimConstraint(String s, BoundSize gapBefore, BoundSize gapAfter, boolean isCols)
+ {
+ DimConstraint dimConstraint = new DimConstraint();
+
+ // Default values.
+ dimConstraint.setGapBefore(gapBefore);
+ dimConstraint.setGapAfter(gapAfter);
+
+ String[] parts = toTrimmedTokens(s, ',');
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ try {
+ if (part.length() == 0)
+ continue;
+
+ if (part.equals("fill")) {
+ dimConstraint.setFill(true);
+ dimConstraint.setAlign(null); // Can not have both fill and alignment
+ continue;
+ }
+
+ if (part.equals("nogrid")) {
+ dimConstraint.setNoGrid(true);
+ continue;
+ }
+
+ int ix = -1;
+ char c = part.charAt(0);
+
+ if (c == 's') {
+ ix = startsWithLenient(part, new String[] {"sizegroup", "sg"}, new int[] {5, 2}, true);
+ if (ix > -1) {
+ dimConstraint.setSizeGroup(part.substring(ix).trim());
+ continue;
+ }
+
+
+ ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true);
+ if (ix > -1) {
+ dimConstraint.setShrinkPriority(Integer.parseInt(part.substring(ix).trim()));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "shrink", 6, true);
+ if (ix > -1) {
+ dimConstraint.setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+ }
+
+ if (c == 'g') {
+ ix = startsWithLenient(part, new String[] {"growpriority", "gp"}, new int[] {5, 2}, true);
+ if (ix > -1) {
+ dimConstraint.setGrowPriority(Integer.parseInt(part.substring(ix).trim()));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "grow", 4, true);
+ if (ix > -1) {
+ dimConstraint.setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+ }
+
+ if (c == 'a') {
+ ix = startsWithLenient(part, "align", 2, true);
+ if (ix > -1) {
+ if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set.
+ dimConstraint.setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), isCols, null));
+ continue;
+ }
+ }
+
+ UnitValue align = parseAlignKeywords(part, isCols);
+ if (align != null) {
+ if (dimConstraint.isFill() == false) // Swallow, but ignore if fill is set.
+ dimConstraint.setAlign(align);
+ continue;
+ }
+
+ // Only min:pref:max still left that is ok
+ dimConstraint.setSize(parseBoundSize(part, false, isCols));
+
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Illegal contraint: '" + part + "'\n" + ex.getMessage());
+ }
+ }
+ return dimConstraint;
+ }
+
+ /** Parses all component constraints and stores the parsed values in the transient (cache) member varables.
+ * @param constrMap The constraints as <code>String</code>s. Strings <b>must be lower case and trimmed</b>
+ * @return The parsed constraints. Never <code>null</code>.
+ */
+ public static Map<ComponentWrapper, CC> parseComponentConstraints(Map<ComponentWrapper, String> constrMap)
+ {
+ HashMap<ComponentWrapper, CC> flowConstrMap = new HashMap<ComponentWrapper, CC>();
+
+ for (Iterator<Map.Entry<ComponentWrapper, String>> it = constrMap.entrySet().iterator(); it.hasNext();) {
+ Map.Entry<ComponentWrapper, String> entry = it.next();
+ flowConstrMap.put(entry.getKey(), parseComponentConstraint(entry.getValue()));
+ }
+
+ return flowConstrMap;
+ }
+
+ /** Parses one component constraint and returns the parsed value.
+ * @param s The string to parse. Should not be <code>null</code> and <b>must be lower case and trimmed</b>.
+ * @throws RuntimeException if the constaint was not valid.
+ * @return The parsed constraint. Never <code>null</code>.
+ */
+ public static CC parseComponentConstraint(String s)
+ {
+ CC cc = new CC();
+
+ if (s.length() == 0)
+ return cc;
+
+ String[] parts = toTrimmedTokens(s, ',');
+
+ for (int i = 0; i < parts.length; i++) {
+ String part = parts[i];
+ try {
+ if (part.length() == 0)
+ continue;
+
+ int ix = -1;
+ char c = part.charAt(0);
+
+ if (c == 'n') {
+ if (part.equals("north")) {
+ cc.setDockSide(0);
+ continue;
+ }
+
+ if (part.equals("newline")) {
+ cc.setNewline(true);
+ continue;
+ }
+
+ if (part.startsWith("newline ")) {
+ String gapSz = part.substring(7).trim();
+ cc.setNewlineGapSize(parseBoundSize(gapSz, true, true));
+ continue;
+ }
+ }
+
+ if (c == 'f' && (part.equals("flowy") || part.equals("flowx"))) {
+ cc.setFlowX(part.charAt(4) == 'x' ? Boolean.TRUE : Boolean.FALSE);
+ continue;
+ }
+
+ if (c == 's') {
+ ix = startsWithLenient(part, "skip", 4, true);
+ if (ix > -1) {
+ String num = part.substring(ix).trim();
+ cc.setSkip(num.length() != 0 ? Integer.parseInt(num) : 1);
+ continue;
+ }
+
+ ix = startsWithLenient(part, "split", 5, true);
+ if (ix > -1) {
+ String split = part.substring(ix).trim();
+ cc.setSplit(split.length() > 0 ? Integer.parseInt(split) : LayoutUtil.INF);
+ continue;
+ }
+
+ if (part.equals("south")) {
+ cc.setDockSide(2);
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"spany","sy"}, new int[] {5, 2}, true);
+ if (ix > -1) {
+ cc.setSpanY(parseSpan(part.substring(ix).trim()));
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"spanx","sx"}, new int[] {5, 2}, true);
+ if (ix > -1) {
+ cc.setSpanX(parseSpan(part.substring(ix).trim()));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "span", 4, true);
+ if (ix > -1) {
+ String[] spans = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ cc.setSpanX(spans[0].length() > 0 ? Integer.parseInt(spans[0]) : LayoutUtil.INF);
+ cc.setSpanY(spans.length > 1 ? Integer.parseInt(spans[1]) : 1);
+ continue;
+ }
+
+ ix = startsWithLenient(part, "shrinkx", 7, true);
+ if (ix > -1) {
+ cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "shrinky", 7, true);
+ if (ix > -1) {
+ cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "shrink", 6, false);
+ if (ix > -1) {
+ String[] shrinks = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ cc.getHorizontal().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ if (shrinks.length > 1)
+ cc.getVertical().setShrink(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"shrinkprio", "shp"}, new int[] {10, 3}, true);
+ if (ix > -1) {
+ String sp = part.substring(ix).trim();
+ if (sp.startsWith("x") || sp.startsWith("y")) { // To gandle "gpx", "gpy", "shrinkpriorityx", shrinkpriorityy"
+ (sp.startsWith("x") ? cc.getHorizontal() : cc.getVertical()).setShrinkPriority(Integer.parseInt(sp.substring(2)));
+ } else {
+ String[] shrinks = toTrimmedTokens(sp, ' ');
+ cc.getHorizontal().setShrinkPriority(Integer.parseInt(shrinks[0]));
+ if (shrinks.length > 1)
+ cc.getVertical().setShrinkPriority(Integer.parseInt(shrinks[1]));
+ }
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"sizegroupx", "sizegroupy", "sgx", "sgy"}, new int[] {9, 9, 2, 2}, true);
+ if (ix > -1) {
+ String sg = part.substring(ix).trim();
+ char lc = part.charAt(ix - 1);
+ if (lc != 'y')
+ cc.getHorizontal().setSizeGroup(sg);
+ if (lc != 'x')
+ cc.getVertical().setSizeGroup(sg);
+ continue;
+ }
+ }
+
+ if (c == 'g') {
+ ix = startsWithLenient(part, "growx", 5, true);
+ if (ix > -1) {
+ cc.getHorizontal().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "growy", 5, true);
+ if (ix > -1) {
+ cc.getVertical().setGrow(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "grow", 4, false);
+ if (ix > -1) {
+ String[] grows = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ cc.getHorizontal().setGrow(parseFloat(grows[0], ResizeConstraint.WEIGHT_100));
+ cc.getVertical().setGrow(parseFloat(grows.length > 1 ? grows[1] : "", ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"growprio", "gp"}, new int[] {8, 2}, true);
+ if (ix > -1) {
+ String gp = part.substring(ix).trim();
+ char c0 = gp.length() > 0 ? gp.charAt(0) : ' ';
+ if (c0 == 'x' || c0 == 'y') { // To gandle "gpx", "gpy", "growpriorityx", growpriorityy"
+ (c0 == 'x' ? cc.getHorizontal() : cc.getVertical()).setGrowPriority(Integer.parseInt(gp.substring(2)));
+ } else {
+ String[] grows = toTrimmedTokens(gp, ' ');
+ cc.getHorizontal().setGrowPriority(Integer.parseInt(grows[0]));
+ if (grows.length > 1)
+ cc.getVertical().setGrowPriority(Integer.parseInt(grows[1]));
+ }
+ continue;
+ }
+
+ if (part.startsWith("gap")) {
+ BoundSize[] gaps = parseGaps(part);
+ if (gaps[0] != null)
+ cc.getVertical().setGapBefore(gaps[0]);
+ if (gaps[1] != null)
+ cc.getHorizontal().setGapBefore(gaps[1]);
+ if (gaps[2] != null)
+ cc.getVertical().setGapAfter(gaps[2]);
+ if (gaps[3] != null)
+ cc.getHorizontal().setGapAfter(gaps[3]);
+ continue;
+ }
+ }
+
+ if (c == 'a') {
+ ix = startsWithLenient(part, new String[] {"aligny", "ay"}, new int[] {6, 2}, true);
+ if (ix > -1) {
+ cc.getVertical().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), false, null));
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"alignx", "ax"}, new int[] {6, 2}, true);
+ if (ix > -1) {
+ cc.getHorizontal().setAlign(parseUnitValueOrAlign(part.substring(ix).trim(), true, null));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "align", 2, true);
+ if (ix > -1) {
+ String[] gaps = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ cc.getHorizontal().setAlign(parseUnitValueOrAlign(gaps[0], true, null));
+ if (gaps.length > 1)
+ cc.getVertical().setAlign(parseUnitValueOrAlign(gaps[1], false, null));
+ continue;
+ }
+ }
+
+ if ((c == 'x' || c == 'y') && part.length() > 2) {
+ char c2 = part.charAt(1);
+ if (c2 == ' ' || (c2 == '2' && part.charAt(2) == ' ')) {
+ if (cc.getPos() == null) {
+ cc.setPos(new UnitValue[4]);
+ } else if (cc.isBoundsInGrid() == false) {
+ throw new IllegalArgumentException("Can not combine 'position' with 'x/y/x2/y2' keywords.");
+ }
+
+ int edge = (c == 'x' ? 0 : 1) + (c2 == '2' ? 2 : 0);
+ UnitValue[] pos = cc.getPos();
+ pos[edge] = parseUnitValue(part.substring(2).trim(), null, c == 'x');
+ cc.setPos(pos);
+ cc.setBoundsInGrid(true);
+ continue;
+ }
+ }
+
+ if (c == 'c') {
+ ix = startsWithLenient(part, "cell", 4, true);
+ if (ix > -1) {
+ String[] grs = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ if (grs.length < 2)
+ throw new IllegalArgumentException("At least two integers must follow " + part);
+ cc.setCellX(Integer.parseInt(grs[0]));
+ cc.setCellY(Integer.parseInt(grs[1]));
+ if (grs.length > 2)
+ cc.setSpanX(Integer.parseInt(grs[2]));
+ if (grs.length > 3)
+ cc.setSpanY(Integer.parseInt(grs[3]));
+ continue;
+ }
+ }
+
+ if (c == 'p') {
+ ix = startsWithLenient(part, "pos", 3, true);
+ if (ix > -1) {
+ if (cc.getPos() != null && cc.isBoundsInGrid())
+ throw new IllegalArgumentException("Can not combine 'pos' with 'x/y/x2/y2' keywords.");
+
+ String[] pos = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ UnitValue[] bounds = new UnitValue[4];
+ for (int j = 0; j < pos.length; j++)
+ bounds[j] = parseUnitValue(pos[j], null, j % 2 == 0);
+
+ if (bounds[0] == null && bounds[2] == null || bounds[1] == null && bounds[3] == null)
+ throw new IllegalArgumentException("Both x and x2 or y and y2 can not be null!");
+
+ cc.setPos(bounds);
+ cc.setBoundsInGrid(false);
+ continue;
+ }
+
+ ix = startsWithLenient(part, "pad", 3, true);
+ if (ix > -1) {
+ UnitValue[] p = parseInsets(part.substring(ix).trim(), false);
+ cc.setPadding(new UnitValue[] {
+ p[0],
+ p.length > 1 ? p[1] : null,
+ p.length > 2 ? p[2] : null,
+ p.length > 3 ? p[3] : null});
+ continue;
+ }
+
+ ix = startsWithLenient(part, "pushx", 5, true);
+ if (ix > -1) {
+ cc.setPushX(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "pushy", 5, true);
+ if (ix > -1) {
+ cc.setPushY(parseFloat(part.substring(ix).trim(), ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+
+ ix = startsWithLenient(part, "push", 4, false);
+ if (ix > -1) {
+ String[] pushs = toTrimmedTokens(part.substring(ix).trim(), ' ');
+ cc.setPushX(parseFloat(pushs[0], ResizeConstraint.WEIGHT_100));
+ cc.setPushY(parseFloat(pushs.length > 1 ? pushs[1] : "", ResizeConstraint.WEIGHT_100));
+ continue;
+ }
+ }
+
+ if (c == 't') {
+ ix = startsWithLenient(part, "tag", 3, true);
+ if (ix > -1) {
+ cc.setTag(part.substring(ix).trim());
+ continue;
+ }
+ }
+
+ if (c == 'w' || c == 'h') {
+ if (part.equals("wrap")) {
+ cc.setWrap(true);
+ continue;
+ }
+
+ if (part.startsWith("wrap ")) {
+ String gapSz = part.substring(5).trim();
+ cc.setWrapGapSize(parseBoundSize(gapSz, true, true));
+ continue;
+ }
+
+ boolean isHor = c == 'w';
+ if (isHor && (part.startsWith("w ") || part.startsWith("width "))) {
+ String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 6).trim();
+ BoundSize wbs = parseBoundSize(uvStr, false, true);
+ LayoutUtil.putCCString(wbs, uvStr);
+ cc.getHorizontal().setSize(wbs);
+ continue;
+ }
+
+ if (!isHor && (part.startsWith("h ") || part.startsWith("height "))) {
+ String uvStr = part.substring(part.charAt(1) == ' ' ? 2 : 7).trim();
+ BoundSize hbs = parseBoundSize(uvStr, false, false);
+ LayoutUtil.putCCString(hbs, uvStr);
+ cc.getVertical().setSize(hbs);
+ continue;
+ }
+
+ if (part.startsWith("wmin ") || part.startsWith("wmax ") || part.startsWith("hmin ") || part.startsWith("hmax ")) {
+ String uvStr = part.substring(5).trim();
+ if (uvStr.length() > 0) {
+ UnitValue uv = parseUnitValue(uvStr, null, isHor);
+ boolean isMin = part.charAt(3) == 'n';
+ DimConstraint dc = isHor ? cc.getHorizontal() : cc.getVertical();
+ dc.setSize(new BoundSize(
+ isMin ? uv : (dc.getSize() != null ? dc.getSize().getMin() : null),
+ dc.getSize() != null ? dc.getSize().getPreferred() : null,
+ isMin ? (dc.getSize() != null ? dc.getSize().getMax() : null) : uv,
+ uvStr
+ ));
+ continue;
+ }
+ }
+
+ if (part.equals("west")) {
+ cc.setDockSide(1);
+// cc.getVertical().setGrow(ResizeConstraint.WEIGHT_100);
+ continue;
+ }
+
+ if (part.startsWith("hidemode ")) {
+ cc.setHideMode(Integer.parseInt(part.substring(9)));
+ continue;
+ }
+ }
+
+ if (c == 'i' && part.startsWith("id ")) {
+ cc.setId(part.substring(3).trim());
+ int dIx = cc.getId().indexOf('.');
+ if (dIx == 0 || dIx == cc.getId().length() - 1)
+ throw new IllegalArgumentException("Dot must not be first or last!");
+
+ continue;
+ }
+
+ if (c == 'e') {
+ if (part.equals("east")) {
+ cc.setDockSide(3);
+// cc.getVertical().setGrow(ResizeConstraint.WEIGHT_100);
+ continue;
+ }
+
+ if (part.equals("external")) {
+ cc.setExternal(true);
+ continue;
+ }
+
+ ix = startsWithLenient(part, new String[] {"endgroupx", "endgroupy", "egx", "egy"}, new int[] {-1, -1, -1, -1}, true);
+ if (ix > -1) {
+ String sg = part.substring(ix).trim();
+ char lc = part.charAt(ix - 1);
+ DimConstraint dc = (lc == 'x' ? cc.getHorizontal() : cc.getVertical());
+ dc.setEndGroup(sg);
+ continue;
+ }
+ }
+
+ if (c == 'd') {
+ if (part.equals("dock north")) {
+ cc.setDockSide(0);
+ continue;
+ }
+ if (part.equals("dock west")) {
+ cc.setDockSide(1);
+ continue;
+ }
+ if (part.equals("dock south")) {
+ cc.setDockSide(2);
+ continue;
+ }
+ if (part.equals("dock east")) {
+ cc.setDockSide(3);
+ continue;
+ }
+
+ if (part.equals("dock center")) {
+ cc.getHorizontal().setGrow(new Float(100f));
+ cc.getVertical().setGrow(new Float(100f));
+ continue;
+ }
+ }
+
+ UnitValue horAlign = parseAlignKeywords(part, true);
+ if (horAlign != null) {
+ cc.getHorizontal().setAlign(horAlign);
+ continue;
+ }
+
+ UnitValue verAlign = parseAlignKeywords(part, false);
+ if (verAlign != null) {
+ cc.getVertical().setAlign(verAlign);
+ continue;
+ }
+
+ throw new IllegalArgumentException("Unknown keyword.");
+
+ } catch (Exception ex) {
+ throw new IllegalArgumentException("Illegal Constraint: '" + part + "'\n" + ex.getMessage());
+ }
+ }
+
+// cc = (CC) serializeTest(cc);
+
+ return cc;
+ }
+
+ /** Parses insets which consists of 1-4 <code>UnitValue</code>s.
+ * @param s The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
+ * @param acceptPanel If "panel" and "dialog" should be accepted. They are used to access platform defaults.
+ * @return An array of length 4 with the parsed insets.
+ * @throws IllegalArgumentException if the parsing could not be done.
+ */
+ public static UnitValue[] parseInsets(String s, boolean acceptPanel)
+ {
+ if (s.length() == 0 || s.equals("dialog") || s.equals("panel")) {
+ if (acceptPanel == false)
+ throw new IllegalAccessError("Insets now allowed: " + s + "\n");
+
+ boolean isPanel = s.startsWith("p");
+ UnitValue[] ins = new UnitValue[4];
+ for (int j = 0; j < 4; j++)
+ ins[j] = isPanel ? PlatformDefaults.getPanelInsets(j) : PlatformDefaults.getDialogInsets(j);
+
+ return ins;
+ } else {
+ String[] insS = toTrimmedTokens(s, ' ');
+ UnitValue[] ins = new UnitValue[4];
+ for (int j = 0; j < 4; j++) {
+ UnitValue insSz = parseUnitValue(insS[j < insS.length ? j : insS.length - 1], UnitValue.ZERO, j % 2 == 1);
+ ins[j] = insSz != null ? insSz : PlatformDefaults.getPanelInsets(j);
+ }
+ return ins;
+ }
+ }
+
+ /** Parses gaps.
+ * @param s The string that contains gap information. Should start with "gap".
+ * @return The gaps as specified in <code>s</code>. Indexed: <code>[top,left,bottom,right][min,pref,max]</code> or
+ * [before,after][min,pref,max] if <code>oneDim</code> is true.
+ */
+ private static BoundSize[] parseGaps(String s)
+ {
+ BoundSize[] ret = new BoundSize[4];
+
+ int ix = startsWithLenient(s, "gaptop", -1, true);
+ if (ix > -1) {
+ s = s.substring(ix).trim();
+ ret[0] = parseBoundSize(s, true, false);
+ return ret;
+ }
+
+ ix = startsWithLenient(s, "gapleft", -1, true);
+ if (ix > -1) {
+ s = s.substring(ix).trim();
+ ret[1] = parseBoundSize(s, true, true);
+ return ret;
+ }
+
+ ix = startsWithLenient(s, "gapbottom", -1, true);
+ if (ix > -1) {
+ s = s.substring(ix).trim();
+ ret[2] = parseBoundSize(s, true, false);
+ return ret;
+ }
+
+ ix = startsWithLenient(s, "gapright", -1, true);
+ if (ix > -1) {
+ s = s.substring(ix).trim();
+ ret[3] = parseBoundSize(s, true, true);
+ return ret;
+ }
+
+ ix = startsWithLenient(s, "gapbefore", -1, true);
+ if (ix > -1) {
+ s = s.substring(ix).trim();
+ ret[1] = parseBoundSize(s, true, true);
+ return ret;
+ }
+
+ ix = startsWithLenient(s, "gapafter", -1, true);
+ if (ix > -1) {
+ s = s.substring(ix).trim();
+ ret[3] = parseBoundSize(s, true, true);
+ return ret;
+ }
+
+ ix = startsWithLenient(s, new String[] {"gapx", "gapy"}, null, true);
+ if (ix > -1) {
+ boolean x = s.charAt(3) == 'x';
+ String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
+ ret[x ? 1 : 0] = parseBoundSize(gaps[0], true, x);
+ if (gaps.length > 1)
+ ret[x ? 3 : 2] = parseBoundSize(gaps[1], true, !x);
+ return ret;
+ }
+
+ ix = startsWithLenient(s, "gap ", 1, true);
+ if (ix > -1) {
+ String[] gaps = toTrimmedTokens(s.substring(ix).trim(), ' ');
+
+ ret[1] = parseBoundSize(gaps[0], true, true); // left
+ if (gaps.length > 1) {
+ ret[3] = parseBoundSize(gaps[1], true, false); // right
+ if (gaps.length > 2) {
+ ret[0] = parseBoundSize(gaps[2], true, true); // top
+ if (gaps.length > 3)
+ ret[2] = parseBoundSize(gaps[3], true, false); // bottom
+ }
+ }
+ return ret;
+ }
+
+ throw new IllegalArgumentException("Unknown Gap part: '" + s + "'");
+ }
+
+ private static int parseSpan(String s)
+ {
+ return s.length() > 0 ? Integer.parseInt(s) : LayoutUtil.INF;
+ }
+
+ private static Float parseFloat(String s, Float nullVal)
+ {
+ return s.length() > 0 ? new Float(Float.parseFloat(s)) : nullVal;
+ }
+
+ /** Parses a singele "min:pref:max" value. May look something like <code>"10px:20lp:30%"</code> or <code>"pref!"</code>.
+ * @param s The string to parse. Not <code>null</code>.
+ * @param isGap If this bound size is a gap (different empty string handling).
+ * @param isHor If the size is for the horizontal dimension.
+ * @return A bound size that may be <code>null</code> if the string was "null", "n" or <code>null</code>.
+ */
+ public static BoundSize parseBoundSize(String s, boolean isGap, boolean isHor)
+ {
+ if (s.length() == 0 || s.equals("null") || s.equals("n"))
+ return null;
+
+ boolean push = false;
+ if (s.endsWith("push")) {
+ if (isGap == false)
+ throw new IllegalArgumentException("Only gaps can have 'push' in size. Use as separate keyword for components.");
+ push = true;
+ int l = s.length();
+ s = s.substring(0, l - (s.endsWith(":push") ? 5 : 4));
+ if (s.length() == 0)
+ return new BoundSize(null, null, null, true, s);
+ }
+
+ String[] sizes = toTrimmedTokens(s, ':');
+ String s0 = sizes[0];
+
+ if (sizes.length == 1) {
+ boolean hasEM = s0.endsWith("!");
+ if (hasEM)
+ s0 = s0.substring(0, s0.length() - 1);
+ UnitValue uv = parseUnitValue(s0, null, isHor);
+ return new BoundSize(((isGap || hasEM) ? uv : null), uv, (hasEM ? uv : null), push, s);
+
+ } else if (sizes.length == 2) {
+ return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), null, push, s);
+ } else if (sizes.length == 3) {
+ return new BoundSize(parseUnitValue(s0, null, isHor), parseUnitValue(sizes[1], null, isHor), parseUnitValue(sizes[2], null, isHor), push, s);
+ } else {
+ throw new IllegalArgumentException("Min:Preferred:Max size section must contain 0, 1 or 2 colons. '" + s + "'");
+ }
+ }
+
+ /** Parses a single unit value that may also be an alignment as parsed by {@link #parseAlignKeywords(String, boolean)}.
+ * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
+ * @param isHor If the value is for the horizontal dimension.
+ * @param emptyReplacement A replacement if <code>s</code> is empty. May be <code>null</code>.
+ * @return The parsed unit value. May be <code>null</code>.
+ */
+ public static UnitValue parseUnitValueOrAlign(String s, boolean isHor, UnitValue emptyReplacement)
+ {
+ if (s.length() == 0)
+ return emptyReplacement;
+
+ UnitValue align = parseAlignKeywords(s, isHor);
+ if (align != null)
+ return align;
+
+ return parseUnitValue(s, emptyReplacement, isHor);
+ }
+
+ /** Parses a single unit value. E.g. "10px" or "5in"
+ * @param s The string to parse. Not <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
+ * @param isHor If the value is for the horizontal dimension.
+ * @return The parsed unit value. <code>null</code> is empty string,
+ */
+ public static UnitValue parseUnitValue(String s, boolean isHor)
+ {
+ return parseUnitValue(s, null, isHor);
+ }
+
+ /** Parses a single unit value.
+ * @param s The string to parse. May be <code>null</code>. May look something like <code>"10px"</code> or <code>"5dlu"</code>.
+ * @param emptyReplacement A replacement <code>s</code> is empty or <code>null</code>. May be <code>null</code>.
+ * @param isHor If the value is for the horizontal dimension.
+ * @return The parsed unit value. May be <code>null</code>.
+ */
+ private static UnitValue parseUnitValue(String s, UnitValue emptyReplacement, boolean isHor)
+ {
+ if (s == null || s.length() == 0)
+ return emptyReplacement;
+
+ String cs = s; // Save creation string.
+ char c0 = s.charAt(0);
+
+ // Remove start and end parentheses, if there.
+ if (c0 == '(' && s.charAt(s.length() - 1) == ')')
+ s = s.substring(1, s.length() - 1);
+
+ if (c0 == 'n' && (s.equals("null") || s.equals("n")))
+ return null;
+
+ if (c0 == 'i' && s.equals("inf"))
+ return UnitValue.INF;
+
+ int oper = getOper(s);
+ boolean inline = oper == UnitValue.ADD || oper == UnitValue.SUB || oper == UnitValue.MUL || oper == UnitValue.DIV;
+
+ if (oper != UnitValue.STATIC) { // It is a multi-value
+
+ String[] uvs;
+ if (inline == false) { // If the format is of type "opr(xxx,yyy)" (compared to in-line "10%+15px")
+ String sub = s.substring(4, s.length() - 1).trim();
+ uvs = toTrimmedTokens(sub, ',');
+ if (uvs.length == 1)
+ return parseUnitValue(sub, null, isHor);
+ } else {
+ char delim;
+ if (oper == UnitValue.ADD) {
+ delim = '+';
+ } else if (oper == UnitValue.SUB) {
+ delim = '-';
+ } else if (oper == UnitValue.MUL) {
+ delim = '*';
+ } else { // div left
+ delim = '/';
+ }
+ uvs = toTrimmedTokens(s, delim);
+ if (uvs.length > 2) { // More than one +-*/.
+ String last = uvs[uvs.length - 1];
+ String first = s.substring(0, s.length() - last.length() - 1);
+ uvs = new String[] {first, last};
+ }
+ }
+
+ if (uvs.length != 2)
+ throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'");
+
+ UnitValue sub1 = parseUnitValue(uvs[0], null, isHor);
+ UnitValue sub2 = parseUnitValue(uvs[1], null, isHor);
+
+ if (sub1 == null || sub2 == null)
+ throw new IllegalArgumentException("Malformed UnitValue. Must be two sub-values: '" + s + "'");
+
+ return new UnitValue(isHor, oper, sub1, sub2, cs);
+ } else {
+ try {
+ String[] numParts = getNumTextParts(s);
+ float value = numParts[0].length() > 0 ? Float.parseFloat(numParts[0]) : 1; // e.g. "related" has no number part..
+
+ return new UnitValue(value, numParts[1], isHor, oper, cs);
+
+ } catch(Exception e) {
+ throw new IllegalArgumentException("Malformed UnitValue: '" + s + "'");
+ }
+ }
+ }
+
+ /** Parses alignment keywords and returns the approprieate <code>UnitValue</code>.
+ * @param s The string to parse. Not <code>null</code>.
+ * @param isHor If alignments for horizontal is checked. <code>false</code> means vertical.
+ * @return The unit value or <code>null</code> if not recognized (no exception).
+ */
+ static UnitValue parseAlignKeywords(String s, boolean isHor)
+ {
+ if (startsWithLenient(s, "center", 1, false) != -1)
+ return UnitValue.CENTER;
+
+ if (isHor) {
+ if (startsWithLenient(s, "left", 1, false) != -1)
+ return UnitValue.LEFT;
+
+ if (startsWithLenient(s, "right", 1, false) != -1)
+ return UnitValue.RIGHT;
+
+ if (startsWithLenient(s, "leading", 4, false) != -1)
+ return UnitValue.LEADING;
+
+ if (startsWithLenient(s, "trailing", 5, false) != -1)
+ return UnitValue.TRAILING;
+
+ if (startsWithLenient(s, "label", 5, false) != -1)
+ return UnitValue.LABEL;
+
+ } else {
+
+ if (startsWithLenient(s, "baseline", 4, false) != -1)
+ return UnitValue.BASELINE_IDENTITY;
+
+ if (startsWithLenient(s, "top", 1, false) != -1)
+ return UnitValue.TOP;
+
+ if (startsWithLenient(s, "bottom", 1, false) != -1)
+ return UnitValue.BOTTOM;
+ }
+
+ return null;
+ }
+
+ /** Splits a text-number combination such as "hello 10.0" into <code>{"hello", "10.0"}</code>.
+ * @param s The string to split. Not <code>null</code>. Needs be be resonably formatted since the method
+ * only finds the first 0-9 or . and cuts the string in half there.
+ * @return Always length 2 and no <code>null</code> elements. Elements are "" if no part found.
+ */
+ private static String[] getNumTextParts(String s)
+ {
+ for (int i = 0, iSz = s.length(); i < iSz; i++) {
+ char c = s.charAt(i);
+ if (c == ' ')
+ throw new IllegalArgumentException("Space in UnitValue: '" + s + "'");
+
+ if ((c < '0' || c > '9') && c != '.' && c != '-')
+ return new String[] {s.substring(0, i).trim(), s.substring(i).trim()};
+ }
+ return new String[] {s, ""};
+ }
+
+ /** Returns the operation depending on the start character.
+ * @param s The string to check. Not <code>null</code>.
+ * @return E.g. UnitValue.ADD, UnitValue.SUB or UnitValue.STATIC. Returns negative value for in-line operations.
+ */
+ private static int getOper(String s)
+ {
+ int len = s.length();
+ if (len < 3)
+ return UnitValue.STATIC;
+
+ if (len > 5 && s.charAt(3) == '(' && s.charAt(len - 1) == ')') {
+ if (s.startsWith("min("))
+ return UnitValue.MIN;
+
+ if (s.startsWith("max("))
+ return UnitValue.MAX;
+
+ if (s.startsWith("mid("))
+ return UnitValue.MID;
+ }
+
+ // Try in-line add/sub. E.g. "pref+10px".
+ for (int j = 0; j < 2; j++) { // First +- then */ (precedence)
+ for (int i = len - 1, p = 0; i > 0; i--) {
+ char c = s.charAt(i);
+ if (c == ')') {
+ p++;
+ } else if (c == '(') {
+ p--;
+ } else if (p == 0) {
+ if (j == 0) {
+ if (c == '+')
+ return UnitValue.ADD;
+ if (c == '-')
+ return UnitValue.SUB;
+ } else {
+ if (c == '*')
+ return UnitValue.MUL;
+ if (c == '/')
+ return UnitValue.DIV;
+ }
+ }
+ }
+ }
+ return UnitValue.STATIC;
+ }
+
+ /** Returns if a string shares at least a specified numbers starting characters with a number of matches.
+ * <p>
+ * This method just excercises {@link #startsWithLenient(String, String, int, boolean)} with every one of
+ * <code>matches</code> and <code>minChars</code>.
+ * @param s The string to check. Not <code>null</code>.
+ * @param matches A number of possible starts for <code>s</code>.
+ * @param minChars The mimimum number of characters to match for every element in <code>matches</code>. Needs
+ * to be of same length as <code>matches</code>. Can be <code>null</code>.
+ * @param acceptTrailing If after the required number of charecters are matched onrecognized characters that are not
+ * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with
+ * "abcdef" and min chars 3.
+ * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not
+ * found.
+ */
+ private static int startsWithLenient(String s, String[] matches, int[] minChars, boolean acceptTrailing)
+ {
+ for (int i = 0; i < matches.length; i++) {
+ int minChar = minChars != null ? minChars[i] : -1;
+ int ix = startsWithLenient(s, matches[i], minChar, acceptTrailing);
+ if (ix > -1)
+ return ix;
+ }
+ return -1;
+ }
+
+ /** Returns if a string shares at least a specified numbers starting characters with a match.
+ * @param s The string to check. Not <code>null</code> and must be trimmed.
+ * @param match The possible start for <code>s</code>. Not <code>null</code> and must be trimmed.
+ * @param minChars The mimimum number of characters to match to <code>s</code> for it this to be considered a match. -1 means
+ * the full length of <code>match</code>.
+ * @param acceptTrailing If after the required number of charecters are matched unrecognized characters that are not
+ * in one of the the <code>matches</code> string should be accepted. For instance if "abczz" should be matched with
+ * "abcdef" and min chars 3.
+ * @return The index of the first unmatched character if <code>minChars</code> was reached or <code>-1</code> if a match was not
+ * found.
+ */
+ private static int startsWithLenient(String s, String match, int minChars, boolean acceptTrailing)
+ {
+ if (s.charAt(0) != match.charAt(0)) // Fast sanity check.
+ return -1;
+
+ if (minChars == -1)
+ minChars = match.length();
+
+ int sSz = s.length();
+ if (sSz < minChars)
+ return -1;
+
+ int mSz = match.length();
+ int sIx = 0;
+ for (int mIx = 0; mIx < mSz; sIx++, mIx++) {
+ while (sIx < sSz && (s.charAt(sIx) == ' ' || s.charAt(sIx) == '_')) // Disregard spaces and _
+ sIx++;
+
+ if (sIx >= sSz || s.charAt(sIx) != match.charAt(mIx))
+ return mIx >= minChars && (acceptTrailing || sIx >= sSz) && (sIx >= sSz || s.charAt(sIx - 1) == ' ') ? sIx : -1;
+ }
+// return (sIx >= sSz || acceptTrailing) && (sIx >= sSz || s.charAt(sIx) == ' ') ? sIx : -1;
+ return sIx >= sSz || acceptTrailing ||s.charAt(sIx) == ' ' ? sIx : -1;
+ }
+
+ /** Parses a string and returns it in those parts of the string that are separated with a <code>sep</code> character.
+ * <p>
+ * separator characters within parentheses will not be counted or handled in any way, whatever the depth.
+ * @param s The string to parse. If it starts and/or ends with a <code>sep</code> the first and/or last element returned will be "". If
+ * two <code>sep</code> are next to eachother and empty element will be "between" the periods. The <code>sep</code> themselves will never be returned.
+ * @param sep The separator char.
+ * @return Those parts of the string that are separated with <code>sep</code>. Never null and at least of size 1
+ */
+ private final static String[] toTrimmedTokens(String s, char sep)
+ {
+ int toks = 0, sSize = s.length();
+
+ // Count the sep:s
+ int p = 0;
+ for(int i = 0; i < sSize; i++) {
+ char c = s.charAt(i);
+ if (c == '(') {
+ p++;
+ } else if (c == ')') {
+ p--;
+ } else if (p == 0 && c == sep) {
+ toks++;
+ }
+ if (p < 0)
+ throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
+ }
+ if (p != 0)
+ throw new IllegalArgumentException("Unbalanced parentheses: '" + s + "'");
+
+ if (toks == 0)
+ return new String [] {s.trim()};
+
+ String[] retArr = new String[toks + 1];
+
+ int st = 0, pNr = 0;
+ p = 0;
+ for (int i = 0; i < sSize; i++) {
+
+ char c = s.charAt(i);
+ if (c == '(') {
+ p++;
+ } else if (c == ')') {
+ p--;
+ } else if (p == 0 && c == sep) {
+ retArr[pNr++] = s.substring(st, i).trim();
+ st = i + 1;
+ }
+ }
+
+ retArr[pNr++] = s.substring(st, sSize).trim();
+ return retArr;
+ }
+
+ /** Parses "AAA[BBB]CCC[DDD]EEE" into {"AAA", "BBB", "CCC", "DDD", "EEE", "FFF"}. Handles empty parts. Will always start and end outside
+ * a [] block so that the number of returned elemets will always be uneven and at least of length 3.
+ * <p>
+ * "|" is interprated as "][".
+ * @param s The string. Might be "" but not null. Should be trimmed.
+ * @return The string divided into elements. Never <code>null</code> and at least of length 3.
+ * @throws IllegalArgumentException If a [] mismatch of some kind. (If not same [ as ] count or if the interleave.)
+ */
+ private final static ArrayList<String> getRowColAndGapsTrimmed(String s)
+ {
+ if (s.indexOf('|') != -1)
+ s = s.replaceAll("\\|", "][");
+
+ ArrayList<String> retList = new ArrayList<String>(Math.max(s.length() >> 2 + 1, 3)); // Aprox return length.
+ int s0 = 0, s1 = 0; // '[' and ']' count.
+ int st = 0; // Start of "next token to add".
+ for (int i = 0, iSz = s.length(); i < iSz; i++) {
+ char c = s.charAt(i);
+ if (c == '[') {
+ s0++;
+ } else if (c == ']') {
+ s1++;
+ } else {
+ continue;
+ }
+
+ if (s0 != s1 && (s0 - 1) != s1)
+ break; // Wrong [ or ] found. Break for throw.
+
+ retList.add(s.substring(st, i).trim());
+ st = i + 1;
+ }
+ if (s0 != s1)
+ throw new IllegalArgumentException("'[' and ']' mismatch in row/column format string: " + s);
+
+ if (s0 == 0) {
+ retList.add("");
+ retList.add(s);
+ retList.add("");
+ } else if (retList.size() % 2 == 0) {
+ retList.add(s.substring(st, s.length()));
+ }
+
+ return retList;
+ }
+
+ /** Makes <code>null</code> "", trimms and converts to lower case.
+ * @param s The string
+ * @return Not null.
+ */
+ public static final String prepare(String s)
+ {
+ return s != null ? s.trim().toLowerCase() : "";
+ }
+
+// /** Tests to serialize and deserialize the object with both XMLEncoder/Decoder and through Serializable
+// * @param o The object to serialize
+// * @return The same object after a tri through the process.
+// */
+// public static final Object serializeTest(Object o)
+// {
+// try {
+// ByteArrayOutputStream barr = new ByteArrayOutputStream();
+// XMLEncoder enc = new XMLEncoder(barr);
+// enc.writeObject(o);
+// enc.close();
+//
+// XMLDecoder dec = new XMLDecoder(new ByteArrayInputStream(barr.toByteArray()));
+// o = dec.readObject();
+// dec.close();
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
+//
+// try {
+// ByteArrayOutputStream barr = new ByteArrayOutputStream();
+// ObjectOutputStream oos = new ObjectOutputStream(barr);
+// oos.writeObject(o);
+// oos.close();
+//
+// ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
+// o = ois.readObject();
+// ois.close();
+// } catch (Exception e) {
+// e.printStackTrace();
+// }
+//
+// return o;
+// }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java b/prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java
new file mode 100644
index 00000000..65428add
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/ContainerWrapper.java
@@ -0,0 +1,69 @@
+package net.miginfocom.layout;
+/*
+ * 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
+ */
+
+/** A class that wraps a container that contains components.
+ */
+public interface ContainerWrapper extends ComponentWrapper
+{
+ /** Returns the components of the container that wrapper is wrapping.
+ * @return The components of the container that wrapper is wrapping. Never <code>null</code>.
+ */
+ public abstract ComponentWrapper[] getComponents();
+
+ /** Returns the number of components that this parent has.
+ * @return The number of components that this parent has.
+ */
+ public abstract int getComponentCount();
+
+ /** Returns the <code>LayoutHandler</code> (in Swing terms) that is handling the layout of this container.
+ * If there exist no such class the method should return the same as {@link #getComponent()}, which is the
+ * container itself.
+ * @return The layout handler instance. Never <code>null</code>.
+ */
+ public abstract Object getLayout();
+
+ /** Returns if this container is using left-to-right component ordering.
+ * @return If this container is using left-to-right component ordering.
+ */
+ public abstract boolean isLeftToRight();
+
+ /** Paints a cell to indicate where it is.
+ * @param x The x coordinate to start the drwaing.
+ * @param y The x coordinate to start the drwaing.
+ * @param width The width to draw/fill
+ * @param height The height to draw/fill
+ */
+ public abstract void paintDebugCell(int x, int y, int width, int height);
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/DimConstraint.java b/prototypes/miglayout/net/miginfocom/layout/DimConstraint.java
new file mode 100644
index 00000000..47c1021c
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/DimConstraint.java
@@ -0,0 +1,466 @@
+package net.miginfocom.layout;
+
+import java.io.*;
+/*
+ * 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
+ */
+
+/** A simple value holder for a constraint for one dimension.
+ */
+public final class DimConstraint implements Externalizable
+{
+ /** How this entity can be resized in the dimension that this constraint represents.
+ */
+ final ResizeConstraint resize = new ResizeConstraint();
+
+ // Look at the properties' getter/setter methods for exmplanation
+
+ private String sizeGroup = null; // A "context" compared with equals.
+
+ private BoundSize size = null; // Min, pref, max. May be null.
+
+ private BoundSize gapBefore = null, gapAfter = null;
+
+ private UnitValue align = null;
+
+
+ // ************** Only applicable on components! *******************
+
+ private String endGroup = null; // A "context" compared with equals.
+
+
+ // ************** Only applicable on rows/columns! *******************
+
+ private boolean fill = false;
+
+ private boolean noGrid = false;
+
+ /** Empty constructor.
+ */
+ public DimConstraint()
+ {
+ }
+
+ /** Returns the grow priority. Relative priority is used for determining which entities gets the extra space first.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The grow priority.
+ */
+ public int getGrowPriority()
+ {
+ return resize.growPrio;
+ }
+
+ /** Sets the grow priority. Relative priority is used for determining which entities gets the extra space first.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The new grow priority.
+ */
+ public void setGrowPriority(int p)
+ {
+ resize.growPrio = p;
+ }
+
+ /** Returns the grow weight.<p>
+ * Grow weight is how flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or
+ * zero mean it will never grow. An entity that has twise the grow weight compared to another entity will get twice
+ * as much of available space.
+ * <p>
+ * GrowWeight are only compared within the same GrowPrio.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current grow weight.
+ */
+ public Float getGrow()
+ {
+ return resize.grow;
+ }
+
+ /** Sets the grow weight.<p>
+ * Grow weight is how flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or
+ * zero mean it will never grow. An entity that has twise the grow weight compared to another entity will get twice
+ * as much of available space.
+ * <p>
+ * GrowWeight are only compared within the same GrowPrio.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param weight The new grow weight.
+ */
+ public void setGrow(Float weight)
+ {
+ resize.grow = weight;
+ }
+
+ /** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The shrink priority.
+ */
+ public int getShrinkPriority()
+ {
+ return resize.shrinkPrio;
+ }
+
+ /** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param p The new shrink priority.
+ */
+ public void setShrinkPriority(int p)
+ {
+ resize.shrinkPrio = p;
+ }
+
+ /** Returns the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
+ * Shrink weight is how flexilble the entity should be, relative to other entities, when it comes to shrinking. <code>null</code> or
+ * zero mean it will never shrink (default). An entity that has twise the shrink weight compared to another entity will get twice
+ * as much of available space.
+ * <p>
+ * Shrink(Weight) are only compared within the same ShrinkPrio.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current shrink weight.
+ */
+ public Float getShrink()
+ {
+ return resize.shrink;
+ }
+
+ /** Sets the shrink priority. Relative priority is used for determining which entities gets smaller first when space is scarse.
+ * Shrink weight is how flexilble the entity should be, relative to other entities, when it comes to shrinking. <code>null</code> or
+ * zero mean it will never shrink (default). An entity that has twise the shrink weight compared to another entity will get twice
+ * as much of available space.
+ * <p>
+ * Shrink(Weight) are only compared within the same ShrinkPrio.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param weight The new shrink weight.
+ */
+ public void setShrink(Float weight)
+ {
+ resize.shrink = weight;
+ }
+
+ public UnitValue getAlignOrDefault(boolean isCols)
+ {
+ if (align != null)
+ return align;
+
+ return isCols ? UnitValue.LEADING : UnitValue.CENTER;
+ }
+
+ /** Returns the alignment used either as a default value for sub-entities or for this entity.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The alignment.
+ */
+ public UnitValue getAlign()
+ {
+ return align;
+ }
+
+ /** Sets the alignment used wither as a default value for sub-entities or for this entity.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param uv The new shrink priority. E.g. {@link UnitValue#CENTER} or {@link net.miginfocom.layout.UnitValue#LEADING}.
+ */
+ public void setAlign(UnitValue uv)
+ {
+ this.align = uv;
+ }
+
+ /** Returns the gap after this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
+ * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The gap after this entitiy
+ */
+ public BoundSize getGapAfter()
+ {
+ return gapAfter;
+ }
+
+ /** Sets the gap after this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
+ * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The new gap.
+ * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean).
+ */
+ public void setGapAfter(BoundSize size)
+ {
+ this.gapAfter = size;
+ }
+
+ boolean hasGapAfter()
+ {
+ return gapAfter != null && gapAfter.isUnset() == false;
+ }
+
+ boolean isGapAfterPush()
+ {
+ return gapAfter != null && gapAfter.getGapPush();
+ }
+
+ /** Returns the gap before this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
+ * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The gap before this entitiy
+ */
+ public BoundSize getGapBefore()
+ {
+ return gapBefore;
+ }
+
+ /** Sets the gap before this entitiy. The gap is an empty space and can have a min/preferred/maximum size so that it can shrink and
+ * grow depending on available space. Gaps are against other entities' edges and not against other entities' gaps.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The new gap.
+ * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean).
+ */
+ public void setGapBefore(BoundSize size)
+ {
+ this.gapBefore = size;
+ }
+
+ boolean hasGapBefore()
+ {
+ return gapBefore != null && gapBefore.isUnset() == false;
+ }
+
+ boolean isGapBeforePush()
+ {
+ return gapBefore != null && gapBefore.getGapPush();
+ }
+
+ /** Returns the min/prerefferd/max size for the entity in the dimension that this object describes.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current size. May be <code>null</code>.
+ * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean).
+ */
+ public BoundSize getSize()
+ {
+ return size;
+ }
+
+ /** Sets the min/prerefferd/max size for the eintity in the dimension that this object describes.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param size The new size. May be <code>null</code>.
+ */
+ public void setSize(BoundSize size)
+ {
+ this.size = size;
+ }
+
+ /** Returns the size group that this entitiy should be in for the demension that this object is describing.
+ * If this constraint is in a size group that is specified here. <code>null</code> means no size group
+ * and all other values are legal. Comparison with .equals(). Components/columnss/rows in the same size group
+ * will have the same min/preferred/max size; that of the largest in the group for the first two and the
+ * smallest for max.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current size group. May be <code>null</code>.
+ */
+ public String getSizeGroup()
+ {
+ return sizeGroup;
+ }
+
+ /** Sets the size group that this entitiy should be in for the demension that this object is describing.
+ * If this constraint is in a size group that is specified here. <code>null</code> means no size group
+ * and all other values are legal. Comparison with .equals(). Components/columnss/rows in the same size group
+ * will have the same min/preferred/max size; that of the largest in the group for the first two and the
+ * smallest for max.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s The new size group. <code>null</code> disables size grouping.
+ */
+ public void setSizeGroup(String s)
+ {
+ sizeGroup = s;
+ }
+
+ // ************** Only applicable on components ! *******************
+
+ /** Returns the end group that this entitiy should be in for the demension that this object is describing.
+ * If this constraint is in an end group that is specified here. <code>null</code> means no end group
+ * and all other values are legal. Comparison with .equals(). Components in the same end group
+ * will have the same end coordinate.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return The current end group. <code>null</code> may be returned.
+ */
+ public String getEndGroup()
+ {
+ return endGroup;
+ }
+
+ /** Sets the end group that this entitiy should be in for the demension that this object is describing.
+ * If this constraint is in an end group that is specified here. <code>null</code> means no end group
+ * and all other values are legal. Comparison with .equals(). Components in the same end group
+ * will have the same end coordinate.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s The new end group. <code>null</code> disables end grouping.
+ */
+ public void setEndGroup(String s)
+ {
+ endGroup = s;
+ }
+
+ // ************** Not applicable on components below ! *******************
+
+ /** Returns if the component in the row/column that this constraint should default be grown in the same dimension that
+ * this constraint represents (width for column and height for a row).
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return code>true</code> means that components should grow.
+ */
+ public boolean isFill()
+ {
+ return fill;
+ }
+
+ /** Sets if the component in the row/column that this constraint should default be grown in the same dimension that
+ * this constraint represents (width for column and height for a row).
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>true</code> means that components should grow.
+ */
+ public void setFill(boolean b)
+ {
+ fill = b;
+ }
+
+ /** Returns if the row/column should default to flow and not to grid behaviour. This means that the whole row/column
+ * will be one cell and all components will end up in that cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>true</code> means that the whole row/column should be one cell.
+ */
+ public boolean isNoGrid()
+ {
+ return noGrid;
+ }
+
+ /** Sets if the row/column should default to flow and not to grid behaviour. This means that the whole row/column
+ * will be one cell and all components will end up in that cell.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>true</code> means that the whole row/column should be one cell.
+ */
+ public void setNoGrid(boolean b)
+ {
+ this.noGrid = b;
+ }
+
+ /** Returns the gaps as pixel values.
+ * @param parent The parent. Used to get the pixel values.
+ * @param defGap The default gap to use if there is no gap set on this object (i.e. it is null).
+ * @param refSize The reference size used to get the pixel sizes.
+ * @param before IF it is the gap before rather than the gap after to return.
+ * @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET}
+ * for gap sizes that are <code>null</code>. Returns <code>null</code> if there was no gap specified. A new and free to use array.
+ */
+ int[] getRowGaps(ContainerWrapper parent, BoundSize defGap, int refSize, boolean before)
+ {
+ BoundSize gap = before ? gapBefore : gapAfter;
+ if (gap == null || gap.isUnset())
+ gap = defGap;
+
+ if (gap == null || gap.isUnset())
+ return null;
+
+ int[] ret = new int[3];
+ for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
+ UnitValue uv = gap.getSize(i);
+ ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET;
+ }
+ return ret;
+ }
+
+ /** Returns the gaps as pixel values.
+ * @param parent The parent. Used to get the pixel values.
+ * @param comp The component that the gap is for. If not for a component it is <code>null</code>.
+ * @param adjGap The gap that the adjacent component, if any, has towards <code>comp</code>.
+ * @param adjacentComp The adjacent component if any. May be <code>null</code>.
+ * @param refSize The reference size used to get the pixel sizes.
+ * @param adjacentSide Whan side the <code>adjacentComp</code> is on. 0 = top, 1 = left, 2 = bottom, 3 = right.
+ * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>.
+ * @param isLTR If it is left-to-right.
+ * @return The [min,preferred,max] sizes for the specified gap. Uses {@link net.miginfocom.layout.LayoutUtil#NOT_SET}
+ * for gap sizes that are <code>null</code>. Returns <code>null</code> if there was no gap specified. A new and free to use array.
+ */
+ int[] getComponentGaps(ContainerWrapper parent, ComponentWrapper comp, BoundSize adjGap, ComponentWrapper adjacentComp, String tag, int refSize, int adjacentSide, boolean isLTR)
+ {
+ BoundSize gap = adjacentSide < 2 ? gapBefore : gapAfter;
+
+ boolean hasGap = gap != null && gap.getGapPush();
+ if ((gap == null || gap.isUnset()) && (adjGap == null || adjGap.isUnset()) && comp != null)
+ gap = PlatformDefaults.getDefaultComponentGap(comp, adjacentComp, adjacentSide + 1, tag, isLTR);
+
+ if (gap == null)
+ return hasGap ? new int[] {0, 0, LayoutUtil.NOT_SET} : null;
+
+ int[] ret = new int[3];
+ for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
+ UnitValue uv = gap.getSize(i);
+ ret[i] = uv != null ? uv.getPixels(refSize, parent, null) : LayoutUtil.NOT_SET;
+ }
+ return ret;
+ }
+
+ // ************************************************
+ // 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() == DimConstraint.class)
+ LayoutUtil.writeAsXML(out, this);
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/Grid.java b/prototypes/miglayout/net/miginfocom/layout/Grid.java
new file mode 100644
index 00000000..c45ce398
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/Grid.java
@@ -0,0 +1,2245 @@
+package net.miginfocom.layout;
+
+
+import java.util.*;
+/*
+ * 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
+ */
+
+/** Holds components in a grid. Does most of the logic behind the layout manager.
+ */
+public final class Grid
+{
+ public static final boolean TEST_GAPS = true;
+
+ private static final Float[] GROW_100 = new Float[] {ResizeConstraint.WEIGHT_100};
+
+ private static final DimConstraint DOCK_DIM_CONSTRAINT = new DimConstraint();
+ static {
+ DOCK_DIM_CONSTRAINT.setGrowPriority(0);
+ }
+
+ /** This is the maximum grid position for "normal" components. Docking components use the space out to
+ * <code>MAX_DOCK_GRID</code> and below 0.
+ */
+ private static final int MAX_GRID = 30000;
+
+ /** Docking components will use the grid coordinates <code>-MAX_DOCK_GRID -> 0</code> and <code>MAX_GRID -> MAX_DOCK_GRID</code>.
+ */
+ private static final int MAX_DOCK_GRID = 32767;
+
+ /** A constraint used for gaps.
+ */
+ private static final ResizeConstraint GAP_RC_CONST = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, null);
+ private static final ResizeConstraint GAP_RC_CONST_PUSH = new ResizeConstraint(200, ResizeConstraint.WEIGHT_100, 50, ResizeConstraint.WEIGHT_100);
+
+ /** The constraints. Never <code>null</code>.
+ */
+ private final LC lc;
+
+ /** The parent that is layout out and this grid is done for. Never <code>null</code>.
+ */
+ private final ContainerWrapper container;
+
+ /** An x, y array implemented as a sparse array to accomodate for any grid size without wasting memory (or rather 15 bit (0-MAX_GRID * 0-MAX_GRID).
+ */
+ private final LinkedHashMap<Integer, Cell> grid = new LinkedHashMap<Integer, Cell>(); // [(y << 16) + x] -> Cell. null key for absolute positioned compwraps
+
+ private HashMap<Integer, BoundSize> wrapGapMap = null; // Row or Column index depending in the dimension that "raps". Normally row indexes but may be column indexes if "flowy". 0 means before first row/col.
+
+ /** The size of the grid. Row count and column count.
+ */
+ private final TreeSet<Integer> rowIndexes = new TreeSet<Integer>(), colIndexes = new TreeSet<Integer>();
+
+ /** The row and column specifications.
+ */
+ private final AC rowConstr, colConstr;
+
+ /** The in the constructor calculated min/pref/max sizes of the rows and columns.
+ */
+ private FlowSizeSpec colFlowSpecs = null, rowFlowSpecs = null;
+
+ /** Components that are connectione in one dimension (such as baseline alignment for instance) are grouped together and stored here.
+ * One for each row/column.
+ */
+ private ArrayList<LinkedDimGroup>[] colGroupLists, rowGroupLists; //[(start)row/col number]
+
+ /** The in the constructor calculated min/pref/max size of the whole grid.
+ */
+ private int[] width = null, height = null;
+
+ /** If debug is on contains the bounds for things to paint when calling {@link ContainerWrapper#paintDebugCell(int, int, int, int)}
+ */
+ private ArrayList<int[]> debugRects = null; // [x, y, width, height]
+
+ /** If any of the absolute coordinates for component bounds has links the name of the target is in this Set.
+ * Since it requires some memory and computations this is checked at the creation so that
+ * the link information is only created if needed later.
+ * <p>
+ * The boolean is true for groups id:s and null for normal id:s.
+ */
+ private HashMap<String, Boolean> linkTargetIDs = null;
+
+ private final int dockOffY, dockOffX;
+
+ private final Float[] growXs, growYs;
+
+ private final ArrayList<LayoutCallback> callbackList;
+
+ /** Constructor.
+ * @param container The container that will be laid out.
+ * @param lc The form flow constraints.
+ * @param rowConstr The rows specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
+ * @param colConstr The columns specifications. If more cell rows are required, the last element will be used for when there is no corresponding element in this array.
+ * @param fcMap The map containing the parsed constraints for each child component of <code>parent</code>. Will not be alterted.
+ * @param callbackList A list of callbacks or <code>null</code> if none. Will not be alterted.
+ */
+ public Grid(ContainerWrapper container, LC lc, AC rowConstr, AC colConstr, Map<ComponentWrapper, CC> fcMap, ArrayList<LayoutCallback> callbackList)
+ {
+ this.lc = lc;
+ this.rowConstr = rowConstr;
+ this.colConstr = colConstr;
+ this.container = container;
+ this.callbackList = callbackList;
+
+ int wrap = lc.getWrapAfter() != 0 ? lc.getWrapAfter() : (lc.isFlowX() ? colConstr : rowConstr).getConstaints().length;
+
+ final ComponentWrapper[] comps = container.getComponents();
+
+ boolean hasTagged = false; // So we do not have to sort if it will not do any good
+ boolean hasPushX = false, hasPushY = false;
+ final int[] p = new int[2];
+ final ArrayList<int[]> spannedRects = new ArrayList<int[]>(2);
+
+ final DimConstraint[] specs = (lc.isFlowX() ? rowConstr : colConstr).getConstaints();
+
+ int sizeGroupsX = 0, sizeGroupsY = 0;
+ int[] dockInsets = null; // top, left, bottom, right insets for docks.
+
+ LinkHandler.clearTemporaryBounds(container.getLayout());
+
+ for (int i = 0; i < comps.length;) {
+ ComponentWrapper comp = comps[i];
+ CC rootCc = fcMap.get(comp);
+
+ int hideMode = comp.isVisible() ? -1 : rootCc.getHideMode() != -1 ? rootCc.getHideMode() : lc.getHideMode();
+
+ if (rootCc == null || hideMode == 3) { // To work with situations where there are components that does not have a layout manager, or not this one.
+ if (rootCc != null)
+ setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
+ i++;
+ continue; // The "external" component should not be handled further.
+ }
+
+ if (rootCc.getHorizontal().getSizeGroup() != null)
+ sizeGroupsX++;
+ if (rootCc.getVertical().getSizeGroup() != null)
+ sizeGroupsY++;
+
+ // Special treatment of absolute positioned components.
+ UnitValue[] pos = getPos(comp, rootCc);
+ BoundSize[] cbSz = getCallbackSize(comp, rootCc);
+ if (pos != null || rootCc.isExternal()) {
+
+ // Check if link information should be saved later.
+ if (pos != null) {
+ for (int l = 0; l < pos.length; l++) {
+ UnitValue u = pos[l];
+ if (u != null && u.isLinkedDeep())
+ addLinkTargetIDs(u);
+ }
+ }
+
+ CompWrap cw = new CompWrap(comp, rootCc, hideMode, pos, cbSz);
+ Cell cell = grid.get(null);
+ if (cell == null) {
+ grid.put(null, new Cell(cw));
+ } else {
+ cell.compWraps.add(cw);
+ }
+
+ if (rootCc.isBoundsInGrid() == false || rootCc.isExternal()) {
+ setLinkedBounds(comp, rootCc, comp.getX(), comp.getY(), comp.getWidth(), comp.getHeight(), rootCc.isExternal());
+ i++;
+ continue;
+ }
+ }
+
+ if (rootCc.getDockSide() != -1) {
+ if (dockInsets == null)
+ dockInsets = new int[] {-MAX_DOCK_GRID, -MAX_DOCK_GRID, MAX_DOCK_GRID, MAX_DOCK_GRID};
+
+ addDockingCell(dockInsets, rootCc.getDockSide(), new CompWrap(comp, rootCc, hideMode, pos, cbSz));
+ i++;
+ continue;
+ }
+
+ Boolean cellFlowX = rootCc.getFlowX();
+ Cell cell = null;
+
+ if (rootCc.isNewline())
+ wrap(p, rootCc.getNewlineGapSize(), true);
+
+ increase(p, rootCc.getSkip()); // Probably 0 advance...
+
+ boolean rowNoGrid = lc.isNoGrid() || ((DimConstraint) LayoutUtil.getIndexSafe(specs, lc.isFlowX() ? p[1] : p[0])).isNoGrid();
+
+ // Move to a free y, x if no absolute grid specified
+ int cx = rootCc.getCellX();
+ int cy = rootCc.getCellY();
+ if ((cx < 0 || cy < 0) && rowNoGrid == false) {
+ while (isCellFree(p[1], p[0], spannedRects) == false) {
+ if (Math.abs(increase(p, 1)) >= wrap)
+ wrap(p, null, true);
+ }
+ } else {
+ if (cx >= 0 && cy >= 0) {
+ if (cy >= 0) {
+ p[0] = cx;
+ p[1] = cy;
+ } else { // Only one coordinate is specified. Use the current row (flowx) or column (flowy) to fill in.
+ if (lc.isFlowX()) {
+ p[0] = cx;
+ } else {
+ p[1] = cx;
+ }
+ }
+ }
+ cell = getCell(p[1], p[0]); // Might be null
+ }
+
+ // If cell is not created yet, create it and set it.
+ if (cell == null) {
+ int spanx = Math.min(rowNoGrid && lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanX(), MAX_GRID - p[0]);
+ int spany = Math.min(rowNoGrid && !lc.isFlowX() ? LayoutUtil.INF : rootCc.getSpanY(), MAX_GRID - p[1]);
+
+ cell = new Cell(spanx, spany, cellFlowX != null ? cellFlowX.booleanValue() : lc.isFlowX());
+
+ setCell(p[1], p[0], cell);
+
+ // Add a rectangle so we can know that spanned cells occupy more space.
+ if (spanx > 1 || spany > 1)
+ spannedRects.add(new int[] {p[0], p[1], spanx, spany});
+ }
+
+ // Add the one, or all, components that split the grid position to the same Cell.
+ boolean forceWrap = false;
+ BoundSize wrapGap = null;
+ int splitLeft = rowNoGrid ? LayoutUtil.INF : rootCc.getSplit() - 1;
+ boolean splitExit = false;
+ for (; splitLeft >= 0 && forceWrap == false && i < comps.length; splitLeft--) {
+ ComponentWrapper compAdd = comps[i];
+ CC cc = fcMap.get(compAdd); // Can not be null.
+
+ hideMode = compAdd.isVisible() ? -1 : cc.getHideMode() != -1 ? cc.getHideMode() : lc.getHideMode();
+
+ if (cc == null || cc.isExternal() || hideMode == 3) {
+ i++;
+ continue; // To work with situations where there are components that does not have a layout manager, or not this one.
+ }
+
+ hasPushX |= (cc.getPushX() != null);
+ hasPushY |= (cc.getPushY() != null);
+
+ if (cc != rootCc) { // If not first in a cell
+ if (cc.isNewline() || cc.isBoundsInGrid() == false)
+ break;
+
+ if (splitLeft > 0 && cc.getSkip() > 0) {
+ splitExit = true;
+ break;
+ }
+
+ pos = getPos(compAdd, cc);
+ cbSz = getCallbackSize(compAdd, cc);
+ }
+
+ CompWrap cw = new CompWrap(compAdd, cc, hideMode, pos, cbSz);
+ cell.compWraps.add(cw);
+ cell.hasTagged |= cc.getTag() != null;
+ hasTagged |= cell.hasTagged;
+
+ if (cc != rootCc) {
+ if (cc.getHorizontal().getSizeGroup() != null)
+ sizeGroupsX++;
+ if (cc.getVertical().getSizeGroup() != null)
+ sizeGroupsY++;
+ }
+
+ int flowSpan = lc.isFlowX() ? rootCc.getSpanX() : rootCc.getSpanY();
+ forceWrap = (cc.isWrap() || (flowSpan == LayoutUtil.INF && splitLeft == 0));
+ wrapGap = cc.getWrapGapSize();
+ i++;
+ }
+
+ if (forceWrap) {
+ wrap(p, wrapGap, true);
+ } else if (rowNoGrid == false) {
+ int span = lc.isFlowX() ? cell.spanx : cell.spany;
+ if (Math.abs((lc.isFlowX() ? p[0] : p[1])) + span >= wrap) {
+ wrap(p, null, true);
+ } else {
+ int adv = lc.isFlowX() ? cell.spanx : cell.spany;
+ if (splitExit)
+ adv--;
+ increase(p, adv);
+ }
+ }
+ }
+
+ // If there were size groups, calculate the largest values in the groups (for min/pref/max) and enforce them on the rest in the group.
+ if (sizeGroupsX > 0 || sizeGroupsY > 0) {
+ HashMap<String, int[]> sizeGroupMapX = sizeGroupsX > 0 ? new HashMap<String, int[]>(sizeGroupsX) : null;
+ HashMap<String, int[]> sizeGroupMapY = sizeGroupsY > 0 ? new HashMap<String, int[]>(sizeGroupsY) : null;
+ ArrayList<CompWrap> sizeGroupCWs = new ArrayList<CompWrap>(Math.max(sizeGroupsX, sizeGroupsY));
+
+ for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
+ Cell cell = it.next();
+ for (int i = 0; i < cell.compWraps.size(); i++) {
+ CompWrap cw = cell.compWraps.get(i);
+
+ if (cw.cc.getHorizontal().getSizeGroup() != null || cw.cc.getVertical().getSizeGroup() != null) {
+ addToSizeGroup(sizeGroupMapX, cw.cc.getHorizontal().getSizeGroup(), cw.horSizes);
+ addToSizeGroup(sizeGroupMapY, cw.cc.getVertical().getSizeGroup(), cw.verSizes);
+ sizeGroupCWs.add(cw);
+ }
+ }
+ }
+
+ // Set/equalize the sizeGroups to same the values.
+ if (sizeGroupCWs != null) {
+ for (int i = 0; i < sizeGroupCWs.size(); i++) {
+ CompWrap cw = sizeGroupCWs.get(i);
+ if (sizeGroupMapX != null)
+ cw.setSizes(sizeGroupMapX.get(cw.cc.getHorizontal().getSizeGroup()), true); // Target method handles null sizes
+ if (sizeGroupMapY != null)
+ cw.setSizes(sizeGroupMapY.get(cw.cc.getVertical().getSizeGroup()), false); // Target method handles null sizes
+ }
+ }
+ }
+
+ if (hasTagged)
+ sortCellsByPlatform(grid.values(), container);
+
+ // Calculate gaps now that the cells are filled and we know all adjacent components.
+ boolean ltr = LayoutUtil.isLeftToRight(lc, container);
+ for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
+ Cell cell = it.next();
+ ArrayList<CompWrap> cws = cell.compWraps;
+
+ for (int i = 0, lastI = cws.size() - 1; i <= lastI; i++) {
+ CompWrap cw = cws.get(i);
+ ComponentWrapper cwBef = i > 0 ? cws.get(i - 1).comp : null;
+ ComponentWrapper cwAft = i < lastI ? cws.get(i + 1).comp : null;
+
+ String tag = fcMap.get(cw.comp).getTag();
+ CC ccBef = cwBef != null ? fcMap.get(cwBef) : null;
+ CC ccAft = cwAft != null ? fcMap.get(cwAft) : null;
+
+ cw.calcGaps(cwBef, ccBef, cwAft, ccAft, tag, cell.flowx, ltr);
+ }
+ }
+
+ dockOffX = getDockInsets(colIndexes);
+ dockOffY = getDockInsets(rowIndexes);
+
+ // Add synthetic indexes for empty rows and columns so they can get a size
+ for (int i = 0, iSz = rowConstr.getCount(); i < iSz; i++)
+ rowIndexes.add(new Integer(i));
+ for (int i = 0, iSz = colConstr.getCount(); i < iSz; i++)
+ colIndexes.add(new Integer(i));
+
+ colGroupLists = divideIntoLinkedGroups(false);
+ rowGroupLists = divideIntoLinkedGroups(true);
+
+ growXs = getDefaultGrowWeights(hasPushX, false);
+ growYs = getDefaultGrowWeights(hasPushY, true);
+
+ }
+
+ /** If the container (parent) that this grid is laying out has changed its bounds, call this method to
+ * clear any cached values.
+ */
+ public void invalidateContainerSize()
+ {
+ colFlowSpecs = null;
+ }
+
+ /** Does the actual layout. Uses many values calculated in the constructor.
+ * @param bounds The bounds to layout against. Normally that of the parent. [x, y, width, height].
+ * @param alignX The alignment for the x-axis.
+ * @param alignY The alignment for the y-axis.
+ * @param debug If debug information should be saved in {@link #debugRects}.
+ * @param checkPrefChange If a check should be done to see if the setting of any new bounds changes the preferred size
+ * of a component. This is normally only turned on for SWT as SWT has a notion of width vs height calculation.
+ * @return If the layout has probably change the preferred size and there is need for a new layout (normally only SWT).
+ */
+ public boolean layout(int[] bounds, UnitValue alignX, UnitValue alignY, boolean debug, boolean checkPrefChange)
+ {
+ if (debug)
+ debugRects = new ArrayList<int[]>();
+
+ checkSizeCalcs();
+
+ resetLinkValues(true);
+
+ layoutInOneDim(bounds[2], alignX, false, growXs);
+ layoutInOneDim(bounds[3], alignY, true, growYs);
+
+ HashMap<String, Integer> endGrpXMap = null, endGrpYMap = null;
+ int compCount = container.getComponentCount();
+
+ // Transfer the calculated bound from the ComponentWrappers to the actual Components.
+ boolean layoutAgain = false;
+ if (compCount > 0) {
+ for (int j = 0; j < (linkTargetIDs != null ? 2 : 1); j++) { // First do the calculations (maybe more than once) then set the bounds when done
+ boolean doAgain;
+ int count = 0;
+ do {
+ doAgain = false;
+ for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
+ ArrayList<CompWrap> compWraps = it.next().compWraps;
+ for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
+ CompWrap cw = compWraps.get(i);
+
+ if (j == 0) {
+ doAgain |= doAbsoluteCorrections(cw, bounds);
+ if (doAgain == false) { // If we are going to do this again, do not bother this time around
+ if (cw.cc.getHorizontal().getEndGroup() != null)
+ endGrpXMap = addToEndGroup(endGrpXMap, cw.cc.getHorizontal().getEndGroup(), cw.x + cw.w);
+ if (cw.cc.getVertical().getEndGroup() != null)
+ endGrpYMap = addToEndGroup(endGrpYMap, cw.cc.getVertical().getEndGroup(), cw.y + cw.h);
+ }
+ }
+
+ if (linkTargetIDs == null || j == 1) {
+ if (cw.cc.getHorizontal().getEndGroup() != null)
+ cw.w = endGrpXMap.get(cw.cc.getHorizontal().getEndGroup()).intValue() - cw.x;
+ if (cw.cc.getVertical().getEndGroup() != null)
+ cw.h = endGrpYMap.get(cw.cc.getVertical().getEndGroup()).intValue() - cw.y;
+
+ cw.x += bounds[0];
+ cw.y += bounds[1];
+ layoutAgain = cw.transferBounds(checkPrefChange && !layoutAgain);
+
+ if (callbackList != null) {
+ for (int cb = 0; cb < callbackList.size(); cb++)
+ callbackList.get(cb).correctBounds(cw.comp);
+ }
+ }
+ }
+ }
+ clearGroupLinkBounds();
+ if (++count > ((compCount << 3) + 10)) {
+ System.err.println("Unstable Cyclic Dependency in absolute-linked values!");
+ break;
+ }
+
+ } while (doAgain);
+ }
+ }
+
+ // Add debug shapes for the "cells". Use the CompWraps as base for inding the cells.
+ if (debug) {
+ Collection<Cell> cwColl = grid.values();
+ for (Iterator<Cell> it = cwColl.iterator(); it.hasNext();) {
+ ArrayList<CompWrap> compWraps = it.next().compWraps;
+ for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
+ CompWrap cw = compWraps.get(i);
+ LinkedDimGroup hGrp = getGroupContaining(colGroupLists, cw);
+ LinkedDimGroup vGrp = getGroupContaining(rowGroupLists, cw);
+
+ if (hGrp != null && vGrp != null)
+ debugRects.add(new int[] {hGrp.lStart + bounds[0] - (hGrp.fromEnd ? hGrp.lSize : 0), vGrp.lStart + bounds[1] - (vGrp.fromEnd ? vGrp.lSize : 0), hGrp.lSize, vGrp.lSize});
+ }
+ }
+ }
+ return layoutAgain;
+ }
+
+ public void paintDebug()
+ {
+ if (debugRects != null) {
+ container.paintDebugOutline();
+
+ ArrayList<int[]> painted = new ArrayList<int[]>();
+ for (int i = 0, iSz = debugRects.size(); i < iSz; i++) {
+ int[] r = debugRects.get(i);
+ if (painted.contains(r) == false) {
+ container.paintDebugCell(r[0], r[1], r[2], r[3]);
+ painted.add(r);
+ }
+ }
+
+ for (Iterator<Cell> it = grid.values().iterator(); it.hasNext();) {
+ ArrayList<CompWrap> compWraps = it.next().compWraps;
+ for (int i = 0, iSz = compWraps.size(); i < iSz; i++)
+ compWraps.get(i).comp.paintDebugOutline();
+ }
+ }
+ }
+
+ public final int[] getWidth()
+ {
+ checkSizeCalcs();
+ return width;
+ }
+
+ public final int[] getHeight()
+ {
+ checkSizeCalcs();
+ return height;
+ }
+
+ private void checkSizeCalcs()
+ {
+ if (colFlowSpecs == null) {
+ colFlowSpecs = calcRowsOrColsSizes(colGroupLists, growXs, container.getWidth(), true);
+ rowFlowSpecs = calcRowsOrColsSizes(rowGroupLists, growYs, container.getHeight(), false);
+
+ width = getMinPrefMaxSumSize(colFlowSpecs.sizes);
+ height = getMinPrefMaxSumSize(rowFlowSpecs.sizes);
+
+ resetLinkValues(false);
+
+ adjustSizeForAbsolute(width, true);
+ adjustSizeForAbsolute(height, false);
+ }
+ }
+
+ private final UnitValue[] getPos(ComponentWrapper cw, CC cc)
+ {
+ UnitValue[] cbPos = null;
+ if (callbackList != null) {
+ for (int i = 0; i < callbackList.size() && cbPos == null; i++)
+ cbPos = callbackList.get(i).getPosition(cw); // NOT a copy!
+ }
+
+ // If one is null, return the other (which many also be null)
+ UnitValue[] ccPos = cc.getPos(); // A copy!!
+ if (cbPos == null || ccPos == null)
+ return cbPos != null ? cbPos : ccPos;
+
+ // Merge
+ for (int i = 0; i < 4; i++) {
+ UnitValue cbUv = cbPos[i];
+ if (cbUv != null)
+ ccPos[i] = cbUv;
+ }
+
+ return ccPos;
+ }
+ private final BoundSize[] getCallbackSize(ComponentWrapper cw, CC cc)
+ {
+ if (callbackList != null) {
+ for (int i = 0; i < callbackList.size(); i++) {
+ BoundSize[] bs = callbackList.get(i).getSize(cw); // NOT a copy!
+ if (bs != null)
+ return bs;
+ }
+ }
+ return null;
+ }
+
+ private final int getDockInsets(TreeSet<Integer> set)
+ {
+ int c = 0;
+ for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
+ if (it.next().intValue() < -MAX_GRID) {
+ c++;
+ } else {
+ break; // Since they are sorted we can break
+ }
+ }
+ return c;
+ }
+
+ /**
+ * @param cw Never <code>null</code>.
+ * @param fc Never <code>null</code>.
+ * @param external The bounds should be stored even if they are not in {@link #linkTargetIDs}.
+ * @return IF a change has been done.
+ */
+ private boolean setLinkedBounds(ComponentWrapper cw, CC fc, int x, int y, int w, int h, boolean external)
+ {
+ String id = fc.getId() != null ? fc.getId() : cw.getLinkId();
+ if (id == null)
+ return false;
+
+ String gid = null;
+ int grIx = id.indexOf('.');
+ if (grIx != -1 ) {
+ gid = id.substring(0, grIx);
+ id = id.substring(grIx + 1);
+ }
+
+ Object lay = container.getLayout();
+ boolean changed = false;
+ if (external || (linkTargetIDs != null && linkTargetIDs.containsKey(id)))
+ changed = LinkHandler.setBounds(lay, id, x, y, w, h, !external, false);
+
+ if (gid != null && (external || (linkTargetIDs != null && linkTargetIDs.containsKey(gid)))) {
+ if (linkTargetIDs == null)
+ linkTargetIDs = new HashMap<String, Boolean>(4);
+
+ linkTargetIDs.put(gid, Boolean.TRUE);
+ changed |= LinkHandler.setBounds(lay, gid, x, y, w, h, !external, true);
+ }
+
+ return changed;
+ }
+
+ private void addLinkTargetIDs(UnitValue uv)
+ {
+ if (uv.isLinked()) {
+ if (linkTargetIDs == null)
+ linkTargetIDs = new HashMap<String, Boolean>(4);
+
+ linkTargetIDs.put(uv.getLinkTargetId(), null);
+ } else {
+ for (int i = uv.getSubUnitCount() - 1; i >= 0; i--) {
+ UnitValue subUv = uv.getSubUnitValue(i);
+ if (subUv.isLinkedDeep())
+ addLinkTargetIDs(subUv);
+ }
+ }
+ }
+
+ /** Go to next cell.
+ * @param p The point to increase
+ * @param cnt How many cells to advance.
+ * @return The new value in the "incresing" dimension.
+ */
+ private final int increase(int[] p, int cnt)
+ {
+ return lc.isFlowX() ? (p[0] += cnt) : (p[1] += cnt);
+ }
+
+ /** Wraps to the next row or column depending on if horizontal flow or vertical flow is used.
+ * @param p The point to wrap and thus set either x or y to 0 and increase the other one.
+ * @param gapSize The gaps size specified in a "wrap XXX" or "newline XXX" or <code>null</code> if none.
+ * @param isWrap If gapSize is from a "wrap" (true) or "newline" (false).
+ */
+ private final void wrap(int[] p, BoundSize gapSize, boolean isWrap)
+ {
+ boolean flowx = lc.isFlowX();
+ p[0] = flowx ? 0 : p[0] + 1;
+ p[1] = flowx ? p[1] + 1 : 0;
+
+ if (gapSize != null) {
+ if (wrapGapMap == null)
+ wrapGapMap = new HashMap<Integer, BoundSize>(8);
+ int ix = p[flowx ? 1 : 0];
+ if (isWrap == false)
+ ix--; // newline. Use index before increment.
+ wrapGapMap.put(new Integer(ix), gapSize);
+
+ // add the row/column so that the gap in the last row/col will not be removed.
+ if (flowx) {
+ rowIndexes.add(new Integer(p[1]));
+ } else {
+ colIndexes.add(new Integer(p[0]));
+ }
+ }
+ }
+
+ /** Sort components (normally buttons in a button bar) so they appear in the correct order.
+ * @param cells The cells to sort.
+ * @param parent The parent.
+ */
+ private static void sortCellsByPlatform(Collection<Cell> cells, ContainerWrapper parent)
+ {
+ String order = PlatformDefaults.getButtonOrder();
+ String orderLo = order.toLowerCase();
+
+ int unrelSize = PlatformDefaults.convertToPixels(1, "u", true, 0, parent, null);
+
+ if (unrelSize == UnitConverter.UNABLE)
+ throw new IllegalArgumentException("'unrelated' not recognized by PlatformDefaults!");
+
+ int[] gapUnrel = new int[] {unrelSize, unrelSize, LayoutUtil.NOT_SET};
+ int[] flGap = new int[] {0, 0, LayoutUtil.NOT_SET};
+
+ for (Iterator<Cell> it = cells.iterator(); it.hasNext();) {
+ Cell cell = it.next();
+ if (cell.hasTagged == false)
+ continue;
+
+ CompWrap prevCW = null;
+ boolean nextUnrel = false;
+ boolean nextPush = false;
+ ArrayList<CompWrap> sortedList = new ArrayList<CompWrap>(cell.compWraps.size());
+
+ for (int i = 0, iSz = orderLo.length(); i < iSz; i++) {
+ char c = orderLo.charAt(i);
+ if (c == '+' || c == '_') {
+ nextUnrel = true;
+ if (c == '+')
+ nextPush = true;
+ } else {
+ String tag = PlatformDefaults.getTagForChar(c);
+ if (tag != null) {
+ for (int j = 0, jSz = cell.compWraps.size(); j < jSz; j++) {
+ CompWrap cw = cell.compWraps.get(j);
+ if (tag.equals(cw.cc.getTag())) {
+ if (Character.isUpperCase(order.charAt(i))) {
+ int min = PlatformDefaults.getMinimumButtonWidth().getPixels(0, parent, cw.comp);
+ if (min > cw.horSizes[LayoutUtil.MIN])
+ cw.horSizes[LayoutUtil.MIN] = min;
+
+ correctMinMax(cw.horSizes);
+ }
+
+ sortedList.add(cw);
+
+ if (nextUnrel) {
+ (prevCW != null ? prevCW : cw).mergeGapSizes(gapUnrel, cell.flowx, prevCW == null);
+ if (nextPush) {
+ cw.forcedPushGaps = 1;
+ nextUnrel = false;
+ nextPush = false;
+ }
+ }
+
+ // "unknown" components will always get an Unrelated gap.
+ if (c == 'u')
+ nextUnrel = true;
+ prevCW = cw;
+ }
+ }
+ }
+ }
+ }
+
+ // If we have a gap that was supposed to push but no more components was found to but the "gap before" then compensate.
+ if (sortedList.size() > 0) {
+ CompWrap cw = sortedList.get(sortedList.size() - 1);
+ if (nextUnrel) {
+ cw.mergeGapSizes(gapUnrel, cell.flowx, false);
+ if (nextPush)
+ cw.forcedPushGaps |= 2;
+ }
+
+ // Remove first and last gap if not set explicitly.
+ if (cw.cc.getHorizontal().getGapAfter() == null)
+ cw.setGaps(flGap, 3);
+
+ cw = sortedList.get(0);
+ if (cw.cc.getHorizontal().getGapBefore() == null)
+ cw.setGaps(flGap, 1);
+ }
+
+ // Exchange the unsorted CompWraps for the sorted one.
+ if (cell.compWraps.size() == sortedList.size()) {
+ cell.compWraps.clear();
+ } else {
+ cell.compWraps.removeAll(sortedList);
+ }
+ cell.compWraps.addAll(sortedList);
+ }
+ }
+
+ private Float[] getDefaultGrowWeights(boolean hasPush, boolean isRows)
+ {
+ if (hasPush == false && (isRows ? lc.isFillY() : lc.isFillX()) == false)
+ return null;
+
+ ArrayList<LinkedDimGroup>[] groupLists = isRows ? rowGroupLists : colGroupLists;
+
+ Float[] gwArr = GROW_100; // Only create specific if any of the components have grow.
+ for (int i = 0, ix = 1; i < groupLists.length; i++, ix += 2) {
+ ArrayList<LinkedDimGroup> grps = groupLists[i];
+ Float rowGw = null;
+ for (int j = 0; j < grps.size(); j++) {
+ LinkedDimGroup grp = grps.get(j);
+
+ for (int c = 0; c < grp._compWraps.size(); c++) {
+ CompWrap cw = grp._compWraps.get(c);
+ Float gw = hasPush ? (isRows ? cw.cc.getPushY() : cw.cc.getPushX()) : (isRows ? cw.cc.getVertical() : cw.cc.getHorizontal()).getGrow();
+ if (rowGw == null || (gw != null && gw.floatValue() > rowGw.floatValue()))
+ rowGw = gw;
+ }
+ }
+
+ if (rowGw != null) {
+ if (gwArr == GROW_100)
+ gwArr = new Float[(groupLists.length << 1) + 1];
+ gwArr[ix] = rowGw;
+ }
+ }
+
+ return gwArr;
+ }
+
+ private void clearGroupLinkBounds()
+ {
+ if (linkTargetIDs == null)
+ return;
+
+ for (Iterator<Map.Entry<String,Boolean>> it = linkTargetIDs.entrySet().iterator(); it.hasNext();) {
+ Map.Entry<String, Boolean> o = it.next();
+ if (o.getValue() == Boolean.TRUE)
+ LinkHandler.clearBounds(container.getLayout(), o.getKey());
+ }
+ }
+
+ private void resetLinkValues(boolean parentSize)
+ {
+ Object lay = container.getLayout();
+ LinkHandler.clearTemporaryBounds(lay);
+
+ boolean defIns = !hasDocks();
+
+ int parW = parentSize ? container.getWidth() : 0;
+ int parH = parentSize ? container.getHeight() : 0;
+ int insX = LayoutUtil.getInsets(lc, 0, defIns).getPixels(0, container, null);
+ int insY = LayoutUtil.getInsets(lc, 1, defIns).getPixels(0, container, null);
+ int insW = parW - insX - LayoutUtil.getInsets(lc, 2, defIns).getPixels(0, container, null);
+ int insH = parH - insY - LayoutUtil.getInsets(lc, 3, defIns).getPixels(0, container, null);
+
+ LinkHandler.setBounds(lay, "visual", insX, insY, insW, insH, true, false);
+ LinkHandler.setBounds(lay, "container", 0, 0, parW, parH, true, false);
+ }
+
+ /** Returns the {@link net.miginfocom.layout.Grid.LinkedDimGroup} that has the {@link net.miginfocom.layout.Grid.CompWrap}
+ * <code>cw</code>.
+ * @param groupLists The lists to search in.
+ * @param cw The component wrap to find.
+ * @return The linked group or <code>null</code> if none had the component wrap.
+ */
+ private static LinkedDimGroup getGroupContaining(ArrayList<LinkedDimGroup>[] groupLists, CompWrap cw)
+ {
+ for (int i = 0; i < groupLists.length; i++) {
+ ArrayList<LinkedDimGroup> groups = groupLists[i];
+ for (int j = 0, jSz = groups.size(); j < jSz; j++) {
+ ArrayList<CompWrap> cwList = groups.get(j)._compWraps;
+ for (int k = 0, kSz = cwList.size(); k < kSz; k++) {
+ if (cwList.get(k) == cw)
+ return groups.get(j);
+ }
+ }
+ }
+ return null;
+ }
+
+ private boolean doAbsoluteCorrections(CompWrap cw, int[] bounds)
+ {
+ boolean changed = false;
+
+ int[] stSz = getAbsoluteDimBounds(cw, bounds[2], true);
+ if (stSz != null)
+ cw.setDimBounds(stSz[0], stSz[1], true);
+
+ stSz = getAbsoluteDimBounds(cw, bounds[3], false);
+ if (stSz != null)
+ cw.setDimBounds(stSz[0], stSz[1], false);
+
+ // If there is a link id, store the new bounds.
+ if (linkTargetIDs != null)
+ changed = setLinkedBounds(cw.comp, cw.cc, cw.x, cw.y, cw.w, cw.h, false);
+
+ return changed;
+ }
+
+ private void adjustSizeForAbsolute(int[] curSizes, boolean isHor)
+ {
+ Cell absCell = grid.get(null);
+ if (absCell == null || absCell.compWraps.size() == 0)
+ return;
+
+ ArrayList<CompWrap> cws = absCell.compWraps;
+
+ int maxEnd = 0;
+ for (int j = 0, cwSz = absCell.compWraps.size(); j < cwSz + 3; j++) { // "Do Again" max absCell.compWraps.size() + 3 times.
+ boolean doAgain = false;
+ for (int i = 0; i < cwSz; i++) {
+ CompWrap cw = cws.get(i);
+ int[] stSz = getAbsoluteDimBounds(cw, 0, isHor);
+ int end = stSz[0] + stSz[1];
+ if (maxEnd < end)
+ maxEnd = end;
+
+ // If there is a link id, store the new bounds.
+ if (linkTargetIDs != null)
+ doAgain |= setLinkedBounds(cw.comp, cw.cc, stSz[0], stSz[0], stSz[1], stSz[1], false);
+ }
+ if (doAgain == false)
+ break;
+
+ // We need to check this again since the coords may be smaller this round.
+ maxEnd = 0;
+ clearGroupLinkBounds();
+ }
+
+ maxEnd += LayoutUtil.getInsets(lc, isHor ? 3 : 2, !hasDocks()).getPixels(0, container, null);
+
+ if (curSizes[LayoutUtil.MIN] < maxEnd)
+ curSizes[LayoutUtil.MIN] = maxEnd;
+ if (curSizes[LayoutUtil.PREF] < maxEnd)
+ curSizes[LayoutUtil.PREF] = maxEnd;
+ }
+
+ private int[] getAbsoluteDimBounds(CompWrap cw, int refSize, boolean isHor)
+ {
+ if (cw.cc.isExternal()) {
+ if (isHor) {
+ return new int[] {cw.comp.getX(), cw.comp.getWidth()};
+ } else {
+ return new int[] {cw.comp.getY(), cw.comp.getHeight()};
+ }
+ }
+
+ int[] plafPad = lc.isVisualPadding() ? cw.comp.getVisualPadding() : null;
+ UnitValue[] pad = cw.cc.getPadding();
+
+ // If no changes do not create a lot of objects
+ if (cw.pos == null && plafPad == null && pad == null)
+ return null;
+
+ // Set start
+ int st = isHor ? cw.x : cw.y;
+ int sz = isHor ? cw.w : cw.h;
+
+ // If absolute, use those coordinates instead.
+ if (cw.pos != null) {
+ UnitValue stUV = cw.pos != null ? cw.pos[isHor ? 0 : 1] : null;
+ UnitValue endUV = cw.pos != null ? cw.pos[isHor ? 2 : 3] : null;
+
+ int minSz = cw.getSize(LayoutUtil.MIN, isHor);
+ int maxSz = cw.getSize(LayoutUtil.MAX, isHor);
+ sz = Math.min(Math.max(cw.getSize(LayoutUtil.PREF, isHor), minSz), maxSz);
+
+ if (stUV != null) {
+ st = stUV.getPixels(stUV.getUnit() == UnitValue.ALIGN ? sz : refSize, container, cw.comp);
+
+ if (endUV != null) // if (endUV == null && cw.cc.isBoundsIsGrid() == true)
+ sz = Math.min(Math.max((isHor ? (cw.x + cw.w) : (cw.y + cw.h)) - st, minSz), maxSz);
+ }
+
+ if (endUV != null) {
+ if (stUV != null) { // if (stUV != null || cw.cc.isBoundsIsGrid()) {
+ sz = Math.min(Math.max(endUV.getPixels(refSize, container, cw.comp) - st, minSz), maxSz);
+ } else {
+ st = endUV.getPixels(refSize, container, cw.comp) - sz;
+ }
+ }
+ }
+
+ // If constraint has padding -> correct the start/size
+ if (pad != null) {
+ UnitValue uv = pad[isHor ? 1 : 0];
+ int p = uv != null ? uv.getPixels(refSize, container, cw.comp) : 0;
+ st += p;
+ uv = pad[isHor ? 3 : 2];
+ sz += -p + (uv != null ? uv.getPixels(refSize, container, cw.comp) : 0);
+ }
+
+ // If the plaf converter has padding -> correct the start/size
+ if (plafPad != null) {
+ int p = plafPad[isHor ? 1 : 0];
+ st += p;
+ sz += -p + (plafPad[isHor ? 3 : 2]);
+ }
+
+ return new int[] {st, sz};
+ }
+
+ private void layoutInOneDim(int refSize, UnitValue align, boolean isRows, Float[] defaultGrowW)
+ {
+ boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
+ DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
+ FlowSizeSpec fss = isRows ? rowFlowSpecs : colFlowSpecs;
+ ArrayList<LinkedDimGroup>[] rowCols = isRows ? rowGroupLists : colGroupLists;
+
+ int[] rowColSizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, defaultGrowW, LayoutUtil.PREF, refSize);
+
+ if (LayoutUtil.isDesignTime(container)) {
+ TreeSet<Integer> indexes = isRows ? rowIndexes : colIndexes;
+ int[] ixArr = new int[indexes.size()];
+ int ix = 0;
+ for (Integer i : indexes)
+ ixArr[ix++] = i.intValue();
+
+ putSizesAndIndexes(container.getComponent(), rowColSizes, ixArr, isRows);
+ }
+
+ int curPos = align != null ? Math.round(align.getPixels(refSize - LayoutUtil.sum(rowColSizes), container, null)) : 0;
+
+ if (fromEnd)
+ curPos = refSize - curPos;
+
+ for (int i = 0 ; i < rowCols.length; i++) {
+ ArrayList<LinkedDimGroup> linkedGroups = rowCols[i];
+ int scIx = i - (isRows ? dockOffY : dockOffX);
+
+ int bIx = i << 1;
+ int bIx2 = bIx + 1;
+
+ curPos += (fromEnd ? -rowColSizes[bIx] : rowColSizes[bIx]);
+
+ DimConstraint primDC = scIx >= 0 ? primDCs[scIx >= primDCs.length ? primDCs.length - 1 : scIx] : DOCK_DIM_CONSTRAINT;
+
+ int rowSize = rowColSizes[bIx2];
+
+ for (int j = 0; j < linkedGroups.size(); j++) {
+ LinkedDimGroup group = linkedGroups.get(j);
+ int groupSize = rowSize;
+ if (group.span > 1)
+ groupSize = LayoutUtil.sum(rowColSizes, bIx2, Math.min((group.span << 1) - 1, rowColSizes.length - bIx2 - 1));
+
+ group.layout(primDC, curPos, groupSize, group.span);
+ }
+
+ curPos += (fromEnd ? -rowSize : rowSize);
+ }
+ }
+
+ private void addToSizeGroup(HashMap<String, int[]> sizeGroups, String sizeGroup, int[] size)
+ {
+ if (sizeGroups == null)
+ return;
+
+ int[] sgSize = sizeGroups.get(sizeGroup);
+ if (sgSize == null) {
+ sizeGroups.put(sizeGroup, new int[] {size[LayoutUtil.MIN], size[LayoutUtil.PREF], size[LayoutUtil.MAX]});
+ } else {
+ sgSize[LayoutUtil.MIN] = Math.max(size[LayoutUtil.MIN], sgSize[LayoutUtil.MIN]);
+ sgSize[LayoutUtil.PREF] = Math.max(size[LayoutUtil.PREF], sgSize[LayoutUtil.PREF]);
+ sgSize[LayoutUtil.MAX] = Math.min(size[LayoutUtil.MAX], sgSize[LayoutUtil.MAX]);
+ }
+ }
+
+ private HashMap<String, Integer> addToEndGroup(HashMap<String, Integer> endGroups, String endGroup, int end)
+ {
+ if (endGroup != null) {
+ if (endGroups == null)
+ endGroups = new HashMap<String, Integer>(2);
+
+ Integer oldEnd = endGroups.get(endGroup);
+ if (oldEnd == null || end > oldEnd.intValue())
+ endGroups.put(endGroup, new Integer(end));
+ }
+ return endGroups;
+ }
+
+ /** Calculates Min, Preferred and Max size for the columns OR rows.
+ * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
+ * @return The sizes in a {@link net.miginfocom.layout.Grid.FlowSizeSpec}.
+ */
+ private FlowSizeSpec calcRowsOrColsSizes(ArrayList<LinkedDimGroup>[] groupsLists, Float[] defGrow, int refSize, boolean isHor)
+ {
+ DimConstraint[] primDCs = (isHor? colConstr : rowConstr).getConstaints();
+ TreeSet<Integer> primIdexes = isHor ? colIndexes : rowIndexes;
+
+ int[][] rowColBoundSizes = new int[primIdexes.size()][];
+ HashMap<String, int[]> sizeGroupMap = new HashMap<String, int[]>(2);
+ DimConstraint[] allDCs = new DimConstraint[primIdexes.size()];
+
+ Iterator<Integer> primIt = primIdexes.iterator();
+ for (int r = 0; r < rowColBoundSizes.length; r++) {
+ int cellIx = primIt.next().intValue();
+ int[] rowColSizes = new int[3];
+
+ if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID) { // If not dock cell
+ allDCs[r] = primDCs[cellIx >= primDCs.length ? primDCs.length - 1 : cellIx];
+ } else {
+ allDCs[r] = DOCK_DIM_CONSTRAINT;
+ }
+
+ ArrayList<LinkedDimGroup> groups = groupsLists[r];
+
+ int[] groupSizes = new int[] {
+ getTotalGroupsSizeParallel(groups, LayoutUtil.MIN, false),
+ getTotalGroupsSizeParallel(groups, LayoutUtil.PREF, false),
+ LayoutUtil.INF};
+
+ correctMinMax(groupSizes);
+ BoundSize dimSize = allDCs[r].getSize();
+
+ for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
+
+ int rowColSize = groupSizes[sType];
+
+ UnitValue uv = dimSize != null ? dimSize.getSize(sType) : null;
+ if (uv != null) {
+ // If the size of the column is a link to some other size, use that instead
+ int unit = uv.getUnit();
+ if (unit == UnitValue.PREF_SIZE) {
+ rowColSize = groupSizes[LayoutUtil.PREF];
+ } else if (unit == UnitValue.MIN_SIZE) {
+ rowColSize = groupSizes[LayoutUtil.MIN];
+ } else if (unit == UnitValue.MAX_SIZE) {
+ rowColSize = groupSizes[LayoutUtil.MAX];
+ } else {
+ rowColSize = uv.getPixels(refSize, container, null);
+ }
+ } else if (cellIx >= -MAX_GRID && cellIx <= MAX_GRID && rowColSize == 0) {
+ rowColSize = LayoutUtil.isDesignTime(container) ? LayoutUtil.getDesignTimeEmptySize() : 0; // Empty rows with no size set gets XX pixels if design time
+ }
+
+ rowColSizes[sType] = rowColSize;
+ }
+
+ correctMinMax(rowColSizes);
+ addToSizeGroup(sizeGroupMap, allDCs[r].getSizeGroup(), rowColSizes);
+
+ rowColBoundSizes[r] = rowColSizes;
+ }
+
+ // Set/equalize the size groups to same the values.
+ if (sizeGroupMap.size() > 0) {
+ for (int r = 0; r < rowColBoundSizes.length; r++) {
+ if (allDCs[r].getSizeGroup() != null)
+ rowColBoundSizes[r] = sizeGroupMap.get(allDCs[r].getSizeGroup());
+ }
+ }
+
+ // Add the gaps
+ ResizeConstraint[] resConstrs = getRowResizeConstraints(allDCs);
+
+ boolean[] fillInPushGaps = new boolean[allDCs.length + 1];
+ int[][] gapSizes = getRowGaps(allDCs, refSize, isHor, fillInPushGaps);
+
+
+ FlowSizeSpec fss = mergeSizesGapsAndResConstrs(resConstrs, fillInPushGaps, rowColBoundSizes, gapSizes, refSize, container);
+
+ // Spanning components are not handled yet. Check and adjust the multi-row min/pref they enforce.
+ adjustMinPrefForSpanningComps(allDCs, defGrow, fss, groupsLists);
+
+ return fss;
+ }
+
+ private static int[] getMinPrefMaxSumSize(int[][] sizes)
+ {
+ int[] retSizes = new int[3];
+
+ for (int i = 0; i < sizes.length; i++) {
+ if (sizes[i] != null) {
+ int[] size = sizes[i];
+ for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.MAX; sType++) {
+ int s = size[sType];
+
+ if (s != LayoutUtil.NOT_SET) {
+ if (sType == LayoutUtil.PREF) {
+ int bnd = size[LayoutUtil.MAX];
+ if (bnd != LayoutUtil.NOT_SET && bnd < s)
+ s = bnd;
+
+ bnd = size[LayoutUtil.MIN];
+ if (bnd > s) // Includes s == LayoutUtil.NOT_SET since < 0.
+ s = bnd;
+ }
+
+ retSizes[sType] += s; // MAX compensated below.
+ }
+ }
+
+ // So that MAX is always correct.
+ if (size[LayoutUtil.MAX] == LayoutUtil.NOT_SET)
+ retSizes[LayoutUtil.MAX] = LayoutUtil.INF;
+ }
+ }
+
+ return retSizes;
+ }
+
+ private static ResizeConstraint[] getRowResizeConstraints(DimConstraint[] specs)
+ {
+ ResizeConstraint[] resConsts = new ResizeConstraint[specs.length];
+ for (int i = 0; i < resConsts.length; i++)
+ resConsts[i] = specs[i].resize;
+ return resConsts;
+ }
+
+ private static ResizeConstraint[] getComponentResizeConstraints(ArrayList<CompWrap> compWraps, boolean isHor)
+ {
+ ResizeConstraint[] resConsts = new ResizeConstraint[compWraps.size()];
+ for (int i = 0; i < resConsts.length; i++) {
+ CC fc = compWraps.get(i).cc;
+ resConsts[i] = fc.getDimConstraint(isHor).resize;
+
+ // Always grow docking components in the correct dimension.
+ int dock = fc.getDockSide();
+ if (isHor ? (dock == 0 || dock == 2) : (dock == 1 || dock == 3)) {
+ ResizeConstraint dc = resConsts[i];
+ resConsts[i] = new ResizeConstraint(dc.shrinkPrio, dc.shrink, dc.growPrio, ResizeConstraint.WEIGHT_100);
+ }
+ }
+ return resConsts;
+ }
+
+ private static boolean[] getComponentGapPush(ArrayList<CompWrap> compWraps, boolean isHor)
+ {
+ // Make one element bigger and or the after gap with the next before gap.
+ boolean[] barr = new boolean[compWraps.size() + 1];
+ for (int i = 0; i < barr.length; i++) {
+
+ boolean push = i > 0 ? compWraps.get(i - 1).isPushGap(isHor, false) : false;
+
+ if (push == false && i < (barr.length - 1))
+ push = compWraps.get(i).isPushGap(isHor, true);
+
+ barr[i] = push;
+ }
+ return barr;
+ }
+
+ /** Returns the row gaps in pixel sizes. One more than there are <code>specs</code> sent in.
+ * @param specs
+ * @param refSize
+ * @param isHor
+ * @param fillInPushGaps If the gaps are pushing. <b>NOTE!</b> this argument will be filled in and thus changed!
+ * @return The row gaps in pixel sizes. One more than there are <code>specs</code> sent in.
+ */
+ private int[][] getRowGaps(DimConstraint[] specs, int refSize, boolean isHor, boolean[] fillInPushGaps)
+ {
+ BoundSize defGap = isHor ? lc.getGridGapX() : lc.getGridGapY();
+ if (defGap == null)
+ defGap = isHor ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY();
+ int[] defGapArr = defGap.getPixelSizes(refSize, container, null);
+
+ boolean defIns = !hasDocks();
+
+ UnitValue firstGap = LayoutUtil.getInsets(lc, isHor ? 1 : 0, defIns);
+ UnitValue lastGap = LayoutUtil.getInsets(lc, isHor ? 3 : 2, defIns);
+
+ int[][] retValues = new int[specs.length + 1][];
+
+ for (int i = 0, wgIx = 0; i < retValues.length; i++) {
+ DimConstraint specBefore = i > 0 ? specs[i - 1] : null;
+ DimConstraint specAfter = i < specs.length ? specs[i] : null;
+
+ // No gap if between docking components.
+ boolean edgeBefore = (specBefore == DOCK_DIM_CONSTRAINT || specBefore == null);
+ boolean edgeAfter = (specAfter == DOCK_DIM_CONSTRAINT || specAfter == null);
+ if (edgeBefore && edgeAfter)
+ continue;
+
+ BoundSize wrapGapSize = (wrapGapMap == null || isHor == lc.isFlowX() ? null : wrapGapMap.get(new Integer(wgIx++)));
+
+ if (wrapGapSize == null) {
+
+ int[] gapBefore = specBefore != null ? specBefore.getRowGaps(container, null, refSize, false) : null;
+ int[] gapAfter = specAfter != null ? specAfter.getRowGaps(container, null, refSize, true) : null;
+
+ if (edgeBefore && gapAfter == null && firstGap != null) {
+
+ int bef = firstGap.getPixels(refSize, container, null);
+ retValues[i] = new int[] {bef, bef, bef};
+
+ } else if (edgeAfter && gapBefore == null && firstGap != null) {
+
+ int aft = lastGap.getPixels(refSize, container, null);
+ retValues[i] = new int[] {aft, aft, aft};
+
+ } else {
+ retValues[i] = gapAfter != gapBefore ? mergeSizes(gapAfter, gapBefore) : new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
+ }
+
+ if (specBefore != null && specBefore.isGapAfterPush() || specAfter != null && specAfter.isGapBeforePush())
+ fillInPushGaps[i] = true;
+ } else {
+
+ if (wrapGapSize.isUnset()) {
+ retValues[i] = new int[] {defGapArr[0], defGapArr[1], defGapArr[2]};
+ } else {
+ retValues[i] = wrapGapSize.getPixelSizes(refSize, container, null);
+ }
+ fillInPushGaps[i] = wrapGapSize.getGapPush();
+ }
+ }
+ return retValues;
+ }
+
+ private static int[][] getGaps(ArrayList<CompWrap> compWraps, boolean isHor)
+ {
+ int compCount = compWraps.size();
+ int[][] retValues = new int[compCount + 1][];
+
+ retValues[0] = compWraps.get(0).getGaps(isHor, true);
+ for (int i = 0; i < compCount; i++) {
+ int[] gap1 = compWraps.get(i).getGaps(isHor, false);
+ int[] gap2 = i < compCount - 1 ? compWraps.get(i + 1).getGaps(isHor, true) : null;
+
+ retValues[i + 1] = mergeSizes(gap1, gap2);
+ }
+
+ return retValues;
+ }
+
+ private boolean hasDocks()
+ {
+ return (dockOffX > 0 || dockOffY > 0 || rowIndexes.last() > MAX_GRID || colIndexes.last() > MAX_GRID);
+ }
+
+ /**
+ * @param specs The specs for the columns or rows. Last index will be used of <code>count</code> is greater than this array's length.
+ * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
+ * @param fss
+ * @param groupsLists
+ */
+ private void adjustMinPrefForSpanningComps(DimConstraint[] specs, Float[] defGrow, FlowSizeSpec fss, ArrayList<LinkedDimGroup>[] groupsLists)
+ {
+ for (int r = 0; r < groupsLists.length; r++) {
+ ArrayList<LinkedDimGroup> groups = groupsLists[r];
+
+ for (int i = 0; i < groups.size(); i++) {
+ LinkedDimGroup group = groups.get(i);
+ if (group.span == 1)
+ continue;
+
+ int cSize = group.getMinPrefMax()[LayoutUtil.PREF];
+ if (cSize == LayoutUtil.NOT_SET)
+ continue;
+
+ int rowSize = 0;
+ int sIx = (r << 1) + 1;
+ int len = Math.min((group.span << 1), fss.sizes.length - sIx) - 1;
+ for (int j = sIx; j < sIx + len; j++) {
+ int sz = fss.sizes[j][LayoutUtil.PREF];
+ if (sz != LayoutUtil.NOT_SET)
+ rowSize += sz;
+ }
+
+ if (rowSize < cSize) {
+ for (int eag = 0, newRowSize = 0; eag < 4 && newRowSize < cSize; eag++)
+ newRowSize = fss.expandSizes(specs, defGrow, cSize, sIx, len, LayoutUtil.PREF, eag);
+ }
+ }
+ }
+ }
+
+ /** For one dimension divide the component wraps into logical groups. One group for component wraps that share a common something,
+ * line the property to layout by base line.
+ * @param isRows If rows, and not columns, are to be divided.
+ * @return One <code>ArrayList<LinkedDimGroup></code> for every row/column.
+ */
+ private ArrayList<LinkedDimGroup>[] divideIntoLinkedGroups(boolean isRows)
+ {
+ boolean fromEnd = !(isRows ? lc.isTopToBottom() : LayoutUtil.isLeftToRight(lc, container));
+ TreeSet<Integer> primIndexes = isRows ? rowIndexes : colIndexes;
+ TreeSet<Integer> secIndexes = isRows ? colIndexes : rowIndexes;
+ DimConstraint[] primDCs = (isRows ? rowConstr : colConstr).getConstaints();
+
+ ArrayList<LinkedDimGroup>[] groupLists = new ArrayList[primIndexes.size()];
+
+ int gIx = 0;
+ for (Iterator<Integer> primIt = primIndexes.iterator(); primIt.hasNext();) {
+ int i = primIt.next().intValue();
+
+ DimConstraint dc;
+ if (i >= -MAX_GRID && i <= MAX_GRID) { // If not dock cell
+ dc = primDCs[i >= primDCs.length ? primDCs.length - 1 : i];
+ } else {
+ dc = DOCK_DIM_CONSTRAINT;
+ }
+
+ ArrayList<LinkedDimGroup> groupList = new ArrayList<LinkedDimGroup>(2);
+ groupLists[gIx++] = groupList;
+
+ for (Iterator<Integer> secIt = secIndexes.iterator(); secIt.hasNext();) {
+ int j = secIt.next().intValue();
+ Cell cell = isRows ? getCell(i, j) : getCell(j, i);
+ if (cell == null || cell.compWraps.size() == 0)
+ continue;
+
+ int span = (isRows ? cell.spany : cell.spanx);
+ if (span > 1)
+ span = convertSpanToSparseGrid(i, span, primIndexes);
+
+ boolean isPar = cell.flowx == isRows;
+
+ if ((isPar == false && cell.compWraps.size() > 1) || span > 1) {
+
+ int linkType = isPar ? LinkedDimGroup.TYPE_PARALLEL : LinkedDimGroup.TYPE_SERIAL;
+ LinkedDimGroup lg = new LinkedDimGroup("p," + j, span, linkType, !isRows, fromEnd);
+ lg.setCompWraps(cell.compWraps);
+ groupList.add(lg);
+ } else {
+ for (int cwIx = 0; cwIx < cell.compWraps.size(); cwIx++) {
+ CompWrap cw = cell.compWraps.get(cwIx);
+ boolean rowBaselineAlign = (isRows && dc.getAlignOrDefault(!isRows) == UnitValue.BASELINE_IDENTITY);
+
+ String linkCtx = cw.getLinkContext(rowBaselineAlign);
+
+ // Find a group with same link context and put it in that group.
+ boolean foundList = false;
+ for (int glIx = 0, lastGl = groupList.size() - 1; glIx <= lastGl ; glIx++) {
+ LinkedDimGroup group = groupList.get(glIx);
+ if (group.linkCtx == linkCtx || linkCtx != null && linkCtx.equals(group.linkCtx)) {
+ group.addCompWrap(cw);
+ foundList = true;
+ break;
+ }
+ }
+
+ // If none found and at last add a new group.
+ if (foundList == false) {
+
+ int linkType = LinkedDimGroup.TYPE_PARALLEL;
+ if (isRows && cw.isBaselineAlign(rowBaselineAlign))
+ linkType = LinkedDimGroup.TYPE_BASELINE;
+
+ LinkedDimGroup lg = new LinkedDimGroup(linkCtx, 1, linkType, !isRows, fromEnd);
+ lg.addCompWrap(cw);
+ groupList.add(lg);
+ }
+ }
+ }
+ }
+ }
+ return groupLists;
+ }
+
+ /** Spanning is specified in the uncompressed grid number. They can for instance be more than 60000 for the outer
+ * edge dock grid cells. When the grid is compressed and indexed after only the cells that area occupied the span
+ * is erratic. This method use the row/col indexes and corrects the span to be correct for the compressed grid.
+ * @param span The span un the uncompressed grid. <code>LayoutUtil.INF</code> will be interpreted to span the rest
+ * of the column/row excluding the surrounding docking components.
+ * @param indexes The indexes in the correct dimension.
+ * @return The converted span.
+ */
+ private int convertSpanToSparseGrid(int curIx, int span, TreeSet<Integer> indexes)
+ {
+ int lastIx = curIx + span;
+ int retSpan = 1;
+
+ for (Iterator<Integer> it = indexes.iterator(); it.hasNext();) {
+ int ix = it.next();
+ if (ix <= curIx)
+ continue; // We have not arrive to the correct index yet
+
+ if (ix >= lastIx)
+ break;
+
+ retSpan++;
+ }
+ return retSpan;
+ }
+
+ private final boolean isCellFree(int r, int c, ArrayList<int[]> occupiedRects)
+ {
+ if (getCell(r, c) != null)
+ return false;
+
+ for (int i = 0; i < occupiedRects.size(); i++) {
+ int[] rect = occupiedRects.get(i);
+ if (rect[0] <= c && rect[1] <= r && rect[0] + rect[2] > c && rect[1] + rect[3] > r)
+ return false;
+ }
+ return true;
+ }
+
+ private Cell getCell(int r, int c)
+ {
+ return grid.get(new Integer((r << 16) + c));
+ }
+
+ private void setCell(int r, int c, Cell cell)
+ {
+ if (c < 0 || c > MAX_GRID || r < 0 || r > MAX_GRID)
+ throw new IllegalArgumentException("Cell position out of bounds. row: " + r + ", col: " + c);
+
+ rowIndexes.add(new Integer(r));
+ colIndexes.add(new Integer(c));
+
+ grid.put(new Integer((r << 16) + c), cell);
+ }
+
+ /** Adds a docking cell. That cell is outside the normal cell indexes.
+ * @param dockInsets The current dock insets. Will be updated!
+ * @param side top == 0, left == 1, bottom = 2, right = 3.
+ * @param cw The compwrap to put in a cell and add.
+ */
+ private void addDockingCell(int[] dockInsets, int side, CompWrap cw)
+ {
+ int r, c, spanx = 1, spany = 1;
+ switch (side) {
+ case 0:
+ case 2:
+ r = side == 0 ? dockInsets[0]++ : dockInsets[2]--;
+ c = dockInsets[1];
+ spanx = dockInsets[3] - dockInsets[1] + 1; // The +1 is for cell 0.
+ colIndexes.add(new Integer(dockInsets[3])); // Make sure there is a receiving cell
+ break;
+
+ case 1:
+ case 3:
+ c = side == 1 ? dockInsets[1]++ : dockInsets[3]--;
+ r = dockInsets[0];
+ spany = dockInsets[2] - dockInsets[0] + 1; // The +1 is for cell 0.
+ rowIndexes.add(new Integer(dockInsets[2])); // Make sure there is a receiving cell
+ break;
+
+ default:
+ throw new IllegalArgumentException("Internal error 123.");
+ }
+
+ rowIndexes.add(new Integer(r));
+ colIndexes.add(new Integer(c));
+
+ grid.put(new Integer((r << 16) + c), new Cell(cw, spanx, spany, spanx > 1));
+ }
+
+ /** A simple representation of a cell in the grid. Contains a number of component wraps and if they span more than one cell.
+ */
+ private static class Cell
+ {
+ private final int spanx, spany;
+ private final boolean flowx;
+ private final ArrayList<CompWrap> compWraps = new ArrayList<CompWrap>(1);
+
+ private boolean hasTagged = false; // If one or more components have styles and need to be checked by the component sorter
+
+ private Cell(CompWrap cw)
+ {
+ this(cw, 1, 1, true);
+ }
+
+ private Cell(int spanx, int spany, boolean flowx)
+ {
+ this(null, spanx, spany, flowx);
+ }
+
+ private Cell(CompWrap cw, int spanx, int spany, boolean flowx)
+ {
+ if (cw != null)
+ compWraps.add(cw);
+ this.spanx = spanx;
+ this.spany = spany;
+ this.flowx = flowx;
+ }
+ }
+
+ /** A number of component wraps that share a layout "something" <b>in one dimension</b>
+ */
+ private static class LinkedDimGroup
+ {
+ private static final int TYPE_SERIAL = 0;
+ private static final int TYPE_PARALLEL = 1;
+ private static final int TYPE_BASELINE = 2;
+
+ private final String linkCtx;
+ private final int span;
+ private final int linkType;
+ private final boolean isHor, fromEnd;
+
+ private ArrayList<CompWrap> _compWraps = new ArrayList<CompWrap>(4);
+
+ private int[] sizes = null;
+ private int lStart = 0, lSize = 0; // Currently mostly for debug painting
+
+ private LinkedDimGroup(String linkCtx, int span, int linkType, boolean isHor, boolean fromEnd)
+ {
+ this.linkCtx = linkCtx;
+ this.span = span;
+ this.linkType = linkType;
+ this.isHor = isHor;
+ this.fromEnd = fromEnd;
+ }
+
+ private void addCompWrap(CompWrap cw)
+ {
+ _compWraps.add(cw);
+ sizes = null;
+ }
+
+ private void setCompWraps(ArrayList<CompWrap> cws)
+ {
+ if (_compWraps != cws) {
+ _compWraps = cws;
+ sizes = null;
+ }
+ }
+
+ private void layout(DimConstraint dc, int start, int size, int spanCount)
+ {
+ lStart = start;
+ lSize = size;
+
+ if (_compWraps.size() == 0)
+ return;
+
+ ContainerWrapper parent = _compWraps.get(0).comp.getParent();
+ if (linkType == TYPE_PARALLEL) {
+ layoutParallel(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd);
+ } else if (linkType == TYPE_BASELINE) {
+ layoutBaseline(parent, _compWraps, dc, start, size, LayoutUtil.PREF, spanCount);
+ } else {
+ layoutSerial(parent, _compWraps, dc, start, size, isHor, spanCount, fromEnd);
+ }
+ }
+
+ /** Returns the min/pref/max sizes for this cell. Returned array <b>must not be altered</b>
+ * @return A shared min/pref/max array of sizes. Always of length 3 and never <code>null</code>. Will always be of type STATIC and PIXEL.
+ */
+ private int[] getMinPrefMax()
+ {
+ if (sizes == null && _compWraps.size() > 0) {
+ sizes = new int[3];
+ for (int sType = LayoutUtil.MIN; sType <= LayoutUtil.PREF; sType++) {
+ if (linkType == TYPE_PARALLEL) {
+ sizes[sType] = getTotalSizeParallel(_compWraps, sType, isHor);
+ } else if (linkType == TYPE_BASELINE) {
+ int[] aboveBelow = getBaselineAboveBelow(_compWraps, sType, false);
+ sizes[sType] = aboveBelow[0] + aboveBelow[1];
+ } else {
+ sizes[sType] = getTotalSizeSerial(_compWraps, sType, isHor);
+ }
+ }
+ sizes[LayoutUtil.MAX] = LayoutUtil.INF;
+ }
+ return sizes;
+ }
+ }
+
+ /** Wraps a {@link java.awt.Component} together with its constraint. Caches a lot of information about the component so
+ * for instance not the preferred size has to be calculated more than once.
+ */
+ private final static class CompWrap
+ {
+ private final ComponentWrapper comp;
+ private final CC cc;
+ private final UnitValue[] pos;
+ private int[][] gaps; // [top,left(actually before),bottom,right(actually after)][min,pref,max]
+
+ private final int[] horSizes = new int[3];
+ private final int[] verSizes = new int[3];
+
+ private int x = LayoutUtil.NOT_SET, y = LayoutUtil.NOT_SET, w = LayoutUtil.NOT_SET, h = LayoutUtil.NOT_SET;
+
+ private int forcedPushGaps = 0; // 1 == before, 2 = after. Bitwise.
+
+ private CompWrap(ComponentWrapper c, CC cc, int eHideMode, UnitValue[] pos, BoundSize[] callbackSz)
+ {
+ this.comp = c;
+ this.cc = cc;
+ this.pos = pos;
+
+ if (eHideMode <= 0) {
+ BoundSize hBS = (callbackSz != null && callbackSz[0] != null) ? callbackSz[0] : cc.getHorizontal().getSize();
+ BoundSize vBS = (callbackSz != null && callbackSz[1] != null) ? callbackSz[1] : cc.getVertical().getSize();
+
+ for (int i = LayoutUtil.MIN; i <= LayoutUtil.MAX; i++) {
+ horSizes[i] = getSize(hBS, i, true);
+ verSizes[i] = getSize(vBS, i, false);
+ }
+
+ correctMinMax(horSizes);
+ correctMinMax(verSizes);
+ }
+
+ if (eHideMode > 1) {
+ gaps = new int[4][];
+ for (int i = 0; i < gaps.length; i++)
+ gaps[i] = new int[3];
+ }
+ }
+
+ private final int getSize(BoundSize uvs, int sizeType, boolean isHor)
+ {
+ if (uvs == null || uvs.getSize(sizeType) == null) {
+ switch(sizeType) {
+ case LayoutUtil.MIN:
+ return isHor ? comp.getMinimumWidth() : comp.getMinimumHeight();
+ case LayoutUtil.PREF:
+ return isHor ? comp.getPreferredWidth() : comp.getPreferredHeight();
+ default:
+ return isHor ? comp.getMaximumWidth() : comp.getMaximumHeight();
+ }
+ }
+
+ ContainerWrapper par = comp.getParent();
+ return uvs.getSize(sizeType).getPixels(isHor ? par.getWidth() : par.getHeight(), par, comp);
+ }
+
+ private final void calcGaps(ComponentWrapper before, CC befCC, ComponentWrapper after, CC aftCC, String tag, boolean flowX, boolean isLTR)
+ {
+ ContainerWrapper par = comp.getParent();
+ int parW = par.getWidth();
+ int parH = par.getHeight();
+
+ BoundSize befGap = before != null ? (flowX ? befCC.getHorizontal() : befCC.getVertical()).getGapAfter() : null;
+ BoundSize aftGap = after != null ? (flowX ? aftCC.getHorizontal() : aftCC.getVertical()).getGapBefore() : null;
+
+ mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, befGap, (flowX ? null : before), tag, parH, 0, isLTR), false, true);
+ mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, befGap, (flowX ? before : null), tag, parW, 1, isLTR), true, true);
+ mergeGapSizes(cc.getVertical().getComponentGaps(par, comp, aftGap, (flowX ? null : after), tag, parH, 2, isLTR), false, false);
+ mergeGapSizes(cc.getHorizontal().getComponentGaps(par, comp, aftGap, (flowX ? after : null), tag, parW, 3, isLTR), true, false);
+ }
+
+ private final void setDimBounds(int start, int size, boolean isHor)
+ {
+ if (isHor) {
+ x = start;
+ w = size;
+ } else {
+ y = start;
+ h = size;
+ }
+ }
+
+ private final boolean isPushGap(boolean isHor, boolean isBefore)
+ {
+ if (isHor && ((isBefore ? 1 : 2) & forcedPushGaps) != 0)
+ return true; // Forced
+
+ DimConstraint dc = cc.getDimConstraint(isHor);
+ BoundSize s = isBefore ? dc.getGapBefore() : dc.getGapAfter();
+ return s != null && s.getGapPush();
+ }
+
+ /**
+ * @return If the preferred size have changed because of the new bounds (needed for SWT only)
+ */
+ private final boolean transferBounds(boolean checkPrefChange)
+ {
+ comp.setBounds(x, y, w, h);
+
+ if (checkPrefChange && w != horSizes[LayoutUtil.PREF]) {
+ BoundSize vSz = cc.getVertical().getSize();
+ if ((vSz == null || vSz.getPreferred() == null)) {
+ if (comp.getPreferredHeight() != verSizes[LayoutUtil.PREF]) {
+ //System.out.println(comp.getComponent() + "oldPrefH: " + verSizes[LayoutUtil.PREF] + ", new: " + comp.getPreferredHeight());
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ private final void setSizes(int[] sizes, boolean isHor)
+ {
+ if (sizes == null)
+ return;
+
+ int[] s = isHor ? horSizes : verSizes;
+ for (int i = 0; i < 3; i++)
+ s[i] = sizes[i];
+ }
+
+ private void setGaps(int[] minPrefMax, int ix)
+ {
+ if (gaps == null)
+ gaps = new int[][] {null, null, null, null};
+
+ gaps[ix] = minPrefMax;
+ }
+
+ private final void mergeGapSizes(int[] sizes, boolean isHor, boolean isTL)
+ {
+ if (gaps == null)
+ gaps = new int[][] {null, null, null, null};
+
+ if (sizes == null)
+ return;
+
+ int gapIX = getGapIx(isHor, isTL);
+ int[] oldGaps = gaps[gapIX];
+ if (oldGaps == null) {
+ oldGaps = new int[] {0, 0, LayoutUtil.INF};
+ gaps[gapIX] = oldGaps;
+ }
+
+ oldGaps[LayoutUtil.MIN] = Math.max(sizes[LayoutUtil.MIN], oldGaps[LayoutUtil.MIN]);
+ oldGaps[LayoutUtil.PREF] = Math.max(sizes[LayoutUtil.PREF], oldGaps[LayoutUtil.PREF]);
+ oldGaps[LayoutUtil.MAX] = Math.min(sizes[LayoutUtil.MAX], oldGaps[LayoutUtil.MAX]);
+ }
+
+ private final int getGapIx(boolean isHor, boolean isTL)
+ {
+ return isHor ? (isTL ? 1 : 3) : (isTL ? 0 : 2);
+ }
+
+ private final String getLinkContext(boolean defBaseline)
+ {
+ return isBaselineAlign(defBaseline) ? "baseline" : null;
+ }
+
+ private final int getSizeInclGaps(int sizeType, boolean isHor)
+ {
+ return filter(sizeType, getGapBefore(sizeType, isHor) + getSize(sizeType, isHor) + getGapAfter(sizeType, isHor));
+ }
+
+ private final int getSize(int sizeType, boolean isHor)
+ {
+ return filter(sizeType, isHor ? horSizes[sizeType] : verSizes[sizeType]);
+ }
+
+ private final int getGapBefore(int sizeType, boolean isHor)
+ {
+ int[] gaps = getGaps(isHor, true);
+ return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
+ }
+
+ private final int getGapAfter(int sizeType, boolean isHor)
+ {
+ int[] gaps = getGaps(isHor, false);
+ return gaps != null ? filter(sizeType, gaps[sizeType]) : 0;
+ }
+
+ private final int[] getGaps(boolean isHor, boolean isTL)
+ {
+ return gaps[getGapIx(isHor, isTL)];
+ }
+
+ private final int filter(int sizeType, int size)
+ {
+ if (size == LayoutUtil.NOT_SET)
+ return sizeType != LayoutUtil.MAX ? 0 : LayoutUtil.INF;
+ return constrainSize(size);
+ }
+
+ private final boolean isBaselineAlign(boolean defValue)
+ {
+ Float g = cc.getVertical().getGrow();
+ if (g != null && g.intValue() != 0)
+ return false;
+
+ UnitValue al = cc.getVertical().getAlign();
+ return comp.hasBaseline() && (al != null ? al == UnitValue.BASELINE_IDENTITY : defValue);
+ }
+
+ private final int getBaseline(int sizeType)
+ {
+ return comp.getBaseline(getSize(sizeType, true), getSize(sizeType, false));
+ }
+ }
+
+ //***************************************************************************************
+ //* Helper Methods
+ //***************************************************************************************
+
+ private static void layoutBaseline(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, int sizeType, int spanCount)
+ {
+ int[] aboveBelow = getBaselineAboveBelow(compWraps, sizeType, true);
+ int blRowSize = aboveBelow[0] + aboveBelow[1];
+
+ CC cc = compWraps.get(0).cc;
+
+ // Align for the whole baseline component array
+ UnitValue align = cc.getVertical().getAlign();
+ if (spanCount == 1 && align == null)
+ align = dc.getAlignOrDefault(false);
+ if (align == UnitValue.BASELINE_IDENTITY)
+ align = UnitValue.CENTER;
+
+ int offset = start + aboveBelow[0] + (align != null ? Math.max(0, align.getPixels(size - blRowSize, parent, null)) : 0);
+ for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
+ CompWrap cw = compWraps.get(i);
+ cw.y += offset;
+
+ if (cw.y + cw.h > start + size)
+ cw.h = start + size - cw.y;
+ }
+ }
+
+ private static void layoutSerial(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd)
+ {
+ FlowSizeSpec fss = mergeSizesGapsAndResConstrs(
+ getComponentResizeConstraints(compWraps, isHor),
+ getComponentGapPush(compWraps, isHor),
+ getComponentSizes(compWraps, isHor),
+ getGaps(compWraps, isHor),
+ 0, null);
+
+ Float[] growW = dc.isFill() ? GROW_100 : null;
+ int[] sizes = LayoutUtil.calculateSerial(fss.sizes, fss.resConstsInclGaps, growW, LayoutUtil.PREF, size);
+ setCompWrapBounds(parent, sizes, compWraps, dc.getAlignOrDefault(isHor), start, size, isHor, fromEnd);
+ }
+
+ private static void setCompWrapBounds(ContainerWrapper parent, int[] allSizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd)
+ {
+ int totSize = LayoutUtil.sum(allSizes);
+ CC cc = compWraps.get(0).cc;
+ UnitValue align = correctAlign(cc, rowAlign, isHor, fromEnd);
+
+ int cSt = start;
+ int slack = size - totSize;
+ if (slack > 0 && align != null) {
+ int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
+ cSt += (fromEnd ? -al : al);
+ }
+
+ for (int i = 0, bIx = 0, iSz = compWraps.size(); i < iSz; i++) {
+ CompWrap cw = compWraps.get(i);
+ if (fromEnd ) {
+ cSt -= allSizes[bIx++];
+ cw.setDimBounds(cSt - allSizes[bIx], allSizes[bIx], isHor);
+ cSt -= allSizes[bIx++];
+ } else {
+ cSt += allSizes[bIx++];
+ cw.setDimBounds(cSt, allSizes[bIx], isHor);
+ cSt += allSizes[bIx++];
+ }
+ }
+ }
+
+ private static void layoutParallel(ContainerWrapper parent, ArrayList<CompWrap> compWraps, DimConstraint dc, int start, int size, boolean isHor, int spanCount, boolean fromEnd)
+ {
+ int[][] sizes = new int[compWraps.size()][]; // [compIx][gapBef,compSize,gapAft]
+
+ for (int i = 0; i < sizes.length; i++) {
+ CompWrap cw = compWraps.get(i);
+
+ DimConstraint cDc = cw.cc.getDimConstraint(isHor);
+
+ ResizeConstraint[] resConstr = new ResizeConstraint[] {
+ cw.isPushGap(isHor, true) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
+ cDc.resize,
+ cw.isPushGap(isHor, false) ? GAP_RC_CONST_PUSH : GAP_RC_CONST,
+ };
+
+ int[][] sz = new int[][] {
+ cw.getGaps(isHor, true), (isHor ? cw.horSizes : cw.verSizes), cw.getGaps(isHor, false)
+ };
+
+ Float[] growW = dc.isFill() ? GROW_100 : null;
+
+ sizes[i] = LayoutUtil.calculateSerial(sz, resConstr, growW, LayoutUtil.PREF, size);
+ }
+
+ UnitValue rowAlign = dc.getAlignOrDefault(isHor);
+ setCompWrapBounds(parent, sizes, compWraps, rowAlign, start, size, isHor, fromEnd);
+ }
+
+ private static void setCompWrapBounds(ContainerWrapper parent, int[][] sizes, ArrayList<CompWrap> compWraps, UnitValue rowAlign, int start, int size, boolean isHor, boolean fromEnd)
+ {
+ for (int i = 0; i < sizes.length; i++) {
+ CompWrap cw = compWraps.get(i);
+
+ UnitValue align = correctAlign(cw.cc, rowAlign, isHor, fromEnd);
+
+ int[] cSizes = sizes[i];
+ int gapBef = cSizes[0];
+ int cSize = cSizes[1]; // No Math.min(size, cSizes[1]) here!
+ int gapAft = cSizes[2];
+
+ int cSt = fromEnd ? start - gapBef : start + gapBef;
+ int slack = size - cSize - gapBef - gapAft;
+ if (slack > 0 && align != null) {
+ int al = Math.min(slack, Math.max(0, align.getPixels(slack, parent, null)));
+ cSt += (fromEnd ? -al : al);
+ }
+
+ cw.setDimBounds(fromEnd ? cSt - cSize : cSt, cSize, isHor);
+ }
+ }
+
+ private static UnitValue correctAlign(CC cc, UnitValue rowAlign, boolean isHor, boolean fromEnd)
+ {
+ UnitValue align = (isHor ? cc.getHorizontal() : cc.getVertical()).getAlign();
+ if (align == null)
+ align = rowAlign;
+ if (align == UnitValue.BASELINE_IDENTITY)
+ align = UnitValue.CENTER;
+
+ if (fromEnd) {
+ if (align == UnitValue.LEFT)
+ align = UnitValue.RIGHT;
+ else if (align == UnitValue.RIGHT)
+ align = UnitValue.LEFT;
+ }
+ return align;
+ }
+
+ private static int[] getBaselineAboveBelow(ArrayList<CompWrap> compWraps, int sType, boolean centerBaseline)
+ {
+ int maxAbove = Short.MIN_VALUE;
+ int maxBelow = Short.MIN_VALUE;
+ for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
+ CompWrap cw = compWraps.get(i);
+
+ int height = cw.getSize(sType, false);
+ if (height >= LayoutUtil.INF)
+ return new int[] {LayoutUtil.INF / 2, LayoutUtil.INF / 2};
+
+ int baseline = cw.getBaseline(sType);
+ int above = baseline + cw.getGapBefore(sType, false);
+ maxAbove = Math.max(above, maxAbove);
+ maxBelow = Math.max(height - baseline + cw.getGapAfter(sType, false), maxBelow);
+
+ if (centerBaseline)
+ cw.setDimBounds(-baseline, height, false);
+ }
+ return new int[] {maxAbove, maxBelow};
+ }
+
+ private static int getTotalSizeParallel(ArrayList<CompWrap> compWraps, int sType, boolean isHor)
+ {
+ int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
+
+ for (int i = 0, iSz = compWraps.size(); i < iSz; i++) {
+ CompWrap cw = compWraps.get(i);
+ int cwSize = cw.getSizeInclGaps(sType, isHor);
+ if (cwSize >= LayoutUtil.INF)
+ return LayoutUtil.INF;
+
+ if (sType == LayoutUtil.MAX ? cwSize < size : cwSize > size)
+ size = cwSize;
+ }
+ return constrainSize(size);
+ }
+
+ private static final int getTotalSizeSerial(ArrayList<CompWrap> compWraps, int sType, boolean isHor)
+ {
+ int totSize = 0;
+ for (int i = 0, iSz = compWraps.size(), lastGapAfter = 0; i < iSz; i++) {
+ CompWrap wrap = compWraps.get(i);
+ int gapBef = wrap.getGapBefore(sType, isHor);
+ if (gapBef > lastGapAfter)
+ totSize += gapBef - lastGapAfter;
+
+ totSize += wrap.getSize(sType, isHor);
+ totSize += (lastGapAfter = wrap.getGapAfter(sType, isHor));
+
+ if (totSize >= LayoutUtil.INF)
+ return LayoutUtil.INF;
+ }
+ return constrainSize(totSize);
+ }
+
+ private static final int getTotalGroupsSizeParallel(ArrayList<LinkedDimGroup> groups, int sType, boolean countSpanning)
+ {
+ int size = sType == LayoutUtil.MAX ? LayoutUtil.INF : 0;
+ for (int i = 0, iSz = groups.size(); i < iSz; i++) {
+ LinkedDimGroup group = groups.get(i);
+ if (countSpanning || group.span == 1) {
+ int grpSize = group.getMinPrefMax()[sType];
+ if (grpSize >= LayoutUtil.INF)
+ return LayoutUtil.INF;
+
+ if (sType == LayoutUtil.MAX ? grpSize < size : grpSize > size)
+ size = grpSize;
+ }
+ }
+ return constrainSize(size);
+ }
+
+ /**
+ * @param compWraps
+ * @param isHor
+ * @return Might contain LayoutUtil.NOT_SET
+ */
+ private static int[][] getComponentSizes(ArrayList<CompWrap> compWraps, boolean isHor)
+ {
+ int[][] compSizes = new int[compWraps.size()][];
+ for (int i = 0; i < compSizes.length; i++) {
+ CompWrap cw = compWraps.get(i);
+ compSizes[i] = isHor ? cw.horSizes : cw.verSizes;
+ }
+ return compSizes;
+ }
+
+ /** Merges sizes and gaps together with Resize Constraints. For gaps {@link #GAP_RC_CONST} is used.
+ * @param resConstr One resize constriant for every row/component. Can be lesser in length and the last element should be used for missing elements.
+ * @param gapPush If the corresponding gap should be considered pushing and thus want to take free space if left over. Should be one more than resConstrs!
+ * @param minPrefMaxSizes The sizes (min/pref/max) for every row/component.
+ * @param gapSizes The gaps before and after each row/component packed in one double sized array.
+ * @param refSize The reference size to get the gap in pixels.
+ * @param parent The parent used to get the gap in pixels.
+ * @return A holder for the merged values.
+ */
+ private static FlowSizeSpec mergeSizesGapsAndResConstrs(ResizeConstraint[] resConstr, boolean[] gapPush, int[][] minPrefMaxSizes, int[][] gapSizes, int refSize, ContainerWrapper parent)
+ {
+ int[][] sizes = new int[(minPrefMaxSizes.length << 1) + 1][]; // Make room for gaps around.
+ ResizeConstraint[] resConstsInclGaps = new ResizeConstraint[sizes.length];
+
+ sizes[0] = gapSizes[0];
+ for (int i = 0, crIx = 1; i < minPrefMaxSizes.length; i++, crIx += 2) {
+
+ // Component bounds and constraints
+ resConstsInclGaps[crIx] = resConstr[i];
+ sizes[crIx] = minPrefMaxSizes[i];
+
+ sizes[crIx + 1] = gapSizes[i + 1];
+
+ if (sizes[crIx - 1] != null)
+ resConstsInclGaps[crIx - 1] = gapPush[i < gapPush.length ? i : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
+
+ if (i == (minPrefMaxSizes.length - 1) && sizes[crIx + 1] != null)
+ resConstsInclGaps[crIx + 1] = gapPush[(i + 1) < gapPush.length ? (i + 1) : gapPush.length - 1] ? GAP_RC_CONST_PUSH : GAP_RC_CONST;
+ }
+
+ // Check for null and set it to 0, 0, 0.
+ for (int i = 0; i < sizes.length; i++) {
+ if (sizes[i] == null)
+ sizes[i] = new int[3];
+ }
+
+ return new FlowSizeSpec(sizes, resConstsInclGaps);
+ }
+
+ private static final int[] mergeSizes(int[] oldValues, int[] newValues)
+ {
+ if (oldValues == null)
+ return newValues;
+
+ if (newValues == null)
+ return oldValues;
+
+ int[] ret = new int[oldValues.length];
+ for (int i = 0; i < ret.length; i++)
+ ret[i] = mergeSizes(oldValues[i], newValues[i], true);
+
+ return ret;
+ }
+
+ private static final int mergeSizes(int oldValue, int newValue, boolean toMax)
+ {
+ if (oldValue == LayoutUtil.NOT_SET || oldValue == newValue)
+ return newValue;
+
+ if (newValue == LayoutUtil.NOT_SET)
+ return oldValue;
+
+ return toMax != oldValue > newValue ? newValue : oldValue;
+ }
+
+ private static final int constrainSize(int s)
+ {
+ return s > 0 ? (s < LayoutUtil.INF ? s : LayoutUtil.INF) : 0;
+ }
+
+ private static final void correctMinMax(int s[])
+ {
+ if (s[LayoutUtil.MIN] > s[LayoutUtil.MAX])
+ s[LayoutUtil.MIN] = s[LayoutUtil.MAX]; // Since MAX is almost always explicitly set use tha
+
+ if (s[LayoutUtil.PREF] < s[LayoutUtil.MIN])
+ s[LayoutUtil.PREF] = s[LayoutUtil.MIN];
+
+ if (s[LayoutUtil.PREF] > s[LayoutUtil.MAX])
+ s[LayoutUtil.PREF] = s[LayoutUtil.MAX];
+ }
+
+ private static final class FlowSizeSpec
+ {
+ private final int[][] sizes;
+ private final ResizeConstraint[] resConstsInclGaps;
+
+ private FlowSizeSpec(int[][] sizes, ResizeConstraint[] resConstsInclGaps)
+ {
+ this.sizes = sizes;
+ this.resConstsInclGaps = resConstsInclGaps;
+ }
+
+ /**
+ * @param specs The specs for the columns or rows. Last index will be used of <code>fromIx + len</code> is greater than this array's length.
+ * @param targetSize The size to try to meat.
+ * @param defGrow The default grow weight if the specs does not have anyone that will grow. Comes from "push" in the CC.
+ * @param fromIx
+ * @param len
+ * @param sizeType
+ * @param eagerness How eager the algorithm should be to try to expand the sizes.
+ * <ul>
+ * <li>0 - Grow only rows/columns which has the <code>sizeType</code> set to be the containing components AND which has a grow weight &gt; 0.
+ * <li>1 - Grow only rows/columns which has the <code>sizeType</code> set to be the containing components AND which has a grow weight &gt; 0 OR unspecified.
+ * <li>2 - Grow all rows/columns that has a grow weight &gt; 0.
+ * <li>3 - Grow all rows/columns that has a grow weight &gt; 0 OR unspecified.
+ * </ul>
+ * @return The new size.
+ */
+ private final int expandSizes(DimConstraint[] specs, Float[] defGrow, int targetSize, int fromIx, int len, int sizeType, int eagerness)
+ {
+ ResizeConstraint[] resConstr = new ResizeConstraint[len];
+ int[][] sizesToExpand = new int[len][];
+ for (int i = 0; i < len; i++) {
+ int size = sizes[i + fromIx][sizeType];
+ sizesToExpand[i] = new int[] {size, size, sizes[i + fromIx][LayoutUtil.MAX]};
+
+ if (eagerness <= 1 && i % 2 == 0) { // // (i % 2 == 0) means only odd indexes, which is only rows/col indexes and not gaps.
+ int cIx = (i + fromIx - 1) >> 1;
+ DimConstraint spec = (DimConstraint) LayoutUtil.getIndexSafe(specs, cIx);
+
+ if ( (sizeType == LayoutUtil.MIN && spec.getSize() != null && spec.getSize().getMin() != null && spec.getSize().getMin().getUnit() != UnitValue.MIN_SIZE) ||
+ (sizeType == LayoutUtil.PREF && spec.getSize() != null && spec.getSize().getPreferred() != null && spec.getSize().getPreferred().getUnit() != UnitValue.PREF_SIZE)) {
+ continue;
+ }
+ }
+ resConstr[i] = (ResizeConstraint) LayoutUtil.getIndexSafe(resConstsInclGaps, i + fromIx);
+ }
+
+ Float[] growW = (eagerness == 1 || eagerness == 3) ? extractSubArray(specs, defGrow, fromIx, len): null;
+ int[] newSizes = LayoutUtil.calculateSerial(sizesToExpand, resConstr, growW, sizeType, targetSize);
+ int newSize = 0;
+
+ for (int i = 0; i < len; i++) {
+ int s = newSizes[i];
+ sizes[i + fromIx][sizeType] = s;
+ newSize += s;
+ }
+ return newSize;
+ }
+ }
+
+ private static Float[] extractSubArray(DimConstraint[] specs, Float[] arr, int ix, int len)
+ {
+ if (arr == null || arr.length < ix + len) {
+ Float[] growLastArr = new Float[len];
+
+ // Handle a group where some rows (first one/few and/or last one/few) are docks.
+ for (int i = ix + len - 1; i >= 0; i -= 2) {
+ int specIx = (i >> 1);
+ if (specs[specIx] != DOCK_DIM_CONSTRAINT) {
+ growLastArr[i - ix] = ResizeConstraint.WEIGHT_100;
+ return growLastArr;
+ }
+ }
+ return growLastArr;
+ }
+
+ Float[] newArr = new Float[len];
+ for (int i = 0; i < len; i++)
+ newArr[i] = arr[ix + i];
+ return newArr;
+ }
+
+ private static WeakHashMap[] PARENT_ROWCOL_SIZES_MAP = null;
+ static synchronized void putSizesAndIndexes(Object parComp, int[] sizes, int[] ixArr, boolean isRows)
+ {
+ if (PARENT_ROWCOL_SIZES_MAP == null) // Lazy since only if designing in IDEs
+ PARENT_ROWCOL_SIZES_MAP = new WeakHashMap[] {new WeakHashMap(4), new WeakHashMap(4)};
+
+ PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].put(parComp, new int[][] {ixArr, sizes});
+ }
+
+ static synchronized int[][] getSizesAndIndexes(Object parComp, boolean isRows)
+ {
+ if (PARENT_ROWCOL_SIZES_MAP == null)
+ return null;
+
+ return (int[][]) PARENT_ROWCOL_SIZES_MAP[isRows ? 0 : 1].get(parComp);
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/IDEUtil.java b/prototypes/miglayout/net/miginfocom/layout/IDEUtil.java
new file mode 100644
index 00000000..b52d37df
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/IDEUtil.java
@@ -0,0 +1,704 @@
+package net.miginfocom.layout;
+/*
+ * 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
+ */
+
+/** This class contains static methods to be used by IDE vendors to convert to and from String/API constraints.
+ * <p>
+ * <b>Note that {@link LayoutUtil#setDesignTime(boolean)} should be set to <code>true</code> for this class'
+ * methods to work.</b>
+ */
+public class IDEUtil
+{
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue ZERO = UnitValue.ZERO;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue TOP = UnitValue.TOP;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue LEADING = UnitValue.LEADING;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue LEFT = UnitValue.LEFT;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue CENTER = UnitValue.CENTER;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue TRAILING = UnitValue.TRAILING;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue RIGHT = UnitValue.RIGHT;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue BOTTOM = UnitValue.BOTTOM;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue LABEL = UnitValue.LABEL;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue INF = UnitValue.INF;
+
+ /** A direct reference to the corresponding value for predefined UnitValues in {@link UnitValue}.
+ */
+ public static final UnitValue BASELINE_IDENTITY = UnitValue.BASELINE_IDENTITY;
+
+ private final static String[] X_Y_STRINGS = new String[] {"x", "y", "x2", "y2"};
+
+ /** Returns the sizes of the rows and gaps for a container. * There will be two arrays returned [0] and [1].
+ * <p>
+ * The first array will be the indexes of the rows where indexes that
+ * are less than 30000 or larger than 30000 is docking rows. There might be extra docking rows that aren't
+ * visible but they always have size 0. Non docking indexes will probably always be 0, 1, 2, 3, etc..
+ * <p>
+ * The second array is the sizes of the form:<br>
+ * <code>[left inset][row size 1][gap 1][row size 2][gap 2][row size n][right inset]</code>.
+ * <p>
+ * The returned sizes will be the ones calculated in the last layout cycle.
+ * @param parentContainer The container to retuern the row sizes and gaps for. In Swing it will be a {@link java.awt.Container} and
+ * in SWT it will be a {@link org.eclipse.swt.widgets.Composite}.
+ * @return The sizes or <code>null</code> if {@link LayoutUtil#isDesignTime()} is <code>false</code> or
+ * <code>parentContainer</code> does not have a MigLayout layout manager.
+ * The returned sizes will be the ones calculated in the last layout cycle.
+ * @see LayoutUtil#isDesignTime()
+ */
+ public static int[][] getRowSizes(Object parentContainer)
+ {
+ return Grid.getSizesAndIndexes(parentContainer, true);
+ }
+
+ /** Returns the sizes of the columns and gaps for a container.
+ * There will be two arrays returned [0] and [1].
+ * <p>
+ * The first array will be the indexes of the columns where indexes that
+ * are less than 30000 or larger than 30000 is docking columns. There might be extra docking columns that aren't
+ * visible but they always have size 0. Non docking indexes will probably always be 0, 1, 2, 3, etc..
+ * <p>
+ * The second array is the sizes of the form:<br>
+ * <code>[top inset][column size 1][gap 1][column size 2][gap 2][column size n][bottom inset]</code>.
+ * <p>
+ * The returned sizes will be the ones calculated in the last layout cycle.
+ * @param parentContainer The container to retuern the column sizes and gaps for. In Swing it will be a {@link java.awt.Container} and
+ * in SWT it will be a {@link org.eclipse.swt.widgets.Composite}.
+ * @return The sizes and indexes or <code>null</code> if {@link LayoutUtil#isDesignTime()} is <code>false</code> or
+ * <code>parentContainer</code> does not have a MigLayout layout manager.
+ * The returned sizes will be the ones calculated in the last layout cycle.
+ * @see LayoutUtil#isDesignTime()
+ */
+ public static int[][] getColumnSizes(Object parentContainer)
+ {
+ return Grid.getSizesAndIndexes(parentContainer, false);
+ }
+
+ /** Returns the a constraint string that can be re-parsed to be the exact same AxisConstraint.
+ * @param ac The axis constraint to return as a constraint string.
+ * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
+ * as a String type (e.g. "flowx, gap rel, right").
+ * @param isCols The the constraint should be returned for columns rather than rows.
+ * @return A String. Never <code>null</code>.
+ */
+ public static final String getConstraintString(AC ac, boolean asAPI, boolean isCols)
+ {
+ StringBuffer sb = new StringBuffer(32);
+
+ DimConstraint[] dims = ac.getConstaints();
+ BoundSize defGap = isCols ? PlatformDefaults.getGridGapX() : PlatformDefaults.getGridGapY();
+
+ for (int i = 0; i < dims.length; i++) {
+ DimConstraint dc = dims[i];
+
+ addRowDimConstraintString(dc, sb, asAPI);
+
+ if (i < dims.length - 1) {
+ BoundSize gapAft = dc.getGapAfter();
+ BoundSize gapBefNext = dims[i + 1].getGapBefore();
+
+ if (gapAft != null && gapAft == gapBefNext && gapAft != defGap) {
+ if (asAPI) {
+ sb.append(".gap(\"").append(getBS(gapAft)).append("\")");
+ } else {
+ sb.append(getBS(gapAft));
+ }
+ } else {
+ if (asAPI)
+ sb.append(".gap()");
+ }
+ }
+ }
+
+ return sb.toString();
+ }
+
+ /** Adds the a constraint string that can be re-parsed to be the exact same DimConstraint.
+ * @param dc The layout constraint to return as a constraint string.
+ * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
+ * as a String type (e.g. "flowx, gap rel, right").
+ */
+ private static final void addRowDimConstraintString(DimConstraint dc, StringBuffer sb, boolean asAPI)
+ {
+ int gp = dc.getGrowPriority();
+
+ int firstComma = sb.length();
+
+ BoundSize size = dc.getSize();
+ if (size != null) {
+ if (asAPI) {
+ sb.append(".size(\"").append(getBS(size)).append("\")");
+ } else {
+ sb.append(',').append(getBS(size));
+ }
+ }
+
+ if (gp != 100) {
+ if (asAPI) {
+ sb.append(".growPrio(").append(gp).append("\")");
+ } else {
+ sb.append(",growprio ").append(gp);
+ }
+ }
+
+ Float gw = dc.getGrow();
+ if (gw != null) {
+ String g = gw.floatValue() != 100f ? LayoutUtil.floatToString(gw.floatValue()) : "";
+ if (asAPI) {
+ if (g.length() == 0) {
+ sb.append(".grow()");
+ } else {
+ sb.append(".grow(\"").append(g).append("\")");
+ }
+ } else {
+ sb.append(",grow").append(g.length() > 0 ? (" " + g) : "");
+ }
+ }
+
+ int sp = dc.getShrinkPriority();
+ if (sp != 100) {
+ if (asAPI) {
+ sb.append(".shrinkPrio(").append(sp).append("\")");
+ } else {
+ sb.append(",shrinkprio ").append(sp);
+ }
+ }
+
+ Float sw = dc.getShrink();
+ if (sw != null && sw.intValue() != 100) {
+ String s = LayoutUtil.floatToString(sw.floatValue());
+ if (asAPI) {
+ sb.append(".shrink(\"").append(s).append("\")");
+ } else {
+ sb.append(",shrink ").append(s);
+ }
+ }
+
+ String eg = dc.getEndGroup();
+ if (eg != null) {
+ if (asAPI) {
+ sb.append(".endGroup(\"").append(eg).append("\")");
+ } else {
+ sb.append(",endgroup ").append(eg);
+ }
+ }
+
+ String sg = dc.getSizeGroup();
+ if (sg != null) {
+ if (asAPI) {
+ sb.append(".sizeGroup(\"").append(sg).append("\")");
+ } else {
+ sb.append(",sizegroup ").append(sg);
+ }
+ }
+
+ UnitValue al = dc.getAlign();
+ if (al != null) {
+ if (asAPI) {
+ sb.append(".align(\"").append(getUV(al)).append("\")");
+ } else {
+ String s = getUV(al);
+ String alKw = (s.equals("top") || s.equals("bottom") || s.equals("left") || s.equals("label") ||
+ s.equals("leading") || s.equals("center") || s.equals("trailing") ||
+ s.equals("right") || s.equals("baseline")) ? "" : "align ";
+ sb.append(',').append(alKw).append(s);
+ }
+ }
+
+ if (dc.isNoGrid()) {
+ if (asAPI) {
+ sb.append(".noGrid()");
+ } else {
+ sb.append(",nogrid");
+ }
+ }
+
+ if (dc.isFill()) {
+ if (asAPI) {
+ sb.append(".fill()");
+ } else {
+ sb.append(",fill");
+ }
+ }
+
+ if (asAPI == false) {
+ if (sb.length() > firstComma) {
+ sb.setCharAt(firstComma, '[');
+ sb.append(']');
+ } else {
+ sb.append("[]");
+ }
+ }
+ }
+
+ /** Returns the a constraint string that can be re-parsed to be the exact same DimConstraint.
+ * @param dc The layout constraint to return as a constraint string.
+ * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
+ * as a String type (e.g. "flowx, gap rel, right").
+ * @param isHor The the DimConstraint is decoration something horizontal (column or x).
+ * @param noGrowAdd If <code>true</code> no grow constraints will be added.
+ * @return A constraint string. Never <code>null</code>.
+ */
+ private static final void addComponentDimConstraintString(DimConstraint dc, StringBuffer sb, boolean asAPI, boolean isHor, boolean noGrowAdd)
+ {
+ int gp = dc.getGrowPriority();
+ if (gp != 100) {
+ if (asAPI) {
+ sb.append(isHor ? ".growPrioX(" : ".growPrioY(").append(gp).append(')');
+ } else {
+ sb.append(isHor ? ",growpriox " : ",growprioy ").append(gp);
+ }
+ }
+
+ if (noGrowAdd == false) {
+ Float gw = dc.getGrow();
+ if (gw != null) {
+ String g = gw.floatValue() != 100f ? LayoutUtil.floatToString(gw.floatValue()) : "";
+ if (asAPI) {
+ sb.append(isHor ? ".growX(" : ".growY(").append(g).append(')');
+ } else {
+ sb.append(isHor ? ",growx" : ",growy").append(g.length() > 0 ? (" " + g) : "");
+ }
+ }
+ }
+
+ int sp = dc.getShrinkPriority();
+ if (sp != 100) {
+ if (asAPI) {
+ sb.append(isHor ? ".shrinkPrioX(" : ".shrinkPrioY(").append(sp).append(')');
+ } else {
+ sb.append(isHor ? ",shrinkpriox " : ",shrinkprioy ").append(sp);
+ }
+ }
+
+ Float sw = dc.getShrink();
+ if (sw != null && sw.intValue() != 100) {
+ String s = LayoutUtil.floatToString(sw.floatValue());
+ if (asAPI) {
+ sb.append(isHor ? ".shrinkX(" : ".shrinkY(").append(s).append(')');
+ } else {
+ sb.append(isHor ? ",shrinkx " : ",shrinky ").append(s);
+ }
+ }
+
+ String eg = dc.getEndGroup();
+ if (eg != null) {
+ if (asAPI) {
+ sb.append(isHor ? ".endGroupX(\"" : ".endGroupY(\"").append(eg).append("\")");
+ } else {
+ sb.append(isHor ? ",endgroupx " : ",endgroupy ").append(eg);
+ }
+ }
+
+ String sg = dc.getSizeGroup();
+ if (sg != null) {
+ if (asAPI) {
+ sb.append(isHor ? ".sizeGroupX(\"" : ".sizeGroupY(\"").append(sg).append("\")");
+ } else {
+ sb.append(isHor ? ",sizegroupx " : ",sizegroupy ").append(sg);
+ }
+ }
+
+ BoundSize size = dc.getSize();
+ if (size != null) {
+ if (size.getPreferred() == null) {
+ if (size.getMin() == null) {
+ if (asAPI) {
+ sb.append(isHor ? ".maxWidth(\"" : ".maxHeight(\"").append(getBS(size)).append("\")");
+ } else {
+ sb.append(isHor ? ",wmax " : ",hmax ").append(getBS(size));
+ }
+
+ } else if (size.getMax() == null) {
+ if (asAPI) {
+ sb.append(isHor ? ".minWidth(\"" : ".minHeight(\"").append(getBS(size)).append("\")");
+ } else {
+ sb.append(isHor ? ",wmin " : ",hmin ").append(getBS(size));
+ }
+ }
+ } else {
+ if (asAPI) {
+ sb.append(isHor ? ".width(\"" : ".height(\"").append(getBS(size)).append("\")");
+ } else {
+ sb.append(isHor ? ",width " : ",height ").append(getBS(size));
+ }
+ }
+ }
+
+ UnitValue al = dc.getAlign();
+ if (al != null) {
+ if (asAPI) {
+ sb.append(isHor ? ".alignX(\"" : ".alignY(\"").append(getUV(al)).append("\")");
+ } else {
+ sb.append(isHor ? ",alignx " : ",aligny ").append(getUV(al));
+ }
+ }
+
+ BoundSize gapBef = dc.getGapBefore();
+ BoundSize gapAft= dc.getGapAfter();
+ if (gapBef != null || gapAft != null) {
+ if (asAPI) {
+ sb.append(isHor ? ".gapX(\"" : ".gapY(\"").append(getBS(gapBef)).append("\", \"").append(getBS(gapAft)).append("\")");
+ } else {
+ sb.append(isHor ? ",gapx " : ",gapy ").append(getBS(gapBef)).append(' ').append(getBS(gapAft));
+ }
+ }
+ }
+
+ /** Returns the a constraint string that can be re-parsed to be the exact same LayoutConstraint.
+ * @param cc The component constraint to return as a constraint string.
+ * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
+ * as a String type (e.g. "flowx, gap rel, right").
+ * @return A String. Never <code>null</code>.
+ */
+ public static final String getConstraintString(CC cc, boolean asAPI)
+ {
+ StringBuffer sb = new StringBuffer(16);
+
+ if (cc.isNewline())
+ sb.append(asAPI ? ".newline()" : ",newline");
+
+ if (cc.isExternal())
+ sb.append(asAPI ? ".external()" : ",external");
+
+ Boolean flowX = cc.getFlowX();
+ if (flowX != null) {
+ if (asAPI) {
+ sb.append(flowX.booleanValue() ? ".flowX()" : ".flowY()");
+ } else {
+ sb.append(flowX.booleanValue() ? ",flowx" : ",flowy");
+ }
+ }
+
+ UnitValue[] pad = cc.getPadding();
+ if (pad != null) {
+ sb.append(asAPI ? ".pad(\"" : ",pad ");
+ for (int i = 0; i < pad.length; i++)
+ sb.append(getUV(pad[i])).append(i < pad.length - 1 ? " " : "");
+ if (asAPI)
+ sb.append("\")");
+ }
+
+ UnitValue[] pos = cc.getPos();
+ if (pos != null) {
+ if (cc.isBoundsInGrid()) {
+ for (int i = 0; i < 4; i++) {
+ if (pos[i] != null) {
+ if (asAPI) {
+ sb.append('.').append(X_Y_STRINGS[i]).append("(\"").append(getUV(pos[i])).append("\")");
+ } else {
+ sb.append(',').append(X_Y_STRINGS[i]).append(getUV(pos[i]));
+ }
+ }
+ }
+ } else {
+ sb.append(asAPI ? ".pos(\"" : ",pos ");
+ int iSz = (pos[2] != null || pos[3] != null) ? 4 : 2; // "pos x y" vs "pos x1 y1 x2 y2".
+ for (int i = 0; i < iSz; i++)
+ sb.append(getUV(pos[i])).append(i < iSz - 1 ? " " : "");
+
+ if (asAPI)
+ sb.append("\")");
+ }
+ }
+
+ String id = cc.getId();
+ if (id != null) {
+ if (asAPI) {
+ sb.append(".id(\"").append(id).append("\")");
+ } else {
+ sb.append(",id ").append(id);
+ }
+ }
+
+ String tag = cc.getTag();
+ if (tag != null) {
+ if (asAPI) {
+ sb.append(".tag(\"").append(tag).append("\")");
+ } else {
+ sb.append(",tag ").append(tag);
+ }
+ }
+
+ int hideMode = cc.getHideMode();
+ if (hideMode >= 0) {
+ if (asAPI) {
+ sb.append(".hideMode(").append(hideMode).append(')');
+ } else {
+ sb.append(",hideMode ").append(hideMode);
+ }
+ }
+
+ int skip = cc.getSkip();
+ if (skip > 0) {
+ if (asAPI) {
+ sb.append(".skip(").append(skip).append(')');
+ } else {
+ sb.append(",skip ").append(skip);
+ }
+ }
+
+ int split = cc.getSplit();
+ if (split > 1) {
+ String s = split == LayoutUtil.INF ? "" : String.valueOf(split);
+ if (asAPI) {
+ sb.append(".split(").append(s).append(')');
+ } else {
+ sb.append(",split ").append(s);
+ }
+ }
+
+ int cx = cc.getCellX();
+ int cy = cc.getCellY();
+ int spanX = cc.getSpanX();
+ int spanY = cc.getSpanY();
+ if (cx >= 0 && cy >= 0) {
+ if (asAPI) {
+ sb.append(".cell(").append(cx).append(", ").append(cy);
+ if (spanX > 1 || spanY > 1)
+ sb.append(", ").append(spanX).append(", ").append(spanY);
+ sb.append(')');
+ } else {
+ sb.append(",cell ").append(cx).append(' ').append(cy);
+ if (spanX > 1 || spanY > 1)
+ sb.append(' ').append(spanX).append(' ').append(spanY);
+ }
+ } else if (spanX > 1 || spanY > 1) {
+ if (spanX > 1 && spanY > 1) {
+ sb.append(asAPI ? ".span(" : ",span ").append(spanX).append(asAPI ? ", " : " ").append(spanY);
+ } else if (spanX > 1) {
+ sb.append(asAPI ? ".spanX(" : ",spanx ").append(spanX == LayoutUtil.INF ? "" : (String.valueOf(spanX)));
+ } else if (spanY > 1) {
+ sb.append(asAPI ? ".spanY(" : ",spany ").append(spanY == LayoutUtil.INF ? "" : (String.valueOf(spanY)));
+ }
+ if (asAPI)
+ sb.append(')');
+ }
+
+ Float pushX = cc.getPushX();
+ Float pushY = cc.getPushY();
+ if (pushX != null || pushY != null) {
+ if (pushX != null && pushY != null) {
+ sb.append(asAPI ? ".push(" : ",push ");
+ if (pushX != 100.0 || pushY != 100.0)
+ sb.append(pushX).append(asAPI ? ", " : " ").append(pushY);
+ } else if (pushX != null) {
+ sb.append(asAPI ? ".pushX(" : ",pushx ").append(pushX == 100 ? "" : (String.valueOf(pushX)));
+ } else if (pushY != null) {
+ sb.append(asAPI ? ".pushY(" : ",pushy ").append(pushY == 100 ? "" : (String.valueOf(pushY)));
+ }
+ if (asAPI)
+ sb.append(')');
+ }
+
+ int dock = cc.getDockSide();
+ if (dock >= 0) {
+ String ds = CC.DOCK_SIDES[dock];
+ if (asAPI) {
+ sb.append(".dock").append(Character.toUpperCase(ds.charAt(0))).append(ds.substring(1)).append("()");
+ } else {
+ sb.append(",").append(ds);
+ }
+ }
+
+ boolean noGrowAdd = cc.getHorizontal().getGrow() != null && cc.getHorizontal().getGrow().intValue() == 100 &&
+ cc.getVertical().getGrow() != null && cc.getVertical().getGrow().intValue() == 100;
+
+ addComponentDimConstraintString(cc.getHorizontal(), sb, asAPI, true, noGrowAdd);
+ addComponentDimConstraintString(cc.getVertical(), sb, asAPI, false, noGrowAdd);
+ if (noGrowAdd)
+ sb.append(asAPI ? ".grow()" : ",grow"); // Combine ".growX().growY()" into ".grow()".
+
+ if (cc.isWrap())
+ sb.append(asAPI ? ".wrap()" : ",wrap");
+
+ String s = sb.toString();
+ return s.length() == 0 || s.charAt(0) != ',' ? s : s.substring(1);
+ }
+
+ /** Returns the a constraint string that can be re-parsed to be the exact same LayoutConstraint.
+ * @param lc The layout constraint to return as a constraint string.
+ * @param asAPI If the returned string should be of API type (e.g. .flowX().gap("rel").align("right")) or
+ * as a String type (e.g. "flowx, gap rel, right").
+ * @return A String. Never <code>null</code>.
+ */
+ public static final String getConstraintString(LC lc, boolean asAPI)
+ {
+ StringBuffer sb = new StringBuffer(16);
+
+ if (lc.isFlowX() == false)
+ sb.append(asAPI ? ".flowY()" : ",flowy");
+
+ boolean fillX = lc.isFillX();
+ boolean fillY = lc.isFillY();
+ if (fillX || fillY) {
+ if (fillX == fillY) {
+ sb.append(asAPI ? ".fill()" : ",fill");
+ } else {
+ sb.append(asAPI ? (fillX ? ".fillX()" : ".fillY()") : (fillX ? ",fillx" : ",filly"));
+ }
+ }
+
+ Boolean leftToRight = lc.getLeftToRight();
+ if (leftToRight != null) {
+ if (asAPI) {
+ sb.append(".leftToRight(").append(leftToRight).append(')');
+ } else {
+ sb.append(leftToRight.booleanValue() ? ",ltr" : ",rtl");
+ }
+ }
+
+ if (lc.isTopToBottom() == false)
+ sb.append(asAPI ? ".bottomToTop()" : ",btt");
+
+ UnitValue[] insets = lc.getInsets();
+ if (insets != null) {
+ String cs = LayoutUtil.getCCString(insets);
+ if (cs != null) {
+ if (asAPI) {
+ sb.append(".insets(\"").append(cs).append("\")");
+ } else {
+ sb.append(",insets ").append(cs);
+ }
+ } else {
+ sb.append(asAPI ? ".insets(\"" : ",insets ");
+ for (int i = 0; i < insets.length; i++)
+ sb.append(getUV(insets[i])).append(i < insets.length - 1 ? " " : "");
+ if (asAPI)
+ sb.append("\")");
+ }
+ }
+
+ if (lc.isNoGrid())
+ sb.append(asAPI ? ".noGrid()" : ",nogrid");
+
+ if (lc.isVisualPadding() == false)
+ sb.append(asAPI ? ".noVisualPadding()" : ",novisualpadding");
+
+ int hideMode = lc.getHideMode();
+ if (hideMode > 0) {
+ if (asAPI) {
+ sb.append(".hideMode(").append(hideMode).append(')');
+ } else {
+ sb.append(",hideMode ").append(hideMode);
+ }
+ }
+
+ UnitValue alignX = lc.getAlignX();
+ UnitValue alignY = lc.getAlignY();
+ if (alignX != null || alignY != null) {
+ if (alignX != null && alignY != null) {
+ sb.append(asAPI ? ".align(\"" : ",align ").append(getUV(alignX)).append(' ').append(getUV(alignY));
+ } else if (alignX != null) {
+ sb.append(asAPI ? ".alignX(\"" : ",alignx ").append(getUV(alignX));
+ } else if (alignY != null) {
+ sb.append(asAPI ? ".alignY(\"" : ",aligny ").append(getUV(alignY));
+ }
+ if (asAPI)
+ sb.append("\")");
+ }
+
+ BoundSize gridGapX = lc.getGridGapX();
+ BoundSize gridGapY = lc.getGridGapY();
+ if (gridGapX != null || gridGapY != null) {
+ if (gridGapX != null && gridGapY != null) {
+ sb.append(asAPI ? ".gridGap(\"" : ",gap ").append(getBS(gridGapX)).append(' ').append(getBS(gridGapY));
+ } else if (gridGapX != null) {
+ sb.append(asAPI ? ".gridGapX(\"" : ",gapx ").append(getBS(gridGapX));
+ } else if (gridGapY != null) {
+ sb.append(asAPI ? ".gridGapY(\"" : ",gapy ").append(getBS(gridGapY));
+ }
+ if (asAPI)
+ sb.append("\")");
+ }
+
+ int wrapAfter = lc.getWrapAfter();
+ if (wrapAfter != LayoutUtil.INF) {
+ String ws = wrapAfter > 0 ? String.valueOf(wrapAfter) : "";
+ if (asAPI) {
+ sb.append(".wrap(").append(ws).append(')');
+ } else {
+ sb.append(",wrap ").append(ws);
+ }
+ }
+
+ int debugMillis = lc.getDebugMillis();
+ if (debugMillis > 0) {
+ if (asAPI) {
+ sb.append(".debug(").append(debugMillis).append(')');
+ } else {
+ sb.append(",debug ").append(debugMillis);
+ }
+ }
+
+ String s = sb.toString();
+ return s.length() == 0 || s.charAt(0) != ',' ? s : s.substring(1);
+ }
+
+ private static String getUV(UnitValue uv)
+ {
+ return uv != null ? uv.getConstraintString() : "null";
+ }
+
+ private static String getBS(BoundSize bs)
+ {
+ return bs != null ? bs.getConstraintString() : "null";
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java b/prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java
new file mode 100644
index 00000000..96367bc1
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/InCellGapProvider.java
@@ -0,0 +1,31 @@
+package net.miginfocom.layout;
+
+/** An interfance to implement if you want to decide the gaps between two types of components within the same cell.
+ * <p>
+ * E.g.:
+ *
+ * <pre>
+ * if (adjacentComp == null || adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.TOP)
+ * return null;
+ *
+ * boolean isHor = (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT);
+ *
+ * if (adjacentComp.getComponetType(false) == ComponentWrapper.TYPE_LABEL && comp.getComponetType(false) == ComponentWrapper.TYPE_TEXT_FIELD)
+ * return isHor ? UNRELATED_Y : UNRELATED_Y;
+ *
+ * return (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT) ? RELATED_X : RELATED_Y;
+ * </pre
+ */
+public interface InCellGapProvider
+{
+ /** Returns the default gap between two components that <b>are in the same cell</b>.
+ * @param comp The component that the gap is for. Never <code>null</code>.
+ * @param adjacentComp The adjacent component if any. May be <code>null</code>.
+ * @param adjacentSide What side the <code>adjacentComp</code> is on. {@link javax.swing.SwingUtilities#TOP} or
+ * {@link javax.swing.SwingUtilities#LEFT} or {@link javax.swing.SwingUtilities#BOTTOM} or {@link javax.swing.SwingUtilities#RIGHT}.
+ * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>.
+ * @param isLTR If it is left-to-right.
+ * @return The default gap between two components or <code>null</code> if there should be no gap.
+ */
+ public abstract BoundSize getDefaultGap(ComponentWrapper comp, ComponentWrapper adjacentComp, int adjacentSide, String tag, boolean isLTR);
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/LC.java b/prototypes/miglayout/net/miginfocom/layout/LC.java
new file mode 100644
index 00000000..82d33191
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/LC.java
@@ -0,0 +1,717 @@
+package net.miginfocom.layout;
+
+import java.io.*;
+/*
+ * 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
+ */
+
+/** Contains the constraints for an instance of the {@link LC} layout manager.
+ */
+public final class LC implements Externalizable
+{
+ // See the corresponding set/get method for documentation of the property!
+
+ private int wrapAfter = LayoutUtil.INF;
+
+ private Boolean leftToRight = null;
+
+ private UnitValue[] insets = null; // Never null elememts but if unset array is null
+
+ private UnitValue alignX = null, alignY = null;
+
+ private BoundSize gridGapX = null, gridGapY = null;
+
+ private int debugMillis = 0;
+
+ private int hideMode = 0;
+
+ private boolean noCache = false;
+
+ private boolean flowX = true;
+
+ private boolean fillX = false, fillY = false;
+
+ private boolean topToBottom = true;
+
+ private boolean noGrid = false;
+
+ private boolean visualPadding = true;
+
+ /** Empty constructor.
+ */
+ public LC()
+ {
+ }
+
+ // ************************************************************************
+ // * JavaBean get/set methods.
+ // ************************************************************************
+
+
+ /** If components have sizes or positions linked to the bounds of the parent in some way (as for instance the <code>"%"</code> unit has) the cache
+ * must be turned off for the panel. If components does not get the correct or expected size or position try to set this property to <code>true</code>.
+ * @return <code>true</code> means no cache and slightly slower layout.
+ */
+ public boolean isNoCache()
+ {
+ return noCache;
+ }
+
+ /** If components have sizes or positions linked to the bounds of the parent in some way (as for instance the <code>"%"</code> unit has) the cache
+ * must be turned off for the panel. If components does not get the correct or expected size or position try to set this property to <code>true</code>.
+ * @param b <code>true</code> means no cache and slightly slower layout.
+ */
+ public void setNoCache(boolean b)
+ {
+ this.noCache = b;
+ }
+
+ /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
+ * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
+ * by this property.
+ * @return The current alignment.
+ */
+ public final UnitValue getAlignX()
+ {
+ return alignX;
+ }
+
+ /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
+ * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
+ * by this property.
+ * @param uv The new alignment. Use {@link ConstraintParser#parseAlignKeywords(String, boolean)} to create the {@link UnitValue}. May be <code>null</code>.
+ */
+ public final void setAlignX(UnitValue uv)
+ {
+ this.alignX = uv;
+ }
+
+ /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
+ * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
+ * by this property.
+ * @return The current alignment.
+ */
+ public final UnitValue getAlignY()
+ {
+ return alignY;
+ }
+
+ /** If the laid out components' bounds in total is less than the final size of the container these align values will be used to align the components
+ * in the parent. <code>null</code> is default and that means top/left alignment. The relative distances between the components will not be affected
+ * by this property.
+ * @param uv The new alignment. Use {@link ConstraintParser#parseAlignKeywords(String, boolean)} to create the {@link UnitValue}. May be <code>null</code>.
+ */
+ public final void setAlignY(UnitValue uv)
+ {
+ this.alignY = uv;
+ }
+
+ /** If <code>&gt; 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code>&lt;= 0</code> (default).
+ * @return The current debug repaint interval.
+ */
+ public final int getDebugMillis()
+ {
+ return debugMillis;
+ }
+
+ /** If <code>&gt; 0</code> the debug decorations will be repainted every <code>millis</code>. No debug information if <code>&lt;= 0</code> (default).
+ * @param millis The new debug repaint interval.
+ */
+ public final void setDebugMillis(int millis)
+ {
+ this.debugMillis = millis;
+ }
+
+ /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
+ * @return <code>true</code> means fill. <code>false</code> is default.
+ */
+ public final boolean isFillX()
+ {
+ return fillX;
+ }
+
+ /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
+ * @param b <code>true</code> means fill. <code>false</code> is default.
+ */
+ public final void setFillX(boolean b)
+ {
+ this.fillX = b;
+ }
+
+ /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
+ * @return <code>true</code> means fill. <code>false</code> is default.
+ */
+ public final boolean isFillY()
+ {
+ return fillY;
+ }
+
+ /** If the layout should always claim the whole bounds of the laid out container even if the preferred size is smaller.
+ * @param b <code>true</code> means fill. <code>false</code> is default.
+ */
+ public final void setFillY(boolean b)
+ {
+ this.fillY = b;
+ }
+
+ /** The default flow direction. Normally (which is <code>true</code>) this is horizontal and that means that the "next" component
+ * will be put in the cell to the right (or to the left if left-to-right is false).
+ * @return <code>true</code> is the default flow horizontally.
+ * @see #setLeftToRight(Boolean)
+ */
+ public final boolean isFlowX()
+ {
+ return flowX;
+ }
+
+ /** The default flow direction. Normally (which is <code>true</code>) this is horizontal and that means that the "next" component
+ * will be put in the cell to the right (or to the left if left-to-right is false).
+ * @param b <code>true</code> is the default flow horizontally.
+ * @see #setLeftToRight(Boolean)
+ */
+ public final void setFlowX(boolean b)
+ {
+ this.flowX = b;
+ }
+
+ /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the columns in the grid.
+ * @return The default grid gap between columns in the grid. <code>null</code> if the platform default is used.
+ */
+ public final BoundSize getGridGapX()
+ {
+ return gridGapX;
+ }
+
+ /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the columns in the grid.
+ * @param x The default grid gap between columns in the grid. If <code>null</code> the platform default is used.
+ */
+ public final void setGridGapX(BoundSize x)
+ {
+ this.gridGapX = x;
+ }
+
+ /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the rows in the grid.
+ * @return The default grid gap between rows in the grid. <code>null</code> if the platform default is used.
+ */
+ public final BoundSize getGridGapY()
+ {
+ return gridGapY;
+ }
+
+ /** If non-<code>null</code> (<code>null</code> is default) these value will be used as the default gaps between the rows in the grid.
+ * @param y The default grid gap between rows in the grid. If <code>null</code> the platform default is used.
+ */
+ public final void setGridGapY(BoundSize y)
+ {
+ this.gridGapY = y;
+ }
+
+ /** How a component that is hidden (not visible) should be treated by default.
+ * @return The mode:<br>
+ * 0 == Normal. Bounds will be caclulated as if the component was visible.<br>
+ * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
+ * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
+ * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
+ */
+ public final int getHideMode()
+ {
+ return hideMode;
+ }
+
+ /** How a component that is hidden (not visible) should be treated.
+ * @param mode The mode:<br>
+ * 0 == Normal. Bounds will be caclulated as if the component was visible.<br>
+ * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
+ * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
+ * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
+ */
+ public final void setHideMode(int mode)
+ {
+ if (mode < 0 || mode > 3)
+ throw new IllegalArgumentException("Wrong hideMode: " + mode);
+
+ this.hideMode = mode;
+ }
+
+ /** The insets for the layed out panel. The insets will be an empty space around the components in the panel. <code>null</code> values
+ * means that the default panel insets for the platform is used. See {@link PlatformDefaults#setDialogInsets(net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue)}.
+ * @return The insets. Of length 4 (top, left, bottom, right) or <code>null</code>. The elements (1 to 4) may be <code>null</code>. The array is a copy and can be used freely.
+ * @see net.miginfocom.layout.ConstraintParser#parseInsets(String, boolean)
+ */
+ public final UnitValue[] getInsets()
+ {
+ return insets != null ? new UnitValue[] {insets[0], insets[1], insets[2], insets[3]} : null;
+ }
+
+ /** The insets for the layed out panel. The insets will be an empty space around the components in the panel. <code>null</code> values
+ * means that the default panel insets for the platform is used. See {@link PlatformDefaults#setDialogInsets(net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue, net.miginfocom.layout.UnitValue)}.
+ * @param ins The new insets. Must be of length 4 (top, left, bottom, right) or <code>null</code>. The elements (1 to 4) may be <code>null</code> to use
+ * the platform default for that side. The array is copied for storage.
+ * @see net.miginfocom.layout.ConstraintParser#parseInsets(String, boolean)
+ */
+ public final void setInsets(UnitValue[] ins)
+ {
+ this.insets = ins != null ? new UnitValue[] {ins[0], ins[1], ins[2], ins[3]} : null;
+ }
+
+ /** If the layout should be forced to be left-to-right or right-to-left. A value of <code>null</code> is default and
+ * means that this will be picked up from the {@link java.util.Locale} that the container being layed out is reporting.
+ * @return <code>Boolean.TRUE</code> if force left-to-right. <code>Boolean.FALSE</code> if force tight-to-left. <code>null</code>
+ * for the default "let the current Locale decide".
+ */
+ public final Boolean getLeftToRight()
+ {
+ return leftToRight;
+ }
+
+ /** If the layout should be forced to be left-to-right or right-to-left. A value of <code>null</code> is default and
+ * means that this will be picked up from the {@link java.util.Locale} that the container being layed out is reporting.
+ * @param b <code>Boolean.TRUE</code> to force left-to-right. <code>Boolean.FALSE</code> to force tight-to-left. <code>null</code>
+ * for the default "let the current Locale decide".
+ */
+ public final void setLeftToRight(Boolean b)
+ {
+ this.leftToRight = b;
+ }
+
+ /** If the whole layout should be non grid based. It is the same as setting the "nogrid" property on every row/column in the grid.
+ * @return <code>true</code> means not grid based. <code>false</code> is default.
+ */
+ public final boolean isNoGrid()
+ {
+ return noGrid;
+ }
+
+ /** If the whole layout should be non grid based. It is the same as setting the "nogrid" property on every row/column in the grid.
+ * @param b <code>true</code> means no grid. <code>false</code> is default.
+ */
+ public final void setNoGrid(boolean b)
+ {
+ this.noGrid = b;
+ }
+
+ /** If the layout should go from the default top-to-bottom in the grid instead of the optinal bottom-to-top.
+ * @return <code>true</code> for the default top-to-bottom.
+ */
+ public final boolean isTopToBottom()
+ {
+ return topToBottom;
+ }
+
+ /** If the layout should go from the default top-to-bottom in the grid instead of the optinal bottom-to-top.
+ * @param b <code>true</code> for the default top-to-bottom.
+ */
+ public final void setTopToBottom(boolean b)
+ {
+ this.topToBottom = b;
+ }
+
+ /** If visual padding should be automatically used and compensated for by this layout instance.
+ * @return <code>true</code> if visual padding.
+ */
+ public final boolean isVisualPadding()
+ {
+ return visualPadding;
+ }
+
+ /** If visual padding should be automatically used and compensated for by this layout instance.
+ * @param b <code>true</code> turns on visual padding.
+ */
+ public final void setVisualPadding(boolean b)
+ {
+ this.visualPadding = b;
+ }
+
+ /** Returns after what cell the grid should always auto wrap.
+ * @return After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the
+ * {@link net.miginfocom.layout.AC} is used. <code>LayoutUtil.INF</code> is used for no auto wrap.
+ */
+ public final int getWrapAfter()
+ {
+ return wrapAfter;
+ }
+
+ /** Sets after what cell the grid should always auto wrap.
+ * @param count After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the
+ * {@link net.miginfocom.layout.AC} is used. <code>LayoutUtil.INF</code> is used for no auto wrap.
+ */
+ public final void setWrapAfter(int count)
+ {
+ this.wrapAfter = count;
+ }
+
+ // ************************************************************************
+ // * Builder methods.
+ // ************************************************************************
+
+ /** Sets a wrap after the number of columns/rows that is defined in the {@link net.miginfocom.layout.AC}.
+ * <p>
+ * Same functionality as {@link #setWrapAfter(int 0)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC wrap()
+ {
+ setWrapAfter(0);
+ return this;
+ }
+
+ /** Same functionality as {@link #setWrapAfter(int)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param count After what cell the grid should always auto wrap. If <code>0</code> the number of columns/rows in the
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC wrapAfter(int count)
+ {
+ setWrapAfter(count);
+ return this;
+ }
+
+ /** Same functionality as {@link #setNoCache(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC noCache()
+ {
+ setNoCache(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setFlowX(boolean false)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC flowY()
+ {
+ setFlowX(false);
+ return this;
+ }
+
+ /** Same functionality as {@link #setFlowX(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC flowX()
+ {
+ setFlowX(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setFillX(boolean true)} and {@link #setFillY(boolean true)} conmbined.T his method returns
+ * <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC fill()
+ {
+ setFillX(true);
+ setFillY(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setFillX(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC fillX()
+ {
+ setFillX(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setFillY(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC fillY()
+ {
+ setFillY(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setLeftToRight(Boolean)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param b <code>true</code> for forcing left-to-right. <code>false</code> for forcing right-to-left.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC leftToRight(boolean b)
+ {
+ setLeftToRight(b ? Boolean.TRUE : Boolean.FALSE); // Not .valueOf du to retroweaver...
+ return this;
+ }
+
+ /** Same functionality as {@link #setTopToBottom(boolean false)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC bottomToTop()
+ {
+ setTopToBottom(false);
+ return this;
+ }
+
+ /** Same functionality as {@link #setNoGrid(boolean true)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC noGrid()
+ {
+ setNoGrid(true);
+ return this;
+ }
+
+ /** Same functionality as {@link #setVisualPadding(boolean false)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ */
+ public final LC noVisualPadding()
+ {
+ setVisualPadding(false);
+ return this;
+ }
+
+ /** Sets the same inset (expressed as a <code>UnitValue</code>, e.g. "10px" or "20mm") all around.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param allSides The unit value to set for all sides. May be <code>null</code> which means that the default panel insets
+ * for the platform is used.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setInsets(UnitValue[])
+ */
+ public final LC insetsAll(String allSides)
+ {
+ UnitValue insH = ConstraintParser.parseUnitValue(allSides, true);
+ UnitValue insV = ConstraintParser.parseUnitValue(allSides, false);
+ insets = new UnitValue[] {insV, insH, insV, insH}; // No setter to avoid copy again
+ return this;
+ }
+
+ /** Same functionality as <code>setInsets(ConstraintParser.parseInsets(s, true))</code>. This method returns <code>this</code>
+ * for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param s The string to parse. E.g. "10 10 10 10" or "20". If less than 4 groups the last will be used for the missing.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setInsets(UnitValue[])
+ */
+ public final LC insets(String s)
+ {
+ insets = ConstraintParser.parseInsets(s, true);
+ return this;
+ }
+
+ /** Sets the different insets (expressed as a <code>UnitValue</code>s, e.g. "10px" or "20mm") for the corresponding sides.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param top The top inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
+ * side for the platform will be used.
+ * @param left The left inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
+ * side for the platform will be used.
+ * @param bottom The bottom inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
+ * side for the platform will be used.
+ * @param right The right inset. E.g. "10px" or "10mm" or "related". May be <code>null</code> in which case the default inset for this
+ * side for the platform will be used.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setInsets(UnitValue[])
+ */
+ public final LC insets(String top, String left, String bottom, String right)
+ {
+ insets = new UnitValue[] { // No setter to avoid copy again
+ ConstraintParser.parseUnitValue(top, false),
+ ConstraintParser.parseUnitValue(left, true),
+ ConstraintParser.parseUnitValue(bottom, false),
+ ConstraintParser.parseUnitValue(right, true)};
+ return this;
+ }
+
+ /** Same functionality as <code>setAlignX(ConstraintParser.parseUnitValueOrAlign(unitValue, true))</code> only this method returns <code>this</code>
+ * for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param align The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setAlignX(UnitValue)
+ */
+ public final LC alignX(String align)
+ {
+ setAlignX(ConstraintParser.parseUnitValueOrAlign(align, true, null));
+ return this;
+ }
+
+ /** Same functionality as <code>setAlignY(ConstraintParser.parseUnitValueOrAlign(align, false))</code> only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param align The align keyword or for instance "100px". E.g "top" or "bottom".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setAlignY(UnitValue)
+ */
+ public final LC alignY(String align)
+ {
+ setAlignY(ConstraintParser.parseUnitValueOrAlign(align, false, null));
+ return this;
+ }
+
+ /** Sets both the alignX and alignY as the same time.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param ax The align keyword or for instance "100px". E.g "left", "right", "leading" or "trailing".
+ * @param ay The align keyword or for instance "100px". E.g "top" or "bottom".
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #alignX(String)
+ * @see #alignY(String)
+ */
+ public final LC align(String ax, String ay)
+ {
+ if (ax != null)
+ alignX(ax);
+
+ if (ay != null)
+ alignY(ay);
+
+ return this;
+ }
+
+ /** Same functionality as <code>setGridGapX(ConstraintParser.parseBoundSize(boundsSize, true, true))</code> only this method
+ * returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param boundsSize The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
+ * <code>"50:100:200"</code> or <code>"100px"</code>.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setGridGapX(BoundSize)
+ */
+ public final LC gridGapX(String boundsSize)
+ {
+ setGridGapX(ConstraintParser.parseBoundSize(boundsSize, true, true));
+ return this;
+ }
+
+ /** Same functionality as <code>setGridGapY(ConstraintParser.parseBoundSize(boundsSize, true, false))</code> only this method
+ * returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param boundsSize The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
+ * <code>"50:100:200"</code> or <code>"100px"</code>.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setGridGapY(BoundSize)
+ */
+ public final LC gridGapY(String boundsSize)
+ {
+ setGridGapY(ConstraintParser.parseBoundSize(boundsSize, true, false));
+ return this;
+ }
+
+ /** Sets both grid gaps at the same time. see {@link #gridGapX(String)} and {@link #gridGapY(String)}.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param gapx The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
+ * <code>"50:100:200"</code> or <code>"100px"</code>.
+ * @param gapy The <code>BoundSize</code> of the gap. This is a minimum and/or preferred and/or maximum size. E.g.
+ * <code>"50:100:200"</code> or <code>"100px"</code>.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #gridGapX(String)
+ * @see #gridGapY(String)
+ */
+ public final LC gridGap(String gapx, String gapy)
+ {
+ if (gapx != null)
+ gridGapX(gapx);
+
+ if (gapy != null)
+ gridGapY(gapy);
+
+ return this;
+ }
+
+ /** Same functionality as {@link #setDebugMillis(int repaintMillis)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param repaintMillis The new debug repaint interval.
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setDebugMillis(int)
+ */
+ public final LC debug(int repaintMillis)
+ {
+ setDebugMillis(repaintMillis);
+ return this;
+ }
+
+ /** Same functionality as {@link #setHideMode(int mode)} only this method returns <code>this</code> for chaining multiple calls.
+ * <p>
+ * For a more thorough explanation of what this constraint does see the white paper or cheat Sheet at www.migcomponents.com.
+ * @param mode The mode:<br>
+ * 0 == Normal. Bounds will be caclulated as if the component was visible.<br>
+ * 1 == If hidden the size will be 0, 0 but the gaps remain.<br>
+ * 2 == If hidden the size will be 0, 0 and gaps set to zero.<br>
+ * 3 == If hidden the component will be disregarded completely and not take up a cell in the grid..
+ * @return <code>this</code> so it is possible to chain calls. E.g. <code>new LayoutConstraint().noGrid().gap().fill()</code>.
+ * @see #setHideMode(int)
+ */
+ public final LC hideMode(int mode)
+ {
+ setHideMode(mode);
+ return this;
+ }
+
+ // ************************************************
+ // 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() == LC.class)
+ LayoutUtil.writeAsXML(out, this);
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java b/prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java
new file mode 100644
index 00000000..f0855701
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/LayoutCallback.java
@@ -0,0 +1,48 @@
+package net.miginfocom.layout;
+
+import net.miginfocom.layout.UnitValue;
+import net.miginfocom.layout.ComponentWrapper;
+import net.miginfocom.layout.BoundSize;
+
+/** A class to extend if you want to provide more control over where a component is placed or the size of it.
+ * <p>
+ * Note! Returned arrays from this class will never be altered. This means that caching of arrays in these methods
+ * is OK.
+ */
+public abstract class LayoutCallback
+{
+ /** Returns a position similar to the "pos" the component constraint.
+ * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT).
+ * <b>Should not be altered.</b>
+ * @return The [x, y, x2, y2] as explained in the documentation for "pos". If <code>null</code>
+ * is returned nothing is done and this is the default.
+ * @see UnitValue
+ * @see net.miginfocom.layout.ConstraintParser#parseUnitValue(String, boolean)
+ */
+ public UnitValue[] getPosition(ComponentWrapper comp)
+ {
+ return null;
+ }
+
+ /** Returns a size similar to the "width" and "height" in the component constraint.
+ * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT).
+ * <b>Should not be altered.</b>
+ * @return The [width, height] as explained in the documentation for "width" and "height". If <code>null</code>
+ * is returned nothing is done and this is the default.
+ * @see net.miginfocom.layout.BoundSize
+ * @see net.miginfocom.layout.ConstraintParser#parseBoundSize(String, boolean, boolean)
+ */
+ public BoundSize[] getSize(ComponentWrapper comp)
+ {
+ return null;
+ }
+
+ /** A last minute change of the bounds. The bound for the layout cycle has been set and you can correct there
+ * after any set of rules you like.
+ * @param comp The component wrapper that holds the actual component (JComponent is Swing and Control in SWT).
+ * <b>Should not be altered.</b>
+ */
+ public void correctBounds(ComponentWrapper comp)
+ {
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java b/prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java
new file mode 100644
index 00000000..05d0633a
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/LayoutUtil.java
@@ -0,0 +1,532 @@
+package net.miginfocom.layout;
+
+import java.beans.*;
+import java.io.*;
+import java.util.IdentityHashMap;
+import java.util.TreeSet;
+import java.util.WeakHashMap;
+/*
+ * 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
+ */
+
+/** A utility class that has only static helper methods.
+ */
+public final class LayoutUtil
+{
+ /** A substitute value for aa really large value. Integer.MAX_VALUE is not used since that means a lot of defensive code
+ * for potential overflow must exist in many places. This value is large enough for being unresonable yet it is hard to
+ * overflow.
+ */
+ static final int INF = (Integer.MAX_VALUE >> 10) - 100; // To reduce likelyhood of overflow errors when calculating.
+
+ /** Tag int for a value that in considered "not set". Used as "null" element in int arays.
+ */
+ static final int NOT_SET = Integer.MIN_VALUE + 12346; // Magic value...
+
+ // Index for the different sizes
+ public static final int MIN = 0;
+ public static final int PREF = 1;
+ public static final int MAX = 2;
+
+ private static WeakHashMap<Object, String> CR_MAP = null;
+ private static WeakHashMap<Object, Boolean> DT_MAP = null; // The Containers that have design time. Value not used.
+ private static int eSz = 15;
+
+ private LayoutUtil()
+ {
+ }
+
+ /** Returns the current version of MiG Layout.
+ * @return The current version of MiG Layout.
+ */
+ public static String getVersion()
+ {
+ return "3.0.3";
+ }
+
+ /** Sets if design time is turned on for a Container in {@link ContainerWrapper}.
+ * @param cw The container to set design time for. <code>null</code> is legal and can be used as
+ * a key to turn on/off design time "in general". Note though that design time "in general" is
+ * always on as long as there is at least one ContainerWrapper with design time.
+ * <p>
+ * <strong>If this method has not ever been called it will default to what
+ * <code>Beans.isDesignTime()</code> returns.</strong> This means that if you call
+ * this method you indicate that you will take responsibility for the design time value.
+ * @param b <code>true</code> means design time on.
+ */
+ public static void setDesignTime(ContainerWrapper cw, boolean b)
+ {
+ if (DT_MAP == null)
+ DT_MAP = new WeakHashMap<Object, Boolean>();
+
+ DT_MAP.put((cw != null ? cw.getComponent() : null), new Boolean(b));
+ }
+
+ /** Returns if design time is turned on for a Container in {@link ContainerWrapper}.
+ * @param cw The container to set design time for. <code>null</code> is legal will return <code>true</code>
+ * if there is at least one <code>ContainerWrapper</code> (or <code>null</code>) that have design time
+ * turned on.
+ * @return If design time is set for <code>cw</code>.
+ */
+ public static boolean isDesignTime(ContainerWrapper cw)
+ {
+ if (DT_MAP == null)
+ return Beans.isDesignTime();
+
+ Boolean b = DT_MAP.get(cw != null ? cw.getComponent() : null);
+ return b != null ? b.booleanValue() : false;
+ }
+
+ /** The size of an empty row or columns in a grid during design time.
+ * @return The number of pixels. Default is 15.
+ */
+ public static int getDesignTimeEmptySize()
+ {
+ return eSz;
+ }
+
+ /** The size of an empty row or columns in a grid during design time.
+ * @param pixels The number of pixels. Default is 15.
+ */
+ public static void setDesignTimeEmptySize(int pixels)
+ {
+ eSz = pixels;
+ }
+
+ /** Associates <code>con</code> with the creation string <code>s</code>. The <code>con</code> object should
+ * probably have an equals method that compares identities or <code>con</code> objects that .equals() will only
+ * be able to have <b>one</b> creation string.
+ * <p>
+ * If {@link LayoutUtil#isDesignTime(ContainerWrapper)} returns <code>false</code> the method does nothing.
+ * @param con The object. if <code>null</code> the method does nothing.
+ * @param s The creation string. if <code>null</code> the method does nothing.
+ */
+ static void putCCString(Object con, String s)
+ {
+ if (s != null && con != null && isDesignTime(null)) {
+ if (CR_MAP == null)
+ CR_MAP = new WeakHashMap<Object, String>(64);
+
+ CR_MAP.put(con, s);
+ }
+ }
+
+ /** Sets/add the persistence delagates to be used for a class.
+ * @param c The class to set the registered deligate for.
+ * @param del The new deligate or <code>null</code> to erase to old one.
+ */
+ static synchronized void setDelegate(Class c, PersistenceDelegate del)
+ {
+ try {
+ Introspector.getBeanInfo(c).getBeanDescriptor().setValue("persistenceDelegate", del);
+ } catch (Exception e1) {
+ }
+ }
+
+ /** Returns strings set with {@link #putCCString(Object, String)} or <code>null</code> if nothing is associated or
+ * {@link LayoutUtil#isDesignTime(ContainerWrapper)} returns <code>false</code>.
+ * @param con The constraitn object.
+ * @return The creation string or <code>null</code> if nothing is registered with the <code>con</code> object.
+ */
+ static String getCCString(Object con)
+ {
+ return CR_MAP != null ? CR_MAP.get(con) : null;
+ }
+
+ static void throwCC()
+ {
+ throw new IllegalStateException("setStoreConstraintData(true) must be set for strings to be saved.");
+ }
+
+ /** Takes a number on min/preferred/max sizes and resize constraints and returns the calculated sizes which sum should add up to <code>bounds</code>. Whether the sum
+ * will actually equal <code>bounds</code> is dependent om the pref/max sizes and resise constraints.
+ * @param sizes [ix],[MIN][PREF][MAX]. Grid.CompWrap.NOT_SET will be treated as N/A or 0. A "[MIN][PREF][MAX]" array with null elements will be interpreted as very flexible (no bounds)
+ * but if the array itself is null it will not get any size.
+ * @param resConstr Elements can be <code>null</code> and the whole array can be <code>null</code>. <code>null</code> means that the size will not be flexible at all.
+ * Can have length less than <code>sizes</code> in which case the last element should be used for the elements missing.
+ * @param defGrowWeights If there is no grow weight for a resConstr the correspinding value of this array is used.
+ * These forced resConstr will be grown last though and only if needed to fill to the bounds.
+ * @param startSizeType The initial size to use. E.g. {@link net.miginfocom.layout.LayoutUtil#MIN}.
+ * @param bounds To use for relative sizes.
+ * @return The sizes. Array length will match <code>sizes</code>.
+ */
+ static int[] calculateSerial(int[][] sizes, ResizeConstraint[] resConstr, Float[] defGrowWeights, int startSizeType, int bounds)
+ {
+ float[] lengths = new float[sizes.length]; // heights/widths that are set
+ float usedLength = 0.0f;
+
+ // Give all preferred size to start with
+ for (int i = 0; i < sizes.length; i++) {
+ if (sizes[i] != null) {
+ float len = sizes[i][startSizeType] != NOT_SET ? sizes[i][startSizeType] : 0;
+ int newSizeBounded = getBrokenBoundary(len, sizes[i][MIN], sizes[i][MAX]);
+ if (newSizeBounded != NOT_SET)
+ len = newSizeBounded;
+
+ usedLength += len;
+ lengths[i] = len;
+ }
+ }
+
+ int useLengthI = Math.round(usedLength);
+ if (useLengthI != bounds && resConstr != null) {
+ boolean isGrow = useLengthI < bounds;
+
+ // Create a Set with the available priorities
+ TreeSet<Integer> prioList = new TreeSet<Integer>();
+ for (int i = 0; i < sizes.length; i++) {
+ ResizeConstraint resC = (ResizeConstraint) getIndexSafe(resConstr, i);
+ if (resC != null)
+ prioList.add(new Integer(isGrow ? resC.growPrio : resC.shrinkPrio));
+ }
+ Integer[] prioIntegers = prioList.toArray(new Integer[prioList.size()]);
+
+ for (int force = 0; force <= ((isGrow && defGrowWeights != null) ? 1 : 0); force++) { // Run twice if defGrow and the need for growing.
+ for (int pr = prioIntegers.length - 1; pr >= 0; pr--) {
+ int curPrio = prioIntegers[pr].intValue();
+
+ float totWeight = 0f;
+ Float[] resizeWeight = new Float[sizes.length];
+ for (int i = 0; i < sizes.length; i++) {
+ if (sizes[i] == null) // if no min/pref/max size at all do not grow or shrink.
+ continue;
+
+ ResizeConstraint resC = (ResizeConstraint) getIndexSafe(resConstr, i);
+ if (resC != null) {
+ int prio = isGrow ? resC.growPrio : resC.shrinkPrio;
+
+ if (curPrio == prio) {
+ if (isGrow) {
+ resizeWeight[i] = (force == 0 || resC.grow != null) ? resC.grow : (defGrowWeights[i < defGrowWeights.length ? i : defGrowWeights.length - 1]);
+ } else {
+ resizeWeight[i] = resC.shrink;
+ }
+ if (resizeWeight[i] != null)
+ totWeight += resizeWeight[i].floatValue();
+ }
+ }
+ }
+
+ if (totWeight > 0f) {
+ boolean hit;
+ do {
+ float toChange = bounds - usedLength;
+ hit = false;
+ float changedWeight = 0f;
+ for (int i = 0; i < sizes.length && totWeight > 0.0001f; i++) {
+
+ Float weight = resizeWeight[i];
+ if (weight != null) {
+ float sizeDelta = toChange * weight.floatValue() / totWeight;
+ float newSize = lengths[i] + sizeDelta;
+
+ if (sizes[i] != null) {
+ int newSizeBounded = getBrokenBoundary(newSize, sizes[i][MIN], sizes[i][MAX]);
+ if (newSizeBounded != NOT_SET) {
+ resizeWeight[i] = null;
+ hit = true;
+ changedWeight += weight.floatValue();
+ newSize = newSizeBounded;
+ sizeDelta = newSize - lengths[i];
+ }
+ }
+
+ lengths[i] = newSize;
+ usedLength += sizeDelta;
+ }
+ }
+ totWeight -= changedWeight;
+ } while (hit);
+ }
+ }
+ }
+ }
+ return roundSizes(lengths);
+ }
+
+ static Object getIndexSafe(Object[] arr, int ix)
+ {
+ return arr != null ? arr[ix < arr.length ? ix : arr.length - 1] : null;
+ }
+
+ /** Returns the broken boundary if <code>sz</code> is outside the boundaries <code>lower</code> or <code>upper</code>. If both boundaries
+ * are broken, the lower one is returned. If <code>sz</code> is &lt; 0 then <code>new Float(0f)</code> is returned so that no sizes can be
+ * negative.
+ * @param sz The size to check
+ * @param lower The lower boundary (or <code>null</code> fo no boundary).
+ * @param upper The upper boundary (or <code>null</code> fo no boundary).
+ * @return The broken boundary or <code>null</code> if no boundary was broken.
+ */
+ private static int getBrokenBoundary(float sz, int lower, int upper)
+ {
+ if (lower != NOT_SET) {
+ if (sz < lower)
+ return new Integer(lower);
+ } else if (sz < 0f) {
+ return new Integer(0);
+ }
+
+ if (upper != NOT_SET && sz > upper)
+ return new Integer(upper);
+
+ return NOT_SET;
+ }
+
+
+ static int sum(int[] terms, int start, int len)
+ {
+ int s = 0;
+ for (int i = start, iSz = start + len; i < iSz; i++)
+ s += terms[i];
+ return s;
+ }
+
+ static int sum(int[] terms)
+ {
+ return sum(terms, 0, terms.length);
+ }
+
+ public static int getSizeSafe(int[] sizes, int sizeType)
+ {
+ if (sizes == null || sizes[sizeType] == NOT_SET)
+ return sizeType == MAX ? LayoutUtil.INF : 0;
+ return sizes[sizeType];
+ }
+
+ static BoundSize derive(BoundSize bs, UnitValue min, UnitValue pref, UnitValue max)
+ {
+ if (bs == null)
+ return new BoundSize(min, pref, max, null);
+
+ return new BoundSize(
+ min != null ? min : bs.getMin(),
+ pref != null ? pref : bs.getPreferred(),
+ max != null ? max : bs.getMax(), null);
+ }
+
+ /** Returns if left-to-right orientation is used. If not set explicitly in the layout constraints the Locale
+ * of the <code>parent</code> is used.
+ * @param lc The constraint if there is one. Can be <code>null</code>.
+ * @param container The parent that may be used to get the left-to-right if ffc does not specify this.
+ * @return If left-to-right orientation is currently used.
+ */
+ public final static boolean isLeftToRight(LC lc, ContainerWrapper container)
+ {
+ if (lc != null && lc.getLeftToRight() != null)
+ return lc.getLeftToRight().booleanValue();
+
+ return container == null || container.isLeftToRight();
+ }
+
+ /** Round a number of float sizes into int sizes so that the total length match up
+ * @param sizes The sizes to round
+ * @return An array of equal length as <code>sizes</code>.
+ */
+ static int[] roundSizes(float[] sizes)
+ {
+ int[] retInts = new int[sizes.length];
+ float posD = 0;
+
+ for (int i = 0; i < retInts.length; i++) {
+ int posI = (int) (posD + 0.5f);
+
+ posD += sizes[i];
+
+ retInts[i] = (int) (posD + 0.5f) - posI;
+ }
+
+ return retInts;
+ }
+
+ /** Safe equals. null == null, but null never equals anything else.
+ * @param o1 The first object. May be <code>null</code>.
+ * @param o2 The second object. May be <code>null</code>.
+ * @return Returns <code>true</code> if <code>o1</code> and <code>o2</code> are equal (using .equals()) or both are <code>null</code>.
+ */
+ static final boolean equals(Object o1, Object o2)
+ {
+ return o1 == o2 || (o1 != null && o2 != null && o1.equals(o2));
+ }
+
+// static int getBaselineCorrect(Component comp)
+// {
+// Dimension pSize = comp.getPreferredSize();
+// int baseline = comp.getBaseline(pSize.width, pSize.height);
+// int nextBaseline = comp.getBaseline(pSize.width, pSize.height + 1);
+//
+// // Amount to add to height when calculating where baseline
+// // lands for a particular height:
+// int padding = 0;
+//
+// // Where the baseline is relative to the mid point
+// int baselineOffset = baseline - pSize.height / 2;
+// if (pSize.height % 2 == 0 && baseline != nextBaseline) {
+// padding = 1;
+// } else if (pSize.height % 2 == 1 && baseline == nextBaseline) {
+// baselineOffset--;
+// padding = 1;
+// }
+//
+// // The following calculates where the baseline lands for
+// // the height z:
+// return (pSize.height + padding) / 2 + baselineOffset;
+// }
+
+ /** Converts a <code>float</code> to a string and is removing the ".0" if the float is an integer.
+ * @param f the float.
+ * @return <code>f</code> as a string. Never <code>null</code>.
+ */
+ static final String floatToString(float f)
+ {
+ String valS = String.valueOf(f);
+ return valS.endsWith(".0") ? valS.substring(0, valS.length() - 2) : valS;
+ }
+
+ /** Returns the inset for the side.
+ * @param side top == 0, left == 1, bottom = 2, right = 3.
+ * @param getDefault If <code>true</code> the default insets will get retrieved if <code>lc</code> has none set.
+ * @return The inset for the side. Never <code>null</code>.
+ */
+ static final UnitValue getInsets(LC lc, int side, boolean getDefault)
+ {
+ UnitValue[] i = lc.getInsets();
+ return (i != null && i[side] != null) ? i[side] : (getDefault ? PlatformDefaults.getPanelInsets(side) : UnitValue.ZERO);
+ }
+
+ /** Writes the objet and CLOSES the stream. Uses the persistence delegate registered in this class.
+ * @param os The stream to write to. Will be closed.
+ * @param o The object to be serialized.
+ * @param listener The listener to recieve the exeptions if there are any. If <code>null</code> not used.
+ */
+ static void writeXMLObject(OutputStream os, Object o, ExceptionListener listener)
+ {
+ ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(LayoutUtil.class.getClassLoader());
+
+ XMLEncoder encoder = new XMLEncoder(os);
+
+ if (listener != null)
+ encoder.setExceptionListener(listener);
+
+ encoder.writeObject(o);
+ encoder.close(); // Must be closed to write.
+
+ Thread.currentThread().setContextClassLoader(oldClassLoader);
+ }
+
+ private static ByteArrayOutputStream writeOutputStream = null;
+ /** Writes an object to XML.
+ * @param out The boject out to write to. Will not be closed.
+ * @param o The object to write.
+ */
+ public static synchronized void writeAsXML(ObjectOutput out, Object o) throws IOException
+ {
+ if (writeOutputStream == null)
+ writeOutputStream = new ByteArrayOutputStream(16384);
+
+ writeOutputStream.reset();
+
+ writeXMLObject(writeOutputStream, o, new ExceptionListener() {
+ public void exceptionThrown(Exception e) {
+ e.printStackTrace();
+ }});
+
+ byte[] buf = writeOutputStream.toByteArray();
+
+ out.writeInt(buf.length);
+ out.write(buf);
+ }
+
+ private static byte[] readBuf = null;
+ /** Reads an object from <code>in</code> using the
+ * @param in The object input to read from.
+ * @return The object. Never <code>null</code>.
+ * @throws IOException If there was a problem saving as XML
+ */
+ public static synchronized Object readAsXML(ObjectInput in) throws IOException
+ {
+ if (readBuf == null)
+ readBuf = new byte[16384];
+
+ Thread cThread = Thread.currentThread();
+ ClassLoader oldCL = null;
+
+ try {
+ oldCL = cThread.getContextClassLoader();
+ cThread.setContextClassLoader(LayoutUtil.class.getClassLoader());
+ } catch(SecurityException e) {
+ }
+
+ Object o = null;
+ try {
+ int length = in.readInt();
+ if (length > readBuf.length)
+ readBuf = new byte[length];
+
+ in.readFully(readBuf, 0, length);
+
+ o = new XMLDecoder(new ByteArrayInputStream(readBuf, 0, length)).readObject();
+
+ } catch(EOFException e) {
+ }
+
+ if (oldCL != null)
+ cThread.setContextClassLoader(oldCL);
+
+ return o;
+ }
+
+ private static final IdentityHashMap<Object, Object> SER_MAP = new IdentityHashMap<Object, Object>(2);
+
+ /** Sets the serialized object and associates it with <code>caller</code>.
+ * @param caller The objec created <code>o</code>
+ * @param o The just serialized object.
+ */
+ public static void setSerializedObject(Object caller, Object o)
+ {
+ synchronized(SER_MAP) {
+ SER_MAP.put(caller, o);
+ }
+ }
+
+ /** Returns the serialized object that are associated with <code>caller</code>. It also removes it from the list.
+ * @param caller The original creator of the object.
+ * @return The object.
+ */
+ public static Object getSerializedObject(Object caller)
+ {
+ synchronized(SER_MAP) {
+ return SER_MAP.remove(caller);
+ }
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/LinkHandler.java b/prototypes/miglayout/net/miginfocom/layout/LinkHandler.java
new file mode 100644
index 00000000..8984bea1
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/LinkHandler.java
@@ -0,0 +1,182 @@
+package net.miginfocom.layout;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+/*
+ * 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
+ */
+
+/**
+ */
+public final class LinkHandler
+{
+ public static final int X = 0;
+ public static final int Y = 1;
+ public static final int WIDTH = 2;
+ public static final int HEIGHT = 3;
+ public static final int X2 = 4;
+ public static final int Y2 = 5;
+
+ private static final ArrayList<WeakReference<Object>> LAYOUTS = new ArrayList<WeakReference<Object>>(4);
+ private static final ArrayList<HashMap<String, int[]>> VALUES = new ArrayList<HashMap<String, int[]>>(4);
+ private static final ArrayList<HashMap<String, int[]>> VALUES_TEMP = new ArrayList<HashMap<String, int[]>>(4);
+
+ private LinkHandler()
+ {
+ }
+
+ public synchronized static Integer getValue(Object layout, String key, int type)
+ {
+ Integer ret = null;
+ boolean cont = true;
+
+ for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
+ Object l = LAYOUTS.get(i).get();
+ if (ret == null && l == layout) {
+ int[] rect = VALUES_TEMP.get(i).get(key);
+ if (cont && rect != null && rect[type] != LayoutUtil.NOT_SET) {
+ ret = new Integer(rect[type]);
+ } else {
+ rect = VALUES.get(i).get(key);
+ ret = (rect != null && rect[type] != LayoutUtil.NOT_SET) ? new Integer(rect[type]) : null;
+ }
+ cont = false;
+ }
+
+ if (l == null) {
+ LAYOUTS.remove(i);
+ VALUES.remove(i);
+ VALUES_TEMP.remove(i);
+ }
+ }
+ return ret;
+ }
+
+ public synchronized static boolean setBounds(Object layout, String key, int x, int y, int width, int height)
+ {
+ return setBounds(layout, key, x, y, width, height, false, false);
+ }
+
+ synchronized static boolean setBounds(Object layout, String key, int x, int y, int width, int height, boolean temporary, boolean incCur)
+ {
+ for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
+ Object l = LAYOUTS.get(i).get();
+ if (l == layout) {
+ HashMap<String, int[]> map = (temporary ? VALUES_TEMP : VALUES).get(i);
+ int[] old = map.get(key);
+
+ if (old == null || old[X] != x || old[Y] != y || old[WIDTH] != width || old[HEIGHT] != height) {
+ if (old == null || incCur == false) {
+ map.put(key, new int[] {x, y, width, height, x + width, y + height});
+ return true;
+ } else {
+ boolean changed = false;
+
+ if (x != LayoutUtil.NOT_SET) {
+ if (old[X] == LayoutUtil.NOT_SET || x < old[X]) {
+ old[X] = x;
+ old[WIDTH] = old[X2] - x;
+ changed = true;
+ }
+
+ if (width != LayoutUtil.NOT_SET) {
+ int x2 = x + width;
+ if (old[X2] == LayoutUtil.NOT_SET || x2 > old[X2]) {
+ old[X2] = x2;
+ old[WIDTH] = x2 - old[X];
+ changed = true;
+ }
+ }
+ }
+
+ if (y != LayoutUtil.NOT_SET) {
+ if (old[Y] == LayoutUtil.NOT_SET || y < old[Y]) {
+ old[Y] = y;
+ old[HEIGHT] = old[Y2] - y;
+ changed = true;
+ }
+
+ if (height != LayoutUtil.NOT_SET) {
+ int y2 = y + height;
+ if (old[Y2] == LayoutUtil.NOT_SET || y2 > old[Y2]) {
+ old[Y2] = y2;
+ old[HEIGHT] = y2 - old[Y];
+ changed = true;
+ }
+ }
+ }
+ return changed;
+ }
+ }
+ return false;
+ }
+ }
+
+ LAYOUTS.add(new WeakReference<Object>(layout));
+ int[] bounds = new int[] {x, y, width, height, x + width, y + height};
+
+ HashMap<String, int[]> values = new HashMap<String, int[]>(4);
+ if (temporary)
+ values.put(key, bounds);
+ VALUES_TEMP.add(values);
+
+ values = new HashMap<String, int[]>(4);
+ if (temporary == false)
+ values.put(key, bounds);
+ VALUES.add(values);
+
+ return true;
+ }
+
+ public synchronized static boolean clearBounds(Object layout, String key)
+ {
+ for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
+ Object l = LAYOUTS.get(i).get();
+ if (l == layout)
+ return VALUES.get(i).remove(key) != null;
+ }
+ return false;
+ }
+
+ synchronized static void clearTemporaryBounds(Object layout)
+ {
+ for (int i = LAYOUTS.size() - 1; i >= 0; i--) {
+ Object l = LAYOUTS.get(i).get();
+ if (l == layout) {
+ VALUES_TEMP.get(i).clear();
+ return;
+ }
+ }
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java b/prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java
new file mode 100644
index 00000000..d805812a
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/PlatformDefaults.java
@@ -0,0 +1,675 @@
+package net.miginfocom.layout;
+
+import javax.swing.*;
+import java.util.HashMap;
+/*
+ * 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
+ */
+
+/** Currently handles Windows and Mac OS X spacing.
+ */
+public final class PlatformDefaults
+{
+ private static int DEF_H_UNIT = UnitValue.LPX;
+ private static int DEF_V_UNIT = UnitValue.LPY;
+
+ private static InCellGapProvider GAP_PROVIDER = null;
+
+ private static volatile int MOD_COUNT = 0;
+
+ private static final UnitValue LPX4 = new UnitValue(4, UnitValue.LPX, null);
+ private static final UnitValue LPX7 = new UnitValue(7, UnitValue.LPX, null);
+ private static final UnitValue LPX8 = new UnitValue(8, UnitValue.LPX, null);
+ private static final UnitValue LPX9 = new UnitValue(9, UnitValue.LPX, null);
+ private static final UnitValue LPX10 = new UnitValue(10, UnitValue.LPX, null);
+ private static final UnitValue LPX11 = new UnitValue(11, UnitValue.LPX, null);
+ private static final UnitValue LPX12 = new UnitValue(12, UnitValue.LPX, null);
+ private static final UnitValue LPX14 = new UnitValue(14, UnitValue.LPX, null);
+ private static final UnitValue LPX16 = new UnitValue(16, UnitValue.LPX, null);
+ private static final UnitValue LPX20 = new UnitValue(20, UnitValue.LPX, null);
+
+ private static final UnitValue LPY4 = new UnitValue(4, UnitValue.LPY, null);
+ private static final UnitValue LPY7 = new UnitValue(7, UnitValue.LPY, null);
+ private static final UnitValue LPY8 = new UnitValue(8, UnitValue.LPY, null);
+ private static final UnitValue LPY9 = new UnitValue(9, UnitValue.LPY, null);
+ private static final UnitValue LPY10 = new UnitValue(10, UnitValue.LPY, null);
+ private static final UnitValue LPY11 = new UnitValue(11, UnitValue.LPY, null);
+ private static final UnitValue LPY12 = new UnitValue(12, UnitValue.LPY, null);
+ private static final UnitValue LPY14 = new UnitValue(14, UnitValue.LPY, null);
+ private static final UnitValue LPY16 = new UnitValue(16, UnitValue.LPY, null);
+ private static final UnitValue LPY20 = new UnitValue(20, UnitValue.LPY, null);
+
+ public static final int WINDOWS_XP = 0;
+ public static final int MAC_OSX = 1;
+// private static final int GNOME = 2;
+// private static final int KDE = 3;
+
+ private static int CUR_PLAF = WINDOWS_XP;
+
+ // Used for holding values.
+ private final static UnitValue[] PANEL_INS = new UnitValue[4];
+ private final static UnitValue[] DIALOG_INS = new UnitValue[4];
+
+ private static String BUTTON_FORMAT = null;
+
+ private static final HashMap<String, UnitValue> HOR_DEFS = new HashMap<String, UnitValue>(32);
+ private static final HashMap<String, UnitValue> VER_DEFS = new HashMap<String, UnitValue>(32);
+ private static BoundSize DEF_VGAP = null, DEF_HGAP = null;
+ static BoundSize RELATED_X = null, RELATED_Y = null, UNRELATED_X = null, UNRELATED_Y = null;
+ private static UnitValue BUTT_WIDTH = null;
+
+ private static Float horScale = null, verScale = null;
+
+ /** I value indicating that the size of the font for the container of the component
+ * will be used as a base for calculating the logical pixel size. This is much as how
+ * Windows calculated DLU (dialog units).
+ * @see net.miginfocom.layout.UnitValue#LPX
+ * @see net.miginfocom.layout.UnitValue#LPY
+ * @see #setLogicalPixelBase(int)
+ */
+ public static final int BASE_FONT_SIZE = 100;
+
+ /** I value indicating that the screen DPI will be used as a base for calculating the
+ * logical pixel size.
+ * <p>
+ * This is the default value.
+ * @see net.miginfocom.layout.UnitValue#LPX
+ * @see net.miginfocom.layout.UnitValue#LPY
+ * @see #setLogicalPixelBase(int)
+ * @see #setVerticalScaleFactor(Float)
+ * @see #setHorizontalScaleFactor(Float)
+ */
+ public static final int BASE_SCALE_FACTOR = 101;
+
+ /** I value indicating that the size of a logica pixel should always be a real pixel
+ * and thus no compensation will be made.
+ * @see net.miginfocom.layout.UnitValue#LPX
+ * @see net.miginfocom.layout.UnitValue#LPY
+ * @see #setLogicalPixelBase(int)
+ */
+ public static final int BASE_REAL_PIXEL = 102;
+
+ private static int LP_BASE = BASE_SCALE_FACTOR;
+
+ private static int BASE_DPI = 96;
+
+ static {
+ setPlatform(getCurrentPlatform());
+ MOD_COUNT = 0;
+ }
+
+ /** Returns the platform that the JRE is running on currently.
+ * @return The platform that the JRE is running on currently. E.g. {@link #MAC_OSX} or {@link #WINDOWS_XP}.
+ */
+ public static int getCurrentPlatform()
+ {
+ return System.getProperty("os.name").startsWith("Mac OS") ? MAC_OSX : WINDOWS_XP;
+ }
+
+ private PlatformDefaults()
+ {
+ }
+
+ /** Set the defaults to the default for the platform
+ * @param plaf The platform. <code>PlatformDefaults.WINDOWS</code> or <code>PlatformDefaults.MAC_OSX</code>
+ */
+ public static void setPlatform(int plaf)
+ {
+ if (plaf < WINDOWS_XP || plaf > MAC_OSX)
+ throw new IllegalArgumentException("Unknown platform: " + plaf);
+
+ CUR_PLAF = plaf;
+ if (plaf == WINDOWS_XP) {
+ setRelatedGap(LPX4, LPY4);
+ setUnrelatedGap(LPX7, LPY9);
+ setParagraphGap(LPX14, LPY14);
+ setIndentGap(LPX9, LPY9);
+ setGridCellGap(LPX4, LPY4);
+
+ setMinimumButtonWidth(new UnitValue(75, UnitValue.LPX, null));
+ setButtonOrder("L_E+U+YNBXOCAH_R");
+ setDialogInsets(LPY11, LPX11, LPY11, LPX11);
+ setPanelInsets(LPY7, LPX7, LPY7, LPX7);
+ BASE_DPI = 96;
+ } else {
+ setRelatedGap(LPX8, LPY8);
+ setUnrelatedGap(LPX12, LPY12);
+ setParagraphGap(LPX16, LPY16);
+ setIndentGap(LPX10, LPY10);
+ setGridCellGap(LPX8, LPY8);
+
+ setMinimumButtonWidth(new UnitValue(68, UnitValue.LPX, null));
+ setButtonOrder("L_HE+U+NYBXCOA_R");
+ setDialogInsets(LPY14, LPX20, LPY20, LPX20);
+ setPanelInsets(LPY16, LPX16, LPY16, LPX16);
+ BASE_DPI = 72;
+ }
+ }
+
+ /** Returns the current platform
+ * @return <code>PlatformDefaults.WINDOWS</code> or <code>PlatformDefaults.MAC_OSX</code>
+ */
+ public static int getPlatform()
+ {
+ return CUR_PLAF;
+ }
+
+ public static int getDefaultDPI()
+ {
+ return BASE_DPI;
+ }
+
+ /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
+ * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
+ * (72 DPI for Mac and 92 DPI for Windows).
+ * @return The forced scale or <code>null</code> for default scaling.
+ * @see #getHorizontalScaleFactor()
+ * @see ComponentWrapper#getHorizontalScreenDPI()
+ */
+ public static Float
+ getHorizontalScaleFactor()
+ {
+ return horScale;
+ }
+
+ /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
+ * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
+ * (72 DPI for Mac and 92 DPI for Windows).
+ * @param f The forced scale or <code>null</code> for default scaling.
+ * @see #getHorizontalScaleFactor()
+ * @see ComponentWrapper#getHorizontalScreenDPI()
+ */
+ public static void setHorizontalScaleFactor(Float f)
+ {
+ if (horScale != f) {
+ horScale = f;
+ MOD_COUNT++;
+ }
+ }
+
+ /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
+ * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
+ * (72 DPI for Mac and 92 DPI for Windows).
+ * @return The forced scale or <code>null</code> for default scaling.
+ * @see #getHorizontalScaleFactor()
+ * @see ComponentWrapper#getVerticalScreenDPI()
+ */
+ public static Float getVerticalScaleFactor()
+ {
+ return verScale;
+ }
+
+ /** The forced scale factor that all screen relative units (e.g. millimeters, inches and logical pixels) will be multiplied
+ * with. If <code>null</code> this will default to a scale that will scale the current screen to the default screen resolution
+ * (72 DPI for Mac and 92 DPI for Windows).
+ * @param f The forced scale or <code>null</code> for default scaling.
+ * @see #getHorizontalScaleFactor()
+ * @see ComponentWrapper#getVerticalScreenDPI()
+ */
+ public static void setVerticalScaleFactor(Float f)
+ {
+ if (verScale != f) {
+ verScale = f;
+ MOD_COUNT++;
+ }
+ }
+
+ /** What base value should be used to calculate logical pixel sizes.
+ * @return The current base. Default is {@link #BASE_SCALE_FACTOR}
+ * @see #BASE_FONT_SIZE
+ * @see # BASE_SCREEN_DPI_FACTOR
+ * @see #BASE_REAL_PIXEL
+ */
+ public static int getLogicalPixelBase()
+ {
+ return LP_BASE;
+ }
+
+ /** What base value should be used to calculate logical pixel sizes.
+ * @param base The new base. Default is {@link #BASE_SCALE_FACTOR}
+ * @see #BASE_FONT_SIZE
+ * @see # BASE_SCREEN_DPI_FACTOR
+ * @see #BASE_REAL_PIXEL
+ */
+ public static void setLogicalPixelBase(int base)
+ {
+ if (LP_BASE != base) {
+ if (base < BASE_FONT_SIZE || base > BASE_SCALE_FACTOR)
+ throw new IllegalArgumentException("Unrecognized base: " + base);
+
+ LP_BASE = base;
+ MOD_COUNT++;
+ }
+ }
+
+ /** Sets gap value for components that are "related".
+ * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ */
+ public static void setRelatedGap(UnitValue x, UnitValue y)
+ {
+ setUnitValue(new String[] {"r", "rel", "related"}, x, y);
+
+ RELATED_X = new BoundSize(x, x, null, "rel:rel");
+ RELATED_Y = new BoundSize(y, y, null, "rel:rel");
+ }
+
+ /** Sets gap value for components that are "unrelated".
+ * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ */
+ public static void setUnrelatedGap(UnitValue x, UnitValue y)
+ {
+ setUnitValue(new String[] {"u", "unrel", "unrelated"}, x, y);
+
+ UNRELATED_X = new BoundSize(x, x, null, "unrel:unrel");
+ UNRELATED_Y = new BoundSize(y, y, null, "unrel:unrel");
+ }
+
+ /** Sets paragraph gap value for components.
+ * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ */
+ public static void setParagraphGap(UnitValue x, UnitValue y)
+ {
+ setUnitValue(new String[] {"p", "para", "paragraph"}, x, y);
+ }
+
+ /** Sets gap value for components that are "intended".
+ * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ */
+ public static void setIndentGap(UnitValue x, UnitValue y)
+ {
+ setUnitValue(new String[] {"i", "ind", "indent"}, x, y);
+ }
+
+ /** Sets gap between two cells in the grid. Note that this is not a gap between component IN a cell, that has to be set
+ * on the component constraints. The value will be the min and preferred size of the gap.
+ * @param x The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ * @param y The value that will be transformed to pixels. If <code>null</code> the current value will not change.
+ */
+ public static void setGridCellGap(UnitValue x, UnitValue y)
+ {
+ if (x != null)
+ DEF_HGAP = new BoundSize(x, x, null, null);
+
+ if (y != null)
+ DEF_VGAP = new BoundSize(y, y, null, null);
+
+ MOD_COUNT++;
+ }
+
+ /** Sets the recommended minimum button width.
+ * @param width The recommended minimum button width.
+ */
+ public static void setMinimumButtonWidth(UnitValue width)
+ {
+ BUTT_WIDTH = width;
+ MOD_COUNT++;
+ }
+
+ /** Returns the recommended minimum button width depending on the current set platform.
+ * @return The recommended minimum button width depending on the current set platform.
+ */
+ public static UnitValue getMinimumButtonWidth()
+ {
+ return BUTT_WIDTH;
+ }
+
+ /** Returns the unit value associated with the unit. (E.i. "related" or "indent"). Must be lower case.
+ * @param unit The unit string.
+ * @return Tthe unit value associated with the unit. <code>null</code> for unrecognized units.
+ */
+ public static UnitValue getUnitValueX(String unit)
+ {
+ return HOR_DEFS.get(unit);
+ }
+
+ /** Returns the unit value associated with the unit. (E.i. "related" or "indent"). Must be lower case.
+ * @param unit The unit string.
+ * @return Tthe unit value associated with the unit. <code>null</code> for unrecognized units.
+ */
+ public static UnitValue getUnitValueY(String unit)
+ {
+ return VER_DEFS.get(unit);
+ }
+
+ /** Sets the unit value assiciated with a unit string. This may be used to store values for new unit strings
+ * or modify old. Note that if a built in unit (such as "related") is modified all versions of it must be
+ * set (I.e. "r", "rel" and "related"). The build in values will be reset to the default ones if the platform
+ * is re-set.
+ * @param unitStrings The unit strings. E.g. "mu", "myunit". Will be converted to lower case and trimmed. Not <code>null</code>.
+ * @param x The value for the horizontal dimension. If <code>null</code> the value is not changed.
+ * @param y The value for the vertical dimension. Might be same object as for <code>x</code>. If <code>null</code> the value is not changed.
+ */
+ public static final void setUnitValue(String[] unitStrings, UnitValue x, UnitValue y)
+ {
+ for (int i = 0; i < unitStrings.length; i++) {
+ String s = unitStrings[i].toLowerCase().trim();
+ if (x != null)
+ HOR_DEFS.put(s, x);
+ if (y != null)
+ VER_DEFS.put(s, y);
+ }
+ MOD_COUNT++;
+ }
+
+ /** Understands ("r", "rel", "related") OR ("u", "unrel", "unrelated") OR ("i", "ind", "indent") OR ("p", "para", "paragraph").
+ */
+ static final int convertToPixels(float value, String unit, boolean isHor, float ref, ContainerWrapper parent, ComponentWrapper comp)
+ {
+ UnitValue uv = (isHor ? HOR_DEFS : VER_DEFS).get(unit);
+ return uv != null ? Math.round(value * uv.getPixels(ref, parent, comp)) : UnitConverter.UNABLE;
+ }
+
+ /** Returns the order for the typical buttons in a standard button bar. It is one letter per button type.
+ * @return The button order.
+ * @see #setButtonOrder(String)
+ */
+ public static final String getButtonOrder()
+ {
+ return BUTTON_FORMAT;
+ }
+
+ /** Sets the order for the typical buttons in a standard button bar. It is one letter per button type.
+ * <p>
+ * Letter in upper case will get the minimum button width that the {@link #getMinimumButtonWidth()} specifies
+ * and letters in lower case will get the width the corrent look&feel specifies.
+ * <p>
+ * Gaps will never be added to before the first component or after the last component. However, '+' (push) will be
+ * applied before and after as well, but with a minimum size of 0 if first/last so there will not be a gap
+ * before or after.
+ * <p>
+ * If gaps are explicitly set on buttons they will never be reduced, but they may be increased.
+ * <p>
+ * These are the characters that can be used:
+ * <ul>
+ * <li><code>'L'</code> - Buttons with this style tag will staticall end up on the left end of the bar.
+ * <li><code>'R'</code> - Buttons with this style tag will staticall end up on the right end of the bar.
+ * <li><code>'H'</code> - A tag for the "help" button that normally is supposed to be on the right.
+ * <li><code>'E'</code> - A tag for the "help2" button that normally is supposed to be on the left.
+ * <li><code>'Y'</code> - A tag for the "yes" button.
+ * <li><code>'N'</code> - A tag for the "no" button.
+ * <li><code>'X'</code> - A tag for the "next >" or "forward >" button.
+ * <li><code>'B'</code> - A tag for the "< back>" or "< previous" button.
+ * <li><code>'I'</code> - A tag for the "finish".
+ * <li><code>'A'</code> - A tag for the "apply" button.
+ * <li><code>'C'</code> - A tag for the "cancel" or "close" button.
+ * <li><code>'O'</code> - A tag for the "ok" or "done" button.
+ * <li><code>'U'</code> - All Uncategorized, Other, or "Unknown" buttons. Tag will be "other".
+ * <li><code>'+'</code> - A glue push gap that will take as much space as it can and at least an "unrelated" gap. (Platform dependant)
+ * <li><code>'_'</code> - (underscore) An "unrelated" gap. (Platform dependant)
+ * </ul>
+ * <p>
+ * Even though the style tags are normally applied to buttons this works with all components.
+ * <p>
+ * The normal style for MAC OS X is <code>"L_HE+U+FBI_NYCOA_R"</code> and for Windows is <code>"L_E+U+FBI_YNOCAH_R"</code>
+ * @param order The new button order for the current platform.
+ */
+ public static final void setButtonOrder(String order)
+ {
+ BUTTON_FORMAT = order;
+ MOD_COUNT++;
+ }
+
+ /** Returns the tag (used in the {@link CC}) for a char. The char is same as used in {@link #getButtonOrder()}.
+ * @param c The char. Must be lower case!
+ * @return The tag that corresponds to the char or <code>null</code> if the char is unrecognized.
+ */
+ static final String getTagForChar(char c)
+ {
+ switch (c) {
+ case 'o':
+ return "ok";
+ case 'c':
+ return "cancel";
+ case 'h':
+ return "help";
+ case 'e':
+ return "help2";
+ case 'y':
+ return "yes";
+ case 'n':
+ return "no";
+ case 'a':
+ return "apply";
+ case 'x':
+ return "next"; // a.k.a forward
+ case 'b':
+ return "back"; // a.k.a. previous
+ case 'i':
+ return "finish";
+ case 'l':
+ return "left";
+ case 'r':
+ return "right";
+ case 'u':
+ return "other";
+ default:
+ return null;
+ }
+ }
+
+ /** Returns the platform recommended inter-cell gap in the horizontal (x) dimension..
+ * @return The platform recommended inter-cell gap in the horizontal (x) dimension..
+ */
+ public static BoundSize getGridGapX()
+ {
+ return DEF_HGAP;
+ }
+
+ /** Returns the platform recommended inter-cell gap in the vertical (x) dimension..
+ * @return The platform recommended inter-cell gap in the vertical (x) dimension..
+ */
+ public static BoundSize getGridGapY()
+ {
+ return DEF_VGAP;
+ }
+
+ /** Returns the default dialog inset depending of the current platform.
+ * @param side top == 0, left == 1, bottom = 2, right = 3.
+ * @return The inset. Never <code>null</code>.
+ */
+ public static UnitValue getDialogInsets(int side)
+ {
+ return DIALOG_INS[side];
+ }
+
+ /** Sets the default insets for a dialog. Values that are null will not be changed.
+ * @param top The top inset. May be <code>null</code>.
+ * @param left The left inset. May be <code>null</code>.
+ * @param bottom The bottom inset. May be <code>null</code>.
+ * @param right The right inset. May be <code>null</code>.
+ */
+ public static void setDialogInsets(UnitValue top, UnitValue left, UnitValue bottom, UnitValue right)
+ {
+ if (top != null)
+ DIALOG_INS[0] = top;
+ if (left != null)
+ DIALOG_INS[1] = left;
+ if (bottom != null)
+ DIALOG_INS[2] = bottom;
+ if (right != null)
+ DIALOG_INS[3] = right;
+
+ MOD_COUNT++;
+ }
+
+ /** Returns the default panel inset depending of the current platform.
+ * @param side top == 0, left == 1, bottom = 2, right = 3.
+ * @return The inset. Never <code>null</code>.
+ */
+ public static UnitValue getPanelInsets(int side)
+ {
+ return PANEL_INS[side];
+ }
+
+ /** Sets the default insets for a dialog. Values that are null will not be changed.
+ * @param top The top inset. May be <code>null</code>.
+ * @param left The left inset. May be <code>null</code>.
+ * @param bottom The bottom inset. May be <code>null</code>.
+ * @param right The right inset. May be <code>null</code>.
+ */
+ public static void setPanelInsets(UnitValue top, UnitValue left, UnitValue bottom, UnitValue right)
+ {
+ if (top != null)
+ PANEL_INS[0] = top;
+
+ if (left != null)
+ PANEL_INS[1] = left;
+
+ if (bottom != null)
+ PANEL_INS[2] = bottom;
+
+ if (right != null)
+ PANEL_INS[3] = right;
+
+ MOD_COUNT++;
+ }
+
+ /** Returns the percentage used for alignment for labels (0 is left, 50 is center and 100 is right).
+ * @return The percentage used for alignment for labels
+ */
+ public static float getLabelAlignPercentage()
+ {
+ return CUR_PLAF == MAC_OSX ? 1f : 0f;
+ }
+
+ /** Returns the default gap between two components that <b>are in the same cell</b>.
+ * @param comp The component that the gap is for. Never <code>null</code>.
+ * @param adjacentComp The adjacent component if any. May be <code>null</code>.
+ * @param adjacentSide What side the <code>adjacentComp</code> is on. {@link javax.swing.SwingUtilities#TOP} or
+ * {@link javax.swing.SwingUtilities#LEFT} or {@link javax.swing.SwingUtilities#BOTTOM} or {@link javax.swing.SwingUtilities#RIGHT}.
+ * @param tag The tag string that the component might be tagged with in the component constraints. May be <code>null</code>.
+ * @param isLTR If it is left-to-right.
+ * @return The default gap between two components or <code>null</code> if there should be no gap.
+ */
+ static BoundSize getDefaultComponentGap(ComponentWrapper comp, ComponentWrapper adjacentComp, int adjacentSide, String tag, boolean isLTR)
+ {
+ if (GAP_PROVIDER != null)
+ return GAP_PROVIDER.getDefaultGap(comp, adjacentComp, adjacentSide, tag, isLTR);
+
+ if (adjacentComp == null)
+ return null;
+
+// if (adjacentComp == null || adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.TOP)
+// return null;
+
+ return (adjacentSide == SwingConstants.LEFT || adjacentSide == SwingConstants.RIGHT) ? RELATED_X : RELATED_Y;
+ }
+
+ /** Returns the current gap privider or <code>null</code> if none is set and "related" should always be used.
+ * @return The current gap privider or <code>null</code> if none is set and "related" should always be used.
+ */
+ public static InCellGapProvider getGapProvider()
+ {
+ return GAP_PROVIDER;
+ }
+
+ /** Sets the current gap privider or <code>null</code> if none is set and "related" should always be used.
+ * @param provider The current gap privider or <code>null</code> if none is set and "related" should always be used.
+ */
+ public static void setGapProvider(InCellGapProvider provider)
+ {
+ GAP_PROVIDER = provider;
+ }
+
+ /** Returns how many times the defaults has been changed. This can be used as a light weight check to
+ * see if layout caches needs to be refreshed.
+ * @return How many times the defaults has been changed.
+ */
+ public static int getModCount()
+ {
+ return MOD_COUNT;
+ }
+
+ /** Tells all layout manager instances to revalidate and recalculated everything.
+ */
+ public void invalidate()
+ {
+ MOD_COUNT++;
+ }
+
+ /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
+ * @return The current default unit.
+ * @see UnitValue#PIXEL
+ * @see UnitValue#LPX
+ */
+ public final static int getDefaultHorizontalUnit()
+ {
+ return DEF_H_UNIT;
+ }
+
+ /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
+ * @param unit The new default unit.
+ * @see UnitValue#PIXEL
+ * @see UnitValue#LPX
+ */
+ public final static void setDefaultHorizontalUnit(int unit)
+ {
+ if (unit < UnitValue.PIXEL || unit > UnitValue.LABEL_ALIGN)
+ throw new IllegalArgumentException("Illegal Unit: " + unit);
+
+ if (DEF_H_UNIT != unit) {
+ DEF_H_UNIT = unit;
+ MOD_COUNT++;
+ }
+ }
+
+ /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
+ * @return The current default unit.
+ * @see UnitValue#PIXEL
+ * @see UnitValue#LPY
+ */
+ public final static int getDefaultVerticalUnit()
+ {
+ return DEF_V_UNIT;
+ }
+
+ /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
+ * @param unit The new default unit.
+ * @see UnitValue#PIXEL
+ * @see UnitValue#LPY
+ */
+ public final static void setDefaultVerticalUnit(int unit)
+ {
+ if (unit < UnitValue.PIXEL || unit > UnitValue.LABEL_ALIGN)
+ throw new IllegalArgumentException("Illegal Unit: " + unit);
+
+ if (DEF_V_UNIT != unit) {
+ DEF_V_UNIT = unit;
+ MOD_COUNT++;
+ }
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java b/prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java
new file mode 100644
index 00000000..75a4c376
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/ResizeConstraint.java
@@ -0,0 +1,92 @@
+package net.miginfocom.layout;
+
+import java.io.*;
+/*
+ * 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
+ */
+
+/** A parsed constraint that specifies how an entity (normally column/row or component) can shrink or
+ * grow compared to other entities.
+ */
+final class ResizeConstraint implements Externalizable
+{
+ static final Float WEIGHT_100 = new Float(100);
+
+ /** How flexilble the entity should be, relative to other entities, when it comes to growing. <code>null</code> or
+ * zero mean it will never grow. An entity that has twise the growWeight compared to another entity will get twice
+ * as much of available space.
+ * <p>
+ * "grow" are only compared within the same "growPrio".
+ */
+ Float grow = null;
+
+ /** The relative priority used for determining which entities gets the extra space first.
+ */
+ int growPrio = 100;
+
+ Float shrink = WEIGHT_100;
+
+ int shrinkPrio = 100;
+
+ public ResizeConstraint() // For Externalizable
+ {
+ }
+
+ ResizeConstraint(int shrinkPrio, Float shrinkWeight, int growPrio, Float growWeight)
+ {
+ this.shrinkPrio = shrinkPrio;
+ this.shrink = shrinkWeight;
+ this.growPrio = growPrio;
+ this.grow = growWeight;
+ }
+
+ // ************************************************
+ // 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() == ResizeConstraint.class)
+ LayoutUtil.writeAsXML(out, this);
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/UnitConverter.java b/prototypes/miglayout/net/miginfocom/layout/UnitConverter.java
new file mode 100644
index 00000000..e94e82bd
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/UnitConverter.java
@@ -0,0 +1,59 @@
+package net.miginfocom.layout;
+/*
+ * 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
+ */
+
+/**
+ */
+public abstract class UnitConverter
+{
+ /** Value to return if this converter can not handle the <code>unit</code> sent in as an argument
+ * to the convert method.
+ */
+ public static final int UNABLE = -87654312;
+
+ /** Converts <code>value</code> to pixels.
+ * @param value The value to be converted.
+ * @param unit The unit of <code>value</code>. Never <code>null</code> and at least one character.
+ * @param refValue Some reference value that may of may not be used. If the unit is percent for instance this value
+ * is the value to take the percent from. Usually the size of the parent component in the appropriate dimension.
+ * @param isHor If the value is horizontal (<code>true</code>) or vertical (<code>false</code>).
+ * @param parent The parent of the target component that <code>value</code> is to be applied to.
+ * Might for instance be needed to get the screen that the component is on in a multi screen environment.
+ * <p>
+ * May be <code>null</code> in which case a "best guess" value should be returned.
+ * @param comp The component, if applicable, or <code>null</code> if none.
+ * @return The number of pixels if <code>unit</code> is handled by this converter, <code>UnitConverter.UNABLE</code> if not.
+ */
+ public abstract int convertToPixels(float value, String unit, boolean isHor, float refValue, ContainerWrapper parent, ComponentWrapper comp);
+}
diff --git a/prototypes/miglayout/net/miginfocom/layout/UnitValue.java b/prototypes/miglayout/net/miginfocom/layout/UnitValue.java
new file mode 100644
index 00000000..aa12ac3e
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/layout/UnitValue.java
@@ -0,0 +1,626 @@
+package net.miginfocom.layout;
+/*
+ * 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 java.beans.Encoder;
+import java.beans.Expression;
+import java.beans.PersistenceDelegate;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public final class UnitValue implements Serializable
+{
+ private static final HashMap<String, Integer> UNIT_MAP = new HashMap<String, Integer>(32);
+
+ private static final ArrayList<UnitConverter> CONVERTERS = new ArrayList<UnitConverter>();
+
+ /** An operation indicating a static value.
+ */
+ public static final int STATIC = 100;
+
+ /** An operation indicating a addition of two sub units.
+ */
+ public static final int ADD = 101; // Must have "sub-unit values"
+
+ /** An operation indicating a subtraction of two sub units
+ */
+ public static final int SUB = 102; // Must have "sub-unit values"
+
+ /** An operation indicating a multiplication of two sub units.
+ */
+ public static final int MUL = 103; // Must have "sub-unit values"
+
+ /** An operation indicating a division of two sub units.
+ */
+ public static final int DIV = 104; // Must have "sub-unit values"
+
+ /** An operation indicating the minimum of two sub units
+ */
+ public static final int MIN = 105; // Must have "sub-unit values"
+
+ /** An operation indicating the maximum of two sub units
+ */
+ public static final int MAX = 106; // Must have "sub-unit values"
+
+ /** An operation indicating the middle value of two sub units
+ */
+ public static final int MID = 107; // Must have "sub-unit values"
+
+
+
+
+ /** A unit indicating pixels.
+ */
+ public static final int PIXEL = 0;
+
+ /** A unit indicating logical horizontal pixels.
+ */
+ public static final int LPX = 1;
+
+ /** A unit indicating logical vertical pixels.
+ */
+ public static final int LPY = 2;
+
+ /** A unit indicating millimeters.
+ */
+ public static final int MM = 3;
+
+ /** A unit indicating centimeters.
+ */
+ public static final int CM = 4;
+
+ /** A unit indicating inches.
+ */
+ public static final int INCH = 5;
+
+ /** A unit indicating percent.
+ */
+ public static final int PERCENT = 6;
+
+ /** A unit indicating points.
+ */
+ public static final int PT = 7;
+
+ /** A unit indicating screen width in pixels.
+ */
+ public static final int SPX = 8;
+
+ /** A unit indicating screen height in pixels.
+ */
+ public static final int SPY = 9;
+
+ /** A unit indicating alignment.
+ */
+ public static final int ALIGN = 12;
+
+ /** A unit indicating minimum size.
+ */
+ public static final int MIN_SIZE = 13;
+
+ /** A unit indicating preferred size.
+ */
+ public static final int PREF_SIZE = 14;
+
+ /** A unit indicating maximum size.
+ */
+ public static final int MAX_SIZE = 15;
+
+ /** A unit indicating botton size.
+ */
+ public static final int BUTTON = 16;
+
+ /** A unit indicating linking to x.
+ */
+ public static final int LINK_X = 18; // First link
+
+ /** A unit indicating linking to y.
+ */
+ public static final int LINK_Y = 19;
+
+ /** A unit indicating linking to width.
+ */
+ public static final int LINK_W = 20;
+
+ /** A unit indicating linking to height.
+ */
+ public static final int LINK_H = 21;
+
+ /** A unit indicating linking to x2.
+ */
+ public static final int LINK_X2 = 22;
+
+ /** A unit indicating linking to y2.
+ */
+ public static final int LINK_Y2 = 23;
+
+ /** A unit indicating linking to x position on screen.
+ */
+ public static final int LINK_XPOS = 24;
+
+ /** A unit indicating linking to y position on screen.
+ */
+ public static final int LINK_YPOS = 25; // Last link
+
+ /** A unit indicating a lookup.
+ */
+ public static final int LOOKUP = 26;
+
+ /** A unit indicating label alignment.
+ */
+ public static final int LABEL_ALIGN = 27;
+
+ private static final int IDENTITY = -1;
+
+ static {
+ UNIT_MAP.put("px", new Integer(PIXEL));
+ UNIT_MAP.put("lpx", new Integer(LPX));
+ UNIT_MAP.put("lpy", new Integer(LPY));
+ UNIT_MAP.put("%", new Integer(PERCENT));
+ UNIT_MAP.put("cm", new Integer(CM));
+ UNIT_MAP.put("in", new Integer(INCH));
+ UNIT_MAP.put("spx", new Integer(SPX));
+ UNIT_MAP.put("spy", new Integer(SPY));
+ UNIT_MAP.put("al", new Integer(ALIGN));
+ UNIT_MAP.put("mm", new Integer(MM));
+ UNIT_MAP.put("pt", new Integer(PT));
+ UNIT_MAP.put("min", new Integer(MIN_SIZE));
+ UNIT_MAP.put("minimum", new Integer(MIN_SIZE));
+ UNIT_MAP.put("p", new Integer(PREF_SIZE));
+ UNIT_MAP.put("pref", new Integer(PREF_SIZE));
+ UNIT_MAP.put("max", new Integer(MAX_SIZE));
+ UNIT_MAP.put("maximum", new Integer(MAX_SIZE));
+ UNIT_MAP.put("button", new Integer(BUTTON));
+ UNIT_MAP.put("label", new Integer(LABEL_ALIGN));
+ }
+
+ static final UnitValue ZERO = new UnitValue(0, null, PIXEL, true, STATIC, null, null, "0px");
+ static final UnitValue TOP = new UnitValue(0, null, PERCENT, false, STATIC, null, null, "top");
+ static final UnitValue LEADING = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "leading");
+ static final UnitValue LEFT = new UnitValue(0, null, PERCENT, true, STATIC, null, null, "left");
+ static final UnitValue CENTER = new UnitValue(50, null, PERCENT, true, STATIC, null, null, "center");
+ static final UnitValue TRAILING = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "trailing");
+ static final UnitValue RIGHT = new UnitValue(100, null, PERCENT, true, STATIC, null, null, "right");
+ static final UnitValue BOTTOM = new UnitValue(100, null, PERCENT, false, STATIC, null, null, "bottom");
+ static final UnitValue LABEL = new UnitValue(0, null, LABEL_ALIGN, false, STATIC, null, null, "label");
+
+ static final UnitValue INF = new UnitValue(LayoutUtil.INF, null, PIXEL, true, STATIC, null, null, "inf");
+
+ static final UnitValue BASELINE_IDENTITY = new UnitValue(0, null, IDENTITY, false, STATIC, null, null, "baseline");
+
+ private final transient float value;
+ private final transient int unit;
+ private final transient int oper;
+ private final transient String unitStr;
+ private final transient boolean isHor;
+ private final transient UnitValue[] subUnits;
+
+ // Pixel
+ public UnitValue(float value) // If hor/ver does not matter.
+ {
+ this(value, null, PIXEL, true, STATIC, null, null, value + "px");
+ }
+
+ public UnitValue(float value, int unit, String createString) // If hor/ver does not matter.
+ {
+ this(value, null, unit, true, STATIC, null, null, createString);
+ }
+
+ UnitValue(float value, String unitStr, boolean isHor, int oper, String createString)
+ {
+ this(value, unitStr, -1, isHor, oper, null, null, createString);
+ }
+
+ UnitValue(boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString)
+ {
+ this(0, "", -1, isHor, oper, sub1, sub2, createString);
+ if (sub1 == null || sub2 == null)
+ throw new IllegalArgumentException("Sub units is null!");
+ }
+
+ private UnitValue(float value, String unitStr, int unit, boolean isHor, int oper, UnitValue sub1, UnitValue sub2, String createString)
+ {
+ if (oper < STATIC || oper > MID)
+ throw new IllegalArgumentException("Unknown Operation: " + oper);
+
+ if (oper >= ADD && oper <= MID && (sub1 == null || sub2 == null))
+ throw new IllegalArgumentException(oper + " Operation may not have null sub-UnitValues.");
+
+ this.value = value;
+ this.oper = oper;
+ this.isHor = isHor;
+ this.unitStr = unitStr;
+ this.unit = unitStr != null ? parseUnitString() : unit;
+ this.subUnits = sub1 != null && sub2 != null ? new UnitValue[] {sub1, sub2} : null;
+
+ LayoutUtil.putCCString(this, createString); // "this" escapes!! Safe though.
+ }
+
+ /** Returns the size in pixels rounded.
+ * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in.
+ * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not
+ * required to return any usable value if <code>null</code>.
+ * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not
+ * connected to any component.
+ * @return The size in pixels.
+ */
+ public final int getPixels(float refValue, ContainerWrapper parent, ComponentWrapper comp)
+ {
+ return Math.round(getPixelsExact(refValue, parent, comp));
+ }
+
+ private static final float[] SCALE = new float[] {25.4f, 2.54f, 1f, 0f, 72f};
+ /** Returns the size in pixels.
+ * @param refValue The reference value. Normally the size of the parent. For unit {@link #ALIGN} the current size of the component should be sent in.
+ * @param parent The parent. May be <code>null</code> for testing the validity of the value, but should normally not and are not
+ * required to return any usable value if <code>null</code>.
+ * @param comp The component, if any, that the value is for. Might be <code>null</code> if the value is not
+ * connected to any component.
+ * @return The size in pixels.
+ */
+ public final float getPixelsExact(float refValue, ContainerWrapper parent, ComponentWrapper comp)
+ {
+ if (parent == null)
+ return 1;
+
+ if (oper == STATIC) {
+ switch (unit) {
+ case PIXEL:
+ return value;
+
+ case LPX:
+ case LPY:
+ return parent.getPixelUnitFactor(unit == LPX) * value;
+
+ case MM:
+ case CM:
+ case INCH:
+ case PT:
+ float f = SCALE[unit - MM];
+ Float s = isHor ? PlatformDefaults.getHorizontalScaleFactor() : PlatformDefaults.getVerticalScaleFactor();
+ if (s != null)
+ f *= s.floatValue();
+ return (isHor ? parent.getHorizontalScreenDPI() : parent.getVerticalScreenDPI()) * value / f;
+
+ case PERCENT:
+ return value * refValue * 0.01f;
+
+ case SPX:
+ case SPY:
+ return (unit == SPX ? parent.getScreenWidth() : parent.getScreenHeight()) * value * 0.01f;
+
+ case ALIGN:
+ Integer st = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.X : LinkHandler.Y);
+ Integer sz = LinkHandler.getValue(parent.getLayout(), "visual", isHor ? LinkHandler.WIDTH : LinkHandler.HEIGHT);
+ if (st == null || sz == null)
+ return 0;
+ return value * (Math.max(0, sz.intValue()) - refValue) + st.intValue();
+
+ case MIN_SIZE:
+ if (comp == null)
+ return 0;
+ return isHor ? comp.getMinimumWidth() : comp.getMinimumHeight();
+
+ case PREF_SIZE:
+ if (comp == null)
+ return 0;
+ return isHor ? comp.getPreferredWidth() : comp.getPreferredHeight();
+
+ case MAX_SIZE:
+ if (comp == null)
+ return 0;
+ return isHor ? comp.getMaximumWidth() : comp.getMaximumHeight();
+
+ case BUTTON:
+ return PlatformDefaults.getMinimumButtonWidth().getPixels(refValue, parent, comp);
+
+ case LINK_X:
+ case LINK_Y:
+ case LINK_W:
+ case LINK_H:
+ case LINK_X2:
+ case LINK_Y2:
+ case LINK_XPOS:
+ case LINK_YPOS:
+ Integer v = LinkHandler.getValue(parent.getLayout(), getLinkTargetId(), unit - (unit >= LINK_XPOS ? LINK_XPOS : LINK_X));
+ if (v == null)
+ return 0;
+
+ if (unit == LINK_XPOS)
+ return parent.getScreenLocationX() + v.intValue();
+ if (unit == LINK_YPOS)
+ return parent.getScreenLocationY() + v.intValue();
+
+ return v.intValue();
+
+ case LOOKUP:
+ float res = lookup(refValue, parent, comp);
+ if (res != UnitConverter.UNABLE)
+ return res;
+
+ case LABEL_ALIGN:
+ return PlatformDefaults.getLabelAlignPercentage() * refValue;
+
+ case IDENTITY:
+ }
+ throw new IllegalArgumentException("Unknown/illegal unit: " + unit + ", unitStr: " + unitStr);
+ }
+
+ if (subUnits != null && subUnits.length == 2) {
+ float r1 = subUnits[0].getPixelsExact(refValue, parent, comp);
+ float r2 = subUnits[1].getPixelsExact(refValue, parent, comp);
+ switch (oper) {
+ case ADD:
+ return r1 + r2;
+ case SUB:
+ return r1 - r2;
+ case MUL:
+ return r1 * r2;
+ case DIV:
+ return r1 / r2;
+ case MIN:
+ return r1 < r2 ? r1 : r2;
+ case MAX:
+ return r1 > r2 ? r1 : r2;
+ case MID:
+ return (r1 + r2) * 0.5f;
+ }
+ }
+
+ throw new IllegalArgumentException("Internal: Unknown Oper: " + oper);
+ }
+
+ private final float lookup(float refValue, ContainerWrapper parent, ComponentWrapper comp)
+ {
+ float res = UnitConverter.UNABLE;
+ for (int i = CONVERTERS.size() - 1; i >= 0; i--) {
+ res = CONVERTERS.get(i).convertToPixels(value, unitStr, isHor, refValue, parent, comp);
+ if (res != UnitConverter.UNABLE)
+ return res;
+ }
+ return PlatformDefaults.convertToPixels(value, unitStr, isHor, refValue, parent, comp);
+ }
+
+ private final int parseUnitString()
+ {
+ int len = unitStr.length();
+ if (len == 0)
+ return isHor ? PlatformDefaults.getDefaultHorizontalUnit() : PlatformDefaults.getDefaultVerticalUnit();
+
+ Integer u = UNIT_MAP.get(unitStr);
+ if (u != null)
+ return u.intValue();
+
+ if (unitStr.equals("lp"))
+ return isHor ? LPX : LPY;
+
+ if (unitStr.equals("sp"))
+ return isHor ? SPX : SPY;
+
+ if (lookup(0, null, null) != UnitConverter.UNABLE) // To test so we can fail fast
+ return LOOKUP;
+
+ if (unitStr.endsWith(".x"))
+ return LINK_X;
+ if (unitStr.endsWith(".y"))
+ return LINK_Y;
+ if (unitStr.endsWith(".w") || unitStr.endsWith(".width"))
+ return LINK_W;
+ if (unitStr.endsWith(".h") || unitStr.endsWith(".height"))
+ return LINK_H;
+ if (unitStr.endsWith(".x2"))
+ return LINK_X2;
+ if (unitStr.endsWith(".y2"))
+ return LINK_Y2;
+ if (unitStr.endsWith(".xpos"))
+ return LINK_XPOS;
+ if (unitStr.endsWith(".ypos"))
+ return LINK_YPOS;
+
+ throw new IllegalArgumentException("Unknown keyword: " + unitStr);
+ }
+
+ final boolean isLinked()
+ {
+ return unit >= LINK_X && unit <= LINK_YPOS;
+ }
+
+ final boolean isLinkedDeep()
+ {
+ if (subUnits == null)
+ return isLinked();
+
+ for (int i = 0; i < subUnits.length; i++) {
+ if (subUnits[i].isLinkedDeep())
+ return true;
+ }
+
+ return false;
+ }
+
+ final String getLinkTargetId()
+ {
+ return unitStr.substring(0, unitStr.length() - (unit < LINK_X2 ? 2 : (unit > LINK_Y2 ? 5 : 3)));
+ }
+
+ final UnitValue getSubUnitValue(int i)
+ {
+ return subUnits[i];
+ }
+
+ final int getSubUnitCount()
+ {
+ return subUnits != null ? subUnits.length : 0;
+ }
+
+ public final UnitValue[] getSubUnits()
+ {
+ return subUnits;
+ }
+
+ public final int getUnit()
+ {
+ return unit;
+ }
+
+ public final String getUnitString()
+ {
+ return unitStr;
+ }
+
+ public final int getOperation()
+ {
+ return oper;
+ }
+
+ public final float getValue()
+ {
+ return value;
+ }
+
+ public final boolean isHorizontal()
+ {
+ return isHor;
+ }
+
+ final public String toString()
+ {
+ return getClass().getName() + ". Value=" + value + ", unit=" + unit + ", unitString: " + unitStr + ", oper=" + oper + ", isHor: " + isHor;
+ }
+
+ /** Returns the creation string for this object. Note that {@link LayoutUtil#setDesignTime(ContainerWrapper, boolean)} must be
+ * set to <code>true</code> for the creation strings to be stored.
+ * @return The constraint string or <code>null</code> if none is registered.
+ */
+ public final String getConstraintString()
+ {
+ return LayoutUtil.getCCString(this);
+ }
+
+ public final int hashCode()
+ {
+ return (int) (value * 12345) + (oper >>> 5) + unit >>> 17;
+ }
+
+ /** Adds a global unit converter that can convert from some <code>unit</code> to pixels.
+ * <p>
+ * This converter will be asked before the platform converter so the values for it (e.g. "related" and "unrelated")
+ * can be overridden. It is however not possible to override the built in ones (e.g. "mm", "pixel" or "lp").
+ * @param conv The converter. Not <code>null</code>.
+ */
+ public final synchronized static void addGlobalUnitConverter(UnitConverter conv)
+ {
+ if (conv == null)
+ throw new NullPointerException();
+ CONVERTERS.add(conv);
+ }
+
+ /** Removed the converter.
+ * @param unit The converter.
+ * @return If there was a converter found and thus removed.
+ */
+ public final synchronized static boolean removeGlobalUnitConverter(String unit)
+ {
+ return CONVERTERS.remove(unit);
+ }
+
+ /** Returns the global converters currently registered. The platform converter will not be in this list.
+ * @return The converters. Never <code>null</code>.
+ */
+ public final synchronized static UnitConverter[] getGlobalUnitConverters()
+ {
+ return CONVERTERS.toArray(new UnitConverter[CONVERTERS.size()]);
+ }
+
+ /** Returns the current default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
+ * @return The current default unit.
+ * @see #PIXEL
+ * @see #LPX
+ * @deprecated Use {@link PlatformDefaults#getDefaultHorizontalUnit()} and {@link PlatformDefaults#getDefaultVerticalUnit()} instead.
+ */
+ public final static int getDefaultUnit()
+ {
+ return PlatformDefaults.getDefaultHorizontalUnit();
+ }
+
+ /** Sets the default unit. The default unit is the unit used if no unit is set. E.g. "width 10".
+ * @param unit The new default unit.
+ * @see #PIXEL
+ * @see #LPX
+ * @deprecated Use {@link PlatformDefaults#setDefaultHorizontalUnit(int)} and {@link PlatformDefaults#setDefaultVerticalUnit(int)} instead.
+ */
+ public final static void setDefaultUnit(int unit)
+ {
+ PlatformDefaults.setDefaultHorizontalUnit(unit);
+ PlatformDefaults.setDefaultVerticalUnit(unit);
+ }
+
+ static {
+ LayoutUtil.setDelegate(UnitValue.class, new PersistenceDelegate() {
+ protected Expression instantiate(Object oldInstance, Encoder out)
+ {
+ UnitValue uv = (UnitValue) oldInstance;
+ String cs = uv.getConstraintString();
+ if (cs == null)
+ throw new IllegalStateException("Design time must be on to use XML persistence. See LayoutUtil.");
+
+ return new Expression(oldInstance, ConstraintParser.class, "parseUnitValueOrAlign", new Object[] {
+ uv.getConstraintString(), (uv.isHorizontal() ? Boolean.TRUE : Boolean.FALSE), null
+ });
+ }
+ });
+ }
+
+ // ************************************************
+ // Persistence Delegate and Serializable combined.
+ // ************************************************
+
+ private static final long serialVersionUID = 1L;
+
+ private Object readResolve() throws ObjectStreamException
+ {
+ return LayoutUtil.getSerializedObject(this);
+ }
+
+ private void writeObject(ObjectOutputStream out) throws IOException
+ {
+ if (getClass() == UnitValue.class)
+ LayoutUtil.writeAsXML(out, this);
+ }
+
+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
+ {
+ LayoutUtil.setSerializedObject(this, LayoutUtil.readAsXML(in));
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/swing/MigLayout.java b/prototypes/miglayout/net/miginfocom/swing/MigLayout.java
new file mode 100644
index 00000000..7444e9d9
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/swing/MigLayout.java
@@ -0,0 +1,549 @@
+package net.miginfocom.swing;
+/*
+ * 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 javax.swing.*;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.*;
+import java.util.*;
+
+/** A very flexbile layout manager.
+ * <p>
+ * Read the documentation that came with this layout manager for information on usage.
+ */
+public final class MigLayout implements LayoutManager2, Externalizable
+{
+ // ******** Instance part ********
+
+ /** The component to string constraints mappings.
+ */
+ private final Map<Component, Object> scrConstrMap = new IdentityHashMap<Component, Object>(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<ComponentWrapper, CC> ccMap = new HashMap<ComponentWrapper, CC>(8);
+ private transient javax.swing.Timer debugTimer = null;
+
+ private transient LC lc = null;
+ private transient AC colSpecs = null, rowSpecs = null;
+ private transient Grid grid = null;
+ private transient int lastModCount = PlatformDefaults.getModCount();
+ private transient int lastHash = -1;
+ private transient Dimension lastInvalidSize = null;
+
+ private transient ArrayList<LayoutCallback> callbackList = null;
+
+ /** Constructor with no constraints.
+ */
+ public MigLayout()
+ {
+ this("", "", "");
+ }
+
+ /** Constructor.
+ * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
+ */
+ public MigLayout(String layoutConstraints)
+ {
+ this(layoutConstraints, "", "");
+ }
+
+ /** Constructor.
+ * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as "".
+ */
+ public MigLayout(String layoutConstraints, String colConstraints)
+ {
+ this(layoutConstraints, colConstraints, "");
+ }
+
+ /** Constructor.
+ * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as "".
+ * @param rowConstraints The constraints for the rows in the grid. <code>null</code> 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. <code>null</code> 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. <code>null</code> will be treated as an empty cosntraint.
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> 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. <code>null</code> will be treated as an empty cosntraint.
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as an empty constraint.
+ * @param rowConstraints The constraints for the rows in the grid. <code>null</code> 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 <code>String</code> 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 <code>String</code> or {@link net.miginfocom.layout.LC} depending what was sent in
+ * to the constructor or set with {@link #setLayoutConstraints(Object)}. Never <code>null</code>.
+ */
+ public Object getLayoutConstraints()
+ {
+ return layoutConstraints;
+ }
+
+ /** Sets the layout constraints for the layout manager instance as a String.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param constr The layout constraints as a String representation. <code>null</code> is converted to <code>""</code> for storage.
+ * @throws RuntimeException if the constaint was not valid.
+ */
+ public void setLayoutConstraints(Object constr)
+ {
+ if (constr == null || constr instanceof String) {
+ constr = ConstraintParser.prepare((String) constr);
+ lc = ConstraintParser.parseLayoutConstraint((String) constr);
+ } else if (constr instanceof LC) {
+ lc = (LC) constr;
+ } else {
+ throw new IllegalArgumentException("Illegal constraint type: " + constr.getClass().toString());
+ }
+ layoutConstraints = constr;
+ grid = null;
+ }
+
+ /** Returns the column layout constraints either as a <code>String</code> or {@link net.miginfocom.layout.AC}.
+ * @return The column constraints eighter as a <code>String</code> or {@link net.miginfocom.layout.LC} depending what was sent in
+ * to the constructor or set with {@link #setLayoutConstraints(Object)}. Never <code>null</code>.
+ */
+ public Object getColumnConstraints()
+ {
+ return colConstraints;
+ }
+
+ /** Sets the column layout constraints for the layout manager instance as a String.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param constr The column layout constraints as a String representation. <code>null</code> is converted to <code>""</code> 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.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @return The row layout constraints as a String representation. Never <code>null</code>.
+ */
+ public Object getRowConstraints()
+ {
+ return rowConstraints;
+ }
+
+ /** Sets the row layout constraints for the layout manager instance as a String.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param constr The row layout constraints as a String representation. <code>null</code> is converted to <code>""</code> 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 the component constraints as a String representation. This string is the exact string as set with {@link #setComponentConstraints(java.awt.Component, Object)}
+ * or set when adding the component to the parent component.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param comp The component to return the constraints for.
+ * @return The component constraints as a String representation ir <code>null</code> if the component is not registered
+ * with this layout manager. The returned values is either a String or a {@link net.miginfocom.layout.CC}
+ * depending on what constraint was sent in when the component was added. May be <code>null</code>.
+ */
+ public Object getComponentConstraints(Component comp)
+ {
+ synchronized(comp.getParent().getTreeLock()) {
+ return scrConstrMap.get(comp);
+ }
+ }
+
+ /** Sets the component constraint for the component that already must be handleded by this layout manager.
+ * <p>
+ * 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}. <code>null</code> is ok.
+ * @param comp The component to set the constraints for.
+ * @throws RuntimeException if the constaint was not valid.
+ * @throws IllegalArgumentException If the component is not handlering the component.
+ */
+ public void setComponentConstraints(Component comp, Object constr)
+ {
+ setComponentConstraintsImpl(comp, constr, false);
+ }
+
+ /** Sets the component constraint for the component that already must be handleded by this layout manager.
+ * <p>
+ * 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}. <code>null</code> is ok.
+ * @param comp The component to set the constraints for.
+ * @throws RuntimeException if the constaint was not valid.
+ * @throws IllegalArgumentException If the component is not handling the component.
+ */
+ private void setComponentConstraintsImpl(Component comp, Object constr, boolean noCheck)
+ {
+ Container parent = comp.getParent();
+ synchronized(parent.getTreeLock()) {
+ if (noCheck == false && scrConstrMap.containsKey(comp) == false)
+ throw new IllegalArgumentException("Component must already be added to parent!");
+
+ ComponentWrapper cw = new SwingComponentWrapper(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 <code>null</code> then <code>false</code> will be returned.
+ * @return If this layout manager is currently managing this component.
+ */
+ public boolean isManagingComponent(Component 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 <code>null</code>.
+ */
+ public void addLayoutCallback(LayoutCallback callback)
+ {
+ if (callback == null)
+ throw new NullPointerException();
+
+ if (callbackList == null)
+ callbackList = new ArrayList<LayoutCallback>(1);
+
+ callbackList.add(callback);
+ }
+
+ /** Removes the callback if it exists.
+ * @param callback The callback. May be <code>null</code>.
+ */
+ 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.
+ * <p>
+ * Red fill and dashed darked red outline is used to indicate occupied cells in the grid. Blue dashed outline indicate indicate
+ * component bounds set.
+ * <p>
+ * 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 b <code>true</code> means debug is turned on.
+ */
+ private synchronized void setDebug(final ComponentWrapper parentW, boolean b)
+ {
+ if (b && (debugTimer == null || debugTimer.getDelay() != lc.getDebugMillis())) {
+ if (debugTimer != null)
+ debugTimer.stop();
+
+ ContainerWrapper pCW = parentW.getParent();
+ final Component parent = pCW != null ? (Component) pCW.getComponent() : null;
+
+ debugTimer = new javax.swing.Timer(lc.getDebugMillis(), new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ if (grid != null)
+ grid.paintDebug();
+ }
+ });
+
+ if (parent != null) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ Container p = parent.getParent();
+ if (p != null) {
+ if (p instanceof JComponent) {
+ ((JComponent) p).revalidate();
+ } else {
+ parent.invalidate();
+ p.validate();
+ }
+ }
+ }
+ });
+ }
+
+ debugTimer.setInitialDelay(100);
+ debugTimer.start();
+
+ } else if (!b && debugTimer != null) {
+ debugTimer.stop();
+ debugTimer = null;
+ }
+ }
+
+ /** Returns the current debugging state.
+ * @return The current debugging state.
+ */
+ private boolean getDebug()
+ {
+ return debugTimer != null;
+ }
+
+ /** 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(Container parent)
+ {
+ if (parent == null)
+ return;
+
+ // Check if the grid is valid
+ int mc = PlatformDefaults.getModCount();
+ if (lastModCount != mc) {
+ grid = null;
+ lastModCount = mc;
+ }
+
+ if (parent.isValid() == false) {
+
+ int hash = 0;
+ for (Iterator<ComponentWrapper> it = ccMap.keySet().iterator(); it.hasNext();)
+ hash += it.next().getLayoutHashCode();
+
+ if (hash != lastHash) {
+ grid = null;
+ lastHash = hash;
+ }
+
+ Dimension ps = parent.getSize();
+ if (lastInvalidSize == null || !lastInvalidSize.equals(ps)) {
+ if (grid != null)
+ grid.invalidateContainerSize();
+ lastInvalidSize = ps;
+ }
+ }
+
+ ContainerWrapper par = checkParent(parent);
+
+ setDebug(par, lc.getDebugMillis() > 0);
+
+ if (grid == null)
+ grid = new Grid(par, lc, rowSpecs, colSpecs, ccMap, callbackList);
+ }
+
+ private final ContainerWrapper checkParent(Container parent)
+ {
+ if (parent == null)
+ return null;
+
+ if (cacheParentW == null || cacheParentW.getComponent() != parent)
+ cacheParentW = new SwingContainerWrapper(parent);
+
+ return cacheParentW;
+ }
+
+ public void layoutContainer(Container parent)
+ {
+ synchronized(parent.getTreeLock()) {
+ checkCache(parent);
+
+ Insets i = parent.getInsets();
+ int[] b = new int[] {
+ i.left,
+ i.top,
+ parent.getWidth() - i.left - i.right,
+ parent.getHeight() - i.top - i.bottom
+ };
+
+ grid.layout(b, lc.getAlignX(), lc.getAlignY(), getDebug(), false);
+ lastInvalidSize = null;
+ }
+ }
+
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ synchronized(parent.getTreeLock()) {
+ return getSizeImpl(parent, LayoutUtil.MIN);
+ }
+ }
+
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ synchronized(parent.getTreeLock()) {
+ return getSizeImpl(parent, LayoutUtil.PREF);
+ }
+ }
+
+ public Dimension maximumLayoutSize(Container parent)
+ {
+ return new Dimension(Short.MAX_VALUE, Short.MAX_VALUE);
+ }
+
+ // Implementation method that does the job.
+ private Dimension getSizeImpl(Container parent, int sizeType)
+ {
+ checkCache(parent);
+
+ Insets i = parent.getInsets();
+
+ int w = LayoutUtil.getSizeSafe(grid != null ? grid.getWidth() : null, sizeType) + i.left + i.right;
+ int h = LayoutUtil.getSizeSafe(grid != null ? grid.getHeight() : null, sizeType) + i.top + i.bottom;
+
+ return new Dimension(w, h);
+ }
+
+ public float getLayoutAlignmentX(Container parent)
+ {
+ return lc != null && lc.getAlignX() != null ? lc.getAlignX().getPixels(1, checkParent(parent), null) : 0;
+ }
+
+ public float getLayoutAlignmentY(Container parent)
+ {
+ return lc != null && lc.getAlignY() != null ? lc.getAlignY().getPixels(1, checkParent(parent), null) : 0;
+ }
+
+ public void addLayoutComponent(String s, Component comp)
+ {
+ addLayoutComponent(comp, s);
+ }
+
+ public void addLayoutComponent(Component comp, Object constraints)
+ {
+ synchronized(comp.getParent().getTreeLock()) {
+ setComponentConstraintsImpl(comp, constraints, true);
+ }
+ }
+
+ public void removeLayoutComponent(Component comp)
+ {
+ synchronized(comp.getParent().getTreeLock()) {
+ scrConstrMap.remove(comp);
+ ccMap.remove(new SwingComponentWrapper(comp));
+ }
+ }
+
+ public void invalidateLayout(Container target)
+ {
+ if (lc.isNoCache())
+ grid = null;
+
+ // the validity of components is maintained automatically.
+ }
+
+ // ************************************************
+ // 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);
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/swing/SwingComponentWrapper.java b/prototypes/miglayout/net/miginfocom/swing/SwingComponentWrapper.java
new file mode 100644
index 00000000..35b069be
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/swing/SwingComponentWrapper.java
@@ -0,0 +1,426 @@
+package net.miginfocom.swing;
+/*
+ * 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.ComponentWrapper;
+import net.miginfocom.layout.ContainerWrapper;
+import net.miginfocom.layout.PlatformDefaults;
+
+import javax.swing.*;
+import javax.swing.text.JTextComponent;
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.lang.reflect.Method;
+import java.util.IdentityHashMap;
+
+/**
+ */
+public class SwingComponentWrapper implements ComponentWrapper
+{
+ private static boolean maxSet = false;
+
+ private static boolean vp = true;
+
+ /** Debug color for component bounds outline.
+ */
+ private static final Color DB_COMP_OUTLINE = new Color(0, 0, 200);
+
+ private final Component c;
+ private int compType = TYPE_UNSET;
+ private final boolean bl;
+
+ public SwingComponentWrapper(Component c)
+ {
+ this.c = c;
+ bl = getBaseline(c.getWidth(), c.getHeight()) != -1;
+ }
+
+ public final int getBaseline(int width, int height)
+ {
+ if (BL_METHOD == null)
+ return -1;
+
+ try {
+ Object[] args = new Object[] {
+ new Integer(width == -1 ? c.getWidth() : width),
+ new Integer(height == -1 ? c.getHeight() : height)
+ };
+ return ((Integer) BL_METHOD.invoke(c, args)).intValue();
+ } catch (Exception e) {
+ return -1;
+ }
+ }
+
+ public final Object getComponent()
+ {
+ return c;
+ }
+
+ /** Cache.
+ */
+ private final static IdentityHashMap<FontMetrics, Point.Float> FM_MAP = new IdentityHashMap<FontMetrics, Point.Float>(4);
+ private final static Font SUBST_FONT = new Font("sansserif", Font.PLAIN, 11);
+
+ public final float getPixelUnitFactor(boolean isHor)
+ {
+ switch (PlatformDefaults.getLogicalPixelBase()) {
+ case PlatformDefaults.BASE_FONT_SIZE:
+ Font font = c.getFont();
+ FontMetrics fm = c.getFontMetrics(font != null ? font : SUBST_FONT);
+ Point.Float p = FM_MAP.get(fm);
+ if (p == null) {
+ Rectangle2D r = fm.getStringBounds("X", c.getGraphics());
+ p = new Point.Float(((float) r.getWidth()) / 6f, ((float) r.getHeight()) / 13.27734375f);
+ FM_MAP.put(fm, p);
+ }
+ return isHor ? p.x : p.y;
+
+ case PlatformDefaults.BASE_SCALE_FACTOR:
+ Float s = isHor ? PlatformDefaults.getHorizontalScaleFactor() : PlatformDefaults.getVerticalScaleFactor();
+ if (s != null)
+ return s.floatValue();
+ return (isHor ? getHorizontalScreenDPI() : getVerticalScreenDPI()) / (float) PlatformDefaults.getDefaultDPI();
+
+ default:
+ return 1f;
+ }
+ }
+
+// /** Cache.
+// */
+// private final static IdentityHashMap<FontMetrics, Point.Float> FM_MAP2 = new IdentityHashMap<FontMetrics, Point.Float>(4);
+// private final static Font SUBST_FONT2 = new Font("sansserif", Font.PLAIN, 11);
+//
+// public float getDialogUnit(boolean isHor)
+// {
+// Font font = c.getFont();
+// FontMetrics fm = c.getFontMetrics(font != null ? font : SUBST_FONT2);
+// Point.Float dluP = FM_MAP2.get(fm);
+// if (dluP == null) {
+// float w = fm.charWidth('X') / 4f;
+// int ascent = fm.getAscent();
+// float h = (ascent > 14 ? ascent : ascent + (15 - ascent) / 3) / 8f;
+//
+// dluP = new Point.Float(w, h);
+// FM_MAP2.put(fm, dluP);
+// }
+// return isHor ? dluP.x : dluP.y;
+// }
+
+ public final int getX()
+ {
+ return c.getX();
+ }
+
+ public final int getY()
+ {
+ return c.getY();
+ }
+
+ public final int getHeight()
+ {
+ return c.getHeight();
+ }
+
+ public final int getWidth()
+ {
+ return c.getWidth();
+ }
+
+ public final int getScreenLocationX()
+ {
+ Point p = new Point();
+ SwingUtilities.convertPointToScreen(p, c);
+ return p.x;
+ }
+
+ public final int getScreenLocationY()
+ {
+ Point p = new Point();
+ SwingUtilities.convertPointToScreen(p, c);
+ return p.y;
+ }
+
+ public final int getMinimumHeight()
+ {
+ c.getPreferredSize(); // To defeat a bug where the minimum size is difference before and after the first call to getPreferredSize();
+ return c.getMinimumSize().height;
+ }
+
+ public final int getMinimumWidth()
+ {
+ c.getPreferredSize(); // To defeat a bug where the minimum size is difference before and after the first call to getPreferredSize();
+ return c.getMinimumSize().width;
+ }
+
+ public final int getPreferredHeight()
+ {
+ return c.getPreferredSize().height;
+ }
+
+ public final int getPreferredWidth()
+ {
+ return c.getPreferredSize().width;
+ }
+
+ public final int getMaximumHeight()
+ {
+ if (!isMaxSet(c))
+ return Short.MAX_VALUE;
+
+ return c.getMaximumSize().height;
+ }
+
+ public final int getMaximumWidth()
+ {
+ if (!isMaxSet(c))
+ return Short.MAX_VALUE;
+
+ return c.getMaximumSize().width;
+ }
+
+
+ private boolean isMaxSet(Component c)
+ {
+ if (IMS_METHOD != null) {
+ try {
+ return ((Boolean) IMS_METHOD.invoke(c, null)).booleanValue();
+ } catch (Exception e) {
+ IMS_METHOD = null; // So we do not try every time.
+ }
+ }
+ return isMaxSizeSetOn1_4();
+ }
+
+ public final ContainerWrapper getParent()
+ {
+ Container p = c.getParent();
+ return p != null ? new SwingContainerWrapper(p) : null;
+ }
+
+ public final int getHorizontalScreenDPI()
+ {
+ return c.getToolkit().getScreenResolution();
+ }
+
+ public final int getVerticalScreenDPI()
+ {
+ return c.getToolkit().getScreenResolution();
+ }
+
+ public final int getScreenWidth()
+ {
+ return c.getToolkit().getScreenSize().width;
+ }
+
+ public final int getScreenHeight()
+ {
+ return c.getToolkit().getScreenSize().height;
+ }
+
+ public final boolean hasBaseline()
+ {
+ return bl;
+ }
+
+ public final String getLinkId()
+ {
+ return c.getName();
+ }
+
+ public final void setBounds(int x, int y, int width, int height)
+ {
+ c.setBounds(x, y, width, height);
+ }
+
+ public boolean isVisible()
+ {
+ return c.isVisible();
+ }
+
+ public final int[] getVisualPadding()
+ {
+ if (vp && c instanceof JTabbedPane) {
+ if (UIManager.getLookAndFeel().getClass().getName().endsWith("WindowsLookAndFeel"))
+ return new int[] {-1, 0, 2, 2};
+ }
+ return null;
+ }
+
+ public static boolean isMaxSizeSetOn1_4()
+ {
+ return maxSet;
+ }
+
+ public static void setMaxSizeSetOn1_4(boolean b)
+ {
+ maxSet = b;
+ }
+
+ public final static boolean isVisualPaddingEnabled()
+ {
+ return vp;
+ }
+
+ public final static void setVisualPaddingEnabled(boolean b)
+ {
+ vp = b;
+ }
+
+ public final void paintDebugOutline()
+ {
+ if (c.isShowing() == false)
+ return;
+
+ Graphics2D g = (Graphics2D) c.getGraphics();
+ if (g == null)
+ return;
+
+ g.setPaint(DB_COMP_OUTLINE);
+ g.setStroke(new BasicStroke(1f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[] {2f, 4f}, 0));
+ g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
+ }
+
+ public int getComponetType(boolean disregardScrollPane)
+ {
+ if (compType == TYPE_UNSET)
+ compType = checkType(disregardScrollPane);
+
+ return compType;
+ }
+
+ public int getLayoutHashCode()
+ {
+ Dimension d = c.getMaximumSize();
+ int h = d.width + (d.height << 5);
+
+ d = c.getPreferredSize();
+ h += (d.width << 10) + (d.height << 15);
+
+ d = c.getMinimumSize();
+ h += (d.width << 20) + (d.height << 25);
+
+ if (c.isVisible())
+ h += 1324511;
+
+ String id = getLinkId();
+ if (id != null)
+ h += id.hashCode();
+ return h;
+
+ // Since 2.3 will check the isValid instead everything that affects that can be removed from the layout hashcode.
+
+// String id = getLinkId();
+// return id != null ? id.hashCode() : 1;
+ }
+
+ private final int checkType(boolean disregardScrollPane)
+ {
+ Component c = this.c;
+
+ if (disregardScrollPane) {
+ if (c instanceof JScrollPane) {
+ c = ((JScrollPane) c).getViewport().getView();
+ } else if (c instanceof ScrollPane) {
+ c = ((ScrollPane) c).getComponent(0);
+ }
+ }
+
+ if (c instanceof JTextField || c instanceof TextField) {
+ return TYPE_TEXT_FIELD;
+ } else if (c instanceof JLabel || c instanceof Label) {
+ return TYPE_LABEL;
+ } else if (c instanceof JToggleButton || c instanceof Checkbox) {
+ return TYPE_CHECK_BOX;
+ } else if (c instanceof AbstractButton || c instanceof Button) {
+ return TYPE_BUTTON;
+ } else if (c instanceof JComboBox || c instanceof Choice) {
+ return TYPE_LABEL;
+ } else if (c instanceof JTextComponent || c instanceof TextComponent) {
+ return TYPE_TEXT_AREA;
+ } else if (c instanceof JPanel || c instanceof Canvas) {
+ return TYPE_PANEL;
+ } else if (c instanceof JList || c instanceof List) {
+ return TYPE_LIST;
+ } else if (c instanceof JTable) {
+ return TYPE_TABLE;
+ } else if (c instanceof JSeparator) {
+ return TYPE_SEPARATOR;
+ } else if (c instanceof JSpinner) {
+ return TYPE_SPINNER;
+ } else if (c instanceof JProgressBar) {
+ return TYPE_PROGRESS_BAR;
+ } else if (c instanceof JSlider) {
+ return TYPE_SLIDER;
+ } else if (c instanceof JScrollPane) {
+ return TYPE_SCROLL_PANE;
+ } else if (c instanceof JScrollBar || c instanceof Scrollbar) {
+ return TYPE_SCROLL_BAR;
+ } else if (c instanceof Container) { // only AWT components is not containers.
+ return TYPE_CONTAINER;
+ }
+ return TYPE_UNKNOWN;
+ }
+
+ public final int hashCode()
+ {
+ return getComponent().hashCode();
+ }
+
+ public final boolean equals(Object o)
+ {
+ if (o instanceof ComponentWrapper == false)
+ return false;
+
+ return getComponent().equals(((ComponentWrapper) o).getComponent());
+ }
+
+ /** Cached method used for getting base line with reflection.
+ */
+ private static Method BL_METHOD = null;
+ static {
+ try {
+ BL_METHOD = Component.class.getDeclaredMethod("getBaseline", new Class[] {int.class, int.class});
+ } catch (Throwable e) { // No such method or security exception
+ }
+ }
+
+ private static Method IMS_METHOD = null;
+ static {
+ try {
+ IMS_METHOD = Component.class.getDeclaredMethod("isMaximumSizeSet", null);
+ } catch (Throwable e) { // No such method or security exception
+ }
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/swing/SwingContainerWrapper.java b/prototypes/miglayout/net/miginfocom/swing/SwingContainerWrapper.java
new file mode 100644
index 00000000..ae48876e
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/swing/SwingContainerWrapper.java
@@ -0,0 +1,108 @@
+package net.miginfocom.swing;
+/*
+ * 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.ComponentWrapper;
+import net.miginfocom.layout.ContainerWrapper;
+
+import java.awt.*;
+
+/**
+ */
+public final class SwingContainerWrapper extends SwingComponentWrapper implements ContainerWrapper
+{
+ /** Debug color for cell outline.
+ */
+ private static final Color DB_CELL_OUTLINE = new Color(255, 0, 0);
+
+ public SwingContainerWrapper(Container c)
+ {
+ super(c);
+ }
+
+ public ComponentWrapper[] getComponents()
+ {
+ Container c = (Container) getComponent();
+ ComponentWrapper[] cws = new ComponentWrapper[c.getComponentCount()];
+ for (int i = 0; i < cws.length; i++)
+ cws[i] = new SwingComponentWrapper(c.getComponent(i));
+ return cws;
+ }
+
+ public int getComponentCount()
+ {
+ return ((Container) getComponent()).getComponentCount();
+ }
+
+ public Object getLayout()
+ {
+ return ((Container) getComponent()).getLayout();
+ }
+
+ public final boolean isLeftToRight()
+ {
+ return ((Container) getComponent()).getComponentOrientation().isLeftToRight();
+ }
+
+ public final void paintDebugCell(int x, int y, int width, int height)
+ {
+ Component c = (Component) getComponent();
+ if (c.isShowing() == false)
+ return;
+
+ Graphics2D g = (Graphics2D) c.getGraphics();
+ if (g == null)
+ return;
+
+ g.setStroke(new BasicStroke(1f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[] {2f, 3f}, 0));
+ g.setPaint(DB_CELL_OUTLINE);
+ g.drawRect(x, y, width - 1, height - 1);
+ }
+
+ public int getComponetType(boolean disregardScrollPane)
+ {
+ return TYPE_CONTAINER;
+ }
+
+ // Removed for 2.3 because the parent.isValid() in MigLayout will catch this instead.
+// public int getLayoutHashCode()
+// {
+// int h = super.getLayoutHashCode();
+//
+// if (isLeftToRight())
+// h += 416343;
+//
+// return h;
+// }
+}
diff --git a/prototypes/miglayout/net/miginfocom/swt/MigLayout.java b/prototypes/miglayout/net/miginfocom/swt/MigLayout.java
new file mode 100644
index 00000000..a36408fb
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/swt/MigLayout.java
@@ -0,0 +1,506 @@
+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.*;
+import org.eclipse.swt.widgets.Composite;
+
+import java.io.*;
+import java.util.*;
+
+/** A very flexbile layout manager.
+ * <p>
+ * 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<Control, Object> scrConstrMap = new IdentityHashMap<Control, Object>(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<ComponentWrapper, CC> ccMap = new HashMap<ComponentWrapper, CC>(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<LayoutCallback> callbackList = null;
+
+ /** Constructor with no constraints.
+ */
+ public MigLayout()
+ {
+ this("", "", "");
+ }
+
+ /** Constructor.
+ * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
+ */
+ public MigLayout(String layoutConstraints)
+ {
+ this(layoutConstraints, "", "");
+ }
+
+ /** Constructor.
+ * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as "".
+ */
+ public MigLayout(String layoutConstraints, String colConstraints)
+ {
+ this(layoutConstraints, colConstraints, "");
+ }
+
+ /** Constructor.
+ * @param layoutConstraints The constraints that concern the whole layout. <code>null</code> will be treated as "".
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as "".
+ * @param rowConstraints The constraints for the rows in the grid. <code>null</code> 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. <code>null</code> 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. <code>null</code> will be treated as an empty cosntraint.
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> 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. <code>null</code> will be treated as an empty cosntraint.
+ * @param colConstraints The constraints for the columns in the grid. <code>null</code> will be treated as an empty constraint.
+ * @param rowConstraints The constraints for the rows in the grid. <code>null</code> 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 <code>String</code> 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 <code>String</code> or {@link net.miginfocom.layout.LC} depending what was sent in
+ * to the constructor or set with {@link #setLayoutConstraints(Object)}. Never <code>null</code>.
+ */
+ public Object getLayoutConstraints()
+ {
+ return layoutConstraints;
+ }
+
+ /** Sets the layout constraints for the layout manager instance as a String.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param s The layout constraints as a String representation. <code>null</code> is converted to <code>""</code> 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 <code>String</code> or {@link net.miginfocom.layout.AC}.
+ * @return The column constraints eighter as a <code>String</code> or {@link net.miginfocom.layout.LC} depending what was sent in
+ * to the constructor or set with {@link #setLayoutConstraints(Object)}. Never <code>null</code>.
+ */
+ public Object getColumnConstraints()
+ {
+ return colConstraints;
+ }
+
+ /** Sets the column layout constraints for the layout manager instance as a String.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param constr The column layout constraints as a String representation. <code>null</code> is converted to <code>""</code> 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.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @return The row layout constraints as a String representation. Never <code>null</code>.
+ */
+ public Object getRowConstraints()
+ {
+ return rowConstraints;
+ }
+
+ /** Sets the row layout constraints for the layout manager instance as a String.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param constr The row layout constraints as a String representation. <code>null</code> is converted to <code>""</code> 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 the component constraints as a String representation. This string is the exact string as set with {@link #setComponentConstraints(org.eclipse.swt.widgets.Control, Object)}
+ * or set when adding the component to the parent component.
+ * <p>
+ * See the class JavaDocs for information on how this string is formatted.
+ * @param comp The component to return the constraints for.
+ * @return The component constraints as a String representation ir <code>null</code> if the component is not registered
+ * with this layout manager. The returned values is wither a String or a {@link net.miginfocom.layout.CC}
+ * depending on what constraint was sent in when the component was added. May be <code>null</code>.
+ */
+ public Object getComponentConstraints(Control comp)
+ {
+ return scrConstrMap.get(comp);
+ }
+
+ /** Sets the component constraint for the component that already must be handleded by this layout manager.
+ * <p>
+ * 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}. <code>null</code> is ok.
+ * @param comp The component to set the constraints for.
+ * @throws RuntimeException if the constaint was not valid.
+ * @throws IllegalArgumentException If the component is not handlering the component.
+ */
+ public void setComponentConstraints(Control comp, Object constr)
+ {
+ setComponentConstraintsImpl(comp, constr, false);
+ }
+
+ /** Sets the component constraint for the component that already must be handleded by this layout manager.
+ * <p>
+ * 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}. <code>null</code> is ok.
+ * @param comp The component to set the constraints for.
+ * @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 <code>null</code> then <code>false</code> 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 <code>null</code>.
+ */
+ public void addLayoutCallback(LayoutCallback callback)
+ {
+ if (callback == null)
+ throw new NullPointerException();
+
+ if (callbackList == null)
+ callbackList = new ArrayList<LayoutCallback>(1);
+
+ callbackList.add(callback);
+ }
+
+ /** Removes the callback if it exists.
+ * @param callback The callback. May be <code>null</code>.
+ */
+ 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.
+ * <p>
+ * Red fill and dashed darked red outline is used to indicate occupied cells in the grid. Blue dashed outline indicate indicate
+ * component bounds set.
+ * <p>
+ * 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 b <code>true</code> means debug is turned on.
+ */
+ private synchronized void setDebug(final ComponentWrapper parentW, boolean b)
+ {
+ if (b && (debugTimer == null || curDelay != lc.getDebugMillis())) {
+ if (debugTimer != null)
+ debugTimer.cancel();
+
+ TimerTask debugTask = new TimerTask() {
+ public void run()
+ {
+ Display.getDefault ().asyncExec(new Runnable () {
+ public void run () {
+ grid.paintDebug();
+ }
+ });
+ }
+ };
+
+ debugTimer = new Timer(true);
+ curDelay = lc.getDebugMillis();
+ debugTimer.schedule(debugTask, 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;
+ }
+
+ /** 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<ComponentWrapper> it = ccMap.keySet().iterator(); it.hasNext();)
+ hash += it.next().getLayoutHashCode();
+
+ if (hash != lastHash) {
+ grid = null;
+ lastHash = hash;
+ }
+
+ setDebug(par, lc.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())
+ 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);
+ }
+} \ No newline at end of file
diff --git a/prototypes/miglayout/net/miginfocom/swt/SwtComponentWrapper.java b/prototypes/miglayout/net/miginfocom/swt/SwtComponentWrapper.java
new file mode 100644
index 00000000..aa7647a7
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/swt/SwtComponentWrapper.java
@@ -0,0 +1,359 @@
+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.ComponentWrapper;
+import net.miginfocom.layout.ContainerWrapper;
+import net.miginfocom.layout.PlatformDefaults;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.*;
+import org.eclipse.swt.widgets.*;
+
+/**
+ */
+public class SwtComponentWrapper implements ComponentWrapper
+{
+ /** Debug color for component bounds outline.
+ */
+ private static Color DB_COMP_OUTLINE = new Color(Display.getCurrent(), 0, 0, 200);
+
+ private static boolean vp = false;
+ private static boolean mz = false;
+
+ private final Control c;
+ private int compType = TYPE_UNSET;
+
+ public SwtComponentWrapper(Control c)
+ {
+ this.c = c;
+ }
+
+ public final int getBaseline(int width, int height)
+ {
+ return -1;
+ }
+
+ public final Object getComponent()
+ {
+ return c;
+ }
+
+ public final float getPixelUnitFactor(boolean isHor)
+ {
+ switch (PlatformDefaults.getLogicalPixelBase()) {
+ case PlatformDefaults.BASE_FONT_SIZE:
+ GC gc = new GC(c);
+ FontMetrics fm = gc.getFontMetrics();
+ float f = isHor ? fm.getAverageCharWidth() / 5f : fm.getHeight() / 13f;
+ gc.dispose();
+ return f;
+
+ case PlatformDefaults.BASE_SCALE_FACTOR:
+ Float s = isHor ? PlatformDefaults.getHorizontalScaleFactor() : PlatformDefaults.getVerticalScaleFactor();
+ if (s != null)
+ return s.floatValue();
+ return (isHor ? getHorizontalScreenDPI() : getVerticalScreenDPI()) / (float) PlatformDefaults.getDefaultDPI();
+
+ default:
+ return 1f;
+ }
+ }
+
+// /** Cache.
+// */
+// private final static IdentityHashMap<FontMetrics, Point.Float> FM_MAP2 = new IdentityHashMap<FontMetrics, Point.Float>(4);
+// private final static Font SUBST_FONT2 = new Font("sansserif", Font.PLAIN, 11);
+//
+// public float getDialogUnit(boolean isHor)
+// {
+// Font font = c.getFont();
+// FontMetrics fm = c.getFontMetrics(font != null ? font : SUBST_FONT2);
+// Point.Float dluP = FM_MAP2.get(fm);
+// if (dluP == null) {
+// float w = fm.charWidth('X') / 4f;
+// int ascent = fm.getAscent();
+// float h = (ascent > 14 ? ascent : ascent + (15 - ascent) / 3) / 8f;
+//
+// dluP = new Point.Float(w, h);
+// FM_MAP2.put(fm, dluP);
+// }
+// return isHor ? dluP.x : dluP.y;
+// }
+
+ public final int getX()
+ {
+ return c.getLocation().x;
+ }
+
+ public final int getY()
+ {
+ return c.getLocation().y;
+ }
+
+ public final int getWidth()
+ {
+ return c.getSize().x;
+ }
+
+ public final int getHeight()
+ {
+ return c.getSize().y;
+ }
+
+ public final int getScreenLocationX()
+ {
+ return c.toDisplay(0, 0).x;
+ }
+
+ public final int getScreenLocationY()
+ {
+ return c.toDisplay(0, 0).y;
+ }
+
+ public final int getMinimumHeight()
+ {
+ return mz ? 0 : computeSize(false).y;
+ }
+
+ public final int getMinimumWidth()
+ {
+ return mz ? 0 : computeSize(true).x;
+ }
+
+ public final int getPreferredHeight()
+ {
+ return computeSize(false).y;
+ }
+
+ public final int getPreferredWidth()
+ {
+ return computeSize(true).x;
+ }
+
+ public final int getMaximumHeight()
+ {
+ return Short.MAX_VALUE;
+ }
+
+ public final int getMaximumWidth()
+ {
+ return Short.MAX_VALUE;
+ }
+
+ private final Point computeSize(boolean h)
+ {
+ Point p = c.getSize();
+ int wHint = (h || p.x <= 0) ? SWT.DEFAULT : p.x;
+ int hHint = (!h || p.y <= 0) ? SWT.DEFAULT : p.y;
+
+ if (wHint != SWT.DEFAULT || hHint != SWT.DEFAULT) {
+ int trim = 0;
+ if (c instanceof Scrollable) {
+ Rectangle rect = ((Scrollable) c).computeTrim (0, 0, 0, 0);
+ trim = h ? rect.height : rect.width;
+ } else {
+ trim = (c.getBorderWidth () << 1);
+ }
+ if (wHint == SWT.DEFAULT) {
+ hHint = Math.max (0, hHint - trim);
+ } else {
+ wHint = Math.max (0, wHint - trim);
+ }
+ }
+
+ return c.computeSize(wHint, hHint);
+ }
+
+ public final ContainerWrapper getParent()
+ {
+ return new SwtContainerWrapper(c.getParent());
+ }
+
+ public int getHorizontalScreenDPI()
+ {
+ return c.getDisplay().getDPI().x;
+ }
+
+ public int getVerticalScreenDPI()
+ {
+ return c.getDisplay().getDPI().y;
+ }
+
+ public final int getScreenWidth()
+ {
+ return c.getDisplay().getBounds().width;
+ }
+
+ public final int getScreenHeight()
+ {
+ return c.getDisplay().getBounds().height;
+ }
+
+ public final boolean hasBaseline()
+ {
+ return false;
+ }
+
+ public final String getLinkId()
+ {
+ return null;
+ }
+
+ public final void setBounds(int x, int y, int width, int height)
+ {
+ c.setBounds(x, y, width, height);
+ }
+
+ public boolean isVisible()
+ {
+ return c.getVisible();
+ }
+
+ public final int[] getVisualPadding()
+ {
+ return null;
+ }
+
+ public final static boolean isUseVisualPadding()
+ {
+ return vp;
+ }
+
+ public final static void setUseVisualPadding(boolean b)
+ {
+ vp = b;
+ }
+
+ /** Sets if minimum size for SWT components should be preferred size (default, false) or 0.
+ * @return <code>true</code> means minimum size is 0.
+ */
+ public static boolean isMinimumSizeZero()
+ {
+ return mz;
+ }
+
+ /** Sets if minimum size for SWT components should be preferred size (default, false) or 0.
+ * @param b <code>true</code> means minimum size is 0.
+ */
+ public static void setMinimumSizeZero(boolean b)
+ {
+ mz = b;
+ }
+
+ public int getLayoutHashCode()
+ {
+ if (c.isDisposed())
+ return -1;
+
+ Point sz = c.getSize();
+ Point p = c.computeSize(sz.x > 0 ? sz.x : SWT.DEFAULT, SWT.DEFAULT, false);
+ int h = p.x + (p.y << 12) + (sz.x << 22) + (sz.y << 16);
+
+ if (c.isVisible())
+ h |= (1 << 25);
+
+ String id = getLinkId();
+ if (id != null)
+ h += id.hashCode();
+ return h;
+ }
+
+ public final void paintDebugOutline()
+ {
+ if (c.isDisposed())
+ return;
+
+ GC gc = new GC(c);
+
+ gc.setLineJoin(SWT.JOIN_MITER);
+ gc.setLineCap(SWT.CAP_SQUARE);
+ gc.setLineStyle(SWT.LINE_DOT);
+
+ gc.setForeground(DB_COMP_OUTLINE);
+ gc.drawRectangle(0, 0, getWidth() - 1, getHeight() - 1);
+
+ gc.dispose();
+ }
+
+ public int getComponetType(boolean disregardScrollPane)
+ {
+ if (compType == TYPE_UNSET)
+ compType = checkType();
+
+ return compType;
+ }
+
+ private final int checkType()
+ {
+ int s = c.getStyle();
+
+ if (c instanceof Text) {
+ return (s & SWT.MULTI) > 0 ? TYPE_TEXT_AREA : TYPE_TEXT_FIELD;
+ } else if (c instanceof Label) {
+ return (s & SWT.SEPARATOR) > 0 ? TYPE_SEPARATOR : TYPE_LABEL;
+ } else if (c instanceof Button) {
+ if ((s & SWT.CHECK) > 0 || (s & SWT.RADIO) > 0)
+ return TYPE_CHECK_BOX;
+ return TYPE_BUTTON;
+ } else if (c instanceof Canvas) {
+ return TYPE_PANEL;
+ } else if (c instanceof List) {
+ return TYPE_LIST;
+ } else if (c instanceof Table) {
+ return TYPE_TABLE;
+ } else if (c instanceof Spinner) {
+ return TYPE_SPINNER;
+ } else if (c instanceof ProgressBar) {
+ return TYPE_PROGRESS_BAR;
+ } else if (c instanceof Slider) {
+ return TYPE_SLIDER;
+ } else if (c instanceof Composite) { // only AWT components is not containers.
+ return TYPE_CONTAINER;
+ }
+ return TYPE_UNKNOWN;
+ }
+
+ public final int hashCode()
+ {
+ return getComponent().hashCode();
+ }
+
+ public final boolean equals(Object o)
+ {
+ if (o == null || o instanceof ComponentWrapper == false)
+ return false;
+
+ return getComponent().equals(((ComponentWrapper) o).getComponent());
+ }
+}
diff --git a/prototypes/miglayout/net/miginfocom/swt/SwtContainerWrapper.java b/prototypes/miglayout/net/miginfocom/swt/SwtContainerWrapper.java
new file mode 100644
index 00000000..033bb2bf
--- /dev/null
+++ b/prototypes/miglayout/net/miginfocom/swt/SwtContainerWrapper.java
@@ -0,0 +1,112 @@
+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.ComponentWrapper;
+import net.miginfocom.layout.ContainerWrapper;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.SWT;
+
+/**
+ */
+public final class SwtContainerWrapper extends SwtComponentWrapper implements ContainerWrapper
+{
+ public SwtContainerWrapper(Composite c)
+ {
+ super(c);
+ }
+
+ public ComponentWrapper[] getComponents()
+ {
+ Composite c = (Composite) getComponent();
+ Control[] cons = c.getChildren();
+ ComponentWrapper[] cws = new ComponentWrapper[cons.length];
+ for (int i = 0; i < cws.length; i++)
+ cws[i] = new SwtComponentWrapper(cons[i]);
+ return cws;
+ }
+
+ public int getComponentCount()
+ {
+ return ((Composite) getComponent()).getChildren().length;
+ }
+
+ public Object getLayout()
+ {
+ return ((Composite) getComponent()).getLayout();
+ }
+
+ public final boolean isLeftToRight()
+ {
+ return (((Composite) getComponent()).getStyle() & SWT.LEFT_TO_RIGHT) > 0;
+ }
+
+ public final void paintDebugCell(int x, int y, int width, int height)
+ {
+ // A Composite can not draw above its children, so the cells can not be painted.
+
+// if (c.isDisposed())
+// return;
+// GC gc = new GC(c);
+//
+// gc.setLineStyle(SWT.LINE_DASHDOTDOT);
+// gc.setLineJoin(SWT.JOIN_MITER);
+// gc.setLineCap(SWT.CAP_SQUARE);
+//
+// gc.setBackground(DB_CELL_BG);
+// gc.fillRectangle(x, y, width, height);
+//
+// gc.setForeground(DB_CELL_OUTLINE);
+// gc.drawRectangle(x, y, width - 1, height - 1);
+//
+// gc.dispose();
+ }
+
+ public int getComponetType(boolean disregardScrollPane)
+ {
+ return TYPE_CONTAINER;
+ }
+
+
+ public int getLayoutHashCode()
+ {
+ int h = super.getLayoutHashCode();
+
+ if (isLeftToRight())
+ h |= (1 << 26);
+
+ return h;
+ }
+}
diff --git a/prototypes/miglayout/readme.txt b/prototypes/miglayout/readme.txt
new file mode 100644
index 00000000..73e96e08
--- /dev/null
+++ b/prototypes/miglayout/readme.txt
@@ -0,0 +1,15 @@
+
+ MiG Layout Manager
+ ------------------
+
+This directory contains the beginnings of my port of the MiG Layout
+Manager from Java to Object Pascal. This is still in the very early
+stages, so I have nothing visual to show yet.
+
+For more information about the MiG Layout (Java Layout Manager) for
+Swing and SWT please visit: http://www.miglayout.com/
+
+Regards,
+ - Graeme -
+
+ ------------------------------------
diff --git a/prototypes/miglayout/test.lpi b/prototypes/miglayout/test.lpi
new file mode 100644
index 00000000..d80b89c9
--- /dev/null
+++ b/prototypes/miglayout/test.lpi
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<CONFIG>
+ <ProjectOptions>
+ <PathDelim Value="/"/>
+ <Version Value="6"/>
+ <General>
+ <Flags>
+ <SaveOnlyProjectUnits Value="True"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ <IconPath Value="./"/>
+ <TargetFileExt Value=""/>
+ </General>
+ <VersionInfo>
+ <ProjectVersion Value=""/>
+ </VersionInfo>
+ <PublishOptions>
+ <Version Value="2"/>
+ <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+ <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+ </PublishOptions>
+ <RunParams>
+ <local>
+ <FormatVersion Value="1"/>
+ <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+ </local>
+ </RunParams>
+ <RequiredPackages Count="1">
+ <Item1>
+ <PackageName Value="fpgui_package"/>
+ </Item1>
+ </RequiredPackages>
+ <Units Count="7">
+ <Unit0>
+ <Filename Value="test.lpr"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="test"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="gui_miglayout.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="gui_miglayout"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="gui_mig_lc.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="gui_mig_lc"/>
+ </Unit2>
+ <Unit3>
+ <Filename Value="gui_mig_constraintparser.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="gui_mig_constraintparser"/>
+ </Unit3>
+ <Unit4>
+ <Filename Value="gui_mig_boundsize.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="gui_mig_boundsize"/>
+ </Unit4>
+ <Unit5>
+ <Filename Value="gui_mig_unitvalue.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="gui_mig_unitvalue"/>
+ </Unit5>
+ <Unit6>
+ <Filename Value="gui_mig_exceptions.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="gui_mig_exceptions"/>
+ </Unit6>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="5"/>
+ <CodeGeneration>
+ <Generate Value="Faster"/>
+ </CodeGeneration>
+ <Other>
+ <CustomOptions Value="-FUunits"/>
+ <CompilerPath Value="$(CompPath)"/>
+ </Other>
+ </CompilerOptions>
+</CONFIG>
diff --git a/prototypes/miglayout/test.lpr b/prototypes/miglayout/test.lpr
new file mode 100644
index 00000000..cd01e75c
--- /dev/null
+++ b/prototypes/miglayout/test.lpr
@@ -0,0 +1,62 @@
+program test;
+
+{$mode objfpc}{$H+}
+
+uses
+ {$IFDEF UNIX}{$IFDEF UseCThreads}
+ cthreads,
+ {$ENDIF}{$ENDIF}
+ Classes, fpgfx, gui_form, gui_label,
+ gui_miglayout, gui_mig_lc, gui_mig_constraintparser, gui_mig_boundsize,
+gui_mig_unitvalue, gui_mig_exceptions;
+
+type
+ TMainForm = class(TfpgForm)
+ private
+ FPanel: TfpgLayoutPanel;
+ FLabel1: TfpgLabel;
+ public
+ constructor Create(AOwner: TComponent); override;
+ procedure AfterCreate; override;
+ end;
+
+{ TMainForm }
+
+constructor TMainForm.Create(AOwner: TComponent);
+begin
+ inherited Create(AOwner);
+ WindowTitle := 'MiG Layout Test';
+ WindowPosition := wpUser;
+
+ FPanel := TfpgLayoutPanel.Create(self);
+
+ SetPosition(100, 100, 300, 200);
+end;
+
+procedure TMainForm.AfterCreate;
+begin
+// FLabel1 := TfpgLabel.Create(FPanel);
+// FPanel.Add(FLabel1, '');
+end;
+
+
+procedure MainProc;
+var
+ frm: TMainForm;
+begin
+ fpgApplication.Initialize;
+ frm := TMainForm.Create(nil);
+ try
+ frm.Show;
+ fpgApplication.Run;
+ finally
+ frm.Free;
+ end;
+end;
+
+begin
+ MainProc;
+end.
+
+
+
diff --git a/prototypes/miglayout/unittests/constraintparser_tests.pas b/prototypes/miglayout/unittests/constraintparser_tests.pas
new file mode 100644
index 00000000..e4746d28
--- /dev/null
+++ b/prototypes/miglayout/unittests/constraintparser_tests.pas
@@ -0,0 +1,142 @@
+unit constraintparser_tests;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes, SysUtils, fpcunit, testregistry, gui_mig_constraintparser,
+ gui_mig_lc;
+
+type
+
+ TTestConstraintParser= class(TTestCase)
+ private
+ cp: TConstraintParser;
+ protected
+ procedure SetUp; override;
+ procedure TearDown; override;
+ published
+ procedure Test_LeftToRight_short;
+ procedure Test_LeftToRight_long;
+ procedure Test_TopToBottom_short;
+ procedure Test_TopToBottom_long;
+ end;
+
+implementation
+
+procedure TTestConstraintParser.Test_LeftToRight_short;
+var
+ lc: TLC;
+begin
+ lc := cp.ParseLayoutConstraint('ltr');
+ AssertNotNull('Failed on 1', lc);
+ AssertTrue('Failed on 2', lc.LeftToRight);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' ltr ');
+ AssertNotNull('Failed on 3', lc);
+ AssertTrue('Failed on 4', lc.LeftToRight);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint('rtl');
+ AssertNotNull('Failed on 5', lc);
+ AssertFalse('Failed on 6', lc.LeftToRight);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' rtl ');
+ AssertNotNull('Failed on 7', lc);
+ AssertFalse('Failed on 8', lc.LeftToRight);
+ FreeAndNil(lc);
+end;
+
+procedure TTestConstraintParser.Test_LeftToRight_long;
+var
+ lc: TLC;
+begin
+ lc := cp.ParseLayoutConstraint('lefttoright');
+ AssertNotNull('Failed on 1', lc);
+ AssertTrue('Failed on 2', lc.LeftToRight);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' lefttoright ');
+ AssertNotNull('Failed on 3', lc);
+ AssertTrue('Failed on 4', lc.LeftToRight);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint('righttoleft');
+ AssertNotNull('Failed on 5', lc);
+ AssertFalse('Failed on 6', lc.LeftToRight);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' righttoleft ');
+ AssertNotNull('Failed on 7', lc);
+ AssertFalse('Failed on 8', lc.LeftToRight);
+ FreeAndNil(lc);
+end;
+
+procedure TTestConstraintParser.Test_TopToBottom_short;
+var
+ lc: TLC;
+begin
+ lc := cp.ParseLayoutConstraint('ttb');
+ AssertNotNull('Failed on 1', lc);
+ AssertTrue('Failed on 2', lc.TopToBottom);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' ttb ');
+ AssertNotNull('Failed on 3', lc);
+ AssertTrue('Failed on 4', lc.TopToBottom);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint('btt');
+ AssertNotNull('Failed on 5', lc);
+ AssertFalse('Failed on 6', lc.TopToBottom);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' btt ');
+ AssertNotNull('Failed on 7', lc);
+ AssertFalse('Failed on 8', lc.TopToBottom);
+ FreeAndNil(lc);
+end;
+
+procedure TTestConstraintParser.Test_TopToBottom_long;
+var
+ lc: TLC;
+begin
+ lc := cp.ParseLayoutConstraint('toptobottom');
+ AssertNotNull('Failed on 1', lc);
+ AssertTrue('Failed on 2', lc.TopToBottom);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' toptobottom ');
+ AssertNotNull('Failed on 3', lc);
+ AssertTrue('Failed on 4', lc.TopToBottom);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint('bottomtotop');
+ AssertNotNull('Failed on 5', lc);
+ AssertFalse('Failed on 6', lc.TopToBottom);
+ FreeAndNil(lc);
+
+ lc := cp.ParseLayoutConstraint(' bottomtotop ');
+ AssertNotNull('Failed on 7', lc);
+ AssertFalse('Failed on 8', lc.TopToBottom);
+ FreeAndNil(lc);
+end;
+
+procedure TTestConstraintParser.SetUp;
+begin
+ cp := TConstraintParser.Create;
+end;
+
+procedure TTestConstraintParser.TearDown;
+begin
+ cp.Free;
+end;
+
+initialization
+
+ RegisterTest(TTestConstraintParser);
+end.
+
diff --git a/prototypes/miglayout/unittests/fpcunit_miglayout.lpi b/prototypes/miglayout/unittests/fpcunit_miglayout.lpi
new file mode 100644
index 00000000..5bd4ed11
--- /dev/null
+++ b/prototypes/miglayout/unittests/fpcunit_miglayout.lpi
@@ -0,0 +1,69 @@
+<?xml version="1.0"?>
+<CONFIG>
+ <ProjectOptions>
+ <PathDelim Value="/"/>
+ <Version Value="6"/>
+ <General>
+ <Flags>
+ <SaveOnlyProjectUnits Value="True"/>
+ </Flags>
+ <SessionStorage Value="InProjectDir"/>
+ <MainUnit Value="0"/>
+ <IconPath Value="./"/>
+ <TargetFileExt Value=""/>
+ </General>
+ <VersionInfo>
+ <ProjectVersion Value=""/>
+ </VersionInfo>
+ <PublishOptions>
+ <Version Value="2"/>
+ <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+ <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
+ </PublishOptions>
+ <RunParams>
+ <local>
+ <FormatVersion Value="1"/>
+ <LaunchingApplication PathPlusParams="/usr/X11R6/bin/xterm -T 'Lazarus Run Output' -e $(LazarusDir)/tools/runwait.sh $(TargetCmdLine)"/>
+ </local>
+ </RunParams>
+ <RequiredPackages Count="2">
+ <Item1>
+ <PackageName Value="FPCUnitConsoleRunner"/>
+ </Item1>
+ <Item2>
+ <PackageName Value="FCL"/>
+ </Item2>
+ </RequiredPackages>
+ <Units Count="3">
+ <Unit0>
+ <Filename Value="fpcunit_miglayout.lpr"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="fpcunit_miglayout"/>
+ </Unit0>
+ <Unit1>
+ <Filename Value="constraintparser_tests.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="constraintparser_tests"/>
+ </Unit1>
+ <Unit2>
+ <Filename Value="../gui_mig_constraintparser.pas"/>
+ <IsPartOfProject Value="True"/>
+ <UnitName Value="gui_mig_constraintparser"/>
+ </Unit2>
+ </Units>
+ </ProjectOptions>
+ <CompilerOptions>
+ <Version Value="5"/>
+ <SearchPaths>
+ <OtherUnitFiles Value="../"/>
+ </SearchPaths>
+ <CodeGeneration>
+ <Generate Value="Faster"/>
+ </CodeGeneration>
+ <Other>
+ <CustomOptions Value="-FUunits
+"/>
+ <CompilerPath Value="$(CompPath)"/>
+ </Other>
+ </CompilerOptions>
+</CONFIG>
diff --git a/prototypes/miglayout/unittests/fpcunit_miglayout.lpr b/prototypes/miglayout/unittests/fpcunit_miglayout.lpr
new file mode 100644
index 00000000..486c9cdf
--- /dev/null
+++ b/prototypes/miglayout/unittests/fpcunit_miglayout.lpr
@@ -0,0 +1,25 @@
+program fpcunit_miglayout;
+
+{$mode objfpc}{$H+}
+
+uses
+ Classes, consoletestrunner, constraintparser_tests, gui_mig_constraintparser;
+
+type
+
+ { TLazTestRunner }
+
+ TMyTestRunner = class(TTestRunner)
+ protected
+ // override the protected methods of TTestRunner to customize its behavior
+ end;
+
+var
+ Application: TMyTestRunner;
+
+begin
+ Application := TMyTestRunner.Create(nil);
+ Application.Initialize;
+ Application.Run;
+ Application.Free;
+end.