<commit_before>/**
 * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
/*
 * Created on Oct 29, 2006
 * @author Fabio
 */
package org.python.pydev.navigator.ui;

import java.io.File;
import java.net.URI;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.internal.navigator.ContributorTrackingSet;
import org.eclipse.ui.internal.navigator.NavigatorContentService;
import org.eclipse.ui.navigator.CommonNavigator;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.navigator.INavigatorPipelineService;
import org.eclipse.ui.navigator.PipelinedShapeModification;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.ShowInContext;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.editorinput.PydevZipFileEditorInput;
import org.python.pydev.editorinput.PydevZipFileStorage;
import org.python.pydev.navigator.LabelAndImage;
import org.python.pydev.navigator.actions.PythonLinkHelper;
import org.python.pydev.navigator.elements.IWrappedResource;
import org.python.pydev.shared_core.callbacks.CallbackWithListeners;
import org.python.pydev.shared_core.callbacks.ICallbackWithListeners;
import org.python.pydev.shared_core.structure.TreeNode;
import org.python.pydev.shared_ui.utils.IViewWithControls;
import org.python.pydev.ui.NotifyViewCreated;

/**
 * This class is the package explorer for pydev. It uses the CNF (Common Navigator Framework) to show
 * the resources as python elements.
 */
@SuppressWarnings({ "restriction", "rawtypes", "unchecked" })
public class PydevPackageExplorer extends CommonNavigator implements IShowInTarget, IViewWithControls {

    /**
     * This viewer is the one used instead of the common viewer -- should only be used to fix failures in the base class.
     */
    public static class PydevCommonViewer extends CommonViewer {

        /**
         * This is used so that we only restore the memento in the 'right' place
         */
        public boolean availableToRestoreMemento = false;

        /**
         * This is the pydev package explorer
         */
        private PydevPackageExplorer pydevPackageExplorer;

        public PydevPackageExplorer getPydevPackageExplorer() {
            return pydevPackageExplorer;
        }

        public PydevCommonViewer(String id, Composite parent, int style, PydevPackageExplorer pydevPackageExplorer) {
            super(id, parent, style);
            this.pydevPackageExplorer = pydevPackageExplorer;

            //We need to be able to compare actual resources and IWrappedResources
            //as if they were the same thing.
            setComparer(new IElementComparer() {

                public int hashCode(Object element) {
                    if (element instanceof IWrappedResource) {
                        IWrappedResource wrappedResource = (IWrappedResource) element;
                        return wrappedResource.getActualObject().hashCode();
                    }
                    return element.hashCode();
                }

                public boolean equals(Object a, Object b) {
                    if (a instanceof IWrappedResource) {
                        IWrappedResource wrappedResource = (IWrappedResource) a;
                        a = wrappedResource.getActualObject();
                    }
                    if (b instanceof IWrappedResource) {
                        IWrappedResource wrappedResource = (IWrappedResource) b;
                        b = wrappedResource.getActualObject();
                    }
                    if (a == null) {
                        if (b == null) {
                            return true;
                        } else {
                            return false;
                        }
                    }
                    if (b == null) {
                        return false;
                    }

                    return a.equals(b);
                }
            });
        }

        /**
         * Returns the tree path for the given item.
         * 
         * It's overridden because when using mylyn, the paths may be expanded but not shown, so segment is null
         * -- that's why we return null if a given segment is null (instead of the assert that it contains in the superclass) 
         * @since 3.2
         */
        @Override
        protected TreePath getTreePathFromItem(Item item) {
            LinkedList<Object> segments = new LinkedList<Object>();
            while (item != null) {
                Object segment = item.getData();
                if (segment == null) {
                    return null;
                }
                segments.addFirst(segment);
                item = getParentItem(item);
            }
            return new TreePath(segments.toArray());
        }
    }

    /**
     * This is the memento to be used.
     */
    private IMemento memento;
    public final ICallbackWithListeners onControlCreated = new CallbackWithListeners();
    public final ICallbackWithListeners onControlDisposed = new CallbackWithListeners();
    private PydevCommonViewer viewer;
    private final PythonLinkHelper pythonLinkHelper = new PythonLinkHelper();
<commit_msg>Bug 987642: perform PYTHONPATH updates for drag & drop with folders that contain src folders.<commit_after>/**
 * Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
 * Licensed under the terms of the Eclipse Public License (EPL).
 * Please see the license.txt included with this distribution for details.
 * Any modifications to this file must keep this entire header intact.
 */
/*
 * Created on Oct 29, 2006
 * @author Fabio
 */
package org.python.pydev.navigator.ui;

import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.internal.resources.Folder;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.viewers.IElementComparer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IMemento;
import org.eclipse.ui.IURIEditorInput;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.internal.navigator.ContributorTrackingSet;
import org.eclipse.ui.internal.navigator.NavigatorContentService;
import org.eclipse.ui.navigator.CommonNavigator;
import org.eclipse.ui.navigator.CommonViewer;
import org.eclipse.ui.navigator.INavigatorPipelineService;
import org.eclipse.ui.navigator.PipelinedShapeModification;
import org.eclipse.ui.part.IShowInTarget;
import org.eclipse.ui.part.ShowInContext;
import org.python.pydev.core.IPythonPathNature;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.core.log.Log;
import org.python.pydev.editorinput.PydevZipFileEditorInput;
import org.python.pydev.editorinput.PydevZipFileStorage;
import org.python.pydev.navigator.LabelAndImage;
import org.python.pydev.navigator.actions.PythonLinkHelper;
import org.python.pydev.navigator.elements.IWrappedResource;
import org.python.pydev.navigator.elements.PythonSourceFolder;
import org.python.pydev.plugin.nature.PythonNature;
import org.python.pydev.shared_core.callbacks.CallbackWithListeners;
import org.python.pydev.shared_core.callbacks.ICallbackWithListeners;
import org.python.pydev.shared_core.structure.TreeNode;
import org.python.pydev.shared_ui.utils.IViewWithControls;
import org.python.pydev.ui.NotifyViewCreated;

/**
 * This class is the package explorer for pydev. It uses the CNF (Common Navigator Framework) to show
 * the resources as python elements.
 */
@SuppressWarnings({ "restriction", "rawtypes", "unchecked" })
public class PydevPackageExplorer extends CommonNavigator implements IShowInTarget, IViewWithControls {

    /**
     * This viewer is the one used instead of the common viewer -- should only be used to fix failures in the base class.
     */
    public static class PydevCommonViewer extends CommonViewer {

        /**
         * This is used so that we only restore the memento in the 'right' place
         */
        public boolean availableToRestoreMemento = false;

        /**
         * This is the pydev package explorer
         */
        private PydevPackageExplorer pydevPackageExplorer;

        public PydevPackageExplorer getPydevPackageExplorer() {
            return pydevPackageExplorer;
        }

        private ISelection cachedSelection;

        public PydevCommonViewer(String id, Composite parent, int style, PydevPackageExplorer pydevPackageExplorer) {
            super(id, parent, style);
            this.pydevPackageExplorer = pydevPackageExplorer;

            //We need to be able to compare actual resources and IWrappedResources
            //as if they were the same thing.
            setComparer(new IElementComparer() {

                public int hashCode(Object element) {
                    if (element instanceof IWrappedResource) {
                        IWrappedResource wrappedResource = (IWrappedResource) element;
                        return wrappedResource.getActualObject().hashCode();
                    }
                    return element.hashCode();
                }

                public boolean equals(Object a, Object b) {
                    if (a instanceof IWrappedResource) {
                        IWrappedResource wrappedResource = (IWrappedResource) a;
                        a = wrappedResource.getActualObject();
                    }
                    if (b instanceof IWrappedResource) {
                        IWrappedResource wrappedResource = (IWrappedResource) b;
                        b = wrappedResource.getActualObject();
                    }
                    if (a == null) {
                        if (b == null) {
                            return true;
                        } else {
                            return false;
                        }
                    }
                    if (b == null) {
                        return false;
                    }

                    return a.equals(b);
                }
            });
        }

        /**
         * Returns the tree path for the given item.
         * 
         * It's overridden because when using mylyn, the paths may be expanded but not shown, so segment is null
         * -- that's why we return null if a given segment is null (instead of the assert that it contains in the superclass) 
         * @since 3.2
         */
        @Override
        protected TreePath getTreePathFromItem(Item item) {
            LinkedList<Object> segments = new LinkedList<Object>();
            while (item != null) {
                Object segment = item.getData();
                if (segment == null) {
                    return null;
                }
                segments.addFirst(segment);
                item = getParentItem(item);
            }
            return new TreePath(segments.toArray());
        }

        /**
         * Returns the current selection.
         *
         * It's overridden because dragging & dropping non-source folders that contain source
         * folders doesn't recognize the inner source folders, resulting in ignored project
         * PYTHONPATH updates. This override treats such folders as PythonSourceFolders.
         */
        @Override
        public ISelection getSelection() {
            if (cachedSelection != null) {
                return cachedSelection;
            }
            Control control = getControl();
            if (control == null || control.isDisposed()) {
                return TreeSelection.EMPTY;
            }
            Widget[] items = getSelection(getControl());
            ArrayList list = new ArrayList(items.length);
            for (int i = 0; i < items.length; i++) {
                Widget item = items[i];
                Object data = item.getData();
                boolean madePySrc = false;
                if (data != null) {
                    if (data instanceof Folder) {
                        Folder folder = (Folder) data;
                        IProject project = folder.getProject();
                        IPythonPathNature pythonPathNature = PythonNature.getPythonPathNature(project);
                        if (pythonPathNature != null) {
                            try {
                                // Check if this project has children of the selection in its PYTHONPATH
                                String sourceString = pythonPathNature.getProjectSourcePath(true);
                                if (sourceString.contains(folder.getFullPath().addTrailingSeparator().toString())) {
                                    item.setData(new PythonSourceFolder(folder.getProject(), folder));
                                    madePySrc = true;
                                }
                            } catch (CoreException e) {
                                Log.log("Error accessing project source path", e);
                            }
                        }
                    }
                    list.add(getTreePathFromItem((Item) item));
                    if (madePySrc) {
                        item.setData(data);
                    }
                }
            }
            cachedSelection = new TreeSelection((TreePath[]) list.toArray(new TreePath[list
                    .size()]), getComparer());
            return cachedSelection;
        }

        /**
         * Clears the selection cache.
         */
        private void clearSelectionCache() {
            cachedSelection = null;
        }

        // Override any methods that clear the cache, so that a Pydev-specific cache can be used.
        @Override
        public void dispose() {
            clearSelectionCache();
            super.dispose();
        }

        @Override
        protected void hookControl(Control control) {
            super.hookControl(control);
            //FIXME - see super's fixme.
            control.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseDown(MouseEvent e) {
                    clearSelectionCache();
                }
            });
        }

        @Override
        protected void setSelectionToWidget(List v, boolean reveal) {
            clearSelectionCache();
            super.setSelectionToWidget(v, reveal);
        }

        @Override
        protected void handleDoubleSelect(SelectionEvent event) {
            clearSelectionCache();
            super.handleDoubleSelect(event);
        }

        @Override
        protected void handleOpen(SelectionEvent event) {
            clearSelectionCache();
            super.handleOpen(event);
        }

        @Override
        protected void handlePostSelect(SelectionEvent e) {
            clearSelectionCache();
            super.handlePostSelect(e);
        }

        @Override
        protected void handleSelect(SelectionEvent event) {
            clearSelectionCache();
            super.handleSelect(event);
        }
    }

    /**
     * This is the memento to be used.
     */
    private IMemento memento;
    public final ICallbackWithListeners onControlCreated = new CallbackWithListeners();
    public final ICallbackWithListeners onControlDisposed = new CallbackWithListeners();
    private PydevCommonViewer viewer;
    private final PythonLinkHelper pythonLinkHelper = new PythonLinkHelper();

{'fraction_non_alphanumeric': 0.08035353243602333, 'fraction_numerical': 0.0022529027785800934, 'mean_word_length': 2.1254739122585304, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4945327', 'n_tokens_mistral': 4530, 'n_tokens_neox': 4300, 'n_words': 1131}