Project: CIShell
package org.cishell.utility.swt;
 
import java.util.ArrayList; 
import java.util.Collection; 
import java.util.Collections; 
import java.util.List; 
import java.util.Map; 
 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.custom.ScrolledComposite; 
import org.eclipse.swt.layout.GridData; 
import org.eclipse.swt.layout.GridLayout; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.swt.widgets.Label; 
 
/** See ScrolledComponentFactory for more information on the overall picture of the layer that this
 * class is part of. 
 * A LITTLE BIT OF HISTORY: 
 ** When tasked with writing the Static Executable Wizard, I ran into a lot of difficulty with 
 ** gracefully handling the dynamic addition and deletion of child components to scrolling 
 ** components. (By scrolling components, I mean the components that actually do the scrolling; that 
 ** is, they SCROLL their child components.) The problem relates to how SWT grid layouts want to be 
 ** sized--I believe that SWT is largely implemented to only handle GUIs that've been setup by time 
 ** the user interacts with them. 
 ** In order to try to make this process more graceful, I came up with this and its 
 ** related classes. 
 * HOW TO USE IT: 
 ** This class only makes sense if T corresponds to a GUI component in some fashion (though it 
 ** doesn't literally have to be an SWT component). 
 ** Override getColumnCount() to specify the number of columns each row has. 
 ** Override createHeaderArea() and createFooterArea() to specify if there should be a header and 
 ** footer, respectively, that is OUTSIDE of the scrolling area. 
 ** Override createColumnLabelTexts() to specify the column labels. The default implementation of 
 ** this method uses the column index to generate labels. 
 ** It's recommended against overriding addComponent() and removeComponent(). 
 ** This class should be subclassed so specific column labels and any desired header/footer 
 ** can be generated. 
 */
 
public class ExpandableComponentWidget<T> extends Composite { 
 public static final int COLUMN_AREA_LAYOUT_VERTICAL_SPACING = 1
 public static final int VERTICAL_SCROLL_INCREMENT = 50
 
 private ScrolledComponentFactory<T> componentFactory; 
 private Composite headerArea; 
 private ScrolledComposite scrollingArea; 
 private GridContainer scrolledAreaGrid; 
 private Composite footerArea; 
 private List<T> components = new ArrayList<T>(); 
 private int uniqueComponentCount = 0
 private Collection<Label> columnLabels; 
 
   Composite parent, ScrolledComponentFactory<T> componentFactory) { 
  super(parent, SWT.NONE); 
  this.componentFactory = componentFactory; 
 
  setLayout(createLayout()); 
  this.headerArea = createHeaderArea(); 
  this.scrollingArea = createScrollingArea(); 
  this.footerArea = createFooterArea(); 
  this.scrolledAreaGrid = createScrolledAreaGrid(this.scrollingArea); 
 
  this.scrollingArea.setExpandHorizontal(true); 
  this.scrollingArea.setExpandVertical(true); 
  this.scrollingArea.setAlwaysShowScrollBars(true); 
  fixSize(); 
  this.scrollingArea.setContent(this.scrolledAreaGrid.getActualParent()); 
  this.scrollingArea.getVerticalBar().setPageIncrement(VERTICAL_SCROLL_INCREMENT); 
  this.columnLabels = createColumnLabels(this.scrolledAreaGrid.getActualParent(), SWT.NONE); 
 
 
 public Composite getHeaderArea() { 
  return this.headerArea; 
 
 
 public Composite getFooterArea() { 
  return this.footerArea; 
 
 
 public List<T> getComponents() { 
  return Collections.unmodifiableList(this.components); 
 
 
 public int getColumnCount() { 
  return 1
 
 
 public T addComponent(int style, Map<String, Object> arguments) 
   throws WidgetConstructionException { 
  // TODO: Fix this terrible hack? 
  if (this.components.size() == 0) { 
   for (Label columnLabel : this.columnLabels) { 
    columnLabel.setVisible(true); 
   
  
 
  final int componentCount = this.components.size(); 
  T component = this.componentFactory.constructWidget( 
   this
   this.scrolledAreaGrid, 
   style, 
   arguments, 
   componentCount, 
   this.uniqueComponentCount); 
  this.uniqueComponentCount++; 
 
  fixSize(); 
 
  this.components.add(component); 
 
  return component; 
 
 
 public void removeComponent(int index) { 
  this.scrolledAreaGrid.removeRow(index); 
  this.components.remove(index); 
  fixSize(); 
 
  for (int ii = 0; ii < this.components.size(); ii++) { 
   this.componentFactory.reindexComponent(this.components.get(ii), ii); 
  
 
  // TODO: Fix this terrible hack? 
  if (this.components.size() == 0) { 
   for (Label columnLabel : this.columnLabels) { 
    columnLabel.setVisible(false); 
   
  
 
 
 public Collection<Label> createColumnLabels(Composite parent, int style) { 
  List<Label> columnLabels = new ArrayList<Label>(); 
 
  for (String columnLabelText : createColumnLabelTexts()) { 
   Label columnLabel = new Label(parent, style); 
   columnLabel.setLayoutData(createColumnLabelLayoutData()); 
   columnLabel.setText(columnLabelText); 
   columnLabels.add(columnLabel); 
  
 
  return columnLabels; 
 
 
 public Collection<String> createColumnLabelTexts() { 
  List<String> columnLabelTexts = new ArrayList<String>(); 
 
  for (int ii = 0; ii < getColumnCount(); ii++) { 
   columnLabelTexts.add("Column " + ii); 
  
 
  return columnLabelTexts; 
 
 
 private void fixSize() { 
  Composite scrolledArea = this.scrolledAreaGrid.getActualParent(); 
  this.scrollingArea.setMinSize(scrolledArea.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 
  scrolledArea.pack(); 
 
 
 protected Composite createHeaderArea() { 
  Composite headerArea = new Composite(this, SWT.NONE); 
  headerArea.setLayoutData(createHeaderAreaLayoutData()); 
  headerArea.setLayout(createHeaderLayout()); 
 
  return headerArea; 
 
 
 protected GridData createHeaderAreaLayoutData() { 
  GridData layoutData = new GridData(SWT.FILL, SWT.TOP, truefalse); 
 
  return layoutData; 
 
 
 protected GridLayout createHeaderLayout() { 
  GridLayout layout = new GridLayout(1false); 
  GUIBuilderUtilities.clearMargins(layout); 
  GUIBuilderUtilities.clearSpacing(layout); 
 
  return layout; 
 
 
 protected ScrolledComposite createScrollingArea() { 
  ScrolledComposite scrollingArea = 
   new ScrolledComposite(this, SWT.BORDER | SWT.V_SCROLL); 
  scrollingArea.setLayoutData(createScrollingAreaLayoutData()); 
  scrollingArea.setLayout(createScrollingLayout()); 
 
  return scrollingArea; 
 
 
 protected GridData createScrollingAreaLayoutData() { 
  GridData layoutData = new GridData(SWT.FILL, SWT.FILL, truetrue); 
 
  return layoutData; 
 
 
 private GridLayout createScrollingLayout() { 
  GridLayout layout = new GridLayout(1true); 
  GUIBuilderUtilities.clearMargins(layout); 
  GUIBuilderUtilities.clearSpacing(layout); 
 
  return layout; 
 
 
 protected Composite createFooterArea() { 
  Composite footerArea = new Composite(this, SWT.BORDER); 
  footerArea.setLayoutData(createFooterAreaLayoutData()); 
  footerArea.setLayout(createFooterLayout()); 
 
  return footerArea; 
 
 
 protected GridData createFooterAreaLayoutData() { 
  GridData layoutData = new GridData(SWT.FILL, SWT.TOP, truefalse); 
 
  return layoutData; 
 
 
 protected GridLayout createFooterLayout() { 
  GridLayout layout = new GridLayout(1false); 
  GUIBuilderUtilities.clearMargins(layout); 
  GUIBuilderUtilities.clearSpacing(layout); 
 
  return layout; 
 
 
 private GridContainer createScrolledAreaGrid(Composite parent) { 
  Composite columnArea = new Composite(parent, SWT.NONE); 
  columnArea.setLayoutData(createScrolledAreaLayoutData()); 
  final int columnCount = getColumnCount(); 
  columnArea.setLayout(createScrolledAreaLayout(columnCount)); 
 
  return new GridContainer(columnArea, columnCount); 
 
 
 protected GridData createScrolledAreaLayoutData() { 
  GridData layoutData = new GridData(SWT.FILL, SWT.FILL, truetrue); 
 
  return layoutData; 
 
 
 protected GridLayout createScrolledAreaLayout(int columnCount) { 
  GridLayout layout = new GridLayout(columnCount, false); 
//  GUIBuilderUtilities.clearMargins(layout); 
//  GUIBuilderUtilities.clearSpacing(layout); 
 
  return layout; 
 
 
 protected GridData createColumnLabelLayoutData() { 
  GridData layoutData = new GridData(SWT.CENTER, SWT.CENTER, falsefalse); 
 
  return layoutData; 
 
 
 protected GridData createComponentLayoutData() { 
  GridData layoutData = new GridData(SWT.FILL, SWT.TOP, truefalse); 
 
  return layoutData; 
 
 
 private static GridLayout createLayout() { 
  GridLayout layout = new GridLayout(1true); 
  GUIBuilderUtilities.clearMargins(layout); 
  GUIBuilderUtilities.clearSpacing(layout); 
 
  return layout; 
 
}