1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.ui.preferences;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
19 import net.sourceforge.phpdt.internal.ui.IJavaHelpContextIds;
20 import net.sourceforge.phpdt.internal.ui.dialogs.StatusDialog;
21 import net.sourceforge.phpdt.internal.ui.dialogs.StatusInfo;
22 import net.sourceforge.phpdt.internal.ui.text.IPHPPartitions;
23 import net.sourceforge.phpdt.internal.ui.text.template.preferences.TemplateVariableProcessor;
24 import net.sourceforge.phpdt.internal.ui.util.SWTUtil;
25 import net.sourceforge.phpdt.ui.IContextMenuConstants;
26 import net.sourceforge.phpdt.ui.PreferenceConstants;
27 import net.sourceforge.phpdt.ui.text.JavaTextTools;
28 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
29 import net.sourceforge.phpeclipse.phpeditor.JavaSourceViewer;
31 import org.eclipse.jface.action.Action;
32 import org.eclipse.jface.action.GroupMarker;
33 import org.eclipse.jface.action.IAction;
34 import org.eclipse.jface.action.IMenuListener;
35 import org.eclipse.jface.action.IMenuManager;
36 import org.eclipse.jface.action.MenuManager;
37 import org.eclipse.jface.action.Separator;
38 import org.eclipse.jface.preference.IPreferenceStore;
39 import org.eclipse.jface.resource.JFaceResources;
40 import org.eclipse.jface.text.Document;
41 import org.eclipse.jface.text.IDocument;
42 import org.eclipse.jface.text.ITextListener;
43 import org.eclipse.jface.text.ITextOperationTarget;
44 import org.eclipse.jface.text.ITextViewer;
45 import org.eclipse.jface.text.TextEvent;
46 import org.eclipse.jface.text.source.ISourceViewer;
47 import org.eclipse.jface.text.source.SourceViewer;
48 import org.eclipse.jface.text.templates.ContextTypeRegistry;
49 import org.eclipse.jface.text.templates.Template;
50 import org.eclipse.jface.text.templates.TemplateContextType;
51 import org.eclipse.jface.text.templates.TemplateException;
52 import org.eclipse.jface.viewers.ISelectionChangedListener;
53 import org.eclipse.jface.viewers.SelectionChangedEvent;
54 import org.eclipse.swt.SWT;
55 import org.eclipse.swt.custom.StyledText;
56 import org.eclipse.swt.custom.VerifyKeyListener;
57 import org.eclipse.swt.events.FocusEvent;
58 import org.eclipse.swt.events.FocusListener;
59 import org.eclipse.swt.events.ModifyEvent;
60 import org.eclipse.swt.events.ModifyListener;
61 import org.eclipse.swt.events.SelectionEvent;
62 import org.eclipse.swt.events.SelectionListener;
63 import org.eclipse.swt.events.VerifyEvent;
64 import org.eclipse.swt.graphics.Font;
65 import org.eclipse.swt.layout.GridData;
66 import org.eclipse.swt.layout.GridLayout;
67 import org.eclipse.swt.widgets.Button;
68 import org.eclipse.swt.widgets.Combo;
69 import org.eclipse.swt.widgets.Composite;
70 import org.eclipse.swt.widgets.Control;
71 import org.eclipse.swt.widgets.Label;
72 import org.eclipse.swt.widgets.Menu;
73 import org.eclipse.swt.widgets.Shell;
74 import org.eclipse.swt.widgets.Text;
75 import org.eclipse.swt.widgets.Widget;
76 import org.eclipse.ui.help.WorkbenchHelp;
77 import org.eclipse.ui.texteditor.ITextEditorActionConstants;
78 import org.eclipse.ui.texteditor.IUpdate;
81 * Dialog to edit a template.
83 public class EditTemplateDialog extends StatusDialog {
85 private static class TextViewerAction extends Action implements IUpdate {
87 private int fOperationCode= -1;
88 private ITextOperationTarget fOperationTarget;
91 * Creates a new action.
93 * @param viewer the viewer
94 * @param operationCode the opcode
96 public TextViewerAction(ITextViewer viewer, int operationCode) {
97 fOperationCode= operationCode;
98 fOperationTarget= viewer.getTextOperationTarget();
103 * Updates the enabled state of the action.
104 * Fires a property change if the enabled state changes.
106 * @see Action#firePropertyChange(String, Object, Object)
108 public void update() {
110 boolean wasEnabled= isEnabled();
111 boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
112 setEnabled(isEnabled);
114 if (wasEnabled != isEnabled) {
115 firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE, isEnabled ? Boolean.TRUE : Boolean.FALSE);
123 if (fOperationCode != -1 && fOperationTarget != null) {
124 fOperationTarget.doOperation(fOperationCode);
129 private final Template fTemplate;
131 private Text fNameText;
132 private Text fDescriptionText;
133 private Combo fContextCombo;
134 private SourceViewer fPatternEditor;
135 private Button fInsertVariableButton;
136 private boolean fIsNameModifiable;
138 private StatusInfo fValidationStatus;
139 private boolean fSuppressError= true; // #4354
140 private Map fGlobalActions= new HashMap(10);
141 private List fSelectionActions = new ArrayList(3);
142 private String[][] fContextTypes;
144 private ContextTypeRegistry fContextTypeRegistry;
146 private final TemplateVariableProcessor fTemplateProcessor= new TemplateVariableProcessor();
149 * Creates a new dialog.
151 * @param parent the shell parent of the dialog
152 * @param template the template to edit
153 * @param edit whether this is a new template or an existing being edited
154 * @param isNameModifiable whether the name of the template may be modified
155 * @param registry the context type registry to use
157 public EditTemplateDialog(Shell parent, Template template, boolean edit, boolean isNameModifiable, ContextTypeRegistry registry) {
160 setShellStyle(getShellStyle() | SWT.MAX | SWT.RESIZE);
163 ? PreferencesMessages.getString("EditTemplateDialog.title.edit") //$NON-NLS-1$
164 : PreferencesMessages.getString("EditTemplateDialog.title.new"); //$NON-NLS-1$
168 fIsNameModifiable= isNameModifiable;
170 // XXX workaround for bug 63313 - disabling prefix until fixed.
171 // String delim= new Document().getLegalLineDelimiters()[0];
173 List contexts= new ArrayList();
174 for (Iterator it= registry.contextTypes(); it.hasNext();) {
175 TemplateContextType type= (TemplateContextType) it.next();
176 // if (type.getId().equals("javadoc")) //$NON-NLS-1$
177 // contexts.add(new String[] { type.getId(), type.getName(), "/**" + delim }); //$NON-NLS-1$
179 contexts.add(new String[] { type.getId(), type.getName(), "" }); //$NON-NLS-1$
181 fContextTypes= (String[][]) contexts.toArray(new String[contexts.size()][]);
183 fValidationStatus= new StatusInfo();
185 fContextTypeRegistry= registry;
187 TemplateContextType type= fContextTypeRegistry.getContextType(template.getContextTypeId());
188 fTemplateProcessor.setContextType(type);
192 * @see net.sourceforge.phpdt.internal.ui.dialogs.StatusDialog#create()
194 public void create() {
196 // update initial ok button to be disabled for new templates
197 boolean valid= fNameText == null || fNameText.getText().trim().length() != 0;
199 StatusInfo status = new StatusInfo();
200 status.setError(PreferencesMessages.getString("EditTemplateDialog.error.noname")); //$NON-NLS-1$
201 updateButtonsEnableState(status);
206 * @see Dialog#createDialogArea(Composite)
208 protected Control createDialogArea(Composite ancestor) {
209 Composite parent= new Composite(ancestor, SWT.NONE);
210 GridLayout layout= new GridLayout();
211 layout.numColumns= 2;
212 parent.setLayout(layout);
213 parent.setLayoutData(new GridData(GridData.FILL_BOTH));
215 ModifyListener listener= new ModifyListener() {
216 public void modifyText(ModifyEvent e) {
217 doTextWidgetChanged(e.widget);
221 if (fIsNameModifiable) {
222 createLabel(parent, PreferencesMessages.getString("EditTemplateDialog.name")); //$NON-NLS-1$
224 Composite composite= new Composite(parent, SWT.NONE);
225 composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
226 layout= new GridLayout();
227 layout.numColumns= 3;
228 layout.marginWidth= 0;
229 layout.marginHeight= 0;
230 composite.setLayout(layout);
232 fNameText= createText(composite);
233 fNameText.addFocusListener(new FocusListener() {
235 public void focusGained(FocusEvent e) {
238 public void focusLost(FocusEvent e) {
239 if (fSuppressError) {
240 fSuppressError= false;
246 createLabel(composite, PreferencesMessages.getString("EditTemplateDialog.context")); //$NON-NLS-1$
247 fContextCombo= new Combo(composite, SWT.READ_ONLY);
249 for (int i= 0; i < fContextTypes.length; i++) {
250 fContextCombo.add(fContextTypes[i][1]);
253 fContextCombo.addModifyListener(listener);
256 createLabel(parent, PreferencesMessages.getString("EditTemplateDialog.description")); //$NON-NLS-1$
258 int descFlags= fIsNameModifiable ? SWT.BORDER : SWT.BORDER | SWT.READ_ONLY;
259 fDescriptionText= new Text(parent, descFlags );
260 fDescriptionText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
262 fDescriptionText.addModifyListener(listener);
264 Label patternLabel= createLabel(parent, PreferencesMessages.getString("EditTemplateDialog.pattern")); //$NON-NLS-1$
265 patternLabel.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
266 fPatternEditor= createEditor(parent);
268 Label filler= new Label(parent, SWT.NONE);
269 filler.setLayoutData(new GridData());
271 Composite composite= new Composite(parent, SWT.NONE);
272 layout= new GridLayout();
273 layout.marginWidth= 0;
274 layout.marginHeight= 0;
275 composite.setLayout(layout);
276 composite.setLayoutData(new GridData());
278 fInsertVariableButton= new Button(composite, SWT.NONE);
279 fInsertVariableButton.setLayoutData(getButtonGridData(fInsertVariableButton));
280 fInsertVariableButton.setText(PreferencesMessages.getString("EditTemplateDialog.insert.variable")); //$NON-NLS-1$
281 fInsertVariableButton.addSelectionListener(new SelectionListener() {
282 public void widgetSelected(SelectionEvent e) {
283 fPatternEditor.getTextWidget().setFocus();
284 fPatternEditor.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
287 public void widgetDefaultSelected(SelectionEvent e) {}
290 fDescriptionText.setText(fTemplate.getDescription());
291 if (fIsNameModifiable) {
292 fNameText.setText(fTemplate.getName());
293 fNameText.addModifyListener(listener);
294 fContextCombo.select(getIndex(fTemplate.getContextTypeId()));
296 fPatternEditor.getControl().setFocus();
300 applyDialogFont(parent);
304 protected void doTextWidgetChanged(Widget w) {
305 if (w == fNameText) {
306 fSuppressError= false;
307 String name= fNameText.getText();
308 fTemplate.setName(name);
310 } else if (w == fContextCombo) {
311 String name= fContextCombo.getText();
312 String contextId= getContextId(name);
313 fTemplate.setContextTypeId(contextId);
314 fTemplateProcessor.setContextType(fContextTypeRegistry.getContextType(contextId));
315 } else if (w == fDescriptionText) {
316 String desc= fDescriptionText.getText();
317 fTemplate.setDescription(desc);
321 private String getContextId(String name) {
325 for (int i= 0; i < fContextTypes.length; i++) {
326 if (name.equals(fContextTypes[i][1])) {
327 return fContextTypes[i][0];
333 protected void doSourceChanged(IDocument document) {
334 String text= document.get();
335 String prefix= getPrefix();
336 fTemplate.setPattern(text.substring(prefix.length(), text.length()));
337 fValidationStatus.setOK();
338 TemplateContextType contextType= fContextTypeRegistry.getContextType(fTemplate.getContextTypeId());
339 if (contextType != null) {
341 contextType.validate(text);
342 } catch (TemplateException e) {
343 fValidationStatus.setError(e.getLocalizedMessage());
351 private static GridData getButtonGridData(Button button) {
352 GridData data= new GridData(GridData.FILL_HORIZONTAL);
353 data.heightHint= SWTUtil.getButtonHeightHint(button);
358 private static Label createLabel(Composite parent, String name) {
359 Label label= new Label(parent, SWT.NULL);
361 label.setLayoutData(new GridData());
366 private static Text createText(Composite parent) {
367 Text text= new Text(parent, SWT.BORDER);
368 text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
373 private SourceViewer createEditor(Composite parent) {
374 String prefix= getPrefix();
375 IDocument document= new Document(prefix + fTemplate.getPattern());
376 JavaTextTools tools= PHPeclipsePlugin.getDefault().getJavaTextTools();
377 tools.setupJavaDocumentPartitioner(document, IPHPPartitions.PHP_PARTITIONING);
378 IPreferenceStore store= PHPeclipsePlugin.getDefault().getCombinedPreferenceStore();
379 SourceViewer viewer= new JavaSourceViewer(parent, null, null, false, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL, store);
380 TemplateEditorSourceViewerConfiguration configuration= new TemplateEditorSourceViewerConfiguration(tools.getColorManager(), store, null, fTemplateProcessor);
381 viewer.configure(configuration);
382 viewer.setEditable(true);
383 // XXX workaround for bug 63313 - disabling prefix until fixed.
384 // viewer.setDocument(document, prefix.length(), document.getLength() - prefix.length());
385 viewer.setDocument(document);
387 Font font= JFaceResources.getFont(PreferenceConstants.EDITOR_TEXT_FONT);
388 viewer.getTextWidget().setFont(font);
389 new JavaSourcePreviewerUpdater(viewer, configuration, store);
391 int nLines= document.getNumberOfLines();
394 } else if (nLines > 12) {
398 Control control= viewer.getControl();
399 GridData data= new GridData(GridData.FILL_BOTH);
400 data.widthHint= convertWidthInCharsToPixels(80);
401 data.heightHint= convertHeightInCharsToPixels(nLines);
402 control.setLayoutData(data);
404 viewer.addTextListener(new ITextListener() {
405 public void textChanged(TextEvent event) {
406 if (event .getDocumentEvent() != null)
407 doSourceChanged(event.getDocumentEvent().getDocument());
411 viewer.addSelectionChangedListener(new ISelectionChangedListener() {
412 public void selectionChanged(SelectionChangedEvent event) {
413 updateSelectionDependentActions();
417 viewer.prependVerifyKeyListener(new VerifyKeyListener() {
418 public void verifyKey(VerifyEvent event) {
419 handleVerifyKeyPressed(event);
426 private String getPrefix() {
428 int idx= getIndex(fTemplate.getContextTypeId());
430 prefix= fContextTypes[idx][2];
432 prefix= ""; //$NON-NLS-1$
437 private void handleVerifyKeyPressed(VerifyEvent event) {
441 if (event.stateMask != SWT.MOD1)
444 switch (event.character) {
446 fPatternEditor.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
452 fPatternEditor.doOperation(ITextOperationTarget.UNDO);
458 private void initializeActions() {
459 TextViewerAction action= new TextViewerAction(fPatternEditor, SourceViewer.UNDO);
460 action.setText(PreferencesMessages.getString("EditTemplateDialog.undo")); //$NON-NLS-1$
461 fGlobalActions.put(ITextEditorActionConstants.UNDO, action);
463 action= new TextViewerAction(fPatternEditor, SourceViewer.CUT);
464 action.setText(PreferencesMessages.getString("EditTemplateDialog.cut")); //$NON-NLS-1$
465 fGlobalActions.put(ITextEditorActionConstants.CUT, action);
467 action= new TextViewerAction(fPatternEditor, SourceViewer.COPY);
468 action.setText(PreferencesMessages.getString("EditTemplateDialog.copy")); //$NON-NLS-1$
469 fGlobalActions.put(ITextEditorActionConstants.COPY, action);
471 action= new TextViewerAction(fPatternEditor, SourceViewer.PASTE);
472 action.setText(PreferencesMessages.getString("EditTemplateDialog.paste")); //$NON-NLS-1$
473 fGlobalActions.put(ITextEditorActionConstants.PASTE, action);
475 action= new TextViewerAction(fPatternEditor, SourceViewer.SELECT_ALL);
476 action.setText(PreferencesMessages.getString("EditTemplateDialog.select.all")); //$NON-NLS-1$
477 fGlobalActions.put(ITextEditorActionConstants.SELECT_ALL, action);
479 action= new TextViewerAction(fPatternEditor, SourceViewer.CONTENTASSIST_PROPOSALS);
480 action.setText(PreferencesMessages.getString("EditTemplateDialog.content.assist")); //$NON-NLS-1$
481 fGlobalActions.put("ContentAssistProposal", action); //$NON-NLS-1$
483 fSelectionActions.add(ITextEditorActionConstants.CUT);
484 fSelectionActions.add(ITextEditorActionConstants.COPY);
485 fSelectionActions.add(ITextEditorActionConstants.PASTE);
487 // create context menu
488 MenuManager manager= new MenuManager(null, null);
489 manager.setRemoveAllWhenShown(true);
490 manager.addMenuListener(new IMenuListener() {
491 public void menuAboutToShow(IMenuManager mgr) {
492 fillContextMenu(mgr);
496 StyledText text= fPatternEditor.getTextWidget();
497 Menu menu= manager.createContextMenu(text);
501 private void fillContextMenu(IMenuManager menu) {
502 menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_UNDO));
503 menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO, (IAction) fGlobalActions.get(ITextEditorActionConstants.UNDO));
505 menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
506 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.CUT));
507 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.COPY));
508 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.PASTE));
509 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.SELECT_ALL));
511 menu.add(new Separator(IContextMenuConstants.GROUP_GENERATE));
512 menu.appendToGroup(IContextMenuConstants.GROUP_GENERATE, (IAction) fGlobalActions.get("ContentAssistProposal")); //$NON-NLS-1$
515 protected void updateSelectionDependentActions() {
516 Iterator iterator= fSelectionActions.iterator();
517 while (iterator.hasNext())
518 updateAction((String)iterator.next());
521 protected void updateUndoAction() {
522 IAction action= (IAction) fGlobalActions.get(ITextEditorActionConstants.UNDO);
523 if (action instanceof IUpdate)
524 ((IUpdate) action).update();
527 protected void updateAction(String actionId) {
528 IAction action= (IAction) fGlobalActions.get(actionId);
529 if (action instanceof IUpdate)
530 ((IUpdate) action).update();
533 private int getIndex(String contextid) {
535 if (contextid == null)
538 for (int i= 0; i < fContextTypes.length; i++) {
539 if (contextid.equals(fContextTypes[i][0])) {
546 protected void okPressed() {
550 private void updateButtons() {
553 boolean valid= fNameText == null || fNameText.getText().trim().length() != 0;
555 status = new StatusInfo();
556 if (!fSuppressError) {
557 status.setError(PreferencesMessages.getString("EditTemplateDialog.error.noname")); //$NON-NLS-1$
560 status= fValidationStatus;
562 updateStatus(status);
566 * @see org.eclipse.jface.window.Window#configureShell(Shell)
568 protected void configureShell(Shell newShell) {
569 super.configureShell(newShell);
570 WorkbenchHelp.setHelp(newShell, IJavaHelpContextIds.EDIT_TEMPLATE_DIALOG);