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