最近做了一個任務,要求把一個grahpical editor里的palette里的內容重新刷新一下,要求是在不關閉editor里前提之下。

       一開始還在懷疑這個能否實現不,不過后來看了看代碼,發現這是完全可行的,且看我細細道來:

        先看GraphicalEditorWithFlyoutPalette里的splitter這個成員,它把整個editor分成了兩個部分一個就是大的用于GEF畫圖的那部份;另外一部分很明顯就是palette啦!說這么多,看看它的createControl方法就全明白啦:
public void createPartControl(Composite parent) {
    splitter 
= new FlyoutPaletteComposite(parent, SWT.NONE, getSite().getPage(),
            getPaletteViewerProvider(), getPalettePreferences());
    
super.createPartControl(splitter);
    splitter.setGraphicalControl(getGraphicalControl());
    
if (page != null{
        splitter.setExternalViewer(page.getPaletteViewer());
        page 
= null;
    }

}

        其中的setExternalviewer就是放的palette的viewer,說到viewer我的第一個聯想就是SWT里的viewer其實不是這樣的,這里的viewer其實與一個基于GEF的Graphcial Viewer;也就是說,我們在一個graphical editor里看到的palette是通過drawer2D畫上去了,和我們平時GEF里的圖形沒什么兩樣。
/**
 * Returns the PaletteRoot for the palette viewer.
 * 
@return the palette root
 
*/

protected abstract PaletteRoot getPaletteRoot();
        再看這個getPaletteRoot方法它為palette viewer提供一個root,那這個root到底是什么呢?我們再繼續往下看。沿著palette root的繼承樹往上找,最后發現了這個:

        一看palette entry的文檔就明白了,其實它就是 palette的模型。
/**
 * Root class (statically) for the palette model.
 * 
 * 
@author Pratik Shah
 
*/

public class PaletteEntry {
        當然如果它是GEF的模型,那么必然他就會有listeners一查代碼,果真是這樣的。
/**
 * A listener can only be added once.  Adding it more than once will do nothing.
 * 
@param listener the PropertyChangeListener that is to be notified of changes
 * 
@see java.beans.PropertyChangeSupport#addPropertyChangeListener(
 *                                                         java.beans.PropertyChangeListener)
 
*/

public void addPropertyChangeListener(PropertyChangeListener listener) {
    listeners.removePropertyChangeListener(listener);
    listeners.addPropertyChangeListener(listener);
}
        那么這個add listener方法被誰用呢?想都不用想了,肯定是被它的edit part 嘍,MVC嘛~~~不信看PaletteEditPart.java的activate方法:

/**
 * 
@see org.eclipse.gef.editparts.AbstractGraphicalEditPart#activate()
 
*/

public void activate() {
    
super.activate();
    PaletteEntry model 
= (PaletteEntry)getModel();
    model.addPropertyChangeListener(
this);
    traverseChildren(model, 
true);
}
        
        
        模型的修改必定會被通知到 edit part 里,它再根據具體的情況對viewer進行更新,見下:
/**
 * 
@see java.beans.PropertyChangeListener#propertyChange(PropertyChangeEvent)
 
*/

public void propertyChange(PropertyChangeEvent evt) {
    String property 
= evt.getPropertyName();
    
if (property.equals(PaletteContainer.PROPERTY_CHILDREN)) {
        traverseChildren((List)evt.getOldValue(), 
false);
        refreshChildren();
        traverseChildren((List)evt.getNewValue(), 
true);
    }
 else if (property.equals(PaletteEntry.PROPERTY_LABEL)
            
|| property.equals(PaletteEntry.PROPERTY_SMALL_ICON)
            
|| property.equals(PaletteEntry.PROPERTY_LARGE_ICON)
            
|| property.equals(PaletteEntry.PROPERTY_DESCRIPTION))
        refreshVisuals();
}

        明白了!?說了那么多其實只要一名句話啦:修改一下palette root里palette entry的內容GEF 就會自動的將palette里的表現更新了。在Dengues的項目里,我在GEFComponentEditor.java里加入以下方法,便可以了:
    /**
     * Reset the content of the palette root will cause palette viewer be refreshed.
     * 
     * yzhang Comment method "refreshPalette".
     
*/
    
public void refreshPalette() {

        List
<PaletteContainer> containers = new ArrayList<PaletteContainer>(root.getChildren());

        
for (PaletteContainer element : containers) {
            
if (element instanceof PaletteGroup) {
                
continue;
            }
            root.remove(element);
        }

        CompEditorPaletteFactory.create(factory, root);

    }

       關于這個方法是如何調用的,這就涉及到另外一個話題了,見《如何解決插件之間循環依賴的問題》。
   
       K字好累。Han hanhan .....