Just An Application

November 1, 2009

An Extended NewAnnotation Wizard For Eclipse: Implementing The Wizard Page UI

The UI for a wizard page is created by its implementation of the

    public void createControl(Composite parent);

method defined in the

    org.eclipse.jface.dialogs.IWizardPage

interface.

The NewAnnotationWizardPage implementation of it is as follows


        @Override
        public void createControl(Composite theParent) 
        {
            initializeDialogUnits(theParent);
		
            Composite composite= new Composite(theParent, SWT.NONE);

            composite.setFont(theParent.getFont());
		
            int nColumns = 4;

            GridLayout layout= new GridLayout();
			
            layout.numColumns= nColumns;
            composite.setLayout(layout);

            createContainerControls(composite, nColumns);
            createPackageControls(composite, nColumns);
            createEnclosingTypeControls(composite, nColumns);

            createSeparator(composite, nColumns);

            createTypeNameControls(composite, nColumns);
            createModifierControls(composite, nColumns);
		
            createSeparator(composite, nColumns);
		
            createAnnotationsControls(composite);
		
            createSeparator(composite, nColumns);

            createCommentControls(composite, nColumns);
            enableCommentControl(true);

            setControl(composite);

            Dialog.applyDialogFont(composite);
        }

This is essentially a clone of the same method from the existing Eclipse supplied class with the addition of these three lines.


        ...

        createSeparator(composite, nColumns);
		
        createAnnotationsControls(composite);
		
        createSeparator(composite, nColumns);
		
        ...

The createAnnotationsControls(Composite) method is responsible for the creation of the new UI elements within the page. These are shown below.

NewControls

The text at the top is a Label and is added directly to the parent composite passed in to the call to createControl(Composite), with a horizontal span set to ensure that it is in a row on its own.


        Label label = new Label(theParent, SWT.NONE);
		
        label.setText(Text.WHICH_ANNOTATIONS_TEXT);
		
        GridData labelData = new GridData();
		
        labelData.horizontalSpan = nColumns;
		
        label.setLayoutData(labelData);

There are controls to specify the addition of the four basic meta-annotations

  • Documented
  • Inherited
  • Retention
  • Target

These controls are grouped together into a Composite which is laid out in two columns using a GridLayout


        Composite  group  = new Composite(theParent, SWT.NONE);
        GridLayout layout = new GridLayout();
		
        layout.numColumns = 2;
        group.setLayout(layout);
		
        GridData groupData = new GridData(GridData.FILL_HORIZONTAL);
		
        groupData.horizontalAlignment = SWT.CENTER;
        groupData.horizontalSpan = nColumns - 1;
        group.setLayoutData(groupData);

Both Documented and Inherited are marker annotations: they are either present or not. In each case a checkbox is used to indicate whether they should be present or not.


        Button button = null;
		
        // Documented
	
        label = new Label(group, SWT.NONE);
        label.setText(Text.DOCUMENTED_LABEL);
		
        button = new Button(group, SWT.CHECK);
        button.addSelectionListener(
                   new SelectionAdapter()
                   {
                       public void widgetSelected(SelectionEvent theEvent)
                       {
                           documented = ((Button)(theEvent.widget)).getSelection();
                       }
                   });
		
        // Inherited
		
        label = new Label(group, SWT.NONE);
        label.setText(Text.INHERITED_LABEL);
		
        button = new Button(group, SWT.CHECK);
        button.addSelectionListener(
                   new SelectionAdapter()
                   {
                       public void widgetSelected(SelectionEvent theEvent)
                       {
                           inherited = ((Button)(theEvent.widget)).getSelection();
                       }
                   });

The Retention annotation has value of type RetentionPolicy which is an Enum with a choice of three values. These are represented by a group of radio buttons. The currently selected value is represented by the corresponding value of RetentionPolicy which is stored in the retention instance variable.


        // Retention
		
        label = new Label(group, SWT.NONE);
        label.setText(Text.RETENTION_LABEL);
		
        Composite  retentionGroup        = new Composite(group, SWT.NONE);
        GridLayout retentionGroupLayout  = new GridLayout();
		
        retentionGroupLayout.numColumns   = N_RETENTION_GROUP_COLUMNS;
        retentionGroup.setLayout(retentionGroupLayout);
		
        Listener listener = new Listener()
                            {
                                @Override
                                public void handleEvent(Event theEvent) 
                                {
                                    Button button = (Button)(theEvent.widget);
									
                                    if (button.getSelection())
                                    {
                                        retention = (RetentionPolicy)button.getData();
                                    }
                                }
                            };
		
        for (String name : sortedNames(RetentionPolicy.class))
        {
            label = new Label(retentionGroup, SWT.NONE);
            label.setText(name);
		
            button = new Button(retentionGroup, SWT.RADIO);
            button.addListener(SWT.Selection, listener);
            button.setData(Enum.valueOf(RetentionPolicy.class, name));
            if (RetentionPolicy.CLASS.name().equals(name))
            {
                button.setSelection(true);
            }
        }

The sortedNames method is a utility method which returns the names of an Enum’s values in alphabetical order. It is possible to obtain a set containing all the values of a given Enum but these are in the order they appear in the Enum definition, which is not necessarily alphabetical.


        private <E extends Enum<E>> Iterable<String> sortedNames(Class<E> theEnumClass)
        {
            List<String> names = new ArrayList<String>();
		
            for (Enum<E> e : EnumSet.allOf(theEnumClass))
            {
                names.add(e.name());
            }
            Collections.sort(names);
            return names;
        }

The Target annotation can have multiple values of the Enum type ElementType. These are represented by a group of checkboxes. The currently selected values are held in the instance variable targets which is of type EnumSet<ElementType>.


        // Targets
		
        label = new Label(group, SWT.NONE);
        label.setText(Text.TARGETS_LABEL);
		
        GridData targetsData = new GridData();
		
        targetsData.verticalAlignment = SWT.TOP;
        label.setLayoutData(targetsData);
		
        Composite targetsGroup       = new Composite(group, SWT.NONE);
        RowLayout targetsGroupLayout = new RowLayout(SWT.VERTICAL);
		
        targetsGroupLayout.marginLeft = 0;
        targetsGroupLayout.marginTop  = 0;
        targetsGroup.setLayout(targetsGroupLayout);
		
        listener = new Listener()
        {
            @Override
            public void handleEvent(Event theEvent) 
            {
                Button      button = (Button)(theEvent.widget);
                ElementType type   = (ElementType)button.getData();
				
                if (button.getSelection())
                {
                    targets.add(type);
                }
                else
                {
                    targets.remove(type);
                }
            }
        };
		
        for (String name : sortedNames(ElementType.class))
        {
            button = new Button(targetsGroup, SWT.CHECK);
            button.addListener(SWT.Selection, listener);
            button.setData(Enum.valueOf(ElementType.class, name));
            button.setText(name);
        }



Copyright (c) 2009 By Simon Lewis. All Rights Reserved

October 29, 2009

An Extended NewAnnotation Wizard For Eclipse

Something you cannot currently do with any of the Eclipse Java type creation wizards is add annotations. This is not a particularly big deal, you can always add them later using the editor, unless you happen to be defining a lot of new annotations which are themselves annotated with one or more of the built-in meta-annotations

in which case it would be quite handy to be able to tick some boxes in the wizard and have them appear auto-magically

Here’s the wizard as implemented by Eclipse

AnnotationWizard

Anyway, because I have been defining quite a few new annotations and was getting quite bored with adding the meta-annotations by hand I thought I would have a go at customizing the default wizard and adding the features I wanted.

It turned out to be a bit more involved than I had expected, but it can be done, and here it is.

NewAnnotationWizard

Not the world’s greatest UI design for sure, but it does the job.


Copyright (c) 2009 By Simon Lewis. All Rights Reserved

Create a free website or blog at WordPress.com.

%d bloggers like this: