View Javadoc
1   /**
2    * 
3    * Copyright (c) 2013-2015, Openflexo
4    * Copyright (c) 2011-2012, AgileBirds
5    * 
6    * This file is part of Gina-core, a component of the software infrastructure 
7    * developed at Openflexo.
8    * 
9    * 
10   * Openflexo is dual-licensed under the European Union Public License (EUPL, either 
11   * version 1.1 of the License, or any later version ), which is available at 
12   * https://joinup.ec.europa.eu/software/page/eupl/licence-eupl
13   * and the GNU General Public License (GPL, either version 3 of the License, or any 
14   * later version), which is available at http://www.gnu.org/licenses/gpl.html .
15   * 
16   * You can redistribute it and/or modify under the terms of either of these licenses
17   * 
18   * If you choose to redistribute it and/or modify under the terms of the GNU GPL, you
19   * must include the following additional permission.
20   *
21   *          Additional permission under GNU GPL version 3 section 7
22   *
23   *          If you modify this Program, or any covered work, by linking or 
24   *          combining it with software containing parts covered by the terms 
25   *          of EPL 1.0, the licensors of this Program grant you additional permission
26   *          to convey the resulting work. * 
27   * 
28   * This software is distributed in the hope that it will be useful, but WITHOUT ANY 
29   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
30   * PARTICULAR PURPOSE. 
31   *
32   * See http://www.openflexo.org/license.html for details.
33   * 
34   * 
35   * Please contact Openflexo (openflexo-contacts@openflexo.org)
36   * or visit www.openflexo.org if you need additional information.
37   * 
38   */
39  
40  package org.openflexo.gina.swing.editor.view.container.layout;
41  
42  import java.awt.Component;
43  import java.awt.Container;
44  import java.awt.Dimension;
45  import java.awt.Rectangle;
46  import java.util.ArrayList;
47  import java.util.List;
48  import java.util.logging.Logger;
49  
50  import javax.swing.Box;
51  import javax.swing.JComponent;
52  import javax.swing.JPanel;
53  
54  import org.openflexo.gina.model.FIBComponent;
55  import org.openflexo.gina.model.container.layout.TwoColsLayoutConstraints;
56  import org.openflexo.gina.model.container.layout.TwoColsLayoutConstraints.TwoColsLayoutLocation;
57  import org.openflexo.gina.swing.editor.view.FIBSwingEditableContainerView;
58  import org.openflexo.gina.swing.editor.view.FIBSwingEditableView;
59  import org.openflexo.gina.swing.editor.view.PlaceHolder;
60  import org.openflexo.gina.swing.editor.view.container.JFIBEditablePanelView;
61  import org.openflexo.gina.swing.view.JFIBView;
62  import org.openflexo.gina.swing.view.container.layout.JTwoColsLayout;
63  import org.openflexo.gina.view.FIBView;
64  import org.openflexo.gina.view.impl.FIBContainerViewImpl;
65  import org.openflexo.logging.FlexoLogger;
66  
67  /**
68   * Swing implementation for edition of a TwoCols layout
69   * 
70   * @author sylvain
71   */
72  public class JEditableTwoColsLayout extends JTwoColsLayout
73  		implements JFIBEditableLayoutManager<JPanel, JComponent, TwoColsLayoutConstraints> {
74  
75  	private static final Logger logger = FlexoLogger.getLogger(JFIBEditablePanelView.class.getPackage().getName());
76  
77  	public JEditableTwoColsLayout(FIBContainerViewImpl<?, JPanel, JComponent> panelView) {
78  		super(panelView);
79  	}
80  
81  	private void fillInContainerWithSubComponents(Container panel, int fromIndex, int toIndex, boolean addGlueWhenRequiredAtTheEnd) {
82  		FIBComponent lastAddedChild = null;
83  
84  		List<FIBView<?, JComponent>> flattenedContents = getFlattenedContents();
85  
86  		for (int j = fromIndex; j < toIndex; j++) {
87  			JFIBView<?, ?> childView = (JFIBView<?, ?>) flattenedContents.get(j);
88  			FIBComponent c = childView.getComponent();
89  			if (c.getConstraints() instanceof TwoColsLayoutConstraints) {
90  				TwoColsLayoutConstraints contraints = (TwoColsLayoutConstraints) c.getConstraints();
91  				if (lastAddedChild != null && lastAddedChild.getConstraints() instanceof TwoColsLayoutConstraints
92  						&& ((TwoColsLayoutConstraints) lastAddedChild.getConstraints()).getLocation() == TwoColsLayoutLocation.left
93  						&& (contraints.getLocation() == TwoColsLayoutLocation.left
94  								|| contraints.getLocation() == TwoColsLayoutLocation.center)) {
95  					// A second LEFT or CENTER component after a previous LEFT one, add glue
96  					// We have to add an extra glue at the end of last component if this one was declared as in LEFT position
97  					Component glue = Box.createHorizontalGlue();
98  					_addChildToContainerWithConstraints(glue, panel,
99  							new TwoColsLayoutConstraints(TwoColsLayoutLocation.right, true, false));
100 				}
101 
102 				if (contraints.getLocation() == TwoColsLayoutLocation.right && ((lastAddedChild == null) || (lastAddedChild != null
103 						&& lastAddedChild.getConstraints() instanceof TwoColsLayoutConstraints
104 						&& ((TwoColsLayoutConstraints) lastAddedChild.getConstraints()).getLocation() == TwoColsLayoutLocation.right))) {
105 					Component glue = Box.createHorizontalGlue();
106 					_addChildToContainerWithConstraints(glue, panel, new TwoColsLayoutConstraints(TwoColsLayoutLocation.left, true, false));
107 				}
108 
109 				_addChildToContainerWithConstraints(Box.createRigidArea(childView.getResultingJComponent().getSize()), panel, contraints);
110 
111 				if (addGlueWhenRequiredAtTheEnd && j == toIndex - 1 && contraints.getLocation() == TwoColsLayoutLocation.left) {
112 					Component glue = Box.createHorizontalGlue();
113 					_addChildToContainerWithConstraints(glue, panel,
114 							new TwoColsLayoutConstraints(TwoColsLayoutLocation.right, true, false));
115 				}
116 			}
117 			lastAddedChild = c;
118 		}
119 
120 	}
121 
122 	/**
123 	 * Make placeholders for component implementing this layout<br>
124 	 * This method is called during a drag-and-drop scheme initiated from the palette
125 	 */
126 	@Override
127 	public List<PlaceHolder> makePlaceHolders(final Dimension preferredSize) {
128 
129 		List<PlaceHolder> returned = new ArrayList<>();
130 
131 		if (!getComponent().getProtectContent()) {
132 
133 			JPanel panel = new JPanel(makeTwoColsLayout());
134 			panel.setPreferredSize(((JFIBView<?, ?>) getContainerView()).getResultingJComponent().getSize());
135 			panel.setSize(((JFIBView<?, ?>) getContainerView()).getResultingJComponent().getSize());
136 
137 			List<List<JFIBView<?, ?>>> rows = new ArrayList<>();
138 			List<JFIBView<?, ?>> currentRow = null;
139 
140 			List<FIBView<?, JComponent>> flattenedContents = getFlattenedContents();
141 
142 			for (int i = 0; i < getFlattenedContents().size(); i++) {
143 
144 				JFIBView<?, ?> childView = (JFIBView<?, ?>) flattenedContents.get(i);
145 				FIBComponent c = childView.getComponent();
146 
147 				if (c.getConstraints() instanceof TwoColsLayoutConstraints) {
148 					TwoColsLayoutConstraints contraints = (TwoColsLayoutConstraints) c.getConstraints();
149 
150 					if (currentRow == null) {
151 						currentRow = new ArrayList<>();
152 					}
153 
154 					if (contraints.getLocation() == TwoColsLayoutLocation.left && currentRow.size() > 0) {
155 						JFIBView<?, ?> previousComponentView = currentRow.get(currentRow.size() - 1);
156 						FIBComponent previousComponent = previousComponentView.getComponent();
157 						if (previousComponent.getConstraints() instanceof TwoColsLayoutConstraints
158 								&& ((TwoColsLayoutConstraints) previousComponent.getConstraints())
159 										.getLocation() == TwoColsLayoutLocation.left)
160 							rows.add(currentRow);
161 						currentRow = new ArrayList<>(); // New row
162 					}
163 
164 					currentRow.add(childView);
165 
166 					if (contraints.getLocation() == TwoColsLayoutLocation.center
167 							|| contraints.getLocation() == TwoColsLayoutLocation.right) {
168 						rows.add(currentRow);
169 						currentRow = null; // Means new row !
170 					}
171 				}
172 			}
173 			if (currentRow != null) {
174 				rows.add(currentRow);
175 			}
176 
177 			// System.out.println("Building placeholders for " + rows.size() + " rows");
178 			// for (int r = 0; r < rows.size(); r++) {
179 			// System.out.println("Row " + r + " with " + rows.get(r));
180 			// }
181 
182 			// In this first step, we will add placeholders for a previous lineb before each row
183 
184 			for (int r = 0; r < rows.size(); r++) {
185 
186 				List<JFIBView<?, ?>> row = rows.get(r);
187 				// System.out.println("Row " + r + " with " + row);
188 
189 				// Reinitialize the panel used for layout computation
190 				panel.removeAll();
191 
192 				int lastInsertedElementIndex = 0;
193 
194 				// First put components already beeing inside the container, until last inserted index matching this row
195 				if (r > 0) {
196 					List<JFIBView<?, ?>> previousRow = rows.get(r - 1);
197 					JFIBView<?, ?> lastElementInRow = previousRow.get(previousRow.size() - 1);
198 					lastInsertedElementIndex = flattenedContents.indexOf(lastElementInRow) + 1;
199 					fillInContainerWithSubComponents(panel, 0, lastInsertedElementIndex, true);
200 				}
201 
202 				// Build center placeholder (will be added for the first row only)
203 				final TwoColsLayoutConstraints centerConstraints = new TwoColsLayoutConstraints(TwoColsLayoutLocation.center, true, false);
204 				Component centerPHComponent = null;
205 				if (r == 0) {
206 					centerPHComponent = Box.createRigidArea(preferredSize);
207 					_addChildToContainerWithConstraints(centerPHComponent, panel, centerConstraints);
208 				}
209 
210 				// Build placeholder for a previous line at left location
211 				final TwoColsLayoutConstraints leftConstraints = new TwoColsLayoutConstraints(TwoColsLayoutLocation.left, true, false);
212 				Component leftPHComponent = Box.createRigidArea(preferredSize);
213 				_addChildToContainerWithConstraints(leftPHComponent, panel, leftConstraints);
214 
215 				// Build placeholder for a previous line at right location
216 				final TwoColsLayoutConstraints rightConstraints = new TwoColsLayoutConstraints(TwoColsLayoutLocation.right, true, false);
217 				Component rightPHComponent = Box.createRigidArea(preferredSize);
218 				_addChildToContainerWithConstraints(rightPHComponent, panel, rightConstraints);
219 
220 				// And add all remaining existing component
221 				fillInContainerWithSubComponents(panel, lastInsertedElementIndex, flattenedContents.size(), true);
222 
223 				panel.doLayout();
224 
225 				// For the first row only, add the 3 placeholders and shit them at required height
226 				if (r == 0) {
227 					returned.add(makePlaceHolder("<center>", centerConstraints, lastInsertedElementIndex, centerPHComponent, 0,
228 							-preferredSize.height));
229 					returned.add(makePlaceHolder("<left>", leftConstraints, lastInsertedElementIndex, leftPHComponent, 0,
230 							-preferredSize.height));
231 					returned.add(makePlaceHolder("<right>", rightConstraints, lastInsertedElementIndex, rightPHComponent, 0,
232 							-preferredSize.height));
233 				}
234 				else {
235 
236 					if (row.size() == 1 && row.get(0).getComponent().getConstraints() instanceof TwoColsLayoutConstraints) {
237 						TwoColsLayoutConstraints existingConstraint = (TwoColsLayoutConstraints) row.get(0).getComponent().getConstraints();
238 						if (existingConstraint.getLocation() == TwoColsLayoutLocation.left) {
239 							// Right component is missing, do not shadow placeholder for this hole, just add the "left" one
240 							returned.add(makePlaceHolder("<left>", leftConstraints, lastInsertedElementIndex, leftPHComponent, 0, 0));
241 						}
242 						else if (existingConstraint.getLocation() == TwoColsLayoutLocation.right) {
243 							// Left component is missing, do not shadow placeholder for this hole, just add the "right" one
244 							returned.add(makePlaceHolder("<right>", rightConstraints, lastInsertedElementIndex, rightPHComponent, 0, 0));
245 						}
246 						else if (existingConstraint.getLocation() == TwoColsLayoutLocation.center) {
247 							// put the two placeholders
248 							returned.add(makePlaceHolder("<left>", leftConstraints, lastInsertedElementIndex, leftPHComponent, 0, 0));
249 							returned.add(makePlaceHolder("<right>", rightConstraints, lastInsertedElementIndex, rightPHComponent, 0, 0));
250 						}
251 					}
252 					else {
253 						// Otherwise add the two left/right placeholders
254 						returned.add(makePlaceHolder("<left>", leftConstraints, lastInsertedElementIndex, leftPHComponent, 0, 0));
255 						returned.add(makePlaceHolder("<right>", rightConstraints, lastInsertedElementIndex, rightPHComponent, 0, 0));
256 					}
257 				}
258 
259 				// If row is not complete add placeholder matching missing component
260 				if (row.size() == 1 && row.get(0).getComponent().getConstraints() instanceof TwoColsLayoutConstraints) {
261 
262 					panel.removeAll();
263 
264 					lastInsertedElementIndex = 0;
265 					if (r > 0) {
266 						List<JFIBView<?, ?>> previousRow = rows.get(r - 1);
267 						JFIBView<?, ?> lastElementInRow = previousRow.get(previousRow.size() - 1);
268 						lastInsertedElementIndex = flattenedContents.indexOf(lastElementInRow) + 1;
269 						fillInContainerWithSubComponents(panel, 0, lastInsertedElementIndex, true);
270 					}
271 
272 					JFIBView<?, ?> existingComponent = row.get(0);
273 
274 					TwoColsLayoutConstraints presentConstraint = (TwoColsLayoutConstraints) existingComponent.getComponent()
275 							.getConstraints();
276 
277 					if (presentConstraint.getLocation() == TwoColsLayoutLocation.left) {
278 
279 						System.out.println("Right component is missing");
280 
281 						_addChildToContainerWithConstraints(Box.createRigidArea(existingComponent.getResultingJComponent().getSize()),
282 								panel, presentConstraint);
283 
284 						lastInsertedElementIndex++;
285 
286 						// Put a placeholder right to existing
287 						rightPHComponent = Box.createRigidArea(preferredSize);
288 						_addChildToContainerWithConstraints(rightPHComponent, panel, rightConstraints);
289 
290 						// Put other components
291 						fillInContainerWithSubComponents(panel, lastInsertedElementIndex, flattenedContents.size(), false);
292 
293 						panel.doLayout();
294 
295 						returned.add(makePlaceHolder("<right>", rightConstraints, lastInsertedElementIndex, rightPHComponent, 0, 0));
296 					}
297 
298 					else if (presentConstraint.getLocation() == TwoColsLayoutLocation.right) {
299 
300 						System.out.println("Left component is missing");
301 
302 						// Put a placeholder left to existing
303 						leftPHComponent = Box.createRigidArea(preferredSize);
304 						_addChildToContainerWithConstraints(leftPHComponent, panel, leftConstraints);
305 
306 						_addChildToContainerWithConstraints(Box.createRigidArea(existingComponent.getResultingJComponent().getSize()),
307 								panel, presentConstraint);
308 
309 						// Put other components
310 						fillInContainerWithSubComponents(panel, lastInsertedElementIndex + 1, flattenedContents.size(), false);
311 
312 						panel.doLayout();
313 
314 						returned.add(makePlaceHolder("<left>", leftConstraints, lastInsertedElementIndex, leftPHComponent, 0, 0));
315 					}
316 				}
317 			}
318 
319 			// Then add placeholders at the end of the component
320 			panel.removeAll();
321 			fillInContainerWithSubComponents(panel, 0, flattenedContents.size(), true);
322 
323 			// Same code as in doLayout(), where we add an extra glue at the end of last component if this one was declared as in LEFT
324 			// position
325 			/*if (getContainerView().getComponent().getSubComponents().size() > 0) {
326 				FIBComponent lastComponent = getContainerView().getComponent().getSubComponents()
327 						.get(getContainerView().getComponent().getSubComponents().size() - 1);
328 				if (lastComponent.getConstraints() instanceof TwoColsLayoutConstraints) {
329 					TwoColsLayoutConstraints contraints = (TwoColsLayoutConstraints) lastComponent.getConstraints();
330 					if (contraints.getLocation() == TwoColsLayoutLocation.left) {
331 						// We have to add glue
332 						Component glue = Box.createHorizontalGlue();
333 						_addChildToContainerWithConstraints(glue, panel,
334 								new TwoColsLayoutConstraints(TwoColsLayoutLocation.right, true, false));
335 					}
336 				}
337 			}*/
338 
339 			final TwoColsLayoutConstraints leftConstraints = new TwoColsLayoutConstraints(TwoColsLayoutLocation.left, true, false);
340 			Component leftPHComponent = Box.createRigidArea(preferredSize);
341 			_addChildToContainerWithConstraints(leftPHComponent, panel, leftConstraints);
342 
343 			final TwoColsLayoutConstraints rightConstraints = new TwoColsLayoutConstraints(TwoColsLayoutLocation.right, true, false);
344 			Component rightPHComponent = Box.createRigidArea(preferredSize);
345 			_addChildToContainerWithConstraints(rightPHComponent, panel, rightConstraints);
346 
347 			final TwoColsLayoutConstraints centerConstraints = new TwoColsLayoutConstraints(TwoColsLayoutLocation.center, true, false);
348 			Component centerPHComponent = Box.createRigidArea(preferredSize);
349 			_addChildToContainerWithConstraints(centerPHComponent, panel, centerConstraints);
350 
351 			panel.doLayout();
352 
353 			returned.add(makePlaceHolder("<left>", leftConstraints, flattenedContents.size(), leftPHComponent, 0, preferredSize.height));
354 			returned.add(makePlaceHolder("<right>", rightConstraints, flattenedContents.size(), rightPHComponent, 0, preferredSize.height));
355 			returned.add(
356 					makePlaceHolder("<center>", centerConstraints, flattenedContents.size(), centerPHComponent, 0, preferredSize.height));
357 
358 		}
359 
360 		return returned;
361 
362 	}
363 
364 	private PlaceHolder makePlaceHolder(String text, final TwoColsLayoutConstraints leftConstraints, final int index, Component component,
365 			int deltaX, int deltaY) {
366 		Rectangle placeHolderBounds = makePlaceHolderBounds(component, deltaX, deltaY);
367 		PlaceHolder returned = new PlaceHolder((FIBSwingEditableContainerView<?, ?>) getContainerView(), text, placeHolderBounds) {
368 			@Override
369 			public void insertComponent(FIBComponent newComponent, int oldIndex) {
370 				if (oldIndex > -1 && oldIndex < index) {
371 					// It's a move (oldIndex != -1), and the old index is before searched index
372 					putSubComponentsAtIndexWithConstraints(newComponent, index - 1, leftConstraints);
373 				}
374 				else {
375 					putSubComponentsAtIndexWithConstraints(newComponent, index, leftConstraints);
376 				}
377 			}
378 		};
379 		returned.setVisible(false);
380 		return returned;
381 	}
382 
383 	private Rectangle makePlaceHolderBounds(Component component, int deltaX, int deltaY) {
384 		Rectangle placeHolderBounds = new Rectangle(component.getBounds().x + deltaX, component.getBounds().y + deltaY,
385 				component.getWidth(), component.getHeight());
386 		if (placeHolderBounds.x < 0) {
387 			placeHolderBounds.width = placeHolderBounds.width + placeHolderBounds.x;
388 			placeHolderBounds.x = 0;
389 		}
390 		if (placeHolderBounds.y < 0) {
391 			placeHolderBounds.height = placeHolderBounds.height + placeHolderBounds.y;
392 			placeHolderBounds.y = 0;
393 		}
394 		if (placeHolderBounds.x + placeHolderBounds.width > ((JFIBView<?, ?>) getContainerView()).getResultingJComponent().getWidth()) {
395 			placeHolderBounds.width = ((JFIBView<?, ?>) getContainerView()).getResultingJComponent().getWidth() - placeHolderBounds.x;
396 		}
397 		if (placeHolderBounds.y + placeHolderBounds.height > ((JFIBView<?, ?>) getContainerView()).getResultingJComponent().getHeight()) {
398 			placeHolderBounds.height = ((JFIBView<?, ?>) getContainerView()).getResultingJComponent().getHeight() - placeHolderBounds.y;
399 		}
400 		return placeHolderBounds;
401 	}
402 
403 	protected void putSubComponentsAtIndexWithConstraints(FIBComponent subComponent, int index, TwoColsLayoutConstraints constraints) {
404 		List<FIBView<?, JComponent>> flattenedContents = getFlattenedContents();
405 		if (flattenedContents.contains(subComponent)) {
406 			// This is a simple move
407 			// System.out.println("Moving component at index " + index);
408 			getComponent().moveToSubComponentsAtIndex(subComponent, index);
409 		}
410 		else {
411 			// System.out.println("Inserting component at index " + index);
412 			// getComponent().setConstraints(constraints);
413 			getComponent().insertToSubComponentsAtIndex(subComponent, constraints, index);
414 		}
415 
416 	}
417 
418 	@Override
419 	public void setOperatorContentsStart(FIBView<?, ?> view) {
420 		if (view instanceof FIBSwingEditableView) {
421 			((FIBSwingEditableView<?, ?>) view).setOperatorContentsStart(true);
422 		}
423 	}
424 
425 }