/*******************************************************************************
 * Copyright (c) 2000, 2006 IBM Corporation and others.
 * 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:
 *     IBM Corporation - initial API and implementation
 *     Sebastian Davids <sdavids@gmx.de> - Collapse all action (25826)
 *     Sebastian Davids <sdavids@gmx.de> - Images for menu items (27481)
 *******************************************************************************/
package org.eclipse.ui.views.navigator;

import java.util.List;

import org.eclipse.core.commands.operations.IUndoContext;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.actions.ActionContext;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.actions.AddBookmarkAction;
import org.eclipse.ui.actions.AddTaskAction;
import org.eclipse.ui.actions.ExportResourcesAction;
import org.eclipse.ui.actions.ImportResourcesAction;
import org.eclipse.ui.actions.NewWizardMenu;
import org.eclipse.ui.actions.WorkingSetFilterActionGroup;
import org.eclipse.ui.dialogs.PropertyDialogAction;
import org.eclipse.ui.ide.IDEActionFactory;
import org.eclipse.ui.internal.views.navigator.ResourceNavigatorMessages;
import org.eclipse.ui.operations.UndoRedoActionGroup;

/**
 * The main action group for the navigator.
 * This contains a few actions and several subgroups.
 */
public class MainActionGroup extends ResourceNavigatorActionGroup {

    protected AddBookmarkAction addBookmarkAction;

    protected AddTaskAction addTaskAction;

    protected PropertyDialogAction propertyDialogAction;

    protected ImportResourcesAction importAction;
    
    protected ExportResourcesAction exportAction;

    protected CollapseAllAction collapseAllAction;

    protected ToggleLinkingAction toggleLinkingAction;

    protected GotoActionGroup gotoGroup;

    protected OpenActionGroup openGroup;

    protected RefactorActionGroup refactorGroup;

    protected WorkingSetFilterActionGroup workingSetGroup;

    protected SortAndFilterActionGroup sortAndFilterGroup;
    
    protected UndoRedoActionGroup undoRedoGroup;

    protected WorkspaceActionGroup workspaceGroup;

    private IResourceChangeListener resourceChangeListener;

    private NewWizardMenu newWizardMenu;

    /**
     * Constructs the main action group.
     * 
     * @param navigator the navigator view
     */
    public MainActionGroup(IResourceNavigator navigator) {
        super(navigator);
        resourceChangeListener = new IResourceChangeListener() {
            public void resourceChanged(IResourceChangeEvent event) {
                handleResourceChanged(event);
            }
        };
        ResourcesPlugin.getWorkspace().addResourceChangeListener(
                resourceChangeListener, IResourceChangeEvent.POST_CHANGE);
        makeSubGroups();
    }

    /**
     * Handles a resource changed event by updating the enablement
     * if one of the selected projects is opened or closed.
     */
    protected void handleResourceChanged(IResourceChangeEvent event) {
        ActionContext context = getContext();
        if (context == null) {
            return;
        }

        final IStructuredSelection selection = (IStructuredSelection) context
                .getSelection();
        if (ResourceSelectionUtil.allResourcesAreOfType(selection,
                IResource.PROJECT) == false) {
            return;
        }
        List sel = selection.toList();
        IResourceDelta delta = event.getDelta();
        if (delta == null) {
            return;
        }
        IResourceDelta[] projDeltas = delta
                .getAffectedChildren(IResourceDelta.CHANGED);
        for (int i = 0; i < projDeltas.length; ++i) {
            IResourceDelta projDelta = projDeltas[i];
            //changing the project open state or description will effect open/close/build action enablement
            if ((projDelta.getFlags() & (IResourceDelta.OPEN | IResourceDelta.DESCRIPTION)) != 0) {
                if (sel.contains(projDelta.getResource())) {
                    getNavigator().getSite().getShell().getDisplay().syncExec(
                            new Runnable() {
                                public void run() {
                                    addTaskAction.selectionChanged(selection);
                                    gotoGroup.updateActionBars();
                                    refactorGroup.updateActionBars();
                                    workspaceGroup.updateActionBars();
                                }
                            });
                }
            }
        }
    }

    /**
     * Makes the actions contained directly in this action group.
     */
    protected void makeActions() {
        Shell shell = navigator.getSite().getShell();

        newWizardMenu = new NewWizardMenu(navigator.getSite().getWorkbenchWindow());
        addBookmarkAction = new AddBookmarkAction(shell);
        addTaskAction = new AddTaskAction(shell);
        propertyDialogAction = new PropertyDialogAction(shell, navigator
                .getViewer());

        importAction = new ImportResourcesAction(navigator.getSite()
                .getWorkbenchWindow());
        importAction
                .setDisabledImageDescriptor(getImageDescriptor("dtool16/import_wiz.gif")); //$NON-NLS-1$
        importAction
                .setImageDescriptor(getImageDescriptor("etool16/import_wiz.gif")); //$NON-NLS-1$		

        exportAction = new ExportResourcesAction(navigator.getSite()
                .getWorkbenchWindow());
        exportAction
                .setDisabledImageDescriptor(getImageDescriptor("dtool16/export_wiz.gif")); //$NON-NLS-1$
        exportAction
                .setImageDescriptor(getImageDescriptor("etool16/export_wiz.gif")); //$NON-NLS-1$		
        
        
        collapseAllAction = new CollapseAllAction(navigator,
                ResourceNavigatorMessages.CollapseAllAction_title);
        collapseAllAction.setToolTipText(ResourceNavigatorMessages.CollapseAllAction_toolTip);
        collapseAllAction
                .setImageDescriptor(getImageDescriptor("elcl16/collapseall.gif")); //$NON-NLS-1$

        toggleLinkingAction = new ToggleLinkingAction(navigator,
                ResourceNavigatorMessages.ToggleLinkingAction_text);
        toggleLinkingAction.setToolTipText(ResourceNavigatorMessages.ToggleLinkingAction_toolTip);
        toggleLinkingAction
                .setImageDescriptor(getImageDescriptor("elcl16/synced.gif"));//$NON-NLS-1$
    }

    /**
     * Makes the sub action groups.
     */
    protected void makeSubGroups() {
        gotoGroup = new GotoActionGroup(navigator);
        openGroup = new OpenActionGroup(navigator);
        refactorGroup = new RefactorActionGroup(navigator);
        IPropertyChangeListener workingSetUpdater = new IPropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent event) {
                String property = event.getProperty();

                if (WorkingSetFilterActionGroup.CHANGE_WORKING_SET
                        .equals(property)) {
                    IResourceNavigator navigator = getNavigator();
                    Object newValue = event.getNewValue();

                    if (newValue instanceof IWorkingSet) {
                        navigator.setWorkingSet((IWorkingSet) newValue);
                    } else if (newValue == null) {
                        navigator.setWorkingSet(null);
                    }
                }
            }
        };
        TreeViewer treeView = navigator.getViewer();
        Shell shell = treeView.getControl().getShell();
        workingSetGroup = new WorkingSetFilterActionGroup(shell,
                workingSetUpdater);
        workingSetGroup.setWorkingSet(navigator.getWorkingSet());
        sortAndFilterGroup = new SortAndFilterActionGroup(navigator);
        workspaceGroup = new WorkspaceActionGroup(navigator);
        IUndoContext workspaceContext= (IUndoContext)ResourcesPlugin.getWorkspace().getAdapter(IUndoContext.class);
		undoRedoGroup= new UndoRedoActionGroup(getNavigator().getSite(), workspaceContext, true);

    }
    
    /**
     * Extends the superclass implementation to set the context in the subgroups.
     */
    public void setContext(ActionContext context) {
        super.setContext(context);
        gotoGroup.setContext(context);
        openGroup.setContext(context);
        refactorGroup.setContext(context);
        sortAndFilterGroup.setContext(context);
        workspaceGroup.setContext(context);
        undoRedoGroup.setContext(context);
    }

    /**
     * Fills the context menu with the actions contained in this group
     * and its subgroups.
     * 
     * @param menu the context menu
     */
    public void fillContextMenu(IMenuManager menu) {
        IStructuredSelection selection = (IStructuredSelection) getContext()
                .getSelection();

        MenuManager newMenu = new MenuManager(ResourceNavigatorMessages.ResourceNavigator_new);
        menu.add(newMenu);
        newMenu.add(newWizardMenu);

        gotoGroup.fillContextMenu(menu);
        openGroup.fillContextMenu(menu);
        menu.add(new Separator());

        refactorGroup.fillContextMenu(menu);
        menu.add(new Separator());

        menu.add(importAction);
        menu.add(exportAction);
        importAction.selectionChanged(selection);
        exportAction.selectionChanged(selection);
        menu.add(new Separator());

        workspaceGroup.fillContextMenu(menu);

        menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
        menu
                .add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS
                        + "-end")); //$NON-NLS-1$
        menu.add(new Separator());

        if (selection.size() == 1) {
            propertyDialogAction.selectionChanged(selection);
            menu.add(propertyDialogAction);
        }
    }

    /**
     * Adds the actions in this group and its subgroups to the action bars.
     */
    public void fillActionBars(IActionBars actionBars) {
        actionBars.setGlobalActionHandler(ActionFactory.PROPERTIES.getId(),
                propertyDialogAction);
        actionBars.setGlobalActionHandler(IDEActionFactory.BOOKMARK.getId(),
                addBookmarkAction);
        actionBars.setGlobalActionHandler(IDEActionFactory.ADD_TASK.getId(),
                addTaskAction);

        gotoGroup.fillActionBars(actionBars);
        openGroup.fillActionBars(actionBars);
        refactorGroup.fillActionBars(actionBars);
        workingSetGroup.fillActionBars(actionBars);
        sortAndFilterGroup.fillActionBars(actionBars);
        workspaceGroup.fillActionBars(actionBars);
        undoRedoGroup.fillActionBars(actionBars);

        IMenuManager menu = actionBars.getMenuManager();
        menu.add(toggleLinkingAction);

        IToolBarManager toolBar = actionBars.getToolBarManager();
        toolBar.add(new Separator());
        toolBar.add(collapseAllAction);
        toolBar.add(toggleLinkingAction);
    }

    /**
     * Updates the actions which were added to the action bars,
     * delegating to the subgroups as necessary.
     */
    public void updateActionBars() {
        IStructuredSelection selection = (IStructuredSelection) getContext()
                .getSelection();
        propertyDialogAction.setEnabled(selection.size() == 1);
        addBookmarkAction.selectionChanged(selection);
        addTaskAction.selectionChanged(selection);

        gotoGroup.updateActionBars();
        openGroup.updateActionBars();
        refactorGroup.updateActionBars();
        workingSetGroup.updateActionBars();
        sortAndFilterGroup.updateActionBars();
        workspaceGroup.updateActionBars();
        undoRedoGroup.updateActionBars();
    }

    /**
     * Runs the default action (open file) by delegating the open group.
     */
    public void runDefaultAction(IStructuredSelection selection) {
        openGroup.runDefaultAction(selection);
    }

    /**
     * Handles a key pressed event by invoking the appropriate action,
     * delegating to the subgroups as necessary.
     */
    public void handleKeyPressed(KeyEvent event) {
        refactorGroup.handleKeyPressed(event);
        workspaceGroup.handleKeyPressed(event);
    }

    /**
     * Extends the superclass implementation to dispose the 
     * actions in this group and its subgroups.
     */
    public void dispose() {
        ResourcesPlugin.getWorkspace().removeResourceChangeListener(
                resourceChangeListener);

        newWizardMenu.dispose();
        collapseAllAction.dispose();
        importAction.dispose();
        exportAction.dispose();
        propertyDialogAction.dispose();
        toggleLinkingAction.dispose();

        gotoGroup.dispose();
        openGroup.dispose();
        refactorGroup.dispose();
        sortAndFilterGroup.dispose();
        workingSetGroup.dispose();
        workspaceGroup.dispose();
        undoRedoGroup.dispose();
        super.dispose();
    }
}
