When does calling subfunctions in createContents() work

SWT Designer allows you to create the views, editors, perspectives, pref pages, composites, etc. that comprise Eclipse SWT & RCP applications and plug-ins.

Moderators: Konstantin.Scheglov, gnebling, Alexander.Mitin, jwren, Eric Clayberg

When does calling subfunctions in createContents() work

Postby rmolin » Thu Jul 14, 2005 4:25 am

Hi,

I find it quite irritating that SWT-Designer is not able to work on classes that other wizards in eclipse have created.

For example: If you use the PDE New plug-in wizard and select the 'plug-in with a property page' template, you have this created for you:

protected Control createContents(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout layout = new GridLayout();
composite.setLayout(layout);
GridData data = new GridData(GridData.FILL);
data.grabExcessHorizontalSpace = true;
composite.setLayoutData(data);

addFirstSection(composite);
addSeparator(composite);
addSecondSection(composite);
return composite;
}

which SWT Designer is not able to parse correctly. The 'composite' is shown, but all other controls are missing.

I understand that there must be limitations to how clever the parser can be, but this seems pretty straightforward...

How should this be refactored, in order for SWT Designer to edit this propertypage correctly ?

Sincerely,

Rune Molin

(using SWT Designer Pro v. 4.0.0)
rmolin
 
Posts: 2
Joined: Thu Jul 14, 2005 4:12 am

Re: When does calling subfunctions in createContens() work

Postby Eric Clayberg » Thu Jul 14, 2005 6:03 am

rmolin wrote:I find it quite irritating that SWT-Designer is not able to work on classes that other wizards in eclipse have created. For example: If you use the PDE New plug-in wizard and select the 'plug-in with a property page' template, you have this created for you:
...
which SWT Designer is not able to parse correctly. The 'composite' is shown, but all other controls are missing. I understand that there must be limitations to how clever the parser can be, but this seems pretty straightforward...

Actually, it is not. IMO, those wizards don't generate very good code. As structured, it is decidedly not GUI builder friendly, and there is no GUI builder in the world right now that would be able to parse it as-is (inluding Eclipse's own VE).

rmolin wrote:How should this be refactored, in order for SWT Designer to edit this propertypage correctly ?

Fortunately, Designer does have a much better parser than most GUI builders, so there are a couple of simple changes that you can make to the PDE generated code to get it to work in Designer:
    1) Convert the composite in the createContents() method into a field
    2) Inline the createDefaultComposite() method.
You should then end up with code like the following which should work fine in Designer (no other GUI builder can do this).

Code: Select all
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.QualifiedName;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.PropertyPage;

public class SamplePropertyPage extends PropertyPage {

   private static final String PATH_TITLE = "Path:";
   private static final String OWNER_TITLE = "&Owner:";
   private static final String OWNER_PROPERTY = "OWNER";
   private static final String DEFAULT_OWNER = "John Doe";

   private static final int TEXT_FIELD_WIDTH = 50;

   private Text ownerText;
   private Composite mainComposite;

   /**
    * Constructor for SamplePropertyPage.
    */
   public SamplePropertyPage() {
      super();
   }

   private void addFirstSection(Composite parent) {
      Composite composite1 = new Composite(parent, SWT.NULL);
      GridLayout layout = new GridLayout();
      layout.numColumns = 2;
      composite1.setLayout(layout);
      
      GridData data = new GridData();
      data.verticalAlignment = GridData.FILL;
      data.horizontalAlignment = GridData.FILL;
      composite1.setLayoutData(data);
      Composite composite = composite1;

      //Label for path field
      Label pathLabel = new Label(composite, SWT.NONE);
      pathLabel.setText(PATH_TITLE);

      // Path text field
      Text pathValueText = new Text(composite, SWT.WRAP | SWT.READ_ONLY);
      pathValueText.setText(((IResource) getElement()).getFullPath().toString());
   }

   private void addSeparator(Composite parent) {
      Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
      GridData gridData = new GridData();
      gridData.horizontalAlignment = GridData.FILL;
      gridData.grabExcessHorizontalSpace = true;
      separator.setLayoutData(gridData);
   }

   private void addSecondSection(Composite parent) {
      Composite composite1 = new Composite(parent, SWT.NULL);
      GridLayout layout = new GridLayout();
      layout.numColumns = 2;
      composite1.setLayout(layout);
      
      GridData data = new GridData();
      data.verticalAlignment = GridData.FILL;
      data.horizontalAlignment = GridData.FILL;
      composite1.setLayoutData(data);
      Composite composite = composite1;

      // Label for owner field
      Label ownerLabel = new Label(composite, SWT.NONE);
      ownerLabel.setText(OWNER_TITLE);

      // Owner text field
      ownerText = new Text(composite, SWT.SINGLE | SWT.BORDER);
      GridData gd = new GridData();
      gd.widthHint = convertWidthInCharsToPixels(TEXT_FIELD_WIDTH);
      ownerText.setLayoutData(gd);

      // Populate owner text field
      try {
         String owner =
            ((IResource) getElement()).getPersistentProperty(
               new QualifiedName("", OWNER_PROPERTY));
         ownerText.setText((owner != null) ? owner : DEFAULT_OWNER);
      } catch (CoreException e) {
         ownerText.setText(DEFAULT_OWNER);
      }
   }

   /**
    * @see PreferencePage#createContents(Composite)
    */
   protected Control createContents(Composite parent) {
      mainComposite = new Composite(parent, SWT.NONE);
      GridLayout layout = new GridLayout();
      mainComposite.setLayout(layout);
      GridData data = new GridData(GridData.FILL);
      data.grabExcessHorizontalSpace = true;
      mainComposite.setLayoutData(data);

      addFirstSection(mainComposite);
      addSeparator(mainComposite);
      addSecondSection(mainComposite);
      return mainComposite;
   }

   protected void performDefaults() {
      // Populate the owner text field with the default value
      ownerText.setText(DEFAULT_OWNER);
   }
   
   public boolean performOk() {
      // store the value in the owner text field
      try {
         ((IResource) getElement()).setPersistentProperty(
            new QualifiedName("", OWNER_PROPERTY),
            ownerText.getText());
      } catch (CoreException e) {
         return false;
      }
      return true;
   }

}


Here's how it looks in Designer...

Image
Eric Clayberg
Software Engineering Manager
Google
http://code.google.com/webtoolkit/download.html

Author: "Eclipse Plug-ins"
http://www.qualityeclipse.com
Eric Clayberg
Moderator
 
Posts: 4503
Joined: Tue Sep 30, 2003 6:39 am
Location: Boston, MA USA

Postby rmolin » Fri Jul 15, 2005 12:02 am

Thanks Eric. Could you briefly explain the guidelines for structuring ones code, i.e. should the main composite always be promoted to a field, why is it OK to call addFirstSection() from createContents() but not OK to call createDefaultComposite() from addFirstSection ?

Rune
rmolin
 
Posts: 2
Joined: Thu Jul 14, 2005 4:12 am

Postby Eric Clayberg » Fri Jul 15, 2005 4:28 pm

rmolin wrote:Could you briefly explain the guidelines for structuring ones code, i.e. should the main composite always be promoted to a field, why is it OK to call addFirstSection() from createContents() but not OK to call createDefaultComposite() from addFirstSection ?

Currently, Designer does not understand local variables passed as parents to another method. The solution to that is to convert the parent containers into fields (note that you can have this happen automatically via Designer's Code Generation and Type Specific preferences). At that point the sub methods don't even need the parent passed as an argument, so you can simplify the code even further. This restriction may be lifted in the future.

The problem with createDefaultComposite() is that Designer does not support parameterized helper methods like this. Designer needs a top-down tree where every widget-creation method is called only once. A method that is called twice leads to ambiguities in what should happen when properties change (changing the property of one widget could affect all of the others built from the same method). This restriction may also be lifted in the future.

The addFirstSection() method is OK because it is only called once. If that method were called twice, those widgets would not be shown.
Eric Clayberg
Software Engineering Manager
Google
http://code.google.com/webtoolkit/download.html

Author: "Eclipse Plug-ins"
http://www.qualityeclipse.com
Eric Clayberg
Moderator
 
Posts: 4503
Joined: Tue Sep 30, 2003 6:39 am
Location: Boston, MA USA


Return to SWT Designer

Who is online

Users browsing this forum: No registered users and 1 guest