d3a5b50a4d18f93db6a3d7d6216b129c2d8c92ee
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / ui / preferences / JavaEditorHoverConfigurationBlock.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2003 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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11
12 package net.sourceforge.phpdt.internal.ui.preferences;
13
14 import java.util.HashMap;
15 import java.util.StringTokenizer;
16
17 import net.sourceforge.phpdt.internal.ui.dialogs.StatusInfo;
18 import net.sourceforge.phpdt.internal.ui.dialogs.StatusUtil;
19 import net.sourceforge.phpdt.internal.ui.text.java.hover.JavaEditorTextHoverDescriptor;
20 import net.sourceforge.phpdt.internal.ui.util.PixelConverter;
21 import net.sourceforge.phpdt.ui.PreferenceConstants;
22 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
23
24 import org.eclipse.core.runtime.IStatus;
25 import org.eclipse.jface.action.Action;
26 import org.eclipse.jface.dialogs.Dialog;
27 import org.eclipse.jface.preference.IPreferenceStore;
28 import org.eclipse.jface.text.Assert;
29 import org.eclipse.swt.SWT;
30 import org.eclipse.swt.events.KeyEvent;
31 import org.eclipse.swt.events.KeyListener;
32 import org.eclipse.swt.events.ModifyEvent;
33 import org.eclipse.swt.events.ModifyListener;
34 import org.eclipse.swt.events.SelectionEvent;
35 import org.eclipse.swt.events.SelectionListener;
36 import org.eclipse.swt.graphics.Point;
37 import org.eclipse.swt.layout.GridData;
38 import org.eclipse.swt.layout.GridLayout;
39 import org.eclipse.swt.widgets.Button;
40 import org.eclipse.swt.widgets.Composite;
41 import org.eclipse.swt.widgets.Control;
42 import org.eclipse.swt.widgets.Label;
43 import org.eclipse.swt.widgets.List;
44 import org.eclipse.swt.widgets.Text;
45
46 /**
47  * Configures Java Editor hover preferences.
48  * 
49  * @since 2.1
50  */
51 class JavaEditorHoverConfigurationBlock {
52
53         private static final String DELIMITER= PreferencesMessages.getString("JavaEditorHoverConfigurationBlock.delimiter"); //$NON-NLS-1$
54
55         // Data structure to hold the values which are edited by the user
56         private static class HoverConfig {
57                 
58                 private String fModifierString;
59                 private boolean fIsEnabled;
60                 private int fStateMask;
61
62                 private HoverConfig(String modifier, int stateMask, boolean enabled) {
63                         fModifierString= modifier;
64                         fIsEnabled= enabled;
65                         fStateMask= stateMask;
66                 }
67         }
68
69         private IPreferenceStore fStore;
70         private HoverConfig[] fHoverConfigs;
71         private Text fModifierEditor;
72         private Button fEnableField;
73         private List fHoverList;
74         private Text fDescription;
75 //      private Button fShowHoverAffordanceCheckbox;
76         
77         private JavaEditorPreferencePage fMainPreferencePage;
78
79         private StatusInfo fStatus;
80
81         public JavaEditorHoverConfigurationBlock(JavaEditorPreferencePage mainPreferencePage, IPreferenceStore store) {
82                 Assert.isNotNull(mainPreferencePage);
83                 Assert.isNotNull(store);
84                 fMainPreferencePage= mainPreferencePage;
85                 fStore= store;
86         }
87
88         /**
89          * Creates page for hover preferences.
90          */
91         public Control createControl(Composite parent) {
92
93                 PixelConverter pixelConverter= new PixelConverter(parent);
94
95                 Composite hoverComposite= new Composite(parent, SWT.NULL);
96                 GridLayout layout= new GridLayout();
97                 layout.numColumns= 2;
98                 hoverComposite.setLayout(layout);
99                 GridData gd= new GridData(GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
100                 hoverComposite.setLayoutData(gd);
101
102                 Label label= new Label(hoverComposite, SWT.NONE);
103                 label.setText(PreferencesMessages.getString("JavaEditorHoverConfigurationBlock.hoverPreferences")); //$NON-NLS-1$
104                 gd= new GridData(GridData.FILL_HORIZONTAL);
105                 gd.horizontalAlignment= GridData.BEGINNING;
106                 gd.horizontalSpan= 2;
107                 label.setLayoutData(gd);
108                 gd= new GridData(GridData.GRAB_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
109
110                 // Hover list
111                 fHoverList= new List(hoverComposite, SWT.SINGLE | SWT.V_SCROLL | SWT.BORDER);
112                 gd= new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.FILL_HORIZONTAL);
113                 int listHeight= 10 * fHoverList.getItemHeight();
114                 gd.heightHint= listHeight;
115                 fHoverList.setLayoutData(gd);
116                 fHoverList.addSelectionListener(new SelectionListener() {
117                         public void widgetSelected(SelectionEvent e) {
118                                 handleHoverListSelection();
119                         }
120                         public void widgetDefaultSelected(SelectionEvent e) {
121                         }
122                 });
123
124
125                 Composite stylesComposite= new Composite(hoverComposite, SWT.NONE);
126                 layout= new GridLayout();
127                 layout.marginHeight= 0;
128                 layout.marginWidth= 0;
129                 layout.numColumns= 2;
130                 stylesComposite.setLayout(layout);
131                 gd= new GridData(GridData.FILL_HORIZONTAL);
132                 gd.heightHint= listHeight + (2 * fHoverList.getBorderWidth());
133                 stylesComposite.setLayoutData(gd);
134
135                 // Enabled checkbox             
136                 fEnableField= new Button(stylesComposite, SWT.CHECK);
137                 fEnableField.setText(PreferencesMessages.getString("JavaEditorHoverConfigurationBlock.enabled")); //$NON-NLS-1$
138                 gd= new GridData(GridData.FILL_HORIZONTAL);
139                 gd.horizontalAlignment= GridData.BEGINNING;
140                 gd.horizontalSpan= 2;
141                 fEnableField.setLayoutData(gd);
142                 fEnableField.addSelectionListener(new SelectionListener() {
143                         public void widgetSelected(SelectionEvent e) {
144                                 int i= fHoverList.getSelectionIndex();
145                                 boolean state= fEnableField.getSelection();
146                                 fModifierEditor.setEnabled(state);
147                                 fHoverConfigs[i].fIsEnabled= state;
148                                 handleModifierModified();
149                         }
150                         public void widgetDefaultSelected(SelectionEvent e) {
151                         }
152                 });
153
154                 // Text field for modifier string
155                 label= new Label(stylesComposite, SWT.LEFT);
156                 label.setText(PreferencesMessages.getString("JavaEditorHoverConfigurationBlock.keyModifier")); //$NON-NLS-1$
157                 fModifierEditor= new Text(stylesComposite, SWT.BORDER);
158                 gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
159                 fModifierEditor.setLayoutData(gd);
160
161                 fModifierEditor.addKeyListener(new KeyListener() {
162                         private boolean isModifierCandidate;
163                         public void keyPressed(KeyEvent e) {
164                                 isModifierCandidate= e.keyCode > 0 && e.character == 0 && e.stateMask == 0;
165                         }
166                 
167                         public void keyReleased(KeyEvent e) {
168                                 if (isModifierCandidate && e.stateMask > 0 && e.stateMask == e.stateMask && e.character == 0) {// && e.time -time < 1000) {
169                                         String text= fModifierEditor.getText();
170                                         Point selection= fModifierEditor.getSelection();
171                                         int i= selection.x - 1;
172                                         while (i > -1 && Character.isWhitespace(text.charAt(i))) {
173                                                 i--;
174                                         }
175                                         boolean needsPrefixDelimiter= i > -1 && !String.valueOf(text.charAt(i)).equals(DELIMITER);
176
177                                         i= selection.y;
178                                         while (i < text.length() && Character.isWhitespace(text.charAt(i))) {
179                                                 i++;
180                                         }
181                                         boolean needsPostfixDelimiter= i < text.length() && !String.valueOf(text.charAt(i)).equals(DELIMITER);
182
183                                         String insertString;
184
185                                         if (needsPrefixDelimiter && needsPostfixDelimiter)
186                                                 insertString= PreferencesMessages.getFormattedString("JavaEditorHoverConfigurationBlock.insertDelimiterAndModifierAndDelimiter", new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
187                                         else if (needsPrefixDelimiter)
188                                                 insertString= PreferencesMessages.getFormattedString("JavaEditorHoverConfigurationBlock.insertDelimiterAndModifier", new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
189                                         else if (needsPostfixDelimiter)
190                                                 insertString= PreferencesMessages.getFormattedString("JavaEditorHoverConfigurationBlock.insertModifierAndDelimiter", new String[] {Action.findModifierString(e.stateMask)}); //$NON-NLS-1$
191                                         else
192                                                 insertString= Action.findModifierString(e.stateMask);
193
194                                         if (insertString != null)
195                                                 fModifierEditor.insert(insertString);
196                                 }
197                         }
198                 });
199
200                 fModifierEditor.addModifyListener(new ModifyListener() {
201                         public void modifyText(ModifyEvent e) {
202                                 handleModifierModified();
203                         }
204                 });
205
206                 // Description
207                 Label descriptionLabel= new Label(stylesComposite, SWT.LEFT);
208                 descriptionLabel.setText(PreferencesMessages.getString("JavaEditorHoverConfigurationBlock.description")); //$NON-NLS-1$
209                 gd= new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
210                 gd.horizontalSpan= 2;
211                 descriptionLabel.setLayoutData(gd);
212                 fDescription= new Text(stylesComposite, SWT.LEFT | SWT.WRAP | SWT.MULTI | SWT.READ_ONLY | SWT.BORDER);
213                 gd= new GridData(GridData.FILL_BOTH);
214                 gd.horizontalSpan= 2;
215                 fDescription.setLayoutData(gd);
216
217                 // Vertical filler
218                 Label filler= new Label(hoverComposite, SWT.LEFT);
219                 gd= new GridData(GridData.BEGINNING | GridData.VERTICAL_ALIGN_FILL);
220                 gd.heightHint= pixelConverter.convertHeightInCharsToPixels(1) / 3;
221                 filler.setLayoutData(gd);
222
223                 // Affordance checkbox
224 //              fShowHoverAffordanceCheckbox= new Button(hoverComposite, SWT.CHECK);
225 //              fShowHoverAffordanceCheckbox.setText(PreferencesMessages.getString("JavaEditorHoverConfigurationBlock.showAffordance")); //$NON-NLS-1$
226 //              gd= new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
227 //              gd.horizontalIndent= 0;
228 //              gd.horizontalSpan= 2;
229 //              fShowHoverAffordanceCheckbox.setLayoutData(gd);
230
231                 initialize();
232
233                 Dialog.applyDialogFont(hoverComposite);
234                 return hoverComposite;
235         }
236
237         private JavaEditorTextHoverDescriptor[] getContributedHovers() {
238                 return PHPeclipsePlugin.getDefault().getJavaEditorTextHoverDescriptors();               
239         }
240
241         void initialize() {
242                 JavaEditorTextHoverDescriptor[] hoverDescs= getContributedHovers();
243                 fHoverConfigs= new HoverConfig[hoverDescs.length];
244                 for (int i= 0; i < hoverDescs.length; i++) {
245                         fHoverConfigs[i]= new HoverConfig(hoverDescs[i].getModifierString(), hoverDescs[i].getStateMask(), hoverDescs[i].isEnabled());
246                         fHoverList.add(hoverDescs[i].getLabel());
247                 }
248                 initializeFields();
249         }
250
251         void initializeFields() {
252                 fHoverList.getDisplay().asyncExec(new Runnable() {
253                         public void run() {
254                                 if (fHoverList != null && !fHoverList.isDisposed()) {
255                                         fHoverList.select(0);
256                                         handleHoverListSelection();
257                                 }
258                         }
259                 });
260 //              fShowHoverAffordanceCheckbox.setSelection(fStore.getBoolean(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE));
261         }
262
263         void performOk() {
264                 StringBuffer buf= new StringBuffer();
265                 StringBuffer maskBuf= new StringBuffer();
266                 for (int i= 0; i < fHoverConfigs.length; i++) {
267                         buf.append(getContributedHovers()[i].getId());
268                         buf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
269                         if (!fHoverConfigs[i].fIsEnabled)
270                                 buf.append(JavaEditorTextHoverDescriptor.DISABLED_TAG);
271                         String modifier= fHoverConfigs[i].fModifierString;
272                         if (modifier == null || modifier.length() == 0)
273                                 modifier= JavaEditorTextHoverDescriptor.NO_MODIFIER;
274                         buf.append(modifier);
275                         buf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
276                         
277                         maskBuf.append(getContributedHovers()[i].getId());
278                         maskBuf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
279                         maskBuf.append(fHoverConfigs[i].fStateMask);
280                         maskBuf.append(JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
281                 }
282                 fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS, buf.toString());
283                 fStore.setValue(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS, maskBuf.toString());
284                 
285 //              fStore.setValue(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE, fShowHoverAffordanceCheckbox.getSelection());
286                 
287                 PHPeclipsePlugin.getDefault().resetJavaEditorTextHoverDescriptors();
288         }
289
290         void performDefaults() {
291                 restoreFromPreferences();
292                 initializeFields();
293         }
294
295         private void restoreFromPreferences() {
296
297 //              fShowHoverAffordanceCheckbox.setSelection(fStore.getBoolean(PreferenceConstants.EDITOR_SHOW_TEXT_HOVER_AFFORDANCE));
298
299                 String compiledTextHoverModifiers= fStore.getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIERS);
300                 
301                 StringTokenizer tokenizer= new StringTokenizer(compiledTextHoverModifiers, JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
302                 HashMap idToModifier= new HashMap(tokenizer.countTokens() / 2);
303
304                 while (tokenizer.hasMoreTokens()) {
305                         String id= tokenizer.nextToken();
306                         if (tokenizer.hasMoreTokens())
307                                 idToModifier.put(id, tokenizer.nextToken());
308                 }
309
310                 String compiledTextHoverModifierMasks= PHPeclipsePlugin.getDefault().getPreferenceStore().getString(PreferenceConstants.EDITOR_TEXT_HOVER_MODIFIER_MASKS);
311
312                 tokenizer= new StringTokenizer(compiledTextHoverModifierMasks, JavaEditorTextHoverDescriptor.VALUE_SEPARATOR);
313                 HashMap idToModifierMask= new HashMap(tokenizer.countTokens() / 2);
314
315                 while (tokenizer.hasMoreTokens()) {
316                         String id= tokenizer.nextToken();
317                         if (tokenizer.hasMoreTokens())
318                                 idToModifierMask.put(id, tokenizer.nextToken());
319                 }
320
321                 for (int i= 0; i < fHoverConfigs.length; i++) {
322                         String modifierString= (String)idToModifier.get(getContributedHovers()[i].getId());
323                         boolean enabled= true;
324                         if (modifierString == null)
325                                 modifierString= JavaEditorTextHoverDescriptor.DISABLED_TAG;
326                         
327                         if (modifierString.startsWith(JavaEditorTextHoverDescriptor.DISABLED_TAG)) {
328                                 enabled= false;
329                                 modifierString= modifierString.substring(1);
330                         }
331
332                         if (modifierString.equals(JavaEditorTextHoverDescriptor.NO_MODIFIER))
333                                 modifierString= ""; //$NON-NLS-1$
334
335                         fHoverConfigs[i].fModifierString= modifierString;
336                         fHoverConfigs[i].fIsEnabled= enabled;
337                         fHoverConfigs[i].fStateMask= JavaEditorTextHoverDescriptor.computeStateMask(modifierString);
338
339                         if (fHoverConfigs[i].fStateMask == -1) {
340                                 try {
341                                         fHoverConfigs[i].fStateMask= Integer.parseInt((String)idToModifierMask.get(getContributedHovers()[i].getId()));
342                                 } catch (NumberFormatException ex) {
343                                         fHoverConfigs[i].fStateMask= -1;
344                                 }
345                         }
346                 }
347         }
348
349         private void handleModifierModified() {
350                 int i= fHoverList.getSelectionIndex();
351                 String modifiers= fModifierEditor.getText();
352                 fHoverConfigs[i].fModifierString= modifiers;
353                 fHoverConfigs[i].fStateMask= JavaEditorTextHoverDescriptor.computeStateMask(modifiers);
354                 if (fHoverConfigs[i].fIsEnabled && fHoverConfigs[i].fStateMask == -1)
355                         fStatus= new StatusInfo(IStatus.ERROR, PreferencesMessages.getFormattedString("JavaEditorHoverConfigurationBlock.modifierIsNotValid", fHoverConfigs[i].fModifierString)); //$NON-NLS-1$
356                 else
357                         fStatus= new StatusInfo();
358                 updateStatus();
359         }
360
361         private void handleHoverListSelection() {       
362                 int i= fHoverList.getSelectionIndex();
363                 boolean enabled= fHoverConfigs[i].fIsEnabled;
364                 fEnableField.setSelection(enabled);
365                 fModifierEditor.setEnabled(enabled);
366                 fModifierEditor.setText(fHoverConfigs[i].fModifierString);
367                 String description= getContributedHovers()[i].getDescription();
368                 if (description == null)
369                         description= ""; //$NON-NLS-1$
370                 fDescription.setText(description);
371         }
372
373         IStatus getStatus() {
374                 if (fStatus == null)
375                         fStatus= new StatusInfo();
376                 return fStatus;
377         }
378
379         private void updateStatus() {
380                 int i= 0;
381                 HashMap stateMasks= new HashMap(fHoverConfigs.length);
382                 while (fStatus.isOK() && i < fHoverConfigs.length) {
383                         if (fHoverConfigs[i].fIsEnabled) {
384                                 String label= getContributedHovers()[i].getLabel();
385                                 Integer stateMask= new Integer(fHoverConfigs[i].fStateMask);
386                                 if (fHoverConfigs[i].fStateMask == -1)
387                                         fStatus= new StatusInfo(IStatus.ERROR, PreferencesMessages.getFormattedString("JavaEditorHoverConfigurationBlock.modifierIsNotValidForHover", new String[] {fHoverConfigs[i].fModifierString, label})); //$NON-NLS-1$
388                                 else if (stateMasks.containsKey(stateMask))
389                                         fStatus= new StatusInfo(IStatus.ERROR, PreferencesMessages.getFormattedString("JavaEditorHoverConfigurationBlock.duplicateModifier", new String[] {label, (String)stateMasks.get(stateMask)})); //$NON-NLS-1$
390                                 else
391                                         stateMasks.put(stateMask, label);
392                         }
393                         i++;
394                 }
395
396                 if (fStatus.isOK())
397                         fMainPreferencePage.updateStatus(fStatus);
398                 else {
399                         fMainPreferencePage.setValid(false);
400                         StatusUtil.applyToStatusLine(fMainPreferencePage, fStatus);
401                 }
402         }
403 }