first scanner /parser copied from the jdt java version
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpeclipse / phpeditor / PHPEditor.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 import net.sourceforge.phpdt.internal.ui.actions.CompositeActionGroup;
15 import net.sourceforge.phpdt.ui.actions.*;
16 import net.sourceforge.phpdt.ui.actions.GenerateActionGroup;
17 import net.sourceforge.phpeclipse.IPreferenceConstants;
18 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
19 import net.sourceforge.phpeclipse.phpeditor.php.PHPCodeScanner;
20 import net.sourceforge.phpeclipse.phpeditor.php.PHPWordExtractor;
21 import net.sourceforge.phpeclipse.phpeditor.util.PHPColorProvider;
22 import org.eclipse.core.runtime.CoreException;
23 import org.eclipse.core.runtime.IProgressMonitor;
24 import org.eclipse.jface.action.Action;
25 import org.eclipse.jface.action.IAction;
26 import org.eclipse.jface.action.MenuManager;
27 import org.eclipse.jface.preference.IPreferenceStore;
28 import org.eclipse.jface.preference.PreferenceConverter;
29 import org.eclipse.jface.text.BadLocationException;
30 import org.eclipse.jface.text.IDocument;
31 import org.eclipse.jface.text.ITextOperationTarget;
32 import org.eclipse.jface.text.source.AnnotationRulerColumn;
33 import org.eclipse.jface.text.source.CompositeRuler;
34 import org.eclipse.jface.text.source.ISourceViewer;
35 import org.eclipse.jface.text.source.IVerticalRuler;
36 import org.eclipse.jface.text.source.IVerticalRulerColumn;
37 import org.eclipse.jface.text.source.LineNumberRulerColumn;
38 import org.eclipse.jface.util.IPropertyChangeListener;
39 import org.eclipse.jface.util.PropertyChangeEvent;
40 import org.eclipse.swt.graphics.Point;
41 import org.eclipse.swt.graphics.RGB;
42 import org.eclipse.ui.IEditorInput;
43 import org.eclipse.ui.actions.ActionContext;
44 import org.eclipse.ui.actions.ActionGroup;
45 import org.eclipse.ui.editors.text.TextEditor;
46 import org.eclipse.ui.texteditor.DefaultRangeIndicator;
47 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
48 import org.eclipse.ui.texteditor.TextOperationAction;
49 import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
50 /**
51  * PHP specific text editor.
52  */
53 public class PHPEditor extends TextEditor {
54
55   // protected PHPActionGroup fActionGroups;
56   /** The outline page */
57   private PHPContentOutlinePage fOutlinePage;
58   private IPreferenceStore phpPrefStore;
59
60   /** The line number ruler column */
61   private LineNumberRulerColumn fLineNumberRulerColumn;
62
63   protected CompositeActionGroup fActionGroups;
64   /** The standard action groups added to the menu */
65   private GenerateActionGroup fGenerateActionGroup;
66   private CompositeActionGroup fContextMenuGroup;
67   /**
68    * Default constructor.
69    */
70   public PHPEditor() {
71     super();
72     setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
73   }
74
75   /**
76    *  Returns the standard action group of this editor.
77    */
78   protected ActionGroup getActionGroup() {
79     return fActionGroups;
80   } 
81   
82   public PHPContentOutlinePage getfOutlinePage() {
83     return fOutlinePage;
84   }
85
86   /** The <code>PHPEditor</code> implementation of this 
87    * <code>AbstractTextEditor</code> method extend the 
88    * actions to add those specific to the receiver
89    */
90   protected void createActions() {
91     super.createActions();
92     setAction(
93       "ContentAssistProposal",
94       new TextOperationAction(
95         PHPEditorMessages.getResourceBundle(),
96         "ContentAssistProposal.",
97         this,
98         ISourceViewer.CONTENTASSIST_PROPOSALS));
99     setAction(
100       "ContentAssistTip",
101       new TextOperationAction(
102         PHPEditorMessages.getResourceBundle(),
103         "ContentAssistTip.",
104         this,
105         ISourceViewer.CONTENTASSIST_CONTEXT_INFORMATION));
106
107     Action action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Comment.", this, ITextOperationTarget.PREFIX);
108     action.setActionDefinitionId(PHPEditorActionDefinitionIds.COMMENT);
109     setAction("Comment", action);
110
111     action = new TextOperationAction(PHPEditorMessages.getResourceBundle(), "Uncomment.", this, ITextOperationTarget.STRIP_PREFIX);
112     action.setActionDefinitionId(PHPEditorActionDefinitionIds.UNCOMMENT);
113     setAction("Uncomment", action);
114
115   //  fActionGroups = new PHPActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
116
117     markAsStateDependentAction("Comment", true); //$NON-NLS-1$
118     markAsStateDependentAction("Uncomment", true); //$NON-NLS-1$
119
120     fGenerateActionGroup= new GenerateActionGroup(this, ITextEditorActionConstants.GROUP_EDIT);
121
122     fActionGroups= new CompositeActionGroup(
123       new ActionGroup[] { fGenerateActionGroup }
124       );
125   
126     
127     // We have to keep the context menu group separate to have better control over positioning
128     fContextMenuGroup= new CompositeActionGroup(new ActionGroup[] {
129       fGenerateActionGroup });
130 //      rg, 
131 //      new LocalHistoryActionGroup(this, ITextEditorActionConstants.GROUP_EDIT)});
132   }
133
134   /** The <code>PHPEditor</code> implementation of this 
135    * <code>AbstractTextEditor</code> method performs any extra 
136    * disposal actions required by the php editor.
137    */
138   public void dispose() {
139     PHPEditorEnvironment.disconnect(this);
140     if (fOutlinePage != null)
141       fOutlinePage.setInput(null);
142       
143     if (fActionGroups != null)
144       fActionGroups.dispose();  
145       
146     super.dispose();
147   }
148
149   /** The <code>PHPEditor</code> implementation of this 
150    * <code>AbstractTextEditor</code> method performs any extra 
151    * revert behavior required by the php editor.
152    */
153   public void doRevertToSaved() {
154     super.doRevertToSaved();
155     if (fOutlinePage != null)
156       fOutlinePage.update();
157   }
158
159   /** The <code>PHPEditor</code> implementation of this 
160    * <code>AbstractTextEditor</code> method performs any extra 
161    * save behavior required by the php editor.
162    */
163   public void doSave(IProgressMonitor monitor) {
164     super.doSave(monitor);
165     // compile or not, according to the user preferences
166     IPreferenceStore store = phpPrefStore;
167     if (store.getBoolean(PHPeclipsePlugin.PHP_PARSE_ON_SAVE)) {
168       IAction a = PHPParserAction.getInstance();
169       if (a != null)
170         a.run();
171     }
172     if (fOutlinePage != null)
173       fOutlinePage.update();
174   }
175
176   /** The <code>PHPEditor</code> implementation of this 
177    * <code>AbstractTextEditor</code> method performs any extra 
178    * save as behavior required by the php editor.
179    */
180   public void doSaveAs() {
181     super.doSaveAs();
182     if (fOutlinePage != null)
183       fOutlinePage.update();
184   }
185
186   /** The <code>PHPEditor</code> implementation of this 
187    * <code>AbstractTextEditor</code> method performs sets the 
188    * input of the outline page after AbstractTextEditor has set input.
189    */
190   public void doSetInput(IEditorInput input) throws CoreException {
191     super.doSetInput(input);
192     if (fOutlinePage != null)
193       fOutlinePage.setInput(input);
194   }
195
196   /** The <code>PHPEditor</code> implementation of this 
197    * <code>AbstractTextEditor</code> method adds any 
198    * PHPEditor specific entries.
199    */
200   public void editorContextMenuAboutToShow(MenuManager menu) {
201     super.editorContextMenuAboutToShow(menu);
202     //  addAction(menu, "ContentAssistProposal"); //$NON-NLS-1$
203     //  addAction(menu, "ContentAssistTip"); //$NON-NLS-1$
204     
205     // fActionGroups.fillContextMenu(menu);
206     
207     ActionContext context= new ActionContext(getSelectionProvider().getSelection());
208     fContextMenuGroup.setContext(context);
209     fContextMenuGroup.fillContextMenu(menu);
210     fContextMenuGroup.setContext(null);
211   }
212
213   protected void updateStateDependentActions() {
214     super.updateStateDependentActions();
215     fGenerateActionGroup.editorStateChanged();
216   }
217   
218   /** The <code>PHPEditor</code> implementation of this 
219    * <code>AbstractTextEditor</code> method performs gets
220    * the java content outline page if request is for a an 
221    * outline page.
222    */
223   public Object getAdapter(Class required) {
224     if (IContentOutlinePage.class.equals(required)) {
225       if (fOutlinePage == null) {
226         fOutlinePage = new PHPContentOutlinePage(getDocumentProvider(), this);
227         if (getEditorInput() != null)
228           fOutlinePage.setInput(getEditorInput());
229       }
230       return fOutlinePage;
231     }
232     return super.getAdapter(required);
233   }
234
235   //  public void openContextHelp() {
236   //    IDocument doc = this.getDocumentProvider().getDocument(this.getEditorInput());
237   //    ITextSelection selection = (ITextSelection) this.getSelectionProvider().getSelection();
238   //    int pos = selection.getOffset();
239   //    String word = getFunctionName(doc, pos);
240   //    openContextHelp(word);
241   //  }
242   //
243   //  private void openContextHelp(String word) {
244   //    open(word);
245   //  }
246   //
247   //  public static void open(String word) {
248   //    IHelp help = WorkbenchHelp.getHelpSupport();
249   //    if (help != null) {
250   //      IHelpResource helpResource = new PHPFunctionHelpResource(word);
251   //      WorkbenchHelp.getHelpSupport().displayHelpResource(helpResource);
252   //    } else {
253   //      //   showMessage(shell, dialogTitle, ActionMessages.getString("Open help not available"), false); //$NON-NLS-1$
254   //    }
255   //  }
256
257   private String getFunctionName(IDocument doc, int pos) {
258     Point word = PHPWordExtractor.findWord(doc, pos);
259     if (word != null) {
260       try {
261         return doc.get(word.x, word.y).replace('_', '-');
262       } catch (BadLocationException e) {
263       }
264     }
265     return "";
266   }
267
268   /*
269      * @see AbstractTextEditor#handlePreferenceStoreChanged(PropertyChangeEvent)
270      */
271   protected void handlePreferenceStoreChanged(PropertyChangeEvent event) {
272
273     try {
274
275       ISourceViewer sourceViewer = getSourceViewer();
276       if (sourceViewer == null)
277         return;
278
279       String property = event.getProperty();
280
281       //      if (JavaSourceViewerConfiguration.PREFERENCE_TAB_WIDTH.equals(property)) {
282       //        Object value= event.getNewValue();
283       //        if (value instanceof Integer) {
284       //          sourceViewer.getTextWidget().setTabs(((Integer) value).intValue());
285       //        } else if (value instanceof String) {
286       //          sourceViewer.getTextWidget().setTabs(Integer.parseInt((String) value));
287       //        }
288       //        return;
289       //      }
290
291       if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
292         if (isLineNumberRulerVisible())
293           showLineNumberRuler();
294         else
295           hideLineNumberRuler();
296         return;
297       }
298
299       if (fLineNumberRulerColumn != null
300         && (IPreferenceConstants.LINE_NUMBER_COLOR.equals(property)
301           || PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT.equals(property)
302           || PREFERENCE_COLOR_BACKGROUND.equals(property))) {
303
304         initializeLineNumberRulerColumn(fLineNumberRulerColumn);
305       }
306
307     } finally {
308       super.handlePreferenceStoreChanged(event);
309     }
310   }
311   /**
312    * Shows the line number ruler column.
313    */
314   private void showLineNumberRuler() {
315     IVerticalRuler v = getVerticalRuler();
316     if (v instanceof CompositeRuler) {
317       CompositeRuler c = (CompositeRuler) v;
318       c.addDecorator(1, createLineNumberRulerColumn());
319     }
320   }
321
322   /**
323   * Return whether the line number ruler column should be 
324   * visible according to the preference store settings.
325   * @return <code>true</code> if the line numbers should be visible
326   */
327   private boolean isLineNumberRulerVisible() {
328     // IPreferenceStore store= getPreferenceStore();
329     return phpPrefStore.getBoolean(IPreferenceConstants.LINE_NUMBER_RULER);
330   }
331   /**
332    * Hides the line number ruler column.
333    */
334   private void hideLineNumberRuler() {
335     IVerticalRuler v = getVerticalRuler();
336     if (v instanceof CompositeRuler) {
337       CompositeRuler c = (CompositeRuler) v;
338       try {
339         c.removeDecorator(1);
340       } catch (Throwable e) {
341       }
342     }
343   }
344
345   /**
346   * Initializes the given line number ruler column from the preference store.
347   * @param rulerColumn the ruler column to be initialized
348   */
349   protected void initializeLineNumberRulerColumn(LineNumberRulerColumn rulerColumn) {
350     //   JavaTextTools textTools= JavaPlugin.getDefault().getJavaTextTools();
351     PHPColorProvider manager = PHPEditorEnvironment.getPHPColorProvider();
352
353     if (phpPrefStore != null) {
354
355       RGB rgb = null;
356       // foreground color
357       if (phpPrefStore.contains(IPreferenceConstants.LINE_NUMBER_COLOR)) {
358         if (phpPrefStore.isDefault(IPreferenceConstants.LINE_NUMBER_COLOR))
359           rgb = PreferenceConverter.getDefaultColor(phpPrefStore, IPreferenceConstants.LINE_NUMBER_COLOR);
360         else
361           rgb = PreferenceConverter.getColor(phpPrefStore, IPreferenceConstants.LINE_NUMBER_COLOR);
362       }
363       rulerColumn.setForeground(manager.getColor(rgb));
364
365       rgb = null;
366       // background color
367       if (!phpPrefStore.getBoolean(IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT)) {
368         if (phpPrefStore.contains(IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND)) {
369           if (phpPrefStore.isDefault(IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND))
370             rgb = PreferenceConverter.getDefaultColor(phpPrefStore, IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND);
371           else
372             rgb = PreferenceConverter.getColor(phpPrefStore, IPreferenceConstants.PREFERENCE_COLOR_BACKGROUND);
373         }
374         rulerColumn.setBackground(manager.getColor(rgb));
375       }
376
377     }
378   }
379
380   /**
381    * Creates a new line number ruler column that is appropriately initialized.
382    */
383   protected IVerticalRulerColumn createLineNumberRulerColumn() {
384     fLineNumberRulerColumn = new LineNumberRulerColumn();
385     initializeLineNumberRulerColumn(fLineNumberRulerColumn);
386     return fLineNumberRulerColumn;
387   }
388
389   /*
390    * @see AbstractTextEditor#createVerticalRuler()
391    */
392   protected IVerticalRuler createVerticalRuler() {
393     CompositeRuler ruler = new CompositeRuler();
394     ruler.addDecorator(0, new AnnotationRulerColumn(VERTICAL_RULER_WIDTH));
395     if (isLineNumberRulerVisible())
396       ruler.addDecorator(1, createLineNumberRulerColumn());
397     return ruler;
398   }
399
400   /* (non-Javadoc)
401    * Method declared on AbstractTextEditor
402    */
403   protected void initializeEditor() {
404     PHPEditorEnvironment.connect(this);
405
406     setSourceViewerConfiguration(new PHPSourceViewerConfiguration());
407     setRangeIndicator(new DefaultRangeIndicator());
408     setEditorContextMenuId("#PHPEditorContext"); //$NON-NLS-1$
409     setRulerContextMenuId("#PHPRulerContext"); //$NON-NLS-1$
410     // setDocumentProvider(PHPeclipsePlugin.getCompilationUnitDocumentProvider());
411     phpPrefStore = PHPeclipsePlugin.getDefault().getPreferenceStore();
412
413     phpPrefStore.addPropertyChangeListener(new IPropertyChangeListener() {
414       public void propertyChange(PropertyChangeEvent event) {
415         PHPCodeScanner scanner = PHPEditorEnvironment.getPHPCodeScanner();
416         if (scanner != null) {
417           scanner.updateToken(PHPEditorEnvironment.getPHPColorProvider());
418         }
419         if (getSourceViewer() != null) {
420           getSourceViewer().invalidateTextPresentation();
421         }
422
423         String property = event.getProperty();
424         if (IPreferenceConstants.LINE_NUMBER_RULER.equals(property)) {
425           if (isLineNumberRulerVisible())
426             showLineNumberRuler();
427           else
428             hideLineNumberRuler();
429           return;
430         }
431       }
432     });
433   }
434 }