GMF中,如何给属性排序
之前搜到一篇《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_XXX_feature", "_UI_XXX_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);又不行,原因是,不说了,自己跟踪下很容易明白。所以不得已,我只好那么做了。不知道有没其他别的更好的技巧?