1bf4dbec1c90b67d39378109e96e6400ed39573e
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPContentOutlinePage.java
1 package net.sourceforge.phpeclipse.phpeditor;
2
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
9
10 Contributors:
11     IBM Corporation - Initial implementation
12     Klaus Hartlage - www.eclipseproject.de
13 **********************************************************************/
14
15 import java.util.ArrayList;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.List;
19
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;
38
39 /**
40  * A content outline page which always represents the functions of the
41  * connected PHPEditor.
42  */
43 public class PHPContentOutlinePage extends ContentOutlinePage {
44
45   /**
46    * A segment element.
47    */
48   protected static class Segment {
49     public String name;
50     public Position position;
51
52     public Segment(String name, Position position) {
53       this.name = name;
54       this.position = position;
55     }
56
57     public String toString() {
58       return name;
59     }
60   };
61   
62   protected static class SegmentComparator implements Comparator {
63     public int compare(Object o1, Object o2) {
64       return ((Segment)o1).name.compareToIgnoreCase(((Segment)o2).name);
65     }
66   }
67
68   /**
69    * Divides the editor's document into ten segments and provides elements for them.
70    */
71   protected class ContentProvider implements ITreeContentProvider {
72
73     protected final static String SEGMENTS = "__php_segments"; //$NON-NLS-1$
74     protected IPositionUpdater fPositionUpdater = new DefaultPositionUpdater(SEGMENTS);
75     protected List fContent = new ArrayList(10);
76     protected List fVariables = new ArrayList(100);
77
78     private String getIdentifier(String text, int firstIndex) {
79       int i = firstIndex;
80       char c;
81       int textLength = text.length();
82       StringBuffer identifier = new StringBuffer();
83       while (i < textLength) {
84         c = text.charAt(i++);
85         if (Character.isJavaIdentifierPart(c) || (c=='$')) {
86           identifier.append(c);
87         } else if ( (i==firstIndex+1) && (c=='$')) {
88           identifier.append(c);
89         } else {
90           return identifier.toString();
91         }
92       }
93       return null;
94     }
95
96     protected void parse(IDocument document) {
97
98       int lines = document.getNumberOfLines();
99       int increment = Math.max(Math.round((float) (lines / 10)), 10);
100
101       String text = document.get();
102       int lastIndex = 0;
103       int i = 0;
104       //      lastIndex = text.indexOf("function ", lastIndex);
105       //      while (lastIndex > 0) {
106       //
107       //        try {
108       //          i = lastIndex + 9;
109       //          while ((i < text.length()) && Character.isJavaIdentifierPart(text.charAt(i))) {
110       //            i++;
111       //          }
112       //          Position p = new Position(lastIndex, i - lastIndex);
113       //          document.addPosition(SEGMENTS, p);
114       //          fContent.add(new Segment(text.substring(lastIndex, i), p));
115       //          //     MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
116       //          lastIndex = text.indexOf("function", lastIndex + 1);
117       //        } catch (BadLocationException e) {
118       //        } catch (BadPositionCategoryException e) {
119       //        }
120       //
121       //      }
122
123       boolean lineCommentMode = false;
124       boolean multiLineCommentMode = false;
125       boolean stringMode = false;
126       boolean functionMode = false;
127       String identifier;
128       int c;
129       int c2;
130
131       int textLength = text.length() - 10;
132       while (i < textLength) {
133         c = text.charAt(i++);
134         if (c == '\n') {
135           lineCommentMode = false;
136           // read until end of line
137         } else if (c == '#') {
138           // read until end of line
139           lineCommentMode = true;
140           continue;
141         } else if (c == '/') {
142           c2 = text.charAt(i++);
143           if (c2 == '/') {
144             lineCommentMode = true;
145             continue;
146           } else if (c2 == '*') {
147             multiLineCommentMode = true;
148             continue;
149           } else {
150             i--;
151           }
152         } else if (c == '*' && multiLineCommentMode) {
153           c2 = text.charAt(i++);
154           if (c2 == '/') {
155             multiLineCommentMode = false;
156             continue;
157           } else {
158             i--;
159           }
160         } else if (c == '\\' && stringMode) {
161           c2 = text.charAt(i++);
162           if (c2 == '"') {
163             continue;
164           } else {
165             i--;
166           }
167         } else if (c == '"') {
168           if (stringMode) {
169             stringMode = false;
170           } else {
171             stringMode = true;
172           }
173           continue;
174         }
175         if (lineCommentMode || multiLineCommentMode || stringMode) {
176           continue;
177         }
178
179         if (functionMode && Character.isJavaIdentifierPart((char) c)) {
180           functionMode = false;
181           lastIndex = i-1;
182           identifier = getIdentifier(text, lastIndex);
183           try {
184             i += identifier.length()-1;
185             Position p = new Position(lastIndex, i - lastIndex);
186             document.addPosition(SEGMENTS, p);
187             fContent.add(new Segment(text.substring(lastIndex, i), p));
188             //     MessageFormat.format("function", new Object[] { new Integer(lastIndex)}), p)); //$NON-NLS-1$
189             //    lastIndex = text.indexOf("function", lastIndex + 1);
190           } catch (BadLocationException e) {
191           } catch (BadPositionCategoryException e) {
192           }
193
194         } else if (c == 'f') {
195           identifier = getIdentifier(text, i - 1);
196           if (identifier.equals("function")) {
197             functionMode = true;
198             i+=8;
199           }
200         } else if (c == '$') {
201           // get the variable name
202           identifier = getIdentifier(text, i - 1);
203           fVariables.add( identifier );
204         }
205
206       }
207       Collections.sort(fContent, new SegmentComparator());
208       Collections.sort(fVariables);
209
210       //                        for (int line = 0; line < lines; line += increment) {
211       //
212       //                                int length = increment;
213       //                                if (line + increment > lines)
214       //                                        length = lines - line;
215       //
216       //                                try {
217       //
218       //                                        int offset = document.getLineOffset(line);
219       //                                        int end = document.getLineOffset(line + length);
220       //                                        length = end - offset;
221       //                                        Position p = new Position(offset, length);
222       //                                        document.addPosition(SEGMENTS, p);
223       //                                        fContent.add(new Segment(MessageFormat.format(PHPEditorMessages.getString("OutlinePage.segment.title_pattern"), new Object[] { new Integer(offset)}), p)); //$NON-NLS-1$
224       //
225       //                                } catch (BadPositionCategoryException x) {
226       //                                } catch (BadLocationException x) {
227       //                                }
228       //                        }
229     }
230
231     /*
232      * @see IContentProvider#inputChanged(Viewer, Object, Object)
233      */
234     public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
235       if (oldInput != null) {
236         IDocument document = fDocumentProvider.getDocument(oldInput);
237         if (document != null) {
238           try {
239             document.removePositionCategory(SEGMENTS);
240           } catch (BadPositionCategoryException x) {
241           }
242           document.removePositionUpdater(fPositionUpdater);
243         }
244       }
245
246       fContent.clear();
247       fVariables.clear();
248
249       if (newInput != null) {
250         IDocument document = fDocumentProvider.getDocument(newInput);
251         if (document != null) {
252           document.addPositionCategory(SEGMENTS);
253           document.addPositionUpdater(fPositionUpdater);
254
255           parse(document);
256         }
257       }
258     }
259
260     /*
261      * @see IContentProvider#dispose
262      */
263     public void dispose() {
264       if (fContent != null) {
265         fContent.clear();
266         fContent = null;
267       }
268             if (fVariables != null) {
269         fVariables.clear();
270         fVariables = null;
271       }
272     }
273
274     /*
275      * @see IContentProvider#isDeleted(Object)
276      */
277     public boolean isDeleted(Object element) {
278       return false;
279     }
280
281     /*
282      * @see IStructuredContentProvider#getElements(Object)
283      */
284     public Object[] getElements(Object element) {
285       return fContent.toArray();
286     }
287
288     /**
289      * returns all PHP variables
290      */
291     public Object[] getVariables() {
292       return fVariables.toArray();
293     }
294     /*
295      * @see ITreeContentProvider#hasChildren(Object)
296      */
297     public boolean hasChildren(Object element) {
298       return element == fInput;
299     }
300
301     /*
302      * @see ITreeContentProvider#getParent(Object)
303      */
304     public Object getParent(Object element) {
305       if (element instanceof Segment)
306         return fInput;
307       return null;
308     }
309
310     /*
311      * @see ITreeContentProvider#getChildren(Object)
312      */
313     public Object[] getChildren(Object element) {
314       if (element == fInput)
315         return fContent.toArray();
316       return new Object[0];
317     }
318   };
319
320   protected Object fInput;
321   protected IDocumentProvider fDocumentProvider;
322   protected ITextEditor fTextEditor;
323
324   /**
325    * Creates a content outline page using the given provider and the given editor.
326    */
327   public PHPContentOutlinePage(IDocumentProvider provider, ITextEditor editor) {
328     super();
329     fDocumentProvider = provider;
330     fTextEditor = editor;
331   }
332
333   /* (non-Javadoc)
334    * Method declared on ContentOutlinePage
335    */
336   public void createControl(Composite parent) {
337
338     super.createControl(parent);
339
340     TreeViewer viewer = getTreeViewer();
341     viewer.setContentProvider(new ContentProvider());
342     viewer.setLabelProvider(new LabelProvider());
343     viewer.addSelectionChangedListener(this);
344
345     if (fInput != null)
346       viewer.setInput(fInput);
347   }
348
349   /* (non-Javadoc)
350    * Method declared on ContentOutlinePage
351    */
352   public void selectionChanged(SelectionChangedEvent event) {
353
354     super.selectionChanged(event);
355
356     ISelection selection = event.getSelection();
357     if (selection.isEmpty())
358       fTextEditor.resetHighlightRange();
359     else {
360       Segment segment = (Segment) ((IStructuredSelection) selection).getFirstElement();
361       int start = segment.position.getOffset();
362       int length = segment.position.getLength();
363       try {
364         fTextEditor.setHighlightRange(start, length, true);
365       } catch (IllegalArgumentException x) {
366         fTextEditor.resetHighlightRange();
367       }
368     }
369   }
370
371   /**
372    * Sets the input of the outline page
373    */
374   public void setInput(Object input) {
375     fInput = input;
376     update();
377   }
378
379   /**
380    * Updates the outline page.
381    */
382   public void update() {
383     TreeViewer viewer = getTreeViewer();
384
385     if (viewer != null) {
386       Control control = viewer.getControl();
387       if (control != null && !control.isDisposed()) {
388         control.setRedraw(false);
389         viewer.setInput(fInput);
390         viewer.expandAll();
391         control.setRedraw(true);
392       }
393     }
394   }
395 }