Tet for Bugs item #690938
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / preferences / EditTemplateDialog.java
1 /*
2  * (c) Copyright IBM Corp. 2000, 2001.
3  * All Rights Reserved.
4  */
5 package net.sourceforge.phpdt.internal.ui.preferences;
6
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.Iterator;
10 import java.util.List;
11 import java.util.Map;
12 import java.util.Vector;
13
14 import net.sourceforge.phpdt.internal.corext.template.ContextTypeRegistry;
15 import net.sourceforge.phpdt.internal.corext.template.Template;
16 import net.sourceforge.phpdt.internal.corext.template.TemplateMessages;
17 import net.sourceforge.phpdt.internal.corext.template.TemplateTranslator;
18 import net.sourceforge.phpdt.internal.ui.dialog.StatusDialog;
19 import net.sourceforge.phpdt.internal.ui.dialog.StatusInfo;
20 import net.sourceforge.phpdt.internal.ui.text.template.TemplateVariableProcessor;
21 import net.sourceforge.phpdt.internal.ui.util.SWTUtil;
22 import net.sourceforge.phpeclipse.IPreferenceConstants;
23 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
24 import net.sourceforge.phpeclipse.phpeditor.PHPSourceViewerConfiguration;
25
26 import org.eclipse.core.runtime.CoreException;
27 import org.eclipse.jface.action.Action;
28 import org.eclipse.jface.action.GroupMarker;
29 import org.eclipse.jface.action.IAction;
30 import org.eclipse.jface.action.IMenuListener;
31 import org.eclipse.jface.action.IMenuManager;
32 import org.eclipse.jface.action.MenuManager;
33 import org.eclipse.jface.action.Separator;
34 import org.eclipse.jface.preference.IPreferenceStore;
35 import org.eclipse.jface.preference.PreferenceConverter;
36 import org.eclipse.jface.resource.JFaceResources;
37 import org.eclipse.jface.text.Document;
38 import org.eclipse.jface.text.IDocument;
39 import org.eclipse.jface.text.ITextListener;
40 import org.eclipse.jface.text.ITextOperationTarget;
41 import org.eclipse.jface.text.ITextViewer;
42 import org.eclipse.jface.text.ITextViewerExtension;
43 import org.eclipse.jface.text.TextEvent;
44 import org.eclipse.jface.text.contentassist.ContentAssistant;
45 import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
46 import org.eclipse.jface.text.contentassist.IContentAssistant;
47 import org.eclipse.jface.text.source.ISourceViewer;
48 import org.eclipse.jface.text.source.SourceViewer;
49 import org.eclipse.jface.viewers.ISelectionChangedListener;
50 import org.eclipse.jface.viewers.SelectionChangedEvent;
51 import org.eclipse.swt.SWT;
52 import org.eclipse.swt.custom.StyledText;
53 import org.eclipse.swt.custom.VerifyKeyListener;
54 import org.eclipse.swt.events.KeyEvent;
55 import org.eclipse.swt.events.KeyListener;
56 import org.eclipse.swt.events.ModifyEvent;
57 import org.eclipse.swt.events.ModifyListener;
58 import org.eclipse.swt.events.SelectionEvent;
59 import org.eclipse.swt.events.SelectionListener;
60 import org.eclipse.swt.events.VerifyEvent;
61 import org.eclipse.swt.graphics.Color;
62 import org.eclipse.swt.graphics.Font;
63 import org.eclipse.swt.graphics.RGB;
64 import org.eclipse.swt.layout.GridData;
65 import org.eclipse.swt.layout.GridLayout;
66 import org.eclipse.swt.widgets.Button;
67 import org.eclipse.swt.widgets.Combo;
68 import org.eclipse.swt.widgets.Composite;
69 import org.eclipse.swt.widgets.Control;
70 import org.eclipse.swt.widgets.Display;
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.ui.texteditor.ITextEditorActionConstants;
76 import org.eclipse.ui.texteditor.IUpdate;
77
78 /**
79  * Dialog to edit a template.
80  */
81 public class EditTemplateDialog extends StatusDialog {
82
83         private static class SimpleJavaSourceViewerConfiguration extends PHPSourceViewerConfiguration {
84
85                 private final IContentAssistProcessor fProcessor;
86
87         //      SimpleJavaSourceViewerConfiguration(JavaTextTools tools, ITextEditor editor, IContentAssistProcessor processor) {
88                 SimpleJavaSourceViewerConfiguration(IContentAssistProcessor processor) {        
89       super();
90                         fProcessor= processor;
91                 }
92                 
93                 /*
94                  * @see SourceViewerConfiguration#getContentAssistant(ISourceViewer)
95                  */
96                 public IContentAssistant getContentAssistant(ISourceViewer sourceViewer) {
97
98                         IPreferenceStore store= PHPeclipsePlugin.getDefault().getPreferenceStore();
99
100                         ContentAssistant assistant= new ContentAssistant();
101                         assistant.setContentAssistProcessor(fProcessor, IDocument.DEFAULT_CONTENT_TYPE);
102                                 // Register the same processor for strings and single line comments to get code completion at the start of those partitions.
103 //                      assistant.setContentAssistProcessor(fProcessor, JavaPartitionScanner.JAVA_STRING);
104 //                      assistant.setContentAssistProcessor(fProcessor, JavaPartitionScanner.JAVA_SINGLE_LINE_COMMENT);
105 //                      
106 //                      assistant.setContentAssistProcessor(fProcessor, JavaPartitionScanner.JAVA_DOC);
107
108 //                      assistant.enableAutoInsert(store.getBoolean(ContentAssistPreference.AUTOINSERT));
109 //                      assistant.enableAutoActivation(store.getBoolean(ContentAssistPreference.AUTOACTIVATION));
110 //                      assistant.setAutoActivationDelay(store.getInt(ContentAssistPreference.AUTOACTIVATION_DELAY));
111                         assistant.setProposalPopupOrientation(IContentAssistant.PROPOSAL_OVERLAY);
112                         assistant.setContextInformationPopupOrientation(IContentAssistant.CONTEXT_INFO_ABOVE);
113 //                      assistant.setInformationControlCreator(getInformationControlCreator(sourceViewer));
114
115                         Display display= sourceViewer.getTextWidget().getDisplay();
116                         
117                         Color background= createColor(store, IPreferenceConstants.PROPOSALS_BACKGROUND, display);                       
118                         assistant.setContextInformationPopupBackground(background);
119                         assistant.setContextSelectorBackground(background);
120                         assistant.setProposalSelectorBackground(background);
121
122                         Color foreground= createColor(store, IPreferenceConstants.PROPOSALS_FOREGROUND, display);
123                         assistant.setContextInformationPopupForeground(foreground);
124                         assistant.setContextSelectorForeground(foreground);
125                         assistant.setProposalSelectorForeground(foreground);
126                         
127                         return assistant;
128                 }       
129
130                 /**
131                  * Creates a color from the information stored in the given preference store.
132                  * Returns <code>null</code> if there is no such information available.
133                  */
134                 private Color createColor(IPreferenceStore store, String key, Display display) {
135                 
136                         RGB rgb= null;          
137                         
138                         if (store.contains(key)) {
139                                 
140                                 if (store.isDefault(key))
141                                         rgb= PreferenceConverter.getDefaultColor(store, key);
142                                 else
143                                         rgb= PreferenceConverter.getColor(store, key);
144                         
145                                 if (rgb != null)
146                                         return new Color(display, rgb);
147                         }
148                         
149                         return null;
150                 }       
151         }
152
153         private static class TextViewerAction extends Action implements IUpdate {
154         
155                 private int fOperationCode= -1;
156                 private ITextOperationTarget fOperationTarget;
157         
158                 public TextViewerAction(ITextViewer viewer, int operationCode) {
159                         fOperationCode= operationCode;
160                         fOperationTarget= viewer.getTextOperationTarget();
161                         update();
162                 }
163         
164                 /**
165                  * Updates the enabled state of the action.
166                  * Fires a property change if the enabled state changes.
167                  * 
168                  * @see Action#firePropertyChange(String, Object, Object)
169                  */
170                 public void update() {
171         
172                         boolean wasEnabled= isEnabled();
173                         boolean isEnabled= (fOperationTarget != null && fOperationTarget.canDoOperation(fOperationCode));
174                         setEnabled(isEnabled);
175         
176                         if (wasEnabled != isEnabled) {
177                                 firePropertyChange(ENABLED, wasEnabled ? Boolean.TRUE : Boolean.FALSE, isEnabled ? Boolean.TRUE : Boolean.FALSE);
178                         }
179                 }
180                 
181                 /**
182                  * @see Action#run()
183                  */
184                 public void run() {
185                         if (fOperationCode != -1 && fOperationTarget != null) {
186                                 fOperationTarget.doOperation(fOperationCode);
187                         }
188                 }
189         }       
190
191         private final Template fTemplate;
192         
193         private Text fNameText;
194         private Text fDescriptionText;
195         private Combo fContextCombo;
196         private SourceViewer fPatternEditor;    
197         private Button fInsertVariableButton;
198
199         private TemplateTranslator fTranslator= new TemplateTranslator();       
200         private boolean fSuppressError= true; // #4354  
201         private Map fGlobalActions= new HashMap(10);
202         private List fSelectionActions = new ArrayList(3);      
203         private Vector fContextTypes= new Vector();
204         
205         private final TemplateVariableProcessor fProcessor= new TemplateVariableProcessor();
206                 
207         public EditTemplateDialog(Shell parent, Template template, boolean edit) {
208                 super(parent);
209                 
210                 setShellStyle(getShellStyle() | SWT.MAX | SWT.RESIZE);
211                 
212                 String title= edit
213                         ? TemplateMessages.getString("EditTemplateDialog.title.edit") //$NON-NLS-1$
214                         : TemplateMessages.getString("EditTemplateDialog.title.new"); //$NON-NLS-1$
215                 setTitle(title);
216
217                 fTemplate= template;
218                 
219                 ContextTypeRegistry registry= ContextTypeRegistry.getInstance();
220                 for (Iterator iterator= registry.iterator(); iterator.hasNext(); )
221                         fContextTypes.add(iterator.next());
222
223                 if (fContextTypes.size() > 0)
224                         fProcessor.setContextType(ContextTypeRegistry.getInstance().getContextType((String) fContextTypes.get(0)));
225         }
226         
227         /*
228          * @see Dialog#createDialogArea(Composite)
229          */
230         protected Control createDialogArea(Composite ancestor) {
231                 Composite parent= new Composite(ancestor, SWT.NONE);
232                 GridLayout layout= new GridLayout();
233                 layout.numColumns= 2;
234                 parent.setLayout(layout);
235                 parent.setLayoutData(new GridData(GridData.FILL_BOTH));
236                 
237                 createLabel(parent, TemplateMessages.getString("EditTemplateDialog.name")); //$NON-NLS-1$       
238                 
239                 Composite composite= new Composite(parent, SWT.NONE);
240                 composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
241                 layout= new GridLayout();               
242                 layout.numColumns= 3;
243                 layout.marginWidth= 0;
244                 layout.marginHeight= 0;
245                 composite.setLayout(layout);
246
247                 fNameText= createText(composite);
248                 fNameText.addModifyListener(new ModifyListener() {
249                         public void modifyText(ModifyEvent e) {
250                                 if (fSuppressError && (fNameText.getText().trim().length() != 0))
251                                         fSuppressError= false;
252
253                                 updateButtons();
254                         }
255                 });
256
257                 createLabel(composite, TemplateMessages.getString("EditTemplateDialog.context")); //$NON-NLS-1$         
258                 fContextCombo= new Combo(composite, SWT.READ_ONLY);
259
260                 for (Iterator iterator= fContextTypes.iterator(); iterator.hasNext(); )
261                         fContextCombo.add((String) iterator.next());
262
263                 fContextCombo.addModifyListener(new ModifyListener() {
264                         public void modifyText(ModifyEvent e) {
265                                 String name= fContextCombo.getText();
266                                 fProcessor.setContextType(ContextTypeRegistry.getInstance().getContextType(name));                              
267                         }
268                 });
269                 
270                 createLabel(parent, TemplateMessages.getString("EditTemplateDialog.description")); //$NON-NLS-1$                
271                 fDescriptionText= createText(parent);
272
273                 Label patternLabel= createLabel(parent, TemplateMessages.getString("EditTemplateDialog.pattern")); //$NON-NLS-1$
274                 patternLabel.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING));
275                 fPatternEditor= createEditor(parent);
276                 
277                 Label filler= new Label(parent, SWT.NONE);              
278                 filler.setLayoutData(new GridData());
279                 
280                 composite= new Composite(parent, SWT.NONE);
281                 layout= new GridLayout();               
282                 layout.marginWidth= 0;
283                 layout.marginHeight= 0;
284                 composite.setLayout(layout);            
285                 composite.setLayoutData(new GridData());
286                 
287                 fInsertVariableButton= new Button(composite, SWT.NONE);
288                 fInsertVariableButton.setLayoutData(getButtonGridData(fInsertVariableButton));
289                 fInsertVariableButton.setText(TemplateMessages.getString("EditTemplateDialog.insert.variable")); //$NON-NLS-1$
290                 fInsertVariableButton.addSelectionListener(new SelectionListener() {
291                         public void widgetSelected(SelectionEvent e) {
292                                 fPatternEditor.getTextWidget().setFocus();
293                                 fPatternEditor.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);                      
294                         }
295
296                         public void widgetDefaultSelected(SelectionEvent e) {}
297                 });
298
299                 fNameText.setText(fTemplate.getName());
300                 fDescriptionText.setText(fTemplate.getDescription());
301                 fContextCombo.select(getIndex(fTemplate.getContextTypeName()));
302
303                 initializeActions();
304
305                 return composite;
306         }
307
308         private static GridData getButtonGridData(Button button) {
309                 GridData data= new GridData(GridData.FILL_HORIZONTAL);
310                 data.heightHint= SWTUtil.getButtonHeigthHint(button);
311         
312                 return data;
313         }
314
315         private static Label createLabel(Composite parent, String name) {
316                 Label label= new Label(parent, SWT.NULL);
317                 label.setText(name);
318                 label.setLayoutData(new GridData());
319
320                 return label;
321         }
322
323         private static Text createText(Composite parent) {
324                 Text text= new Text(parent, SWT.BORDER);
325                 text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));             
326                 
327                 return text;
328         }
329
330         private SourceViewer createEditor(Composite parent) {
331                 SourceViewer viewer= new SourceViewer(parent, null, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
332         //      JavaTextTools tools= JavaPlugin.getDefault().getJavaTextTools();
333                 IDocument document= new Document(fTemplate.getPattern());
334         //      IDocumentPartitioner partitioner= tools.createDocumentPartitioner();
335         //      document.setDocumentPartitioner(partitioner);
336         //      partitioner.connect(document);          
337         //      viewer.configure(new SimpleJavaSourceViewerConfiguration(tools, null, fProcessor));
338                 viewer.configure(new SimpleJavaSourceViewerConfiguration(fProcessor));
339     viewer.setEditable(true);
340                 viewer.setDocument(document);
341                 
342                 Font font= JFaceResources.getFontRegistry().get(JFaceResources.TEXT_FONT);
343                 viewer.getTextWidget().setFont(font);
344                 
345                 Control control= viewer.getControl();
346                 GridData data= new GridData(GridData.FILL_BOTH);
347                 data.widthHint= convertWidthInCharsToPixels(60);
348                 data.heightHint= convertHeightInCharsToPixels(5);
349                 control.setLayoutData(data);
350                 
351                 viewer.addTextListener(new ITextListener() {
352                         public void textChanged(TextEvent event) {
353                             try {
354                                         fTranslator.translate(event.getDocumentEvent().getDocument().get());
355                             } catch (CoreException e) {
356                                 PHPeclipsePlugin.log(e);
357                             }
358                                 
359                                 updateUndoAction();
360                                 updateButtons();
361                         }
362                 });
363
364                 viewer.addSelectionChangedListener(new ISelectionChangedListener() {                    
365                         public void selectionChanged(SelectionChangedEvent event) {
366                                 updateSelectionDependentActions();
367                         }
368                 });
369
370                 if (viewer instanceof ITextViewerExtension) {
371                          ((ITextViewerExtension) viewer).prependVerifyKeyListener(new VerifyKeyListener() {
372                                 public void verifyKey(VerifyEvent event) {
373                                         handleVerifyKeyPressed(event);
374                                 }
375                         });
376                 } else {                        
377                         viewer.getTextWidget().addKeyListener(new KeyListener() {
378                                 public void keyPressed(KeyEvent e) {
379                                         handleKeyPressed(e);
380                                 }
381         
382                                 public void keyReleased(KeyEvent e) {}
383                         });
384                 }
385                 
386                 return viewer;
387         }
388
389         private void handleKeyPressed(KeyEvent event) {
390                 if (event.stateMask != SWT.CTRL)
391                         return;
392                         
393                 switch (event.character) {
394                         case ' ':
395                                 fPatternEditor.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
396                                 break;
397
398                         // CTRL-Z
399                         case (int) 'z' - (int) 'a' + 1:
400                                 fPatternEditor.doOperation(ITextOperationTarget.UNDO);
401                                 break;                          
402                 }
403         }
404
405         private void handleVerifyKeyPressed(VerifyEvent event) {
406                 if (!event.doit)
407                         return;
408
409                 if (event.stateMask != SWT.CTRL)
410                         return;
411                         
412                 switch (event.character) {
413                         case ' ':
414                                 fPatternEditor.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS);
415                                 event.doit= false;
416                                 break;
417
418                         // CTRL-Z
419                         case (int) 'z' - (int) 'a' + 1:
420                                 fPatternEditor.doOperation(ITextOperationTarget.UNDO);
421                                 event.doit= false;
422                                 break;                          
423                 }
424         }
425
426         private void initializeActions() {
427                 TextViewerAction action= new TextViewerAction(fPatternEditor, SourceViewer.UNDO);
428                 action.setText(TemplateMessages.getString("EditTemplateDialog.undo")); //$NON-NLS-1$
429                 fGlobalActions.put(ITextEditorActionConstants.UNDO, action);
430
431                 action= new TextViewerAction(fPatternEditor, SourceViewer.CUT);
432                 action.setText(TemplateMessages.getString("EditTemplateDialog.cut")); //$NON-NLS-1$
433                 fGlobalActions.put(ITextEditorActionConstants.CUT, action);
434
435                 action= new TextViewerAction(fPatternEditor, SourceViewer.COPY);
436                 action.setText(TemplateMessages.getString("EditTemplateDialog.copy")); //$NON-NLS-1$
437                 fGlobalActions.put(ITextEditorActionConstants.COPY, action);
438
439                 action= new TextViewerAction(fPatternEditor, SourceViewer.PASTE);
440                 action.setText(TemplateMessages.getString("EditTemplateDialog.paste")); //$NON-NLS-1$
441                 fGlobalActions.put(ITextEditorActionConstants.PASTE, action);
442
443                 action= new TextViewerAction(fPatternEditor, SourceViewer.SELECT_ALL);
444                 action.setText(TemplateMessages.getString("EditTemplateDialog.select.all")); //$NON-NLS-1$
445                 fGlobalActions.put(ITextEditorActionConstants.SELECT_ALL, action);
446
447                 action= new TextViewerAction(fPatternEditor, SourceViewer.CONTENTASSIST_PROPOSALS);
448                 action.setText(TemplateMessages.getString("EditTemplateDialog.content.assist")); //$NON-NLS-1$
449                 fGlobalActions.put("ContentAssistProposal", action); //$NON-NLS-1$
450
451                 fSelectionActions.add(ITextEditorActionConstants.CUT);
452                 fSelectionActions.add(ITextEditorActionConstants.COPY);
453                 fSelectionActions.add(ITextEditorActionConstants.PASTE);
454                 
455                 // create context menu
456                 MenuManager manager= new MenuManager(null, null);
457                 manager.setRemoveAllWhenShown(true);
458                 manager.addMenuListener(new IMenuListener() {
459                         public void menuAboutToShow(IMenuManager mgr) {
460                                 fillContextMenu(mgr);
461                         }
462                 });
463
464                 StyledText text= fPatternEditor.getTextWidget();                
465                 Menu menu= manager.createContextMenu(text);
466                 text.setMenu(menu);
467         }
468
469         private void fillContextMenu(IMenuManager menu) {
470                 menu.add(new GroupMarker(ITextEditorActionConstants.GROUP_UNDO));
471                 menu.appendToGroup(ITextEditorActionConstants.GROUP_UNDO, (IAction) fGlobalActions.get(ITextEditorActionConstants.UNDO));
472                 
473                 menu.add(new Separator(ITextEditorActionConstants.GROUP_EDIT));         
474                 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.CUT));
475                 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.COPY));
476                 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.PASTE));
477                 menu.appendToGroup(ITextEditorActionConstants.GROUP_EDIT, (IAction) fGlobalActions.get(ITextEditorActionConstants.SELECT_ALL));
478
479         //      menu.add(new Separator(IContextMenuConstants.GROUP_GENERATE));
480         //      menu.appendToGroup(IContextMenuConstants.GROUP_GENERATE, (IAction) fGlobalActions.get("ContentAssistProposal")); //$NON-NLS-1$
481         }
482
483         protected void updateSelectionDependentActions() {
484                 Iterator iterator= fSelectionActions.iterator();
485                 while (iterator.hasNext())
486                         updateAction((String)iterator.next());          
487         }
488
489         protected void updateUndoAction() {
490                 IAction action= (IAction) fGlobalActions.get(ITextEditorActionConstants.UNDO);
491                 if (action instanceof IUpdate)
492                         ((IUpdate) action).update();
493         }
494
495         protected void updateAction(String actionId) {
496                 IAction action= (IAction) fGlobalActions.get(actionId);
497                 if (action instanceof IUpdate)
498                         ((IUpdate) action).update();
499         }
500
501         private int getIndex(String context) {
502                 ContextTypeRegistry registry= ContextTypeRegistry.getInstance();
503                 registry.getContextType(context);
504                 
505                 if (context == null)
506                         return -1;
507                         
508                 return fContextTypes.indexOf(context);
509         }
510         
511         protected void okPressed() {
512                 fTemplate.setName(fNameText.getText());
513                 fTemplate.setDescription(fDescriptionText.getText());
514                 fTemplate.setContext(fContextCombo.getText());
515                 fTemplate.setPattern(fPatternEditor.getTextWidget().getText());
516                 
517                 super.okPressed();
518         }
519         
520         private void updateButtons() {          
521                 boolean valid= fNameText.getText().trim().length() != 0;
522
523                 StatusInfo status= new StatusInfo();
524                 
525                 if (!valid) {
526                         if (fSuppressError)
527                                 status.setError(""); //$NON-NLS-1$                                                      
528                         else
529                                 status.setError(TemplateMessages.getString("EditTemplateDialog.error.noname")); //$NON-NLS-1$
530                 } else if (fTranslator.getErrorMessage() != null) {
531                         status.setError(fTranslator.getErrorMessage()); 
532                 }
533
534                 updateStatus(status);
535         }
536
537         /*
538          * @see org.eclipse.jface.window.Window#configureShell(Shell)
539          */
540         protected void configureShell(Shell newShell) {
541                 super.configureShell(newShell);
542 //              WorkbenchHelp.setHelp(newShell, IJavaHelpContextIds.EDIT_TEMPLATE_DIALOG);
543         }
544
545
546 }