net.sf.eclipsensis.wizard.NSISWizardContentsPage.java Source code

Java tutorial

Introduction

Here is the source code for net.sf.eclipsensis.wizard.NSISWizardContentsPage.java

Source

/*******************************************************************************
 * Copyright (c) 2004-2010 Sunil Kamath (IcemanK).
 * All rights reserved.
 * This program is made available under the terms of the Common Public License
 * v1.0 which is available at http://www.eclipse.org/legal/cpl-v10.html
 *
 * Contributors:
 *     Sunil Kamath (IcemanK) - initial API and implementation
 *******************************************************************************/
package net.sf.eclipsensis.wizard;

import java.beans.*;
import java.text.MessageFormat;
import java.util.*;
import java.util.List;

import net.sf.eclipsensis.*;
import net.sf.eclipsensis.util.*;
import net.sf.eclipsensis.util.winapi.WinAPI;
import net.sf.eclipsensis.viewer.StructuredViewerUpDownMover;
import net.sf.eclipsensis.wizard.settings.*;
import net.sf.eclipsensis.wizard.util.NSISWizardDialogUtil;

import org.eclipse.jface.dialogs.*;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;

public class NSISWizardContentsPage extends AbstractNSISWizardPage implements INSISConstants {
    public static final String NAME = "nsisWizardContents"; //$NON-NLS-1$

    private static final int[] cDeleteConfirmButtonIds = { IDialogConstants.YES_ID, IDialogConstants.YES_TO_ALL_ID,
            IDialogConstants.NO_ID, IDialogConstants.NO_TO_ALL_ID };

    private static final String cDeleteConfirmTitle = EclipseNSISPlugin
            .getResourceString("delete.confirmation.title"); //$NON-NLS-1$

    private static final String cDeleteConfirmMessageFormat = EclipseNSISPlugin
            .getResourceString("delete.confirmation.message"); //$NON-NLS-1$

    private TreeViewer mContentsTreeViewer;

    /**
     * @param pageName
     * @param title
     */
    public NSISWizardContentsPage() {
        super(NAME, EclipseNSISPlugin.getResourceString("wizard.contents.title"), //$NON-NLS-1$
                EclipseNSISPlugin.getResourceString("wizard.contents.description")); //$NON-NLS-1$
    }

    @Override
    protected boolean hasRequiredFields() {
        return false;
    }

    @Override
    protected String getHelpContextId() {
        return INSISConstants.PLUGIN_CONTEXT_PREFIX + "nsis_wizcontents_context"; //$NON-NLS-1$
    }

    public void refresh() {
        if (mContentsTreeViewer != null) {
            mContentsTreeViewer.refresh();
        }
    }

    @Override
    protected Control createPageControl(Composite parent) {
        NSISWizardSettings settings = mWizard.getSettings();

        final Composite composite = new Composite(parent, SWT.NONE);

        final GridLayout layout = new GridLayout(1, false);
        composite.setLayout(layout);

        ResourceBundle bundle = EclipseNSISPlugin.getDefault().getResourceBundle();

        Label contentsLabel = NSISWizardDialogUtil.createLabel(composite, "wizard.contents.text", true, null, //$NON-NLS-1$
                false);
        Dialog.applyDialogFont(contentsLabel);
        final GridData gridData = (GridData) contentsLabel.getLayoutData();
        gridData.widthHint = Common.calculateControlSize(contentsLabel, 80, 0).x;
        composite.addListener(SWT.Resize, new Listener() {
            boolean init = false;

            public void handleEvent(Event e) {
                if (init) {
                    Point size = composite.getSize();
                    gridData.widthHint = size.x - 2 * layout.marginWidth;
                    composite.layout();
                } else {
                    init = true;
                }
            }
        });

        Group contentsGroup = NSISWizardDialogUtil.createGroup(composite, 1, "", null, false); //$NON-NLS-1$
        GridData gd = (GridData) contentsGroup.getLayoutData();
        gd.grabExcessVerticalSpace = true;
        gd.verticalAlignment = GridData.FILL;

        final ToolBar contentsToolbar = createToolBar(contentsGroup, bundle);
        gd = new GridData(SWT.FILL, SWT.CENTER, true, false);
        gd.horizontalSpan = 1;
        contentsToolbar.setLayoutData(gd);

        final ToolItem addToolItem = contentsToolbar.getItem(0);
        final ToolItem editToolItem = contentsToolbar.getItem(1);
        final ToolItem deleteToolItem = contentsToolbar.getItem(2);

        Composite composite2 = new Composite(contentsGroup, SWT.NONE);
        gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.horizontalSpan = 1;
        composite2.setLayoutData(gd);

        GridLayout layout2 = new GridLayout(2, false);
        layout2.marginHeight = 0;
        layout2.marginWidth = 0;
        composite2.setLayout(layout2);

        final Tree contentsTree = new Tree(composite2, SWT.MULTI | SWT.BORDER);
        gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.horizontalSpan = 1;
        contentsTree.setLayoutData(gd);

        updateSelectComponents();
        mContentsTreeViewer = new TreeViewer(contentsTree);
        mContentsTreeViewer.setLabelProvider(new NSISInstallElementLabelProvider());
        mContentsTreeViewer.setContentProvider(new NSISInstallElementTreeContentProvider(settings));
        mContentsTreeViewer.setAutoExpandLevel(AbstractTreeViewer.ALL_LEVELS);
        mContentsTreeViewer.setInput(settings);
        ColumnViewerToolTipSupport.enableFor(mContentsTreeViewer);

        final StructuredViewerUpDownMover<NSISWizardSettings, INSISInstallElement> mover = new StructuredViewerUpDownMover<NSISWizardSettings, INSISInstallElement>() {
            private TreeViewer mTreeViewer = null;

            @Override
            public void setViewer(StructuredViewer viewer) {
                mTreeViewer = (TreeViewer) viewer;
            }

            @Override
            public StructuredViewer getViewer() {
                return mTreeViewer;
            }

            @Override
            protected int[] getSelectedIndices() {
                List<INSISInstallElement> list = getSelectionList(mTreeViewer);
                INSISInstallElement parent = getSelectionParent(list);
                if (parent != null) {
                    List<INSISInstallElement> allElements = getAllElements(parent);
                    int[] selectedIndices = new int[list.size()];
                    int i = 0;
                    for (Iterator<INSISInstallElement> iter = list.iterator(); iter.hasNext();) {
                        selectedIndices[i++] = allElements.indexOf(iter.next());
                    }

                    return selectedIndices;
                }
                return new int[0];
            }

            private List<INSISInstallElement> getAllElements(INSISInstallElement parent) {
                if (parent != null) {
                    INSISInstallElement[] children = parent.getChildren();
                    if (!Common.isEmptyArray(children)) {
                        return Arrays.asList(children);
                    }
                }
                return Collections.<INSISInstallElement>emptyList();
            }

            @Override
            protected List<INSISInstallElement> getAllElements() {
                return getAllElements(getSelectionParent(getSelectionList(mTreeViewer)));
            }

            @Override
            protected void updateStructuredViewerInput(NSISWizardSettings input, List<INSISInstallElement> elements,
                    List<INSISInstallElement> move, boolean isDown) {
                INSISInstallElement parent = getSelectionParent(move);
                if (parent != null && parent instanceof AbstractNSISInstallGroup) {
                    parent.removeAllChildren();
                    for (Iterator<INSISInstallElement> iter = elements.iterator(); iter.hasNext();) {
                        INSISInstallElement element = iter.next();
                        parent.addChild(element);
                    }
                    mTreeViewer.refresh(parent, true);
                    expandGroup(mTreeViewer, (AbstractNSISInstallGroup) parent);
                }
            }

            /**
             * @param viewer
             */
            @Override
            protected void refreshViewer(StructuredViewer viewer, List<INSISInstallElement> elements,
                    List<INSISInstallElement> move, boolean isDown) {
            }
        };
        mover.setViewer(mContentsTreeViewer);

        Composite composite3 = new Composite(composite2, SWT.NONE);
        gd = new GridData();
        composite3.setLayoutData(gd);

        layout2 = new GridLayout();
        layout2.marginHeight = 0;
        layout2.marginWidth = 0;
        composite3.setLayout(layout2);

        final Button upButton = new Button(composite3, SWT.PUSH);
        upButton.setImage(
                EclipseNSISPlugin.getImageManager().getImage(EclipseNSISPlugin.getResourceString("up.icon"))); //$NON-NLS-1$
        upButton.setToolTipText(EclipseNSISPlugin.getResourceString("up.tooltip")); //$NON-NLS-1$
        upButton.setEnabled(mover.canMoveUp());
        upButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                mover.moveUp();
            }
        });

        final Button downButton = new Button(composite3, SWT.PUSH);
        downButton.setImage(
                EclipseNSISPlugin.getImageManager().getImage(EclipseNSISPlugin.getResourceString("down.icon"))); //$NON-NLS-1$
        downButton.setToolTipText(EclipseNSISPlugin.getResourceString("down.tooltip")); //$NON-NLS-1$
        downButton.setEnabled(mover.canMoveDown());
        downButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                mover.moveDown();
            }
        });

        mContentsTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            public void selectionChanged(SelectionChangedEvent event) {
                enableItems(event.getSelection(), addToolItem, editToolItem, deleteToolItem);
                upButton.setEnabled(mover.canMoveUp());
                downButton.setEnabled(mover.canMoveDown());
            }
        });

        mContentsTreeViewer.addTreeListener(new ITreeViewerListener() {
            public void setState(TreeExpansionEvent event, boolean state) {
                Object element = event.getElement();
                if (element instanceof AbstractNSISInstallGroup) {
                    ((AbstractNSISInstallGroup) element).setExpanded(state);
                }
            }

            public void treeCollapsed(TreeExpansionEvent event) {
                setState(event, false);
            }

            public void treeExpanded(TreeExpansionEvent event) {
                setState(event, true);
            }
        });

        configureDND(mContentsTreeViewer);

        SelectionAdapter editSelectionAdapter = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                ISelection sel = mContentsTreeViewer.getSelection();
                if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
                    Object obj = ((IStructuredSelection) sel).getFirstElement();
                    if (obj instanceof INSISInstallElement) {
                        editElement(composite, mContentsTreeViewer, (INSISInstallElement) obj);
                        updateSelectComponents();
                        checkUnselectedSections();
                    }
                }
            }
        };

        SelectionAdapter deleteSelectionAdapter = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                ISelection sel = mContentsTreeViewer.getSelection();
                if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
                    deleteElements(mContentsTreeViewer, sel);
                    updateSelectComponents();
                }
            }
        };

        final SelectionAdapter addSelectionAdapter = new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                MenuItem mi = (MenuItem) e.widget;
                String type = (String) mi.getData();
                INSISInstallElement element = NSISInstallElementFactory.create(type);
                if (element != null) {
                    try {
                        if (element.isEditable()) {
                            ISelection se = mContentsTreeViewer.getSelection();
                            if (!se.isEmpty() && se instanceof IStructuredSelection) {
                                Object obj = ((IStructuredSelection) se).getFirstElement();
                                if (obj instanceof INSISInstallElement) {
                                    INSISInstallElement parent = (INSISInstallElement) obj;
                                    if (element.edit(mWizard)) {
                                        if (parent.addChild(element)) {
                                            mContentsTreeViewer.refresh(parent, true);
                                            mContentsTreeViewer.reveal(element);
                                            if (element.hasChildren()) {
                                                mContentsTreeViewer.expandToLevel(element,
                                                        AbstractTreeViewer.ALL_LEVELS);
                                            }
                                            updateSelectComponents();
                                            setPageComplete(validatePage(VALIDATE_ALL));
                                        }
                                    }
                                }
                            }
                        }
                    } catch (Exception ex) {
                        delayedValidateAfterError(ex.getLocalizedMessage(), 2000);
                    }
                }
            }
        };

        final Menu addPopupMenu = new Menu(getShell(), SWT.POP_UP);
        addToolItem.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                Rectangle rect = addToolItem.getBounds();
                Point pt = new Point(rect.x, rect.y + rect.height);
                pt = contentsToolbar.toDisplay(pt);
                updateAddMenu(addPopupMenu, mContentsTreeViewer.getSelection(), addSelectionAdapter);
                addPopupMenu.setLocation(pt.x, pt.y);
                addPopupMenu.setVisible(true);
            }
        });
        editToolItem.addSelectionListener(editSelectionAdapter);
        deleteToolItem.addSelectionListener(deleteSelectionAdapter);
        contentsToolbar.getItem(3).addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                mContentsTreeViewer.expandAll();
            }
        });
        contentsToolbar.getItem(4).addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                mContentsTreeViewer.collapseAll();
            }
        });

        final Menu itemPopupMenu = createMenu(bundle);
        final Menu addDropdownMenu = new Menu(getShell(), SWT.DROP_DOWN);

        final MenuItem addMenuItem = itemPopupMenu.getItem(0);
        final MenuItem editMenuItem = itemPopupMenu.getItem(1);
        final MenuItem deleteMenuItem = itemPopupMenu.getItem(2);

        addMenuItem.setMenu(addDropdownMenu);
        editMenuItem.addSelectionListener(editSelectionAdapter);
        deleteMenuItem.addSelectionListener(deleteSelectionAdapter);

        contentsTree.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetDefaultSelected(SelectionEvent e) {
                ISelection sel = mContentsTreeViewer.getSelection();
                if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
                    IStructuredSelection ssel = (IStructuredSelection) sel;
                    Object obj = ssel.getFirstElement();
                    if (obj instanceof INSISInstallElement) {
                        editElement(composite, mContentsTreeViewer, (INSISInstallElement) obj);
                        updateSelectComponents();
                        checkUnselectedSections();
                    }
                }
            }
        });

        contentsTree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseUp(MouseEvent e) {
                if (e.button == 3) {
                    TreeItem ti = contentsTree.getItem(new Point(e.x, e.y));
                    if (ti != null) {
                        ISelection sel = mContentsTreeViewer.getSelection();
                        enableItems(sel, addMenuItem, editMenuItem, deleteMenuItem);
                        updateAddMenu(addDropdownMenu, sel, addSelectionAdapter);
                        Point pt = contentsTree.toDisplay(e.x, e.y);
                        itemPopupMenu.setLocation(pt.x, pt.y);
                        itemPopupMenu.setVisible(true);
                    }
                }
            }
        });

        contentsTree.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                if (e.character == SWT.DEL) {
                    if (e.stateMask == 0) {
                        ISelection sel = mContentsTreeViewer.getSelection();
                        if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
                            if (canDeleteElements((IStructuredSelection) sel)) {
                                deleteElements(mContentsTreeViewer, sel);
                                updateSelectComponents();
                            }
                        }

                    }
                }
            }
        });

        addPageChangedRunnable(new Runnable() {
            public void run() {
                checkUnselectedSections();
            }
        });

        final PropertyChangeListener propertyListener = new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent evt) {
                if (NSISWizardSettings.TARGET_PLATFORM.equals(evt.getPropertyName())) {
                    mContentsTreeViewer.refresh(true);
                }
            }
        };
        settings.addPropertyChangeListener(propertyListener);
        final INSISWizardSettingsListener listener = new INSISWizardSettingsListener() {
            public void settingsChanged(NSISWizardSettings oldSettings, final NSISWizardSettings newSettings) {
                if (oldSettings != null) {
                    oldSettings.removePropertyChangeListener(propertyListener);
                }
                mContentsTreeViewer.setInput(newSettings);
                mContentsTreeViewer.expandToLevel(newSettings.getInstaller(), AbstractTreeViewer.ALL_LEVELS);
                newSettings.addPropertyChangeListener(propertyListener);
            }
        };
        mWizard.addSettingsListener(listener);

        composite.addDisposeListener(new DisposeListener() {
            public void widgetDisposed(DisposeEvent e) {
                mWizard.removeSettingsListener(listener);
                mWizard.getSettings().removePropertyChangeListener(propertyListener);
            }
        });

        setPageComplete(validatePage(VALIDATE_ALL));

        return composite;
    }

    private void expandGroup(TreeViewer tv, AbstractNSISInstallGroup group) {
        if (tv.getExpandedState(group) != group.isExpanded()) {
            tv.setExpandedState(group, group.isExpanded());
        }
        INSISInstallElement[] children = group.getChildren();
        if (!Common.isEmptyArray(children)) {
            for (int i = 0; i < children.length; i++) {
                if (children[i] instanceof AbstractNSISInstallGroup) {
                    expandGroup(tv, (AbstractNSISInstallGroup) children[i]);
                }
            }
        }
    }

    private void configureDND(final TreeViewer tv) {
        Transfer[] types = new Transfer[] { ContentsTransfer.INSTANCE };
        int operations = DND.DROP_MOVE | DND.DROP_COPY;
        tv.addDragSupport(operations, types, new DragSourceListener() {
            public void dragFinished(DragSourceEvent event) {
            }

            public void dragSetData(DragSourceEvent event) {
                List<INSISInstallElement> selection = getSelectionList(tv);
                INSISInstallElement parent = getSelectionParent(selection);
                if (parent == null) {
                    event.data = null;
                } else {
                    event.data = new ContentsTransferData(parent, selection);
                }
            }

            public void dragStart(DragSourceEvent event) {
                List<INSISInstallElement> selection = getSelectionList(tv);
                INSISInstallElement parent = getSelectionParent(selection);
                if (parent == null) {
                    event.doit = false;
                }
            }
        });
        tv.addDropSupport(operations, new Transfer[] { ContentsTransfer.INSTANCE, FileTransfer.getInstance() },
                new DropTargetAdapter() {
                    private int determineOperation(String[] files, String[] types, INSISInstallElement target,
                            DropTargetEvent event, int defaultFeedback) {
                        if (target == null) {
                            return DND.DROP_NONE;
                        }
                        int operation = DND.DROP_COPY;
                        boolean filesOnly = true;
                        for (int i = 0; i < files.length; i++) {
                            if (IOUtility.isValidFile(files[i])) {
                                if (files[i].regionMatches(true, files[i].length() - REG_FILE_EXTENSION.length(),
                                        REG_FILE_EXTENSION, 0, REG_FILE_EXTENSION.length())) {
                                    types[i] = NSISInstallRegistryValue.TYPE;
                                } else {
                                    types[i] = NSISInstallFile.TYPE;
                                }
                            } else {
                                //Directory
                                filesOnly = false;
                                types[i] = NSISInstallDirectory.TYPE;
                            }
                        }
                        NSISInstallFiles.FileItem fileItem = null;
                        if (filesOnly) {
                            fileItem = new NSISInstallFiles.FileItem();
                        }
                        for (int i = 0; i < types.length; i++) {
                            if (!target.acceptsChildType(types[i])) {
                                if (types[i].equals(NSISInstallRegistryValue.TYPE)) {
                                    types[i] = NSISInstallFile.TYPE;
                                    if (target.acceptsChildType(types[i])) {
                                        continue;
                                    }
                                }
                                if (fileItem != null && types[i].equals(NSISInstallFile.TYPE) && filesOnly) {
                                    fileItem.setName(files[i]);
                                    if (target.canAddChild(fileItem)) {
                                        types[i] = NSISInstallFiles.FileItem.FILEITEM_TYPE;
                                        continue;
                                    }
                                }
                                operation = DND.DROP_NONE;
                                break;
                            }
                        }
                        return operation;
                    }

                    private int determineOperation(List<INSISInstallElement> selection,
                            INSISInstallElement oldParent, INSISInstallElement newParent, DropTargetEvent event,
                            int defaultFeedback) {
                        int operation = DND.DROP_NONE;
                        if (newParent != null) {
                            boolean shift = WinAPI.INSTANCE.getKeyState(WinAPI.VK_SHIFT) < 0;
                            boolean ctrl = WinAPI.INSTANCE.getKeyState(WinAPI.VK_CTRL) < 0;
                            if (ctrl && shift) {
                                operation = DND.DROP_NONE;
                            } else {
                                if (ctrl) {
                                    operation = DND.DROP_COPY;
                                } else if (shift) {
                                    operation = DND.DROP_MOVE;
                                } else {
                                    operation = DND.DROP_DEFAULT;
                                }
                            }
                            if (newParent != oldParent || operation == DND.DROP_COPY) {
                                for (Iterator<INSISInstallElement> iter = selection.iterator(); iter.hasNext();) {
                                    if (!newParent.canAddChild(iter.next())) {
                                        operation = DND.DROP_NONE;
                                        break;
                                    }
                                }
                            }
                            if (operation != DND.DROP_NONE && event != null) {
                                event.feedback |= defaultFeedback;
                            }
                        }
                        return operation;
                    }

                    @Override
                    public void dragOver(DropTargetEvent event) {
                        event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL;
                        int detail = DND.DROP_NONE;
                        if (event.item instanceof TreeItem) {
                            Tree tree = tv.getTree();
                            TreeItem item = (TreeItem) event.item;
                            Object data = item.getData();
                            if (data instanceof INSISInstallElement) {
                                INSISInstallElement element = (INSISInstallElement) data;
                                if (ContentsTransfer.INSTANCE.isSupportedType(event.currentDataType)) {
                                    ContentsTransferData transferData = (ContentsTransferData) ContentsTransfer.INSTANCE
                                            .nativeToJava(event.currentDataType);
                                    if (transferData.parent != null) {
                                        Point pt = tree.getDisplay().map(null, tree, event.x, event.y);
                                        Rectangle bounds = item.getBounds();
                                        if (pt.y < bounds.y + bounds.height / 3) {
                                            detail = determineOperation(transferData.selection, transferData.parent,
                                                    element.getParent(), event, DND.FEEDBACK_INSERT_BEFORE);
                                        } else if (pt.y > bounds.y + 2 * bounds.height / 3) {
                                            detail = determineOperation(transferData.selection, transferData.parent,
                                                    element.getParent(), event, DND.FEEDBACK_INSERT_AFTER);
                                        } else {
                                            detail = determineOperation(transferData.selection, transferData.parent,
                                                    element, event, DND.FEEDBACK_SELECT);
                                        }
                                    }
                                } else if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                                    Object transferData = FileTransfer.getInstance()
                                            .nativeToJava(event.currentDataType);
                                    if (transferData instanceof String[]) {
                                        String[] files = (String[]) transferData;
                                        String[] types = new String[files.length];
                                        Point pt = tree.getDisplay().map(null, tree, event.x, event.y);
                                        Rectangle bounds = item.getBounds();
                                        if (pt.y < bounds.y + bounds.height / 3) {
                                            detail = determineOperation(files, types, element.getParent(), event,
                                                    DND.FEEDBACK_INSERT_BEFORE);
                                        } else if (pt.y > bounds.y + 2 * bounds.height / 3) {
                                            detail = determineOperation(files, types, element.getParent(), event,
                                                    DND.FEEDBACK_INSERT_AFTER);
                                        } else {
                                            detail = determineOperation(files, types, element, event,
                                                    DND.FEEDBACK_SELECT);
                                        }
                                    }
                                }
                            }
                        }
                        event.detail = detail;
                    }

                    private void doDrop(List<INSISInstallElement> selection, int detail,
                            INSISInstallElement oldParent, INSISInstallElement newParent, int index) {
                        int index2 = index;
                        try {
                            for (Iterator<INSISInstallElement> iter = selection.iterator(); iter.hasNext();) {
                                INSISInstallElement el = iter.next();
                                switch (detail) {
                                case DND.DROP_COPY:
                                    el = (INSISInstallElement) el.clone();
                                    //$FALL-THROUGH$
                                case DND.DROP_DEFAULT:
                                case DND.DROP_MOVE:
                                    if (oldParent == newParent) {
                                        int n = oldParent.indexOf(el);
                                        if (n < index2) {
                                            index2--;
                                        }
                                        oldParent.removeChild(el);
                                    }
                                    newParent.addChild(index2++, el);
                                }
                            }
                            setPageComplete(validatePage(VALIDATE_ALL));
                        } catch (Exception ex) {
                            delayedValidateAfterError(ex.getLocalizedMessage(), 2000);
                        } finally {
                            tv.refresh(true);
                            if (newParent instanceof AbstractNSISInstallGroup) {
                                ((AbstractNSISInstallGroup) newParent).setExpanded(true);
                                expandGroup(tv, (AbstractNSISInstallGroup) newParent);
                            }
                        }
                    }

                    private void doDrop(String[] files, String[] types, INSISInstallElement target, int index) {
                        int index2 = index;
                        try {
                            RegistryImporter importer = null;
                            RegistryImportStrategy strategy = null;

                            for (int i = 0; i < files.length; i++) {
                                INSISInstallElement el = null;
                                if (types[i].equals(NSISInstallFile.TYPE)) {
                                    el = new NSISInstallFile();
                                    ((NSISInstallFile) el).setName(files[i]);
                                } else if (types[i].equals(NSISInstallDirectory.TYPE)) {
                                    el = new NSISInstallDirectory();
                                    ((NSISInstallDirectory) el).setName(files[i]);
                                } else if (types[i].equals(NSISInstallFiles.FileItem.FILEITEM_TYPE)) {
                                    el = new NSISInstallFiles.FileItem();
                                    ((NSISInstallFiles.FileItem) el).setName(files[i]);
                                } else if (types[i].equals(NSISInstallRegistryValue.TYPE)) {
                                    try {
                                        if (importer == null || strategy == null) {
                                            importer = new RegistryImporter();
                                            strategy = new RegistryImportStrategy();
                                        } else {
                                            strategy.reset();
                                        }
                                        importer.importRegFile(getShell(), files[i], strategy);
                                        List<NSISInstallRegistryItem> list = strategy.getRegistryItems();
                                        if (!Common.isEmptyCollection(list)) {
                                            for (Iterator<NSISInstallRegistryItem> iter = list.iterator(); iter
                                                    .hasNext();) {
                                                NSISInstallRegistryItem element = iter.next();
                                                target.addChild(index2++, element);
                                            }
                                        }
                                        continue;
                                    } catch (Exception ex) {
                                    }
                                    el = new NSISInstallFile();
                                    ((NSISInstallFile) el).setName(files[i]);
                                }
                                if (el != null) {
                                    target.addChild(index2++, el);
                                }
                            }
                            setPageComplete(validatePage(VALIDATE_ALL));
                        } catch (Exception ex) {
                            delayedValidateAfterError(ex.getLocalizedMessage(), 2000);
                        } finally {
                            tv.refresh(true);
                            if (target instanceof AbstractNSISInstallGroup) {
                                ((AbstractNSISInstallGroup) target).setExpanded(true);
                                expandGroup(tv, (AbstractNSISInstallGroup) target);
                            }
                        }
                    }

                    @Override
                    public void drop(DropTargetEvent event) {
                        int detail = DND.DROP_NONE;

                        if (event.item instanceof TreeItem) {
                            Tree tree = tv.getTree();
                            TreeItem item = (TreeItem) event.item;
                            Object data = item.getData();
                            if (data instanceof INSISInstallElement) {
                                INSISInstallElement element = (INSISInstallElement) data;
                                if (ContentsTransfer.INSTANCE.isSupportedType(event.currentDataType)) {
                                    if (event.data instanceof ContentsTransferData) {
                                        ContentsTransferData transferData = (ContentsTransferData) event.data;
                                        if (transferData.parent != null) {
                                            Point pt = tree.getDisplay().map(null, tree, event.x, event.y);
                                            Rectangle bounds = item.getBounds();
                                            if (pt.y < bounds.y + bounds.height / 3) {
                                                detail = determineOperation(transferData.selection,
                                                        transferData.parent, element.getParent(), null, 0);
                                                if (detail != DND.DROP_NONE) {
                                                    doDrop(transferData.selection, detail, transferData.parent,
                                                            element.getParent(),
                                                            element.getParent().indexOf(element));
                                                }
                                            } else if (pt.y > bounds.y + 2 * bounds.height / 3) {
                                                detail = determineOperation(transferData.selection,
                                                        transferData.parent, element.getParent(), null, 0);
                                                if (detail != DND.DROP_NONE) {
                                                    doDrop(transferData.selection, detail, transferData.parent,
                                                            element.getParent(),
                                                            element.getParent().indexOf(element) + 1);
                                                }
                                            } else {
                                                detail = determineOperation(transferData.selection,
                                                        transferData.parent, element, null, 0);
                                                if (detail != DND.DROP_NONE) {
                                                    doDrop(transferData.selection, detail, transferData.parent,
                                                            element, element.getChildCount());
                                                }
                                            }
                                        }
                                    }
                                } else if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                                    if (event.data instanceof String[]) {
                                        String[] files = (String[]) event.data;
                                        String[] types = new String[files.length];
                                        Point pt = tree.getDisplay().map(null, tree, event.x, event.y);
                                        Rectangle bounds = item.getBounds();
                                        if (pt.y < bounds.y + bounds.height / 3) {
                                            detail = determineOperation(files, types, element.getParent(), event,
                                                    DND.FEEDBACK_INSERT_BEFORE);
                                            if (detail != DND.DROP_NONE) {
                                                doDrop(files, types, element.getParent(),
                                                        element.getParent().indexOf(element));
                                            }
                                        } else if (pt.y > bounds.y + 2 * bounds.height / 3) {
                                            detail = determineOperation(files, types, element.getParent(), event,
                                                    DND.FEEDBACK_INSERT_AFTER);
                                            if (detail != DND.DROP_NONE) {
                                                doDrop(files, types, element.getParent(),
                                                        element.getParent().indexOf(element) + 1);
                                            }
                                        } else {
                                            detail = determineOperation(files, types, element, event,
                                                    DND.FEEDBACK_SELECT);
                                            if (detail != DND.DROP_NONE) {
                                                doDrop(files, types, element, element.getChildCount());
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        event.detail = detail;
                    }
                });
    }

    private List<INSISInstallElement> getSelectionList(TreeViewer tv) {
        List<INSISInstallElement> list = new ArrayList<INSISInstallElement>();
        ISelection sel = tv.getSelection();
        if (!sel.isEmpty() && sel instanceof IStructuredSelection) {
            for (Object o : ((IStructuredSelection) sel).toList()) {
                list.add((INSISInstallElement) o);
            }
        }
        return list;
    }

    private INSISInstallElement getSelectionParent(List<INSISInstallElement> list) {
        INSISInstallElement parent = null;
        if (!Common.isEmptyCollection(list)) {
            for (Iterator<INSISInstallElement> iter = list.iterator(); iter.hasNext();) {
                INSISInstallElement element = iter.next();
                if (parent != null) {
                    if (!parent.equals(element.getParent())) {
                        return null;
                    }
                } else {
                    parent = element.getParent();
                    if (parent == null) {
                        return null;
                    }
                }
            }
        }
        return parent;
    }

    private boolean shouldSelectComponents(INSISInstallElement item) {
        if (item instanceof NSISSection) {
            return !((NSISSection) item).isHidden();
        } else if (item instanceof NSISSectionGroup) {
            INSISInstallElement[] items = item.getChildren();
            if (!Common.isEmptyArray(items)) {
                for (int i = 0; i < items.length; i++) {
                    if (shouldSelectComponents(items[i])) {
                        return true;
                    }
                }
            }
        }

        return false;
    }

    private void updateSelectComponents() {
        NSISWizardSettings settings = mWizard.getSettings();

        if (settings.getInstallerType() != INSISWizardConstants.INSTALLER_TYPE_SILENT) {
            INSISInstallElement[] items = settings.getInstaller().getChildren();
            if (!Common.isEmptyArray(items)) {
                for (int i = 0; i < items.length; i++) {
                    if (shouldSelectComponents(items[i])) {
                        settings.setSelectComponents(true);
                        return;
                    }
                }
            }
        }
        settings.setSelectComponents(false);
    }

    private void editElement(Composite composite, TreeViewer tv, INSISInstallElement element) {
        try {
            if (element.edit(mWizard)) {
                tv.refresh(element, true);
                if (element.hasChildren()) {
                    tv.expandToLevel(element, AbstractTreeViewer.ALL_LEVELS);
                }
                setPageComplete(validatePage(VALIDATE_ALL));
            }
        } catch (Exception ex) {
            delayedValidateAfterError(ex.getLocalizedMessage(), 2000);
        }
    }

    /**
     * @param tv
     * @param sel
     */
    private void deleteElements(final TreeViewer tv, ISelection sel) {
        if (sel instanceof IStructuredSelection) {
            IStructuredSelection ssel = (IStructuredSelection) sel;
            if (!ssel.isEmpty()) {
                try {
                    int buttonId = -1;
                    for (Iterator<?> iter = ssel.iterator(); iter.hasNext();) {
                        INSISInstallElement element = (INSISInstallElement) iter.next();
                        if (element.hasChildren()) {
                            if (buttonId == IDialogConstants.NO_TO_ALL_ID) {
                                continue;
                            } else if (buttonId != IDialogConstants.YES_TO_ALL_ID) {
                                int index = new MessageDialog(getShell(), cDeleteConfirmTitle,
                                        EclipseNSISPlugin.getShellImage(),
                                        MessageFormat
                                                .format(cDeleteConfirmMessageFormat,
                                                        new Object[] { element.getDisplayName() }),
                                        MessageDialog.QUESTION,
                                        new String[] { IDialogConstants.YES_LABEL,
                                                IDialogConstants.YES_TO_ALL_LABEL, IDialogConstants.NO_LABEL,
                                                IDialogConstants.NO_TO_ALL_LABEL },
                                        0).open();
                                if (index >= 0) {
                                    buttonId = cDeleteConfirmButtonIds[index];
                                } else {
                                    return;
                                }

                                if (buttonId == IDialogConstants.NO_ID
                                        || buttonId == IDialogConstants.NO_TO_ALL_ID) {
                                    continue;
                                }
                            }
                        }
                        INSISInstallElement parent = element.getParent();
                        if (parent != null) {
                            parent.removeChild(element);
                            tv.refresh(parent, true);
                        }
                    }
                    setPageComplete(validatePage(VALIDATE_ALL));
                } catch (Exception ex) {
                    delayedValidateAfterError(ex.getLocalizedMessage(), 2000);
                } finally {
                    tv.refresh(false);
                }
            }
        }
    }

    /**
     * @param errorMessage
     */
    private void delayedValidateAfterError(String errorMessage, final int delay) {
        setErrorMessage(errorMessage);
        final Display display = getShell().getDisplay();
        new Thread(new Runnable() {
            public void run() {
                try {
                    Thread.sleep(delay);
                } catch (InterruptedException ie) {
                }
                display.asyncExec(new Runnable() {
                    public void run() {
                        setPageComplete(validatePage(VALIDATE_ALL));
                    }
                });
            }
        }, EclipseNSISPlugin.getResourceString("wizard.contents.validator.thread.name")).start(); //$NON-NLS-1$
    }

    private void enableItem(Item item, boolean state) {
        if (item instanceof ToolItem) {
            ((ToolItem) item).setEnabled(state);
        } else if (item instanceof MenuItem) {
            ((MenuItem) item).setEnabled(state);
        }
    }

    private void enableItems(ISelection sel, Item addItem, Item editItem, Item deleteItem) {
        if (sel.isEmpty()) {
            enableItem(addItem, false);
            enableItem(editItem, false);
            enableItem(deleteItem, false);
        } else if (sel instanceof IStructuredSelection) {
            IStructuredSelection selection = (IStructuredSelection) sel;
            if (selection.size() > 1) {
                enableItem(addItem, false);
                enableItem(editItem, false);
            } else {
                Object obj = selection.getFirstElement();
                if (obj instanceof INSISInstallElement) {
                    INSISInstallElement element = (INSISInstallElement) obj;
                    enableItem(addItem, !Common.isEmptyArray(element.getChildTypes()));
                    enableItem(editItem, element.isEditable());
                }
            }
            enableItem(deleteItem, canDeleteElements(selection));
        }
    }

    private boolean isAncestorOf(INSISInstallElement first, INSISInstallElement second) {
        INSISInstallElement second2 = second;
        while (!first.equals(second2)) {
            second2 = second2.getParent();
            if (second2 == null) {
                return false;
            }
        }
        return true;
    }

    /**
     * @param selection
     * @return
     */
    private boolean canDeleteElements(IStructuredSelection selection) {
        Set<INSISInstallElement> elements = new HashSet<INSISInstallElement>();
        if (selection.size() > 0) {
            if (selection.size() > 1) {
                for (Iterator<?> iter = selection.iterator(); iter.hasNext();) {
                    Object obj = iter.next();
                    if (obj instanceof INSISInstallElement) {
                        INSISInstallElement element = (INSISInstallElement) obj;
                        if (!element.isRemovable()) {
                            return false;
                        } else {
                            for (Iterator<INSISInstallElement> iterator = elements.iterator(); iterator
                                    .hasNext();) {
                                INSISInstallElement element2 = iterator.next();
                                if (isAncestorOf(element, element2) || isAncestorOf(element2, element)) {
                                    return false;
                                }
                            }
                            elements.add(element);
                        }
                    }
                }
                return true;
            } else {
                Object obj = selection.getFirstElement();
                if (obj instanceof INSISInstallElement) {
                    return ((INSISInstallElement) obj).isRemovable();
                }
            }
        }
        return false;
    }

    private void updateAddMenu(Menu addPopupMenu, ISelection selection, SelectionAdapter adapter) {
        if (!selection.isEmpty()) {
            if (selection instanceof IStructuredSelection) {
                IStructuredSelection ssel = (IStructuredSelection) selection;
                if (ssel.size() == 1) {
                    Object obj = ssel.getFirstElement();
                    if (obj instanceof INSISInstallElement) {
                        INSISInstallElement element = (INSISInstallElement) obj;
                        String[] childTypes = element.getChildTypes();
                        if (!Common.isEmptyArray(childTypes)) {
                            int n = addPopupMenu.getItemCount();
                            for (int i = 0; i < n; i++) {
                                addPopupMenu.getItem(0).dispose();
                            }

                            for (int i = 0; i < childTypes.length; i++) {
                                MenuItem mi = new MenuItem(addPopupMenu, SWT.PUSH);
                                mi.addSelectionListener(adapter);
                                mi.setData(childTypes[i]);
                                mi.setText(NSISInstallElementFactory.getTypeName(childTypes[i]));
                                mi.setImage(NSISInstallElementFactory.getImage(childTypes[i]));
                            }

                        }
                    }
                }
            }
        }
    }

    /**
     * @param composite
     * @param bundle
     */
    private ToolBar createToolBar(Composite parent, ResourceBundle bundle) {
        ToolBar toolbar = new ToolBar(parent, SWT.FLAT);

        int[] styles = { SWT.DROP_DOWN, SWT.PUSH, SWT.PUSH, SWT.PUSH, SWT.PUSH };
        Image[] images = { CommonImages.ADD_ICON, CommonImages.EDIT_ICON, CommonImages.DELETE_ICON,
                CommonImages.EXPANDALL_ICON, CommonImages.COLLAPSEALL_ICON };
        Image[] disabledImages = { CommonImages.ADD_DISABLED_ICON, CommonImages.EDIT_DISABLED_ICON,
                CommonImages.DELETE_DISABLED_ICON, CommonImages.EXPANDALL_DISABLED_ICON,
                CommonImages.COLLAPSEALL_DISABLED_ICON };
        String[] tooltips = { "add.tooltip", "edit.tooltip", "delete.tooltip", "expandall.tooltip", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
                "collapseall.tooltip" }; //$NON-NLS-1$
        boolean[] state = { false, false, false, true, true };
        for (int i = 0; i < styles.length; i++) {
            ToolItem ti = new ToolItem(toolbar, styles[i]);
            ti.setImage(images[i]);
            ti.setDisabledImage(disabledImages[i]);
            ti.setToolTipText(bundle.getString(tooltips[i]));
            ti.setEnabled(state[i]);
        }
        return toolbar;
    }

    /**
     * @param composite
     * @param bundle
     */
    private Menu createMenu(ResourceBundle bundle) {
        Menu menu = new Menu(getShell(), SWT.POP_UP);

        int[] styles = { SWT.CASCADE, SWT.PUSH, SWT.PUSH };
        Image[] images = { CommonImages.ADD_ICON, CommonImages.EDIT_ICON, CommonImages.DELETE_ICON };
        String[] tooltips = { "add.tooltip", "edit.tooltip", "delete.tooltip" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        for (int i = 0; i < styles.length; i++) {
            MenuItem mi = new MenuItem(menu, styles[i]);
            mi.setImage(images[i]);
            mi.setText(bundle.getString(tooltips[i]));
            mi.setEnabled(false);
        }
        return menu;
    }

    private void checkUnselectedSections() {
        NSISWizardSettings settings = mWizard.getSettings();

        if (Common.isEmpty(getMessage()) || getMessageType() != ERROR) {
            if (settings.getInstallerType() == INSISWizardConstants.INSTALLER_TYPE_SILENT) {
                INSISInstallElement[] items = settings.getInstaller().getChildren();
                if (!Common.isEmptyArray(items)) {
                    for (int i = 0; i < items.length; i++) {
                        if (items[i] instanceof NSISSection) {
                            if (((NSISSection) items[i]).isDefaultUnselected()) {
                                setMessage(
                                        EclipseNSISPlugin.getResourceString("silent.unselected.sections.warning"), //$NON-NLS-1$
                                        WARNING);
                                return;
                            }
                        } else if (items[i] instanceof NSISSectionGroup) {
                            INSISInstallElement[] items2 = items[i].getChildren();
                            if (!Common.isEmptyArray(items2)) {
                                for (int j = 0; j < items2.length; j++) {
                                    if (items2[j] instanceof NSISSection) {
                                        if (((NSISSection) items2[j]).isDefaultUnselected()) {
                                            setMessage(EclipseNSISPlugin.getResourceString(
                                                    "silent.unselected.sections.warning"), WARNING); //$NON-NLS-1$
                                            return;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            } else {
                setMessage(EclipseNSISPlugin.getResourceString("wizard.contents.description")); //$NON-NLS-1$
            }
        }
    }

    @Override
    public boolean validatePage(int flag) {
        if (isTemplateWizard()) {
            return true;
        } else {
            NSISWizardSettings settings = mWizard.getSettings();

            List<INSISInstallElement> changedElements = new ArrayList<INSISInstallElement>();
            String error = settings.getInstaller().validate(changedElements);
            if (mContentsTreeViewer != null && changedElements.size() > 0) {
                mContentsTreeViewer.update(changedElements.toArray(), null);
            }
            setErrorMessage(error);
            boolean b = error == null;
            setPageComplete(b);
            checkUnselectedSections();
            return b;
        }
    }

    private static class RegistryImportStrategy implements RegistryImporter.IRegistryImportStrategy {
        private List<NSISInstallRegistryItem> mRegistryItems = new ArrayList<NSISInstallRegistryItem>();

        public void reset() {
            mRegistryItems.clear();
        }

        public List<NSISInstallRegistryItem> getRegistryItems() {
            return mRegistryItems;
        }

        public void addRegistryKey(String rootKey, String subKey) {
            NSISInstallRegistryKey regKey = new NSISInstallRegistryKey();
            regKey.setRootKey(NSISWizardDisplayValues.getHKeyIndex(rootKey));
            regKey.setSubKey(subKey);
            mRegistryItems.add(regKey);
        }

        public void addRegistryValue(String rootKey, String subKey, String value, int type, String data) {
            int type2 = type;
            switch (type2) {
            case WinAPI.REG_BINARY:
                type2 = REG_BIN;
                break;
            case WinAPI.REG_DWORD:
                type2 = REG_DWORD;
                break;
            case WinAPI.REG_EXPAND_SZ:
                type2 = REG_EXPAND_SZ;
                break;
            case WinAPI.REG_SZ:
                type2 = REG_SZ;
                break;
            default:
                return;
            }
            NSISInstallRegistryValue regVal = new NSISInstallRegistryValue();
            regVal.setRootKey(NSISWizardDisplayValues.getHKeyIndex(rootKey));
            regVal.setSubKey(subKey);
            regVal.setValue(value);
            regVal.setData(data);
            regVal.setValueType(type2);
            mRegistryItems.add(regVal);
        }

        public void beginRegistryKeySection(String rootKey, String subKey) {
        }

        public void deleteRegistryKey(String rootKey, String subKey) {
        }

        public void deleteRegistryValue(String rootKey, String subKey, String value) {
        }
    }

    private class ContentsTransferData {
        INSISInstallElement parent;
        List<INSISInstallElement> selection;

        public ContentsTransferData(INSISInstallElement parent, List<INSISInstallElement> selection) {
            this.parent = parent;
            this.selection = selection;
        }
    }

    private static class ContentsTransfer extends ObjectTransfer {
        public static final ContentsTransfer INSTANCE = new ContentsTransfer();
        private static final String[] TYPE_NAMES = { new StringBuffer("NSIS Wizard contents transfer").append( //$NON-NLS-1$
                System.currentTimeMillis()).append(":").append(INSTANCE.hashCode()).toString() };//$NON-NLS-1$
        private static final int[] TYPEIDS = { registerType(TYPE_NAMES[0]) };

        private ContentsTransfer() {
        }

        @Override
        protected int[] getTypeIds() {
            return TYPEIDS;
        }

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