Klaus Hartlage - www.eclipseproject.de
**********************************************************************/
-import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.DefaultPositionUpdater;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
-
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.eclipse.ui.texteditor.ITextEditor;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
/**
- * A content outline page which always represents the content of the
- * connected editor in 10 segments.
+ * A content outline page which always represents the functions of the
+ * connected PHPEditor.
*/
public class PHPContentOutlinePage extends ContentOutlinePage {
- /**
- * A segment element.
- */
- protected static class Segment {
- public String name;
- public Position position;
-
- public Segment(String name, Position position) {
- this.name= name;
- this.position= position;
- }
-
- public String toString() {
- return name;
- }
- };
-
- /**
- * Divides the editor's document into ten segments and provides elements for them.
- */
- protected class ContentProvider implements ITreeContentProvider {
-
- protected final static String SEGMENTS= "__java_segments"; //$NON-NLS-1$
- protected IPositionUpdater fPositionUpdater= new DefaultPositionUpdater(SEGMENTS);
- protected List fContent= new ArrayList(10);
-
- protected void parse(IDocument document) {
-
- int lines= document.getNumberOfLines();
- int increment= Math.max(Math.round((float) (lines / 10)), 10);
-
- for (int line= 0; line < lines; line += increment) {
-
- int length= increment;
- if (line + increment > lines)
- length= lines - line;
-
- try {
-
- int offset= document.getLineOffset(line);
- int end= document.getLineOffset(line + length);
- length= end - offset;
- Position p= new Position(offset, length);
- document.addPosition(SEGMENTS, p);
- fContent.add(new Segment(MessageFormat.format(PHPEditorMessages.getString("OutlinePage.segment.title_pattern"), new Object[] { new Integer(offset) }), p)); //$NON-NLS-1$
-
- } catch (BadPositionCategoryException x) {
- } catch (BadLocationException x) {
- }
- }
- }
-
- /*
- * @see IContentProvider#inputChanged(Viewer, Object, Object)
- */
- public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- if (oldInput != null) {
- IDocument document= fDocumentProvider.getDocument(oldInput);
- if (document != null) {
- try {
- document.removePositionCategory(SEGMENTS);
- } catch (BadPositionCategoryException x) {
- }
- document.removePositionUpdater(fPositionUpdater);
- }
- }
-
- fContent.clear();
-
- if (newInput != null) {
- IDocument document= fDocumentProvider.getDocument(newInput);
- if (document != null) {
- document.addPositionCategory(SEGMENTS);
- document.addPositionUpdater(fPositionUpdater);
-
- parse(document);
- }
- }
- }
-
- /*
- * @see IContentProvider#dispose
- */
- public void dispose() {
- if (fContent != null) {
- fContent.clear();
- fContent= null;
- }
- }
-
- /*
- * @see IContentProvider#isDeleted(Object)
- */
- public boolean isDeleted(Object element) {
- return false;
- }
-
- /*
- * @see IStructuredContentProvider#getElements(Object)
- */
- public Object[] getElements(Object element) {
- return fContent.toArray();
- }
-
- /*
- * @see ITreeContentProvider#hasChildren(Object)
- */
- public boolean hasChildren(Object element) {
- return element == fInput;
- }
-
- /*
- * @see ITreeContentProvider#getParent(Object)
- */
- public Object getParent(Object element) {
- if (element instanceof Segment)
- return fInput;
- return null;
- }
-
- /*
- * @see ITreeContentProvider#getChildren(Object)
- */
- public Object[] getChildren(Object element) {
- if (element == fInput)
- return fContent.toArray();
- return new Object[0];
- }
- };
-
- protected Object fInput;
- protected IDocumentProvider fDocumentProvider;
- protected ITextEditor fTextEditor;
-
- /**
- * Creates a content outline page using the given provider and the given editor.
- */
- public PHPContentOutlinePage(IDocumentProvider provider, ITextEditor editor) {
- super();
- fDocumentProvider= provider;
- fTextEditor= editor;
- }
-
- /* (non-Javadoc)
- * Method declared on ContentOutlinePage
- */
- public void createControl(Composite parent) {
-
- super.createControl(parent);
-
- TreeViewer viewer= getTreeViewer();
- viewer.setContentProvider(new ContentProvider());
- viewer.setLabelProvider(new LabelProvider());
- viewer.addSelectionChangedListener(this);
-
- if (fInput != null)
- viewer.setInput(fInput);
- }
-
- /* (non-Javadoc)
- * Method declared on ContentOutlinePage
- */
- public void selectionChanged(SelectionChangedEvent event) {
-
- super.selectionChanged(event);
-
- ISelection selection= event.getSelection();
- if (selection.isEmpty())
- fTextEditor.resetHighlightRange();
- else {
- Segment segment= (Segment) ((IStructuredSelection) selection).getFirstElement();
- int start= segment.position.getOffset();
- int length= segment.position.getLength();
- try {
- fTextEditor.setHighlightRange(start, length, true);
- } catch (IllegalArgumentException x) {
- fTextEditor.resetHighlightRange();
- }
- }
- }
-
- /**
- * Sets the input of the outline page
- */
- public void setInput(Object input) {
- fInput= input;
- update();
- }
-
- /**
- * Updates the outline page.
- */
- public void update() {
- TreeViewer viewer= getTreeViewer();
-
- if (viewer != null) {
- Control control= viewer.getControl();
- if (control != null && !control.isDisposed()) {
- control.setRedraw(false);
- viewer.setInput(fInput);
- viewer.expandAll();
- control.setRedraw(true);
- }
- }
- }
+ /**
+ * A segment element.
+ */
+ protected static class Segment {
+ public String name;
+ public Position position;
+
+ public Segment(String name, Position position) {
+ this.name = name;
+ this.position = position;
+ }
+
+ public String toString() {
+ return name;
+ }
+ };
+
+ protected static class SegmentComparator implements Comparator {
+ public int compare(Object o1, Object o2) {
+ return ((Segment)o1).name.compareToIgnoreCase(((Segment)o2).name);
+ }
+ }
+
+ /**
+ * Divides the editor's document into ten segments and provides elements for them.
+ */
+ protected class ContentProvider implements ITreeContentProvider {
+
+ protected final static String SEGMENTS = "__php_segments"; //$NON-NLS-1$
+ protected IPositionUpdater fPositionUpdater = new DefaultPositionUpdater(SEGMENTS);
+ protected List fContent = new ArrayList(10);
+ protected List fVariables = new ArrayList(100);
+
+ private String getIdentifier(String text, int firstIndex) {
+ int i = firstIndex;
+ char c;
+ int textLength = text.length();
+ StringBuffer identifier = new StringBuffer();
+ while (i < textLength) {
+ c = text.charAt(i++);
+ if (Character.isJavaIdentifierPart(c) || (c=='$')) {
+ identifier.append(c);
+ } else if ( (i==firstIndex+1) && (c=='$')) {
+ identifier.append(c);
+ } else {
+ return identifier.toString();
+ }
+ }
+ return null;
+ }
+
+ protected void parse(IDocument document) {
+
+ int lines = document.getNumberOfLines();
+ int increment = Math.max(Math.round((float) (lines / 10)), 10);
+
+ String text = document.get();
+ int lastIndex = 0;
+ int i = 0;
+ // lastIndex = text.indexOf("function ", lastIndex);
+ // while (lastIndex > 0) {
+ //
+ // try {
+ // i = lastIndex + 9;
+ // while ((i < text.length()) && Character.isJavaIdentifierPart(text.charAt(i))) {
+ // i++;
+ // }
+ // Position p = new Position(lastIndex, i - lastIndex);
+ // document.addPosition(SEGMENTS, p);
+ // fContent.add(new Segment(text.substring(lastIndex, i), p));
+ // // MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
+ // lastIndex = text.indexOf("function", lastIndex + 1);
+ // } catch (BadLocationException e) {
+ // } catch (BadPositionCategoryException e) {
+ // }
+ //
+ // }
+
+ boolean lineCommentMode = false;
+ boolean multiLineCommentMode = false;
+ boolean stringMode = false;
+ boolean functionMode = false;
+ String identifier;
+ int c;
+ int c2;
+
+ int textLength = text.length() - 10;
+ while (i < textLength) {
+ c = text.charAt(i++);
+ if (c == '\n') {
+ lineCommentMode = false;
+ // read until end of line
+ } else if (c == '#') {
+ // read until end of line
+ lineCommentMode = true;
+ continue;
+ } else if (c == '/') {
+ c2 = text.charAt(i++);
+ if (c2 == '/') {
+ lineCommentMode = true;
+ continue;
+ } else if (c2 == '*') {
+ multiLineCommentMode = true;
+ continue;
+ } else {
+ i--;
+ }
+ } else if (c == '*' && multiLineCommentMode) {
+ c2 = text.charAt(i++);
+ if (c2 == '/') {
+ multiLineCommentMode = false;
+ continue;
+ } else {
+ i--;
+ }
+ } else if (c == '\\' && stringMode) {
+ c2 = text.charAt(i++);
+ if (c2 == '"') {
+ continue;
+ } else {
+ i--;
+ }
+ } else if (c == '"') {
+ if (stringMode) {
+ stringMode = false;
+ } else {
+ stringMode = true;
+ }
+ continue;
+ }
+ if (lineCommentMode || multiLineCommentMode || stringMode) {
+ continue;
+ }
+
+ if (functionMode && Character.isJavaIdentifierPart((char) c)) {
+ functionMode = false;
+ lastIndex = i-1;
+ identifier = getIdentifier(text, lastIndex);
+ try {
+ i += identifier.length()-1;
+ Position p = new Position(lastIndex, i - lastIndex);
+ document.addPosition(SEGMENTS, p);
+ fContent.add(new Segment(text.substring(lastIndex, i), p));
+ // MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
+ // lastIndex = text.indexOf("function", lastIndex + 1);
+ } catch (BadLocationException e) {
+ } catch (BadPositionCategoryException e) {
+ }
+
+ } else if (c == 'f') {
+ identifier = getIdentifier(text, i - 1);
+ if (identifier.equals("function")) {
+ functionMode = true;
+ i+=8;
+ }
+ } else if (c == '$') {
+ // get the variable name
+ identifier = getIdentifier(text, i - 1);
+ fVariables.add( identifier );
+ }
+
+ }
+ Collections.sort(fContent, new SegmentComparator());
+ Collections.sort(fVariables);
+
+ // for (int line = 0; line < lines; line += increment) {
+ //
+ // int length = increment;
+ // if (line + increment > lines)
+ // length = lines - line;
+ //
+ // try {
+ //
+ // int offset = document.getLineOffset(line);
+ // int end = document.getLineOffset(line + length);
+ // length = end - offset;
+ // Position p = new Position(offset, length);
+ // document.addPosition(SEGMENTS, p);
+ // fContent.add(new Segment(MessageFormat.format(PHPEditorMessages.getString("OutlinePage.segment.title_pattern"), new Object[] { new Integer(offset)}), p)); //$NON-NLS-1$
+ //
+ // } catch (BadPositionCategoryException x) {
+ // } catch (BadLocationException x) {
+ // }
+ // }
+ }
+
+ /*
+ * @see IContentProvider#inputChanged(Viewer, Object, Object)
+ */
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ if (oldInput != null) {
+ IDocument document = fDocumentProvider.getDocument(oldInput);
+ if (document != null) {
+ try {
+ document.removePositionCategory(SEGMENTS);
+ } catch (BadPositionCategoryException x) {
+ }
+ document.removePositionUpdater(fPositionUpdater);
+ }
+ }
+
+ fContent.clear();
+ fVariables.clear();
+
+ if (newInput != null) {
+ IDocument document = fDocumentProvider.getDocument(newInput);
+ if (document != null) {
+ document.addPositionCategory(SEGMENTS);
+ document.addPositionUpdater(fPositionUpdater);
+
+ parse(document);
+ }
+ }
+ }
+
+ /*
+ * @see IContentProvider#dispose
+ */
+ public void dispose() {
+ if (fContent != null) {
+ fContent.clear();
+ fContent = null;
+ }
+ if (fVariables != null) {
+ fVariables.clear();
+ fVariables = null;
+ }
+ }
+
+ /*
+ * @see IContentProvider#isDeleted(Object)
+ */
+ public boolean isDeleted(Object element) {
+ return false;
+ }
+
+ /*
+ * @see IStructuredContentProvider#getElements(Object)
+ */
+ public Object[] getElements(Object element) {
+ return fContent.toArray();
+ }
+
+ /**
+ * returns all PHP variables
+ */
+ public Object[] getVariables() {
+ return fVariables.toArray();
+ }
+ /*
+ * @see ITreeContentProvider#hasChildren(Object)
+ */
+ public boolean hasChildren(Object element) {
+ return element == fInput;
+ }
+
+ /*
+ * @see ITreeContentProvider#getParent(Object)
+ */
+ public Object getParent(Object element) {
+ if (element instanceof Segment)
+ return fInput;
+ return null;
+ }
+
+ /*
+ * @see ITreeContentProvider#getChildren(Object)
+ */
+ public Object[] getChildren(Object element) {
+ if (element == fInput)
+ return fContent.toArray();
+ return new Object[0];
+ }
+ };
+
+ protected Object fInput;
+ protected IDocumentProvider fDocumentProvider;
+ protected ITextEditor fTextEditor;
+
+ /**
+ * Creates a content outline page using the given provider and the given editor.
+ */
+ public PHPContentOutlinePage(IDocumentProvider provider, ITextEditor editor) {
+ super();
+ fDocumentProvider = provider;
+ fTextEditor = editor;
+ }
+
+ /* (non-Javadoc)
+ * Method declared on ContentOutlinePage
+ */
+ public void createControl(Composite parent) {
+
+ super.createControl(parent);
+
+ TreeViewer viewer = getTreeViewer();
+ viewer.setContentProvider(new ContentProvider());
+ viewer.setLabelProvider(new LabelProvider());
+ viewer.addSelectionChangedListener(this);
+
+ if (fInput != null)
+ viewer.setInput(fInput);
+ }
+
+ /* (non-Javadoc)
+ * Method declared on ContentOutlinePage
+ */
+ public void selectionChanged(SelectionChangedEvent event) {
+
+ super.selectionChanged(event);
+
+ ISelection selection = event.getSelection();
+ if (selection.isEmpty())
+ fTextEditor.resetHighlightRange();
+ else {
+ Segment segment = (Segment) ((IStructuredSelection) selection).getFirstElement();
+ int start = segment.position.getOffset();
+ int length = segment.position.getLength();
+ try {
+ fTextEditor.setHighlightRange(start, length, true);
+ } catch (IllegalArgumentException x) {
+ fTextEditor.resetHighlightRange();
+ }
+ }
+ }
+
+ /**
+ * Sets the input of the outline page
+ */
+ public void setInput(Object input) {
+ fInput = input;
+ update();
+ }
+
+ /**
+ * Updates the outline page.
+ */
+ public void update() {
+ TreeViewer viewer = getTreeViewer();
+
+ if (viewer != null) {
+ Control control = viewer.getControl();
+ if (control != null && !control.isDisposed()) {
+ control.setRedraw(false);
+ viewer.setInput(fInput);
+ viewer.expandAll();
+ control.setRedraw(true);
+ }
+ }
+ }
}