前回はMaster
パッケージ・クラスの構造の整理 
今までは
パッケージの分割
まず、
| パッケージ名 | 説明 | 所属するファイル | 
|---|---|---|
| plugin | プラグイン全体で使用するクラスを配置する | Activator. | 
| model | モデルクラスを配置する | Field. | 
| ui | ユーザーインタフェースに関係するクラスを配置する | FormDesignerEditor. | 
 
Master(一覧)のクラス化  
現在のフォームデザイナーのソースコードの中で一番複雑なのは、
マニフェストエディターの
FieldsMasterSectionPartクラスでウィジェットの生成・
public class FieldsMasterSectionPart extends SectionPart {
    public FieldsMasterSectionPart(Composite parent, IManagedForm managedForm) {
        super(parent, 
              managedForm.getToolkit(), 
              Section.TITLE_BAR | Section.DESCRIPTION);
        initialize(managedForm);
        createContents(getSection(), managedForm.getToolkit());
    }
    private void createContents(Section section, FormToolkit toolkit) {
        section.setText("フィールド一覧");
        section.setDescription("編集するフィールドを選択してください。");
        Composite composite = toolkit.createComposite(section);
        composite.setLayout(new GridLayout(2, false));
       
        Table table = toolkit.createTable(
                        composite, 
                        SWT.SINGLE | SWT.FULL_SELECTION);
        table.setHeaderVisible(true);
        table.setLinesVisible(true);
        GridData layoutData = new GridData();
        layoutData.horizontalAlignment = GridData.FILL;
        layoutData.verticalAlignment = GridData.FILL;
        layoutData.grabExcessHorizontalSpace = true;
        layoutData.grabExcessVerticalSpace = true;
        table.setLayoutData(layoutData);
       
        TableColumn column1 = new TableColumn(table, SWT.NULL);
        column1.setText("フィールド名");
        column1.setWidth(100);
        TableColumn column2 = new TableColumn(table, SWT.NULL);
        column2.setText("説明");
        column2.setWidth(100);
        TableViewer viewer = new TableViewer(table);
        viewer.setContentProvider(new ArrayContentProvider());
        viewer.setLabelProvider(new ITableLabelProvider() {
            public Image getColumnImage(Object element, int columnIndex) {
                return null;
            }
            public String getColumnText(Object element, int columnIndex) {
                if (element == null) {
                    return "";
                }
                if (!(element instanceof Field)) {
                    return "";
                }
                
                Field field = (Field) element;
                if (columnIndex == 0) {
                    return field.getName();
                } else if (columnIndex == 1) {
                    return field.getDescription();
                }
                return "";
            }
            public void addListener(ILabelProviderListener listener) {
            }
            public void dispose() {
            }
            public boolean isLabelProperty(Object element, String property) {
                return false;
            }
            public void removeListener(ILabelProviderListener listener) {
            }
        });
        final SectionPart part = new SectionPart(section);
        viewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                FieldsMasterSectionPart.this.getManagedForm().fireSelectionChanged(
                                part,  
                                event.getSelection());
            }
        });
        Composite buttons = toolkit.createComposite(composite);
        layoutData = new GridData();
        layoutData.verticalAlignment = GridData.FILL;
        buttons.setLayoutData(layoutData);
        buttons.setLayout(new GridLayout());
        Button addButton = toolkit.createButton(buttons, "追加(&A)...", SWT.PUSH);
        layoutData = new GridData();
        layoutData.horizontalAlignment = GridData.FILL;
        addButton.setLayoutData(layoutData);
        
        Button delButton = toolkit.createButton(buttons, "削除(&D)...", SWT.PUSH);
        layoutData = new GridData();
        layoutData.horizontalAlignment = GridData.FILL;
        delButton.setLayoutData(layoutData);
        Button upButton = toolkit.createButton(buttons, "上へ", SWT.PUSH);
        layoutData = new GridData();
        layoutData.horizontalAlignment = GridData.FILL;
        upButton.setLayoutData(layoutData);
        Button downButton = toolkit.createButton(buttons, "下へ", SWT.PUSH);
        layoutData = new GridData();
        layoutData.horizontalAlignment = GridData.FILL;
        downButton.setLayoutData(layoutData);
        section.setClient(composite);
        
        viewer.setInput(createSample());
    }
    private List createSample() {
        List fields = new ArrayList();
        
        Field field1 = new Field("name");
        field1.setDescription("名前");
        field1.setRequired(true);
        field1.setMessage("名前は必須です。");
        
        fields.add(field1);
        Field field2 = new Field("phone");
        field2.setDescription("電話番号");
        field2.setRequired(true);
        field2.setMessage("電話番号は必須です。");
        
        fields.add(field2);
        
        Field field3 = new Field("address");
        field3.setDescription("住所");
        field3.setRequired(false);
        
        fields.add(field3);
        
        return fields;
    }
}   private class FieldsBlock extends MasterDetailsBlock {
    @Override
    protected void createMasterPart(
                    final IManagedForm managedForm,
                    final Composite parent) {
        new FieldsMasterSectionPart(parent, managedForm);
    }
    @Override
    protected void createToolBarActions(IManagedForm managedForm) {
    }
    @Override
    protected void registerPages(DetailsPart detailsPart) {
        ...
    }
}ここまで実装できたら、
Details(詳細)のクラス化  
続いて、
public class FieldDetailsPage implements IDetailsPage {
   ...
   (ソースコードはFieldsBlockクラスのregisterPages()メソッドのIDetailsPageインタフェースの無名クラスをそのまま移動してきます。)
   ...
}private class FieldsBlock extends MasterDetailsBlock {
    @Override
    protected void createMasterPart(
                    final IManagedForm managedForm,
                    final Composite parent) {
        new FieldsMasterSectionPart(parent, managedForm);
    }
    @Override
    protected void createToolBarActions(IManagedForm managedForm) {
    }
    @Override
    protected void registerPages(DetailsPart detailsPart) {
        detailsPart.registerPage(Field.class, new FieldDetailsPage());
    }
}ここまで実装できたら、
ボタンの実装
ソースコードはだいぶ整理できましたので、
[追加]ボタン 
[追加]
private void createContents(Section section, FormToolkit toolkit) {
    ...
    final TableViewer viewer = new TableViewer(table);
    ...
    final Composite buttons = toolkit.createComposite(composite);
    ...
    Button addButton = toolkit.createButton(buttons, "追加(&A)...", SWT.PUSH);
    layoutData = new GridData();
    layoutData.horizontalAlignment = GridData.FILL;
    addButton.setLayoutData(layoutData);
    addButton.addSelectionListener(new SelectionListener() {
        public void widgetSelected(SelectionEvent e) {
            InputDialog dialog = new InputDialog(
                                    buttons.getShell(), 
                                    "フィールド名入力", 
                                    "フィールド名を入力してください。", 
                                    null, 
                                    null);
            dialog.open();
            Field field = new Field(dialog.getValue());
            viewer.add(field);
            viewer.setSelection(new StructuredSelection(field));
        }
        public void widgetDefaultSelected(SelectionEvent e) {
        }
    });
    ...
}widgetSelected()メソッドの中でviewerとbuttonsを使用するので、
それでは実行してみましょう。
![[追加]ボタンをクリックするとフィールド名の入力を促すダイアログが表示される [追加]ボタンをクリックするとフィールド名の入力を促すダイアログが表示される](/assets/images/dev/serial/01/eclipse-plugin/0009/thumb/TH800_0009-02.png) 
[削除]ボタン 
削除は選択されているFieldオブジェクトを取得し、
private void createContents(Section section, FormToolkit toolkit) {
    ...
    Button delButton = toolkit.createButton(buttons, "削除(&D)...", SWT.PUSH);
    layoutData = new GridData();
    layoutData.horizontalAlignment = GridData.FILL;
    delButton.setLayoutData(layoutData);
    delButton.addSelectionListener(new SelectionListener() {
        public void widgetSelected(SelectionEvent e) {
            Field field = 
                (Field) ((IStructuredSelection) viewer.getSelection())
                .getFirstElement();
            viewer.remove(field);
        }
        public void widgetDefaultSelected(SelectionEvent e) {
        }
    });
}それでは実行してみましょう。Master
[上へ][下へ]ボタン  
最後に
private void createContents(Section section, FormToolkit toolkit) {
    ...
    Button upButton = toolkit.createButton(buttons, "上へ", SWT.PUSH);
    layoutData = new GridData();
    layoutData.horizontalAlignment = GridData.FILL;
    upButton.setLayoutData(layoutData);
    upButton.addSelectionListener(new SelectionListener() {
        public void widgetSelected(SelectionEvent e) {
            int index = viewer.getTable().getSelectionIndex();
            if (index == 0) {
                return;
            }
            Field tmpField = (Field) viewer.getElementAt(index - 1);
            viewer.replace(viewer.getElementAt(index), index - 1);
            viewer.replace(tmpField, index);
            viewer.setSelection(
                    new StructuredSelection((Field) viewer.getElementAt(index - 1)));
        }
        public void widgetDefaultSelected(SelectionEvent e) {
        }
    });
    
    Button downButton = toolkit.createButton(buttons, "下へ", SWT.PUSH);
    layoutData = new GridData();
    layoutData.horizontalAlignment = GridData.FILL;
    downButton.setLayoutData(layoutData);
    downButton.addSelectionListener(new SelectionListener() {
        public void widgetSelected(SelectionEvent e) {
            int index = viewer.getTable().getSelectionIndex();
            if (index + 1 == viewer.getTable().getItemCount()) {
                return;
            }
            Field tmpField = (Field) viewer.getElementAt(index + 1);
            viewer.replace(viewer.getElementAt(index), index + 1);
            viewer.replace(tmpField, index);
            viewer.setSelection(
                    new StructuredSelection((Field) viewer.getElementAt(index + 1)));
        }
        public void widgetDefaultSelected(SelectionEvent e) {
        }
    });
    ...
}それでは実行してみましょう。Master
![[上へ]ボタン、[下へ]ボタンに合わせてフィールドが上下に移動する [上へ]ボタン、[下へ]ボタンに合わせてフィールドが上下に移動する](/assets/images/dev/serial/01/eclipse-plugin/0009/thumb/TH400_0009-03.png) 
Details(詳細)の変更の反映  
Master
ManagedFormクラスのfireSelectionChanged()メソッドの実装を見るとわかるのですが、
IPartSelectionListenerインタフェースはselectionChanged()メソッドを定義しているので、
public class FieldsMasterSectionPart extends SectionPart implements IPartSelectionListener {
    private TableViewer fViewer;
    ...
    private void createContents(Section section, FormToolkit toolkit) {
        ...
        fViewer = new TableViewer(table);
        ...
        fViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                FieldsMasterSectionPart.this.getManagedForm().fireSelectionChanged(
                                FieldsMasterSectionPart.this,  
                                event.getSelection());
            }
        });
        ...
        section.setClient(composite);
        getManagedForm().addPart(this);
        fViewer.setInput(createSample());
    }
    ...
    public void selectionChanged(IFormPart part, ISelection selection) {
        if (part == this) {
            return;
        }
        if (!(selection instanceof IStructuredSelection)) {
            return;
        }
        fViewer.refresh((Field) ((IStructuredSelection) selection).getFirstElement());
    }
}次に変更を通知するDetails
public class FieldDetailsPage implements IDetailsPage {
    private Field fField;
    private SectionPart fSectionPart;
    ...
    public void createContents(Composite parent) {
        ...
        layoutData = new GridData();
        layoutData.grabExcessHorizontalSpace = true;
        layoutData.horizontalAlignment = GridData.FILL;
        composite.setLayoutData(layoutData);
        fSectionPart = new SectionPart(section);
        FocusListener focusListener = new FocusListener() {
            public void focusGained(FocusEvent e) {
            }
            public void focusLost(FocusEvent event) {
                if (fNameText == event.widget) {
                    fField.setName(fNameText.getText());
                } else if (fDescriptionText == event.widget) {
                    fField.setDescription(fDescriptionText.getText());
                } else if (fRequiredYesButton == event.widget
                           || fRequiredNoButton == event.widget) {
                    fField.setRequired(fRequiredYesButton.getSelection());
                } else if (fMessageText == event.widget) {
                    fField.setMessage(fMessageText.getText());
                }
                fForm.fireSelectionChanged(
                            fSectionPart, 
                            new StructuredSelection(fField));
            }
        };
        toolkit.createLabel(composite, "フィールド名");
        ...
        fNameText.addFocusListener(focusListener);
        toolkit.createLabel(composite, "概要");
        ...
        fDescriptionText.addFocusListener(focusListener);
        toolkit.createLabel(composite, "必須");
        ...
        fRequiredYesButton.addFocusListener(focusListener);
        fRequiredNoButton.addFocusListener(focusListener);
        
        toolkit.createLabel(composite, "メッセージ");
        ...
        fMessageText.addFocusListener(focusListener);
        section.setClient(composite);
    }
    ...
    public void selectionChanged(IFormPart part,
                                 ISelection selection) {
        if (fSectionPart == part) {
            return;
        }
        ...
        fField = field;
    }
}それでは実行してみましょう。フィールド名や概要を変更して、
 
おわりに
今回はテーブル、
次回はバリデータ定義フォームの実装を説明します。