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.PlatformUI;
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;
89 private ITextOperationTarget fOperationTarget;
92 * Creates a new action.
96 * @param operationCode
99 public TextViewerAction(ITextViewer viewer, int operationCode) {
100 fOperationCode = operationCode;
101 fOperationTarget = viewer.getTextOperationTarget();
106 * Updates the enabled state of the action. Fires a property change if
107 * the enabled state changes.
109 * @see Action#firePropertyChange(String, Object, Object)
111 public void update() {
113 boolean wasEnabled = isEnabled();
114 boolean isEnabled = (fOperationTarget != null && fOperationTarget
115 .canDoOperation(fOperationCode));
116 setEnabled(isEnabled);
118 if (wasEnabled != isEnabled) {
119 firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE
120 : Boolean.FALSE, isEnabled ? Boolean.TRUE
129 if (fOperationCode != -1 && fOperationTarget != null) {
130 fOperationTarget.doOperation(fOperationCode);
135 private final Template fTemplate;
137 private Text fNameText;
139 private Text fDescriptionText;
141 private Combo fContextCombo;
143 private SourceViewer fPatternEditor;
145 private Button fInsertVariableButton;
147 private boolean fIsNameModifiable;
149 private StatusInfo fValidationStatus;
151 private boolean fSuppressError = true; // #4354
153 private Map fGlobalActions = new HashMap(10);
155 private List fSelectionActions = new ArrayList(3);
157 private String[][] fContextTypes;
159 private ContextTypeRegistry fContextTypeRegistry;
161 private final TemplateVariableProcessor fTemplateProcessor = new TemplateVariableProcessor();
164 * Creates a new dialog.
167 * the shell parent of the dialog
169 * the template to edit
171 * whether this is a new template or an existing being edited
172 * @param isNameModifiable
173 * whether the name of the template may be modified
175 * the context type registry to use
177 public EditTemplateDialog(Shell parent, Template template, boolean edit,
178 boolean isNameModifiable, ContextTypeRegistry registry) {
181 setShellStyle(getShellStyle() | SWT.MAX | SWT.RESIZE);
183 String title = edit ? PreferencesMessages
184 .getString("EditTemplateDialog.title.edit") //$NON-NLS-1$
185 : PreferencesMessages.getString("EditTemplateDialog.title.new"); //$NON-NLS-1$
188 fTemplate = template;
189 fIsNameModifiable = isNameModifiable;
191 // XXX workaround for bug 63313 - disabling prefix until fixed.
192 // String delim= new Document().getLegalLineDelimiters()[0];
194 List contexts = new ArrayList();
195 for (Iterator it = registry.contextTypes(); it.hasNext();) {
196 TemplateContextType type = (TemplateContextType) it.next();
197 // if (type.getId().equals("javadoc")) //$NON-NLS-1$
198 // contexts.add(new String[] { type.getId(), type.getName(), "/**" +
199 // delim }); //$NON-NLS-1$
201 contexts.add(new String[] { type.getId(), type.getName(), "" }); //$NON-NLS-1$
203 fContextTypes = (String[][]) contexts.toArray(new String[contexts
206 fValidationStatus = new StatusInfo();
208 fContextTypeRegistry = registry;
210 TemplateContextType type = fContextTypeRegistry.getContextType(template
211 .getContextTypeId());
212 fTemplateProcessor.setContextType(type);
216 * @see net.sourceforge.phpdt.internal.ui.dialogs.StatusDialog#create()
218 public void create() {
220 // update initial ok button to be disabled for new templates
221 boolean valid = fNameText == null
222 || fNameText.getText().trim().length() != 0;
224 StatusInfo status = new StatusInfo();
225 status.setError(PreferencesMessages
226 .getString("EditTemplateDialog.error.noname")); //$NON-NLS-1$
227 updateButtonsEnableState(status);
232 * @see Dialog#createDialogArea(Composite)
234 protected Control createDialogArea(Composite ancestor) {
235 Composite parent = new Composite(ancestor, SWT.NONE);
236 GridLayout layout = new GridLayout();
237 layout.numColumns = 2;
238 parent.setLayout(layout);
239 parent.setLayoutData(new GridData(GridData.FILL_BOTH));
241 ModifyListener listener = new ModifyListener() {
242 public void modifyText(ModifyEvent e) {
243 doTextWidgetChanged(e.widget);
247 if (fIsNameModifiable) {
248 createLabel(parent, PreferencesMessages
249 .getString("EditTemplateDialog.name")); //$NON-NLS-1$
251 Composite composite = new Composite(parent, SWT.NONE);
252 composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
253 layout = new GridLayout();
254 layout.numColumns = 3;
255 layout.marginWidth = 0;
256 layout.marginHeight = 0;
257 composite.setLayout(layout);
259 fNameText = createText(composite);
260 fNameText.addFocusListener(new FocusListener() {
262 public void focusGained(FocusEvent e) {
265 public void focusLost(FocusEvent e) {
266 if (fSuppressError) {
267 fSuppressError = false;
273 createLabel(composite, PreferencesMessages
274 .getString("EditTemplateDialog.context")); //$NON-NLS-1$
275 fContextCombo = new Combo(composite, SWT.READ_ONLY);
277 for (int i = 0; i < fContextTypes.length; i++) {
278 fContextCombo.add(fContextTypes[i][1]);
281 fContextCombo.addModifyListener(listener);
284 createLabel(parent, PreferencesMessages
285 .getString("EditTemplateDialog.description")); //$NON-NLS-1$
287 int descFlags = fIsNameModifiable ? SWT.BORDER : SWT.BORDER
289 fDescriptionText = new Text(parent, descFlags);
290 fDescriptionText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
292 fDescriptionText.addModifyListener(listener);
294 Label patternLabel = createLabel(parent, PreferencesMessages
295 .getString("EditTemplateDialog.pattern")); //$NON-NLS-1$
296 patternLabel.setLayoutData(new GridData(
297 GridData.VERTICAL_ALIGN_BEGINNING));
298 fPatternEditor = createEditor(parent);
300 Label filler = new Label(parent, SWT.NONE);
301 filler.setLayoutData(new GridData());
303 Composite composite = new Composite(parent, SWT.NONE);
304 layout = new GridLayout();
305 layout.marginWidth = 0;
306 layout.marginHeight = 0;
307 composite.setLayout(layout);
308 composite.setLayoutData(new GridData());
310 fInsertVariableButton = new Button(composite, SWT.NONE);
311 fInsertVariableButton
312 .setLayoutData(getButtonGridData(fInsertVariableButton));
313 fInsertVariableButton.setText(PreferencesMessages
314 .getString("EditTemplateDialog.insert.variable")); //$NON-NLS-1$
315 fInsertVariableButton.addSelectionListener(new SelectionListener() {
316 public void widgetSelected(SelectionEvent e) {
317 fPatternEditor.getTextWidget().setFocus();
319 .doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
322 public void widgetDefaultSelected(SelectionEvent e) {
326 fDescriptionText.setText(fTemplate.getDescription());
327 if (fIsNameModifiable) {
328 fNameText.setText(fTemplate.getName());
329 fNameText.addModifyListener(listener);
330 fContextCombo.select(getIndex(fTemplate.getContextTypeId()));
332 fPatternEditor.getControl().setFocus();
336 applyDialogFont(parent);
340 protected void doTextWidgetChanged(Widget w) {
341 if (w == fNameText) {
342 fSuppressError = false;
343 String name = fNameText.getText();
344 fTemplate.setName(name);
346 } else if (w == fContextCombo) {
347 String name = fContextCombo.getText();
348 String contextId = getContextId(name);
349 fTemplate.setContextTypeId(contextId);
350 fTemplateProcessor.setContextType(fContextTypeRegistry
351 .getContextType(contextId));
352 } else if (w == fDescriptionText) {
353 String desc = fDescriptionText.getText();
354 fTemplate.setDescription(desc);
358 private String getContextId(String name) {
362 for (int i = 0; i < fContextTypes.length; i++) {
363 if (name.equals(fContextTypes[i][1])) {
364 return fContextTypes[i][0];
370 protected void doSourceChanged(IDocument document) {
371 String text = document.get();
372 String prefix = getPrefix();
373 fTemplate.setPattern(text.substring(prefix.length(), text.length()));
374 fValidationStatus.setOK();
375 TemplateContextType contextType = fContextTypeRegistry
376 .getContextType(fTemplate.getContextTypeId());
377 if (contextType != null) {
379 contextType.validate(text);
380 } catch (TemplateException e) {
381 fValidationStatus.setError(e.getLocalizedMessage());
389 private static GridData getButtonGridData(Button button) {
390 GridData data = new GridData(GridData.FILL_HORIZONTAL);
391 data.heightHint = SWTUtil.getButtonHeightHint(button);
396 private static Label createLabel(Composite parent, String name) {
397 Label label = new Label(parent, SWT.NULL);
399 label.setLayoutData(new GridData());
404 private static Text createText(Composite parent) {
405 Text text = new Text(parent, SWT.BORDER);
406 text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
411 private SourceViewer createEditor(Composite parent) {
412 String prefix = getPrefix();
413 IDocument document = new Document(prefix + fTemplate.getPattern());
414 JavaTextTools tools = PHPeclipsePlugin.getDefault().getJavaTextTools();
415 tools.setupJavaDocumentPartitioner(document,
416 IPHPPartitions.PHP_PARTITIONING);
417 IPreferenceStore store = PHPeclipsePlugin.getDefault()
418 .getCombinedPreferenceStore();
419 SourceViewer viewer = new JavaSourceViewer(parent, null, null, false,
420 SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL, store);
421 TemplateEditorSourceViewerConfiguration configuration = new TemplateEditorSourceViewerConfiguration(
422 tools.getColorManager(), store, null, fTemplateProcessor);
423 viewer.configure(configuration);
424 viewer.setEditable(true);
425 // XXX workaround for bug 63313 - disabling prefix until fixed.
426 // viewer.setDocument(document, prefix.length(), document.getLength() -
428 viewer.setDocument(document);
430 Font font = JFaceResources
431 .getFont(PreferenceConstants.EDITOR_TEXT_FONT);
432 viewer.getTextWidget().setFont(font);
433 new JavaSourcePreviewerUpdater(viewer, configuration, store);
435 int nLines = document.getNumberOfLines();
438 } else if (nLines > 12) {
442 Control control = viewer.getControl();
443 GridData data = new GridData(GridData.FILL_BOTH);
444 data.widthHint = convertWidthInCharsToPixels(80);
445 data.heightHint = convertHeightInCharsToPixels(nLines);
446 control.setLayoutData(data);
448 viewer.addTextListener(new ITextListener() {
449 public void textChanged(TextEvent event) {
450 if (event.getDocumentEvent() != null)
451 doSourceChanged(event.getDocumentEvent().getDocument());
455 viewer.addSelectionChangedListener(new ISelectionChangedListener() {
456 public void selectionChanged(SelectionChangedEvent event) {
457 updateSelectionDependentActions();
461 viewer.prependVerifyKeyListener(new VerifyKeyListener() {
462 public void verifyKey(VerifyEvent event) {
463 handleVerifyKeyPressed(event);
470 private String getPrefix() {
472 int idx = getIndex(fTemplate.getContextTypeId());
474 prefix = fContextTypes[idx][2];
476 prefix = ""; //$NON-NLS-1$
481 private void handleVerifyKeyPressed(VerifyEvent event) {
485 if (event.stateMask != SWT.MOD1)
488 switch (event.character) {
490 fPatternEditor.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
496 fPatternEditor.doOperation(ITextOperationTarget.UNDO);
502 private void initializeActions() {
503 TextViewerAction action = new TextViewerAction(fPatternEditor,
506 .setText(PreferencesMessages
507 .getString("EditTemplateDialog.undo")); //$NON-NLS-1$
508 fGlobalActions.put(ITextEditorActionConstants.UNDO, action);
510 action = new TextViewerAction(fPatternEditor, SourceViewer.CUT);
511 action.setText(PreferencesMessages.getString("EditTemplateDialog.cut")); //$NON-NLS-1$
512 fGlobalActions.put(ITextEditorActionConstants.CUT, action);
514 action = new TextViewerAction(fPatternEditor, SourceViewer.COPY);
516 .setText(PreferencesMessages
517 .getString("EditTemplateDialog.copy")); //$NON-NLS-1$
518 fGlobalActions.put(ITextEditorActionConstants.COPY, action);
520 action = new TextViewerAction(fPatternEditor, SourceViewer.PASTE);
521 action.setText(PreferencesMessages
522 .getString("EditTemplateDialog.paste")); //$NON-NLS-1$
523 fGlobalActions.put(ITextEditorActionConstants.PASTE, action);
525 action = new TextViewerAction(fPatternEditor, SourceViewer.SELECT_ALL);
526 action.setText(PreferencesMessages
527 .getString("EditTemplateDialog.select.all")); //$NON-NLS-1$
528 fGlobalActions.put(ITextEditorActionConstants.SELECT_ALL, action);
530 action = new TextViewerAction(fPatternEditor,
531 SourceViewer.CONTENTASSIST_PROPOSALS);
532 action.setText(PreferencesMessages
533 .getString("EditTemplateDialog.content.assist")); //$NON-NLS-1$
534 fGlobalActions.put("ContentAssistProposal", action); //$NON-NLS-1$
536 fSelectionActions.add(ITextEditorActionConstants.CUT);
537 fSelectionActions.add(ITextEditorActionConstants.COPY);
538 fSelectionActions.add(ITextEditorActionConstants.PASTE);
540 // create context menu
541 MenuManager manager = new MenuManager(null, null);
542 manager.setRemoveAllWhenShown(true);
543 manager.addMenuListener(new IMenuListener() {
544 public void menuAboutToShow(IMenuManager mgr) {
545 fillContextMenu(mgr);
549 StyledText text = fPatternEditor.getTextWidget();
550 Menu menu = manager.createContextMenu(text);
554 private void fillContextMenu(IMenuManager menu) {
555 menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_UNDO));
556 menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO,
557 (IAction) fGlobalActions.get(ITextEditorActionConstants.UNDO));
559 menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));
560 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
561 (IAction) fGlobalActions.get(ITextEditorActionConstants.CUT));
562 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
563 (IAction) fGlobalActions.get(ITextEditorActionConstants.COPY));
564 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
565 (IAction) fGlobalActions.get(ITextEditorActionConstants.PASTE));
566 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT,
567 (IAction) fGlobalActions
568 .get(ITextEditorActionConstants.SELECT_ALL));
570 menu.add(new Separator(IContextMenuConstants.GROUP_GENERATE));
571 menu.appendToGroup(IContextMenuConstants.GROUP_GENERATE,
572 (IAction) fGlobalActions.get("ContentAssistProposal")); //$NON-NLS-1$
575 protected void updateSelectionDependentActions() {
576 Iterator iterator = fSelectionActions.iterator();
577 while (iterator.hasNext())
578 updateAction((String) iterator.next());
581 protected void updateUndoAction() {
582 IAction action = (IAction) fGlobalActions
583 .get(ITextEditorActionConstants.UNDO);
584 if (action instanceof IUpdate)
585 ((IUpdate) action).update();
588 protected void updateAction(String actionId) {
589 IAction action = (IAction) fGlobalActions.get(actionId);
590 if (action instanceof IUpdate)
591 ((IUpdate) action).update();
594 private int getIndex(String contextid) {
596 if (contextid == null)
599 for (int i = 0; i < fContextTypes.length; i++) {
600 if (contextid.equals(fContextTypes[i][0])) {
607 protected void okPressed() {
611 private void updateButtons() {
614 boolean valid = fNameText == null
615 || fNameText.getText().trim().length() != 0;
617 status = new StatusInfo();
618 if (!fSuppressError) {
619 status.setError(PreferencesMessages
620 .getString("EditTemplateDialog.error.noname")); //$NON-NLS-1$
623 status = fValidationStatus;
625 updateStatus(status);
629 * @see org.eclipse.jface.window.Window#configureShell(Shell)
631 protected void configureShell(Shell newShell) {
632 super.configureShell(newShell);
633 PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
634 IJavaHelpContextIds.EDIT_TEMPLATE_DIALOG);