2010년 2월 25일 목요일

SWT Table Cell Editor 사용

SWT Table의 기본 셀 에디터는 TextCellEditor 다
셀이 선택되었을 때 Text 입력 모드로 변경이 되고, 엔터키가 입력되거나 포커스를 잃게 되었을때 Text안의 문자열로 값이 설정된다.
리스트에서 선택하는 경우에는 ComboCellEditor를 사용하면 된다.

나는 메소드의 파라미터에 대한 타입을 지정하는 셀에디터가 필요했다.
Primitive 타입은 Combo를 이용하여 선택할 수 있도록 하고,
클래스는 찾기 버튼을 클릭할때 JDT의 JavaUI.createTypeDialog() 메소드를 이용하여 별도의 다이얼로그에서 선택할 수 있도록 해야했다.
또한 배열타입을 고려하여 사용자가 직접 값을 입력할 필요도 있었다. (이부분은 Combo 의 스타일만 적용하면 된다.)

이와 같은 요구사항을 종합해 보면 메소드 파라미터 목록은 테이블의 각 아이템으로 설정이 가능하며,
파라미터 타입은 별도의 CellEditor를 구현해야만 하고, 파라미터명은 TextCellEditor를 이용하여 구현하면 된다.
타입을 설정하기 위한 CellEditor는 Combo와 버튼이 있어야 하고 Combo에는 Primitive 타입을 선택할 수 있도록 하고 버튼이 클릭되면 타입(Class, Interface, Enum 등)을 선택할 수 있는 다이얼로그 창이 열린 후 선택된 값으로 설정되도록 해야 한다.


1. 테이블의 각 셀에 셀 에디터 설정하기


protected void setupViewer(TableViewer tableViewer) {
Table table = tableViewer.getTable();

table.addListener(SWT.MeasureItem, measureListener = new Listener() {

@Override
public void handleEvent(Event event) {
event.height = event.gc.getFontMetrics().getHeight() * 2;
}
});
TableViewerColumn column = null;

column = new TableViewerColumn(tableViewer, SWT.NONE);
column.getColumn().setText("parameter type");
column.getColumn().setWidth(200);

EditingSupport editingSupport = new ParameterEditingSupport(viewer, MethodParameterColumn.PARAMETER_TYPE);
column.setLabelProvider(new ParameterLabelProvider(MethodParameterColumn.PARAMETER_TYPE));
column.setEditingSupport(editingSupport);


column = new TableViewerColumn(tableViewer, SWT.NONE);
column.getColumn().setText("name");
column.getColumn().setWidth(200);
column.setLabelProvider(new ParameterLabelProvider(MethodParameterColumn.PARAMETER_NAME));
column.setEditingSupport(new ParameterEditingSupport(viewer, MethodParameterColumn.PARAMETER_NAME));

table.setLinesVisible(true);
table.setHeaderVisible(true);
}

2. EditingSupport 클래스 구현하기

class ParameterEditingSupport extends EditingSupport {
private final MethodParameterColumn column;
private boolean editable;

public ParameterEditingSupport(ColumnViewer viewer, MethodParameterColumn column) {
super(viewer);
this.column = column;
init();
}

@Override
protected boolean canEdit(Object element) {
return this.editable;
}

@Override
protected CellEditor getCellEditor(Object element) {

if (element instanceof MethodParameter) {
final MethodParameter parameter = (MethodParameter) element;

switch(column) {
case PARAMETER_TYPE:
final CellEditor cellEditor = new TypeSelectionDialogCellEditor(viewer.getTable(), javaProject);
cellEditor.addListener(new ICellEditorListener() {

@Override
public void applyEditorValue() {
System.out.println("applyEditorValue()");
System.out.println("value: " + cellEditor.getValue());
parameter.setType((String)cellEditor.getValue());
manager.refresh();
}

@Override
public void cancelEditor() {
System.out.println("cancelEditor()");
}

@Override
public void editorValueChanged(boolean oldValidState,
boolean newValidState) {
System.out.println("editorValueChanged: " + oldValidState + ", " + newValidState);
}

});

return cellEditor;
case PARAMETER_NAME:
this.editable = true;
return new TextCellEditor(viewer.getTable());
}

}
return new TextCellEditor(viewer.getTable());
}

@Override
protected Object getValue(Object element) {
if (element instanceof MethodParameter) {
MethodParameter cast = (MethodParameter) element;
return MethodParameterManagerHelper.getValue(cast, column);
}
return "NULL";
}

@Override
protected void setValue(Object element, Object value) {
if (element instanceof MethodParameter) {
MethodParameter cast = (MethodParameter) element;

MethodParameterManagerHelper.setValue(value, cast, column);
getViewer().update(element, MethodParameterColumn.getColumnProperties());
getViewer().refresh(element);
return;
}
throw new IllegalArgumentException("invalid element: " + element);
}

private void init() {
switch(column) {
case PARAMETER_TYPE:
this.editable = true;
break;
case PARAMETER_NAME:
this.editable = true;
break;
}
}
}


3. CellEditor 구현하기
각 셀에 대한 에디터는 getCellEditor() 메소드에 의해서 결정된다. parameterType에 대한 CellEditor는 위의 코드에서 TypeSelectionDialogCellEditor 이다.
클래스에 대한 소스 코드 양이 많지 않으니 모두 포함하도록 한다.


package com.archnal.amf.ui.wizards;


import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.search.SearchEngine;
import org.eclipse.jdt.ui.IJavaElementSearchConstants;
import org.eclipse.jdt.ui.JavaUI;
import org.eclipse.jface.viewers.DialogCellEditor;
import org.eclipse.jface.window.Window;
import org.eclipse.pde.internal.ui.PDEPlugin;
import org.eclipse.pde.internal.ui.PDEUIMessages;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.SelectionDialog;

public class TypeSelectionDialogCellEditor extends DialogCellEditor {
private static final String[] PRIMITIVE_PARAMETER_TYPES = {
"boolean",
"byte",
"char",
"double",
"float",
"int",
"long",
"short"
};
private IJavaProject javaProject;
private Combo combo;
private SelectionListener selectionListener;


public TypeSelectionDialogCellEditor(Composite parent, IJavaProject javaProject) {
super(parent);
this.javaProject = javaProject;
}

@Override
public void dispose() {
combo.removeSelectionListener(selectionListener);

super.dispose();
}
@Override
protected Control createContents(Composite cell) {
// return super.createContents(cell);

Composite composite = new Composite(cell, getStyle());
composite.setBackground(cell.getBackground());

GridLayout layout = new GridLayout(1, false);
layout.marginWidth = 0;
layout.marginHeight = 0;
composite.setLayout(layout);

GridData gd = new GridData(GridData.FILL_HORIZONTAL);

combo = new Combo(composite, SWT.NONE);
combo.setItems(PRIMITIVE_PARAMETER_TYPES);
combo.setLayoutData(gd);

combo.addSelectionListener(selectionListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {

markDirty();

String value = combo.getText();
doSetValue(value);

fireApplyEditorValue();
}
});
return composite;
}

@Override
protected Object openDialogBox(Control cellEditorWindow) {
// TODO Auto-generated method stub
try {
final int scopeType = IJavaElementSearchConstants.CONSIDER_ALL_TYPES;
// String filter = getReturnType();
String filter = getValue() == null ? "" : getValue().toString();

// filter = filter.substring(filter.lastIndexOf(".") + 1); //$NON-NLS-1$
// SelectionDialog dialog = JavaUI.createTypeDialog(PDEPlugin.getActiveWorkbenchShell(), PlatformUI.getWorkbench().getProgressService(), SearchEngine.createWorkspaceScope(), scopeType, false, filter);
SelectionDialog dialog = JavaUI.createTypeDialog(PDEPlugin.getActiveWorkbenchShell(), PlatformUI.getWorkbench().getProgressService(), SearchEngine.createJavaSearchScope(new IJavaElement[] { javaProject }), scopeType, false, filter);
dialog.setTitle(PDEUIMessages.GeneralInfoSection_selectionTitle);
if (dialog.open() == Window.OK) {
IType type = (IType) dialog.getResult()[0];
return type.getFullyQualifiedName('$');
// returnTypeCombo.setText(type.getFullyQualifiedName('$'));
// entry.setValue(type.getFullyQualifiedName('$'));
// entry.commit();
}
} catch (CoreException e) {
e.printStackTrace();
}
return null;
}

}


위의 소스 코드에서 다음과 같은 사항은 주의해서 볼 필요가 있다.
TypeSelectionDialogCellEditor.openDialogBox()에서
doSetValue() 메소드 호출 후 fireApplyEditorValue() 메소드를 호출하여
셀의 값이 변경되었음을 누군가에게 통지하고 있다.
어딘가에서는 그 값을 변경하여 모델이 되는 파라미터 타입 값을 변경해 주어야 한다.
ParameterEditingSupport 클래스의 getCellEditor() 메소드에 파라미터 타입에 대한 셀 에디터 생성 시 ICellEditorListener를 등록하여 applyEditorValue()메소드에서 값이 변경될 때마다 파라미터 타입에 변경해주고 있음을 알 수 있다.

댓글 없음:

댓글 쓰기