Azureus源码剖析(五)

      这篇说说GUI方面,就以打开种子文件这个窗口为例,我对其代码进行了精简,拿出了一个基本的骨架。

 

首先来看基本的消息主循环部分:

    final Display display = new Display();
        invoke(
null);//创建窗口的主代码
    
        
while (stTorrentWindow != null && !stTorrentWindow.bClosed)
        {
//窗口创建完成且没有关闭
            if (!display.readAndDispatch())
            {
                display.sleep();
            }
        }
        display.dispose();

 

这里运用了单例模式来表示窗口,考虑到线程同步性,在静态工厂方法中使用了synchronized 关键字

private static TorrentWindow stTorrentWindow = null;

    
public synchronized static final void invoke(Shell parent)
    {
        
if (stTorrentWindow == null)
        {
//第一次创建窗口
            stTorrentWindow = new TorrentWindow(parent);
        }
        
else
        {
//激活已经创建的窗口
            if (stTorrentWindow.shell != null)
            {
                stTorrentWindow.shell.forceActive();
            }
        }
    }
    
private TorrentWindow(final Shell parent)
    {
        openWindow(parent);
    }

 

      真正的窗口创建工作是在openWindow方法中完成的,下面给出部分核心代码:

private void openWindow(Shell parent)
    {
        GridData gridData;
        
        shell 
= ShellFactory.createShell(parent, SWT.RESIZE | SWT.DIALOG_TRIM);
        shell.setText(
"打开 Torrent");
        
        GridLayout layout 
= new GridLayout();
        shell.setLayout(layout);
        shell.addListener(SWT.Resize, 
new Listener()
        {
            
public void handleEvent(Event e) {
                    
            }
        });
        
// Torrents
        
// ========

        Composite cButtons 
= new Composite(shell, SWT.NONE);
        RowLayout rLayout 
= new RowLayout(SWT.HORIZONTAL);
        rLayout.marginBottom 
= 0;
        rLayout.marginLeft 
= 0;
        rLayout.marginRight 
= 0;
        rLayout.marginTop 
= 0;
        cButtons.setLayout(rLayout);
        
        
// Buttons for tableTorrents
        Button browseTorrent = new Button(cButtons, SWT.PUSH);
        browseTorrent.setText(
"添加文件");
        browseTorrent.addListener(SWT.Selection, 
new Listener(){
            
public void handleEvent(Event arg0) {
                FileDialog fDialog 
= new FileDialog(shell, SWT.OPEN | SWT.MULTI);
                fDialog.setFilterExtensions(
new String[]{
                        
"*.torrent",
                        
"*.tor",
                        FILE_WILDCARD
                });
                fDialog.setFilterNames(
new String[]{
                        
"*.torrent",
                        
"*.tor",
                        FILE_WILDCARD
                });
                fDialog.setText(
"选择 Torrent文件");
                String fileName 
= fDialog.open();
                
if (fileName != null)
                {
                    
//addTorrents(fDialog.getFilterPath(), fDialog.getFileNames());
                }
            }
        });
        setGridData(cButtons, GridData.FILL_HORIZONTAL, browseTorrent, MIN_BUTTON_HEIGHT);
        
        Button browseURL 
= new Button(cButtons, SWT.PUSH);
        browseURL.setText(
"从URL添加");
        browseURL.addListener(SWT.Selection, 
new Listener(){
            
public void handleEvent(Event e) {
                browseURL();
            }
        });
        
        Button browseFolder 
= new Button(cButtons, SWT.PUSH);
        browseFolder.setText(
"从文件夹添加");
        browseFolder.addListener(SWT.Selection, 
new Listener(){
            
public void handleEvent(Event e)
            {
                DirectoryDialog fDialog 
= new DirectoryDialog(shell, SWT.NULL);
                fDialog.setMessage(
"选择 Torrent 文件所在目录");
                String path 
= fDialog.open();
                
if (path != null)
                {
                    addTorrents(path, 
null);
                }
            }
        });
        
        Group gTorrentsArea 
= new Group(shell, SWT.NONE);
        gridData 
= new GridData(GridData.FILL_HORIZONTAL);
        gTorrentsArea.setLayoutData(gridData);
        layout 
= new GridLayout();
        gTorrentsArea.setLayout(layout);
        gTorrentsArea.setText(
"Torrent文件");
        
        Composite cTorrentList 
= new Composite(gTorrentsArea, SWT.NONE);
        gridData 
= new GridData(GridData.FILL_HORIZONTAL);
        cTorrentList.setLayoutData(gridData);
        createTorrentListArea(cTorrentList);
        
//关闭窗口
        shell.addDisposeListener(new DisposeListener() 
        {
            
public void widgetDisposed(DisposeEvent e)
            {
                
if (!bClosed)
                    close(
falsetrue);
            }
        });

        shell.addListener(SWT.Traverse, 
new Listener() 
        {
            
public void handleEvent(Event e) 
            {
                
if (e.detail == SWT.TRAVERSE_ESCAPE) 
                {
                    close(
truetrue);
                }
            }
        });
        shell.open();
//显示窗口
    }

 

这里最重要的如何创建Shell的:

 

shell = ShellFactory.createShell(parent, SWT.RESIZE | SWT.DIALOG_TRIM);

 

下面就来看看ShellFactory的代码,主要是在ShellManager中加入新创建的Shell,如果此Shell已经创建过,则不再次加入

public final class ShellFactory 
{
    
public static Shell createShell(final Shell parent, final int styles)
    {
        
return getRegistedShell(new Shell(parent, styles));
    }
    
private static Shell getRegistedShell(final Shell toRegister)
    {
        
if (null == toRegister)
            
return null;
        ShellManager.sharedManager().addWindow(toRegister);
        
return toRegister;
    }
}

      最后来看ShellManager是如何管理Shell的:

 

public class ShellManager
{
    
private static ShellManager instance;

    
private final Collection shells = new ArrayList();//被管理的Shell
    private final List addHandlers = new LinkedList();//加入Shell时调用
    private final List removeHandlers = new LinkedList();//删除Shell时调用

    
static
    {
        instance 
= new ShellManager();
    }

    
/**
     * <p>Gets the application's shared shell manager</p>
     * <p>This ShellManager has no bearing on other ShellManager instances</p>
     * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>
     * 
@return
     
*/
    
public static final ShellManager sharedManager()
    {
//静态工厂方法
        return instance;
    }

    
public static boolean verifyShellRect(Shell shell, boolean bAdjustIfInvalid) 
    {
//验证窗口矩阵的合法性
        boolean bMetricsOk;
        
try {
            bMetricsOk 
= false;
            Point ptTopLeft 
= shell.getLocation();

            Monitor[] monitors 
= shell.getDisplay().getMonitors();
            
for (int j = 0; j < monitors.length && !bMetricsOk; j++) {
                Rectangle bounds 
= monitors[j].getBounds();
                bMetricsOk 
= bounds.contains(ptTopLeft);
            }
        } 
catch (NoSuchMethodError e) {
            Rectangle bounds 
= shell.getDisplay().getBounds();
            bMetricsOk 
= shell.getBounds().intersects(bounds);
        }
        
if (!bMetricsOk && bAdjustIfInvalid) {
            centreWindow(shell);
        }
        
return bMetricsOk;
    }
    
    
public static void centreWindow(Shell shell)
    {
//窗口居中
        Rectangle displayArea; // area to center in
        try {
            displayArea 
= shell.getMonitor().getClientArea();
        } 
catch (NoSuchMethodError e) {
            displayArea 
= shell.getDisplay().getClientArea();
        }

        Rectangle shellRect 
= shell.getBounds();

        
if (shellRect.height > displayArea.height) {
            shellRect.height 
= displayArea.height;
        }
        
if (shellRect.width > displayArea.width - 50) {
            shellRect.width 
= displayArea.width;
        }

        shellRect.x 
= displayArea.x + (displayArea.width - shellRect.width) / 2;
        shellRect.y 
= displayArea.y + (displayArea.height - shellRect.height) / 2;

        shell.setBounds(shellRect);
    }
    
/**
     * Adds a shell to the shell manager. If the shell is already managed, it is not added again.
     * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>
     * 
@param shell A SWT Shell
     
*/
    
public final void addWindow(final Shell shell)
    {
//加入新窗口
        
//Debug.out("Invoked by thread " + Thread.currentThread().getName());
        if(shells.contains(shell)) {return;}

        shells.add(shell);
        notifyAddListeners(shell);
        shell.addDisposeListener(
new DisposeListener()
        {
            
public void widgetDisposed(DisposeEvent event)
            {
                
try 
                {
                    removeWindow(shell);
                } 
                
catch (Exception e)
                {
                    
//Logger.log(new LogEvent(LogIDs.GUI, "removeWindow", e));
                }
            }
        });
        shell.addListener(SWT.Show, 
new Listener() 
        {
            
public void handleEvent(Event event) 
            {
                verifyShellRect(shell, 
false);
            }
        });
    }

    
/**
     * Removes a shell from the shell manager
     * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>
     * 
@param shell A SWT Shell
     
*/
    
public final void removeWindow(Shell shell)
    {
//删除窗口
        shells.remove(shell);
        notifyRemoveListeners(shell);
    }

    
/**
     * <p>Gets the shells managed by the manager as an Iterator</p>
     * <p>The order in which the shells were added are retained.</p>
     * <p><b>Note</b>: This method must be invoked by the SWT display thread</p>
     * 
@return The iterator
     
*/
    
public final Iterator getWindows()
    {
        
return shells.iterator();
    }

    
/**
     * Gets whether the ShellManager manages no shells
     * 
@return True if ShellManager is empty
     
*/
    
public final boolean isEmpty()
    {
        
return shells.isEmpty();
    }

    
/**
     * Gets the number of shells the ShellManager manages
     * 
@return The number
     
*/
    
public final int getSize()
    {
        
return shells.size();
    }

    
/**
     * <p>Invokes the handleEvent method specified by the SWT listener for each managed shell</p>
     * <p>The event's widget is set to the reference of the shell invoking it</p>
     * 
@param command A command implemented as a SWT Listener
     
*/
    
public final void performForShells(final Listener command)
    {
        Iterator iter 
= shells.iterator();
        
for(int i = 0; i < shells.size(); i++)
        {
            Shell aShell 
= (Shell)iter.next();
            Event evt 
= new Event();
            evt.widget 
= aShell;
            evt.data 
= this;
            command.handleEvent(evt);
        }
    }

    
/**
     * Gets the set of managed shells
     * 
@return The set
     
*/
    
protected final Collection getManagedShellSet()
    {
        
return shells;
    }

    
// events

    
/**
     * <p>Adds a listener that will be invoked when a shell has been added to the ShellManager</p>
     * <p>The listener and the shell will automatically be removed when the shell is disposed</p>
     * 
@param listener A SWT Listener
     
*/
    
public final void addWindowAddedListener(Listener listener)
    {
        addHandlers.add(listener);
    }

    
/**
     * Removes a listener that will be invoked when a shell has been added to the ShellManager
     * 
@param listener A SWT Listener
     
*/
    
public final void removeWindowAddedListener(Listener listener)
    {
        addHandlers.remove(listener);
    }

    
/**
     * Adds a listener that will be invoked when a shell has been removed from the ShellManager
     * 
@param listener A SWT Listener
     
*/
    
public final void addWindowRemovedListener(Listener listener)
    {
        removeHandlers.add(listener);
    }

    
/**
     * Removes a listener that will be invoked when a shell has been removed from the ShellManager
     * 
@param listener A SWT Listener
     
*/
    
public final void removeWindowRemovedListener(Listener listener)
    {
        removeHandlers.remove(listener);
    }

    
/**
     * Notifies the WindowAddedListener handlers
     * 
@param sender A SWT shell that "sends" the events
     
*/
    
protected final void notifyAddListeners(Shell sender)
    {
        Iterator iter 
= addHandlers.iterator();
        
for(int i = 0; i < addHandlers.size(); i++)
        {
            ((Listener)iter.next()).handleEvent(getSWTEvent(sender));
        }
    }

    
/**
     * Notifies the WindowRemovedListener handlers
     * 
@param sender A SWT shell that "sends" the events
     
*/
    
protected final void notifyRemoveListeners(Shell sender)
    {
        Iterator iter 
= removeHandlers.iterator();
        
for(int i = 0; i < removeHandlers.size(); i++)
        {
            ((Listener)iter.next()).handleEvent(getSWTEvent(sender));
        }
    }
    
/**
     * <p>Gets a generated SWT Event based on the shell</p>
     * <p>The widget field of the event should be set to the shell</p>
     * 
@param shell A SWT Shell
     * 
@return The event
     
*/
    
protected Event getSWTEvent(Shell shell)
    {
        Event e 
= new Event();
        e.widget 
= shell;
        e.item 
= shell;
        
return e;
    }
}

 

posted on 2009-05-13 11:24  Phinecos(洞庭散人)  阅读(1367)  评论(1编辑  收藏  举报

导航