之前搜到一篇《GEF 给PropertySheetPage设置属性排序功能》的博客,如何将这种方法移植到GMF中呢?可以如下做:
首先,新建一个类MyPropertySheetPage,继承至PropertySheetPage。
public class MyPropertySheetPage extends PropertySheetPage {
@Override
public void createControl(Composite parent) {
// 设置一个使用描述来排序的Sorter
PropertySheetSorter sorter = new PropertySheetSorter() {
public int compare(IPropertySheetEntry entryA, IPropertySheetEntry entryB) {
return getCollator().compare(entryA.getDescription(), entryB.getDescription());
}
};
this.setSorter(sorter);
super.createControl(parent);
}
}
其次,新建一个类MyPropetySection,继承至AbstractModelerPropertySection。
public class MyPropertySection extends AbstractModelerPropertySection {
/**
* the property sheet page for this section
*/
protected MyPropertySheetPage page;
/* (non-Javadoc)
* @see org.eclipse.ui.views.properties.tabbed.ISection#createControls(org.eclipse.swt.widgets.Composite, org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
*/
public void createControls(final Composite parent,
TabbedPropertySheetPage aTabbedPropertySheetPage) {
super.createControls(parent, aTabbedPropertySheetPage);
Composite composite = getWidgetFactory()
.createFlatFormComposite(parent);
FormData data = null;
String tableLabelStr = getTableLabel();
CLabel tableLabel = null;
if (tableLabelStr != null && tableLabelStr.length() > 0) {
tableLabel = getWidgetFactory().createCLabel(composite,
tableLabelStr);
data = new FormData();
data.left = new FormAttachment(0, 0);
data.top = new FormAttachment(0, 0);
tableLabel.setLayoutData(data);
}
page = new MyPropertySheetPage();
UndoableModelPropertySheetEntry root = new UndoableModelPropertySheetEntry(
OperationHistoryFactory.getOperationHistory());
root.setPropertySourceProvider(getPropertySourceProvider());
page.setRootEntry(root);
page.createControl(composite);
data = new FormData();
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100, 0);
if (tableLabel == null) {
data.top = new FormAttachment(0, 0);
} else {
data.top = new FormAttachment(tableLabel, 0, SWT.BOTTOM);
}
data.bottom = new FormAttachment(100, 0);
data.height = 100;
data.width = 100;
page.getControl().setLayoutData(data);
setActionBars(aTabbedPropertySheetPage.getSite().getActionBars());
}
/**
* Sets and prepares the actionBars for this section
*
* @param actionBars the action bars for this page
* @see org.eclipse.gmf.runtime.common.ui.properties.TabbedPropertySheetPage#setActionBars(org.eclipse.ui.IActionBars)
*/
public void setActionBars(IActionBars actionBars) {
if (actionBars != null) {
actionBars.getMenuManager().removeAll();
actionBars.getToolBarManager().removeAll();
actionBars.getStatusLineManager().removeAll();
page.makeContributions(actionBars.getMenuManager(), actionBars
.getToolBarManager(), actionBars.getStatusLineManager());
actionBars.getToolBarManager().update(true);
}
}
/**
* Returns the PropertySource provider. The default implementation returns
* static adapter factory for the properties services. If the extending
* class needs to use a different provider then this method has to be
* overwriten.
*
* @return The PropertySource provider
*/
protected IPropertySourceProvider getPropertySourceProvider() {
return propertiesProvider;
}
/**
* Returns the label for the table. The default implementation returns null,
* that is, there is no label.
*
* @return The label for the table
*/
protected String getTableLabel() {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.ui.views.properties.tabbed.ISection#setInput(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void setInput(IWorkbenchPart part, ISelection selection) {
IEditingDomainProvider provider = (IEditingDomainProvider) part
.getAdapter(IEditingDomainProvider.class);
if (provider != null) {
EditingDomain theEditingDomain = provider.getEditingDomain();
if (theEditingDomain instanceof TransactionalEditingDomain) {
setEditingDomain((TransactionalEditingDomain) theEditingDomain);
}
}
// Set the eObject for the section, too. The workbench part may not
// adapt to IEditingDomainProvider, in which case the selected EObject
// will be used to derive the editing domain.
if (!selection.isEmpty() && selection instanceof IStructuredSelection) {
Object firstElement = ((IStructuredSelection) selection)
.getFirstElement();
if (firstElement != null) {
EObject adapted = unwrap(firstElement);
if (adapted != null) {
setEObject(adapted);
}
}
}
page.selectionChanged(part, selection);
}
/* (non-Javadoc)
* @see org.eclipse.ui.views.properties.tabbed.ISection#dispose()
*/
public void dispose() {
super.dispose();
if (page != null) {
page.dispose();
page = null;
}
}
/* (non-Javadoc)
* @see org.eclipse.ui.views.properties.tabbed.ISection#refresh()
*/
public void refresh() {
page.refresh();
}
/* (non-Javadoc)
* @see org.eclipse.ui.views.properties.tabbed.ISection#shouldUseExtraSpace()
*/
public boolean shouldUseExtraSpace() {
return true;
}
/**
* Update if nessesary, upon receiving the model event.
*
* @see #aboutToBeShown()
* @see #aboutToBeHidden()
* @param notification -
* even notification
* @param element -
* element that has changed
*/
public void update(final Notification notification, EObject element) {
if (!isDisposed()) {
postUpdateRequest(new Runnable() {
public void run() {
if (!isDisposed() && !isNotifierDeleted(notification))
refresh();
}
});
}
}
/* (non-Javadoc)
* @see org.eclipse.gmf.runtime.emf.core.edit.IDemuxedMListener#getFilter()
*/
public NotificationFilter getFilter() {
return NotificationFilter.createEventTypeFilter(Notification.SET).or(
NotificationFilter.createEventTypeFilter(Notification.UNSET)).or(
NotificationFilter.createEventTypeFilter(Notification.ADD)).or(
NotificationFilter.createEventTypeFilter(Notification.ADD_MANY))
.or(NotificationFilter.createEventTypeFilter(Notification.REMOVE))
.or(
NotificationFilter
.createEventTypeFilter(Notification.REMOVE_MANY)).and(
NotificationFilter.createNotifierTypeFilter(EObject.class));
}
/*
* (non-Javadoc)
*
* @see org.eclipse.gmf.runtime.diagram.ui.properties.sections.AbstractModelerPropertySection#addToEObjectList(java.lang.Object)
*/
protected boolean addToEObjectList(Object object) {
/* not implemented */
return true;
}
}
然后,修改*.sheet包里的GMF自动生成的XXXPropertySection类,让其继承MyPropertySection:
public class XXXPropertySection extends MyPropertySection implements
IPropertySourceProvider {
最后,在生成的工程*.edit里的*.provider包的某个XXXItemProvider类里,修改类方法addXXXPropertyDescriptor(),将getString("_UI_PropertyDescriptor_description", "_UI_Process_level_feature", "_UI_Process_type")(即String description参数)改为"01","02", "03",比如:
protected void addStartTimePropertyDescriptor(Object object) {
itemPropertyDescriptors.add
(createItemPropertyDescriptor
(((ComposeableAdapterFactory)adapterFactory).getRootAdapterFactory(),
getResourceLocator(),
getString("_UI_Process_startTime_feature"),
"01"/*getString("_UI_PropertyDescriptor_description", "_UI_Process_startTime_feature", "_UI_Process_type")*/,
DfdPackage.Literals.PROCESS__START_TIME,
true,
false,
false,
ItemPropertyDescriptor.INTEGRAL_VALUE_IMAGE,
null,
null));
}
这样,每个属性就可以按照规定的顺序排序了。
ps:
上面XXXPropertySection类原本是继承AdvancedPropertySection类的,我新建的类:MyPropertySection其实和AdvancedPropertySection基本一样(从AdvancedPropertySection类copy过来的),只是修改了两行代码(黄色代码部分),然后让XXXPropertySection类继承MyPropertySection。一般的思路是让XXXPropertySection继承AdvancedPropertySection,然后重写方法createControls(),将方法里的page = new PropertySheetPage();这行替换为如下代码段:
propertySheetPage = new PropertySheetPage() {
@Override
public void createControl(Composite parent) {
// 设置一个使用描述来排序的Sorter
PropertySheetSorter sorter = new PropertySheetSorter() {
public int compare(IPropertySheetEntry entryA, IPropertySheetEntry entryB) {
return getCollator().compare(entryA.getDescription(), entryB.getDescription());
}
};
this.setSorter(sorter);
super.createControl(parent);
}
};
但这样会带来一个问题,createControls()的super.createControls(parent, aTabbedPropertySheetPage);这行代码,会调用AdvancedPropertySection类的createControls(),而AdvancedPropertySection类的createControls()又有一行page = new PropertySheetPage();这样会导致生成两个PropertySheetPage。但你要是去掉super.createControls(parent, aTabbedPropertySheetPage);又不行,原因是,不说了,自己跟踪下很容易明白。所以不得已,我只好那么做了。不知道有没其他别的更好的技巧?