edu.tsinghua.lumaqq.ui.debug.Debugger.java Source code

Java tutorial

Introduction

Here is the source code for edu.tsinghua.lumaqq.ui.debug.Debugger.java

Source

/*
* LumaQQ - Java QQ Client
*
* Copyright (C) 2004 luma <stubma@163.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.tsinghua.lumaqq.ui.debug;

import static org.apache.commons.codec.digest.DigestUtils.md5;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.custom.ViewForm;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MenuAdapter;
import org.eclipse.swt.events.MenuEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;

import edu.tsinghua.lumaqq.qq.Crypter;
import edu.tsinghua.lumaqq.qq.QQ;
import edu.tsinghua.lumaqq.qq.Util;
import edu.tsinghua.lumaqq.qq.beans.QQUser;
import edu.tsinghua.lumaqq.qq.debug.BasicDebugPacket;
import edu.tsinghua.lumaqq.qq.debug.DebugSwitch;
import edu.tsinghua.lumaqq.qq.debug.FragmentDO;
import edu.tsinghua.lumaqq.qq.debug.IDebugListener;
import edu.tsinghua.lumaqq.qq.debug.IDebugObject;
import edu.tsinghua.lumaqq.qq.debug.InitialArgument;
import edu.tsinghua.lumaqq.qq.debug._03DebugPacket;
import edu.tsinghua.lumaqq.qq.debug._05DebugPacket;
import edu.tsinghua.lumaqq.qq.net.IConnection;
import edu.tsinghua.lumaqq.qq.packets.PacketHelper;
import edu.tsinghua.lumaqq.qq.packets.PacketParseException;
import edu.tsinghua.lumaqq.qq.packets.in.LoginReplyPacket;
import edu.tsinghua.lumaqq.qq.packets.in.GetKeyReplyPacket;
import edu.tsinghua.lumaqq.resource.Resources;
import edu.tsinghua.lumaqq.ui.MainShell;
import edu.tsinghua.lumaqq.ui.helper.UITool;
import edu.tsinghua.lumaqq.ui.provider.ListContentProvider;

/**
 * <pre>
 * ??????????
 * ?input??????
 * DebugSwitch??
 * </pre>
 * 
 * @author luma
 */
public class Debugger extends ApplicationWindow implements IDebugListener {
    /**
     * ??
     * 
     * @author luma
     */
    private class PacketNameCellModifier implements ICellModifier {
        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ICellModifier#canModify(java.lang.Object, java.lang.String)
         */
        public boolean canModify(Object element, String property) {
            return Debugger.NAME.equals(property);
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ICellModifier#getValue(java.lang.Object, java.lang.String)
         */
        public Object getValue(Object element, String property) {
            IDebugObject obj = (IDebugObject) element;

            if (Debugger.NAME.equals(property))
                return obj.getName();
            else
                return null;
        }

        /* (non-Javadoc)
         * @see org.eclipse.jface.viewers.ICellModifier#modify(java.lang.Object, java.lang.String, java.lang.Object)
         */
        public void modify(Object element, String property, Object value) {
            IDebugObject obj = (IDebugObject) ((TableItem) element).getData();

            if (Debugger.NAME.equals(property)) {
                obj.setName((String) value);
                packetViewer.refresh(obj);
            }
        }
    }

    /**
     * <pre>
     * ??UI??UI
     * </pre>
     * 
     * @author luma
     */
    private class AddPacketRunnable implements Runnable {
        public IDebugObject obj;

        /* (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        public void run() {
            packets.add(obj);
            if (!packetViewer.getControl().isDisposed())
                packetViewer.refresh();
        }
    }

    private Display display;

    // ??
    private boolean debug;

    private Font font;
    private Resources res;
    private AddPacketRunnable addPacketRunnable;
    private MainShell main;
    private QQUser user;
    private PacketHelper packetHelper;

    private StyledText textBytes, textInput;
    private Text textSend;
    private TableViewer packetViewer;
    private List<IDebugObject> packets;
    private CTabFolder viewFolder;

    private static Crypter crypter = new Crypter();
    protected static final String NAME = "name";

    private Menu packetMenu, textMenu, decryptMenu, encryptMenu, parseMenu, sendMenu;
    private ToolItem tiParse, tiDecrypt;

    private Button chkBodyOnly;
    private Label lblSelection;

    private ToolItem tiInputArg;

    private ToolItem tiEncrypt;

    /**
     * @param main
     *       MainShell, null?
     */
    public Debugger(MainShell main) {
        super(null);
        this.main = main;
        if (main != null)
            user = main.getClient().getUser();
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.window.ApplicationWindow#configureShell(org.eclipse.swt.widgets.Shell)
     */
    protected void configureShell(Shell shell) {
        initializeVariables(shell);
        shell.setText("Debugger 2006");
        shell.setImage(res.getImage(Resources.icoDebug));
        shell.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                font.dispose();
            }
        });
        setBlockOnOpen(main == null);
        if (main != null) {
            final ShellListener sl = new ShellAdapter() {
                @Override
                public void shellClosed(ShellEvent e) {
                    close();
                }
            };
            main.getShell().addShellListener(sl);
            shell.addShellListener(new ShellAdapter() {
                @Override
                public void shellClosed(ShellEvent e) {
                    main.getShell().removeShellListener(sl);
                }
            });
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.window.Window#handleShellCloseEvent()
     */
    protected void handleShellCloseEvent() {
        disableDebug();
        super.handleShellCloseEvent();
    }

    /**
     * ?
     */
    private void disableDebug() {
        DebugSwitch ds = DebugSwitch.getInstance();
        ds.removeDebugListener(this);
        setDebug(false);
        tiInputArg.setText("Start Debug");
    }

    /**
     * ?
     */
    private void enableDebug() {
        DebugSwitch ds = DebugSwitch.getInstance();
        ds.addDebugListener(this);
        setDebug(true);
        tiInputArg.setText("Stop Debug");
    }

    /**
     * ???????
     * 
     * @param e
     *          
     */
    private void switchDebugMode() {
        /* ? */
        if (debug)
            disableDebug();
        else
            enableDebug();
    }

    /**
     * ???
     */
    private void initMenu() {
        initPacketMenu();
        initTextMenu();
        initDecryptMenu();
        initParseMenu();
        initSendMenu();
        initEncryptMenu();
    }

    /**
     * 
     * 
     * @param key
     */
    private void encryptInput(byte[] key) {
        byte[] b = Util.convertHexStringToByte(textInput.getText());
        if (b == null)
            b = Util.getBytes(textInput.getText());
        if (b == null)
            return;

        b = crypter.encrypt(b, key);
        textInput.append(System.getProperty("line.separator"));
        textInput.append(Util.convertByteToHexString(b));
    }

    private void initEncryptMenu() {
        MenuItem mi;
        // ??
        encryptMenu = new Menu(getShell());
        // ?
        final MenuItem miSessionKey = new MenuItem(encryptMenu, SWT.PUSH);
        miSessionKey.setText("Encrypt with Session Key");
        miSessionKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getSessionKey());
            }
        });
        // ?
        final MenuItem miPasswordKey = new MenuItem(encryptMenu, SWT.PUSH);
        miPasswordKey.setText("Encrypt with Password Key");
        miPasswordKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getPasswordKey());
            }
        });
        // ?
        final MenuItem miFileSessionKey = new MenuItem(encryptMenu, SWT.PUSH);
        miFileSessionKey.setText("Encrypt with File Session Key");
        miFileSessionKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getFileSessionKey());
            }
        });
        // QQ?
        final MenuItem miInitKey = new MenuItem(encryptMenu, SWT.PUSH);
        miInitKey.setText("Encrypt with QQ Initial Key");
        miInitKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getInitKey());
            }
        });
        // 
        final MenuItem miAgentKey = new MenuItem(encryptMenu, SWT.PUSH);
        miAgentKey.setText("Encrypt with File Agent Key");
        miAgentKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getFileAgentKey());
            }
        });
        // 03
        final MenuItem mi03Key = new MenuItem(encryptMenu, SWT.PUSH);
        mi03Key.setText("Encrypt with Unknown Key 03");
        mi03Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getUnknown03Key());
            }
        });
        // 06
        final MenuItem mi06Key = new MenuItem(encryptMenu, SWT.PUSH);
        mi06Key.setText("Encrypt with Unknown Key 06");
        mi06Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getUnknown06Key());
            }
        });
        // 07
        final MenuItem mi07Key = new MenuItem(encryptMenu, SWT.PUSH);
        mi07Key.setText("Encrypt with Unknown Key 07");
        mi07Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getUnknown07Key());
            }
        });
        // 08
        final MenuItem mi08Key = new MenuItem(encryptMenu, SWT.PUSH);
        mi08Key.setText("Encrypt with Unknown Key 08");
        mi08Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                encryptInput(user.getUnknown08Key());
            }
        });
        // ?
        mi = new MenuItem(encryptMenu, SWT.PUSH);
        mi.setText("Encrypt with User Input Key...");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String s = getInput("Input a KEY and the content of the input textbox will be decrypted with it");
                if (s == null)
                    showMessage("Your input is invalid!");
                else {
                    byte[] key = Util.convertHexStringToByte(s);
                    if (key == null || key.length != QQ.QQ_LENGTH_KEY)
                        showMessage("The key is invalid!");
                    else
                        encryptInput(key);
                }
            }
        });
        // ??
        mi = new MenuItem(encryptMenu, SWT.PUSH);
        mi.setText("Encrypt with Key of User Input Password...");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String s = getInput(
                        "Input a password and the content of the input textbox will be decrypted with its password key");
                if (s == null)
                    showMessage("Your input is empty");
                else {
                    byte[] key = md5(md5(s.getBytes()));
                    encryptInput(key);
                }
            }
        });
        // ??
        encryptMenu.addMenuListener(new MenuAdapter() {
            @Override
            public void menuShown(MenuEvent e) {
                boolean userNull = user == null;
                miAgentKey.setEnabled(!userNull && user.getFileAgentKey() != null);
                mi03Key.setEnabled(!userNull && user.getUnknown03Key() != null);
                mi06Key.setEnabled(!userNull && user.getUnknown06Key() != null);
                mi07Key.setEnabled(!userNull && user.getUnknown07Key() != null);
                mi08Key.setEnabled(!userNull && user.getUnknown08Key() != null);
                miInitKey.setEnabled(main != null);
                miFileSessionKey.setEnabled(!userNull && user.getFileSessionKey() != null);
                miSessionKey.setEnabled(!userNull && user.getSessionKey() != null);
                miPasswordKey.setEnabled(!userNull && user.getPasswordKey() != null);
            }
        });
    }

    private void initPacketMenu() {
        /* ??? */
        final Table packetTable = packetViewer.getTable();
        packetMenu = new Menu(packetTable);
        // 
        MenuItem mi = new MenuItem(packetMenu, SWT.PUSH);
        mi.setText("Remove");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                int[] index = packetTable.getSelectionIndices();
                for (int i = index.length - 1; i >= 0; i--)
                    removeDebugObject(index[i]);
            }
        });
        // 
        mi = new MenuItem(packetMenu, SWT.PUSH);
        mi.setText("Remove All");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                removeAllPackets();
            }
        });

        // ??
        packetMenu.addMenuListener(new MenuAdapter() {
            public void menuShown(MenuEvent e) {
                packetMenu.getItem(0).setEnabled(packetTable.getSelectionIndex() != -1);
                packetMenu.getItem(1).setEnabled(packetTable.getItemCount() > 0);
            }
        });
    }

    private void initTextMenu() {
        MenuItem mi;
        // body????
        textMenu = new Menu(getShell());
        // copy
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Copy");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                byte[] b = Util.convertHexStringToByte(getSelectionText());
                if (b != null) {
                    Clipboard clipboard = new Clipboard(display);
                    clipboard.setContents(new Object[] { textBytes.getSelectionText() },
                            new Transfer[] { TextTransfer.getInstance() });
                    clipboard.dispose();
                }
            }
        });
        // copy as string
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Copy As String");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                byte[] b = Util.convertHexStringToByte(getSelectionText());
                if (b != null) {
                    Clipboard clipboard = new Clipboard(display);
                    clipboard.setContents(new Object[] { Util.getString(b) },
                            new Transfer[] { TextTransfer.getInstance() });
                    clipboard.dispose();
                }
            }
        });
        // separator
        mi = new MenuItem(textMenu, SWT.SEPARATOR);
        // As Text
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Show as Text");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                byte[] b = Util.convertHexStringToByte(getSelectionText());
                if (b != null) {
                    String msg = Util.getString(b);
                    showMessage(msg);
                }
            }
        });
        // get ip
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Show as IP");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                StringTokenizer st = new StringTokenizer(getSelectionText(), " ");
                int len = st.countTokens();
                if (len != 4)
                    showWarning("To show an IP, you should selected 4 bytes.");
                else {
                    byte[] ip = Util.convertHexStringToByte(getSelectionText());
                    showMessage(edu.tsinghua.lumaqq.qq.Util.getIpStringFromBytes(ip));
                }
            }
        });
        // get port
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Show as Port");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                StringTokenizer st = new StringTokenizer(getSelectionText(), " ");
                int len = st.countTokens();
                if (len != 2)
                    showWarning("To show a port, you should selected 2 bytes.");
                else {
                    byte[] ip = Util.convertHexStringToByte(getSelectionText());
                    int port = (ip[0] << 8) & 0xFF00 | ip[1] & 0xFF;
                    showMessage(String.valueOf(port));
                }
            }
        });
        // get integer
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Show as Integer");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                StringTokenizer st = new StringTokenizer(getSelectionText(), " ");
                int len = st.countTokens();
                if (len > 4)
                    showWarning("To show a integer, you should selected no more than 4 bytes.");
                else {
                    String s = getSelectionText().replaceAll(" ", "");
                    int i = Util.getInt(s, 16, 0);
                    showMessage(String.valueOf(i));
                }
            }
        });
        // get long
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Show as Long");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                StringTokenizer st = new StringTokenizer(getSelectionText(), " ");
                int len = st.countTokens();
                if (len > 8)
                    showWarning("To show a integer, you should selected no more than 8 bytes.");
                else {
                    String s = getSelectionText().replaceAll(" ", "");
                    long l = Util.getLong(s, 16, 0);
                    showMessage(String.valueOf(l));
                }
            }
        });
        // get time
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Show as Time");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                StringTokenizer st = new StringTokenizer(getSelectionText(), " ");
                int len = st.countTokens();
                if (len > 4)
                    showWarning("To show a integer, you should selected no more than 4 bytes.");
                else {
                    String s = getSelectionText().replaceAll(" ", "");
                    long t = Util.getLong(s, 16, 0) * 1000L;
                    showMessage(new Date(t).toString());
                }
            }
        });
        // separator
        mi = new MenuItem(textMenu, SWT.SEPARATOR);
        // Go to
        mi = new MenuItem(textMenu, SWT.PUSH);
        mi.setText("Go To...");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String s = getInput("Which byte you want to locate");
                if (s == null)
                    showWarning("You Should Input a Integer");
                else {
                    int index = Util.getInt(s, -1);
                    if (index == -1)
                        return;
                    textBytes.setSelection(index * 3, index * 3 + 2);
                }
            }
        });
        // menu listener
        textMenu.addMenuListener(new MenuAdapter() {
            public void menuShown(MenuEvent e) {
                textMenu.getItem(0).setEnabled(getSelectionText().length() > 0);
            }
        });
    }

    private void initSendMenu() {
        MenuItem mi;
        // ????
        if (main != null) {
            sendMenu = new Menu(getShell());
            // ?????
            mi = new MenuItem(sendMenu, SWT.PUSH);
            mi.setText("As Basic Family");
            mi.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    char command = inputCommand();
                    if (command == QQ.QQ_CMD_UNKNOWN)
                        return;
                    byte[] b = Util.convertHexStringToByte(textSend.getText().trim());
                    if (b == null)
                        showWarning("The content you input can't parsed as a byte array");
                    else {
                        BasicDebugPacket packet = new BasicDebugPacket(command, user);
                        packet.setBody(b);
                        main.getClient().sendPacket(packet);
                    }
                }
            });
            // Advanced...
            mi = new MenuItem(sendMenu, SWT.PUSH);
            mi.setText("Advanced...");
            mi.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    PortDialog dialog = new PortDialog(getShell(), main.getClient());
                    if (dialog.open() == IDialogConstants.OK_ID) {
                        String id = dialog.getConnectionId();
                        IConnection con = main.getClient().getConnectionPool().getConnection(id);
                        if (con == null)
                            return;
                        int family = dialog.getSelectedFamily();
                        if (family == 0)
                            return;

                        char command = inputCommand();
                        if (command == QQ.QQ_CMD_UNKNOWN)
                            return;
                        byte[] b = Util.convertHexStringToByte(textSend.getText().trim());
                        if (b == null)
                            showWarning("The content you input can't parsed as a byte array");
                        else {
                            switch (family) {
                            case QQ.QQ_PROTOCOL_FAMILY_BASIC:
                                BasicDebugPacket packet = new BasicDebugPacket(command, user);
                                packet.setBody(b);
                                main.getClient().sendPacket(packet, id);
                                break;
                            case QQ.QQ_PROTOCOL_FAMILY_03:
                                _03DebugPacket _03packet = new _03DebugPacket(command, user);
                                _03packet.setBody(b);
                                main.getClient().sendPacket(_03packet, id);
                                break;
                            case QQ.QQ_PROTOCOL_FAMILY_05:
                                _05DebugPacket _05packet = new _05DebugPacket(command, user);
                                _05packet.setBody(b);
                                main.getClient().sendPacket(_05packet, id);
                                break;
                            }
                        }
                    }
                }
            });
        }
    }

    private void initParseMenu() {
        MenuItem mi;
        // ???
        parseMenu = new Menu(getShell());
        // ?
        mi = new MenuItem(parseMenu, SWT.PUSH);
        mi.setText("Incoming Packet");
        mi.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                byte[] b = Util.convertHexStringToByte(textInput.getText());
                if (b == null) {
                    showError("Parse packet error!");
                } else {
                    ByteBuffer buf = ByteBuffer.wrap(b);
                    try {
                        if (packetHelper.parseIn(QQ.QQ_PROTOCOL_ALL, buf, user, true) == null)
                            showError("Parse packet error!");
                    } catch (PacketParseException e1) {
                        showError("Parse packet error!");
                    }
                }
            }
        });
        // ?
        mi = new MenuItem(parseMenu, SWT.PUSH);
        mi.setText("Outcoming Packet");
        mi.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                byte[] b = Util.convertHexStringToByte(textInput.getText());
                if (b == null) {
                    showError("Parse packet error!");
                } else {
                    ByteBuffer buf = ByteBuffer.wrap(b);
                    try {
                        if (packetHelper.parseOut(QQ.QQ_PROTOCOL_ALL, buf, user) == null)
                            showError("Parse packet error!");
                    } catch (PacketParseException e1) {
                        showError("Parse packet error!");
                    }
                }
            }
        });
    }

    private void initDecryptMenu() {
        MenuItem mi;
        // ??
        decryptMenu = new Menu(getShell());
        // ?
        final MenuItem miSessionKey = new MenuItem(decryptMenu, SWT.PUSH);
        miSessionKey.setText("Decrypt with Session Key");
        miSessionKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getSessionKey());
            }
        });
        // ?
        final MenuItem miPasswordKey = new MenuItem(decryptMenu, SWT.PUSH);
        miPasswordKey.setText("Decrpty with Password Key");
        miPasswordKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getPasswordKey());
            }
        });
        // ?
        final MenuItem miFileSessionKey = new MenuItem(decryptMenu, SWT.PUSH);
        miFileSessionKey.setText("Decrypt with File Session Key");
        miFileSessionKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getFileSessionKey());
            }
        });
        // QQ?
        final MenuItem miInitKey = new MenuItem(decryptMenu, SWT.PUSH);
        miInitKey.setText("Decrypt with QQ Initial Key");
        miInitKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getInitKey());
            }
        });
        // 
        final MenuItem miAgentKey = new MenuItem(decryptMenu, SWT.PUSH);
        miAgentKey.setText("Decrypt with File Agent Key");
        miAgentKey.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getFileAgentKey());
            }
        });
        // 03
        final MenuItem mi03Key = new MenuItem(decryptMenu, SWT.PUSH);
        mi03Key.setText("Decrypt with Unknown Key 03");
        mi03Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getUnknown03Key());
            }
        });
        // 06
        final MenuItem mi06Key = new MenuItem(decryptMenu, SWT.PUSH);
        mi06Key.setText("Decrypt with Unknown Key 06");
        mi06Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getUnknown06Key());
            }
        });
        // 07
        final MenuItem mi07Key = new MenuItem(decryptMenu, SWT.PUSH);
        mi07Key.setText("Decrypt with Unknown Key 07");
        mi07Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getUnknown07Key());
            }
        });
        // 08
        final MenuItem mi08Key = new MenuItem(decryptMenu, SWT.PUSH);
        mi08Key.setText("Decrypt with Unknown Key 08");
        mi08Key.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                decryptInput(user.getUnknown08Key());
            }
        });
        // ?
        mi = new MenuItem(decryptMenu, SWT.PUSH);
        mi.setText("Decrypt with User Input Key...");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String s = getInput("Input a KEY and the content of the input textbox will be decrypted with it");
                if (s == null)
                    showMessage("Your input is invalid!");
                else {
                    byte[] key = Util.convertHexStringToByte(s);
                    if (key == null || key.length != QQ.QQ_LENGTH_KEY)
                        showMessage("The key is invalid!");
                    else
                        decryptInput(key);
                }
            }
        });
        // ??
        mi = new MenuItem(decryptMenu, SWT.PUSH);
        mi.setText("Decrypt with Key of User Input Password...");
        mi.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                String s = getInput(
                        "Input a password and the content of the input textbox will be decrypted with its password key");
                if (s == null)
                    showMessage("Your input is empty");
                else {
                    byte[] key = md5(md5(s.getBytes()));
                    decryptInput(key);
                }
            }
        });
        // ??
        decryptMenu.addMenuListener(new MenuAdapter() {
            @Override
            public void menuShown(MenuEvent e) {
                boolean userNull = user == null;
                miAgentKey.setEnabled(!userNull && user.getFileAgentKey() != null);
                mi03Key.setEnabled(!userNull && user.getUnknown03Key() != null);
                mi06Key.setEnabled(!userNull && user.getUnknown06Key() != null);
                mi07Key.setEnabled(!userNull && user.getUnknown07Key() != null);
                mi08Key.setEnabled(!userNull && user.getUnknown08Key() != null);
                miInitKey.setEnabled(main != null);
                miFileSessionKey.setEnabled(!userNull && user.getFileSessionKey() != null);
                miSessionKey.setEnabled(!userNull && user.getSessionKey() != null);
                miPasswordKey.setEnabled(!userNull && user.getPasswordKey() != null);
            }
        });
    }

    /**
     * @return
     *       command
     */
    protected char inputCommand() {
        String s = getInput("Input the packet command in Hex");
        if (s == null)
            return QQ.QQ_CMD_UNKNOWN;
        try {
            char command = (char) Integer.parseInt(s, 16);
            return command;
        } catch (NumberFormatException e1) {
            showWarning("The command you inputed isn't correct");
            return QQ.QQ_CMD_UNKNOWN;
        }
    }

    /**
      * ???
      * 
      * @param shell
      */
    protected void initializeVariables(Shell shell) {
        display = shell.getDisplay();
        res = Resources.getInstance();
        font = new Font(display, "Courier New", 9, SWT.NORMAL);
        packets = new ArrayList<IDebugObject>();
        addPacketRunnable = new AddPacketRunnable();
    }

    /**
     * ????main
     * 
     * @param args
     *          ?
     */
    public static void main(String[] args) {
        new Debugger(null).open();
    }

    /**
     * ?
     * 
     * @param msg
     *       ??
     * @return
     *       
     */
    private String getInput(String msg) {
        InputDialog dialog = new InputDialog(getShell(), "Input", msg, null, null);
        if (dialog.open() == IDialogConstants.OK_ID)
            return dialog.getValue();
        else
            return null;
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.window.Window#createContents(org.eclipse.swt.widgets.Composite)
     */
    protected Control createContents(Composite parent) {
        parent.setLayout(new GridLayout());
        Composite control = new Composite(parent, SWT.NONE);
        GridLayout layout = new GridLayout();
        layout.marginHeight = layout.marginWidth = 0;
        control.setLayout(layout);
        control.setLayoutData(new GridData(GridData.FILL_BOTH));

        boolean individual = main == null;

        UITool.setDefaultBackground(parent.getBackground());

        layout = new GridLayout(2, false);
        layout.marginHeight = layout.marginWidth = 0;
        Composite comp = UITool.createContainer(control, new GridData(GridData.FILL_HORIZONTAL), layout);

        // 0x001D?key
        ToolBar mainTb = new ToolBar(comp, SWT.FLAT);
        ToolItem tiInputKey = new ToolItem(mainTb, SWT.PUSH);
        tiInputKey.setText("Input 0x001D Keys");
        tiInputKey.setEnabled(individual);
        tiInputKey.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                onInputKey();
            }
        });

        // ??
        tiInputArg = new ToolItem(mainTb, SWT.PUSH);
        tiInputArg.setText(individual ? "Input Initial Argument" : "Start Debug");
        tiInputArg.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                onStart();
            }
        });

        SashForm hSash = new SashForm(control, SWT.HORIZONTAL);
        hSash.setLayoutData(new GridData(GridData.FILL_BOTH));

        CTabFolder tableFolder = new CTabFolder(hSash, SWT.TOP | SWT.BORDER);
        CTabItem packetTab = new CTabItem(tableFolder, SWT.NONE);
        packetTab.setText("Packets");
        packetTab.setImage(res.getImage(Resources.icoDebugPacket));
        tableFolder.setSelection(0);
        packetViewer = new TableViewer(tableFolder, SWT.MULTI | SWT.FULL_SELECTION | SWT.V_SCROLL);
        packetViewer.setContentProvider(new ListContentProvider<IDebugObject>(packets));
        packetViewer.setLabelProvider(new DebugObjectLabelProvider());
        packetViewer.setUseHashlookup(true);
        packetViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                onPacketViewerSelectionChanged(event);
            }
        });

        Table packetTable = packetViewer.getTable();
        new TableColumn(packetTable, SWT.LEFT);
        packetTable.addControlListener(new ControlAdapter() {
            public void controlResized(ControlEvent e) {
                Table t = (Table) e.getSource();
                t.getColumn(0).setWidth(t.getClientArea().width);
            }
        });
        packetTable.addMouseListener(new MouseAdapter() {
            public void mouseUp(MouseEvent e) {
                if (e.button == 3)
                    packetMenu.setVisible(true);
            }
        });
        packetTab.setControl(packetTable);
        packetViewer.setColumnProperties(new String[] { NAME });
        packetViewer.setCellEditors(new CellEditor[] { new TextCellEditor(packetTable) });
        packetViewer.setCellModifier(new PacketNameCellModifier());
        packetViewer.setInput(this);

        viewFolder = new CTabFolder(hSash, SWT.TOP | SWT.BORDER);
        // ??
        CTabItem byteTab = new CTabItem(viewFolder, SWT.NONE);
        byteTab.setText("Bytes");
        byteTab.setImage(res.getImage(Resources.icoDebugBytes));
        ViewForm byteForm = new ViewForm(viewFolder, SWT.FLAT);
        Composite c = new Composite(byteForm, SWT.NONE);
        c.setLayout(new GridLayout(2, false));
        chkBodyOnly = new Button(c, SWT.CHECK | SWT.FLAT);
        chkBodyOnly.setText("Body Only");
        chkBodyOnly.setLayoutData(new GridData());
        chkBodyOnly.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                IStructuredSelection selection = (IStructuredSelection) packetViewer.getSelection();
                IDebugObject obj = (IDebugObject) selection.getFirstElement();
                if (obj != null)
                    textBytes.setText(chkBodyOnly.getSelection() ? obj.getBodyHexString() : obj.getHexString());
            }
        });
        lblSelection = new Label(c, SWT.LEFT);
        lblSelection.setText("Selection: null");
        GridData gd = new GridData();
        gd.widthHint = 200;
        lblSelection.setLayoutData(gd);
        byteForm.setTopLeft(c);
        textBytes = new StyledText(byteForm, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY | SWT.V_SCROLL);
        textBytes.setFont(font);
        textBytes.addMouseListener(new MouseAdapter() {
            public void mouseUp(MouseEvent e) {
                if (e.button == 3) {
                    textMenu.setLocation(textBytes.toDisplay(e.x, e.y));
                    textMenu.setVisible(true);
                }
            }
        });
        textBytes.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                Point selection = textBytes.getSelectionRange();
                int start = (selection.x + 1) / 3;
                int end = (selection.x + selection.y + 1) / 3;
                lblSelection.setText("Start: " + start + ", Length: " + (end - start) + ", Hex: "
                        + Integer.toHexString(end - start).toUpperCase());
            }
        });
        byteForm.setContent(textBytes);
        byteTab.setControl(byteForm);

        // ?
        CTabItem inputTab = new CTabItem(viewFolder, SWT.NONE);
        inputTab.setText("Input");
        inputTab.setImage(res.getImage(Resources.icoDebugInput));
        ViewForm inputForm = new ViewForm(viewFolder, SWT.FLAT);
        // viewform?
        final ToolBar tb = new ToolBar(inputForm, SWT.FLAT);
        // ?
        tiParse = new ToolItem(tb, SWT.DROP_DOWN);
        tiParse.setText("Parse as");
        tiParse.setEnabled(main != null);
        tiParse.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Rectangle rect = tiParse.getBounds();
                Point p = tb.toDisplay(rect.x, rect.y);
                p.y += rect.height;
                parseMenu.setLocation(p);
                parseMenu.setVisible(true);
            }
        });
        // ?md5
        ToolItem tiMd5 = new ToolItem(tb, SWT.PUSH);
        tiMd5.setText("MD5");
        tiMd5.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                byte[] b = Util.convertHexStringToByte(textInput.getText());
                if (b == null)
                    b = Util.getBytes(textInput.getText());
                if (b == null)
                    return;
                b = md5(b);
                textInput.append(System.getProperty("line.separator"));
                textInput.append(Util.convertByteToHexString(b));
            }
        });
        // 
        tiDecrypt = new ToolItem(tb, SWT.DROP_DOWN);
        tiDecrypt.setText("Decrypt");
        tiDecrypt.addSelectionListener(new SelectionAdapter() {
            public void widgetSelected(SelectionEvent e) {
                Rectangle rect = tiDecrypt.getBounds();
                Point p = tb.toDisplay(rect.x, rect.y);
                p.y += rect.height;
                decryptMenu.setLocation(p);
                decryptMenu.setVisible(true);
            }
        });
        tiEncrypt = new ToolItem(tb, SWT.DROP_DOWN);
        tiEncrypt.setText("Encrypt");
        tiEncrypt.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Rectangle rect = tiEncrypt.getBounds();
                Point p = tb.toDisplay(rect.x, rect.y);
                p.y += rect.height;
                encryptMenu.setLocation(p);
                encryptMenu.setVisible(true);
            }
        });
        inputForm.setTopLeft(tb);
        // 
        final Label lblInputSelection = new Label(inputForm, SWT.RIGHT);
        lblInputSelection.setText("Selection: null, Length: 0, Hex: 0");
        inputForm.setTopRight(lblInputSelection);
        textInput = new StyledText(inputForm, SWT.MULTI | SWT.WRAP | SWT.V_SCROLL);
        textInput.setFont(font);
        textInput.addModifyListener(new ModifyListener() {
            public void modifyText(ModifyEvent e) {
                int start = 0;
                int end = textInput.getText().length() / 3;
                lblInputSelection.setText(
                        "Length: " + (end - start) + " Hex: " + Integer.toHexString(end - start).toUpperCase());
            }
        });
        textInput.addMouseListener(new MouseAdapter() {
            public void mouseUp(MouseEvent e) {
                if (e.button == 3) {
                    textMenu.setLocation(textInput.toDisplay(e.x, e.y));
                    textMenu.setVisible(true);
                }
            }
        });
        inputForm.setContent(textInput);
        inputTab.setControl(inputForm);

        // ???
        if (!individual) {
            CTabItem sendTab = new CTabItem(viewFolder, SWT.NONE);
            sendTab.setText("Send");
            sendTab.setImage(res.getImage(Resources.icoDebugSend));
            ViewForm sendForm = new ViewForm(viewFolder, SWT.FLAT);
            sendTab.setControl(sendForm);

            final ToolBar sendBar = new ToolBar(sendForm, SWT.FLAT);
            final ToolItem tiSend = new ToolItem(sendBar, SWT.DROP_DOWN);
            tiSend.setText("Send");
            tiSend.addSelectionListener(new SelectionAdapter() {
                public void widgetSelected(SelectionEvent e) {
                    Rectangle rect = tiSend.getBounds();
                    Point p = sendBar.toDisplay(rect.x, rect.y);
                    p.y += rect.height;
                    sendMenu.setLocation(p);
                    sendMenu.setVisible(true);
                }
            });
            sendForm.setTopLeft(sendBar);

            textSend = new Text(sendForm, SWT.MULTI | SWT.V_SCROLL | SWT.WRAP);
            textSend.setFont(font);
            sendForm.setContent(textSend);
        }

        viewFolder.setSelection(0);

        hSash.setWeights(new int[] { 30, 70 });

        initMenu();
        return control;
    }

    protected void onInputKey() {
        if (user == null || packetHelper == null)
            return;

        String s = getInput("Input 0x001D reply packet");
        byte[] b = Util.convertHexStringToByte(s);
        if (b == null)
            return;
        ByteBuffer buf = ByteBuffer.wrap(b);
        try {
            GetKeyReplyPacket packet = (GetKeyReplyPacket) packetHelper.parseIn(QQ.QQ_PROTOCOL_FAMILY_BASIC, buf,
                    user, true);
            switch (packet.subCommand) {
            case QQ.QQ_SUB_CMD_REQUEST_FILE_AGENT_KEY:
                user.setFileAgentKey(packet.key);
                break;
            case QQ.QQ_SUB_CMD_REQUEST_UNKNOWN03_KEY:
                user.setUnknown03Key(packet.key);
                break;
            case QQ.QQ_SUB_CMD_REQUEST_UNKNOWN06_KEY:
                user.setUnknown06Key(packet.key);
                break;
            case QQ.QQ_SUB_CMD_REQUEST_UNKNOWN07_KEY:
                user.setUnknown07Key(packet.key);
                break;
            case QQ.QQ_SUB_CMD_REQUEST_UNKNOWN08_KEY:
                user.setUnknown08Key(packet.key);
                break;
            }
        } catch (PacketParseException e1) {
            return;
        }
    }

    /**
      * Agent?
      */
    protected void onAgent() {
        if (user == null)
            return;

        InputDialog dialog = new InputDialog(getShell(), "Agent Key", "Input File Agent Key", null, null);
        if (dialog.open() == IDialogConstants.OK_ID) {
            byte[] key = Util.convertHexStringToByte(dialog.getValue());
            user.setFileAgentKey(key);
        } else
            return;

        dialog = new InputDialog(getShell(), "Agent Token", "Input File Agent Token", null, null);
        if (dialog.open() == IDialogConstants.OK_ID) {
            byte[] token = Util.convertHexStringToByte(dialog.getValue());
            user.setFileAgentToken(token);
        }
    }

    /**
     * start
     */
    protected void onStart() {
        packetHelper = new PacketHelper(QQ.QQ_PROTOCOL_ALL);
        if (main == null) {
            if (!debug) {
                InitialArgument arg = openDialog();
                if (arg != null) {
                    if (initIndividualMode(arg)) {
                        tiInputArg.setText("User " + user.getQQ());
                        tiInputArg.getParent().layout();
                        tiParse.setEnabled(true);
                    }
                }
            }
        } else
            switchDebugMode();
    }

    /**
     * ??
     * 
     * @return
     *          DebugArgument
     */
    protected InitialArgument openDialog() {
        InitialArgumentDialog dialog = new InitialArgumentDialog(getShell());
        if (dialog.open() == IDialogConstants.OK_ID)
            return dialog.getArg();
        else
            return null;
    }

    /**
     * @param event
     */
    protected void onPacketViewerSelectionChanged(SelectionChangedEvent event) {
        IStructuredSelection selection = (IStructuredSelection) event.getSelection();
        IDebugObject obj = (IDebugObject) selection.getFirstElement();
        if (obj != null)
            textBytes.setText(chkBodyOnly.getSelection() ? obj.getBodyHexString() : obj.getHexString());
    }

    /**
     * @return
     *       ??text
     */
    private String getSelectionText() {
        if (viewFolder.getSelectionIndex() == 0)
            return textBytes.getSelectionText();
        else if (viewFolder.getSelectionIndex() == 1)
            return textInput.getSelectionText();
        else
            return "";
    }

    /**
     * ???
     * 
     * @param arg
     *          ?
     * @return true??
     */
    protected boolean initIndividualMode(InitialArgument arg) {
        try {
            // ?
            DebugSwitch.getInstance().addDebugListener(this);
            setDebug(true);

            // ???????
            user = new QQUser(arg.getQQ(), arg.getPassword());
            ByteBuffer myBuf = ByteBuffer.wrap(arg.getLoginReply());
            LoginReplyPacket lrp = (LoginReplyPacket) packetHelper.parseIn(QQ.QQ_PROTOCOL_FAMILY_BASIC, myBuf, user,
                    true);
            if (lrp == null)
                throw new PacketParseException("Error Format");
            user.setSessionKey(lrp.sessionKey);
            byte[] b = new byte[4 + QQ.QQ_LENGTH_KEY];
            b[0] = (byte) ((user.getQQ() >>> 24) & 0xFF);
            b[1] = (byte) ((user.getQQ() >>> 16) & 0xFF);
            b[2] = (byte) ((user.getQQ() >>> 8) & 0xFF);
            b[3] = (byte) (user.getQQ() & 0xFF);
            System.arraycopy(user.getSessionKey(), 0, b, 4, QQ.QQ_LENGTH_KEY);
            user.setFileSessionKey(md5(b));
            return true;
        } catch (PacketParseException e) {
            DebugSwitch.getInstance().removeDebugListener(this);
            setDebug(false);
            return false;
        }
    }

    /* (non-Javadoc)
     * @see edu.tsinghua.lumaqq.qq.debug.IDebugListener#deliverDebugObject(edu.tsinghua.lumaqq.qq.debug.IDebugObject)
     */
    public void deliverDebugObject(IDebugObject obj) {
        addDebugObject(obj);
    }

    /**
     * @return Returns the debug.
     */
    public boolean isDebug() {
        return debug;
    }

    /**
     * @param debug The debug to set.
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    private void showMessage(String msg) {
        MessageDialog.openInformation(getShell(), "Debug", msg);
    }

    private void showWarning(String msg) {
        MessageDialog.openWarning(getShell(), "Warning", msg);
    }

    private void showError(String msg) {
        MessageDialog.openError(getShell(), "Error", msg);
    }

    /**
     * DebugObject
     * 
     * @param obj
     *       IDebugObject
     */
    public void addDebugObject(IDebugObject obj) {
        addPacketRunnable.obj = obj;
        display.syncExec(addPacketRunnable);
    }

    /**
     * 
     * 
     * @param index
     */
    public void removeDebugObject(int index) {
        packets.remove(index);
        packetViewer.refresh();
    }

    /**
     * packets
     */
    public void removeAllPackets() {
        packets.clear();
        packetViewer.refresh();
    }

    /**
     * 
     * 
     * @param key
     */
    protected void decryptInput(byte[] key) {
        byte[] b = Util.convertHexStringToByte(textInput.getText());
        if (b == null)
            showWarning("Can't get byte array from your input!");
        else {
            try {
                b = crypter.decrypt(b, key);
                if (b == null)
                    showWarning("Decrypt Error!");
                else
                    addDebugObject(new FragmentDO(b));
            } catch (Exception e) {
                showError(e.getMessage());
            }
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.jface.window.Window#getInitialSize()
     */
    protected Point getInitialSize() {
        return new Point(800, 600);
    }
}