⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pythonbasemodelprovider.java

📁 Python Development Environment (Python IDE plugin for Eclipse). Features editor, code completion, re
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
 * Created on Oct 11, 2006
 * @author Fabio
 */
package org.python.pydev.navigator;

import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
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.IWorkspace;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.model.BaseWorkbenchContentProvider;
import org.python.pydev.core.ICodeCompletionASTManager;
import org.python.pydev.core.IModule;
import org.python.pydev.core.IModulesManager;
import org.python.pydev.core.ModulesKey;
import org.python.pydev.editor.codecompletion.revisited.ProjectModulesManager;
import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper;
import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule;
import org.python.pydev.navigator.elements.IWrappedResource;
import org.python.pydev.navigator.elements.PythonFile;
import org.python.pydev.navigator.elements.PythonFolder;
import org.python.pydev.navigator.elements.PythonNode;
import org.python.pydev.navigator.elements.PythonProjectSourceFolder;
import org.python.pydev.navigator.elements.PythonResource;
import org.python.pydev.navigator.elements.PythonSourceFolder;
import org.python.pydev.outline.ParsedItem;
import org.python.pydev.parser.visitors.scope.ASTEntryWithChildren;
import org.python.pydev.parser.visitors.scope.OutlineCreatorVisitor;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.plugin.nature.IPythonNatureListener;
import org.python.pydev.plugin.nature.PythonNature;
import org.python.pydev.plugin.nature.PythonNatureListenersManager;

/**
 * A good part of the refresh for the model was gotten from org.eclipse.ui.model.WorkbenchContentProvider
 * (mostly just changed the way to get content changes in python files)
 * 
 * There are other important notifications that we need to learn about. 
 * Namely:
 *  - When a source folder is created
 *  - When the way to see it changes (flat or not)
 * 
 * @author Fabio
 */
public class PythonBaseModelProvider extends BaseWorkbenchContentProvider implements IResourceChangeListener, IPythonNatureListener {

    /**
     * Object representing an empty array.
     */
    private static final Object[] EMPTY = new Object[0];

    /**
     * These are the source folders that can be found in this file provider. The way we
     * see things in this provider, the python model starts only after some source folder
     * is found.
     */
    private Map<IProject, Set<PythonSourceFolder>> projectToSourceFolders = new HashMap<IProject, Set<PythonSourceFolder>>();
    
    /**
     * This is the viewer that we're using to see the contents of this file provider.
     */
    protected Viewer viewer;
    
    /**
     * Constructor... registers itself as a python nature listener
     */
    public PythonBaseModelProvider(){
        PythonNatureListenersManager.addPythonNatureListener(this);
    }
    
    public static final boolean DEBUG = false;
    
    /**
     * Notification received when the pythonpath has been changed or rebuilt.
     */
    public void notifyPythonPathRebuilt(IProject project, List<String> projectPythonpath) {
    	internalDoNotifyPythonPathRebuilt(project, projectPythonpath);
    }

    /**
     * This is the actual implementation of the rebuild. 
     * 
     * @return the element that should be refreshed.
     */
    public IResource internalDoNotifyPythonPathRebuilt(IProject project, List<String> projectPythonpath) {
        IResource refreshObject = project;
        if(DEBUG){
    		System.out.println("\n\nRebuilding pythonpath: "+project+" - "+projectPythonpath);
    	}
    	HashSet<Path> projectPythonpathSet = new HashSet<Path>();
    	for (String string : projectPythonpath) {
    		Path newPath = new Path(string);
    		if(project.getLocation().equals(newPath)){
    		    refreshObject = project.getParent();
    		}
            projectPythonpathSet.add(newPath);
		}

        Map<IProject, Set<PythonSourceFolder>> p = projectToSourceFolders;
        if(p != null){
        	Set<PythonSourceFolder> existingSourceFolders = p.get(project);
        	
        	//iterate in a copy
        	for (PythonSourceFolder pythonSourceFolder : new HashSet<PythonSourceFolder>(existingSourceFolders)) {
				IPath fullPath = pythonSourceFolder.container.getLocation();
				if(!projectPythonpathSet.contains(fullPath)){
				    if(pythonSourceFolder instanceof PythonProjectSourceFolder){
				        refreshObject = project.getParent();
				    }
					existingSourceFolders.remove(pythonSourceFolder);//it's not a valid source folder anymore...
					if(DEBUG){
						System.out.println("Removing:"+pythonSourceFolder+" - "+fullPath);
					}
				}
			}
        }
        
        
        Runnable refreshRunnable = getRefreshRunnable(refreshObject);
        final Collection<Runnable> runnables = new ArrayList<Runnable>();
        runnables.add(refreshRunnable);
        processRunnables(runnables);
        return refreshObject;
    }
    
    /**
     * @see PythonModelProvider#getResourceInPythonModel(IResource, boolean, boolean)
     */
    protected Object getResourceInPythonModel(IResource object) {
        return getResourceInPythonModel(object, false, false);
    }
    
    /**
     * @see PythonModelProvider#getResourceInPythonModel(IResource, boolean, boolean)
     */
    protected Object getResourceInPythonModel(IResource object, boolean returnNullIfNotFound) {
        return getResourceInPythonModel(object, false, returnNullIfNotFound);
    }
    
    /**
     * Given some IResource in the filesystem, return the representation for it in the python model
     * or the resource itself if it could not be found in the python model.
     * 
     * Note that this method only returns some resource already created (it does not 
     * create some resource if it still does not exist)
     */
    protected Object getResourceInPythonModel(IResource object, boolean removeFoundResource, boolean returnNullIfNotFound) {
        if(DEBUG){
            System.out.println("Getting resource in python model:"+object);
        }
        Set<PythonSourceFolder> sourceFolders = getProjectSourceFolders(object.getProject());
        Object f = null;
        PythonSourceFolder sourceFolder = null;
        
        for (Iterator<PythonSourceFolder> it = sourceFolders.iterator();f == null && it.hasNext();) {
            sourceFolder = it.next();
            if(sourceFolder.getActualObject().equals(object)){
                f = sourceFolder;
            }else{
                f = sourceFolder.getChild(object);
            }
        }
        if(f == null){
            if(returnNullIfNotFound){
                return null;
            }else{
                return object;
            }
        }else{
            if(removeFoundResource){
                if(f == sourceFolder){
                    sourceFolders.remove(f);
                }else{
                    sourceFolder.removeChild(object);
                }
            }
        }
        return f;
    }

    /**
     * @param object: the resource we're interested in
     * @return a set with the PythonSourceFolder that exist in the project that contains it
     */
    protected Set<PythonSourceFolder> getProjectSourceFolders(IProject project) {
        Map<IProject, Set<PythonSourceFolder>> p = projectToSourceFolders;
        //may be already disposed
        if(p != null){
            Set<PythonSourceFolder> sourceFolder = p.get(project);
            if(sourceFolder == null){
                sourceFolder = new HashSet<PythonSourceFolder>();
                p.put(project, sourceFolder);
            }
            return sourceFolder;
        }
        return new HashSet<PythonSourceFolder>();
    }
    
    /**
     * @return whether there are children for the given element. Note that there is 
     * an optimization in this method, so that it works correctly for elements that 
     * are not python files, and returns true if it is a python file with any content
     * (even if that content does not actually map to a node. 
     * 
     * @see org.eclipse.ui.model.BaseWorkbenchContentProvider#hasChildren(java.lang.Object)
     */
    public boolean hasChildren(Object element) {
        if(element instanceof PythonFile){
            PythonFile f = (PythonFile) element;
            if(PythonPathHelper.isValidSourceFile(f.getActualObject())){
                try {
                    InputStream contents = f.getContents();
                    try{
                        if(contents.read() == -1){
                            return false; //if there is no content in the file, it has no children
                        }else{
                            return true; //if it has any content, it has children (performance reasons)
                        }
                    }finally{
                        contents.close();
                    }
                } catch (Exception e) {
                    PydevPlugin.log(e);
                    return false;
                }
            }
            return false; 
        }
        return getChildren(element).length > 0;
    }


    /**
     * The inputs for this method are:
     * 
     * IWorkingSet (in which case it will return the projects -- IResource -- that are a part of the working set)
     * IResource (in which case it will return IWrappedResource or IResources)
     * IWrappedResource (in which case it will return IWrappedResources)
     * 
     * @return the children for some element (IWrappedResource or IResource)
     */
    public Object[] getChildren(Object parentElement) {
        
        //------------------------------------------- for the working set, just return the children directly
//        if(parentElement instanceof IWorkingSet){
//            IWorkingSet set = (IWorkingSet) parentElement;
//            return set.getElements();
//        }
        
        Object[] childrenToReturn = null;
        
        if(parentElement instanceof IWrappedResource){
            // we're below some python model
            childrenToReturn = getChildrenForIWrappedResource((IWrappedResource) parentElement);
            
            
        } else if(parentElement instanceof IResource || parentElement instanceof IWorkingSet){
            // now, this happens if we're not below a python model(so, we may only find a source folder here)
            childrenToReturn = getChildrenForIResourceOrWorkingSet(parentElement);
        }
        
        if(childrenToReturn == null){
            return EMPTY;
        }
        return childrenToReturn;
    }

    /**
     * @param parentElement an IResource from where we want to get the children (or a working set)
     *  
     * @return as we're not below a source folder here, we have still not entered the 'python' domain,
     * and as the starting point for the 'python' domain is always a source folder, the things
     * that can be returned are IResources and PythonSourceFolders.
     */
    private Object[] getChildrenForIResourceOrWorkingSet(Object parentElement) {
        PythonNature nature = null;
        IProject project = null;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -