org.eclipse.wb.internal.swing.preferences.laf.LafPreferencePage.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.wb.internal.swing.preferences.laf.LafPreferencePage.java

Source

/*******************************************************************************
 * Copyright (c) 2011 Google, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Google, Inc. - initial API and implementation
 *******************************************************************************/
package org.eclipse.wb.internal.swing.preferences.laf;

import com.google.common.collect.Lists;

import org.eclipse.wb.internal.core.DesignerPlugin;
import org.eclipse.wb.internal.core.utils.GenericsUtils;
import org.eclipse.wb.internal.core.utils.check.Assert;
import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
import org.eclipse.wb.internal.core.utils.ui.GridDataFactory;
import org.eclipse.wb.internal.core.utils.ui.GridLayoutFactory;
import org.eclipse.wb.internal.swing.Activator;
import org.eclipse.wb.internal.swing.ToolkitProvider;
import org.eclipse.wb.internal.swing.laf.LafSupport;
import org.eclipse.wb.internal.swing.laf.command.AddCategoryCommand;
import org.eclipse.wb.internal.swing.laf.command.Command;
import org.eclipse.wb.internal.swing.laf.command.MoveCategoryCommand;
import org.eclipse.wb.internal.swing.laf.command.MoveCommand;
import org.eclipse.wb.internal.swing.laf.command.RemoveCategoryCommand;
import org.eclipse.wb.internal.swing.laf.command.RemoveCommand;
import org.eclipse.wb.internal.swing.laf.command.RenameCategoryCommand;
import org.eclipse.wb.internal.swing.laf.command.SetVisibleCommand;
import org.eclipse.wb.internal.swing.laf.model.CategoryInfo;
import org.eclipse.wb.internal.swing.laf.model.LafEntryInfo;
import org.eclipse.wb.internal.swing.laf.model.LafInfo;
import org.eclipse.wb.internal.swing.laf.model.SeparatorLafInfo;
import org.eclipse.wb.internal.swing.laf.ui.AddCustomLookAndFeelDialog;
import org.eclipse.wb.internal.swing.laf.ui.EditCustomLookAndFeelDialog;
import org.eclipse.wb.internal.swing.preferences.Messages;

import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.ArrayUtils;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.text.MessageFormat;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRadioButton;
import javax.swing.JRootPane;
import javax.swing.JTextField;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;

import swingintegration.example.EmbeddedSwingComposite;

/**
 * The {@link PreferencePage} for managing Swing Look-n-Feel.
 * 
 * @author mitin_aa
 * @author scheglov_ke
 * @coverage swing.preferences.laf
 */
public class LafPreferencePage extends PreferencePage implements IWorkbenchPreferencePage, IPreferenceConstants {
    // constants
    private static final Image CATEGORY_IMAGE = Activator.getImage("info/laf/container.gif");
    private static final Image LAF_ITEM_IMAGE = Activator.getImage("info/laf/laf.png");
    // variables
    private LafInfo m_defaultLAF;
    private final LookAndFeel m_currentLookAndFeel;
    // ui variables
    private CheckboxTreeViewer m_lafTree;
    private Group m_previewGroup;
    private Button m_deleteButton;
    private Button m_applyInMainButton;
    private Button m_moveUpButton;
    private Button m_moveDownButton;
    private Button m_editButton;
    private Button m_setDefaultButton;
    // updating preview
    private boolean m_updatingPreview;
    private final Timer m_previewTimer = new Timer();
    private TimerTask m_previewTimerTask;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructor
    //
    ////////////////////////////////////////////////////////////////////////////
    public LafPreferencePage() {
        m_currentLookAndFeel = UIManager.getLookAndFeel();
        m_defaultLAF = LafSupport.getDefaultLAF();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Contents
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    protected Control createContents(Composite parent) {
        Composite container = new Composite(parent, SWT.NONE);
        GridLayoutFactory.create(container).margins(0);
        {
            m_applyInMainButton = new Button(container, SWT.CHECK);
            m_applyInMainButton.setText(Messages.LafPreferencePage_applyInMain);
            m_applyInMainButton.setSelection(getPreferenceStore().getBoolean(P_APPLY_IN_MAIN));
        }
        {
            Group lafGroup = new Group(container, SWT.NONE);
            GridDataFactory.create(lafGroup).grab().fill();
            GridLayoutFactory.create(lafGroup).columns(2);
            lafGroup.setText(Messages.LafPreferencePage_available);
            // LAF tree
            {
                m_lafTree = new CheckboxTreeViewer(lafGroup, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.VIRTUAL);
                final Tree tree = m_lafTree.getTree();
                GridDataFactory.create(tree).grab().fill();
                m_lafTree.setContentProvider(new LAFItemsContentProvider());
                m_lafTree.setLabelProvider(new LAFItemsLabelProvider());
                m_lafTree.addSelectionChangedListener(new ISelectionChangedListener() {
                    public void selectionChanged(SelectionChangedEvent event) {
                        handleLAFSelectionChanged();
                    }
                });
                m_lafTree.addDoubleClickListener(new IDoubleClickListener() {
                    public void doubleClick(DoubleClickEvent event) {
                        handleSetDefaultLAF();
                    }
                });
                m_lafTree.setInput(new Object[0]);
                refreshViewer();
                m_lafTree.addCheckStateListener(new ICheckStateListener() {
                    public void checkStateChanged(CheckStateChangedEvent event) {
                        handleChangeVisibility(event);
                    }
                });
                configureDND();
            }
            // buttons
            {
                createButtons(lafGroup);
            }
        }
        {
            m_previewGroup = new Group(container, SWT.NONE);
            GridDataFactory.create(m_previewGroup).grabH().fill();
            m_previewGroup.setText(Messages.LafPreferencePage_preview);
            m_previewGroup.setLayout(new FillLayout());
        }
        // return back LAF
        container.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                // cancel preview updating
                cancelPreviewUpdate();
                m_previewTimer.cancel();
                restoreLookAndFeel();
            }
        });
        return container;
    }

    /**
     * Creates the buttons on own composite for managing look-and-feels.
     */
    private void createButtons(Composite parent) {
        Composite buttonsComposite = new Composite(parent, SWT.NONE);
        GridDataFactory.create(buttonsComposite).grabV().fill();
        GridLayoutFactory.create(buttonsComposite).noMargins();
        //
        createButton(buttonsComposite, Messages.LafPreferencePage_addButton, new Listener() {
            public void handleEvent(Event event) {
                handleAddUserDefinedLAF();
            }
        });
        createButton(buttonsComposite, Messages.LafPreferencePage_addCategoryButton, new Listener() {
            public void handleEvent(Event event) {
                handleAddCategory();
            }
        });
        //
        createButtonSeparator(buttonsComposite);
        m_setDefaultButton = createButton(buttonsComposite, Messages.LafPreferencePage_setDefaultButton,
                new Listener() {
                    public void handleEvent(Event event) {
                        handleSetDefaultLAF();
                    }
                });
        createButtonSeparator(buttonsComposite);
        m_editButton = createButton(buttonsComposite, Messages.LafPreferencePage_editButton, new Listener() {
            public void handleEvent(Event event) {
                handleEdit();
            }
        });
        m_deleteButton = createButton(buttonsComposite, Messages.LafPreferencePage_removeButton, new Listener() {
            public void handleEvent(Event event) {
                handleDelete();
            }
        });
        //
        createButtonSeparator(buttonsComposite);
        m_moveUpButton = createButton(buttonsComposite, Messages.LafPreferencePage_upButton, new Listener() {
            public void handleEvent(Event event) {
                handleMove(-1);
            }
        });
        m_moveDownButton = createButton(buttonsComposite, Messages.LafPreferencePage_downButton, new Listener() {
            public void handleEvent(Event event) {
                handleMove(+2);
            }
        });
        //
        createButtonSeparator(buttonsComposite);
        createButton(buttonsComposite, Messages.LafPreferencePage_collapseAllButton, new Listener() {
            public void handleEvent(Event event) {
                m_lafTree.collapseAll();
            }
        });
        createButton(buttonsComposite, Messages.LafPreferencePage_expandAllButton, new Listener() {
            public void handleEvent(Event event) {
                m_lafTree.expandAll();
            }
        });
        // update buttons
        updateButtons();
    }

    /**
     * Creates {@link Button} with given text and {@link SWT#Selection} listener.
     */
    private static Button createButton(Composite parent, String text, Listener selectionListener) {
        Button button = new Button(parent, SWT.NONE);
        GridDataFactory.create(button).grabH().fillH();
        button.setText(text);
        button.addListener(SWT.Selection, selectionListener);
        return button;
    }

    /**
     * Creates separator between buttons on vertical buttons bar.
     */
    private static void createButtonSeparator(Composite parent) {
        Label separator = new Label(parent, SWT.NONE);
        GridDataFactory.create(separator).hintV(7);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    //   IWorkbenchPreferencePage
    //
    ////////////////////////////////////////////////////////////////////////////
    public void init(IWorkbench workbench) {
    }

    @Override
    public IPreferenceStore getPreferenceStore() {
        return ToolkitProvider.DESCRIPTION.getPreferences();
    }

    @Override
    public boolean performOk() {
        getPreferenceStore().setValue(P_APPLY_IN_MAIN, m_applyInMainButton.getSelection());
        getPreferenceStore().setValue(P_DEFAULT_LAF, m_defaultLAF.getID());
        // write all executed commands
        {
            for (Command command : m_commands) {
                LafSupport.commands_add(command);
            }
            LafSupport.commands_write();
            if (!m_commands.isEmpty()) {
                fireLookAndFeelsChanged();
            }
        }
        return super.performOk();
    }

    @Override
    protected void performDefaults() {
        m_applyInMainButton.setSelection(getPreferenceStore().getDefaultBoolean(P_APPLY_IN_MAIN));
        m_defaultLAF = LafSupport.getSettingsDefaultLAF();
        if (MessageDialog.openConfirm(getShell(), Messages.LafPreferencePage_removeConfirmTitle,
                Messages.LafPreferencePage_removeConfirmMessage)) {
            LafSupport.resetToDefaults();
            refreshViewer();
            fireLookAndFeelsChanged();
        }
        super.performDefaults();
    }

    /**
     * Runs the firing of listeners asynchronously, needed for dispose listeners to be fired first and
     * restore
     */
    private void fireLookAndFeelsChanged() {
        restoreLookAndFeel();
        LafSupport.fireLookAndFeelsChanged();
    }

    @Override
    public boolean performCancel() {
        LafSupport.reloadLAFList();
        return super.performCancel();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Action handling
    //
    ////////////////////////////////////////////////////////////////////////////
    private void handleAddCategory() {
        InputDialog inputDialog = new InputDialog(getShell(), Messages.LafPreferencePage_addCategoryTitle,
                Messages.LafPreferencePage_addCategoryMessage, "", null);
        if (inputDialog.open() == Window.OK) {
            commands_add(new AddCategoryCommand("category_" + System.currentTimeMillis(), inputDialog.getValue()));
        }
    }

    /**
     * Changes the visibility state.
     */
    private void handleChangeVisibility(CheckStateChangedEvent event) {
        LafEntryInfo checkedEntry = (LafEntryInfo) event.getElement();
        commands_add(new SetVisibleCommand(checkedEntry, event.getChecked()));
    }

    private void handleMove(int moveDelta) {
        m_lafTree.getTree().setRedraw(false);
        try {
            for (Object entry : getSelectedEntries()) {
                if (entry instanceof CategoryInfo) {
                    CategoryInfo category = (CategoryInfo) entry;
                    List<CategoryInfo> categories = LafSupport.getLAFCategoriesList();
                    int index = categories.indexOf(entry);
                    int targetIndex = index + moveDelta;
                    CategoryInfo nextCategory = targetIndex < categories.size()
                            ? (CategoryInfo) categories.get(targetIndex)
                            : null;
                    commands_add(new MoveCategoryCommand(category, nextCategory));
                } else if (entry instanceof LafInfo) {
                    LafInfo lafInfo = (LafInfo) entry;
                    CategoryInfo category = lafInfo.getCategory();
                    List<LafInfo> lafs = category.getLAFList();
                    int index = lafs.indexOf(lafInfo);
                    if (index + moveDelta < lafs.size()) {
                        commands_add(new MoveCommand(lafInfo, category, lafs.get(index + moveDelta)));
                    } else {
                        commands_add(new MoveCommand(lafInfo, category, null));
                    }
                }
            }
            refreshViewer();
            updateButtons();
        } finally {
            m_lafTree.getTree().setRedraw(true);
        }
    }

    /**
     * Called by pressing "default" button or double-clicking in LAF list. Marks selected LAF as
     * default.
     */
    private void handleSetDefaultLAF() {
        final LafInfo selectedLAF = getSelectedLAF();
        if (selectedLAF == null || selectedLAF instanceof SeparatorLafInfo) {
            return;
        }
        m_defaultLAF = selectedLAF;
        refreshViewer();
    }

    /**
     * Handles the selection changing in LAF table.
     * 
     * @param event
     */
    protected void handleLAFSelectionChanged() {
        // update buttons
        updateButtons();
        // update preview
        updatePreview();
    }

    /**
     * Deletes (or permanently hide) LAF and store LAF list into persistence.
     */
    @SuppressWarnings("unchecked")
    private void handleDelete() {
        List<Object> selection = getSelectedEntries();
        if (selection.contains(m_defaultLAF)) {
            MessageDialog.openWarning(getShell(), Messages.LafPreferencePage_deleteWarningTitle,
                    Messages.LafPreferencePage_deleteWarningMessage);
            // filter out default LAF
            selection = (List<Object>) CollectionUtils.select(selection, new Predicate() {
                public boolean evaluate(Object object) {
                    return object != m_defaultLAF;
                }
            });
        }
        if (!selection.isEmpty()) {
            if (MessageDialog.openConfirm(getShell(), Messages.LafPreferencePage_deleteConfirmTitle,
                    MessageFormat.format(Messages.LafPreferencePage_deleteConfirmMessage, selection.size()))) {
                for (Object entry : selection) {
                    if (entry instanceof CategoryInfo) {
                        commands_add(new RemoveCategoryCommand((CategoryInfo) entry));
                    } else if (entry instanceof LafInfo) {
                        commands_add(new RemoveCommand((LafInfo) entry));
                    }
                }
                refreshViewer();
            }
        }
    }

    /**
     * Adds user-defined LAF.
     */
    private void handleAddUserDefinedLAF() {
        CategoryInfo targetCategory = LafSupport.getCategory(LafSupport.ROOT_ID);
        {
            List<Object> selectedEntries = getSelectedEntries();
            if (!CollectionUtils.isEmpty(selectedEntries)) {
                Object entry = selectedEntries.get(0);
                if (entry instanceof CategoryInfo) {
                    targetCategory = (CategoryInfo) entry;
                } else if (entry instanceof LafInfo) {
                    targetCategory = ((LafInfo) entry).getCategory();
                }
            }
        }
        AddCustomLookAndFeelDialog dialog = new AddCustomLookAndFeelDialog(DesignerPlugin.getShell(),
                targetCategory);
        if (dialog.open() == Window.OK) {
            List<Command> commands = dialog.getCommands();
            for (Command command : commands) {
                commands_add(command);
            }
            refreshViewer();
        }
    }

    /**
     * Performs editing either of category or look-and-feel entry.
     */
    private void handleEdit() {
        Object entry = getSelectedEntries().get(0);
        if (entry instanceof CategoryInfo) {
            CategoryInfo category = (CategoryInfo) entry;
            InputDialog inputDialog = new InputDialog(getShell(), Messages.LafPreferencePage_editCategoryTitle,
                    Messages.LafPreferencePage_editCategoryMessage, category.getName(), null);
            // execute dialog
            if (inputDialog.open() == Window.OK) {
                commands_add(new RenameCategoryCommand(category, inputDialog.getValue()));
            }
        } else if (entry instanceof LafInfo) {
            LafInfo lafInfo = (LafInfo) entry;
            EditCustomLookAndFeelDialog dialog = new EditCustomLookAndFeelDialog(DesignerPlugin.getShell(),
                    lafInfo);
            // execute dialog
            if (dialog.open() == Window.OK) {
                List<Command> commands = dialog.getCommands();
                for (Command command : commands) {
                    commands_add(command);
                }
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Update UI
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Simply refreshes the LAF list viewer.
     */
    private void refreshViewer() {
        m_lafTree.refresh();
        updateVisibilityStates();
    }

    /**
     * Updates buttons basing on selection in LAF list viewer.
     */
    private void updateButtons() {
        List<Object> selection = getSelectedEntries();
        m_setDefaultButton.setEnabled(selection.size() == 1 && selection.get(0) instanceof LafInfo);
        m_editButton.setEnabled(selection.size() == 1);
        m_deleteButton.setEnabled(!selection.isEmpty());
        // move up/down
        List<CategoryInfo> categories = LafSupport.getLAFCategoriesList();
        {
            boolean upEnabled = !selection.isEmpty();
            boolean downEnabled = !selection.isEmpty();
            for (Object element : selection) {
                if (element instanceof CategoryInfo) {
                    upEnabled &= categories.indexOf(element) != 0;
                    downEnabled &= categories.indexOf(element) != categories.size() - 1;
                } else if (element instanceof LafInfo) {
                    LafInfo lafInfo = (LafInfo) element;
                    List<LafInfo> lafList = lafInfo.getCategory().getLAFList();
                    upEnabled &= lafList.indexOf(lafInfo) != 0;
                    downEnabled &= lafList.indexOf(lafInfo) != lafList.size() - 1;
                }
            }
            m_moveUpButton.setEnabled(upEnabled);
            m_moveDownButton.setEnabled(downEnabled);
        }
    }

    /**
     * Updates the LAF list checking items which has "visible" property set.
     */
    private void updateVisibilityStates() {
        List<Object> visibleElements = Lists.newArrayList();
        for (CategoryInfo category : LafSupport.getLAFCategoriesList()) {
            if (category.isVisible()) {
                visibleElements.add(category);
            }
            for (LafInfo lafInfo : category.getLAFList()) {
                if (lafInfo.isVisible()) {
                    visibleElements.add(lafInfo);
                }
            }
        }
        // update viewer
        m_lafTree.setCheckedElements(visibleElements.toArray());
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Swing LAF Preview
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Restores the {@link LookAndFeel} used before preview changed it.
     */
    private void restoreLookAndFeel() {
        ExecutionUtils.runLog(new RunnableEx() {
            public void run() throws Exception {
                UIManager.put("ClassLoader", m_currentLookAndFeel.getClass().getClassLoader());
                UIManager.setLookAndFeel(m_currentLookAndFeel);
            }
        });
    }

    /**
     * Schedules Swing LAF preview updating.
     */
    private void updatePreview() {
        cancelPreviewUpdate();
        m_previewTimerTask = new TimerTask() {
            @Override
            public void run() {
                DesignerPlugin.getStandardDisplay().syncExec(new Runnable() {
                    public void run() {
                        updatePreview0();
                    }
                });
            }
        };
        m_previewTimer.schedule(m_previewTimerTask, 200);
    }

    /**
     * Updates the Swing preview part basing on selected LAF.
     */
    private void updatePreview0() {
        if (m_updatingPreview) {
            return;
        }
        m_updatingPreview = true;
        try {
            ExecutionUtils.runLog(new RunnableEx() {
                public void run() throws Exception {
                    try {
                        m_previewGroup.getParent().setRedraw(false);
                        for (Control control : m_previewGroup.getChildren()) {
                            control.dispose();
                        }
                        LafInfo selectedLAF = getSelectedLAF();
                        if (selectedLAF == null) {
                            // nothing selected
                            return;
                        }
                        LookAndFeel lookAndFeel = selectedLAF.getLookAndFeelInstance();
                        m_previewGroup.getParent().layout(true);
                        UIManager.put("ClassLoader", lookAndFeel.getClass().getClassLoader());
                        UIManager.setLookAndFeel(lookAndFeel);
                        createPreviewArea(m_previewGroup);
                        m_previewGroup.getParent().layout(true);
                    } finally {
                        m_previewGroup.getParent().setRedraw(true);
                    }
                }
            });
        } finally {
            m_updatingPreview = false;
        }
    }

    /**
     * Cancels any pending preview updating task.
     */
    private void cancelPreviewUpdate() {
        if (m_previewTimerTask != null) {
            m_previewTimerTask.cancel();
        }
    }

    /**
     * Creates {@link EmbeddedSwingComposite} with some Swing components to show it using different
     * LAFs.
     */
    private void createPreviewArea(Group previewGroup) {
        try {
            LookAndFeel currentLookAndFeel = UIManager.getLookAndFeel();
            EmbeddedSwingComposite awtComposite = new EmbeddedSwingComposite(previewGroup, SWT.NONE) {
                @Override
                protected JComponent createSwingComponent() {
                    // create the JRootPane
                    JRootPane rootPane = new JRootPane();
                    {
                        JMenuBar menuBar = new JMenuBar();
                        rootPane.setJMenuBar(menuBar);
                        {
                            JMenu mnFile = new JMenu(Messages.LafPreferencePage_previewFile);
                            menuBar.add(mnFile);
                            {
                                JMenuItem mntmNew = new JMenuItem(Messages.LafPreferencePage_previewNew);
                                mnFile.add(mntmNew);
                            }
                            {
                                JMenuItem mntmExit = new JMenuItem(Messages.LafPreferencePage_previewExit);
                                mnFile.add(mntmExit);
                            }
                        }
                        {
                            JMenu mnView = new JMenu(Messages.LafPreferencePage_previewView);
                            menuBar.add(mnView);
                            {
                                JMenuItem mntmCommon = new JMenuItem(Messages.LafPreferencePage_previewCommon);
                                mnView.add(mntmCommon);
                            }
                        }
                    }
                    GridBagLayout gridBagLayout = new GridBagLayout();
                    gridBagLayout.columnWidths = new int[] { 0, 0, 0 };
                    gridBagLayout.rowHeights = new int[] { 0, 0, 0, 0 };
                    gridBagLayout.columnWeights = new double[] { 0.0, 0.0, 1.0E-4 };
                    gridBagLayout.rowWeights = new double[] { 0.0, 0.0, 0.0, 1.0E-4 };
                    rootPane.getContentPane().setLayout(gridBagLayout);
                    {
                        JLabel lblLabel = new JLabel(Messages.LafPreferencePage_previewLabel);
                        GridBagConstraints gbc = new GridBagConstraints();
                        gbc.insets = new Insets(0, 0, 5, 5);
                        gbc.gridx = 0;
                        gbc.gridy = 0;
                        rootPane.getContentPane().add(lblLabel, gbc);
                    }
                    {
                        JButton btnPushButton = new JButton(Messages.LafPreferencePage_previewButton);
                        GridBagConstraints gbc = new GridBagConstraints();
                        gbc.insets = new Insets(0, 0, 5, 0);
                        gbc.gridx = 1;
                        gbc.gridy = 0;
                        rootPane.getContentPane().add(btnPushButton, gbc);
                    }
                    {
                        JComboBox comboBox = new JComboBox();
                        comboBox.setModel(new DefaultComboBoxModel(new String[] {
                                Messages.LafPreferencePage_previewCombo, "ComboBox Item 1", "ComboBox Item 2" }));
                        GridBagConstraints gbc = new GridBagConstraints();
                        gbc.insets = new Insets(0, 0, 5, 5);
                        gbc.fill = GridBagConstraints.HORIZONTAL;
                        gbc.gridx = 0;
                        gbc.gridy = 1;
                        rootPane.getContentPane().add(comboBox, gbc);
                    }
                    {
                        JRadioButton rdbtnRadioButton = new JRadioButton(Messages.LafPreferencePage_previewRadio);
                        GridBagConstraints gbc = new GridBagConstraints();
                        gbc.insets = new Insets(0, 0, 5, 0);
                        gbc.gridx = 1;
                        gbc.gridy = 1;
                        rootPane.getContentPane().add(rdbtnRadioButton, gbc);
                    }
                    {
                        JCheckBox chckbxCheckbox = new JCheckBox(Messages.LafPreferencePage_previewCheck);
                        GridBagConstraints gbc = new GridBagConstraints();
                        gbc.insets = new Insets(0, 0, 0, 5);
                        gbc.gridx = 0;
                        gbc.gridy = 2;
                        rootPane.getContentPane().add(chckbxCheckbox, gbc);
                    }
                    {
                        JTextField textField = new JTextField();
                        textField.setText(Messages.LafPreferencePage_previewTextField);
                        GridBagConstraints gbc = new GridBagConstraints();
                        gbc.fill = GridBagConstraints.HORIZONTAL;
                        gbc.gridx = 1;
                        gbc.gridy = 2;
                        rootPane.getContentPane().add(textField, gbc);
                    }
                    return rootPane;
                }
            };
            awtComposite.populate();
            // restore current laf
            UIManager.put("ClassLoader", currentLookAndFeel.getClass().getClassLoader());
            UIManager.setLookAndFeel(currentLookAndFeel);
        } catch (Throwable e) {
            DesignerPlugin.log(e);
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Commands
    //
    ////////////////////////////////////////////////////////////////////////////
    private final List<Command> m_commands = Lists.newArrayList();

    /**
     * Executes new {@link Command} and updates {@link #m_viewer} accordingly.
     */
    private void commands_add(Command command) {
        command.execute();
        command.addToCommandList(m_commands);
        refreshViewer();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // DND
    //
    ////////////////////////////////////////////////////////////////////////////
    private List<Object> m_dragEntries;
    private boolean m_dragCategory;

    /**
     * Configures DND for LAF list viewer.
     */
    private void configureDND() {
        Transfer[] transfers = new Transfer[] { LookAndFeelTransfer.INSTANCE };
        m_lafTree.addDragSupport(DND.DROP_MOVE, transfers, new DragSourceListener() {
            public void dragStart(DragSourceEvent event) {
                m_dragEntries = getSelectedEntries();
                m_dragCategory = m_dragEntries.get(0) instanceof CategoryInfo;
                // check that we drag only categories or only entries
                for (Object element : m_dragEntries) {
                    if (m_dragCategory != element instanceof CategoryInfo) {
                        event.doit = false;
                    }
                }
            }

            public void dragSetData(DragSourceEvent event) {
            }

            public void dragFinished(DragSourceEvent event) {
            }
        });
        ViewerDropAdapter dropAdapter = new ViewerDropAdapter(m_lafTree) {
            @Override
            protected int determineLocation(DropTargetEvent event) {
                if (event.item instanceof Item) {
                    Item item = (Item) event.item;
                    Point coordinates = m_lafTree.getControl().toControl(event.x, event.y);
                    Rectangle bounds = getBounds(item);
                    // when dragging LAF entry relation with category can be only ON
                    if (!m_dragCategory && determineTarget(event) instanceof CategoryInfo) {
                        return LOCATION_ON;
                    }
                    // in all other cases, drop before/after
                    return coordinates.y < bounds.y + bounds.height / 2 ? LOCATION_BEFORE : LOCATION_AFTER;
                }
                return LOCATION_NONE;
            }

            @Override
            public boolean validateDrop(Object target, int operation, TransferData transferType) {
                // category can be dragged only relative other category
                if (m_dragCategory) {
                    return target instanceof CategoryInfo;
                }
                // all other cases are valid
                return true;
            }

            @Override
            public boolean performDrop(Object data) {
                Object target = getCurrentTarget();
                int location = getCurrentLocation();
                if (m_dragCategory) {
                    Assert.instanceOf(CategoryInfo.class, target);
                    Assert.isTrue(location == LOCATION_BEFORE || location == LOCATION_AFTER);
                    // prepare next category
                    CategoryInfo nextCategory;
                    {
                        List<CategoryInfo> categories = LafSupport.getLAFCategoriesList();
                        int index = categories.indexOf(target);
                        if (location == LOCATION_BEFORE) {
                            nextCategory = categories.get(index);
                        } else {
                            nextCategory = GenericsUtils.getNextOrNull(categories, index);
                        }
                    }
                    // add commands
                    for (Object element : m_dragEntries) {
                        CategoryInfo category = (CategoryInfo) element;
                        commands_add(new MoveCategoryCommand(category, nextCategory));
                    }
                } else if (target instanceof CategoryInfo) {
                    Assert.isTrue(location == LOCATION_ON);
                    CategoryInfo targetCategory = (CategoryInfo) target;
                    for (Object entry : m_dragEntries) {
                        commands_add(new MoveCommand((LafInfo) entry, targetCategory, null));
                    }
                } else {
                    LafInfo targetLAF = (LafInfo) target;
                    CategoryInfo targetCategory = targetLAF.getCategory();
                    // prepare next LAF
                    LafInfo nextLAF;
                    {
                        List<LafInfo> entries = targetCategory.getLAFList();
                        int index = entries.indexOf(targetLAF);
                        if (location == LOCATION_BEFORE) {
                            nextLAF = entries.get(index);
                        } else {
                            nextLAF = GenericsUtils.getNextOrNull(entries, index);
                        }
                    }
                    // add commands
                    for (Object entry : m_dragEntries) {
                        commands_add(new MoveCommand((LafInfo) entry, targetCategory, nextLAF));
                    }
                }
                // refresh viewer to show result of applying commands
                refreshViewer();
                return true;
            }
        };
        dropAdapter.setScrollExpandEnabled(false);
        m_lafTree.addDropSupport(DND.DROP_MOVE, transfers, dropAdapter);
    }

    /**
     * Implementation of {@link ByteArrayTransfer} for LAF entries.
     * 
     * @author mitin_aa
     */
    private static final class LookAndFeelTransfer extends ByteArrayTransfer {
        public static LookAndFeelTransfer INSTANCE = new LookAndFeelTransfer();
        private static final String TYPE_NAME = "__WBP_LookAndFeel_Tranfser";
        private static final int TYPE_ID = registerType(TYPE_NAME);

        ////////////////////////////////////////////////////////////////////////////
        //
        // Constructor
        //
        ////////////////////////////////////////////////////////////////////////////
        private LookAndFeelTransfer() {
        }

        ////////////////////////////////////////////////////////////////////////////
        //
        // Transfer
        //
        ////////////////////////////////////////////////////////////////////////////
        @Override
        protected int[] getTypeIds() {
            return new int[] { TYPE_ID };
        }

        @Override
        protected String[] getTypeNames() {
            return new String[] { TYPE_NAME };
        }

        @Override
        protected void javaToNative(Object object, TransferData transferData) {
        }

        @Override
        protected Object nativeToJava(TransferData transferData) {
            return ArrayUtils.EMPTY_BYTE_ARRAY;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Utils/Misc
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * @return the currently selected {@link LafInfo} from LAF table or <code>null</code> if nothing
     *         or separator selected.
     */
    private LafInfo getSelectedLAF() {
        IStructuredSelection selection = (IStructuredSelection) m_lafTree.getSelection();
        if (selection == null) {
            return null;
        }
        Object firstElement = selection.getFirstElement();
        return firstElement instanceof LafInfo && !(firstElement instanceof SeparatorLafInfo)
                ? (LafInfo) firstElement
                : null;
    }

    /**
     * @return the {@link List} of anything selectes in LAF list viewer.
     */
    @SuppressWarnings("unchecked")
    private List<Object> getSelectedEntries() {
        IStructuredSelection selection = (IStructuredSelection) m_lafTree.getSelection();
        return selection.toList();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Content/LabelProvider for LAF list
    //
    ////////////////////////////////////////////////////////////////////////////
    private final class LAFItemsLabelProvider extends LabelProvider {
        ////////////////////////////////////////////////////////////////////////////
        //
        // LabelProvider
        //
        ////////////////////////////////////////////////////////////////////////////
        @Override
        public String getText(Object element) {
            LafEntryInfo laf = (LafEntryInfo) element;
            String name = laf.getName();
            boolean isDefault = m_defaultLAF != null && laf.getID().equals(m_defaultLAF.getID())
                    && name.equals(m_defaultLAF.getName());
            return isDefault ? name + " [default]" : name;
        }

        @Override
        public Image getImage(Object element) {
            if (element instanceof CategoryInfo) {
                return CATEGORY_IMAGE;
            }
            return LAF_ITEM_IMAGE;
        }
    }

    /**
     * Content provider for LAF list.
     * 
     * @author mitin_aa
     */
    private static class LAFItemsContentProvider implements ITreeContentProvider {
        @SuppressWarnings("unchecked")
        public Object[] getElements(Object inputElement) {
            List<Object> resultList = Lists.newArrayList();
            for (CategoryInfo category : LafSupport.getLAFCategoriesList()) {
                if (LafSupport.isRootCategory(category)) {
                    resultList.addAll(category.getLAFList());
                } else {
                    resultList.add(category);
                }
            }
            // filter out SeparatorLAFInfo
            resultList = (List<Object>) CollectionUtils.select(resultList, new Predicate() {
                public boolean evaluate(Object object) {
                    return !(object instanceof SeparatorLafInfo);
                }
            });
            return resultList.toArray(new Object[resultList.size()]);
        }

        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof CategoryInfo) {
                CategoryInfo category = (CategoryInfo) parentElement;
                return LafSupport.isRootCategory(category) ? ArrayUtils.EMPTY_OBJECT_ARRAY
                        : category.getLAFList().toArray();
            }
            return ArrayUtils.EMPTY_OBJECT_ARRAY;
        }

        public Object getParent(Object element) {
            if (element instanceof LafInfo) {
                return ((LafInfo) element).getCategory();
            }
            return null;
        }

        public boolean hasChildren(Object element) {
            return getChildren(element).length != 0;
        }

        public void dispose() {
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }
    }
}