|
From: <caw...@us...> - 2007-07-17 14:38:33
|
Revision: 2770
http://svn.sourceforge.net/rubyeclipse/?rev=2770&view=rev
Author: cawilliams
Date: 2007-07-17 07:38:30 -0700 (Tue, 17 Jul 2007)
Log Message:
-----------
more type hierarchy work
Added Paths:
-----------
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/ITypeHierarchyLifeCycleListener.java
trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/ITypeHierarchyLifeCycleListener.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/ITypeHierarchyLifeCycleListener.java (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/ITypeHierarchyLifeCycleListener.java 2007-07-17 14:38:30 UTC (rev 2770)
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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
+ *******************************************************************************/
+package org.rubypeople.rdt.internal.ui.typehierarchy;
+
+import org.rubypeople.rdt.core.IType;
+
+
+/**
+ * Used by the TypeHierarchyLifeCycle to inform listeners about a change in the
+ * type hierarchy
+ */
+public interface ITypeHierarchyLifeCycleListener {
+
+ /**
+ * A Java element changed.
+ */
+ void typeHierarchyChanged(TypeHierarchyLifeCycle typeHierarchyProvider, IType[] changedTypes);
+
+}
Property changes on: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/ITypeHierarchyLifeCycleListener.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Added: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java
===================================================================
--- trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java (rev 0)
+++ trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java 2007-07-17 14:38:30 UTC (rev 2770)
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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
+ *******************************************************************************/
+package org.rubypeople.rdt.internal.ui.typehierarchy;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.jface.operation.IRunnableContext;
+import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.rubypeople.rdt.core.ElementChangedEvent;
+import org.rubypeople.rdt.core.IElementChangedListener;
+import org.rubypeople.rdt.core.IRegion;
+import org.rubypeople.rdt.core.IRubyElement;
+import org.rubypeople.rdt.core.IRubyElementDelta;
+import org.rubypeople.rdt.core.IRubyProject;
+import org.rubypeople.rdt.core.IRubyScript;
+import org.rubypeople.rdt.core.ISourceFolder;
+import org.rubypeople.rdt.core.ISourceFolderRoot;
+import org.rubypeople.rdt.core.IType;
+import org.rubypeople.rdt.core.ITypeHierarchy;
+import org.rubypeople.rdt.core.ITypeHierarchyChangedListener;
+import org.rubypeople.rdt.core.RubyCore;
+import org.rubypeople.rdt.core.RubyModelException;
+import org.rubypeople.rdt.internal.corext.util.RubyModelUtil;
+import org.rubypeople.rdt.internal.ui.RubyPlugin;
+
+/**
+ * Manages a type hierarchy, to keep it refreshed, and to allow it to be shared.
+ */
+public class TypeHierarchyLifeCycle implements ITypeHierarchyChangedListener, IElementChangedListener {
+
+ private boolean fHierarchyRefreshNeeded;
+ private ITypeHierarchy fHierarchy;
+ private IRubyElement fInputElement;
+ private boolean fIsSuperTypesOnly;
+
+ private List fChangeListeners;
+
+ public TypeHierarchyLifeCycle() {
+ this(false);
+ }
+
+ public TypeHierarchyLifeCycle(boolean isSuperTypesOnly) {
+ fHierarchy= null;
+ fInputElement= null;
+ fIsSuperTypesOnly= isSuperTypesOnly;
+ fChangeListeners= new ArrayList(2);
+ }
+
+ public ITypeHierarchy getHierarchy() {
+ return fHierarchy;
+ }
+
+ public IRubyElement getInputElement() {
+ return fInputElement;
+ }
+
+
+ public void freeHierarchy() {
+ if (fHierarchy != null) {
+ fHierarchy.removeTypeHierarchyChangedListener(this);
+ RubyCore.removeElementChangedListener(this);
+ fHierarchy= null;
+ fInputElement= null;
+ }
+ }
+
+ public void removeChangedListener(ITypeHierarchyLifeCycleListener listener) {
+ fChangeListeners.remove(listener);
+ }
+
+ public void addChangedListener(ITypeHierarchyLifeCycleListener listener) {
+ if (!fChangeListeners.contains(listener)) {
+ fChangeListeners.add(listener);
+ }
+ }
+
+ private void fireChange(IType[] changedTypes) {
+ for (int i= fChangeListeners.size()-1; i>=0; i--) {
+ ITypeHierarchyLifeCycleListener curr= (ITypeHierarchyLifeCycleListener) fChangeListeners.get(i);
+ curr.typeHierarchyChanged(this, changedTypes);
+ }
+ }
+
+ public void ensureRefreshedTypeHierarchy(final IRubyElement element, IRunnableContext context) throws InvocationTargetException, InterruptedException {
+ if (element == null || !element.exists()) {
+ freeHierarchy();
+ return;
+ }
+ boolean hierachyCreationNeeded= (fHierarchy == null || !element.equals(fInputElement));
+
+ if (hierachyCreationNeeded || fHierarchyRefreshNeeded) {
+
+ IRunnableWithProgress op= new IRunnableWithProgress() {
+ public void run(IProgressMonitor pm) throws InvocationTargetException, InterruptedException {
+ try {
+ doHierarchyRefresh(element, pm);
+ } catch (RubyModelException e) {
+ throw new InvocationTargetException(e);
+ } catch (OperationCanceledException e) {
+ throw new InterruptedException();
+ }
+ }
+ };
+ fHierarchyRefreshNeeded= true;
+ context.run(true, true, op);
+ fHierarchyRefreshNeeded= false;
+ }
+ }
+
+ private ITypeHierarchy createTypeHierarchy(IRubyElement element, IProgressMonitor pm) throws RubyModelException {
+ if (element.getElementType() == IRubyElement.TYPE) {
+ IType type= (IType) element;
+ if (fIsSuperTypesOnly) {
+ return type.newSupertypeHierarchy(pm);
+ } else {
+ return type.newTypeHierarchy(pm);
+ }
+ } else {
+ IRegion region= RubyCore.newRegion();
+ if (element.getElementType() == IRubyElement.RUBY_PROJECT) {
+ // for projects only add the contained source folders
+ ISourceFolderRoot[] roots= ((IRubyProject) element).getSourceFolderRoots();
+ for (int i= 0; i < roots.length; i++) {
+ if (!roots[i].isExternal()) {
+ region.add(roots[i]);
+ }
+ }
+ } else if (element.getElementType() == IRubyElement.SOURCE_FOLDER) {
+ ISourceFolderRoot[] roots= element.getRubyProject().getSourceFolderRoots();
+ String name= element.getElementName();
+ for (int i= 0; i < roots.length; i++) {
+ ISourceFolder pack= roots[i].getSourceFolder(name);
+ if (pack.exists()) {
+ region.add(pack);
+ }
+ }
+ } else {
+ region.add(element);
+ }
+ IRubyProject jproject= element.getRubyProject();
+ return jproject.newTypeHierarchy(region, pm);
+ }
+ }
+
+
+ public synchronized void doHierarchyRefresh(IRubyElement element, IProgressMonitor pm) throws RubyModelException {
+ boolean hierachyCreationNeeded= (fHierarchy == null || !element.equals(fInputElement));
+ // to ensure the order of the two listeners always remove / add listeners on operations
+ // on type hierarchies
+ if (fHierarchy != null) {
+ fHierarchy.removeTypeHierarchyChangedListener(this);
+ RubyCore.removeElementChangedListener(this);
+ }
+ if (hierachyCreationNeeded) {
+ fHierarchy= createTypeHierarchy(element, pm);
+ if (pm != null && pm.isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ fInputElement= element;
+ } else {
+ fHierarchy.refresh(pm);
+ }
+ fHierarchy.addTypeHierarchyChangedListener(this);
+ RubyCore.addElementChangedListener(this);
+ fHierarchyRefreshNeeded= false;
+ }
+
+ /*
+ * @see ITypeHierarchyChangedListener#typeHierarchyChanged
+ */
+ public void typeHierarchyChanged(ITypeHierarchy typeHierarchy) {
+ fHierarchyRefreshNeeded= true;
+ fireChange(null);
+ }
+
+ /*
+ * @see IElementChangedListener#elementChanged(ElementChangedEvent)
+ */
+ public void elementChanged(ElementChangedEvent event) {
+ if (fChangeListeners.isEmpty()) {
+ return;
+ }
+
+ if (fHierarchyRefreshNeeded) {
+ return;
+ } else {
+ ArrayList changedTypes= new ArrayList();
+ processDelta(event.getDelta(), changedTypes);
+ if (changedTypes.size() > 0) {
+ fireChange((IType[]) changedTypes.toArray(new IType[changedTypes.size()]));
+ }
+ }
+ }
+
+ /*
+ * Assume that the hierarchy is intact (no refresh needed)
+ */
+ private void processDelta(IRubyElementDelta delta, ArrayList changedTypes) {
+ IRubyElement element= delta.getElement();
+ switch (element.getElementType()) {
+ case IRubyElement.TYPE:
+ processTypeDelta((IType) element, changedTypes);
+ processChildrenDelta(delta, changedTypes); // (inner types)
+ break;
+ case IRubyElement.RUBY_MODEL:
+ case IRubyElement.RUBY_PROJECT:
+ case IRubyElement.SOURCE_FOLDER_ROOT:
+ case IRubyElement.SOURCE_FOLDER:
+ processChildrenDelta(delta, changedTypes);
+ break;
+ case IRubyElement.SCRIPT:
+ IRubyScript cu= (IRubyScript)element;
+ if (!RubyModelUtil.isPrimary(cu)) {
+ return;
+ }
+
+ if (delta.getKind() == IRubyElementDelta.CHANGED && isPossibleStructuralChange(delta.getFlags())) {
+ try {
+ if (cu.exists()) {
+ IType[] types= cu.getAllTypes();
+ for (int i= 0; i < types.length; i++) {
+ processTypeDelta(types[i], changedTypes);
+ }
+ }
+ } catch (RubyModelException e) {
+ RubyPlugin.log(e);
+ }
+ } else {
+ processChildrenDelta(delta, changedTypes);
+ }
+ break;
+ }
+ }
+
+ private boolean isPossibleStructuralChange(int flags) {
+ return (flags & (IRubyElementDelta.F_CONTENT | IRubyElementDelta.F_FINE_GRAINED)) == IRubyElementDelta.F_CONTENT;
+ }
+
+ private void processTypeDelta(IType type, ArrayList changedTypes) {
+ if (getHierarchy().contains(type)) {
+ changedTypes.add(type);
+ }
+ }
+
+ private void processChildrenDelta(IRubyElementDelta delta, ArrayList changedTypes) {
+ IRubyElementDelta[] children= delta.getAffectedChildren();
+ for (int i= 0; i < children.length; i++) {
+ processDelta(children[i], changedTypes); // recursive
+ }
+ }
+
+
+}
Property changes on: trunk/org.rubypeople.rdt.ui/src/org/rubypeople/rdt/internal/ui/typehierarchy/TypeHierarchyLifeCycle.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|