1 package net.sourceforge.phpeclipse.phpeditor;
 
   3 /**********************************************************************
 
   4 Copyright (c) 2000, 2002 IBM Corp. and others.
 
   5 All rights reserved. This program and the accompanying materials
 
   6 are made available under the terms of the Common Public License v1.0
 
   7 which accompanies this distribution, and is available at
 
   8 http://www.eclipse.org/legal/cpl-v10.html
 
  11     IBM Corporation - Initial implementation
 
  12     Klaus Hartlage - www.eclipseproject.de
 
  13 **********************************************************************/
 
  15 import java.util.ArrayList;
 
  16 import java.util.Collections;
 
  17 import java.util.Comparator;
 
  18 import java.util.List;
 
  20 import org.eclipse.jface.text.BadLocationException;
 
  21 import org.eclipse.jface.text.BadPositionCategoryException;
 
  22 import org.eclipse.jface.text.DefaultPositionUpdater;
 
  23 import org.eclipse.jface.text.IDocument;
 
  24 import org.eclipse.jface.text.IPositionUpdater;
 
  25 import org.eclipse.jface.text.Position;
 
  26 import org.eclipse.jface.viewers.ISelection;
 
  27 import org.eclipse.jface.viewers.IStructuredSelection;
 
  28 import org.eclipse.jface.viewers.ITreeContentProvider;
 
  29 import org.eclipse.jface.viewers.LabelProvider;
 
  30 import org.eclipse.jface.viewers.SelectionChangedEvent;
 
  31 import org.eclipse.jface.viewers.TreeViewer;
 
  32 import org.eclipse.jface.viewers.Viewer;
 
  33 import org.eclipse.swt.widgets.Composite;
 
  34 import org.eclipse.swt.widgets.Control;
 
  35 import org.eclipse.ui.texteditor.IDocumentProvider;
 
  36 import org.eclipse.ui.texteditor.ITextEditor;
 
  37 import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
 
  40  * A content outline page which always represents the functions of the
 
  41  * connected PHPEditor.
 
  43 public class PHPContentOutlinePage extends ContentOutlinePage {
 
  44   private static final String ERROR = "error"; //$NON-NLS-1$
 
  45   private static final String WARNING = "warning"; //$NON-NLS-1$
 
  49   protected static class Segment {
 
  51     public Position position;
 
  53     public Segment(String name, Position position) {
 
  55       this.position = position;
 
  58     public String toString() {
 
  63   protected static class SegmentComparator implements Comparator {
 
  64     public int compare(Object o1, Object o2) {
 
  65       return ((Segment) o1).name.compareToIgnoreCase(((Segment) o2).name);
 
  70    * Divides the editor's document into ten segments and provides elements for them.
 
  72   protected class ContentProvider implements ITreeContentProvider {
 
  74     protected final static String SEGMENTS = "__php_segments"; //$NON-NLS-1$
 
  75     protected IPositionUpdater fPositionUpdater = new DefaultPositionUpdater(SEGMENTS);
 
  76     protected List fContent = new ArrayList(10);
 
  77     protected List fVariables = new ArrayList(100);
 
  79     private String getIdentifier(String text, int firstIndex) {
 
  82       int textLength = text.length();
 
  83       StringBuffer identifier = new StringBuffer();
 
  84       while (i < textLength) {
 
  86         if (Character.isJavaIdentifierPart(c) || (c == '$')) {
 
  88         } else if ((i == firstIndex + 1) && (c == '$')) {
 
  91           return identifier.toString();
 
  97     protected void parse(IDocument document) {
 
  99       int lines = document.getNumberOfLines();
 
 100       int increment = Math.max(Math.round((float) (lines / 10)), 10);
 
 102       String text = document.get();
 
 105       //      lastIndex = text.indexOf("function ", lastIndex);
 
 106       //      while (lastIndex > 0) {
 
 109       //          i = lastIndex + 9;
 
 110       //          while ((i < text.length()) && Character.isJavaIdentifierPart(text.charAt(i))) {
 
 113       //          Position p = new Position(lastIndex, i - lastIndex);
 
 114       //          document.addPosition(SEGMENTS, p);
 
 115       //          fContent.add(new Segment(text.substring(lastIndex, i), p));
 
 116       //          //     MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
 
 117       //          lastIndex = text.indexOf("function", lastIndex + 1);
 
 118       //        } catch (BadLocationException e) {
 
 119       //        } catch (BadPositionCategoryException e) {
 
 124       boolean lineCommentMode = false;
 
 125       boolean multiLineCommentMode = false;
 
 126       boolean stringMode = false;
 
 127       boolean functionMode = false;
 
 132       int textLength = text.length() - 10;
 
 133       while (i < textLength) {
 
 134         c = text.charAt(i++);
 
 136           lineCommentMode = false;
 
 137           // read until end of line
 
 138         } else if (c == '#') {
 
 139           // read until end of line
 
 140           lineCommentMode = true;
 
 142         } else if (c == '/') {
 
 143           c2 = text.charAt(i++);
 
 145             lineCommentMode = true;
 
 147           } else if (c2 == '*') {
 
 148             multiLineCommentMode = true;
 
 153         } else if (c == '*' && multiLineCommentMode) {
 
 154           c2 = text.charAt(i++);
 
 156             multiLineCommentMode = false;
 
 161         } else if (c == '\\' && stringMode) {
 
 162           c2 = text.charAt(i++);
 
 168         } else if (c == '"') {
 
 176         if (lineCommentMode || multiLineCommentMode || stringMode) {
 
 180         if (functionMode && Character.isJavaIdentifierPart((char) c)) {
 
 181           functionMode = false;
 
 183           identifier = getIdentifier(text, lastIndex);
 
 185             i += identifier.length() - 1;
 
 186             Position p = new Position(lastIndex, i - lastIndex);
 
 187             document.addPosition(SEGMENTS, p);
 
 188             fContent.add(new Segment(text.substring(lastIndex, i), p));
 
 189             //     MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
 
 190             //    lastIndex = text.indexOf("function", lastIndex + 1);
 
 191           } catch (BadLocationException e) {
 
 192           } catch (BadPositionCategoryException e) {
 
 195         } else if (c == 'f') {
 
 196           identifier = getIdentifier(text, i - 1);
 
 197           if (identifier.equals("function")) {
 
 201         } else if (c == '$') {
 
 202           // get the variable name
 
 203           identifier = getIdentifier(text, i - 1);
 
 204           fVariables.add(identifier);
 
 208       Collections.sort(fContent, new SegmentComparator());
 
 209       Collections.sort(fVariables);
 
 211       //                        for (int line = 0; line < lines; line += increment) {
 
 213       //                                int length = increment;
 
 214       //                                if (line + increment > lines)
 
 215       //                                        length = lines - line;
 
 219       //                                        int offset = document.getLineOffset(line);
 
 220       //                                        int end = document.getLineOffset(line + length);
 
 221       //                                        length = end - offset;
 
 222       //                                        Position p = new Position(offset, length);
 
 223       //                                        document.addPosition(SEGMENTS, p);
 
 224       //                                        fContent.add(new Segment(MessageFormat.format(PHPEditorMessages.getString("OutlinePage.segment.title_pattern"), new Object[] { new Integer(offset)}), p)); //$NON-NLS-1$
 
 226       //                                } catch (BadPositionCategoryException x) {
 
 227       //                                } catch (BadLocationException x) {
 
 233      * @see IContentProvider#inputChanged(Viewer, Object, Object)
 
 235     public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
 
 236       if (oldInput != null) {
 
 237         IDocument document = fDocumentProvider.getDocument(oldInput);
 
 238         if (document != null) {
 
 240             document.removePositionCategory(SEGMENTS);
 
 241           } catch (BadPositionCategoryException x) {
 
 243           document.removePositionUpdater(fPositionUpdater);
 
 250       if (newInput != null) {
 
 251         IDocument document = fDocumentProvider.getDocument(newInput);
 
 252         if (document != null) {
 
 253           document.addPositionCategory(SEGMENTS);
 
 254           document.addPositionUpdater(fPositionUpdater);
 
 262      * @see IContentProvider#dispose
 
 264     public void dispose() {
 
 265       if (fContent != null) {
 
 269       if (fVariables != null) {
 
 276      * @see IContentProvider#isDeleted(Object)
 
 278     public boolean isDeleted(Object element) {
 
 283      * @see IStructuredContentProvider#getElements(Object)
 
 285     public Object[] getElements(Object element) {
 
 286       return fContent.toArray();
 
 290      * returns all PHP variables
 
 292     public Object[] getVariables() {
 
 293       return fVariables.toArray();
 
 296      * @see ITreeContentProvider#hasChildren(Object)
 
 298     public boolean hasChildren(Object element) {
 
 299       return element == fInput;
 
 303      * @see ITreeContentProvider#getParent(Object)
 
 305     public Object getParent(Object element) {
 
 306       if (element instanceof Segment)
 
 312      * @see ITreeContentProvider#getChildren(Object)
 
 314     public Object[] getChildren(Object element) {
 
 315       if (element == fInput)
 
 316         return fContent.toArray();
 
 317       return new Object[0];
 
 321   protected Object fInput;
 
 322   protected IDocumentProvider fDocumentProvider;
 
 323   protected ITextEditor fTextEditor;
 
 326    * Creates a content outline page using the given provider and the given editor.
 
 328   public PHPContentOutlinePage(IDocumentProvider provider, ITextEditor editor) {
 
 330     fDocumentProvider = provider;
 
 331     fTextEditor = editor;
 
 335    * Method declared on ContentOutlinePage
 
 337   public void createControl(Composite parent) {
 
 339     super.createControl(parent);
 
 341     TreeViewer viewer = getTreeViewer();
 
 342     viewer.setContentProvider(new ContentProvider());
 
 343     viewer.setLabelProvider(new LabelProvider());
 
 344     viewer.addSelectionChangedListener(this);
 
 347       viewer.setInput(fInput);
 
 351    * Method declared on ContentOutlinePage
 
 353   public void selectionChanged(SelectionChangedEvent event) {
 
 355     super.selectionChanged(event);
 
 357     ISelection selection = event.getSelection();
 
 358     if (selection.isEmpty())
 
 359       fTextEditor.resetHighlightRange();
 
 361       Segment segment = (Segment) ((IStructuredSelection) selection).getFirstElement();
 
 362       int start = segment.position.getOffset();
 
 363       int length = segment.position.getLength();
 
 365         fTextEditor.setHighlightRange(start, length, true);
 
 366       } catch (IllegalArgumentException x) {
 
 367         fTextEditor.resetHighlightRange();
 
 373    * Sets the input of the outline page
 
 375   public void setInput(Object input) {
 
 381    * Updates the outline page.
 
 383   public void update() {
 
 384     TreeViewer viewer = getTreeViewer();
 
 386     if (viewer != null) {
 
 387       Control control = viewer.getControl();
 
 388       if (control != null && !control.isDisposed()) {
 
 389         control.setRedraw(false);
 
 390         viewer.setInput(fInput);
 
 392         control.setRedraw(true);